From efe51805064a0fdc261e3f1e5c85ebebcb58b9ba Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 19 Feb 2019 10:24:22 -0800 Subject: [PATCH 001/205] Initial commit --- .gitignore | 32 +++ LICENSE | 674 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 3 files changed, 708 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..259148f --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 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 General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cc0f487 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# SSLClient +Arduino library to add SSL functionality to any Client class From 852937a3ae93953778acedad1cf7c3023ffeef3f Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 19 Feb 2019 10:33:22 -0800 Subject: [PATCH 002/205] created arduino library to wrap BearSSL for the EthernetClient library --- library.properties | 9 +++++++++ src/keywords.txt | 0 2 files changed, 9 insertions(+) create mode 100644 library.properties create mode 100644 src/keywords.txt diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..8b31264 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=SSLClient +version=0.1 +author=OPEnS Lab +maintainer=OPEnS Lab +sentence=Arduino library to add SSL functionality to any Client class +paragraph=Uses BearSSL to communicate over SSL. +category=Communication +url=https://github.com/OPEnSLab-OSU/SSLClient +includes=SSLClient.h \ No newline at end of file diff --git a/src/keywords.txt b/src/keywords.txt new file mode 100644 index 0000000..e69de29 From 1bce219f3fdcec89d9943b09fbee316e78a16086 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 19 Feb 2019 10:48:11 -0800 Subject: [PATCH 003/205] add bearSSL library to project --- SSLClient.h | 42 + bearssl.h | 170 + bearssl_aead.h | 1059 ++++ bearssl_block.h | 2618 ++++++++++ bearssl_ec.h | 883 ++++ bearssl_hash.h | 1346 ++++++ bearssl_hmac.h | 241 + bearssl_kdf.h | 185 + bearssl_pem.h | 294 ++ bearssl_prf.h | 150 + bearssl_rand.h | 397 ++ bearssl_rsa.h | 1366 ++++++ bearssl_ssl.h | 4296 +++++++++++++++++ bearssl_x509.h | 1397 ++++++ config.h | 229 + inner.h | 2532 ++++++++++ src/keywords.txt => keywords.txt | 0 src/bearssl/src/aead/ccm.c | 346 ++ src/bearssl/src/aead/eax.c | 525 ++ src/bearssl/src/aead/gcm.c | 318 ++ src/bearssl/src/codec/ccopy.c | 44 + src/bearssl/src/codec/dec16be.c | 38 + src/bearssl/src/codec/dec16le.c | 38 + src/bearssl/src/codec/dec32be.c | 38 + src/bearssl/src/codec/dec32le.c | 38 + src/bearssl/src/codec/dec64be.c | 38 + src/bearssl/src/codec/dec64le.c | 38 + src/bearssl/src/codec/enc16be.c | 38 + src/bearssl/src/codec/enc16le.c | 38 + src/bearssl/src/codec/enc32be.c | 38 + src/bearssl/src/codec/enc32le.c | 38 + src/bearssl/src/codec/enc64be.c | 38 + src/bearssl/src/codec/enc64le.c | 38 + src/bearssl/src/codec/pemdec.c | 526 ++ src/bearssl/src/codec/pemdec.t0 | 314 ++ src/bearssl/src/codec/pemenc.c | 173 + src/bearssl/src/ec/ec_all_m15.c | 121 + src/bearssl/src/ec/ec_all_m31.c | 121 + src/bearssl/src/ec/ec_c25519_i15.c | 398 ++ src/bearssl/src/ec/ec_c25519_i31.c | 387 ++ src/bearssl/src/ec/ec_c25519_m15.c | 1478 ++++++ src/bearssl/src/ec/ec_c25519_m31.c | 769 +++ src/bearssl/src/ec/ec_curve25519.c | 46 + src/bearssl/src/ec/ec_default.c | 36 + src/bearssl/src/ec/ec_keygen.c | 86 + src/bearssl/src/ec/ec_p256_m15.c | 2130 ++++++++ src/bearssl/src/ec/ec_p256_m31.c | 1475 ++++++ src/bearssl/src/ec/ec_prime_i15.c | 820 ++++ src/bearssl/src/ec/ec_prime_i31.c | 819 ++++ src/bearssl/src/ec/ec_pubkey.c | 85 + src/bearssl/src/ec/ec_secp256r1.c | 51 + src/bearssl/src/ec/ec_secp384r1.c | 57 + src/bearssl/src/ec/ec_secp521r1.c | 64 + src/bearssl/src/ec/ecdsa_atr.c | 134 + src/bearssl/src/ec/ecdsa_default_sign_asn1.c | 36 + src/bearssl/src/ec/ecdsa_default_sign_raw.c | 36 + src/bearssl/src/ec/ecdsa_default_vrfy_asn1.c | 36 + src/bearssl/src/ec/ecdsa_default_vrfy_raw.c | 36 + src/bearssl/src/ec/ecdsa_i15_bits.c | 47 + src/bearssl/src/ec/ecdsa_i15_sign_asn1.c | 45 + src/bearssl/src/ec/ecdsa_i15_sign_raw.c | 174 + src/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c | 48 + src/bearssl/src/ec/ecdsa_i15_vrfy_raw.c | 166 + src/bearssl/src/ec/ecdsa_i31_bits.c | 47 + src/bearssl/src/ec/ecdsa_i31_sign_asn1.c | 45 + src/bearssl/src/ec/ecdsa_i31_sign_raw.c | 173 + src/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c | 48 + src/bearssl/src/ec/ecdsa_i31_vrfy_raw.c | 165 + src/bearssl/src/ec/ecdsa_rta.c | 121 + src/bearssl/src/hash/dig_oid.c | 84 + src/bearssl/src/hash/dig_size.c | 50 + src/bearssl/src/hash/ghash_ctmul.c | 345 ++ src/bearssl/src/hash/ghash_ctmul32.c | 251 + src/bearssl/src/hash/ghash_ctmul64.c | 154 + src/bearssl/src/hash/ghash_pclmul.c | 389 ++ src/bearssl/src/hash/ghash_pwr8.c | 411 ++ src/bearssl/src/hash/md5.c | 208 + src/bearssl/src/hash/md5sha1.c | 141 + src/bearssl/src/hash/mgf1.c | 56 + src/bearssl/src/hash/multihash.c | 166 + src/bearssl/src/hash/sha1.c | 191 + src/bearssl/src/hash/sha2big.c | 285 ++ src/bearssl/src/hash/sha2small.c | 341 ++ src/bearssl/src/int/i15_add.c | 46 + src/bearssl/src/int/i15_bitlen.c | 44 + src/bearssl/src/int/i15_decmod.c | 124 + src/bearssl/src/int/i15_decode.c | 56 + src/bearssl/src/int/i15_decred.c | 100 + src/bearssl/src/int/i15_encode.c | 56 + src/bearssl/src/int/i15_fmont.c | 59 + src/bearssl/src/int/i15_iszero.c | 39 + src/bearssl/src/int/i15_moddiv.c | 465 ++ src/bearssl/src/int/i15_modpow.c | 50 + src/bearssl/src/int/i15_modpow2.c | 160 + src/bearssl/src/int/i15_montmul.c | 184 + src/bearssl/src/int/i15_mulacc.c | 61 + src/bearssl/src/int/i15_muladd.c | 173 + src/bearssl/src/int/i15_ninv15.c | 38 + src/bearssl/src/int/i15_reduce.c | 66 + src/bearssl/src/int/i15_rshift.c | 47 + src/bearssl/src/int/i15_sub.c | 46 + src/bearssl/src/int/i15_tmont.c | 36 + src/bearssl/src/int/i31_add.c | 46 + src/bearssl/src/int/i31_bitlen.c | 44 + src/bearssl/src/int/i31_decmod.c | 124 + src/bearssl/src/int/i31_decode.c | 57 + src/bearssl/src/int/i31_decred.c | 103 + src/bearssl/src/int/i31_encode.c | 79 + src/bearssl/src/int/i31_fmont.c | 60 + src/bearssl/src/int/i31_iszero.c | 39 + src/bearssl/src/int/i31_moddiv.c | 488 ++ src/bearssl/src/int/i31_modpow.c | 65 + src/bearssl/src/int/i31_modpow2.c | 160 + src/bearssl/src/int/i31_montmul.c | 93 + src/bearssl/src/int/i31_mulacc.c | 61 + src/bearssl/src/int/i31_muladd.c | 157 + src/bearssl/src/int/i31_ninv31.c | 39 + src/bearssl/src/int/i31_reduce.c | 66 + src/bearssl/src/int/i31_rshift.c | 47 + src/bearssl/src/int/i31_sub.c | 46 + src/bearssl/src/int/i31_tmont.c | 36 + src/bearssl/src/int/i32_add.c | 51 + src/bearssl/src/int/i32_bitlen.c | 44 + src/bearssl/src/int/i32_decmod.c | 77 + src/bearssl/src/int/i32_decode.c | 63 + src/bearssl/src/int/i32_decred.c | 107 + src/bearssl/src/int/i32_div32.c | 56 + src/bearssl/src/int/i32_encode.c | 72 + src/bearssl/src/int/i32_fmont.c | 60 + src/bearssl/src/int/i32_iszero.c | 39 + src/bearssl/src/int/i32_modpow.c | 65 + src/bearssl/src/int/i32_montmul.c | 69 + src/bearssl/src/int/i32_mulacc.c | 52 + src/bearssl/src/int/i32_muladd.c | 138 + src/bearssl/src/int/i32_ninv32.c | 39 + src/bearssl/src/int/i32_reduce.c | 66 + src/bearssl/src/int/i32_sub.c | 51 + src/bearssl/src/int/i32_tmont.c | 36 + src/bearssl/src/int/i62_modpow2.c | 493 ++ src/bearssl/src/kdf/hkdf.c | 107 + src/bearssl/src/mac/hmac.c | 122 + src/bearssl/src/mac/hmac_ct.c | 193 + src/bearssl/src/rand/aesctr_drbg.c | 206 + src/bearssl/src/rand/hmac_drbg.c | 157 + src/bearssl/src/rand/sysrng.c | 169 + src/bearssl/src/rsa/rsa_default_keygen.c | 38 + src/bearssl/src/rsa/rsa_default_modulus.c | 36 + .../src/rsa/rsa_default_oaep_decrypt.c | 38 + .../src/rsa/rsa_default_oaep_encrypt.c | 38 + src/bearssl/src/rsa/rsa_default_pkcs1_sign.c | 38 + src/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c | 38 + src/bearssl/src/rsa/rsa_default_priv.c | 38 + src/bearssl/src/rsa/rsa_default_privexp.c | 36 + src/bearssl/src/rsa/rsa_default_pub.c | 38 + src/bearssl/src/rsa/rsa_default_pubexp.c | 36 + src/bearssl/src/rsa/rsa_i15_keygen.c | 583 +++ src/bearssl/src/rsa/rsa_i15_modulus.c | 99 + src/bearssl/src/rsa/rsa_i15_oaep_decrypt.c | 41 + src/bearssl/src/rsa/rsa_i15_oaep_encrypt.c | 44 + src/bearssl/src/rsa/rsa_i15_pkcs1_sign.c | 37 + src/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c | 43 + src/bearssl/src/rsa/rsa_i15_priv.c | 209 + src/bearssl/src/rsa/rsa_i15_privexp.c | 320 ++ src/bearssl/src/rsa/rsa_i15_pub.c | 113 + src/bearssl/src/rsa/rsa_i15_pubexp.c | 152 + src/bearssl/src/rsa/rsa_i31_keygen.c | 37 + src/bearssl/src/rsa/rsa_i31_keygen_inner.c | 608 +++ src/bearssl/src/rsa/rsa_i31_modulus.c | 99 + src/bearssl/src/rsa/rsa_i31_oaep_decrypt.c | 41 + src/bearssl/src/rsa/rsa_i31_oaep_encrypt.c | 44 + src/bearssl/src/rsa/rsa_i31_pkcs1_sign.c | 37 + src/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c | 43 + src/bearssl/src/rsa/rsa_i31_priv.c | 203 + src/bearssl/src/rsa/rsa_i31_privexp.c | 318 ++ src/bearssl/src/rsa/rsa_i31_pub.c | 106 + src/bearssl/src/rsa/rsa_i31_pubexp.c | 152 + src/bearssl/src/rsa/rsa_i32_oaep_decrypt.c | 41 + src/bearssl/src/rsa/rsa_i32_oaep_encrypt.c | 44 + src/bearssl/src/rsa/rsa_i32_pkcs1_sign.c | 37 + src/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c | 43 + src/bearssl/src/rsa/rsa_i32_priv.c | 160 + src/bearssl/src/rsa/rsa_i32_pub.c | 77 + src/bearssl/src/rsa/rsa_i62_keygen.c | 57 + src/bearssl/src/rsa/rsa_i62_oaep_decrypt.c | 61 + src/bearssl/src/rsa/rsa_i62_oaep_encrypt.c | 64 + src/bearssl/src/rsa/rsa_i62_pkcs1_sign.c | 57 + src/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c | 63 + src/bearssl/src/rsa/rsa_i62_priv.c | 223 + src/bearssl/src/rsa/rsa_i62_pub.c | 125 + src/bearssl/src/rsa/rsa_oaep_pad.c | 112 + src/bearssl/src/rsa/rsa_oaep_unpad.c | 145 + src/bearssl/src/rsa/rsa_pkcs1_sig_pad.c | 100 + src/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c | 121 + src/bearssl/src/rsa/rsa_ssl_decrypt.c | 52 + src/bearssl/src/settings.c | 306 ++ src/bearssl/src/ssl/prf.c | 73 + src/bearssl/src/ssl/prf_md5sha1.c | 43 + src/bearssl/src/ssl/prf_sha256.c | 36 + src/bearssl/src/ssl/prf_sha384.c | 36 + src/bearssl/src/ssl/ssl_ccert_single_ec.c | 156 + src/bearssl/src/ssl/ssl_ccert_single_rsa.c | 149 + src/bearssl/src/ssl/ssl_client.c | 78 + .../src/ssl/ssl_client_default_rsapub.c | 32 + src/bearssl/src/ssl/ssl_client_full.c | 179 + src/bearssl/src/ssl/ssl_engine.c | 1569 ++++++ .../src/ssl/ssl_engine_default_aescbc.c | 64 + .../src/ssl/ssl_engine_default_aesccm.c | 67 + .../src/ssl/ssl_engine_default_aesgcm.c | 89 + .../src/ssl/ssl_engine_default_chapol.c | 65 + .../src/ssl/ssl_engine_default_descbc.c | 37 + src/bearssl/src/ssl/ssl_engine_default_ec.c | 36 + .../src/ssl/ssl_engine_default_ecdsa.c | 38 + .../src/ssl/ssl_engine_default_rsavrfy.c | 32 + src/bearssl/src/ssl/ssl_hashes.c | 46 + src/bearssl/src/ssl/ssl_hs_client.c | 1915 ++++++++ src/bearssl/src/ssl/ssl_hs_client.t0 | 1276 +++++ src/bearssl/src/ssl/ssl_hs_common.t0 | 1382 ++++++ src/bearssl/src/ssl/ssl_hs_server.c | 2009 ++++++++ src/bearssl/src/ssl/ssl_hs_server.t0 | 1510 ++++++ src/bearssl/src/ssl/ssl_io.c | 261 + src/bearssl/src/ssl/ssl_keyexport.c | 83 + src/bearssl/src/ssl/ssl_lru.c | 537 +++ src/bearssl/src/ssl/ssl_rec_cbc.c | 440 ++ src/bearssl/src/ssl/ssl_rec_ccm.c | 213 + src/bearssl/src/ssl/ssl_rec_chapol.c | 177 + src/bearssl/src/ssl/ssl_rec_gcm.c | 235 + src/bearssl/src/ssl/ssl_scert_single_ec.c | 142 + src/bearssl/src/ssl/ssl_scert_single_rsa.c | 162 + src/bearssl/src/ssl/ssl_server.c | 52 + src/bearssl/src/ssl/ssl_server_full_ec.c | 149 + src/bearssl/src/ssl/ssl_server_full_rsa.c | 132 + src/bearssl/src/ssl/ssl_server_mine2c.c | 71 + src/bearssl/src/ssl/ssl_server_mine2g.c | 71 + src/bearssl/src/ssl/ssl_server_minf2c.c | 71 + src/bearssl/src/ssl/ssl_server_minf2g.c | 71 + src/bearssl/src/ssl/ssl_server_minr2g.c | 70 + src/bearssl/src/ssl/ssl_server_minu2g.c | 70 + src/bearssl/src/ssl/ssl_server_minv2g.c | 70 + src/bearssl/src/symcipher/aes_big_cbcdec.c | 69 + src/bearssl/src/symcipher/aes_big_cbcenc.c | 67 + src/bearssl/src/symcipher/aes_big_ctr.c | 84 + src/bearssl/src/symcipher/aes_big_ctrcbc.c | 142 + src/bearssl/src/symcipher/aes_big_dec.c | 254 + src/bearssl/src/symcipher/aes_big_enc.c | 157 + src/bearssl/src/symcipher/aes_common.c | 112 + src/bearssl/src/symcipher/aes_ct.c | 328 ++ src/bearssl/src/symcipher/aes_ct64.c | 398 ++ src/bearssl/src/symcipher/aes_ct64_cbcdec.c | 104 + src/bearssl/src/symcipher/aes_ct64_cbcenc.c | 81 + src/bearssl/src/symcipher/aes_ct64_ctr.c | 114 + src/bearssl/src/symcipher/aes_ct64_ctrcbc.c | 433 ++ src/bearssl/src/symcipher/aes_ct64_dec.c | 159 + src/bearssl/src/symcipher/aes_ct64_enc.c | 115 + src/bearssl/src/symcipher/aes_ct_cbcdec.c | 111 + src/bearssl/src/symcipher/aes_ct_cbcenc.c | 91 + src/bearssl/src/symcipher/aes_ct_ctr.c | 116 + src/bearssl/src/symcipher/aes_ct_ctrcbc.c | 422 ++ src/bearssl/src/symcipher/aes_ct_dec.c | 170 + src/bearssl/src/symcipher/aes_ct_enc.c | 112 + src/bearssl/src/symcipher/aes_pwr8.c | 445 ++ src/bearssl/src/symcipher/aes_pwr8_cbcdec.c | 670 +++ src/bearssl/src/symcipher/aes_pwr8_cbcenc.c | 417 ++ src/bearssl/src/symcipher/aes_pwr8_ctr.c | 717 +++ src/bearssl/src/symcipher/aes_pwr8_ctrcbc.c | 946 ++++ src/bearssl/src/symcipher/aes_small_cbcdec.c | 69 + src/bearssl/src/symcipher/aes_small_cbcenc.c | 67 + src/bearssl/src/symcipher/aes_small_ctr.c | 84 + src/bearssl/src/symcipher/aes_small_ctrcbc.c | 142 + src/bearssl/src/symcipher/aes_small_dec.c | 176 + src/bearssl/src/symcipher/aes_small_enc.c | 129 + src/bearssl/src/symcipher/aes_x86ni.c | 240 + src/bearssl/src/symcipher/aes_x86ni_cbcdec.c | 223 + src/bearssl/src/symcipher/aes_x86ni_cbcenc.c | 122 + src/bearssl/src/symcipher/aes_x86ni_ctr.c | 211 + src/bearssl/src/symcipher/aes_x86ni_ctrcbc.c | 596 +++ src/bearssl/src/symcipher/chacha20_ct.c | 106 + src/bearssl/src/symcipher/chacha20_sse2.c | 237 + src/bearssl/src/symcipher/des_ct.c | 411 ++ src/bearssl/src/symcipher/des_ct_cbcdec.c | 87 + src/bearssl/src/symcipher/des_ct_cbcenc.c | 69 + src/bearssl/src/symcipher/des_support.c | 166 + src/bearssl/src/symcipher/des_tab.c | 310 ++ src/bearssl/src/symcipher/des_tab_cbcdec.c | 85 + src/bearssl/src/symcipher/des_tab_cbcenc.c | 67 + src/bearssl/src/symcipher/poly1305_ctmul.c | 260 + src/bearssl/src/symcipher/poly1305_ctmul32.c | 297 ++ src/bearssl/src/symcipher/poly1305_ctmulq.c | 475 ++ src/bearssl/src/symcipher/poly1305_i15.c | 221 + src/bearssl/src/x509/asn1.t0 | 757 +++ src/bearssl/src/x509/asn1enc.c | 93 + src/bearssl/src/x509/encode_ec_pk8der.c | 110 + src/bearssl/src/x509/encode_ec_rawder.c | 161 + src/bearssl/src/x509/encode_rsa_pk8der.c | 97 + src/bearssl/src/x509/encode_rsa_rawder.c | 96 + src/bearssl/src/x509/skey_decoder.c | 650 +++ src/bearssl/src/x509/skey_decoder.t0 | 373 ++ src/bearssl/src/x509/x509_decoder.c | 773 +++ src/bearssl/src/x509/x509_decoder.t0 | 321 ++ src/bearssl/src/x509/x509_knownkey.c | 105 + src/bearssl/src/x509/x509_minimal.c | 1713 +++++++ src/bearssl/src/x509/x509_minimal.t0 | 1508 ++++++ src/bearssl/src/x509/x509_minimal_full.c | 59 + 302 files changed, 77556 insertions(+) create mode 100644 SSLClient.h create mode 100644 bearssl.h create mode 100644 bearssl_aead.h create mode 100644 bearssl_block.h create mode 100644 bearssl_ec.h create mode 100644 bearssl_hash.h create mode 100644 bearssl_hmac.h create mode 100644 bearssl_kdf.h create mode 100644 bearssl_pem.h create mode 100644 bearssl_prf.h create mode 100644 bearssl_rand.h create mode 100644 bearssl_rsa.h create mode 100644 bearssl_ssl.h create mode 100644 bearssl_x509.h create mode 100644 config.h create mode 100644 inner.h rename src/keywords.txt => keywords.txt (100%) create mode 100644 src/bearssl/src/aead/ccm.c create mode 100644 src/bearssl/src/aead/eax.c create mode 100644 src/bearssl/src/aead/gcm.c create mode 100644 src/bearssl/src/codec/ccopy.c create mode 100644 src/bearssl/src/codec/dec16be.c create mode 100644 src/bearssl/src/codec/dec16le.c create mode 100644 src/bearssl/src/codec/dec32be.c create mode 100644 src/bearssl/src/codec/dec32le.c create mode 100644 src/bearssl/src/codec/dec64be.c create mode 100644 src/bearssl/src/codec/dec64le.c create mode 100644 src/bearssl/src/codec/enc16be.c create mode 100644 src/bearssl/src/codec/enc16le.c create mode 100644 src/bearssl/src/codec/enc32be.c create mode 100644 src/bearssl/src/codec/enc32le.c create mode 100644 src/bearssl/src/codec/enc64be.c create mode 100644 src/bearssl/src/codec/enc64le.c create mode 100644 src/bearssl/src/codec/pemdec.c create mode 100644 src/bearssl/src/codec/pemdec.t0 create mode 100644 src/bearssl/src/codec/pemenc.c create mode 100644 src/bearssl/src/ec/ec_all_m15.c create mode 100644 src/bearssl/src/ec/ec_all_m31.c create mode 100644 src/bearssl/src/ec/ec_c25519_i15.c create mode 100644 src/bearssl/src/ec/ec_c25519_i31.c create mode 100644 src/bearssl/src/ec/ec_c25519_m15.c create mode 100644 src/bearssl/src/ec/ec_c25519_m31.c create mode 100644 src/bearssl/src/ec/ec_curve25519.c create mode 100644 src/bearssl/src/ec/ec_default.c create mode 100644 src/bearssl/src/ec/ec_keygen.c create mode 100644 src/bearssl/src/ec/ec_p256_m15.c create mode 100644 src/bearssl/src/ec/ec_p256_m31.c create mode 100644 src/bearssl/src/ec/ec_prime_i15.c create mode 100644 src/bearssl/src/ec/ec_prime_i31.c create mode 100644 src/bearssl/src/ec/ec_pubkey.c create mode 100644 src/bearssl/src/ec/ec_secp256r1.c create mode 100644 src/bearssl/src/ec/ec_secp384r1.c create mode 100644 src/bearssl/src/ec/ec_secp521r1.c create mode 100644 src/bearssl/src/ec/ecdsa_atr.c create mode 100644 src/bearssl/src/ec/ecdsa_default_sign_asn1.c create mode 100644 src/bearssl/src/ec/ecdsa_default_sign_raw.c create mode 100644 src/bearssl/src/ec/ecdsa_default_vrfy_asn1.c create mode 100644 src/bearssl/src/ec/ecdsa_default_vrfy_raw.c create mode 100644 src/bearssl/src/ec/ecdsa_i15_bits.c create mode 100644 src/bearssl/src/ec/ecdsa_i15_sign_asn1.c create mode 100644 src/bearssl/src/ec/ecdsa_i15_sign_raw.c create mode 100644 src/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c create mode 100644 src/bearssl/src/ec/ecdsa_i15_vrfy_raw.c create mode 100644 src/bearssl/src/ec/ecdsa_i31_bits.c create mode 100644 src/bearssl/src/ec/ecdsa_i31_sign_asn1.c create mode 100644 src/bearssl/src/ec/ecdsa_i31_sign_raw.c create mode 100644 src/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c create mode 100644 src/bearssl/src/ec/ecdsa_i31_vrfy_raw.c create mode 100644 src/bearssl/src/ec/ecdsa_rta.c create mode 100644 src/bearssl/src/hash/dig_oid.c create mode 100644 src/bearssl/src/hash/dig_size.c create mode 100644 src/bearssl/src/hash/ghash_ctmul.c create mode 100644 src/bearssl/src/hash/ghash_ctmul32.c create mode 100644 src/bearssl/src/hash/ghash_ctmul64.c create mode 100644 src/bearssl/src/hash/ghash_pclmul.c create mode 100644 src/bearssl/src/hash/ghash_pwr8.c create mode 100644 src/bearssl/src/hash/md5.c create mode 100644 src/bearssl/src/hash/md5sha1.c create mode 100644 src/bearssl/src/hash/mgf1.c create mode 100644 src/bearssl/src/hash/multihash.c create mode 100644 src/bearssl/src/hash/sha1.c create mode 100644 src/bearssl/src/hash/sha2big.c create mode 100644 src/bearssl/src/hash/sha2small.c create mode 100644 src/bearssl/src/int/i15_add.c create mode 100644 src/bearssl/src/int/i15_bitlen.c create mode 100644 src/bearssl/src/int/i15_decmod.c create mode 100644 src/bearssl/src/int/i15_decode.c create mode 100644 src/bearssl/src/int/i15_decred.c create mode 100644 src/bearssl/src/int/i15_encode.c create mode 100644 src/bearssl/src/int/i15_fmont.c create mode 100644 src/bearssl/src/int/i15_iszero.c create mode 100644 src/bearssl/src/int/i15_moddiv.c create mode 100644 src/bearssl/src/int/i15_modpow.c create mode 100644 src/bearssl/src/int/i15_modpow2.c create mode 100644 src/bearssl/src/int/i15_montmul.c create mode 100644 src/bearssl/src/int/i15_mulacc.c create mode 100644 src/bearssl/src/int/i15_muladd.c create mode 100644 src/bearssl/src/int/i15_ninv15.c create mode 100644 src/bearssl/src/int/i15_reduce.c create mode 100644 src/bearssl/src/int/i15_rshift.c create mode 100644 src/bearssl/src/int/i15_sub.c create mode 100644 src/bearssl/src/int/i15_tmont.c create mode 100644 src/bearssl/src/int/i31_add.c create mode 100644 src/bearssl/src/int/i31_bitlen.c create mode 100644 src/bearssl/src/int/i31_decmod.c create mode 100644 src/bearssl/src/int/i31_decode.c create mode 100644 src/bearssl/src/int/i31_decred.c create mode 100644 src/bearssl/src/int/i31_encode.c create mode 100644 src/bearssl/src/int/i31_fmont.c create mode 100644 src/bearssl/src/int/i31_iszero.c create mode 100644 src/bearssl/src/int/i31_moddiv.c create mode 100644 src/bearssl/src/int/i31_modpow.c create mode 100644 src/bearssl/src/int/i31_modpow2.c create mode 100644 src/bearssl/src/int/i31_montmul.c create mode 100644 src/bearssl/src/int/i31_mulacc.c create mode 100644 src/bearssl/src/int/i31_muladd.c create mode 100644 src/bearssl/src/int/i31_ninv31.c create mode 100644 src/bearssl/src/int/i31_reduce.c create mode 100644 src/bearssl/src/int/i31_rshift.c create mode 100644 src/bearssl/src/int/i31_sub.c create mode 100644 src/bearssl/src/int/i31_tmont.c create mode 100644 src/bearssl/src/int/i32_add.c create mode 100644 src/bearssl/src/int/i32_bitlen.c create mode 100644 src/bearssl/src/int/i32_decmod.c create mode 100644 src/bearssl/src/int/i32_decode.c create mode 100644 src/bearssl/src/int/i32_decred.c create mode 100644 src/bearssl/src/int/i32_div32.c create mode 100644 src/bearssl/src/int/i32_encode.c create mode 100644 src/bearssl/src/int/i32_fmont.c create mode 100644 src/bearssl/src/int/i32_iszero.c create mode 100644 src/bearssl/src/int/i32_modpow.c create mode 100644 src/bearssl/src/int/i32_montmul.c create mode 100644 src/bearssl/src/int/i32_mulacc.c create mode 100644 src/bearssl/src/int/i32_muladd.c create mode 100644 src/bearssl/src/int/i32_ninv32.c create mode 100644 src/bearssl/src/int/i32_reduce.c create mode 100644 src/bearssl/src/int/i32_sub.c create mode 100644 src/bearssl/src/int/i32_tmont.c create mode 100644 src/bearssl/src/int/i62_modpow2.c create mode 100644 src/bearssl/src/kdf/hkdf.c create mode 100644 src/bearssl/src/mac/hmac.c create mode 100644 src/bearssl/src/mac/hmac_ct.c create mode 100644 src/bearssl/src/rand/aesctr_drbg.c create mode 100644 src/bearssl/src/rand/hmac_drbg.c create mode 100644 src/bearssl/src/rand/sysrng.c create mode 100644 src/bearssl/src/rsa/rsa_default_keygen.c create mode 100644 src/bearssl/src/rsa/rsa_default_modulus.c create mode 100644 src/bearssl/src/rsa/rsa_default_oaep_decrypt.c create mode 100644 src/bearssl/src/rsa/rsa_default_oaep_encrypt.c create mode 100644 src/bearssl/src/rsa/rsa_default_pkcs1_sign.c create mode 100644 src/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_default_priv.c create mode 100644 src/bearssl/src/rsa/rsa_default_privexp.c create mode 100644 src/bearssl/src/rsa/rsa_default_pub.c create mode 100644 src/bearssl/src/rsa/rsa_default_pubexp.c create mode 100644 src/bearssl/src/rsa/rsa_i15_keygen.c create mode 100644 src/bearssl/src/rsa/rsa_i15_modulus.c create mode 100644 src/bearssl/src/rsa/rsa_i15_oaep_decrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i15_oaep_encrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i15_pkcs1_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i15_priv.c create mode 100644 src/bearssl/src/rsa/rsa_i15_privexp.c create mode 100644 src/bearssl/src/rsa/rsa_i15_pub.c create mode 100644 src/bearssl/src/rsa/rsa_i15_pubexp.c create mode 100644 src/bearssl/src/rsa/rsa_i31_keygen.c create mode 100644 src/bearssl/src/rsa/rsa_i31_keygen_inner.c create mode 100644 src/bearssl/src/rsa/rsa_i31_modulus.c create mode 100644 src/bearssl/src/rsa/rsa_i31_oaep_decrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i31_oaep_encrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i31_pkcs1_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i31_priv.c create mode 100644 src/bearssl/src/rsa/rsa_i31_privexp.c create mode 100644 src/bearssl/src/rsa/rsa_i31_pub.c create mode 100644 src/bearssl/src/rsa/rsa_i31_pubexp.c create mode 100644 src/bearssl/src/rsa/rsa_i32_oaep_decrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i32_oaep_encrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i32_pkcs1_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i32_priv.c create mode 100644 src/bearssl/src/rsa/rsa_i32_pub.c create mode 100644 src/bearssl/src/rsa/rsa_i62_keygen.c create mode 100644 src/bearssl/src/rsa/rsa_i62_oaep_decrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i62_oaep_encrypt.c create mode 100644 src/bearssl/src/rsa/rsa_i62_pkcs1_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i62_priv.c create mode 100644 src/bearssl/src/rsa/rsa_i62_pub.c create mode 100644 src/bearssl/src/rsa/rsa_oaep_pad.c create mode 100644 src/bearssl/src/rsa/rsa_oaep_unpad.c create mode 100644 src/bearssl/src/rsa/rsa_pkcs1_sig_pad.c create mode 100644 src/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c create mode 100644 src/bearssl/src/rsa/rsa_ssl_decrypt.c create mode 100644 src/bearssl/src/settings.c create mode 100644 src/bearssl/src/ssl/prf.c create mode 100644 src/bearssl/src/ssl/prf_md5sha1.c create mode 100644 src/bearssl/src/ssl/prf_sha256.c create mode 100644 src/bearssl/src/ssl/prf_sha384.c create mode 100644 src/bearssl/src/ssl/ssl_ccert_single_ec.c create mode 100644 src/bearssl/src/ssl/ssl_ccert_single_rsa.c create mode 100644 src/bearssl/src/ssl/ssl_client.c create mode 100644 src/bearssl/src/ssl/ssl_client_default_rsapub.c create mode 100644 src/bearssl/src/ssl/ssl_client_full.c create mode 100644 src/bearssl/src/ssl/ssl_engine.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_aescbc.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_aesccm.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_aesgcm.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_chapol.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_descbc.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_ec.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_ecdsa.c create mode 100644 src/bearssl/src/ssl/ssl_engine_default_rsavrfy.c create mode 100644 src/bearssl/src/ssl/ssl_hashes.c create mode 100644 src/bearssl/src/ssl/ssl_hs_client.c create mode 100644 src/bearssl/src/ssl/ssl_hs_client.t0 create mode 100644 src/bearssl/src/ssl/ssl_hs_common.t0 create mode 100644 src/bearssl/src/ssl/ssl_hs_server.c create mode 100644 src/bearssl/src/ssl/ssl_hs_server.t0 create mode 100644 src/bearssl/src/ssl/ssl_io.c create mode 100644 src/bearssl/src/ssl/ssl_keyexport.c create mode 100644 src/bearssl/src/ssl/ssl_lru.c create mode 100644 src/bearssl/src/ssl/ssl_rec_cbc.c create mode 100644 src/bearssl/src/ssl/ssl_rec_ccm.c create mode 100644 src/bearssl/src/ssl/ssl_rec_chapol.c create mode 100644 src/bearssl/src/ssl/ssl_rec_gcm.c create mode 100644 src/bearssl/src/ssl/ssl_scert_single_ec.c create mode 100644 src/bearssl/src/ssl/ssl_scert_single_rsa.c create mode 100644 src/bearssl/src/ssl/ssl_server.c create mode 100644 src/bearssl/src/ssl/ssl_server_full_ec.c create mode 100644 src/bearssl/src/ssl/ssl_server_full_rsa.c create mode 100644 src/bearssl/src/ssl/ssl_server_mine2c.c create mode 100644 src/bearssl/src/ssl/ssl_server_mine2g.c create mode 100644 src/bearssl/src/ssl/ssl_server_minf2c.c create mode 100644 src/bearssl/src/ssl/ssl_server_minf2g.c create mode 100644 src/bearssl/src/ssl/ssl_server_minr2g.c create mode 100644 src/bearssl/src/ssl/ssl_server_minu2g.c create mode 100644 src/bearssl/src/ssl/ssl_server_minv2g.c create mode 100644 src/bearssl/src/symcipher/aes_big_cbcdec.c create mode 100644 src/bearssl/src/symcipher/aes_big_cbcenc.c create mode 100644 src/bearssl/src/symcipher/aes_big_ctr.c create mode 100644 src/bearssl/src/symcipher/aes_big_ctrcbc.c create mode 100644 src/bearssl/src/symcipher/aes_big_dec.c create mode 100644 src/bearssl/src/symcipher/aes_big_enc.c create mode 100644 src/bearssl/src/symcipher/aes_common.c create mode 100644 src/bearssl/src/symcipher/aes_ct.c create mode 100644 src/bearssl/src/symcipher/aes_ct64.c create mode 100644 src/bearssl/src/symcipher/aes_ct64_cbcdec.c create mode 100644 src/bearssl/src/symcipher/aes_ct64_cbcenc.c create mode 100644 src/bearssl/src/symcipher/aes_ct64_ctr.c create mode 100644 src/bearssl/src/symcipher/aes_ct64_ctrcbc.c create mode 100644 src/bearssl/src/symcipher/aes_ct64_dec.c create mode 100644 src/bearssl/src/symcipher/aes_ct64_enc.c create mode 100644 src/bearssl/src/symcipher/aes_ct_cbcdec.c create mode 100644 src/bearssl/src/symcipher/aes_ct_cbcenc.c create mode 100644 src/bearssl/src/symcipher/aes_ct_ctr.c create mode 100644 src/bearssl/src/symcipher/aes_ct_ctrcbc.c create mode 100644 src/bearssl/src/symcipher/aes_ct_dec.c create mode 100644 src/bearssl/src/symcipher/aes_ct_enc.c create mode 100644 src/bearssl/src/symcipher/aes_pwr8.c create mode 100644 src/bearssl/src/symcipher/aes_pwr8_cbcdec.c create mode 100644 src/bearssl/src/symcipher/aes_pwr8_cbcenc.c create mode 100644 src/bearssl/src/symcipher/aes_pwr8_ctr.c create mode 100644 src/bearssl/src/symcipher/aes_pwr8_ctrcbc.c create mode 100644 src/bearssl/src/symcipher/aes_small_cbcdec.c create mode 100644 src/bearssl/src/symcipher/aes_small_cbcenc.c create mode 100644 src/bearssl/src/symcipher/aes_small_ctr.c create mode 100644 src/bearssl/src/symcipher/aes_small_ctrcbc.c create mode 100644 src/bearssl/src/symcipher/aes_small_dec.c create mode 100644 src/bearssl/src/symcipher/aes_small_enc.c create mode 100644 src/bearssl/src/symcipher/aes_x86ni.c create mode 100644 src/bearssl/src/symcipher/aes_x86ni_cbcdec.c create mode 100644 src/bearssl/src/symcipher/aes_x86ni_cbcenc.c create mode 100644 src/bearssl/src/symcipher/aes_x86ni_ctr.c create mode 100644 src/bearssl/src/symcipher/aes_x86ni_ctrcbc.c create mode 100644 src/bearssl/src/symcipher/chacha20_ct.c create mode 100644 src/bearssl/src/symcipher/chacha20_sse2.c create mode 100644 src/bearssl/src/symcipher/des_ct.c create mode 100644 src/bearssl/src/symcipher/des_ct_cbcdec.c create mode 100644 src/bearssl/src/symcipher/des_ct_cbcenc.c create mode 100644 src/bearssl/src/symcipher/des_support.c create mode 100644 src/bearssl/src/symcipher/des_tab.c create mode 100644 src/bearssl/src/symcipher/des_tab_cbcdec.c create mode 100644 src/bearssl/src/symcipher/des_tab_cbcenc.c create mode 100644 src/bearssl/src/symcipher/poly1305_ctmul.c create mode 100644 src/bearssl/src/symcipher/poly1305_ctmul32.c create mode 100644 src/bearssl/src/symcipher/poly1305_ctmulq.c create mode 100644 src/bearssl/src/symcipher/poly1305_i15.c create mode 100644 src/bearssl/src/x509/asn1.t0 create mode 100644 src/bearssl/src/x509/asn1enc.c create mode 100644 src/bearssl/src/x509/encode_ec_pk8der.c create mode 100644 src/bearssl/src/x509/encode_ec_rawder.c create mode 100644 src/bearssl/src/x509/encode_rsa_pk8der.c create mode 100644 src/bearssl/src/x509/encode_rsa_rawder.c create mode 100644 src/bearssl/src/x509/skey_decoder.c create mode 100644 src/bearssl/src/x509/skey_decoder.t0 create mode 100644 src/bearssl/src/x509/x509_decoder.c create mode 100644 src/bearssl/src/x509/x509_decoder.t0 create mode 100644 src/bearssl/src/x509/x509_knownkey.c create mode 100644 src/bearssl/src/x509/x509_minimal.c create mode 100644 src/bearssl/src/x509/x509_minimal.t0 create mode 100644 src/bearssl/src/x509/x509_minimal_full.c diff --git a/SSLClient.h b/SSLClient.h new file mode 100644 index 0000000..bf50be5 --- /dev/null +++ b/SSLClient.h @@ -0,0 +1,42 @@ +/* Copyright 2019 OSU OPEnS Lab + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * SSLCLient.h + * + * This library was created to provide SSL functionality to the {@link https://learn.adafruit.com/adafruit-wiz5500-wiznet-ethernet-featherwing/overview} + * Adafruit Ethernet shield. Since this shield does not implement SSL functionality on + * its own, we need to use an external library: in this case BearSSL {@link https://bearssl.org/}, + * which is also use in the Arduino ESP8266 core. SSLClient will serve to implement the + * BearSSL functionality inbetween EthernetCLient and the User, such that the user will + * simply need to start with: + * SSLCLient client(ethCLient); + * And then call the functions they normally would with EthernetClient using SSLCLient. + */ + +#include "bearssl.h" + +#ifdef SSLClient_H_ +#define SSLClient_H_ + + + + +#endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/bearssl.h b/bearssl.h new file mode 100644 index 0000000..4f4797c --- /dev/null +++ b/bearssl.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_H__ +#define BR_BEARSSL_H__ + +#include +#include + +/** \mainpage BearSSL API + * + * # API Layout + * + * The functions and structures defined by the BearSSL API are located + * in various header files: + * + * | Header file | Elements | + * | :-------------- | :------------------------------------------------ | + * | bearssl_hash.h | Hash functions | + * | bearssl_hmac.h | HMAC | + * | bearssl_kdf.h | Key Derivation Functions | + * | bearssl_rand.h | Pseudorandom byte generators | + * | bearssl_prf.h | PRF implementations (for SSL/TLS) | + * | bearssl_block.h | Symmetric encryption | + * | bearssl_aead.h | AEAD algorithms (combined encryption + MAC) | + * | bearssl_rsa.h | RSA encryption and signatures | + * | bearssl_ec.h | Elliptic curves support (including ECDSA) | + * | bearssl_ssl.h | SSL/TLS engine interface | + * | bearssl_x509.h | X.509 certificate decoding and validation | + * | bearssl_pem.h | Base64/PEM decoding support functions | + * + * Applications using BearSSL are supposed to simply include `bearssl.h` + * as follows: + * + * #include + * + * The `bearssl.h` file itself includes all the other header files. It is + * possible to include specific header files, but it has no practical + * advantage for the application. The API is separated into separate + * header files only for documentation convenience. + * + * + * # Conventions + * + * ## MUST and SHALL + * + * In all descriptions, the usual "MUST", "SHALL", "MAY",... terminology + * is used. Failure to meet requirements expressed with a "MUST" or + * "SHALL" implies undefined behaviour, which means that segmentation + * faults, buffer overflows, and other similar adverse events, may occur. + * + * In general, BearSSL is not very forgiving of programming errors, and + * does not include much failsafes or error reporting when the problem + * does not arise from external transient conditions, and can be fixed + * only in the application code. This is done so in order to make the + * total code footprint lighter. + * + * + * ## `NULL` values + * + * Function parameters with a pointer type shall not be `NULL` unless + * explicitly authorised by the documentation. As an exception, when + * the pointer aims at a sequence of bytes and is accompanied with + * a length parameter, and the length is zero (meaning that there is + * no byte at all to retrieve), then the pointer may be `NULL` even if + * not explicitly allowed. + * + * + * ## Memory Allocation + * + * BearSSL does not perform dynamic memory allocation. This implies that + * for any functionality that requires a non-transient state, the caller + * is responsible for allocating the relevant context structure. Such + * allocation can be done in any appropriate area, including static data + * segments, the heap, and the stack, provided that proper alignment is + * respected. The header files define these context structures + * (including size and contents), so the C compiler should handle + * alignment automatically. + * + * Since there is no dynamic resource allocation, there is also nothing to + * release. When the calling code is done with a BearSSL feature, it + * may simple release the context structures it allocated itself, with + * no "close function" to call. If the context structures were allocated + * on the stack (as local variables), then even that release operation is + * implicit. + * + * + * ## Structure Contents + * + * Except when explicitly indicated, structure contents are opaque: they + * are included in the header files so that calling code may know the + * structure sizes and alignment requirements, but callers SHALL NOT + * access individual fields directly. For fields that are supposed to + * be read from or written to, the API defines accessor functions (the + * simplest of these accessor functions are defined as `static inline` + * functions, and the C compiler will optimise them away). + * + * + * # API Usage + * + * BearSSL usage for running a SSL/TLS client or server is described + * on the [BearSSL Web site](https://www.bearssl.org/api1.html). The + * BearSSL source archive also comes with sample code. + */ + +#include "bearssl_hash.h" +#include "bearssl_hmac.h" +#include "bearssl_kdf.h" +#include "bearssl_rand.h" +#include "bearssl_prf.h" +#include "bearssl_block.h" +#include "bearssl_aead.h" +#include "bearssl_rsa.h" +#include "bearssl_ec.h" +#include "bearssl_ssl.h" +#include "bearssl_x509.h" +#include "bearssl_pem.h" + +/** \brief Type for a configuration option. + * + * A "configuration option" is a value that is selected when the BearSSL + * library itself is compiled. Most options are boolean; their value is + * then either 1 (option is enabled) or 0 (option is disabled). Some + * values have other integer values. Option names correspond to macro + * names. Some of the options can be explicitly set in the internal + * `"config.h"` file. + */ +typedef struct { + /** \brief Configurable option name. */ + const char *name; + /** \brief Configurable option value. */ + long value; +} br_config_option; + +/** \brief Get configuration report. + * + * This function returns compiled configuration options, each as a + * 'long' value. Names match internal macro names, in particular those + * that can be set in the `"config.h"` inner file. For boolean options, + * the numerical value is 1 if enabled, 0 if disabled. For maximum + * key sizes, values are expressed in bits. + * + * The returned array is terminated by an entry whose `name` is `NULL`. + * + * \return the configuration report. + */ +const br_config_option *br_get_config(void); + +#endif diff --git a/bearssl_aead.h b/bearssl_aead.h new file mode 100644 index 0000000..8e35a1f --- /dev/null +++ b/bearssl_aead.h @@ -0,0 +1,1059 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_AEAD_H__ +#define BR_BEARSSL_AEAD_H__ + +#include +#include + +#include "bearssl_block.h" +#include "bearssl_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_aead.h + * + * # Authenticated Encryption with Additional Data + * + * This file documents the API for AEAD encryption. + * + * + * ## Procedural API + * + * An AEAD algorithm processes messages and provides confidentiality + * (encryption) and checked integrity (MAC). It uses the following + * parameters: + * + * - A symmetric key. Exact size depends on the AEAD algorithm. + * + * - A nonce (IV). Size depends on the AEAD algorithm; for most + * algorithms, it is crucial for security that any given nonce + * value is never used twice for the same key and distinct + * messages. + * + * - Data to encrypt and protect. + * + * - Additional authenticated data, which is covered by the MAC but + * otherwise left untouched (i.e. not encrypted). + * + * The AEAD algorithm encrypts the data, and produces an authentication + * tag. It is assumed that the encrypted data, the tag, the additional + * authenticated data and the nonce are sent to the receiver; the + * additional data and the nonce may be implicit (e.g. using elements of + * the underlying transport protocol, such as record sequence numbers). + * The receiver will recompute the tag value and compare it with the one + * received; if they match, then the data is correct, and can be + * decrypted and used; otherwise, at least one of the elements was + * altered in transit, normally leading to wholesale rejection of the + * complete message. + * + * For each AEAD algorithm, identified by a symbolic name (hereafter + * denoted as "`xxx`"), the following functions are defined: + * + * - `br_xxx_init()` + * + * Initialise the AEAD algorithm, on a provided context structure. + * Exact parameters depend on the algorithm, and may include + * pointers to extra implementations and context structures. The + * secret key is provided at this point, either directly or + * indirectly. + * + * - `br_xxx_reset()` + * + * Start a new AEAD computation. The nonce value is provided as + * parameter to this function. + * + * - `br_xxx_aad_inject()` + * + * Inject some additional authenticated data. Additional data may + * be provided in several chunks of arbitrary length. + * + * - `br_xxx_flip()` + * + * This function MUST be called after injecting all additional + * authenticated data, and before beginning to encrypt the plaintext + * (or decrypt the ciphertext). + * + * - `br_xxx_run()` + * + * Process some plaintext (to encrypt) or ciphertext (to decrypt). + * Encryption/decryption is done in place. Data may be provided in + * several chunks of arbitrary length. + * + * - `br_xxx_get_tag()` + * + * Compute the authentication tag. All message data (encrypted or + * decrypted) must have been injected at that point. Also, this + * call may modify internal context elements, so it may be called + * only once for a given AEAD computation. + * + * - `br_xxx_check_tag()` + * + * An alternative to `br_xxx_get_tag()`, meant to be used by the + * receiver: the authentication tag is internally recomputed, and + * compared with the one provided as parameter. + * + * This API makes the following assumptions on the AEAD algorithm: + * + * - Encryption does not expand the size of the ciphertext; there is + * no padding. This is true of most modern AEAD modes such as GCM. + * + * - The additional authenticated data must be processed first, + * before the encrypted/decrypted data. + * + * - Nonce, plaintext and additional authenticated data all consist + * in an integral number of bytes. There is no provision to use + * elements whose length in bits is not a multiple of 8. + * + * Each AEAD algorithm has its own requirements and limits on the sizes + * of additional data and plaintext. This API does not provide any + * way to report invalid usage; it is up to the caller to ensure that + * the provided key, nonce, and data elements all fit the algorithm's + * requirements. + * + * + * ## Object-Oriented API + * + * Each context structure begins with a field (called `vtable`) that + * points to an instance of a structure that references the relevant + * functions through pointers. Each such structure contains the + * following: + * + * - `reset` + * + * Pointer to the reset function, that allows starting a new + * computation. + * + * - `aad_inject` + * + * Pointer to the additional authenticated data injection function. + * + * - `flip` + * + * Pointer to the function that transitions from additional data + * to main message data processing. + * + * - `get_tag` + * + * Pointer to the function that computes and returns the tag. + * + * - `check_tag` + * + * Pointer to the function that computes and verifies the tag against + * a received value. + * + * Note that there is no OOP method for context initialisation: the + * various AEAD algorithms have different requirements that would not + * map well to a single initialisation API. + * + * The OOP API is not provided for CCM, due to its specific requirements + * (length of plaintext must be known in advance). + */ + +/** + * \brief Class type of an AEAD algorithm. + */ +typedef struct br_aead_class_ br_aead_class; +struct br_aead_class_ { + + /** + * \brief Size (in bytes) of authentication tags created by + * this AEAD algorithm. + */ + size_t tag_size; + + /** + * \brief Reset an AEAD context. + * + * This function resets an already initialised AEAD context for + * a new computation run. Implementations and keys are + * conserved. This function can be called at any time; it + * cancels any ongoing AEAD computation that uses the provided + * context structure. + + * The provided IV is a _nonce_. Each AEAD algorithm has its + * own requirements on IV size and contents; for most of them, + * it is crucial to security that each nonce value is used + * only once for a given secret key. + * + * \param cc AEAD context structure. + * \param iv AEAD nonce to use. + * \param len AEAD nonce length (in bytes). + */ + void (*reset)(const br_aead_class **cc, const void *iv, size_t len); + + /** + * \brief Inject additional authenticated data. + * + * The provided data is injected into a running AEAD + * computation. Additional data must be injected _before_ the + * call to `flip()`. Additional data can be injected in several + * chunks of arbitrary length. + * + * \param cc AEAD context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ + void (*aad_inject)(const br_aead_class **cc, + const void *data, size_t len); + + /** + * \brief Finish injection of additional authenticated data. + * + * This function MUST be called before beginning the actual + * encryption or decryption (with `run()`), even if no + * additional authenticated data was injected. No additional + * authenticated data may be injected after this function call. + * + * \param cc AEAD context structure. + */ + void (*flip)(const br_aead_class **cc); + + /** + * \brief Encrypt or decrypt some data. + * + * Data encryption or decryption can be done after `flip()` has + * been called on the context. If `encrypt` is non-zero, then + * the provided data shall be plaintext, and it is encrypted in + * place. Otherwise, the data shall be ciphertext, and it is + * decrypted in place. + * + * Data may be provided in several chunks of arbitrary length. + * + * \param cc AEAD context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ + void (*run)(const br_aead_class **cc, int encrypt, + void *data, size_t len); + + /** + * \brief Compute authentication tag. + * + * Compute the AEAD authentication tag. The tag length depends + * on the AEAD algorithm; it is written in the provided `tag` + * buffer. This call terminates the AEAD run: no data may be + * processed with that AEAD context afterwards, until `reset()` + * is called to initiate a new AEAD run. + * + * The tag value must normally be sent along with the encrypted + * data. When decrypting, the tag value must be recomputed and + * compared with the received tag: if the two tag values differ, + * then either the tag or the encrypted data was altered in + * transit. As an alternative to this function, the + * `check_tag()` function may be used to compute and check the + * tag value. + * + * Tag length depends on the AEAD algorithm. + * + * \param cc AEAD context structure. + * \param tag destination buffer for the tag. + */ + void (*get_tag)(const br_aead_class **cc, void *tag); + + /** + * \brief Compute and check authentication tag. + * + * This function is an alternative to `get_tag()`, and is + * normally used on the receiving end (i.e. when decrypting + * messages). The tag value is recomputed and compared with the + * provided tag value. If they match, 1 is returned; on + * mismatch, 0 is returned. A returned value of 0 means that the + * data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * Tag length depends on the AEAD algorithm. + * + * \param cc AEAD context structure. + * \param tag tag value to compare with. + * \return 1 on success (exact match of tag value), 0 otherwise. + */ + uint32_t (*check_tag)(const br_aead_class **cc, const void *tag); + + /** + * \brief Compute authentication tag (with truncation). + * + * This function is similar to `get_tag()`, except that the tag + * length is provided. Some AEAD algorithms allow several tag + * lengths, usually by truncating the normal tag. Shorter tags + * mechanically increase success probability of forgeries. + * The range of allowed tag lengths depends on the algorithm. + * + * \param cc AEAD context structure. + * \param tag destination buffer for the tag. + * \param len tag length (in bytes). + */ + void (*get_tag_trunc)(const br_aead_class **cc, void *tag, size_t len); + + /** + * \brief Compute and check authentication tag (with truncation). + * + * This function is similar to `check_tag()` except that it + * works over an explicit tag length. See `get_tag()` for a + * discussion of explicit tag lengths; the range of allowed tag + * lengths depends on the algorithm. + * + * \param cc AEAD context structure. + * \param tag tag value to compare with. + * \param len tag length (in bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ + uint32_t (*check_tag_trunc)(const br_aead_class **cc, + const void *tag, size_t len); +}; + +/** + * \brief Context structure for GCM. + * + * GCM is an AEAD mode that combines a block cipher in CTR mode with a + * MAC based on GHASH, to provide authenticated encryption: + * + * - Any block cipher with 16-byte blocks can be used with GCM. + * + * - The nonce can have any length, from 0 up to 2^64-1 bits; however, + * 96-bit nonces (12 bytes) are recommended (nonces with a length + * distinct from 12 bytes are internally hashed, which risks reusing + * nonce value with a small but not always negligible probability). + * + * - Additional authenticated data may have length up to 2^64-1 bits. + * + * - Message length may range up to 2^39-256 bits at most. + * + * - The authentication tag has length 16 bytes. + * + * The GCM initialisation function receives as parameter an + * _initialised_ block cipher implementation context, with the secret + * key already set. A pointer to that context will be kept within the + * GCM context structure. It is up to the caller to allocate and + * initialise that block cipher context. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_aead_class *vtable; + +#ifndef BR_DOXYGEN_IGNORE + const br_block_ctr_class **bctx; + br_ghash gh; + unsigned char h[16]; + unsigned char j0_1[12]; + unsigned char buf[16]; + unsigned char y[16]; + uint32_t j0_2, jc; + uint64_t count_aad, count_ctr; +#endif +} br_gcm_context; + +/** + * \brief Initialize a GCM context. + * + * A block cipher implementation, with its initialised context structure, + * is provided. The block cipher MUST use 16-byte blocks in CTR mode, + * and its secret key MUST have been already set in the provided context. + * A GHASH implementation must also be provided. The parameters are linked + * in the GCM context. + * + * After this function has been called, the `br_gcm_reset()` function must + * be called, to provide the IV for GCM computation. + * + * \param ctx GCM context structure. + * \param bctx block cipher context (already initialised with secret key). + * \param gh GHASH implementation. + */ +void br_gcm_init(br_gcm_context *ctx, + const br_block_ctr_class **bctx, br_ghash gh); + +/** + * \brief Reset a GCM context. + * + * This function resets an already initialised GCM context for a new + * computation run. Implementations and keys are conserved. This function + * can be called at any time; it cancels any ongoing GCM computation that + * uses the provided context structure. + * + * The provided IV is a _nonce_. It is critical to GCM security that IV + * values are not repeated for the same encryption key. IV can have + * arbitrary length (up to 2^64-1 bits), but the "normal" length is + * 96 bits (12 bytes). + * + * \param ctx GCM context structure. + * \param iv GCM nonce to use. + * \param len GCM nonce length (in bytes). + */ +void br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len); + +/** + * \brief Inject additional authenticated data into GCM. + * + * The provided data is injected into a running GCM computation. Additional + * data must be injected _before_ the call to `br_gcm_flip()`. + * Additional data can be injected in several chunks of arbitrary length; + * the maximum total size of additional authenticated data is 2^64-1 + * bits. + * + * \param ctx GCM context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ +void br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len); + +/** + * \brief Finish injection of additional authenticated data into GCM. + * + * This function MUST be called before beginning the actual encryption + * or decryption (with `br_gcm_run()`), even if no additional authenticated + * data was injected. No additional authenticated data may be injected + * after this function call. + * + * \param ctx GCM context structure. + */ +void br_gcm_flip(br_gcm_context *ctx); + +/** + * \brief Encrypt or decrypt some data with GCM. + * + * Data encryption or decryption can be done after `br_gcm_flip()` + * has been called on the context. If `encrypt` is non-zero, then the + * provided data shall be plaintext, and it is encrypted in place. + * Otherwise, the data shall be ciphertext, and it is decrypted in place. + * + * Data may be provided in several chunks of arbitrary length. The maximum + * total length for data is 2^39-256 bits, i.e. about 65 gigabytes. + * + * \param ctx GCM context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +void br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len); + +/** + * \brief Compute GCM authentication tag. + * + * Compute the GCM authentication tag. The tag is a 16-byte value which + * is written in the provided `tag` buffer. This call terminates the + * GCM run: no data may be processed with that GCM context afterwards, + * until `br_gcm_reset()` is called to initiate a new GCM run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_gcm_check_tag()` function can be used to + * compute and check the tag value. + * + * \param ctx GCM context structure. + * \param tag destination buffer for the tag (16 bytes). + */ +void br_gcm_get_tag(br_gcm_context *ctx, void *tag); + +/** + * \brief Compute and check GCM authentication tag. + * + * This function is an alternative to `br_gcm_get_tag()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * \param ctx GCM context structure. + * \param tag tag value to compare with (16 bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_gcm_check_tag(br_gcm_context *ctx, const void *tag); + +/** + * \brief Compute GCM authentication tag (with truncation). + * + * This function is similar to `br_gcm_get_tag()`, except that it allows + * the tag to be truncated to a smaller length. The intended tag length + * is provided as `len` (in bytes); it MUST be no more than 16, but + * it may be smaller. Note that decreasing tag length mechanically makes + * forgeries easier; NIST SP 800-38D specifies that the tag length shall + * lie between 12 and 16 bytes (inclusive), but may be truncated down to + * 4 or 8 bytes, for specific applications that can tolerate it. It must + * also be noted that successful forgeries leak information on the + * authentication key, making subsequent forgeries easier. Therefore, + * tag truncation, and in particular truncation to sizes lower than 12 + * bytes, shall be envisioned only with great care. + * + * The tag is written in the provided `tag` buffer. This call terminates + * the GCM run: no data may be processed with that GCM context + * afterwards, until `br_gcm_reset()` is called to initiate a new GCM + * run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_gcm_check_tag_trunc()` function can be used to + * compute and check the tag value. + * + * \param ctx GCM context structure. + * \param tag destination buffer for the tag. + * \param len tag length (16 bytes or less). + */ +void br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len); + +/** + * \brief Compute and check GCM authentication tag (with truncation). + * + * This function is an alternative to `br_gcm_get_tag_trunc()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * Tag length MUST be 16 bytes or less. The normal GCM tag length is 16 + * bytes. See `br_check_tag_trunc()` for some discussion on the potential + * perils of truncating authentication tags. + * + * \param ctx GCM context structure. + * \param tag tag value to compare with. + * \param len tag length (in bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_gcm_check_tag_trunc(br_gcm_context *ctx, + const void *tag, size_t len); + +/** + * \brief Class instance for GCM. + */ +extern const br_aead_class br_gcm_vtable; + +/** + * \brief Context structure for EAX. + * + * EAX is an AEAD mode that combines a block cipher in CTR mode with + * CBC-MAC using the same block cipher and the same key, to provide + * authenticated encryption: + * + * - Any block cipher with 16-byte blocks can be used with EAX + * (technically, other block sizes are defined as well, but this + * is not implemented by these functions; shorter blocks also + * imply numerous security issues). + * + * - The nonce can have any length, as long as nonce values are + * not reused (thus, if nonces are randomly selected, the nonce + * size should be such that reuse probability is negligible). + * + * - Additional authenticated data length is unlimited. + * + * - Message length is unlimited. + * + * - The authentication tag has length 16 bytes. + * + * The EAX initialisation function receives as parameter an + * _initialised_ block cipher implementation context, with the secret + * key already set. A pointer to that context will be kept within the + * EAX context structure. It is up to the caller to allocate and + * initialise that block cipher context. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_aead_class *vtable; + +#ifndef BR_DOXYGEN_IGNORE + const br_block_ctrcbc_class **bctx; + unsigned char L2[16]; + unsigned char L4[16]; + unsigned char nonce[16]; + unsigned char head[16]; + unsigned char ctr[16]; + unsigned char cbcmac[16]; + unsigned char buf[16]; + size_t ptr; +#endif +} br_eax_context; + +/** + * \brief EAX captured state. + * + * Some internal values computed by EAX may be captured at various + * points, and reused for another EAX run with the same secret key, + * for lower per-message overhead. Captured values do not depend on + * the nonce. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + unsigned char st[3][16]; +#endif +} br_eax_state; + +/** + * \brief Initialize an EAX context. + * + * A block cipher implementation, with its initialised context + * structure, is provided. The block cipher MUST use 16-byte blocks in + * CTR + CBC-MAC mode, and its secret key MUST have been already set in + * the provided context. The parameters are linked in the EAX context. + * + * After this function has been called, the `br_eax_reset()` function must + * be called, to provide the nonce for EAX computation. + * + * \param ctx EAX context structure. + * \param bctx block cipher context (already initialised with secret key). + */ +void br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx); + +/** + * \brief Capture pre-AAD state. + * + * This function precomputes key-dependent data, and stores it in the + * provided `st` structure. This structure should then be used with + * `br_eax_reset_pre_aad()`, or updated with `br_eax_get_aad_mac()` + * and then used with `br_eax_reset_post_aad()`. + * + * The EAX context structure is unmodified by this call. + * + * \param ctx EAX context structure. + * \param st recipient for captured state. + */ +void br_eax_capture(const br_eax_context *ctx, br_eax_state *st); + +/** + * \brief Reset an EAX context. + * + * This function resets an already initialised EAX context for a new + * computation run. Implementations and keys are conserved. This function + * can be called at any time; it cancels any ongoing EAX computation that + * uses the provided context structure. + * + * It is critical to EAX security that nonce values are not repeated for + * the same encryption key. Nonces can have arbitrary length. If nonces + * are randomly generated, then a nonce length of at least 128 bits (16 + * bytes) is recommended, to make nonce reuse probability sufficiently + * low. + * + * \param ctx EAX context structure. + * \param nonce EAX nonce to use. + * \param len EAX nonce length (in bytes). + */ +void br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len); + +/** + * \brief Reset an EAX context with a pre-AAD captured state. + * + * This function is an alternative to `br_eax_reset()`, that reuses a + * previously captured state structure for lower per-message overhead. + * The state should have been populated with `br_eax_capture_state()` + * but not updated with `br_eax_get_aad_mac()`. + * + * After this function is called, additional authenticated data MUST + * be injected. At least one byte of additional authenticated data + * MUST be provided with `br_eax_aad_inject()`; computation result will + * be incorrect if `br_eax_flip()` is called right away. + * + * After injection of the AAD and call to `br_eax_flip()`, at least + * one message byte must be provided. Empty messages are not supported + * with this reset mode. + * + * \param ctx EAX context structure. + * \param st pre-AAD captured state. + * \param nonce EAX nonce to use. + * \param len EAX nonce length (in bytes). + */ +void br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st, + const void *nonce, size_t len); + +/** + * \brief Reset an EAX context with a post-AAD captured state. + * + * This function is an alternative to `br_eax_reset()`, that reuses a + * previously captured state structure for lower per-message overhead. + * The state should have been populated with `br_eax_capture_state()` + * and then updated with `br_eax_get_aad_mac()`. + * + * After this function is called, message data MUST be injected. The + * `br_eax_flip()` function MUST NOT be called. At least one byte of + * message data MUST be provided with `br_eax_run()`; empty messages + * are not supported with this reset mode. + * + * \param ctx EAX context structure. + * \param st post-AAD captured state. + * \param nonce EAX nonce to use. + * \param len EAX nonce length (in bytes). + */ +void br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st, + const void *nonce, size_t len); + +/** + * \brief Inject additional authenticated data into EAX. + * + * The provided data is injected into a running EAX computation. Additional + * data must be injected _before_ the call to `br_eax_flip()`. + * Additional data can be injected in several chunks of arbitrary length; + * the total amount of additional authenticated data is unlimited. + * + * \param ctx EAX context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ +void br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len); + +/** + * \brief Finish injection of additional authenticated data into EAX. + * + * This function MUST be called before beginning the actual encryption + * or decryption (with `br_eax_run()`), even if no additional authenticated + * data was injected. No additional authenticated data may be injected + * after this function call. + * + * \param ctx EAX context structure. + */ +void br_eax_flip(br_eax_context *ctx); + +/** + * \brief Obtain a copy of the MAC on additional authenticated data. + * + * This function may be called only after `br_eax_flip()`; it copies the + * AAD-specific MAC value into the provided state. The MAC value depends + * on the secret key and the additional data itself, but not on the + * nonce. The updated state `st` is meant to be used as parameter for a + * further `br_eax_reset_post_aad()` call. + * + * \param ctx EAX context structure. + * \param st captured state to update. + */ +static inline void +br_eax_get_aad_mac(const br_eax_context *ctx, br_eax_state *st) +{ + memcpy(st->st[1], ctx->head, sizeof ctx->head); +} + +/** + * \brief Encrypt or decrypt some data with EAX. + * + * Data encryption or decryption can be done after `br_eax_flip()` + * has been called on the context. If `encrypt` is non-zero, then the + * provided data shall be plaintext, and it is encrypted in place. + * Otherwise, the data shall be ciphertext, and it is decrypted in place. + * + * Data may be provided in several chunks of arbitrary length. + * + * \param ctx EAX context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +void br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len); + +/** + * \brief Compute EAX authentication tag. + * + * Compute the EAX authentication tag. The tag is a 16-byte value which + * is written in the provided `tag` buffer. This call terminates the + * EAX run: no data may be processed with that EAX context afterwards, + * until `br_eax_reset()` is called to initiate a new EAX run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_eax_check_tag()` function can be used to + * compute and check the tag value. + * + * \param ctx EAX context structure. + * \param tag destination buffer for the tag (16 bytes). + */ +void br_eax_get_tag(br_eax_context *ctx, void *tag); + +/** + * \brief Compute and check EAX authentication tag. + * + * This function is an alternative to `br_eax_get_tag()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * \param ctx EAX context structure. + * \param tag tag value to compare with (16 bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_eax_check_tag(br_eax_context *ctx, const void *tag); + +/** + * \brief Compute EAX authentication tag (with truncation). + * + * This function is similar to `br_eax_get_tag()`, except that it allows + * the tag to be truncated to a smaller length. The intended tag length + * is provided as `len` (in bytes); it MUST be no more than 16, but + * it may be smaller. Note that decreasing tag length mechanically makes + * forgeries easier; NIST SP 800-38D specifies that the tag length shall + * lie between 12 and 16 bytes (inclusive), but may be truncated down to + * 4 or 8 bytes, for specific applications that can tolerate it. It must + * also be noted that successful forgeries leak information on the + * authentication key, making subsequent forgeries easier. Therefore, + * tag truncation, and in particular truncation to sizes lower than 12 + * bytes, shall be envisioned only with great care. + * + * The tag is written in the provided `tag` buffer. This call terminates + * the EAX run: no data may be processed with that EAX context + * afterwards, until `br_eax_reset()` is called to initiate a new EAX + * run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_eax_check_tag_trunc()` function can be used to + * compute and check the tag value. + * + * \param ctx EAX context structure. + * \param tag destination buffer for the tag. + * \param len tag length (16 bytes or less). + */ +void br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len); + +/** + * \brief Compute and check EAX authentication tag (with truncation). + * + * This function is an alternative to `br_eax_get_tag_trunc()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * Tag length MUST be 16 bytes or less. The normal EAX tag length is 16 + * bytes. See `br_check_tag_trunc()` for some discussion on the potential + * perils of truncating authentication tags. + * + * \param ctx EAX context structure. + * \param tag tag value to compare with. + * \param len tag length (in bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_eax_check_tag_trunc(br_eax_context *ctx, + const void *tag, size_t len); + +/** + * \brief Class instance for EAX. + */ +extern const br_aead_class br_eax_vtable; + +/** + * \brief Context structure for CCM. + * + * CCM is an AEAD mode that combines a block cipher in CTR mode with + * CBC-MAC using the same block cipher and the same key, to provide + * authenticated encryption: + * + * - Any block cipher with 16-byte blocks can be used with CCM + * (technically, other block sizes are defined as well, but this + * is not implemented by these functions; shorter blocks also + * imply numerous security issues). + * + * - The authentication tag length, and plaintext length, MUST be + * known when starting processing data. Plaintext and ciphertext + * can still be provided by chunks, but the total size must match + * the value provided upon initialisation. + * + * - The nonce length is constrained between 7 and 13 bytes (inclusive). + * Furthermore, the plaintext length, when encoded, must fit over + * 15-nonceLen bytes; thus, if the nonce has length 13 bytes, then + * the plaintext length cannot exceed 65535 bytes. + * + * - Additional authenticated data length is practically unlimited + * (formal limit is at 2^64 bytes). + * + * - The authentication tag has length 4 to 16 bytes (even values only). + * + * The CCM initialisation function receives as parameter an + * _initialised_ block cipher implementation context, with the secret + * key already set. A pointer to that context will be kept within the + * CCM context structure. It is up to the caller to allocate and + * initialise that block cipher context. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + const br_block_ctrcbc_class **bctx; + unsigned char ctr[16]; + unsigned char cbcmac[16]; + unsigned char tagmask[16]; + unsigned char buf[16]; + size_t ptr; + size_t tag_len; +#endif +} br_ccm_context; + +/** + * \brief Initialize a CCM context. + * + * A block cipher implementation, with its initialised context + * structure, is provided. The block cipher MUST use 16-byte blocks in + * CTR + CBC-MAC mode, and its secret key MUST have been already set in + * the provided context. The parameters are linked in the CCM context. + * + * After this function has been called, the `br_ccm_reset()` function must + * be called, to provide the nonce for CCM computation. + * + * \param ctx CCM context structure. + * \param bctx block cipher context (already initialised with secret key). + */ +void br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx); + +/** + * \brief Reset a CCM context. + * + * This function resets an already initialised CCM context for a new + * computation run. Implementations and keys are conserved. This function + * can be called at any time; it cancels any ongoing CCM computation that + * uses the provided context structure. + * + * The `aad_len` parameter contains the total length, in bytes, of the + * additional authenticated data. It may be zero. That length MUST be + * exact. + * + * The `data_len` parameter contains the total length, in bytes, of the + * data that will be injected (plaintext or ciphertext). That length MUST + * be exact. Moreover, that length MUST be less than 2^(8*(15-nonce_len)). + * + * The nonce length (`nonce_len`), in bytes, must be in the 7..13 range + * (inclusive). + * + * The tag length (`tag_len`), in bytes, must be in the 4..16 range, and + * be an even integer. Short tags mechanically allow for higher forgery + * probabilities; hence, tag sizes smaller than 12 bytes shall be used only + * with care. + * + * It is critical to CCM security that nonce values are not repeated for + * the same encryption key. Random generation of nonces is not generally + * recommended, due to the relatively small maximum nonce value. + * + * Returned value is 1 on success, 0 on error. An error is reported if + * the tag or nonce length is out of range, or if the + * plaintext/ciphertext length cannot be encoded with the specified + * nonce length. + * + * \param ctx CCM context structure. + * \param nonce CCM nonce to use. + * \param nonce_len CCM nonce length (in bytes, 7 to 13). + * \param aad_len additional authenticated data length (in bytes). + * \param data_len plaintext/ciphertext length (in bytes). + * \param tag_len tag length (in bytes). + * \return 1 on success, 0 on error. + */ +int br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len, + uint64_t aad_len, uint64_t data_len, size_t tag_len); + +/** + * \brief Inject additional authenticated data into CCM. + * + * The provided data is injected into a running CCM computation. Additional + * data must be injected _before_ the call to `br_ccm_flip()`. + * Additional data can be injected in several chunks of arbitrary length, + * but the total amount MUST exactly match the value which was provided + * to `br_ccm_reset()`. + * + * \param ctx CCM context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ +void br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len); + +/** + * \brief Finish injection of additional authenticated data into CCM. + * + * This function MUST be called before beginning the actual encryption + * or decryption (with `br_ccm_run()`), even if no additional authenticated + * data was injected. No additional authenticated data may be injected + * after this function call. + * + * \param ctx CCM context structure. + */ +void br_ccm_flip(br_ccm_context *ctx); + +/** + * \brief Encrypt or decrypt some data with CCM. + * + * Data encryption or decryption can be done after `br_ccm_flip()` + * has been called on the context. If `encrypt` is non-zero, then the + * provided data shall be plaintext, and it is encrypted in place. + * Otherwise, the data shall be ciphertext, and it is decrypted in place. + * + * Data may be provided in several chunks of arbitrary length, provided + * that the total length exactly matches the length provided to the + * `br_ccm_reset()` call. + * + * \param ctx CCM context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +void br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len); + +/** + * \brief Compute CCM authentication tag. + * + * Compute the CCM authentication tag. This call terminates the CCM + * run: all data must have been injected with `br_ccm_run()` (in zero, + * one or more successive calls). After this function has been called, + * no more data can br processed; a `br_ccm_reset()` call is required + * to start a new message. + * + * The tag length was provided upon context initialisation (last call + * to `br_ccm_reset()`); it is returned by this function. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_ccm_check_tag()` function can be used to + * compute and check the tag value. + * + * \param ctx CCM context structure. + * \param tag destination buffer for the tag (up to 16 bytes). + * \return the tag length (in bytes). + */ +size_t br_ccm_get_tag(br_ccm_context *ctx, void *tag); + +/** + * \brief Compute and check CCM authentication tag. + * + * This function is an alternative to `br_ccm_get_tag()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * \param ctx CCM context structure. + * \param tag tag value to compare with (up to 16 bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_ccm_check_tag(br_ccm_context *ctx, const void *tag); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_block.h b/bearssl_block.h new file mode 100644 index 0000000..683a490 --- /dev/null +++ b/bearssl_block.h @@ -0,0 +1,2618 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_BLOCK_H__ +#define BR_BEARSSL_BLOCK_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_block.h + * + * # Block Ciphers and Symmetric Ciphers + * + * This file documents the API for block ciphers and other symmetric + * ciphers. + * + * + * ## Procedural API + * + * For a block cipher implementation, up to three separate sets of + * functions are provided, for CBC encryption, CBC decryption, and CTR + * encryption/decryption. Each set has its own context structure, + * initialised with the encryption key. + * + * For CBC encryption and decryption, the data to encrypt or decrypt is + * referenced as a sequence of blocks. The implementations assume that + * there is no partial block; no padding is applied or removed. The + * caller is responsible for handling any kind of padding. + * + * Function for CTR encryption are defined only for block ciphers with + * blocks of 16 bytes or more (i.e. AES, but not DES/3DES). + * + * Each implemented block cipher is identified by an "internal name" + * from which are derived the names of structures and functions that + * implement the cipher. For the block cipher of internal name "`xxx`", + * the following are defined: + * + * - `br_xxx_BLOCK_SIZE` + * + * A macro that evaluates to the block size (in bytes) of the + * cipher. For all implemented block ciphers, this value is a + * power of two. + * + * - `br_xxx_cbcenc_keys` + * + * Context structure that contains the subkeys resulting from the key + * expansion. These subkeys are appropriate for CBC encryption. The + * structure first field is called `vtable` and points to the + * appropriate OOP structure. + * + * - `br_xxx_cbcenc_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for CBC encryption are computed and + * written in the provided context structure. The key length MUST be + * adequate for the implemented block cipher. This function also sets + * the `vtable` field. + * + * - `br_xxx_cbcenc_run(const br_xxx_cbcenc_keys *ctx, void *iv, void *data, size_t len)` + * + * Perform CBC encryption of `len` bytes, in place. The encrypted data + * replaces the cleartext. `len` MUST be a multiple of the block length + * (if it is not, the function may loop forever or overflow a buffer). + * The IV is provided with the `iv` pointer; it is also updated with + * a copy of the last encrypted block. + * + * - `br_xxx_cbcdec_keys` + * + * Context structure that contains the subkeys resulting from the key + * expansion. These subkeys are appropriate for CBC decryption. The + * structure first field is called `vtable` and points to the + * appropriate OOP structure. + * + * - `br_xxx_cbcdec_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for CBC decryption are computed and + * written in the provided context structure. The key length MUST be + * adequate for the implemented block cipher. This function also sets + * the `vtable` field. + * + * - `br_xxx_cbcdec_run(const br_xxx_cbcdec_keys *ctx, void *iv, void *data, size_t num_blocks)` + * + * Perform CBC decryption of `len` bytes, in place. The decrypted data + * replaces the ciphertext. `len` MUST be a multiple of the block length + * (if it is not, the function may loop forever or overflow a buffer). + * The IV is provided with the `iv` pointer; it is also updated with + * a copy of the last _encrypted_ block. + * + * - `br_xxx_ctr_keys` + * + * Context structure that contains the subkeys resulting from the key + * expansion. These subkeys are appropriate for CTR encryption and + * decryption. The structure first field is called `vtable` and + * points to the appropriate OOP structure. + * + * - `br_xxx_ctr_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for CTR encryption and decryption + * are computed and written in the provided context structure. The + * key length MUST be adequate for the implemented block cipher. This + * function also sets the `vtable` field. + * + * - `br_xxx_ctr_run(const br_xxx_ctr_keys *ctx, const void *iv, uint32_t cc, void *data, size_t len)` (returns `uint32_t`) + * + * Perform CTR encryption/decryption of some data. Processing is done + * "in place" (the output data replaces the input data). This function + * implements the "standard incrementing function" from NIST SP800-38A, + * annex B: the IV length shall be 4 bytes less than the block size + * (i.e. 12 bytes for AES) and the counter is the 32-bit value starting + * with `cc`. The data length (`len`) is not necessarily a multiple of + * the block size. The new counter value is returned, which supports + * chunked processing, provided that each chunk length (except possibly + * the last one) is a multiple of the block size. + * + * - `br_xxx_ctrcbc_keys` + * + * Context structure that contains the subkeys resulting from the + * key expansion. These subkeys are appropriate for doing combined + * CTR encryption/decryption and CBC-MAC, as used in the CCM and EAX + * authenticated encryption modes. The structure first field is + * called `vtable` and points to the appropriate OOP structure. + * + * - `br_xxx_ctrcbc_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for combined CTR + * encryption/decryption and CBC-MAC are computed and written in the + * provided context structure. The key length MUST be adequate for + * the implemented block cipher. This function also sets the + * `vtable` field. + * + * - `br_xxx_ctrcbc_encrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)` + * + * Perform CTR encryption of some data, and CBC-MAC. Processing is + * done "in place" (the output data replaces the input data). This + * function applies CTR encryption on the data, using a full + * block-size counter (i.e. for 128-bit blocks, the counter is + * incremented as a 128-bit value). The 'ctr' array contains the + * initial value for the counter (used in the first block) and it is + * updated with the new value after data processing. The 'cbcmac' + * value shall point to a block-sized value which is used as IV for + * CBC-MAC, computed over the encrypted data (output of CTR + * encryption); the resulting CBC-MAC is written over 'cbcmac' on + * output. + * + * The data length MUST be a multiple of the block size. + * + * - `br_xxx_ctrcbc_decrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)` + * + * Perform CTR decryption of some data, and CBC-MAC. Processing is + * done "in place" (the output data replaces the input data). This + * function applies CTR decryption on the data, using a full + * block-size counter (i.e. for 128-bit blocks, the counter is + * incremented as a 128-bit value). The 'ctr' array contains the + * initial value for the counter (used in the first block) and it is + * updated with the new value after data processing. The 'cbcmac' + * value shall point to a block-sized value which is used as IV for + * CBC-MAC, computed over the encrypted data (input of CTR + * encryption); the resulting CBC-MAC is written over 'cbcmac' on + * output. + * + * The data length MUST be a multiple of the block size. + * + * - `br_xxx_ctrcbc_ctr(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *data, size_t len)` + * + * Perform CTR encryption or decryption of the provided data. The + * data is processed "in place" (the output data replaces the input + * data). A full block-sized counter is applied (i.e. for 128-bit + * blocks, the counter is incremented as a 128-bit value). The 'ctr' + * array contains the initial value for the counter (used in the + * first block), and it is updated with the new value after data + * processing. + * + * The data length MUST be a multiple of the block size. + * + * - `br_xxx_ctrcbc_mac(const br_xxx_ctrcbc_keys *ctx, void *cbcmac, const void *data, size_t len)` + * + * Compute CBC-MAC over the provided data. The IV for CBC-MAC is + * provided as 'cbcmac'; the output is written over the same array. + * The data itself is untouched. The data length MUST be a multiple + * of the block size. + * + * + * It shall be noted that the key expansion functions return `void`. If + * the provided key length is not allowed, then there will be no error + * reporting; implementations need not validate the key length, thus an + * invalid key length may result in undefined behaviour (e.g. buffer + * overflow). + * + * Subkey structures contain no interior pointer, and no external + * resources are allocated upon key expansion. They can thus be + * discarded without any explicit deallocation. + * + * + * ## Object-Oriented API + * + * Each context structure begins with a field (called `vtable`) that + * points to an instance of a structure that references the relevant + * functions through pointers. Each such structure contains the + * following: + * + * - `context_size` + * + * The size (in bytes) of the context structure for subkeys. + * + * - `block_size` + * + * The cipher block size (in bytes). + * + * - `log_block_size` + * + * The base-2 logarithm of cipher block size (e.g. 4 for blocks + * of 16 bytes). + * + * - `init` + * + * Pointer to the key expansion function. + * + * - `run` + * + * Pointer to the encryption/decryption function. + * + * For combined CTR/CBC-MAC encryption, the `vtable` has a slightly + * different structure: + * + * - `context_size` + * + * The size (in bytes) of the context structure for subkeys. + * + * - `block_size` + * + * The cipher block size (in bytes). + * + * - `log_block_size` + * + * The base-2 logarithm of cipher block size (e.g. 4 for blocks + * of 16 bytes). + * + * - `init` + * + * Pointer to the key expansion function. + * + * - `encrypt` + * + * Pointer to the CTR encryption + CBC-MAC function. + * + * - `decrypt` + * + * Pointer to the CTR decryption + CBC-MAC function. + * + * - `ctr` + * + * Pointer to the CTR encryption/decryption function. + * + * - `mac` + * + * Pointer to the CBC-MAC function. + * + * For block cipher "`xxx`", static, constant instances of these + * structures are defined, under the names: + * + * - `br_xxx_cbcenc_vtable` + * - `br_xxx_cbcdec_vtable` + * - `br_xxx_ctr_vtable` + * - `br_xxx_ctrcbc_vtable` + * + * + * ## Implemented Block Ciphers + * + * Provided implementations are: + * + * | Name | Function | Block Size (bytes) | Key lengths (bytes) | + * | :-------- | :------- | :----------------: | :-----------------: | + * | aes_big | AES | 16 | 16, 24 and 32 | + * | aes_small | AES | 16 | 16, 24 and 32 | + * | aes_ct | AES | 16 | 16, 24 and 32 | + * | aes_ct64 | AES | 16 | 16, 24 and 32 | + * | aes_x86ni | AES | 16 | 16, 24 and 32 | + * | aes_pwr8 | AES | 16 | 16, 24 and 32 | + * | des_ct | DES/3DES | 8 | 8, 16 and 24 | + * | des_tab | DES/3DES | 8 | 8, 16 and 24 | + * + * **Note:** DES/3DES nominally uses keys of 64, 128 and 192 bits (i.e. 8, + * 16 and 24 bytes), but some of the bits are ignored by the algorithm, so + * the _effective_ key lengths, from a security point of view, are 56, + * 112 and 168 bits, respectively. + * + * `aes_big` is a "classical" AES implementation, using tables. It + * is fast but not constant-time, since it makes data-dependent array + * accesses. + * + * `aes_small` is an AES implementation optimized for code size. It + * is substantially slower than `aes_big`; it is not constant-time + * either. + * + * `aes_ct` is a constant-time implementation of AES; its code is about + * as big as that of `aes_big`, while its performance is comparable to + * that of `aes_small`. However, it is constant-time. This + * implementation should thus be considered to be the "default" AES in + * BearSSL, to be used unless the operational context guarantees that a + * non-constant-time implementation is safe, or an architecture-specific + * constant-time implementation can be used (e.g. using dedicated + * hardware opcodes). + * + * `aes_ct64` is another constant-time implementation of AES. It is + * similar to `aes_ct` but uses 64-bit values. On 32-bit machines, + * `aes_ct64` is not faster than `aes_ct`, often a bit slower, and has + * a larger footprint; however, on 64-bit architectures, `aes_ct64` + * is typically twice faster than `aes_ct` for modes that allow parallel + * operations (i.e. CTR, and CBC decryption, but not CBC encryption). + * + * `aes_x86ni` exists only on x86 architectures (32-bit and 64-bit). It + * uses the AES-NI opcodes when available. + * + * `aes_pwr8` exists only on PowerPC / POWER architectures (32-bit and + * 64-bit, both little-endian and big-endian). It uses the AES opcodes + * present in POWER8 and later. + * + * `des_tab` is a classic, table-based implementation of DES/3DES. It + * is not constant-time. + * + * `des_ct` is an constant-time implementation of DES/3DES. It is + * substantially slower than `des_tab`. + * + * ## ChaCha20 and Poly1305 + * + * ChaCha20 is a stream cipher. Poly1305 is a MAC algorithm. They + * are described in [RFC 7539](https://tools.ietf.org/html/rfc7539). + * + * Two function pointer types are defined: + * + * - `br_chacha20_run` describes a function that implements ChaCha20 + * only. + * + * - `br_poly1305_run` describes an implementation of Poly1305, + * in the AEAD combination with ChaCha20 specified in RFC 7539 + * (the ChaCha20 implementation is provided as a function pointer). + * + * `chacha20_ct` is a straightforward implementation of ChaCha20 in + * plain C; it is constant-time, small, and reasonably fast. + * + * `chacha20_sse2` leverages SSE2 opcodes (on x86 architectures that + * support these opcodes). It is faster than `chacha20_ct`. + * + * `poly1305_ctmul` is an implementation of the ChaCha20+Poly1305 AEAD + * construction, where the Poly1305 part is performed with mixed 32-bit + * multiplications (operands are 32-bit, result is 64-bit). + * + * `poly1305_ctmul32` implements ChaCha20+Poly1305 using pure 32-bit + * multiplications (32-bit operands, 32-bit result). It is slower than + * `poly1305_ctmul`, except on some specific architectures such as + * the ARM Cortex M0+. + * + * `poly1305_ctmulq` implements ChaCha20+Poly1305 with mixed 64-bit + * multiplications (operands are 64-bit, result is 128-bit) on 64-bit + * platforms that support such operations. + * + * `poly1305_i15` implements ChaCha20+Poly1305 with the generic "i15" + * big integer implementation. It is meant mostly for testing purposes, + * although it can help with saving a few hundred bytes of code footprint + * on systems where code size is scarce. + */ + +/** + * \brief Class type for CBC encryption implementations. + * + * A `br_block_cbcenc_class` instance points to the functions implementing + * a specific block cipher, when used in CBC mode for encrypting data. + */ +typedef struct br_block_cbcenc_class_ br_block_cbcenc_class; +struct br_block_cbcenc_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_cbcenc_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CBC encryption. + * + * The `iv` parameter points to the IV for this run; it is + * updated with a copy of the last encrypted block. The data + * is encrypted "in place"; its length (`len`) MUST be a + * multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param iv IV for CBC encryption (updated). + * \param data data to encrypt. + * \param len data length (in bytes, multiple of block size). + */ + void (*run)(const br_block_cbcenc_class *const *ctx, + void *iv, void *data, size_t len); +}; + +/** + * \brief Class type for CBC decryption implementations. + * + * A `br_block_cbcdec_class` instance points to the functions implementing + * a specific block cipher, when used in CBC mode for decrypting data. + */ +typedef struct br_block_cbcdec_class_ br_block_cbcdec_class; +struct br_block_cbcdec_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_cbcdec_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CBC decryption. + * + * The `iv` parameter points to the IV for this run; it is + * updated with a copy of the last encrypted block. The data + * is decrypted "in place"; its length (`len`) MUST be a + * multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param iv IV for CBC decryption (updated). + * \param data data to decrypt. + * \param len data length (in bytes, multiple of block size). + */ + void (*run)(const br_block_cbcdec_class *const *ctx, + void *iv, void *data, size_t len); +}; + +/** + * \brief Class type for CTR encryption/decryption implementations. + * + * A `br_block_ctr_class` instance points to the functions implementing + * a specific block cipher, when used in CTR mode for encrypting or + * decrypting data. + */ +typedef struct br_block_ctr_class_ br_block_ctr_class; +struct br_block_ctr_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_ctr_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CTR encryption or decryption. + * + * The `iv` parameter points to the IV for this run; its + * length is exactly 4 bytes less than the block size (e.g. + * 12 bytes for AES/CTR). The IV is combined with a 32-bit + * block counter to produce the block value which is processed + * with the block cipher. + * + * The data to encrypt or decrypt is updated "in place". Its + * length (`len` bytes) is not required to be a multiple of + * the block size; if the final block is partial, then the + * corresponding key stream bits are dropped. + * + * The resulting counter value is returned. + * + * \param ctx context structure (already initialised). + * \param iv IV for CTR encryption/decryption. + * \param cc initial value for the block counter. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \return the new block counter value. + */ + uint32_t (*run)(const br_block_ctr_class *const *ctx, + const void *iv, uint32_t cc, void *data, size_t len); +}; + +/** + * \brief Class type for combined CTR and CBC-MAC implementations. + * + * A `br_block_ctrcbc_class` instance points to the functions implementing + * a specific block cipher, when used in CTR mode for encrypting or + * decrypting data, along with CBC-MAC. + */ +typedef struct br_block_ctrcbc_class_ br_block_ctrcbc_class; +struct br_block_ctrcbc_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_ctrcbc_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CTR encryption + CBC-MAC. + * + * The `ctr` parameter points to the counter; its length shall + * be equal to the block size. It is updated by this function + * as encryption proceeds. + * + * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC + * is computed over the encrypted data (output of CTR + * encryption). Its length shall be equal to the block size. The + * computed CBC-MAC value is written over the `cbcmac` array. + * + * The data to encrypt is updated "in place". Its length (`len` + * bytes) MUST be a multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param ctr counter for CTR encryption (initial and final). + * \param cbcmac IV and output buffer for CBC-MAC. + * \param data data to encrypt. + * \param len data length (in bytes). + */ + void (*encrypt)(const br_block_ctrcbc_class *const *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + + /** + * \brief Run the CTR decryption + CBC-MAC. + * + * The `ctr` parameter points to the counter; its length shall + * be equal to the block size. It is updated by this function + * as decryption proceeds. + * + * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC + * is computed over the encrypted data (i.e. before CTR + * decryption). Its length shall be equal to the block size. The + * computed CBC-MAC value is written over the `cbcmac` array. + * + * The data to decrypt is updated "in place". Its length (`len` + * bytes) MUST be a multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param ctr counter for CTR encryption (initial and final). + * \param cbcmac IV and output buffer for CBC-MAC. + * \param data data to decrypt. + * \param len data length (in bytes). + */ + void (*decrypt)(const br_block_ctrcbc_class *const *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + + /** + * \brief Run the CTR encryption/decryption only. + * + * The `ctr` parameter points to the counter; its length shall + * be equal to the block size. It is updated by this function + * as decryption proceeds. + * + * The data to decrypt is updated "in place". Its length (`len` + * bytes) MUST be a multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param ctr counter for CTR encryption (initial and final). + * \param data data to decrypt. + * \param len data length (in bytes). + */ + void (*ctr)(const br_block_ctrcbc_class *const *ctx, + void *ctr, void *data, size_t len); + + /** + * \brief Run the CBC-MAC only. + * + * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC + * is computed over the encrypted data (i.e. before CTR + * decryption). Its length shall be equal to the block size. The + * computed CBC-MAC value is written over the `cbcmac` array. + * + * The data is unmodified. Its length (`len` bytes) MUST be a + * multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param cbcmac IV and output buffer for CBC-MAC. + * \param data data to decrypt. + * \param len data length (in bytes). + */ + void (*mac)(const br_block_ctrcbc_class *const *ctx, + void *cbcmac, const void *data, size_t len); +}; + +/* + * Traditional, table-based AES implementation. It is fast, but uses + * internal tables (in particular a 1 kB table for encryption, another + * 1 kB table for decryption, and a 256-byte table for key schedule), + * and it is not constant-time. In contexts where cache-timing attacks + * apply, this implementation may leak the secret key. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_big_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_big` implementation). + */ +extern const br_block_cbcenc_class br_aes_big_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_big` implementation). + */ +extern const br_block_cbcdec_class br_aes_big_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_big` implementation). + */ +extern const br_block_ctr_class br_aes_big_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_big` implementation). + */ +extern const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to encrypt or decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * AES implementation optimized for size. It is slower than the + * traditional table-based AES implementation, but requires much less + * code. It still uses data-dependent table accesses (albeit within a + * much smaller 256-byte table), which makes it conceptually vulnerable + * to cache-timing attacks. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_small_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_small` implementation). + */ +extern const br_block_cbcenc_class br_aes_small_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_small` implementation). + */ +extern const br_block_cbcdec_class br_aes_small_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_small` implementation). + */ +extern const br_block_ctr_class br_aes_small_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_small` implementation). + */ +extern const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * Constant-time AES implementation. Its size is similar to that of + * 'aes_big', and its performance is similar to that of 'aes_small' (faster + * decryption, slower encryption). However, it is constant-time, i.e. + * immune to cache-timing and similar attacks. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_ct_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_ct` implementation). + */ +extern const br_block_cbcenc_class br_aes_ct_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_ct` implementation). + */ +extern const br_block_cbcdec_class br_aes_ct_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_ct` implementation). + */ +extern const br_block_ctr_class br_aes_ct_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_ct` implementation). + */ +extern const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * 64-bit constant-time AES implementation. It is similar to 'aes_ct' + * but uses 64-bit registers, making it about twice faster than 'aes_ct' + * on 64-bit platforms, while remaining constant-time and with a similar + * code size. (The doubling in performance is only for CBC decryption + * and CTR mode; CBC encryption is non-parallel and cannot benefit from + * the larger registers.) + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_ct64_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_ct64` implementation). + */ +extern const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_ct64` implementation). + */ +extern const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_ct64` implementation). + */ +extern const br_block_ctr_class br_aes_ct64_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_ct64` implementation). + */ +extern const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * AES implementation using AES-NI opcodes (x86 platform). + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_x86ni_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_cbcenc_get_vtable()`. + */ +extern const br_block_cbcenc_class br_aes_x86ni_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_cbcdec_get_vtable()`. + */ +extern const br_block_cbcdec_class br_aes_x86ni_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_ctr_get_vtable()`. + */ +extern const br_block_ctr_class br_aes_x86ni_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_ctrcbc_get_vtable()`. + */ +extern const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_cbcenc_init(br_aes_x86ni_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_cbcdec_init(br_aes_x86ni_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_ctr_init(br_aes_x86ni_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_x86ni_cbcenc_run(const br_aes_x86ni_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/** + * \brief Obtain the `aes_x86ni` AES-CBC (encryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_x86ni_cbcenc_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CBC (encryption) implementation, or `NULL`. + */ +const br_block_cbcenc_class *br_aes_x86ni_cbcenc_get_vtable(void); + +/** + * \brief Obtain the `aes_x86ni` AES-CBC (decryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_x86ni_cbcdec_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CBC (decryption) implementation, or `NULL`. + */ +const br_block_cbcdec_class *br_aes_x86ni_cbcdec_get_vtable(void); + +/** + * \brief Obtain the `aes_x86ni` AES-CTR implementation, if available. + * + * This function returns a pointer to `br_aes_x86ni_ctr_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CTR implementation, or `NULL`. + */ +const br_block_ctr_class *br_aes_x86ni_ctr_get_vtable(void); + +/** + * \brief Obtain the `aes_x86ni` AES-CTR + CBC-MAC implementation, if + * available. + * + * This function returns a pointer to `br_aes_x86ni_ctrcbc_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CTR implementation, or `NULL`. + */ +const br_block_ctrcbc_class *br_aes_x86ni_ctrcbc_get_vtable(void); + +/* + * AES implementation using POWER8 opcodes. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_pwr8_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_cbcenc_get_vtable()`. + */ +extern const br_block_cbcenc_class br_aes_pwr8_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_cbcdec_get_vtable()`. + */ +extern const br_block_cbcdec_class br_aes_pwr8_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_ctr_get_vtable()`. + */ +extern const br_block_ctr_class br_aes_pwr8_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_ctrcbc_get_vtable()`. + */ +extern const br_block_ctrcbc_class br_aes_pwr8_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_cbcenc_init(br_aes_pwr8_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_cbcdec_init(br_aes_pwr8_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_ctr_init(br_aes_pwr8_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_ctrcbc_init(br_aes_pwr8_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_pwr8_cbcenc_run(const br_aes_pwr8_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_pwr8_cbcdec_run(const br_aes_pwr8_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_pwr8_ctr_run(const br_aes_pwr8_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_encrypt(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_decrypt(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_ctr(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_mac(const br_aes_pwr8_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/** + * \brief Obtain the `aes_pwr8` AES-CBC (encryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_pwr8_cbcenc_vtable`, if + * that implementation was compiled in the library _and_ the POWER8 + * crypto opcodes are available on the currently running CPU. If either + * of these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CBC (encryption) implementation, or `NULL`. + */ +const br_block_cbcenc_class *br_aes_pwr8_cbcenc_get_vtable(void); + +/** + * \brief Obtain the `aes_pwr8` AES-CBC (decryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_pwr8_cbcdec_vtable`, if + * that implementation was compiled in the library _and_ the POWER8 + * crypto opcodes are available on the currently running CPU. If either + * of these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CBC (decryption) implementation, or `NULL`. + */ +const br_block_cbcdec_class *br_aes_pwr8_cbcdec_get_vtable(void); + +/** + * \brief Obtain the `aes_pwr8` AES-CTR implementation, if available. + * + * This function returns a pointer to `br_aes_pwr8_ctr_vtable`, if that + * implementation was compiled in the library _and_ the POWER8 crypto + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CTR implementation, or `NULL`. + */ +const br_block_ctr_class *br_aes_pwr8_ctr_get_vtable(void); + +/** + * \brief Obtain the `aes_pwr8` AES-CTR + CBC-MAC implementation, if + * available. + * + * This function returns a pointer to `br_aes_pwr8_ctrcbc_vtable`, if + * that implementation was compiled in the library _and_ the POWER8 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CTR implementation, or `NULL`. + */ +const br_block_ctrcbc_class *br_aes_pwr8_ctrcbc_get_vtable(void); + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC encryption) for all AES implementations. + */ +typedef union { + const br_block_cbcenc_class *vtable; + br_aes_big_cbcenc_keys c_big; + br_aes_small_cbcenc_keys c_small; + br_aes_ct_cbcenc_keys c_ct; + br_aes_ct64_cbcenc_keys c_ct64; + br_aes_x86ni_cbcenc_keys c_x86ni; + br_aes_pwr8_cbcenc_keys c_pwr8; +} br_aes_gen_cbcenc_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC decryption) for all AES implementations. + */ +typedef union { + const br_block_cbcdec_class *vtable; + br_aes_big_cbcdec_keys c_big; + br_aes_small_cbcdec_keys c_small; + br_aes_ct_cbcdec_keys c_ct; + br_aes_ct64_cbcdec_keys c_ct64; + br_aes_x86ni_cbcdec_keys c_x86ni; + br_aes_pwr8_cbcdec_keys c_pwr8; +} br_aes_gen_cbcdec_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CTR encryption and decryption) for all AES implementations. + */ +typedef union { + const br_block_ctr_class *vtable; + br_aes_big_ctr_keys c_big; + br_aes_small_ctr_keys c_small; + br_aes_ct_ctr_keys c_ct; + br_aes_ct64_ctr_keys c_ct64; + br_aes_x86ni_ctr_keys c_x86ni; + br_aes_pwr8_ctr_keys c_pwr8; +} br_aes_gen_ctr_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CTR encryption/decryption + CBC-MAC) for all AES implementations. + */ +typedef union { + const br_block_ctrcbc_class *vtable; + br_aes_big_ctrcbc_keys c_big; + br_aes_small_ctrcbc_keys c_small; + br_aes_ct_ctrcbc_keys c_ct; + br_aes_ct64_ctrcbc_keys c_ct64; + br_aes_x86ni_ctrcbc_keys c_x86ni; + br_aes_pwr8_ctrcbc_keys c_pwr8; +} br_aes_gen_ctrcbc_keys; + +/* + * Traditional, table-based implementation for DES/3DES. Since tables are + * used, cache-timing attacks are conceptually possible. + */ + +/** \brief DES/3DES block size (8 bytes). */ +#define br_des_tab_BLOCK_SIZE 8 + +/** + * \brief Context for DES subkeys (`des_tab` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_tab_cbcenc_keys; + +/** + * \brief Context for DES subkeys (`des_tab` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_tab_cbcdec_keys; + +/** + * \brief Class instance for DES CBC encryption (`des_tab` implementation). + */ +extern const br_block_cbcenc_class br_des_tab_cbcenc_vtable; + +/** + * \brief Class instance for DES CBC decryption (`des_tab` implementation). + */ +extern const br_block_cbcdec_class br_des_tab_cbcdec_vtable; + +/** + * \brief Context initialisation (key schedule) for DES CBC encryption + * (`des_tab` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for DES CBC decryption + * (`des_tab` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with DES (`des_tab` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with DES (`des_tab` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/* + * Constant-time implementation for DES/3DES. It is substantially slower + * (by a factor of about 4x), but also immune to cache-timing attacks. + */ + +/** \brief DES/3DES block size (8 bytes). */ +#define br_des_ct_BLOCK_SIZE 8 + +/** + * \brief Context for DES subkeys (`des_ct` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_ct_cbcenc_keys; + +/** + * \brief Context for DES subkeys (`des_ct` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_ct_cbcdec_keys; + +/** + * \brief Class instance for DES CBC encryption (`des_ct` implementation). + */ +extern const br_block_cbcenc_class br_des_ct_cbcenc_vtable; + +/** + * \brief Class instance for DES CBC decryption (`des_ct` implementation). + */ +extern const br_block_cbcdec_class br_des_ct_cbcdec_vtable; + +/** + * \brief Context initialisation (key schedule) for DES CBC encryption + * (`des_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for DES CBC decryption + * (`des_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with DES (`des_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with DES (`des_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/* + * These structures are large enough to accommodate subkeys for all + * DES/3DES implementations. + */ + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC encryption) for all DES implementations. + */ +typedef union { + const br_block_cbcenc_class *vtable; + br_des_tab_cbcenc_keys tab; + br_des_ct_cbcenc_keys ct; +} br_des_gen_cbcenc_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC decryption) for all DES implementations. + */ +typedef union { + const br_block_cbcdec_class *vtable; + br_des_tab_cbcdec_keys c_tab; + br_des_ct_cbcdec_keys c_ct; +} br_des_gen_cbcdec_keys; + +/** + * \brief Type for a ChaCha20 implementation. + * + * An implementation follows the description in RFC 7539: + * + * - Key is 256 bits (`key` points to exactly 32 bytes). + * + * - IV is 96 bits (`iv` points to exactly 12 bytes). + * + * - Block counter is over 32 bits and starts at value `cc`; the + * resulting value is returned. + * + * Data (pointed to by `data`, of length `len`) is encrypted/decrypted + * in place. If `len` is not a multiple of 64, then the excess bytes from + * the last block processing are dropped (therefore, "chunked" processing + * works only as long as each non-final chunk has a length multiple of 64). + * + * \param key secret key (32 bytes). + * \param iv IV (12 bytes). + * \param cc initial counter value. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +typedef uint32_t (*br_chacha20_run)(const void *key, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief ChaCha20 implementation (straightforward C code, constant-time). + * + * \see br_chacha20_run + * + * \param key secret key (32 bytes). + * \param iv IV (12 bytes). + * \param cc initial counter value. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +uint32_t br_chacha20_ct_run(const void *key, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief ChaCha20 implementation (SSE2 code, constant-time). + * + * This implementation is available only on x86 platforms, depending on + * compiler support. Moreover, in 32-bit mode, it might not actually run, + * if the underlying hardware does not implement the SSE2 opcode (in + * 64-bit mode, SSE2 is part of the ABI, so if the code could be compiled + * at all, then it can run). Use `br_chacha20_sse2_get()` to safely obtain + * a pointer to that function. + * + * \see br_chacha20_run + * + * \param key secret key (32 bytes). + * \param iv IV (12 bytes). + * \param cc initial counter value. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +uint32_t br_chacha20_sse2_run(const void *key, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief Obtain the `sse2` ChaCha20 implementation, if available. + * + * This function returns a pointer to `br_chacha20_sse2_run`, if + * that implementation was compiled in the library _and_ the SSE2 + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `0`. + * + * \return the `sse2` ChaCha20 implementation, or `0`. + */ +br_chacha20_run br_chacha20_sse2_get(void); + +/** + * \brief Type for a ChaCha20+Poly1305 AEAD implementation. + * + * The provided data is encrypted or decrypted with ChaCha20. The + * authentication tag is computed on the concatenation of the + * additional data and the ciphertext, with the padding and lengths + * as described in RFC 7539 (section 2.8). + * + * After decryption, the caller is responsible for checking that the + * computed tag matches the expected value. + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +typedef void (*br_poly1305_run)(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (mixed 32-bit multiplications). + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_ctmul_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (pure 32-bit multiplications). + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_ctmul32_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (i15). + * + * This implementation relies on the generic big integer code "i15" + * (which uses pure 32-bit multiplications). As such, it may save a + * little code footprint in a context where "i15" is already included + * (e.g. for elliptic curves or for RSA); however, it is also + * substantially slower than the ctmul and ctmul32 implementations. + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_i15_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (ctmulq). + * + * This implementation uses 64-bit multiplications (result over 128 bits). + * It is available only on platforms that offer such a primitive (in + * practice, 64-bit architectures). Use `br_poly1305_ctmulq_get()` to + * dynamically obtain a pointer to that function, or 0 if not supported. + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_ctmulq_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief Get the ChaCha20+Poly1305 "ctmulq" implementation, if available. + * + * This function returns a pointer to the `br_poly1305_ctmulq_run()` + * function if supported on the current platform; otherwise, it returns 0. + * + * \return the ctmulq ChaCha20+Poly1305 implementation, or 0. + */ +br_poly1305_run br_poly1305_ctmulq_get(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_ec.h b/bearssl_ec.h new file mode 100644 index 0000000..db22692 --- /dev/null +++ b/bearssl_ec.h @@ -0,0 +1,883 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_EC_H__ +#define BR_BEARSSL_EC_H__ + +#include +#include + +#include "bearssl_rand.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_ec.h + * + * # Elliptic Curves + * + * This file documents the EC implementations provided with BearSSL, and + * ECDSA. + * + * ## Elliptic Curve API + * + * Only "named curves" are supported. Each EC implementation supports + * one or several named curves, identified by symbolic identifiers. + * These identifiers are small integers, that correspond to the values + * registered by the + * [IANA](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8). + * + * Since all currently defined elliptic curve identifiers are in the 0..31 + * range, it is convenient to encode support of some curves in a 32-bit + * word, such that bit x corresponds to curve of identifier x. + * + * An EC implementation is incarnated by a `br_ec_impl` instance, that + * offers the following fields: + * + * - `supported_curves` + * + * A 32-bit word that documents the identifiers of the curves supported + * by this implementation. + * + * - `generator()` + * + * Callback method that returns a pointer to the conventional generator + * point for that curve. + * + * - `order()` + * + * Callback method that returns a pointer to the subgroup order for + * that curve. That value uses unsigned big-endian encoding. + * + * - `xoff()` + * + * Callback method that returns the offset and length of the X + * coordinate in an encoded point. + * + * - `mul()` + * + * Multiply a curve point with an integer. + * + * - `mulgen()` + * + * Multiply the curve generator with an integer. This may be faster + * than the generic `mul()`. + * + * - `muladd()` + * + * Multiply two curve points by two integers, and return the sum of + * the two products. + * + * All curve points are represented in uncompressed format. The `mul()` + * and `muladd()` methods take care to validate that the provided points + * are really part of the relevant curve subgroup. + * + * For all point multiplication functions, the following holds: + * + * - Functions validate that the provided points are valid members + * of the relevant curve subgroup. An error is reported if that is + * not the case. + * + * - Processing is constant-time, even if the point operands are not + * valid. This holds for both the source and resulting points, and + * the multipliers (integers). Only the byte length of the provided + * multiplier arrays (not their actual value length in bits) may + * leak through timing-based side channels. + * + * - The multipliers (integers) MUST be lower than the subgroup order. + * If this property is not met, then the result is indeterminate, + * but an error value is not ncessearily returned. + * + * + * ## ECDSA + * + * ECDSA signatures have two standard formats, called "raw" and "asn1". + * Internally, such a signature is a pair of modular integers `(r,s)`. + * The "raw" format is the concatenation of the unsigned big-endian + * encodings of these two integers, possibly left-padded with zeros so + * that they have the same encoded length. The "asn1" format is the + * DER encoding of an ASN.1 structure that contains the two integer + * values: + * + * ECDSASignature ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * In general, in all of X.509 and SSL/TLS, the "asn1" format is used. + * BearSSL offers ECDSA implementations for both formats; conversion + * functions between the two formats are also provided. Conversion of a + * "raw" format signature into "asn1" may enlarge a signature by no more + * than 9 bytes for all supported curves; conversely, conversion of an + * "asn1" signature to "raw" may expand the signature but the "raw" + * length will never be more than twice the length of the "asn1" length + * (and usually it will be shorter). + * + * Note that for a given signature, the "raw" format is not fully + * deterministic, in that it does not enforce a minimal common length. + */ + +/* + * Standard curve ID. These ID are equal to the assigned numerical + * identifiers assigned to these curves for TLS: + * http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 + */ + +/** \brief Identifier for named curve sect163k1. */ +#define BR_EC_sect163k1 1 + +/** \brief Identifier for named curve sect163r1. */ +#define BR_EC_sect163r1 2 + +/** \brief Identifier for named curve sect163r2. */ +#define BR_EC_sect163r2 3 + +/** \brief Identifier for named curve sect193r1. */ +#define BR_EC_sect193r1 4 + +/** \brief Identifier for named curve sect193r2. */ +#define BR_EC_sect193r2 5 + +/** \brief Identifier for named curve sect233k1. */ +#define BR_EC_sect233k1 6 + +/** \brief Identifier for named curve sect233r1. */ +#define BR_EC_sect233r1 7 + +/** \brief Identifier for named curve sect239k1. */ +#define BR_EC_sect239k1 8 + +/** \brief Identifier for named curve sect283k1. */ +#define BR_EC_sect283k1 9 + +/** \brief Identifier for named curve sect283r1. */ +#define BR_EC_sect283r1 10 + +/** \brief Identifier for named curve sect409k1. */ +#define BR_EC_sect409k1 11 + +/** \brief Identifier for named curve sect409r1. */ +#define BR_EC_sect409r1 12 + +/** \brief Identifier for named curve sect571k1. */ +#define BR_EC_sect571k1 13 + +/** \brief Identifier for named curve sect571r1. */ +#define BR_EC_sect571r1 14 + +/** \brief Identifier for named curve secp160k1. */ +#define BR_EC_secp160k1 15 + +/** \brief Identifier for named curve secp160r1. */ +#define BR_EC_secp160r1 16 + +/** \brief Identifier for named curve secp160r2. */ +#define BR_EC_secp160r2 17 + +/** \brief Identifier for named curve secp192k1. */ +#define BR_EC_secp192k1 18 + +/** \brief Identifier for named curve secp192r1. */ +#define BR_EC_secp192r1 19 + +/** \brief Identifier for named curve secp224k1. */ +#define BR_EC_secp224k1 20 + +/** \brief Identifier for named curve secp224r1. */ +#define BR_EC_secp224r1 21 + +/** \brief Identifier for named curve secp256k1. */ +#define BR_EC_secp256k1 22 + +/** \brief Identifier for named curve secp256r1. */ +#define BR_EC_secp256r1 23 + +/** \brief Identifier for named curve secp384r1. */ +#define BR_EC_secp384r1 24 + +/** \brief Identifier for named curve secp521r1. */ +#define BR_EC_secp521r1 25 + +/** \brief Identifier for named curve brainpoolP256r1. */ +#define BR_EC_brainpoolP256r1 26 + +/** \brief Identifier for named curve brainpoolP384r1. */ +#define BR_EC_brainpoolP384r1 27 + +/** \brief Identifier for named curve brainpoolP512r1. */ +#define BR_EC_brainpoolP512r1 28 + +/** \brief Identifier for named curve Curve25519. */ +#define BR_EC_curve25519 29 + +/** \brief Identifier for named curve Curve448. */ +#define BR_EC_curve448 30 + +/** + * \brief Structure for an EC public key. + */ +typedef struct { + /** \brief Identifier for the curve used by this key. */ + int curve; + /** \brief Public curve point (uncompressed format). */ + unsigned char *q; + /** \brief Length of public curve point (in bytes). */ + size_t qlen; +} br_ec_public_key; + +/** + * \brief Structure for an EC private key. + * + * The private key is an integer modulo the curve subgroup order. The + * encoding below tolerates extra leading zeros. In general, it is + * recommended that the private key has the same length as the curve + * subgroup order. + */ +typedef struct { + /** \brief Identifier for the curve used by this key. */ + int curve; + /** \brief Private key (integer, unsigned big-endian encoding). */ + unsigned char *x; + /** \brief Private key length (in bytes). */ + size_t xlen; +} br_ec_private_key; + +/** + * \brief Type for an EC implementation. + */ +typedef struct { + /** + * \brief Supported curves. + * + * This word is a bitfield: bit `x` is set if the curve of ID `x` + * is supported. E.g. an implementation supporting both NIST P-256 + * (secp256r1, ID 23) and NIST P-384 (secp384r1, ID 24) will have + * value `0x01800000` in this field. + */ + uint32_t supported_curves; + + /** + * \brief Get the conventional generator. + * + * This function returns the conventional generator (encoded + * curve point) for the specified curve. This function MUST NOT + * be called if the curve is not supported. + * + * \param curve curve identifier. + * \param len receiver for the encoded generator length (in bytes). + * \return the encoded generator. + */ + const unsigned char *(*generator)(int curve, size_t *len); + + /** + * \brief Get the subgroup order. + * + * This function returns the order of the subgroup generated by + * the conventional generator, for the specified curve. Unsigned + * big-endian encoding is used. This function MUST NOT be called + * if the curve is not supported. + * + * \param curve curve identifier. + * \param len receiver for the encoded order length (in bytes). + * \return the encoded order. + */ + const unsigned char *(*order)(int curve, size_t *len); + + /** + * \brief Get the offset and length for the X coordinate. + * + * This function returns the offset and length (in bytes) of + * the X coordinate in an encoded non-zero point. + * + * \param curve curve identifier. + * \param len receiver for the X coordinate length (in bytes). + * \return the offset for the X coordinate (in bytes). + */ + size_t (*xoff)(int curve, size_t *len); + + /** + * \brief Multiply a curve point by an integer. + * + * The source point is provided in array `G` (of size `Glen` bytes); + * the multiplication result is written over it. The multiplier + * `x` (of size `xlen` bytes) uses unsigned big-endian encoding. + * + * Rules: + * + * - The specified curve MUST be supported. + * + * - The source point must be a valid point on the relevant curve + * subgroup (and not the "point at infinity" either). If this is + * not the case, then this function returns an error (0). + * + * - The multiplier integer MUST be non-zero and less than the + * curve subgroup order. If this property does not hold, then + * the result is indeterminate and an error code is not + * guaranteed. + * + * Returned value is 1 on success, 0 on error. On error, the + * contents of `G` are indeterminate. + * + * \param G point to multiply. + * \param Glen length of the encoded point (in bytes). + * \param x multiplier (unsigned big-endian). + * \param xlen multiplier length (in bytes). + * \param curve curve identifier. + * \return 1 on success, 0 on error. + */ + uint32_t (*mul)(unsigned char *G, size_t Glen, + const unsigned char *x, size_t xlen, int curve); + + /** + * \brief Multiply the generator by an integer. + * + * The multiplier MUST be non-zero and less than the curve + * subgroup order. Results are indeterminate if this property + * does not hold. + * + * \param R output buffer for the point. + * \param x multiplier (unsigned big-endian). + * \param xlen multiplier length (in bytes). + * \param curve curve identifier. + * \return encoded result point length (in bytes). + */ + size_t (*mulgen)(unsigned char *R, + const unsigned char *x, size_t xlen, int curve); + + /** + * \brief Multiply two points by two integers and add the + * results. + * + * The point `x*A + y*B` is computed and written back in the `A` + * array. + * + * Rules: + * + * - The specified curve MUST be supported. + * + * - The source points (`A` and `B`) must be valid points on + * the relevant curve subgroup (and not the "point at + * infinity" either). If this is not the case, then this + * function returns an error (0). + * + * - If the `B` pointer is `NULL`, then the conventional + * subgroup generator is used. With some implementations, + * this may be faster than providing a pointer to the + * generator. + * + * - The multiplier integers (`x` and `y`) MUST be non-zero + * and less than the curve subgroup order. If either integer + * is zero, then an error is reported, but if one of them is + * not lower than the subgroup order, then the result is + * indeterminate and an error code is not guaranteed. + * + * - If the final result is the point at infinity, then an + * error is returned. + * + * Returned value is 1 on success, 0 on error. On error, the + * contents of `A` are indeterminate. + * + * \param A first point to multiply. + * \param B second point to multiply (`NULL` for the generator). + * \param len common length of the encoded points (in bytes). + * \param x multiplier for `A` (unsigned big-endian). + * \param xlen length of multiplier for `A` (in bytes). + * \param y multiplier for `A` (unsigned big-endian). + * \param ylen length of multiplier for `A` (in bytes). + * \param curve curve identifier. + * \return 1 on success, 0 on error. + */ + uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve); +} br_ec_impl; + +/** + * \brief EC implementation "i31". + * + * This implementation internally uses generic code for modular integers, + * with a representation as sequences of 31-bit words. It supports secp256r1, + * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521). + */ +extern const br_ec_impl br_ec_prime_i31; + +/** + * \brief EC implementation "i15". + * + * This implementation internally uses generic code for modular integers, + * with a representation as sequences of 15-bit words. It supports secp256r1, + * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521). + */ +extern const br_ec_impl br_ec_prime_i15; + +/** + * \brief EC implementation "m15" for P-256. + * + * This implementation uses specialised code for curve secp256r1 (also + * known as NIST P-256), with optional Karatsuba decomposition, and fast + * modular reduction thanks to the field modulus special format. Only + * 32-bit multiplications are used (with 32-bit results, not 64-bit). + */ +extern const br_ec_impl br_ec_p256_m15; + +/** + * \brief EC implementation "m31" for P-256. + * + * This implementation uses specialised code for curve secp256r1 (also + * known as NIST P-256), relying on multiplications of 31-bit values + * (MUL31). + */ +extern const br_ec_impl br_ec_p256_m31; + +/** + * \brief EC implementation "i15" (generic code) for Curve25519. + * + * This implementation uses the generic code for modular integers (with + * 15-bit words) to support Curve25519. Due to the specificities of the + * curve definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_i15; + +/** + * \brief EC implementation "i31" (generic code) for Curve25519. + * + * This implementation uses the generic code for modular integers (with + * 31-bit words) to support Curve25519. Due to the specificities of the + * curve definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_i31; + +/** + * \brief EC implementation "m15" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 15 bits. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m15; + +/** + * \brief EC implementation "m31" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 31 bits. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m31; + +/** + * \brief Aggregate EC implementation "m15". + * + * This implementation is a wrapper for: + * + * - `br_ec_c25519_m15` for Curve25519 + * - `br_ec_p256_m15` for NIST P-256 + * - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512) + */ +extern const br_ec_impl br_ec_all_m15; + +/** + * \brief Aggregate EC implementation "m31". + * + * This implementation is a wrapper for: + * + * - `br_ec_c25519_m31` for Curve25519 + * - `br_ec_p256_m31` for NIST P-256 + * - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512) + */ +extern const br_ec_impl br_ec_all_m31; + +/** + * \brief Get the "default" EC implementation for the current system. + * + * This returns a pointer to the preferred implementation on the + * current system. + * + * \return the default EC implementation. + */ +const br_ec_impl *br_ec_get_default(void); + +/** + * \brief Convert a signature from "raw" to "asn1". + * + * Conversion is done "in place" and the new length is returned. + * Conversion may enlarge the signature, but by no more than 9 bytes at + * most. On error, 0 is returned (error conditions include an odd raw + * signature length, or an oversized integer). + * + * \param sig signature to convert. + * \param sig_len signature length (in bytes). + * \return the new signature length, or 0 on error. + */ +size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len); + +/** + * \brief Convert a signature from "asn1" to "raw". + * + * Conversion is done "in place" and the new length is returned. + * Conversion may enlarge the signature, but the new signature length + * will be less than twice the source length at most. On error, 0 is + * returned (error conditions include an invalid ASN.1 structure or an + * oversized integer). + * + * \param sig signature to convert. + * \param sig_len signature length (in bytes). + * \return the new signature length, or 0 on error. + */ +size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len); + +/** + * \brief Type for an ECDSA signer function. + * + * A pointer to the EC implementation is provided. The hash value is + * assumed to have the length inferred from the designated hash function + * class. + * + * Signature is written in the buffer pointed to by `sig`, and the length + * (in bytes) is returned. On error, nothing is written in the buffer, + * and 0 is returned. This function returns 0 if the specified curve is + * not supported by the provided EC implementation. + * + * The signature format is either "raw" or "asn1", depending on the + * implementation; maximum length is predictable from the implemented + * curve: + * + * | curve | raw | asn1 | + * | :--------- | --: | ---: | + * | NIST P-256 | 64 | 72 | + * | NIST P-384 | 96 | 104 | + * | NIST P-521 | 132 | 139 | + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +typedef size_t (*br_ecdsa_sign)(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief Type for an ECDSA signature verification function. + * + * A pointer to the EC implementation is provided. The hashed value, + * computed over the purportedly signed data, is also provided with + * its length. + * + * The signature format is either "raw" or "asn1", depending on the + * implementation. + * + * Returned value is 1 on success (valid signature), 0 on error. This + * function returns 0 if the specified curve is not supported by the + * provided EC implementation. + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_ecdsa_vrfy)(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature generator, "i31" implementation, "asn1" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i31_sign_asn1(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature generator, "i31" implementation, "raw" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i31_sign_raw(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature verifier, "i31" implementation, "asn1" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature verifier, "i31" implementation, "raw" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature generator, "i15" implementation, "asn1" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i15_sign_asn1(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature generator, "i15" implementation, "raw" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i15_sign_raw(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature verifier, "i15" implementation, "asn1" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature verifier, "i15" implementation, "raw" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief Get "default" ECDSA implementation (signer, asn1 format). + * + * This returns the preferred implementation of ECDSA signature generation + * ("asn1" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_sign br_ecdsa_sign_asn1_get_default(void); + +/** + * \brief Get "default" ECDSA implementation (signer, raw format). + * + * This returns the preferred implementation of ECDSA signature generation + * ("raw" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_sign br_ecdsa_sign_raw_get_default(void); + +/** + * \brief Get "default" ECDSA implementation (verifier, asn1 format). + * + * This returns the preferred implementation of ECDSA signature verification + * ("asn1" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_vrfy br_ecdsa_vrfy_asn1_get_default(void); + +/** + * \brief Get "default" ECDSA implementation (verifier, raw format). + * + * This returns the preferred implementation of ECDSA signature verification + * ("raw" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_vrfy br_ecdsa_vrfy_raw_get_default(void); + +/** + * \brief Maximum size for EC private key element buffer. + * + * This is the largest number of bytes that `br_ec_keygen()` may need or + * ever return. + */ +#define BR_EC_KBUF_PRIV_MAX_SIZE 72 + +/** + * \brief Maximum size for EC public key element buffer. + * + * This is the largest number of bytes that `br_ec_compute_public()` may + * need or ever return. + */ +#define BR_EC_KBUF_PUB_MAX_SIZE 145 + +/** + * \brief Generate a new EC private key. + * + * If the specified `curve` is not supported by the elliptic curve + * implementation (`impl`), then this function returns zero. + * + * The `sk` structure fields are set to the new private key data. In + * particular, `sk.x` is made to point to the provided key buffer (`kbuf`), + * in which the actual private key data is written. That buffer is assumed + * to be large enough. The `BR_EC_KBUF_PRIV_MAX_SIZE` defines the maximum + * size for all supported curves. + * + * The number of bytes used in `kbuf` is returned. If `kbuf` is `NULL`, then + * the private key is not actually generated, and `sk` may also be `NULL`; + * the minimum length for `kbuf` is still computed and returned. + * + * If `sk` is `NULL` but `kbuf` is not `NULL`, then the private key is + * still generated and stored in `kbuf`. + * + * \param rng_ctx source PRNG context (already initialized). + * \param impl the elliptic curve implementation. + * \param sk the private key structure to fill, or `NULL`. + * \param kbuf the key element buffer, or `NULL`. + * \param curve the curve identifier. + * \return the key data length (in bytes), or zero. + */ +size_t br_ec_keygen(const br_prng_class **rng_ctx, + const br_ec_impl *impl, br_ec_private_key *sk, + void *kbuf, int curve); + +/** + * \brief Compute EC public key from EC private key. + * + * This function uses the provided elliptic curve implementation (`impl`) + * to compute the public key corresponding to the private key held in `sk`. + * The public key point is written into `kbuf`, which is then linked from + * the `*pk` structure. The size of the public key point, i.e. the number + * of bytes used in `kbuf`, is returned. + * + * If `kbuf` is `NULL`, then the public key point is NOT computed, and + * the public key structure `*pk` is unmodified (`pk` may be `NULL` in + * that case). The size of the public key point is still returned. + * + * If `pk` is `NULL` but `kbuf` is not `NULL`, then the public key + * point is computed and stored in `kbuf`, and its size is returned. + * + * If the curve used by the private key is not supported by the curve + * implementation, then this function returns zero. + * + * The private key MUST be valid. An off-range private key value is not + * necessarily detected, and leads to unpredictable results. + * + * \param impl the elliptic curve implementation. + * \param pk the public key structure to fill (or `NULL`). + * \param kbuf the public key point buffer (or `NULL`). + * \param sk the source private key. + * \return the public key point length (in bytes), or zero. + */ +size_t br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk, + void *kbuf, const br_ec_private_key *sk); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_hash.h b/bearssl_hash.h new file mode 100644 index 0000000..3b15ba7 --- /dev/null +++ b/bearssl_hash.h @@ -0,0 +1,1346 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_HASH_H__ +#define BR_BEARSSL_HASH_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_hash.h + * + * # Hash Functions + * + * This file documents the API for hash functions. + * + * + * ## Procedural API + * + * For each implemented hash function, of name "`xxx`", the following + * elements are defined: + * + * - `br_xxx_vtable` + * + * An externally defined instance of `br_hash_class`. + * + * - `br_xxx_SIZE` + * + * A macro that evaluates to the output size (in bytes) of the + * hash function. + * + * - `br_xxx_ID` + * + * A macro that evaluates to a symbolic identifier for the hash + * function. Such identifiers are used with HMAC and signature + * algorithm implementations. + * + * NOTE: for the "standard" hash functions defined in [the TLS + * standard](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1), + * the symbolic identifiers match the constants used in TLS, i.e. + * 1 to 6 for MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512, + * respectively. + * + * - `br_xxx_context` + * + * Context for an ongoing computation. It is allocated by the + * caller, and a pointer to it is passed to all functions. A + * context contains no interior pointer, so it can be moved around + * and cloned (with a simple `memcpy()` or equivalent) in order to + * capture the function state at some point. Computations that use + * distinct context structures are independent of each other. The + * first field of `br_xxx_context` is always a pointer to the + * `br_xxx_vtable` structure; `br_xxx_init()` sets that pointer. + * + * - `br_xxx_init(br_xxx_context *ctx)` + * + * Initialise the provided context. Previous contents of the structure + * are ignored. This calls resets the context to the start of a new + * hash computation; it also sets the first field of the context + * structure (called `vtable`) to a pointer to the statically + * allocated constant `br_xxx_vtable` structure. + * + * - `br_xxx_update(br_xxx_context *ctx, const void *data, size_t len)` + * + * Add some more bytes to the hash computation represented by the + * provided context. + * + * - `br_xxx_out(const br_xxx_context *ctx, void *out)` + * + * Complete the hash computation and write the result in the provided + * buffer. The output buffer MUST be large enough to accommodate the + * result. The context is NOT modified by this operation, so this + * function can be used to get a "partial hash" while still keeping + * the possibility of adding more bytes to the input. + * + * - `br_xxx_state(const br_xxx_context *ctx, void *out)` + * + * Get a copy of the "current state" for the computation so far. For + * MD functions (MD5, SHA-1, SHA-2 family), this is the running state + * resulting from the processing of the last complete input block. + * Returned value is the current input length (in bytes). + * + * - `br_xxx_set_state(br_xxx_context *ctx, const void *stb, uint64_t count)` + * + * Set the internal state to the provided values. The 'stb' and + * 'count' values shall match that which was obtained from + * `br_xxx_state()`. This restores the hash state only if the state + * values were at an appropriate block boundary. This does NOT set + * the `vtable` pointer in the context. + * + * Context structures can be discarded without any explicit deallocation. + * Hash function implementations are purely software and don't reserve + * any resources outside of the context structure itself. + * + * + * ## Object-Oriented API + * + * For each hash function that follows the procedural API described + * above, an object-oriented API is also provided. In that API, function + * pointers from the vtable (`br_xxx_vtable`) are used. The vtable + * incarnates object-oriented programming. An introduction on the OOP + * concept used here can be read on the BearSSL Web site:
+ *    [https://www.bearssl.org/oop.html](https://www.bearssl.org/oop.html) + * + * The vtable offers functions called `init()`, `update()`, `out()`, + * `set()` and `set_state()`, which are in fact the functions from + * the procedural API. That vtable also contains two informative fields: + * + * - `context_size` + * + * The size of the context structure (`br_xxx_context`), in bytes. + * This can be used by generic implementations to perform dynamic + * context allocation. + * + * - `desc` + * + * A "descriptor" field that encodes some information on the hash + * function: symbolic identifier, output size, state size, + * internal block size, details on the padding. + * + * Users of this object-oriented API (in particular generic HMAC + * implementations) may make the following assumptions: + * + * - Hash output size is no more than 64 bytes. + * - Hash internal state size is no more than 64 bytes. + * - Internal block size is a power of two, no less than 16 and no more + * than 256. + * + * + * ## Implemented Hash Functions + * + * Implemented hash functions are: + * + * | Function | Name | Output length | State length | + * | :-------- | :------ | :-----------: | :----------: | + * | MD5 | md5 | 16 | 16 | + * | SHA-1 | sha1 | 20 | 20 | + * | SHA-224 | sha224 | 28 | 32 | + * | SHA-256 | sha256 | 32 | 32 | + * | SHA-384 | sha384 | 48 | 64 | + * | SHA-512 | sha512 | 64 | 64 | + * | MD5+SHA-1 | md5sha1 | 36 | 36 | + * + * (MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the + * same input; in the implementation, the internal data buffer is + * shared, thus making it more memory-efficient than separate MD5 and + * SHA-1. It can be useful in implementing SSL 3.0, TLS 1.0 and TLS + * 1.1.) + * + * + * ## Multi-Hasher + * + * An aggregate hasher is provided, that can compute several standard + * hash functions in parallel. It uses `br_multihash_context` and a + * procedural API. It is configured with the implementations (the vtables) + * that it should use; it will then compute all these hash functions in + * parallel, on the same input. It is meant to be used in cases when the + * hash of an object will be used, but the exact hash function is not + * known yet (typically, streamed processing on X.509 certificates). + * + * Only the standard hash functions (MD5, SHA-1, SHA-224, SHA-256, SHA-384 + * and SHA-512) are supported by the multi-hasher. + * + * + * ## GHASH + * + * GHASH is not a generic hash function; it is a _universal_ hash function, + * which, as the name does not say, means that it CANNOT be used in most + * places where a hash function is needed. GHASH is used within the GCM + * encryption mode, to provide the checked integrity functionality. + * + * A GHASH implementation is basically a function that uses the type defined + * in this file under the name `br_ghash`: + * + * typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len); + * + * The `y` pointer refers to a 16-byte value which is used as input, and + * receives the output of the GHASH invocation. `h` is a 16-byte secret + * value (that serves as key). `data` and `len` define the input data. + * + * Three GHASH implementations are provided, all constant-time, based on + * the use of integer multiplications with appropriate masking to cancel + * carry propagation. + */ + +/** + * \brief Class type for hash function implementations. + * + * A `br_hash_class` instance references the methods implementing a hash + * function. Constant instances of this structure are defined for each + * implemented hash function. Such instances are also called "vtables". + * + * Vtables are used to support object-oriented programming, as + * described on [the BearSSL Web site](https://www.bearssl.org/oop.html). + */ +typedef struct br_hash_class_ br_hash_class; +struct br_hash_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate for + * computing this hash function. + */ + size_t context_size; + + /** + * \brief Descriptor word that contains information about the hash + * function. + * + * For each word `xxx` described below, use `BR_HASHDESC_xxx_OFF` + * and `BR_HASHDESC_xxx_MASK` to access the specific value, as + * follows: + * + * (hf->desc >> BR_HASHDESC_xxx_OFF) & BR_HASHDESC_xxx_MASK + * + * The defined elements are: + * + * - `ID`: the symbolic identifier for the function, as defined + * in [TLS](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1) + * (MD5 = 1, SHA-1 = 2,...). + * + * - `OUT`: hash output size, in bytes. + * + * - `STATE`: internal running state size, in bytes. + * + * - `LBLEN`: base-2 logarithm for the internal block size, as + * defined for HMAC processing (this is 6 for MD5, SHA-1, SHA-224 + * and SHA-256, since these functions use 64-byte blocks; for + * SHA-384 and SHA-512, this is 7, corresponding to their + * 128-byte blocks). + * + * The descriptor may contain a few other flags. + */ + uint32_t desc; + + /** + * \brief Initialisation method. + * + * This method takes as parameter a pointer to a context area, + * that it initialises. The first field of the context is set + * to this vtable; other elements are initialised for a new hash + * computation. + * + * \param ctx pointer to (the first field of) the context. + */ + void (*init)(const br_hash_class **ctx); + + /** + * \brief Data injection method. + * + * The `len` bytes starting at address `data` are injected into + * the running hash computation incarnated by the specified + * context. The context is updated accordingly. It is allowed + * to have `len == 0`, in which case `data` is ignored (and could + * be `NULL`), and nothing happens. + * on the input data. + * + * \param ctx pointer to (the first field of) the context. + * \param data pointer to the first data byte to inject. + * \param len number of bytes to inject. + */ + void (*update)(const br_hash_class **ctx, const void *data, size_t len); + + /** + * \brief Produce hash output. + * + * The hash output corresponding to all data bytes injected in the + * context since the last `init()` call is computed, and written + * in the buffer pointed to by `dst`. The hash output size depends + * on the implemented hash function (e.g. 16 bytes for MD5). + * The context is _not_ modified by this call, so further bytes + * may be afterwards injected to continue the current computation. + * + * \param ctx pointer to (the first field of) the context. + * \param dst destination buffer for the hash output. + */ + void (*out)(const br_hash_class *const *ctx, void *dst); + + /** + * \brief Get running state. + * + * This method saves the current running state into the `dst` + * buffer. What constitutes the "running state" depends on the + * hash function; for Merkle-Damgård hash functions (like + * MD5 or SHA-1), this is the output obtained after processing + * each block. The number of bytes injected so far is returned. + * The context is not modified by this call. + * + * \param ctx pointer to (the first field of) the context. + * \param dst destination buffer for the state. + * \return the injected total byte length. + */ + uint64_t (*state)(const br_hash_class *const *ctx, void *dst); + + /** + * \brief Set running state. + * + * This methods replaces the running state for the function. + * + * \param ctx pointer to (the first field of) the context. + * \param stb source buffer for the state. + * \param count injected total byte length. + */ + void (*set_state)(const br_hash_class **ctx, + const void *stb, uint64_t count); +}; + +#ifndef BR_DOXYGEN_IGNORE +#define BR_HASHDESC_ID(id) ((uint32_t)(id) << BR_HASHDESC_ID_OFF) +#define BR_HASHDESC_ID_OFF 0 +#define BR_HASHDESC_ID_MASK 0xFF + +#define BR_HASHDESC_OUT(size) ((uint32_t)(size) << BR_HASHDESC_OUT_OFF) +#define BR_HASHDESC_OUT_OFF 8 +#define BR_HASHDESC_OUT_MASK 0x7F + +#define BR_HASHDESC_STATE(size) ((uint32_t)(size) << BR_HASHDESC_STATE_OFF) +#define BR_HASHDESC_STATE_OFF 15 +#define BR_HASHDESC_STATE_MASK 0xFF + +#define BR_HASHDESC_LBLEN(ls) ((uint32_t)(ls) << BR_HASHDESC_LBLEN_OFF) +#define BR_HASHDESC_LBLEN_OFF 23 +#define BR_HASHDESC_LBLEN_MASK 0x0F + +#define BR_HASHDESC_MD_PADDING ((uint32_t)1 << 28) +#define BR_HASHDESC_MD_PADDING_128 ((uint32_t)1 << 29) +#define BR_HASHDESC_MD_PADDING_BE ((uint32_t)1 << 30) +#endif + +/* + * Specific hash functions. + * + * Rules for contexts: + * -- No interior pointer. + * -- No pointer to external dynamically allocated resources. + * -- First field is called 'vtable' and is a pointer to a + * const-qualified br_hash_class instance (pointer is set by init()). + * -- SHA-224 and SHA-256 contexts are identical. + * -- SHA-384 and SHA-512 contexts are identical. + * + * Thus, contexts can be moved and cloned to capture the hash function + * current state; and there is no need for any explicit "release" function. + */ + +/** + * \brief Symbolic identifier for MD5. + */ +#define br_md5_ID 1 + +/** + * \brief MD5 output size (in bytes). + */ +#define br_md5_SIZE 16 + +/** + * \brief Constant vtable for MD5. + */ +extern const br_hash_class br_md5_vtable; + +/** + * \brief MD5 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val[4]; +#endif +} br_md5_context; + +/** + * \brief MD5 context initialisation. + * + * This function initialises or resets a context for a new MD5 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_md5_init(br_md5_context *ctx); + +/** + * \brief Inject some data bytes in a running MD5 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_md5_update(br_md5_context *ctx, const void *data, size_t len); + +/** + * \brief Compute MD5 output. + * + * The MD5 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_md5_out(const br_md5_context *ctx, void *out); + +/** + * \brief Save MD5 running state. + * + * The running state for MD5 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_md5_state(const br_md5_context *ctx, void *out); + +/** + * \brief Restore MD5 running state. + * + * The running state for MD5 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_md5_set_state(br_md5_context *ctx, const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-1. + */ +#define br_sha1_ID 2 + +/** + * \brief SHA-1 output size (in bytes). + */ +#define br_sha1_SIZE 20 + +/** + * \brief Constant vtable for SHA-1. + */ +extern const br_hash_class br_sha1_vtable; + +/** + * \brief SHA-1 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val[5]; +#endif +} br_sha1_context; + +/** + * \brief SHA-1 context initialisation. + * + * This function initialises or resets a context for a new SHA-1 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha1_init(br_sha1_context *ctx); + +/** + * \brief Inject some data bytes in a running SHA-1 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha1_update(br_sha1_context *ctx, const void *data, size_t len); + +/** + * \brief Compute SHA-1 output. + * + * The SHA-1 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha1_out(const br_sha1_context *ctx, void *out); + +/** + * \brief Save SHA-1 running state. + * + * The running state for SHA-1 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha1_state(const br_sha1_context *ctx, void *out); + +/** + * \brief Restore SHA-1 running state. + * + * The running state for SHA-1 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha1_set_state(br_sha1_context *ctx, const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-224. + */ +#define br_sha224_ID 3 + +/** + * \brief SHA-224 output size (in bytes). + */ +#define br_sha224_SIZE 28 + +/** + * \brief Constant vtable for SHA-224. + */ +extern const br_hash_class br_sha224_vtable; + +/** + * \brief SHA-224 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val[8]; +#endif +} br_sha224_context; + +/** + * \brief SHA-224 context initialisation. + * + * This function initialises or resets a context for a new SHA-224 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha224_init(br_sha224_context *ctx); + +/** + * \brief Inject some data bytes in a running SHA-224 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha224_update(br_sha224_context *ctx, const void *data, size_t len); + +/** + * \brief Compute SHA-224 output. + * + * The SHA-224 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha224_out(const br_sha224_context *ctx, void *out); + +/** + * \brief Save SHA-224 running state. + * + * The running state for SHA-224 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha224_state(const br_sha224_context *ctx, void *out); + +/** + * \brief Restore SHA-224 running state. + * + * The running state for SHA-224 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha224_set_state(br_sha224_context *ctx, + const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-256. + */ +#define br_sha256_ID 4 + +/** + * \brief SHA-256 output size (in bytes). + */ +#define br_sha256_SIZE 32 + +/** + * \brief Constant vtable for SHA-256. + */ +extern const br_hash_class br_sha256_vtable; + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief SHA-256 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +} br_sha256_context; +#else +typedef br_sha224_context br_sha256_context; +#endif + +/** + * \brief SHA-256 context initialisation. + * + * This function initialises or resets a context for a new SHA-256 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha256_init(br_sha256_context *ctx); + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Inject some data bytes in a running SHA-256 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha256_update(br_sha256_context *ctx, const void *data, size_t len); +#else +#define br_sha256_update br_sha224_update +#endif + +/** + * \brief Compute SHA-256 output. + * + * The SHA-256 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha256_out(const br_sha256_context *ctx, void *out); + +#if BR_DOXYGEN_IGNORE +/** + * \brief Save SHA-256 running state. + * + * The running state for SHA-256 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha256_state(const br_sha256_context *ctx, void *out); +#else +#define br_sha256_state br_sha224_state +#endif + +#if BR_DOXYGEN_IGNORE +/** + * \brief Restore SHA-256 running state. + * + * The running state for SHA-256 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha256_set_state(br_sha256_context *ctx, + const void *stb, uint64_t count); +#else +#define br_sha256_set_state br_sha224_set_state +#endif + +/** + * \brief Symbolic identifier for SHA-384. + */ +#define br_sha384_ID 5 + +/** + * \brief SHA-384 output size (in bytes). + */ +#define br_sha384_SIZE 48 + +/** + * \brief Constant vtable for SHA-384. + */ +extern const br_hash_class br_sha384_vtable; + +/** + * \brief SHA-384 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[128]; + uint64_t count; + uint64_t val[8]; +#endif +} br_sha384_context; + +/** + * \brief SHA-384 context initialisation. + * + * This function initialises or resets a context for a new SHA-384 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha384_init(br_sha384_context *ctx); + +/** + * \brief Inject some data bytes in a running SHA-384 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha384_update(br_sha384_context *ctx, const void *data, size_t len); + +/** + * \brief Compute SHA-384 output. + * + * The SHA-384 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha384_out(const br_sha384_context *ctx, void *out); + +/** + * \brief Save SHA-384 running state. + * + * The running state for SHA-384 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha384_state(const br_sha384_context *ctx, void *out); + +/** + * \brief Restore SHA-384 running state. + * + * The running state for SHA-384 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha384_set_state(br_sha384_context *ctx, + const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-512. + */ +#define br_sha512_ID 6 + +/** + * \brief SHA-512 output size (in bytes). + */ +#define br_sha512_SIZE 64 + +/** + * \brief Constant vtable for SHA-512. + */ +extern const br_hash_class br_sha512_vtable; + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief SHA-512 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +} br_sha512_context; +#else +typedef br_sha384_context br_sha512_context; +#endif + +/** + * \brief SHA-512 context initialisation. + * + * This function initialises or resets a context for a new SHA-512 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha512_init(br_sha512_context *ctx); + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Inject some data bytes in a running SHA-512 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha512_update(br_sha512_context *ctx, const void *data, size_t len); +#else +#define br_sha512_update br_sha384_update +#endif + +/** + * \brief Compute SHA-512 output. + * + * The SHA-512 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha512_out(const br_sha512_context *ctx, void *out); + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Save SHA-512 running state. + * + * The running state for SHA-512 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha512_state(const br_sha512_context *ctx, void *out); +#else +#define br_sha512_state br_sha384_state +#endif + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Restore SHA-512 running state. + * + * The running state for SHA-512 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha512_set_state(br_sha512_context *ctx, + const void *stb, uint64_t count); +#else +#define br_sha512_set_state br_sha384_set_state +#endif + +/* + * "md5sha1" is a special hash function that computes both MD5 and SHA-1 + * on the same input, and produces a 36-byte output (MD5 and SHA-1 + * concatenation, in that order). State size is also 36 bytes. + */ + +/** + * \brief Symbolic identifier for MD5+SHA-1. + * + * MD5+SHA-1 is the concatenation of MD5 and SHA-1, computed over the + * same input. It is not one of the functions identified in TLS, so + * we give it a symbolic identifier of value 0. + */ +#define br_md5sha1_ID 0 + +/** + * \brief MD5+SHA-1 output size (in bytes). + */ +#define br_md5sha1_SIZE 36 + +/** + * \brief Constant vtable for MD5+SHA-1. + */ +extern const br_hash_class br_md5sha1_vtable; + +/** + * \brief MD5+SHA-1 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val_md5[4]; + uint32_t val_sha1[5]; +#endif +} br_md5sha1_context; + +/** + * \brief MD5+SHA-1 context initialisation. + * + * This function initialises or resets a context for a new SHA-512 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_md5sha1_init(br_md5sha1_context *ctx); + +/** + * \brief Inject some data bytes in a running MD5+SHA-1 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_md5sha1_update(br_md5sha1_context *ctx, const void *data, size_t len); + +/** + * \brief Compute MD5+SHA-1 output. + * + * The MD5+SHA-1 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_md5sha1_out(const br_md5sha1_context *ctx, void *out); + +/** + * \brief Save MD5+SHA-1 running state. + * + * The running state for MD5+SHA-1 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_md5sha1_state(const br_md5sha1_context *ctx, void *out); + +/** + * \brief Restore MD5+SHA-1 running state. + * + * The running state for MD5+SHA-1 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_md5sha1_set_state(br_md5sha1_context *ctx, + const void *stb, uint64_t count); + +/** + * \brief Aggregate context for configurable hash function support. + * + * The `br_hash_compat_context` type is a type which is large enough to + * serve as context for all standard hash functions defined above. + */ +typedef union { + const br_hash_class *vtable; + br_md5_context md5; + br_sha1_context sha1; + br_sha224_context sha224; + br_sha256_context sha256; + br_sha384_context sha384; + br_sha512_context sha512; + br_md5sha1_context md5sha1; +} br_hash_compat_context; + +/* + * The multi-hasher is a construct that handles hashing of the same input + * data with several hash functions, with a single shared input buffer. + * It can handle MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 + * simultaneously, though which functions are activated depends on + * the set implementation pointers. + */ + +/** + * \brief Multi-hasher context structure. + * + * The multi-hasher runs up to six hash functions in the standard TLS list + * (MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512) in parallel, over + * the same input. + * + * The multi-hasher does _not_ follow the OOP structure with a vtable. + * Instead, it is configured with the vtables of the hash functions it + * should run. Structure fields are not supposed to be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[128]; + uint64_t count; + uint32_t val_32[25]; + uint64_t val_64[16]; + const br_hash_class *impl[6]; +#endif +} br_multihash_context; + +/** + * \brief Clear a multi-hasher context. + * + * This should always be called once on a given context, _before_ setting + * the implementation pointers. + * + * \param ctx the multi-hasher context. + */ +void br_multihash_zero(br_multihash_context *ctx); + +/** + * \brief Set a hash function implementation. + * + * Implementations shall be set _after_ clearing the context (with + * `br_multihash_zero()`) but _before_ initialising the computation + * (with `br_multihash_init()`). The hash function implementation + * MUST be one of the standard hash functions (MD5, SHA-1, SHA-224, + * SHA-256, SHA-384 or SHA-512); it may also be `NULL` to remove + * an implementation from the multi-hasher. + * + * \param ctx the multi-hasher context. + * \param id the hash function symbolic identifier. + * \param impl the hash function vtable, or `NULL`. + */ +static inline void +br_multihash_setimpl(br_multihash_context *ctx, + int id, const br_hash_class *impl) +{ + /* + * This code relies on hash functions ID being values 1 to 6, + * in the MD5 to SHA-512 order. + */ + ctx->impl[id - 1] = impl; +} + +/** + * \brief Get a hash function implementation. + * + * This function returns the currently configured vtable for a given + * hash function (by symbolic ID). If no such function was configured in + * the provided multi-hasher context, then this function returns `NULL`. + * + * \param ctx the multi-hasher context. + * \param id the hash function symbolic identifier. + * \return the hash function vtable, or `NULL`. + */ +static inline const br_hash_class * +br_multihash_getimpl(const br_multihash_context *ctx, int id) +{ + return ctx->impl[id - 1]; +} + +/** + * \brief Reset a multi-hasher context. + * + * This function prepares the context for a new hashing computation, + * for all implementations configured at that point. + * + * \param ctx the multi-hasher context. + */ +void br_multihash_init(br_multihash_context *ctx); + +/** + * \brief Inject some data bytes in a running multi-hashing computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_multihash_update(br_multihash_context *ctx, + const void *data, size_t len); + +/** + * \brief Compute a hash output from a multi-hasher. + * + * The hash output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `dst`. The hash + * function to use is identified by `id` and must be one of the standard + * hash functions. If that hash function was indeed configured in the + * multi-hasher context, the corresponding hash value is written in + * `dst` and its length (in bytes) is returned. If the hash function + * was _not_ configured, then nothing is written in `dst` and 0 is + * returned. + * + * The context itself is not modified, so extra bytes may be injected + * afterwards to continue the hash computations. + * + * \param ctx pointer to the context structure. + * \param id the hash function symbolic identifier. + * \param dst destination buffer for the hash output. + * \return the hash output length (in bytes), or 0. + */ +size_t br_multihash_out(const br_multihash_context *ctx, int id, void *dst); + +/** + * \brief Type for a GHASH implementation. + * + * GHASH is a sort of keyed hash meant to be used to implement GCM in + * combination with a block cipher (with 16-byte blocks). + * + * The `y` array has length 16 bytes and is used for input and output; in + * a complete GHASH run, it starts with an all-zero value. `h` is a 16-byte + * value that serves as key (it is derived from the encryption key in GCM, + * using the block cipher). The data length (`len`) is expressed in bytes. + * The `y` array is updated. + * + * If the data length is not a multiple of 16, then the data is implicitly + * padded with zeros up to the next multiple of 16. Thus, when using GHASH + * in GCM, this method may be called twice, for the associated data and + * for the ciphertext, respectively; the zero-padding implements exactly + * the GCM rules. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using multiplications (mixed 32-bit). + * + * This implementation uses multiplications of 32-bit values, with a + * 64-bit result. It is constant-time (if multiplications are + * constant-time). + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_ctmul(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using multiplications (strict 32-bit). + * + * This implementation uses multiplications of 32-bit values, with a + * 32-bit result. It is usually somewhat slower than `br_ghash_ctmul()`, + * but it is expected to be faster on architectures for which the + * 32-bit multiplication opcode does not yield the upper 32 bits of the + * product. It is constant-time (if multiplications are constant-time). + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using multiplications (64-bit). + * + * This implementation uses multiplications of 64-bit values, with a + * 64-bit result. It is constant-time (if multiplications are + * constant-time). It is substantially faster than `br_ghash_ctmul()` + * and `br_ghash_ctmul32()` on most 64-bit architectures. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using the `pclmulqdq` opcode (part of the + * AES-NI instructions). + * + * This implementation is available only on x86 platforms where the + * compiler supports the relevant intrinsic functions. Even if the + * compiler supports these functions, the local CPU might not support + * the `pclmulqdq` opcode, meaning that a call will fail with an + * illegal instruction exception. To safely obtain a pointer to this + * function when supported (or 0 otherwise), use `br_ghash_pclmul_get()`. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_pclmul(void *y, const void *h, const void *data, size_t len); + +/** + * \brief Obtain the `pclmul` GHASH implementation, if available. + * + * If the `pclmul` implementation was compiled in the library (depending + * on the compiler abilities) _and_ the local CPU appears to support the + * opcode, then this function will return a pointer to the + * `br_ghash_pclmul()` function. Otherwise, it will return `0`. + * + * \return the `pclmul` GHASH implementation, or `0`. + */ +br_ghash br_ghash_pclmul_get(void); + +/** + * \brief GHASH implementation using the POWER8 opcodes. + * + * This implementation is available only on POWER8 platforms (and later). + * To safely obtain a pointer to this function when supported (or 0 + * otherwise), use `br_ghash_pwr8_get()`. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_pwr8(void *y, const void *h, const void *data, size_t len); + +/** + * \brief Obtain the `pwr8` GHASH implementation, if available. + * + * If the `pwr8` implementation was compiled in the library (depending + * on the compiler abilities) _and_ the local CPU appears to support the + * opcode, then this function will return a pointer to the + * `br_ghash_pwr8()` function. Otherwise, it will return `0`. + * + * \return the `pwr8` GHASH implementation, or `0`. + */ +br_ghash br_ghash_pwr8_get(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_hmac.h b/bearssl_hmac.h new file mode 100644 index 0000000..4dc01ca --- /dev/null +++ b/bearssl_hmac.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_HMAC_H__ +#define BR_BEARSSL_HMAC_H__ + +#include +#include + +#include "bearssl_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_hmac.h + * + * # HMAC + * + * HMAC is initialized with a key and an underlying hash function; it + * then fills a "key context". That context contains the processed + * key. + * + * With the key context, a HMAC context can be initialized to process + * the input bytes and obtain the MAC output. The key context is not + * modified during that process, and can be reused. + * + * IMPORTANT: HMAC shall be used only with functions that have the + * following properties: + * + * - hash output size does not exceed 64 bytes; + * - hash internal state size does not exceed 64 bytes; + * - internal block length is a power of 2 between 16 and 256 bytes. + */ + +/** + * \brief HMAC key context. + * + * The HMAC key context is initialised with a hash function implementation + * and a secret key. Contents are opaque (callers should not access them + * directly). The caller is responsible for allocating the context where + * appropriate. Context initialisation and usage incurs no dynamic + * allocation, so there is no release function. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + const br_hash_class *dig_vtable; + unsigned char ksi[64], kso[64]; +#endif +} br_hmac_key_context; + +/** + * \brief HMAC key context initialisation. + * + * Initialise the key context with the provided key, using the hash function + * identified by `digest_vtable`. This supports arbitrary key lengths. + * + * \param kc HMAC key context to initialise. + * \param digest_vtable pointer to the hash function implementation vtable. + * \param key pointer to the HMAC secret key. + * \param key_len HMAC secret key length (in bytes). + */ +void br_hmac_key_init(br_hmac_key_context *kc, + const br_hash_class *digest_vtable, const void *key, size_t key_len); + +/* + * \brief Get the underlying hash function. + * + * This function returns a pointer to the implementation vtable of the + * hash function used for this HMAC key context. + * + * \param kc HMAC key context. + * \return the hash function implementation. + */ +static inline const br_hash_class *br_hmac_key_get_digest( + const br_hmac_key_context *kc) +{ + return kc->dig_vtable; +} + +/** + * \brief HMAC computation context. + * + * The HMAC computation context maintains the state for a single HMAC + * computation. It is modified as input bytes are injected. The context + * is caller-allocated and has no release function since it does not + * dynamically allocate external resources. Its contents are opaque. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + br_hash_compat_context dig; + unsigned char kso[64]; + size_t out_len; +#endif +} br_hmac_context; + +/** + * \brief HMAC computation initialisation. + * + * Initialise a HMAC context with a key context. The key context is + * unmodified. Relevant data from the key context is immediately copied; + * the key context can thus be independently reused, modified or released + * without impacting this HMAC computation. + * + * An explicit output length can be specified; the actual output length + * will be the minimum of that value and the natural HMAC output length. + * If `out_len` is 0, then the natural HMAC output length is selected. The + * "natural output length" is the output length of the underlying hash + * function. + * + * \param ctx HMAC context to initialise. + * \param kc HMAC key context (already initialised with the key). + * \param out_len HMAC output length (0 to select "natural length"). + */ +void br_hmac_init(br_hmac_context *ctx, + const br_hmac_key_context *kc, size_t out_len); + +/** + * \brief Get the HMAC output size. + * + * The HMAC output size is the number of bytes that will actually be + * produced with `br_hmac_out()` with the provided context. This function + * MUST NOT be called on a non-initialised HMAC computation context. + * The returned value is the minimum of the HMAC natural length (output + * size of the underlying hash function) and the `out_len` parameter which + * was used with the last `br_hmac_init()` call on that context (if the + * initialisation `out_len` parameter was 0, then this function will + * return the HMAC natural length). + * + * \param ctx the (already initialised) HMAC computation context. + * \return the HMAC actual output size. + */ +static inline size_t +br_hmac_size(br_hmac_context *ctx) +{ + return ctx->out_len; +} + +/* + * \brief Get the underlying hash function. + * + * This function returns a pointer to the implementation vtable of the + * hash function used for this HMAC context. + * + * \param hc HMAC context. + * \return the hash function implementation. + */ +static inline const br_hash_class *br_hmac_get_digest( + const br_hmac_context *hc) +{ + return hc->dig.vtable; +} + +/** + * \brief Inject some bytes in HMAC. + * + * The provided `len` bytes are injected as extra input in the HMAC + * computation incarnated by the `ctx` HMAC context. It is acceptable + * that `len` is zero, in which case `data` is ignored (and may be + * `NULL`) and this function does nothing. + */ +void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len); + +/** + * \brief Compute the HMAC output. + * + * The destination buffer MUST be large enough to accommodate the result; + * its length is at most the "natural length" of HMAC (i.e. the output + * length of the underlying hash function). The context is NOT modified; + * further bytes may be processed. Thus, "partial HMAC" values can be + * efficiently obtained. + * + * Returned value is the output length (in bytes). + * + * \param ctx HMAC computation context. + * \param out destination buffer for the HMAC output. + * \return the produced value length (in bytes). + */ +size_t br_hmac_out(const br_hmac_context *ctx, void *out); + +/** + * \brief Constant-time HMAC computation. + * + * This function compute the HMAC output in constant time. Some extra + * input bytes are processed, then the output is computed. The extra + * input consists in the `len` bytes pointed to by `data`. The `len` + * parameter must lie between `min_len` and `max_len` (inclusive); + * `max_len` bytes are actually read from `data`. Computing time (and + * memory access pattern) will not depend upon the data byte contents or + * the value of `len`. + * + * The output is written in the `out` buffer, that MUST be large enough + * to receive it. + * + * The difference `max_len - min_len` MUST be less than 230 + * (i.e. about one gigabyte). + * + * This function computes the output properly only if the underlying + * hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256, + * SHA-384 or SHA-512). + * + * The provided context is NOT modified. + * + * \param ctx the (already initialised) HMAC computation context. + * \param data the extra input bytes. + * \param len the extra input length (in bytes). + * \param min_len minimum extra input length (in bytes). + * \param max_len maximum extra input length (in bytes). + * \param out destination buffer for the HMAC output. + * \return the produced value length (in bytes). + */ +size_t br_hmac_outCT(const br_hmac_context *ctx, + const void *data, size_t len, size_t min_len, size_t max_len, + void *out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_kdf.h b/bearssl_kdf.h new file mode 100644 index 0000000..f018d7e --- /dev/null +++ b/bearssl_kdf.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_KDF_H__ +#define BR_BEARSSL_KDF_H__ + +#include +#include + +#include "bearssl_hash.h" +#include "bearssl_hmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_kdf.h + * + * # Key Derivation Functions + * + * KDF are functions that takes a variable length input, and provide a + * variable length output, meant to be used to derive subkeys from a + * master key. + * + * ## HKDF + * + * HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869). + * It is based on HMAC, itself using an underlying hash function. Any + * hash function can be used, as long as it is compatible with the rules + * for the HMAC implementation (i.e. output size is 64 bytes or less, hash + * internal state size is 64 bytes or less, and the internal block length is + * a power of 2 between 16 and 256 bytes). HKDF has two phases: + * + * - HKDF-Extract: the input data in ingested, along with a "salt" value. + * + * - HKDF-Expand: the output is produced, from the result of processing + * the input and salt, and using an extra non-secret parameter called + * "info". + * + * The "salt" and "info" strings are non-secret and can be empty. Their role + * is normally to bind the input and output, respectively, to conventional + * identifiers that qualifu them within the used protocol or application. + * + * The implementation defined in this file uses the following functions: + * + * - `br_hkdf_init()`: initialize an HKDF context, with a hash function, + * and the salt. This starts the HKDF-Extract process. + * + * - `br_hkdf_inject()`: inject more input bytes. This function may be + * called repeatedly if the input data is provided by chunks. + * + * - `br_hkdf_flip()`: end the HKDF-Extract process, and start the + * HKDF-Expand process. + * + * - `br_hkdf_produce()`: get the next bytes of output. This function + * may be called several times to obtain the full output by chunks. + * For correct HKDF processing, the same "info" string must be + * provided for each call. + * + * Note that the HKDF total output size (the number of bytes that + * HKDF-Expand is willing to produce) is limited: if the hash output size + * is _n_ bytes, then the maximum output size is _255*n_. + */ + +/** + * \brief HKDF context. + * + * The HKDF context is initialized with a hash function implementation + * and a salt value. Contents are opaque (callers should not access them + * directly). The caller is responsible for allocating the context where + * appropriate. Context initialisation and usage incurs no dynamic + * allocation, so there is no release function. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + union { + br_hmac_context hmac_ctx; + br_hmac_key_context prk_ctx; + } u; + unsigned char buf[64]; + size_t ptr; + size_t dig_len; + unsigned chunk_num; +#endif +} br_hkdf_context; + +/** + * \brief HKDF context initialization. + * + * The underlying hash function and salt value are provided. Arbitrary + * salt lengths can be used. + * + * HKDF makes a difference between a salt of length zero, and an + * absent salt (the latter being equivalent to a salt consisting of + * bytes of value zero, of the same length as the hash function output). + * If `salt_len` is zero, then this function assumes that the salt is + * present but of length zero. To specify an _absent_ salt, use + * `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored). + * + * \param hc HKDF context to initialise. + * \param digest_vtable pointer to the hash function implementation vtable. + * \param salt HKDF-Extract salt. + * \param salt_len HKDF-Extract salt length (in bytes). + */ +void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable, + const void *salt, size_t salt_len); + +/** + * \brief The special "absent salt" value for HKDF. + */ +#define BR_HKDF_NO_SALT (&br_hkdf_no_salt) + +#ifndef BR_DOXYGEN_IGNORE +extern const unsigned char br_hkdf_no_salt; +#endif + +/** + * \brief HKDF input injection (HKDF-Extract). + * + * This function injects some more input bytes ("key material") into + * HKDF. This function may be called several times, after `br_hkdf_init()` + * but before `br_hkdf_flip()`. + * + * \param hc HKDF context. + * \param ikm extra input bytes. + * \param ikm_len number of extra input bytes. + */ +void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len); + +/** + * \brief HKDF switch to the HKDF-Expand phase. + * + * This call terminates the HKDF-Extract process (input injection), and + * starts the HKDF-Expand process (output production). + * + * \param hc HKDF context. + */ +void br_hkdf_flip(br_hkdf_context *hc); + +/** + * \brief HKDF output production (HKDF-Expand). + * + * Produce more output bytes from the current state. This function may be + * called several times, but only after `br_hkdf_flip()`. + * + * Returned value is the number of actually produced bytes. The total + * output length is limited to 255 times the output length of the + * underlying hash function. + * + * \param hc HKDF context. + * \param info application specific information string. + * \param info_len application specific information string length (in bytes). + * \param out destination buffer for the HKDF output. + * \param out_len the length of the requested output (in bytes). + * \return the produced output length (in bytes). + */ +size_t br_hkdf_produce(br_hkdf_context *hc, + const void *info, size_t info_len, void *out, size_t out_len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_pem.h b/bearssl_pem.h new file mode 100644 index 0000000..8dba582 --- /dev/null +++ b/bearssl_pem.h @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_PEM_H__ +#define BR_BEARSSL_PEM_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_pem.h + * + * # PEM Support + * + * PEM is a traditional encoding layer use to store binary objects (in + * particular X.509 certificates, and private keys) in text files. While + * the acronym comes from an old, defunct standard ("Privacy Enhanced + * Mail"), the format has been reused, with some variations, by many + * systems, and is a _de facto_ standard, even though it is not, actually, + * specified in all clarity anywhere. + * + * ## Format Details + * + * BearSSL contains a generic, streamed PEM decoder, which handles the + * following format: + * + * - The input source (a sequence of bytes) is assumed to be the + * encoding of a text file in an ASCII-compatible charset. This + * includes ISO-8859-1, Windows-1252, and UTF-8 encodings. Each + * line ends on a newline character (U+000A LINE FEED). The + * U+000D CARRIAGE RETURN characters are ignored, so the code + * accepts both Windows-style and Unix-style line endings. + * + * - Each object begins with a banner that occurs at the start of + * a line; the first banner characters are "`-----BEGIN `" (five + * dashes, the word "BEGIN", and a space). The banner matching is + * not case-sensitive. + * + * - The _object name_ consists in the characters that follow the + * banner start sequence, up to the end of the line, but without + * trailing dashes (in "normal" PEM, there are five trailing + * dashes, but this implementation is not picky about these dashes). + * The BearSSL decoder normalises the name characters to uppercase + * (for ASCII letters only) and accepts names up to 127 characters. + * + * - The object ends with a banner that again occurs at the start of + * a line, and starts with "`-----END `" (again case-insensitive). + * + * - Between that start and end banner, only Base64 data shall occur. + * Base64 converts each sequence of three bytes into four + * characters; the four characters are ASCII letters, digits, "`+`" + * or "`-`" signs, and one or two "`=`" signs may occur in the last + * quartet. Whitespace is ignored (whitespace is any ASCII character + * of code 32 or less, so control characters are whitespace) and + * lines may have arbitrary length; the only restriction is that the + * four characters of a quartet must appear on the same line (no + * line break inside a quartet). + * + * - A single file may contain more than one PEM object. Bytes that + * occur between objects are ignored. + * + * + * ## PEM Decoder API + * + * The PEM decoder offers a state-machine API. The caller allocates a + * decoder context, then injects source bytes. Source bytes are pushed + * with `br_pem_decoder_push()`. The decoder stops accepting bytes when + * it reaches an "event", which is either the start of an object, the + * end of an object, or a decoding error within an object. + * + * The `br_pem_decoder_event()` function is used to obtain the current + * event; it also clears it, thus allowing the decoder to accept more + * bytes. When a object start event is raised, the decoder context + * offers the found object name (normalised to ASCII uppercase). + * + * When an object is reached, the caller must set an appropriate callback + * function, which will receive (by chunks) the decoded object data. + * + * Since the decoder context makes no dynamic allocation, it requires + * no explicit deallocation. + */ + +/** + * \brief PEM decoder context. + * + * Contents are opaque (they should not be accessed directly). + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + const unsigned char *hbuf; + size_t hlen; + + void (*dest)(void *dest_ctx, const void *src, size_t len); + void *dest_ctx; + + unsigned char event; + char name[128]; + unsigned char buf[255]; + size_t ptr; +#endif +} br_pem_decoder_context; + +/** + * \brief Initialise a PEM decoder structure. + * + * \param ctx decoder context to initialise. + */ +void br_pem_decoder_init(br_pem_decoder_context *ctx); + +/** + * \brief Push some bytes into the decoder. + * + * Returned value is the number of bytes actually consumed; this may be + * less than the number of provided bytes if an event is raised. When an + * event is raised, it must be read (with `br_pem_decoder_event()`); + * until the event is read, this function will return 0. + * + * \param ctx decoder context. + * \param data new data bytes. + * \param len number of new data bytes. + * \return the number of bytes actually received (may be less than `len`). + */ +size_t br_pem_decoder_push(br_pem_decoder_context *ctx, + const void *data, size_t len); + +/** + * \brief Set the receiver for decoded data. + * + * When an object is entered, the provided function (with opaque context + * pointer) will be called repeatedly with successive chunks of decoded + * data for that object. If `dest` is set to 0, then decoded data is + * simply ignored. The receiver can be set at any time, but, in practice, + * it should be called immediately after receiving a "start of object" + * event. + * + * \param ctx decoder context. + * \param dest callback for receiving decoded data. + * \param dest_ctx opaque context pointer for the `dest` callback. + */ +static inline void +br_pem_decoder_setdest(br_pem_decoder_context *ctx, + void (*dest)(void *dest_ctx, const void *src, size_t len), + void *dest_ctx) +{ + ctx->dest = dest; + ctx->dest_ctx = dest_ctx; +} + +/** + * \brief Get the last event. + * + * If an event was raised, then this function returns the event value, and + * also clears it, thereby allowing the decoder to proceed. If no event + * was raised since the last call to `br_pem_decoder_event()`, then this + * function returns 0. + * + * \param ctx decoder context. + * \return the raised event, or 0. + */ +int br_pem_decoder_event(br_pem_decoder_context *ctx); + +/** + * \brief Event: start of object. + * + * This event is raised when the start of a new object has been detected. + * The object name (normalised to uppercase) can be accessed with + * `br_pem_decoder_name()`. + */ +#define BR_PEM_BEGIN_OBJ 1 + +/** + * \brief Event: end of object. + * + * This event is raised when the end of the current object is reached + * (normally, i.e. with no decoding error). + */ +#define BR_PEM_END_OBJ 2 + +/** + * \brief Event: decoding error. + * + * This event is raised when decoding fails within an object. + * This formally closes the current object and brings the decoder back + * to the "out of any object" state. The offending line in the source + * is consumed. + */ +#define BR_PEM_ERROR 3 + +/** + * \brief Get the name of the encountered object. + * + * The encountered object name is defined only when the "start of object" + * event is raised. That name is normalised to uppercase (for ASCII letters + * only) and does not include trailing dashes. + * + * \param ctx decoder context. + * \return the current object name. + */ +static inline const char * +br_pem_decoder_name(br_pem_decoder_context *ctx) +{ + return ctx->name; +} + +/** + * \brief Encode an object in PEM. + * + * This function encodes the provided binary object (`data`, of length `len` + * bytes) into PEM. The `banner` text will be included in the header and + * footer (e.g. use `"CERTIFICATE"` to get a `"BEGIN CERTIFICATE"` header). + * + * The length (in characters) of the PEM output is returned; that length + * does NOT include the terminating zero, that this function nevertheless + * adds. If using the returned value for allocation purposes, the allocated + * buffer size MUST be at least one byte larger than the returned size. + * + * If `dest` is `NULL`, then the encoding does not happen; however, the + * length of the encoded object is still computed and returned. + * + * The `data` pointer may be `NULL` only if `len` is zero (when encoding + * an object of length zero, which is not very useful), or when `dest` + * is `NULL` (in that case, source data bytes are ignored). + * + * Some `flags` can be specified to alter the encoding behaviour: + * + * - If `BR_PEM_LINE64` is set, then line-breaking will occur after + * every 64 characters of output, instead of the default of 76. + * + * - If `BR_PEM_CRLF` is set, then end-of-line sequence will use + * CR+LF instead of a single LF. + * + * The `data` and `dest` buffers may overlap, in which case the source + * binary data is destroyed in the process. Note that the PEM-encoded output + * is always larger than the source binary. + * + * \param dest the destination buffer (or `NULL`). + * \param data the source buffer (can be `NULL` in some cases). + * \param len the source length (in bytes). + * \param banner the PEM banner expression. + * \param flags the behavioural flags. + * \return the PEM object length (in characters), EXCLUDING the final zero. + */ +size_t br_pem_encode(void *dest, const void *data, size_t len, + const char *banner, unsigned flags); + +/** + * \brief PEM encoding flag: split lines at 64 characters. + */ +#define BR_PEM_LINE64 0x0001 + +/** + * \brief PEM encoding flag: use CR+LF line endings. + */ +#define BR_PEM_CRLF 0x0002 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_prf.h b/bearssl_prf.h new file mode 100644 index 0000000..fdf608c --- /dev/null +++ b/bearssl_prf.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_PRF_H__ +#define BR_BEARSSL_PRF_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_prf.h + * + * # The TLS PRF + * + * The "PRF" is the pseudorandom function used internally during the + * SSL/TLS handshake, notably to expand negotiated shared secrets into + * the symmetric encryption keys that will be used to process the + * application data. + * + * TLS 1.0 and 1.1 define a PRF that is based on both MD5 and SHA-1. This + * is implemented by the `br_tls10_prf()` function. + * + * TLS 1.2 redefines the PRF, using an explicit hash function. The + * `br_tls12_sha256_prf()` and `br_tls12_sha384_prf()` functions apply that + * PRF with, respectively, SHA-256 and SHA-384. Most standard cipher suites + * rely on the SHA-256 based PRF, but some use SHA-384. + * + * The PRF always uses as input three parameters: a "secret" (some + * bytes), a "label" (ASCII string), and a "seed" (again some bytes). An + * arbitrary output length can be produced. The "seed" is provided as an + * arbitrary number of binary chunks, that gets internally concatenated. + */ + +/** + * \brief Type for a seed chunk. + * + * Each chunk may have an arbitrary length, and may be empty (no byte at + * all). If the chunk length is zero, then the pointer to the chunk data + * may be `NULL`. + */ +typedef struct { + /** + * \brief Pointer to the chunk data. + */ + const void *data; + + /** + * \brief Chunk length (in bytes). + */ + size_t len; +} br_tls_prf_seed_chunk; + +/** + * \brief PRF implementation for TLS 1.0 and 1.1. + * + * This PRF is the one specified by TLS 1.0 and 1.1. It internally uses + * MD5 and SHA-1. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +void br_tls10_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/** + * \brief PRF implementation for TLS 1.2, with SHA-256. + * + * This PRF is the one specified by TLS 1.2, when the underlying hash + * function is SHA-256. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +void br_tls12_sha256_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/** + * \brief PRF implementation for TLS 1.2, with SHA-384. + * + * This PRF is the one specified by TLS 1.2, when the underlying hash + * function is SHA-384. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +void br_tls12_sha384_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/** + * brief A convenient type name for a PRF implementation. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +typedef void (*br_tls_prf_impl)(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_rand.h b/bearssl_rand.h new file mode 100644 index 0000000..0a9f544 --- /dev/null +++ b/bearssl_rand.h @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_RAND_H__ +#define BR_BEARSSL_RAND_H__ + +#include +#include + +#include "bearssl_block.h" +#include "bearssl_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_rand.h + * + * # Pseudo-Random Generators + * + * A PRNG is a state-based engine that outputs pseudo-random bytes on + * demand. It is initialized with an initial seed, and additional seed + * bytes can be added afterwards. Bytes produced depend on the seeds and + * also on the exact sequence of calls (including sizes requested for + * each call). + * + * + * ## Procedural and OOP API + * + * For the PRNG of name "`xxx`", two API are provided. The _procedural_ + * API defined a context structure `br_xxx_context` and three functions: + * + * - `br_xxx_init()` + * + * Initialise the context with an initial seed. + * + * - `br_xxx_generate()` + * + * Produce some pseudo-random bytes. + * + * - `br_xxx_update()` + * + * Inject some additional seed. + * + * The initialisation function sets the first context field (`vtable`) + * to a pointer to the vtable that supports the OOP API. The OOP API + * provides access to the same functions through function pointers, + * named `init()`, `generate()` and `update()`. + * + * Note that the context initialisation method may accept additional + * parameters, provided as a 'const void *' pointer at API level. These + * additional parameters depend on the implemented PRNG. + * + * + * ## HMAC_DRBG + * + * HMAC_DRBG is defined in [NIST SP 800-90A Revision + * 1](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf). + * It uses HMAC repeatedly, over some configurable underlying hash + * function. In BearSSL, it is implemented under the "`hmac_drbg`" name. + * The "extra parameters" pointer for context initialisation should be + * set to a pointer to the vtable for the underlying hash function (e.g. + * pointer to `br_sha256_vtable` to use HMAC_DRBG with SHA-256). + * + * According to the NIST standard, each request shall produce up to + * 219 bits (i.e. 64 kB of data); moreover, the context shall + * be reseeded at least once every 248 requests. This + * implementation does not maintain the reseed counter (the threshold is + * too high to be reached in practice) and does not object to producing + * more than 64 kB in a single request; thus, the code cannot fail, + * which corresponds to the fact that the API has no room for error + * codes. However, this implies that requesting more than 64 kB in one + * `generate()` request, or making more than 248 requests + * without reseeding, is formally out of NIST specification. There is + * no currently known security penalty for exceeding the NIST limits, + * and, in any case, HMAC_DRBG usage in implementing SSL/TLS always + * stays much below these thresholds. + * + * + * ## AESCTR_DRBG + * + * AESCTR_DRBG is a custom PRNG based on AES-128 in CTR mode. This is + * meant to be used only in situations where you are desperate for + * speed, and have an hardware-optimized AES/CTR implementation. Whether + * this will yield perceptible improvements depends on what you use the + * pseudorandom bytes for, and how many you want; for instance, RSA key + * pair generation uses a substantial amount of randomness, and using + * AESCTR_DRBG instead of HMAC_DRBG yields a 15 to 20% increase in key + * generation speed on a recent x86 CPU (Intel Core i7-6567U at 3.30 GHz). + * + * Internally, it uses CTR mode with successive counter values, starting + * at zero (counter value expressed over 128 bits, big-endian convention). + * The counter is not allowed to reach 32768; thus, every 32768*16 bytes + * at most, the `update()` function is run (on an empty seed, if none is + * provided). The `update()` function computes the new AES-128 key by + * applying a custom hash function to the concatenation of a state-dependent + * word (encryption of an all-one block with the current key) and the new + * seed. The custom hash function uses Hirose's construction over AES-256; + * see the comments in `aesctr_drbg.c` for details. + * + * This DRBG does not follow an existing standard, and thus should be + * considered as inadequate for production use until it has been properly + * analysed. + */ + +/** + * \brief Class type for PRNG implementations. + * + * A `br_prng_class` instance references the methods implementing a PRNG. + * Constant instances of this structure are defined for each implemented + * PRNG. Such instances are also called "vtables". + */ +typedef struct br_prng_class_ br_prng_class; +struct br_prng_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate for + * running this PRNG. + */ + size_t context_size; + + /** + * \brief Initialisation method. + * + * The context to initialise is provided as a pointer to its + * first field (the vtable pointer); this function sets that + * first field to a pointer to the vtable. + * + * The extra parameters depend on the implementation; each + * implementation defines what kind of extra parameters it + * expects (if any). + * + * Requirements on the initial seed depend on the implemented + * PRNG. + * + * \param ctx PRNG context to initialise. + * \param params extra parameters for the PRNG. + * \param seed initial seed. + * \param seed_len initial seed length (in bytes). + */ + void (*init)(const br_prng_class **ctx, const void *params, + const void *seed, size_t seed_len); + + /** + * \brief Random bytes generation. + * + * This method produces `len` pseudorandom bytes, in the `out` + * buffer. The context is updated accordingly. + * + * \param ctx PRNG context. + * \param out output buffer. + * \param len number of pseudorandom bytes to produce. + */ + void (*generate)(const br_prng_class **ctx, void *out, size_t len); + + /** + * \brief Inject additional seed bytes. + * + * The provided seed bytes are added into the PRNG internal + * entropy pool. + * + * \param ctx PRNG context. + * \param seed additional seed. + * \param seed_len additional seed length (in bytes). + */ + void (*update)(const br_prng_class **ctx, + const void *seed, size_t seed_len); +}; + +/** + * \brief Context for HMAC_DRBG. + * + * The context contents are opaque, except the first field, which + * supports OOP. + */ +typedef struct { + /** + * \brief Pointer to the vtable. + * + * This field is set with the initialisation method/function. + */ + const br_prng_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char K[64]; + unsigned char V[64]; + const br_hash_class *digest_class; +#endif +} br_hmac_drbg_context; + +/** + * \brief Statically allocated, constant vtable for HMAC_DRBG. + */ +extern const br_prng_class br_hmac_drbg_vtable; + +/** + * \brief HMAC_DRBG initialisation. + * + * The context to initialise is provided as a pointer to its first field + * (the vtable pointer); this function sets that first field to a + * pointer to the vtable. + * + * The `seed` value is what is called, in NIST terminology, the + * concatenation of the "seed", "nonce" and "personalization string", in + * that order. + * + * The `digest_class` parameter defines the underlying hash function. + * Formally, the NIST standard specifies that the hash function shall + * be only SHA-1 or one of the SHA-2 functions. This implementation also + * works with any other implemented hash function (such as MD5), but + * this is non-standard and therefore not recommended. + * + * \param ctx HMAC_DRBG context to initialise. + * \param digest_class vtable for the underlying hash function. + * \param seed initial seed. + * \param seed_len initial seed length (in bytes). + */ +void br_hmac_drbg_init(br_hmac_drbg_context *ctx, + const br_hash_class *digest_class, const void *seed, size_t seed_len); + +/** + * \brief Random bytes generation with HMAC_DRBG. + * + * This method produces `len` pseudorandom bytes, in the `out` + * buffer. The context is updated accordingly. Formally, requesting + * more than 65536 bytes in one request falls out of specification + * limits (but it won't fail). + * + * \param ctx HMAC_DRBG context. + * \param out output buffer. + * \param len number of pseudorandom bytes to produce. + */ +void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len); + +/** + * \brief Inject additional seed bytes in HMAC_DRBG. + * + * The provided seed bytes are added into the HMAC_DRBG internal + * entropy pool. The process does not _replace_ existing entropy, + * thus pushing non-random bytes (i.e. bytes which are known to the + * attackers) does not degrade the overall quality of generated bytes. + * + * \param ctx HMAC_DRBG context. + * \param seed additional seed. + * \param seed_len additional seed length (in bytes). + */ +void br_hmac_drbg_update(br_hmac_drbg_context *ctx, + const void *seed, size_t seed_len); + +/** + * \brief Get the hash function implementation used by a given instance of + * HMAC_DRBG. + * + * This calls MUST NOT be performed on a context which was not + * previously initialised. + * + * \param ctx HMAC_DRBG context. + * \return the hash function vtable. + */ +static inline const br_hash_class * +br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx) +{ + return ctx->digest_class; +} + +/** + * \brief Type for a provider of entropy seeds. + * + * A "seeder" is a function that is able to obtain random values from + * some source and inject them as entropy seed in a PRNG. A seeder + * shall guarantee that the total entropy of the injected seed is large + * enough to seed a PRNG for purposes of cryptographic key generation + * (i.e. at least 128 bits). + * + * A seeder may report a failure to obtain adequate entropy. Seeders + * shall endeavour to fix themselves transient errors by trying again; + * thus, callers may consider reported errors as permanent. + * + * \param ctx PRNG context to seed. + * \return 1 on success, 0 on error. + */ +typedef int (*br_prng_seeder)(const br_prng_class **ctx); + +/** + * \brief Get a seeder backed by the operating system or hardware. + * + * Get a seeder that feeds on RNG facilities provided by the current + * operating system or hardware. If no such facility is known, then 0 + * is returned. + * + * If `name` is not `NULL`, then `*name` is set to a symbolic string + * that identifies the seeder implementation. If no seeder is returned + * and `name` is not `NULL`, then `*name` is set to a pointer to the + * constant string `"none"`. + * + * \param name receiver for seeder name, or `NULL`. + * \return the system seeder, if available, or 0. + */ +br_prng_seeder br_prng_seeder_system(const char **name); + +/** + * \brief Context for AESCTR_DRBG. + * + * The context contents are opaque, except the first field, which + * supports OOP. + */ +typedef struct { + /** + * \brief Pointer to the vtable. + * + * This field is set with the initialisation method/function. + */ + const br_prng_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + br_aes_gen_ctr_keys sk; + uint32_t cc; +#endif +} br_aesctr_drbg_context; + +/** + * \brief Statically allocated, constant vtable for AESCTR_DRBG. + */ +extern const br_prng_class br_aesctr_drbg_vtable; + +/** + * \brief AESCTR_DRBG initialisation. + * + * The context to initialise is provided as a pointer to its first field + * (the vtable pointer); this function sets that first field to a + * pointer to the vtable. + * + * The internal AES key is first set to the all-zero key; then, the + * `br_aesctr_drbg_update()` function is called with the provided `seed`. + * The call is performed even if the seed length (`seed_len`) is zero. + * + * The `aesctr` parameter defines the underlying AES/CTR implementation. + * + * \param ctx AESCTR_DRBG context to initialise. + * \param aesctr vtable for the AES/CTR implementation. + * \param seed initial seed (can be `NULL` if `seed_len` is zero). + * \param seed_len initial seed length (in bytes). + */ +void br_aesctr_drbg_init(br_aesctr_drbg_context *ctx, + const br_block_ctr_class *aesctr, const void *seed, size_t seed_len); + +/** + * \brief Random bytes generation with AESCTR_DRBG. + * + * This method produces `len` pseudorandom bytes, in the `out` + * buffer. The context is updated accordingly. + * + * \param ctx AESCTR_DRBG context. + * \param out output buffer. + * \param len number of pseudorandom bytes to produce. + */ +void br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, + void *out, size_t len); + +/** + * \brief Inject additional seed bytes in AESCTR_DRBG. + * + * The provided seed bytes are added into the AESCTR_DRBG internal + * entropy pool. The process does not _replace_ existing entropy, + * thus pushing non-random bytes (i.e. bytes which are known to the + * attackers) does not degrade the overall quality of generated bytes. + * + * \param ctx AESCTR_DRBG context. + * \param seed additional seed. + * \param seed_len additional seed length (in bytes). + */ +void br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, + const void *seed, size_t seed_len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_rsa.h b/bearssl_rsa.h new file mode 100644 index 0000000..0eaf2a2 --- /dev/null +++ b/bearssl_rsa.h @@ -0,0 +1,1366 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_RSA_H__ +#define BR_BEARSSL_RSA_H__ + +#include +#include + +#include "bearssl_rand.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_rsa.h + * + * # RSA + * + * This file documents the RSA implementations provided with BearSSL. + * Note that the SSL engine accesses these implementations through a + * configurable API, so it is possible to, for instance, run a SSL + * server which uses a RSA engine which is not based on this code. + * + * ## Key Elements + * + * RSA public and private keys consist in lists of big integers. All + * such integers are represented with big-endian unsigned notation: + * first byte is the most significant, and the value is positive (so + * there is no dedicated "sign bit"). Public and private key structures + * thus contain, for each such integer, a pointer to the first value byte + * (`unsigned char *`), and a length (`size_t`) which is the number of + * relevant bytes. As a general rule, minimal-length encoding is not + * enforced: values may have extra leading bytes of value 0. + * + * RSA public keys consist in two integers: + * + * - the modulus (`n`); + * - the public exponent (`e`). + * + * RSA private keys, as defined in + * [PKCS#1](https://tools.ietf.org/html/rfc3447), contain eight integers: + * + * - the modulus (`n`); + * - the public exponent (`e`); + * - the private exponent (`d`); + * - the first prime factor (`p`); + * - the second prime factor (`q`); + * - the first reduced exponent (`dp`, which is `d` modulo `p-1`); + * - the second reduced exponent (`dq`, which is `d` modulo `q-1`); + * - the CRT coefficient (`iq`, the inverse of `q` modulo `p`). + * + * However, the implementations defined in BearSSL use only five of + * these integers: `p`, `q`, `dp`, `dq` and `iq`. + * + * ## Security Features and Limitations + * + * The implementations contained in BearSSL have the following limitations + * and features: + * + * - They are constant-time. This means that the execution time and + * memory access pattern may depend on the _lengths_ of the private + * key components, but not on their value, nor on the value of + * the operand. Note that this property is not achieved through + * random masking, but "true" constant-time code. + * + * - They support only private keys with two prime factors. RSA private + * keys with three or more prime factors are nominally supported, but + * rarely used; they may offer faster operations, at the expense of + * more code and potentially a reduction in security if there are + * "too many" prime factors. + * + * - The public exponent may have arbitrary length. Of course, it is + * a good idea to keep public exponents small, so that public key + * operations are fast; but, contrary to some widely deployed + * implementations, BearSSL has no problem with public exponents + * longer than 32 bits. + * + * - The two prime factors of the modulus need not have the same length + * (but severely imbalanced factor lengths might reduce security). + * Similarly, there is no requirement that the first factor (`p`) + * be greater than the second factor (`q`). + * + * - Prime factors and modulus must be smaller than a compile-time limit. + * This is made necessary by the use of fixed-size stack buffers, and + * the limit has been adjusted to keep stack usage under 2 kB for the + * RSA operations. Currently, the maximum modulus size is 4096 bits, + * and the maximum prime factor size is 2080 bits. + * + * - The RSA functions themselves do not enforce lower size limits, + * except that which is absolutely necessary for the operation to + * mathematically make sense (e.g. a PKCS#1 v1.5 signature with + * SHA-1 requires a modulus of at least 361 bits). It is up to users + * of this code to enforce size limitations when appropriate (e.g. + * the X.509 validation engine, by default, rejects RSA keys of + * less than 1017 bits). + * + * - Within the size constraints expressed above, arbitrary bit lengths + * are supported. There is no requirement that prime factors or + * modulus have a size multiple of 8 or 16. + * + * - When verifying PKCS#1 v1.5 signatures, both variants of the hash + * function identifying header (with and without the ASN.1 NULL) are + * supported. When producing such signatures, the variant with the + * ASN.1 NULL is used. + * + * ## Implementations + * + * Three RSA implementations are included: + * + * - The **i32** implementation internally represents big integers + * as arrays of 32-bit integers. It is perfunctory and portable, + * but not very efficient. + * + * - The **i31** implementation uses 32-bit integers, each containing + * 31 bits worth of integer data. The i31 implementation is somewhat + * faster than the i32 implementation (the reduced integer size makes + * carry propagation easier) for a similar code footprint, but uses + * very slightly larger stack buffers (about 4% bigger). + * + * - The **i62** implementation is similar to the i31 implementation, + * except that it internally leverages the 64x64->128 multiplication + * opcode. This implementation is available only on architectures + * where such an opcode exists. It is much faster than i31. + * + * - The **i15** implementation uses 16-bit integers, each containing + * 15 bits worth of integer data. Multiplication results fit on + * 32 bits, so this won't use the "widening" multiplication routine + * on ARM Cortex M0/M0+, for much better performance and constant-time + * execution. + */ + +/** + * \brief RSA public key. + * + * The structure references the modulus and the public exponent. Both + * integers use unsigned big-endian representation; extra leading bytes + * of value 0 are allowed. + */ +typedef struct { + /** \brief Modulus. */ + unsigned char *n; + /** \brief Modulus length (in bytes). */ + size_t nlen; + /** \brief Public exponent. */ + unsigned char *e; + /** \brief Public exponent length (in bytes). */ + size_t elen; +} br_rsa_public_key; + +/** + * \brief RSA private key. + * + * The structure references the private factors, reduced private + * exponents, and CRT coefficient. It also contains the bit length of + * the modulus. The big integers use unsigned big-endian representation; + * extra leading bytes of value 0 are allowed. However, the modulus bit + * length (`n_bitlen`) MUST be exact. + */ +typedef struct { + /** \brief Modulus bit length (in bits, exact value). */ + uint32_t n_bitlen; + /** \brief First prime factor. */ + unsigned char *p; + /** \brief First prime factor length (in bytes). */ + size_t plen; + /** \brief Second prime factor. */ + unsigned char *q; + /** \brief Second prime factor length (in bytes). */ + size_t qlen; + /** \brief First reduced private exponent. */ + unsigned char *dp; + /** \brief First reduced private exponent length (in bytes). */ + size_t dplen; + /** \brief Second reduced private exponent. */ + unsigned char *dq; + /** \brief Second reduced private exponent length (in bytes). */ + size_t dqlen; + /** \brief CRT coefficient. */ + unsigned char *iq; + /** \brief CRT coefficient length (in bytes). */ + size_t iqlen; +} br_rsa_private_key; + +/** + * \brief Type for a RSA public key engine. + * + * The public key engine performs the modular exponentiation of the + * provided value with the public exponent. The value is modified in + * place. + * + * The value length (`xlen`) is verified to have _exactly_ the same + * length as the modulus (actual modulus length, without extra leading + * zeros in the modulus representation in memory). If the length does + * not match, then this function returns 0 and `x[]` is unmodified. + * + * It `xlen` is correct, then `x[]` is modified. Returned value is 1 + * on success, 0 on error. Error conditions include an oversized `x[]` + * (the array has the same length as the modulus, but the numerical value + * is not lower than the modulus) and an invalid modulus (e.g. an even + * integer). If an error is reported, then the new contents of `x[]` are + * unspecified. + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_public)(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief Type for a RSA signature verification engine (PKCS#1 v1.5). + * + * Parameters are: + * + * - The signature itself. The provided array is NOT modified. + * + * - The encoded OID for the hash function. The provided array must begin + * with a single byte that contains the length of the OID value (in + * bytes), followed by exactly that many bytes. This parameter may + * also be `NULL`, in which case the raw hash value should be used + * with the PKCS#1 v1.5 "type 1" padding (as used in SSL/TLS up + * to TLS-1.1, with a 36-byte hash value). + * + * - The hash output length, in bytes. + * + * - The public key. + * + * - An output buffer for the hash value. The caller must still compare + * it with the hash of the data over which the signature is computed. + * + * **Constraints:** + * + * - Hash length MUST be no more than 64 bytes. + * + * - OID value length MUST be no more than 32 bytes (i.e. `hash_oid[0]` + * must have a value in the 0..32 range, inclusive). + * + * This function verifies that the signature length (`xlen`) matches the + * modulus length (this function returns 0 on mismatch). If the modulus + * size exceeds the maximum supported RSA size, then the function also + * returns 0. + * + * Returned value is 1 on success, 0 on error. + * + * Implementations of this type need not be constant-time. + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pkcs1_vrfy)(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief Type for a RSA encryption engine (OAEP). + * + * Parameters are: + * + * - A source of random bytes. The source must be already initialized. + * + * - A hash function, used internally with the mask generation function + * (MGF1). + * + * - A label. The `label` pointer may be `NULL` if `label_len` is zero + * (an empty label, which is the default in PKCS#1 v2.2). + * + * - The public key. + * + * - The destination buffer. Its maximum length (in bytes) is provided; + * if that length is lower than the public key length, then an error + * is reported. + * + * - The source message. + * + * The encrypted message output has exactly the same length as the modulus + * (mathematical length, in bytes, not counting extra leading zeros in the + * modulus representation in the public key). + * + * The source message (`src`, length `src_len`) may overlap with the + * destination buffer (`dst`, length `dst_max_len`). + * + * This function returns the actual encrypted message length, in bytes; + * on error, zero is returned. An error is reported if the output buffer + * is not large enough, or the public is invalid, or the public key + * modulus exceeds the maximum supported RSA size. + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +typedef size_t (*br_rsa_oaep_encrypt)( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief Type for a RSA private key engine. + * + * The `x[]` buffer is modified in place, and its length is inferred from + * the modulus length (`x[]` is assumed to have a length of + * `(sk->n_bitlen+7)/8` bytes). + * + * Returned value is 1 on success, 0 on error. + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_private)(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief Type for a RSA signature generation engine (PKCS#1 v1.5). + * + * Parameters are: + * + * - The encoded OID for the hash function. The provided array must begin + * with a single byte that contains the length of the OID value (in + * bytes), followed by exactly that many bytes. This parameter may + * also be `NULL`, in which case the raw hash value should be used + * with the PKCS#1 v1.5 "type 1" padding (as used in SSL/TLS up + * to TLS-1.1, with a 36-byte hash value). + * + * - The hash value computes over the data to sign (its length is + * expressed in bytes). + * + * - The RSA private key. + * + * - The output buffer, that receives the signature. + * + * Returned value is 1 on success, 0 on error. Error conditions include + * a too small modulus for the provided hash OID and value, or some + * invalid key parameters. The signature length is exactly + * `(sk->n_bitlen+7)/8` bytes. + * + * This function is expected to be constant-time with regards to the + * private key bytes (lengths of the modulus and the individual factors + * may leak, though) and to the hashed data. + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pkcs1_sign)(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief Encoded OID for SHA-1 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA1 \ + ((const unsigned char *)"\x05\x2B\x0E\x03\x02\x1A") + +/** + * \brief Encoded OID for SHA-224 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA224 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04") + +/** + * \brief Encoded OID for SHA-256 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA256 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01") + +/** + * \brief Encoded OID for SHA-384 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA384 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02") + +/** + * \brief Encoded OID for SHA-512 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA512 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03") + +/** + * \brief Type for a RSA decryption engine (OAEP). + * + * Parameters are: + * + * - A hash function, used internally with the mask generation function + * (MGF1). + * + * - A label. The `label` pointer may be `NULL` if `label_len` is zero + * (an empty label, which is the default in PKCS#1 v2.2). + * + * - The private key. + * + * - The source and destination buffer. The buffer initially contains + * the encrypted message; the buffer contents are altered, and the + * decrypted message is written at the start of that buffer + * (decrypted message is always shorter than the encrypted message). + * + * If decryption fails in any way, then `*len` is unmodified, and the + * function returns 0. Otherwise, `*len` is set to the decrypted message + * length, and 1 is returned. The implementation is responsible for + * checking that the input message length matches the key modulus length, + * and that the padding is correct. + * + * Implementations MUST use constant-time check of the validity of the + * OAEP padding, at least until the leading byte and hash value have + * been checked. Whether overall decryption worked, and the length of + * the decrypted message, may leak. + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_oaep_decrypt)( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/* + * RSA "i32" engine. Integers are internally represented as arrays of + * 32-bit integers, and the core multiplication primitive is the + * 32x32->64 multiplication. + */ + +/** + * \brief RSA public key engine "i32". + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i32". + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA private key engine "i32". + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i32". + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/* + * RSA "i31" engine. Similar to i32, but only 31 bits are used per 32-bit + * word. This uses slightly more stack space (about 4% more) and code + * space, but it quite faster. + */ + +/** + * \brief RSA public key engine "i31". + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i31". + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA private key engine "i31". + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i31". + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/* + * RSA "i62" engine. Similar to i31, but internal multiplication use + * 64x64->128 multiplications. This is available only on architecture + * that offer such an opcode. + */ + +/** + * \brief RSA public key engine "i62". + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_public_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i62". + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pkcs1_vrfy_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA private key engine "i62". + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_private_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i62". + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pkcs1_sign_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief Get the RSA "i62" implementation (public key operations), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_public br_rsa_i62_public_get(void); + +/** + * \brief Get the RSA "i62" implementation (PKCS#1 signature verification), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pkcs1_vrfy br_rsa_i62_pkcs1_vrfy_get(void); + +/** + * \brief Get the RSA "i62" implementation (private key operations), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_private br_rsa_i62_private_get(void); + +/** + * \brief Get the RSA "i62" implementation (PKCS#1 signature generation), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pkcs1_sign br_rsa_i62_pkcs1_sign_get(void); + +/** + * \brief Get the RSA "i62" implementation (OAEP encryption), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_oaep_encrypt br_rsa_i62_oaep_encrypt_get(void); + +/** + * \brief Get the RSA "i62" implementation (OAEP decryption), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_oaep_decrypt br_rsa_i62_oaep_decrypt_get(void); + +/* + * RSA "i15" engine. Integers are represented as 15-bit integers, so + * the code uses only 32-bit multiplication (no 64-bit result), which + * is vastly faster (and constant-time) on the ARM Cortex M0/M0+. + */ + +/** + * \brief RSA public key engine "i15". + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i15". + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA private key engine "i15". + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i15". + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief Get "default" RSA implementation (public-key operations). + * + * This returns the preferred implementation of RSA (public-key operations) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_public br_rsa_public_get_default(void); + +/** + * \brief Get "default" RSA implementation (private-key operations). + * + * This returns the preferred implementation of RSA (private-key operations) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_private br_rsa_private_get_default(void); + +/** + * \brief Get "default" RSA implementation (PKCS#1 signature verification). + * + * This returns the preferred implementation of RSA (signature verification) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pkcs1_vrfy br_rsa_pkcs1_vrfy_get_default(void); + +/** + * \brief Get "default" RSA implementation (PKCS#1 signature generation). + * + * This returns the preferred implementation of RSA (signature generation) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pkcs1_sign br_rsa_pkcs1_sign_get_default(void); + +/** + * \brief Get "default" RSA implementation (OAEP encryption). + * + * This returns the preferred implementation of RSA (OAEP encryption) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_oaep_encrypt br_rsa_oaep_encrypt_get_default(void); + +/** + * \brief Get "default" RSA implementation (OAEP decryption). + * + * This returns the preferred implementation of RSA (OAEP decryption) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_oaep_decrypt br_rsa_oaep_decrypt_get_default(void); + +/** + * \brief RSA decryption helper, for SSL/TLS. + * + * This function performs the RSA decryption for a RSA-based key exchange + * in a SSL/TLS server. The provided RSA engine is used. The `data` + * parameter points to the value to decrypt, of length `len` bytes. On + * success, the 48-byte pre-master secret is copied into `data`, starting + * at the first byte of that buffer; on error, the contents of `data` + * become indeterminate. + * + * This function first checks that the provided value length (`len`) is + * not lower than 59 bytes, and matches the RSA modulus length; if neither + * of this property is met, then this function returns 0 and the buffer + * is unmodified. + * + * Otherwise, decryption and then padding verification are performed, both + * in constant-time. A decryption error, or a bad padding, or an + * incorrect decrypted value length are reported with a returned value of + * 0; on success, 1 is returned. The caller (SSL server engine) is supposed + * to proceed with a random pre-master secret in case of error. + * + * \param core RSA private key engine. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len length (in bytes) of the data to decrypt. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_ssl_decrypt(br_rsa_private core, const br_rsa_private_key *sk, + unsigned char *data, size_t len); + +/** + * \brief RSA encryption (OAEP) with the "i15" engine. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i15_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i15" engine. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief RSA encryption (OAEP) with the "i31" engine. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i31_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i31" engine. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief RSA encryption (OAEP) with the "i32" engine. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i32_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i32" engine. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief RSA encryption (OAEP) with the "i62" engine. + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_oaep_encrypt_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i62_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i62" engine. + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_oaep_decrypt_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief Get buffer size to hold RSA private key elements. + * + * This macro returns the length (in bytes) of the buffer needed to + * receive the elements of a RSA private key, as generated by one of + * the `br_rsa_*_keygen()` functions. If the provided size is a constant + * expression, then the whole macro evaluates to a constant expression. + * + * \param size target key size (modulus size, in bits) + * \return the length of the private key buffer, in bytes. + */ +#define BR_RSA_KBUF_PRIV_SIZE(size) (5 * (((size) + 15) >> 4)) + +/** + * \brief Get buffer size to hold RSA public key elements. + * + * This macro returns the length (in bytes) of the buffer needed to + * receive the elements of a RSA public key, as generated by one of + * the `br_rsa_*_keygen()` functions. If the provided size is a constant + * expression, then the whole macro evaluates to a constant expression. + * + * \param size target key size (modulus size, in bits) + * \return the length of the public key buffer, in bytes. + */ +#define BR_RSA_KBUF_PUB_SIZE(size) (4 + (((size) + 7) >> 3)) + +/** + * \brief Type for RSA key pair generator implementation. + * + * This function generates a new RSA key pair whose modulus has bit + * length `size` bits. The private key elements are written in the + * `kbuf_priv` buffer, and pointer values and length fields to these + * elements are populated in the provided private key structure `sk`. + * Similarly, the public key elements are written in `kbuf_pub`, with + * pointers and lengths set in `pk`. + * + * If `pk` is `NULL`, then `kbuf_pub` may be `NULL`, and only the + * private key is set. + * + * If `pubexp` is not zero, then its value will be used as public + * exponent. Valid RSA public exponent values are odd integers + * greater than 1. If `pubexp` is zero, then the public exponent will + * have value 3. + * + * The provided PRNG (`rng_ctx`) must have already been initialized + * and seeded. + * + * Returned value is 1 on success, 0 on error. An error is reported + * if the requested range is outside of the supported key sizes, or + * if an invalid non-zero public exponent value is provided. Supported + * range starts at 512 bits, and up to an implementation-defined + * maximum (by default 4096 bits). Note that key sizes up to 768 bits + * have been broken in practice, and sizes lower than 2048 bits are + * usually considered to be weak and should not be used. + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +typedef uint32_t (*br_rsa_keygen)( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief RSA key pair generation with the "i15" engine. + * + * \see br_rsa_keygen + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +uint32_t br_rsa_i15_keygen( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief RSA key pair generation with the "i31" engine. + * + * \see br_rsa_keygen + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +uint32_t br_rsa_i31_keygen( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief RSA key pair generation with the "i62" engine. + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_keygen_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_keygen + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +uint32_t br_rsa_i62_keygen( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief Get the RSA "i62" implementation (key pair generation), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_keygen br_rsa_i62_keygen_get(void); + +/** + * \brief Get "default" RSA implementation (key pair generation). + * + * This returns the preferred implementation of RSA (key pair generation) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_keygen br_rsa_keygen_get_default(void); + +/** + * \brief Type for a modulus computing function. + * + * Such a function computes the public modulus from the private key. The + * encoded modulus (unsigned big-endian) is written on `n`, and the size + * (in bytes) is returned. If `n` is `NULL`, then the size is returned but + * the modulus itself is not computed. + * + * If the key size exceeds an internal limit, 0 is returned. + * + * \param n destination buffer (or `NULL`). + * \param sk RSA private key. + * \return the modulus length (in bytes), or 0. + */ +typedef size_t (*br_rsa_compute_modulus)(void *n, const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA modulus ("i15" engine). + * + * \see br_rsa_compute_modulus + * + * \param n destination buffer (or `NULL`). + * \param sk RSA private key. + * \return the modulus length (in bytes), or 0. + */ +size_t br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA modulus ("i31" engine). + * + * \see br_rsa_compute_modulus + * + * \param n destination buffer (or `NULL`). + * \param sk RSA private key. + * \return the modulus length (in bytes), or 0. + */ +size_t br_rsa_i31_compute_modulus(void *n, const br_rsa_private_key *sk); + +/** + * \brief Get "default" RSA implementation (recompute modulus). + * + * This returns the preferred implementation of RSA (recompute modulus) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_compute_modulus br_rsa_compute_modulus_get_default(void); + +/** + * \brief Type for a public exponent computing function. + * + * Such a function recomputes the public exponent from the private key. + * 0 is returned if any of the following occurs: + * + * - Either `p` or `q` is not equal to 3 modulo 4. + * + * - The public exponent does not fit on 32 bits. + * + * - An internal limit is exceeded. + * + * - The private key is invalid in some way. + * + * For all private keys produced by the key generator functions + * (`br_rsa_keygen` type), this function succeeds and returns the true + * public exponent. The public exponent is always an odd integer greater + * than 1. + * + * \return the public exponent, or 0. + */ +typedef uint32_t (*br_rsa_compute_pubexp)(const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA public exponent ("i15" engine). + * + * \see br_rsa_compute_pubexp + * + * \return the public exponent, or 0. + */ +uint32_t br_rsa_i15_compute_pubexp(const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA public exponent ("i31" engine). + * + * \see br_rsa_compute_pubexp + * + * \return the public exponent, or 0. + */ +uint32_t br_rsa_i31_compute_pubexp(const br_rsa_private_key *sk); + +/** + * \brief Get "default" RSA implementation (recompute public exponent). + * + * This returns the preferred implementation of RSA (recompute public + * exponent) on the current system. + * + * \return the default implementation. + */ +br_rsa_compute_pubexp br_rsa_compute_pubexp_get_default(void); + +/** + * \brief Type for a private exponent computing function. + * + * An RSA private key (`br_rsa_private_key`) contains two reduced + * private exponents, which are sufficient to perform private key + * operations. However, standard encoding formats for RSA private keys + * require also a copy of the complete private exponent (non-reduced), + * which this function recomputes. + * + * This function suceeds if all the following conditions hold: + * + * - Both private factors `p` and `q` are equal to 3 modulo 4. + * + * - The provided public exponent `pubexp` is correct, and, in particular, + * is odd, relatively prime to `p-1` and `q-1`, and greater than 1. + * + * - No internal storage limit is exceeded. + * + * For all private keys produced by the key generator functions + * (`br_rsa_keygen` type), this function succeeds. Note that the API + * restricts the public exponent to a maximum size of 32 bits. + * + * The encoded private exponent is written in `d` (unsigned big-endian + * convention), and the length (in bytes) is returned. If `d` is `NULL`, + * then the exponent is not written anywhere, but the length is still + * returned. On error, 0 is returned. + * + * Not all error conditions are detected when `d` is `NULL`; therefore, the + * returned value shall be checked also when actually producing the value. + * + * \param d destination buffer (or `NULL`). + * \param sk RSA private key. + * \param pubexp the public exponent. + * \return the private exponent length (in bytes), or 0. + */ +typedef size_t (*br_rsa_compute_privexp)(void *d, + const br_rsa_private_key *sk, uint32_t pubexp); + +/** + * \brief Recompute RSA private exponent ("i15" engine). + * + * \see br_rsa_compute_privexp + * + * \param d destination buffer (or `NULL`). + * \param sk RSA private key. + * \param pubexp the public exponent. + * \return the private exponent length (in bytes), or 0. + */ +size_t br_rsa_i15_compute_privexp(void *d, + const br_rsa_private_key *sk, uint32_t pubexp); + +/** + * \brief Recompute RSA private exponent ("i31" engine). + * + * \see br_rsa_compute_privexp + * + * \param d destination buffer (or `NULL`). + * \param sk RSA private key. + * \param pubexp the public exponent. + * \return the private exponent length (in bytes), or 0. + */ +size_t br_rsa_i31_compute_privexp(void *d, + const br_rsa_private_key *sk, uint32_t pubexp); + +/** + * \brief Get "default" RSA implementation (recompute private exponent). + * + * This returns the preferred implementation of RSA (recompute private + * exponent) on the current system. + * + * \return the default implementation. + */ +br_rsa_compute_privexp br_rsa_compute_privexp_get_default(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_ssl.h b/bearssl_ssl.h new file mode 100644 index 0000000..8c8c86b --- /dev/null +++ b/bearssl_ssl.h @@ -0,0 +1,4296 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_SSL_H__ +#define BR_BEARSSL_SSL_H__ + +#include +#include + +#include "bearssl_block.h" +#include "bearssl_hash.h" +#include "bearssl_hmac.h" +#include "bearssl_prf.h" +#include "bearssl_rand.h" +#include "bearssl_x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_ssl.h + * + * # SSL + * + * For an overview of the SSL/TLS API, see [the BearSSL Web + * site](https://www.bearssl.org/api1.html). + * + * The `BR_TLS_*` constants correspond to the standard cipher suites and + * their values in the [IANA + * registry](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4). + * + * The `BR_ALERT_*` constants are for standard TLS alert messages. When + * a fatal alert message is sent of received, then the SSL engine context + * status is set to the sum of that alert value (an integer in the 0..255 + * range) and a fixed offset (`BR_ERR_SEND_FATAL_ALERT` for a sent alert, + * `BR_ERR_RECV_FATAL_ALERT` for a received alert). + */ + +/** \brief Optimal input buffer size. */ +#define BR_SSL_BUFSIZE_INPUT (16384 + 325) + +/** \brief Optimal output buffer size. */ +#define BR_SSL_BUFSIZE_OUTPUT (16384 + 85) + +/** \brief Optimal buffer size for monodirectional engine + (shared input/output buffer). */ +#define BR_SSL_BUFSIZE_MONO BR_SSL_BUFSIZE_INPUT + +/** \brief Optimal buffer size for bidirectional engine + (single buffer split into two separate input/output buffers). */ +#define BR_SSL_BUFSIZE_BIDI (BR_SSL_BUFSIZE_INPUT + BR_SSL_BUFSIZE_OUTPUT) + +/* + * Constants for known SSL/TLS protocol versions (SSL 3.0, TLS 1.0, TLS 1.1 + * and TLS 1.2). Note that though there is a constant for SSL 3.0, that + * protocol version is not actually supported. + */ + +/** \brief Protocol version: SSL 3.0 (unsupported). */ +#define BR_SSL30 0x0300 +/** \brief Protocol version: TLS 1.0. */ +#define BR_TLS10 0x0301 +/** \brief Protocol version: TLS 1.1. */ +#define BR_TLS11 0x0302 +/** \brief Protocol version: TLS 1.2. */ +#define BR_TLS12 0x0303 + +/* + * Error constants. They are used to report the reason why a context has + * been marked as failed. + * + * Implementation note: SSL-level error codes should be in the 1..31 + * range. The 32..63 range is for certificate decoding and validation + * errors. Received fatal alerts imply an error code in the 256..511 range. + */ + +/** \brief SSL status: no error so far (0). */ +#define BR_ERR_OK 0 + +/** \brief SSL status: caller-provided parameter is incorrect. */ +#define BR_ERR_BAD_PARAM 1 + +/** \brief SSL status: operation requested by the caller cannot be applied + with the current context state (e.g. reading data while outgoing data + is waiting to be sent). */ +#define BR_ERR_BAD_STATE 2 + +/** \brief SSL status: incoming protocol or record version is unsupported. */ +#define BR_ERR_UNSUPPORTED_VERSION 3 + +/** \brief SSL status: incoming record version does not match the expected + version. */ +#define BR_ERR_BAD_VERSION 4 + +/** \brief SSL status: incoming record length is invalid. */ +#define BR_ERR_BAD_LENGTH 5 + +/** \brief SSL status: incoming record is too large to be processed, or + buffer is too small for the handshake message to send. */ +#define BR_ERR_TOO_LARGE 6 + +/** \brief SSL status: decryption found an invalid padding, or the record + MAC is not correct. */ +#define BR_ERR_BAD_MAC 7 + +/** \brief SSL status: no initial entropy was provided, and none can be + obtained from the OS. */ +#define BR_ERR_NO_RANDOM 8 + +/** \brief SSL status: incoming record type is unknown. */ +#define BR_ERR_UNKNOWN_TYPE 9 + +/** \brief SSL status: incoming record or message has wrong type with + regards to the current engine state. */ +#define BR_ERR_UNEXPECTED 10 + +/** \brief SSL status: ChangeCipherSpec message from the peer has invalid + contents. */ +#define BR_ERR_BAD_CCS 12 + +/** \brief SSL status: alert message from the peer has invalid contents + (odd length). */ +#define BR_ERR_BAD_ALERT 13 + +/** \brief SSL status: incoming handshake message decoding failed. */ +#define BR_ERR_BAD_HANDSHAKE 14 + +/** \brief SSL status: ServerHello contains a session ID which is larger + than 32 bytes. */ +#define BR_ERR_OVERSIZED_ID 15 + +/** \brief SSL status: server wants to use a cipher suite that we did + not claim to support. This is also reported if we tried to advertise + a cipher suite that we do not support. */ +#define BR_ERR_BAD_CIPHER_SUITE 16 + +/** \brief SSL status: server wants to use a compression that we did not + claim to support. */ +#define BR_ERR_BAD_COMPRESSION 17 + +/** \brief SSL status: server's max fragment length does not match + client's. */ +#define BR_ERR_BAD_FRAGLEN 18 + +/** \brief SSL status: secure renegotiation failed. */ +#define BR_ERR_BAD_SECRENEG 19 + +/** \brief SSL status: server sent an extension type that we did not + announce, or used the same extension type several times in a single + ServerHello. */ +#define BR_ERR_EXTRA_EXTENSION 20 + +/** \brief SSL status: invalid Server Name Indication contents (when + used by the server, this extension shall be empty). */ +#define BR_ERR_BAD_SNI 21 + +/** \brief SSL status: invalid ServerHelloDone from the server (length + is not 0). */ +#define BR_ERR_BAD_HELLO_DONE 22 + +/** \brief SSL status: internal limit exceeded (e.g. server's public key + is too large). */ +#define BR_ERR_LIMIT_EXCEEDED 23 + +/** \brief SSL status: Finished message from peer does not match the + expected value. */ +#define BR_ERR_BAD_FINISHED 24 + +/** \brief SSL status: session resumption attempt with distinct version + or cipher suite. */ +#define BR_ERR_RESUME_MISMATCH 25 + +/** \brief SSL status: unsupported or invalid algorithm (ECDHE curve, + signature algorithm, hash function). */ +#define BR_ERR_INVALID_ALGORITHM 26 + +/** \brief SSL status: invalid signature (on ServerKeyExchange from + server, or in CertificateVerify from client). */ +#define BR_ERR_BAD_SIGNATURE 27 + +/** \brief SSL status: peer's public key does not have the proper type + or is not allowed for requested operation. */ +#define BR_ERR_WRONG_KEY_USAGE 28 + +/** \brief SSL status: client did not send a certificate upon request, + or the client certificate could not be validated. */ +#define BR_ERR_NO_CLIENT_AUTH 29 + +/** \brief SSL status: I/O error or premature close on underlying + transport stream. This error code is set only by the simplified + I/O API ("br_sslio_*"). */ +#define BR_ERR_IO 31 + +/** \brief SSL status: base value for a received fatal alert. + + When a fatal alert is received from the peer, the alert value + is added to this constant. */ +#define BR_ERR_RECV_FATAL_ALERT 256 + +/** \brief SSL status: base value for a sent fatal alert. + + When a fatal alert is sent to the peer, the alert value is added + to this constant. */ +#define BR_ERR_SEND_FATAL_ALERT 512 + +/* ===================================================================== */ + +/** + * \brief Decryption engine for SSL. + * + * When processing incoming records, the SSL engine will use a decryption + * engine that uses a specific context structure, and has a set of + * methods (a vtable) that follows this template. + * + * The decryption engine is responsible for applying decryption, verifying + * MAC, and keeping track of the record sequence number. + */ +typedef struct br_sslrec_in_class_ br_sslrec_in_class; +struct br_sslrec_in_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Test validity of the incoming record length. + * + * This function returns 1 if the announced length for an + * incoming record is valid, 0 otherwise, + * + * \param ctx decryption engine context. + * \param record_len incoming record length. + * \return 1 of a valid length, 0 otherwise. + */ + int (*check_length)(const br_sslrec_in_class *const *ctx, + size_t record_len); + + /** + * \brief Decrypt the incoming record. + * + * This function may assume that the record length is valid + * (it has been previously tested with `check_length()`). + * Decryption is done in place; `*len` is updated with the + * cleartext length, and the address of the first plaintext + * byte is returned. If the record is correct but empty, then + * `*len` is set to 0 and a non-`NULL` pointer is returned. + * + * On decryption/MAC error, `NULL` is returned. + * + * \param ctx decryption engine context. + * \param record_type record type (23 for application data, etc). + * \param version record version. + * \param payload address of encrypted payload. + * \param len pointer to payload length (updated). + * \return pointer to plaintext, or `NULL` on error. + */ + unsigned char *(*decrypt)(const br_sslrec_in_class **ctx, + int record_type, unsigned version, + void *payload, size_t *len); +}; + +/** + * \brief Encryption engine for SSL. + * + * When building outgoing records, the SSL engine will use an encryption + * engine that uses a specific context structure, and has a set of + * methods (a vtable) that follows this template. + * + * The encryption engine is responsible for applying encryption and MAC, + * and keeping track of the record sequence number. + */ +typedef struct br_sslrec_out_class_ br_sslrec_out_class; +struct br_sslrec_out_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Compute maximum plaintext sizes and offsets. + * + * When this function is called, the `*start` and `*end` + * values contain offsets designating the free area in the + * outgoing buffer for plaintext data; that free area is + * preceded by a 5-byte space which will receive the record + * header. + * + * The `max_plaintext()` function is responsible for adjusting + * both `*start` and `*end` to make room for any record-specific + * header, MAC, padding, and possible split. + * + * \param ctx encryption engine context. + * \param start pointer to start of plaintext offset (updated). + * \param end pointer to start of plaintext offset (updated). + */ + void (*max_plaintext)(const br_sslrec_out_class *const *ctx, + size_t *start, size_t *end); + + /** + * \brief Perform record encryption. + * + * This function encrypts the record. The plaintext address and + * length are provided. Returned value is the start of the + * encrypted record (or sequence of records, if a split was + * performed), _including_ the 5-byte header, and `*len` is + * adjusted to the total size of the record(s), there again + * including the header(s). + * + * \param ctx decryption engine context. + * \param record_type record type (23 for application data, etc). + * \param version record version. + * \param plaintext address of plaintext. + * \param len pointer to plaintext length (updated). + * \return pointer to start of built record. + */ + unsigned char *(*encrypt)(const br_sslrec_out_class **ctx, + int record_type, unsigned version, + void *plaintext, size_t *len); +}; + +/** + * \brief Context for a no-encryption engine. + * + * The no-encryption engine processes outgoing records during the initial + * handshake, before encryption is applied. + */ +typedef struct { + /** \brief No-encryption engine vtable. */ + const br_sslrec_out_class *vtable; +} br_sslrec_out_clear_context; + +/** \brief Static, constant vtable for the no-encryption engine. */ +extern const br_sslrec_out_class br_sslrec_out_clear_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for CBC mode. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for CBC processing: block cipher implementation, block cipher key, + * HMAC parameters (hash function, key, MAC length), and IV. If the + * IV is `NULL`, then a per-record IV will be used (TLS 1.1+). + */ +typedef struct br_sslrec_in_cbc_class_ br_sslrec_in_cbc_class; +struct br_sslrec_in_cbc_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CBC decryption). + * \param bc_key block cipher key. + * \param bc_key_len block cipher key length (in bytes). + * \param dig_impl hash function for HMAC. + * \param mac_key HMAC key. + * \param mac_key_len HMAC key length (in bytes). + * \param mac_out_len HMAC output length (in bytes). + * \param iv initial IV (or `NULL`). + */ + void (*init)(const br_sslrec_in_cbc_class **ctx, + const br_block_cbcdec_class *bc_impl, + const void *bc_key, size_t bc_key_len, + const br_hash_class *dig_impl, + const void *mac_key, size_t mac_key_len, size_t mac_out_len, + const void *iv); +}; + +/** + * \brief Record encryption engine class, for CBC mode. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for CBC processing: block cipher implementation, block cipher key, + * HMAC parameters (hash function, key, MAC length), and IV. If the + * IV is `NULL`, then a per-record IV will be used (TLS 1.1+). + */ +typedef struct br_sslrec_out_cbc_class_ br_sslrec_out_cbc_class; +struct br_sslrec_out_cbc_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CBC encryption). + * \param bc_key block cipher key. + * \param bc_key_len block cipher key length (in bytes). + * \param dig_impl hash function for HMAC. + * \param mac_key HMAC key. + * \param mac_key_len HMAC key length (in bytes). + * \param mac_out_len HMAC output length (in bytes). + * \param iv initial IV (or `NULL`). + */ + void (*init)(const br_sslrec_out_cbc_class **ctx, + const br_block_cbcenc_class *bc_impl, + const void *bc_key, size_t bc_key_len, + const br_hash_class *dig_impl, + const void *mac_key, size_t mac_key_len, size_t mac_out_len, + const void *iv); +}; + +/** + * \brief Context structure for decrypting incoming records with + * CBC + HMAC. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_sslrec_in_cbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_cbcdec_class *vtable; + br_aes_gen_cbcdec_keys aes; + br_des_gen_cbcdec_keys des; + } bc; + br_hmac_key_context mac; + size_t mac_len; + unsigned char iv[16]; + int explicit_IV; +#endif +} br_sslrec_in_cbc_context; + +/** + * \brief Static, constant vtable for record decryption with CBC. + */ +extern const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable; + +/** + * \brief Context structure for encrypting outgoing records with + * CBC + HMAC. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_sslrec_out_cbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_cbcenc_class *vtable; + br_aes_gen_cbcenc_keys aes; + br_des_gen_cbcenc_keys des; + } bc; + br_hmac_key_context mac; + size_t mac_len; + unsigned char iv[16]; + int explicit_IV; +#endif +} br_sslrec_out_cbc_context; + +/** + * \brief Static, constant vtable for record encryption with CBC. + */ +extern const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for GCM mode. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for GCM processing: block cipher implementation, block cipher key, + * GHASH implementation, and 4-byte IV. + */ +typedef struct br_sslrec_in_gcm_class_ br_sslrec_in_gcm_class; +struct br_sslrec_in_gcm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param gh_impl GHASH implementation. + * \param iv static IV (4 bytes). + */ + void (*init)(const br_sslrec_in_gcm_class **ctx, + const br_block_ctr_class *bc_impl, + const void *key, size_t key_len, + br_ghash gh_impl, + const void *iv); +}; + +/** + * \brief Record encryption engine class, for GCM mode. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for GCM processing: block cipher implementation, block cipher key, + * GHASH implementation, and 4-byte IV. + */ +typedef struct br_sslrec_out_gcm_class_ br_sslrec_out_gcm_class; +struct br_sslrec_out_gcm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param gh_impl GHASH implementation. + * \param iv static IV (4 bytes). + */ + void (*init)(const br_sslrec_out_gcm_class **ctx, + const br_block_ctr_class *bc_impl, + const void *key, size_t key_len, + br_ghash gh_impl, + const void *iv); +}; + +/** + * \brief Context structure for processing records with GCM. + * + * The same context structure is used for encrypting and decrypting. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + union { + const void *gen; + const br_sslrec_in_gcm_class *in; + const br_sslrec_out_gcm_class *out; + } vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_ctr_class *vtable; + br_aes_gen_ctr_keys aes; + } bc; + br_ghash gh; + unsigned char iv[4]; + unsigned char h[16]; +#endif +} br_sslrec_gcm_context; + +/** + * \brief Static, constant vtable for record decryption with GCM. + */ +extern const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable; + +/** + * \brief Static, constant vtable for record encryption with GCM. + */ +extern const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for ChaCha20+Poly1305. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for ChaCha20+Poly1305 processing: ChaCha20 implementation, + * Poly1305 implementation, key, and 12-byte IV. + */ +typedef struct br_sslrec_in_chapol_class_ br_sslrec_in_chapol_class; +struct br_sslrec_in_chapol_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param ichacha ChaCha20 implementation. + * \param ipoly Poly1305 implementation. + * \param key secret key (32 bytes). + * \param iv static IV (12 bytes). + */ + void (*init)(const br_sslrec_in_chapol_class **ctx, + br_chacha20_run ichacha, + br_poly1305_run ipoly, + const void *key, const void *iv); +}; + +/** + * \brief Record encryption engine class, for ChaCha20+Poly1305. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for ChaCha20+Poly1305 processing: ChaCha20 implementation, + * Poly1305 implementation, key, and 12-byte IV. + */ +typedef struct br_sslrec_out_chapol_class_ br_sslrec_out_chapol_class; +struct br_sslrec_out_chapol_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param ichacha ChaCha20 implementation. + * \param ipoly Poly1305 implementation. + * \param key secret key (32 bytes). + * \param iv static IV (12 bytes). + */ + void (*init)(const br_sslrec_out_chapol_class **ctx, + br_chacha20_run ichacha, + br_poly1305_run ipoly, + const void *key, const void *iv); +}; + +/** + * \brief Context structure for processing records with ChaCha20+Poly1305. + * + * The same context structure is used for encrypting and decrypting. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + union { + const void *gen; + const br_sslrec_in_chapol_class *in; + const br_sslrec_out_chapol_class *out; + } vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + unsigned char key[32]; + unsigned char iv[12]; + br_chacha20_run ichacha; + br_poly1305_run ipoly; +#endif +} br_sslrec_chapol_context; + +/** + * \brief Static, constant vtable for record decryption with ChaCha20+Poly1305. + */ +extern const br_sslrec_in_chapol_class br_sslrec_in_chapol_vtable; + +/** + * \brief Static, constant vtable for record encryption with ChaCha20+Poly1305. + */ +extern const br_sslrec_out_chapol_class br_sslrec_out_chapol_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for CCM mode. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for CCM processing: block cipher implementation, block cipher key, + * and 4-byte IV. + */ +typedef struct br_sslrec_in_ccm_class_ br_sslrec_in_ccm_class; +struct br_sslrec_in_ccm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR+CBC). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param iv static IV (4 bytes). + * \param tag_len tag length (in bytes) + */ + void (*init)(const br_sslrec_in_ccm_class **ctx, + const br_block_ctrcbc_class *bc_impl, + const void *key, size_t key_len, + const void *iv, size_t tag_len); +}; + +/** + * \brief Record encryption engine class, for CCM mode. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for CCM processing: block cipher implementation, block cipher key, + * and 4-byte IV. + */ +typedef struct br_sslrec_out_ccm_class_ br_sslrec_out_ccm_class; +struct br_sslrec_out_ccm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR+CBC). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param iv static IV (4 bytes). + * \param tag_len tag length (in bytes) + */ + void (*init)(const br_sslrec_out_ccm_class **ctx, + const br_block_ctrcbc_class *bc_impl, + const void *key, size_t key_len, + const void *iv, size_t tag_len); +}; + +/** + * \brief Context structure for processing records with CCM. + * + * The same context structure is used for encrypting and decrypting. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + union { + const void *gen; + const br_sslrec_in_ccm_class *in; + const br_sslrec_out_ccm_class *out; + } vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_ctrcbc_class *vtable; + br_aes_gen_ctrcbc_keys aes; + } bc; + unsigned char iv[4]; + size_t tag_len; +#endif +} br_sslrec_ccm_context; + +/** + * \brief Static, constant vtable for record decryption with CCM. + */ +extern const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable; + +/** + * \brief Static, constant vtable for record encryption with CCM. + */ +extern const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable; + +/* ===================================================================== */ + +/** + * \brief Type for session parameters, to be saved for session resumption. + */ +typedef struct { + /** \brief Session ID buffer. */ + unsigned char session_id[32]; + /** \brief Session ID length (in bytes, at most 32). */ + unsigned char session_id_len; + /** \brief Protocol version. */ + uint16_t version; + /** \brief Cipher suite. */ + uint16_t cipher_suite; + /** \brief Master secret. */ + unsigned char master_secret[48]; +} br_ssl_session_parameters; + +#ifndef BR_DOXYGEN_IGNORE +/* + * Maximum number of cipher suites supported by a client or server. + */ +#define BR_MAX_CIPHER_SUITES 48 +#endif + +/** + * \brief Context structure for SSL engine. + * + * This strucuture is common to the client and server; both the client + * context (`br_ssl_client_context`) and the server context + * (`br_ssl_server_context`) include a `br_ssl_engine_context` as their + * first field. + * + * The engine context manages records, including alerts, closures, and + * transitions to new encryption/MAC algorithms. Processing of handshake + * records is delegated to externally provided code. This structure + * should not be used directly. + * + * Structure contents are opaque and shall not be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + /* + * The error code. When non-zero, then the state is "failed" and + * no I/O may occur until reset. + */ + int err; + + /* + * Configured I/O buffers. They are either disjoint, or identical. + */ + unsigned char *ibuf, *obuf; + size_t ibuf_len, obuf_len; + + /* + * Maximum fragment length applies to outgoing records; incoming + * records can be processed as long as they fit in the input + * buffer. It is guaranteed that incoming records at least as big + * as max_frag_len can be processed. + */ + uint16_t max_frag_len; + unsigned char log_max_frag_len; + unsigned char peer_log_max_frag_len; + + /* + * Buffering management registers. + */ + size_t ixa, ixb, ixc; + size_t oxa, oxb, oxc; + unsigned char iomode; + unsigned char incrypt; + + /* + * Shutdown flag: when set to non-zero, incoming record bytes + * will not be accepted anymore. This is used after a close_notify + * has been received: afterwards, the engine no longer claims that + * it could receive bytes from the transport medium. + */ + unsigned char shutdown_recv; + + /* + * 'record_type_in' is set to the incoming record type when the + * record header has been received. + * 'record_type_out' is used to make the next outgoing record + * header when it is ready to go. + */ + unsigned char record_type_in, record_type_out; + + /* + * When a record is received, its version is extracted: + * -- if 'version_in' is 0, then it is set to the received version; + * -- otherwise, if the received version is not identical to + * the 'version_in' contents, then a failure is reported. + * + * This implements the SSL requirement that all records shall + * use the negotiated protocol version, once decided (in the + * ServerHello). It is up to the handshake handler to adjust this + * field when necessary. + */ + uint16_t version_in; + + /* + * 'version_out' is used when the next outgoing record is ready + * to go. + */ + uint16_t version_out; + + /* + * Record handler contexts. + */ + union { + const br_sslrec_in_class *vtable; + br_sslrec_in_cbc_context cbc; + br_sslrec_gcm_context gcm; + br_sslrec_chapol_context chapol; + br_sslrec_ccm_context ccm; + } in; + union { + const br_sslrec_out_class *vtable; + br_sslrec_out_clear_context clear; + br_sslrec_out_cbc_context cbc; + br_sslrec_gcm_context gcm; + br_sslrec_chapol_context chapol; + br_sslrec_ccm_context ccm; + } out; + + /* + * The "application data" flag. Value: + * 0 handshake is in process, no application data acceptable + * 1 application data can be sent and received + * 2 closing, no application data can be sent, but some + * can still be received (and discarded) + */ + unsigned char application_data; + + /* + * Context RNG. + * + * rng_init_done is initially 0. It is set to 1 when the + * basic structure of the RNG is set, and 2 when some + * entropy has been pushed in. The value 2 marks the RNG + * as "properly seeded". + * + * rng_os_rand_done is initially 0. It is set to 1 when + * some seeding from the OS or hardware has been attempted. + */ + br_hmac_drbg_context rng; + int rng_init_done; + int rng_os_rand_done; + + /* + * Supported minimum and maximum versions, and cipher suites. + */ + uint16_t version_min; + uint16_t version_max; + uint16_t suites_buf[BR_MAX_CIPHER_SUITES]; + unsigned char suites_num; + + /* + * For clients, the server name to send as a SNI extension. For + * servers, the name received in the SNI extension (if any). + */ + char server_name[256]; + + /* + * "Security parameters". These are filled by the handshake + * handler, and used when switching encryption state. + */ + unsigned char client_random[32]; + unsigned char server_random[32]; + br_ssl_session_parameters session; + + /* + * ECDHE elements: curve and point from the peer. The server also + * uses that buffer for the point to send to the client. + */ + unsigned char ecdhe_curve; + unsigned char ecdhe_point[133]; + unsigned char ecdhe_point_len; + + /* + * Secure renegotiation (RFC 5746): 'reneg' can be: + * 0 first handshake (server support is not known) + * 1 peer does not support secure renegotiation + * 2 peer supports secure renegotiation + * + * The saved_finished buffer contains the client and the + * server "Finished" values from the last handshake, in + * that order (12 bytes each). + */ + unsigned char reneg; + unsigned char saved_finished[24]; + + /* + * Behavioural flags. + */ + uint32_t flags; + + /* + * Context variables for the handshake processor. The 'pad' must + * be large enough to accommodate an RSA-encrypted pre-master + * secret, or an RSA signature; since we want to support up to + * RSA-4096, this means at least 512 bytes. (Other pad usages + * require its length to be at least 256.) + */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + unsigned char pad[512]; + unsigned char *hbuf_in, *hbuf_out, *saved_hbuf_out; + size_t hlen_in, hlen_out; + void (*hsrun)(void *ctx); + + /* + * The 'action' value communicates OOB information between the + * engine and the handshake processor. + * + * From the engine: + * 0 invocation triggered by I/O + * 1 invocation triggered by explicit close + * 2 invocation triggered by explicit renegotiation + */ + unsigned char action; + + /* + * State for alert messages. Value is either 0, or the value of + * the alert level byte (level is either 1 for warning, or 2 for + * fatal; we convert all other values to 'fatal'). + */ + unsigned char alert; + + /* + * Closure flags. This flag is set when a close_notify has been + * received from the peer. + */ + unsigned char close_received; + + /* + * Multi-hasher for the handshake messages. The handshake handler + * is responsible for resetting it when appropriate. + */ + br_multihash_context mhash; + + /* + * Pointer to the X.509 engine. The engine is supposed to be + * already initialized. It is used to validate the peer's + * certificate. + */ + const br_x509_class **x509ctx; + + /* + * Certificate chain to send. This is used by both client and + * server, when they send their respective Certificate messages. + * If chain_len is 0, then chain may be NULL. + */ + const br_x509_certificate *chain; + size_t chain_len; + const unsigned char *cert_cur; + size_t cert_len; + + /* + * List of supported protocol names (ALPN extension). If unset, + * (number of names is 0), then: + * - the client sends no ALPN extension; + * - the server ignores any incoming ALPN extension. + * + * Otherwise: + * - the client sends an ALPN extension with all the names; + * - the server selects the first protocol in its list that + * the client also supports, or fails (fatal alert 120) + * if the client sends an ALPN extension and there is no + * match. + * + * The 'selected_protocol' field contains 1+n if the matching + * name has index n in the list (the value is 0 if no match was + * performed, e.g. the peer did not send an ALPN extension). + */ + const char **protocol_names; + uint16_t protocol_names_num; + uint16_t selected_protocol; + + /* + * Pointers to implementations; left to NULL for unsupported + * functions. For the raw hash functions, implementations are + * referenced from the multihasher (mhash field). + */ + br_tls_prf_impl prf10; + br_tls_prf_impl prf_sha256; + br_tls_prf_impl prf_sha384; + const br_block_cbcenc_class *iaes_cbcenc; + const br_block_cbcdec_class *iaes_cbcdec; + const br_block_ctr_class *iaes_ctr; + const br_block_ctrcbc_class *iaes_ctrcbc; + const br_block_cbcenc_class *ides_cbcenc; + const br_block_cbcdec_class *ides_cbcdec; + br_ghash ighash; + br_chacha20_run ichacha; + br_poly1305_run ipoly; + const br_sslrec_in_cbc_class *icbc_in; + const br_sslrec_out_cbc_class *icbc_out; + const br_sslrec_in_gcm_class *igcm_in; + const br_sslrec_out_gcm_class *igcm_out; + const br_sslrec_in_chapol_class *ichapol_in; + const br_sslrec_out_chapol_class *ichapol_out; + const br_sslrec_in_ccm_class *iccm_in; + const br_sslrec_out_ccm_class *iccm_out; + const br_ec_impl *iec; + br_rsa_pkcs1_vrfy irsavrfy; + br_ecdsa_vrfy iecdsa; +#endif +} br_ssl_engine_context; + +/** + * \brief Get currently defined engine behavioural flags. + * + * \param cc SSL engine context. + * \return the flags. + */ +static inline uint32_t +br_ssl_engine_get_flags(br_ssl_engine_context *cc) +{ + return cc->flags; +} + +/** + * \brief Set all engine behavioural flags. + * + * \param cc SSL engine context. + * \param flags new value for all flags. + */ +static inline void +br_ssl_engine_set_all_flags(br_ssl_engine_context *cc, uint32_t flags) +{ + cc->flags = flags; +} + +/** + * \brief Set some engine behavioural flags. + * + * The flags set in the `flags` parameter are set in the context; other + * flags are untouched. + * + * \param cc SSL engine context. + * \param flags additional set flags. + */ +static inline void +br_ssl_engine_add_flags(br_ssl_engine_context *cc, uint32_t flags) +{ + cc->flags |= flags; +} + +/** + * \brief Clear some engine behavioural flags. + * + * The flags set in the `flags` parameter are cleared from the context; other + * flags are untouched. + * + * \param cc SSL engine context. + * \param flags flags to remove. + */ +static inline void +br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags) +{ + cc->flags &= ~flags; +} + +/** + * \brief Behavioural flag: enforce server preferences. + * + * If this flag is set, then the server will enforce its own cipher suite + * preference order; otherwise, it follows the client preferences. + */ +#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0) + +/** + * \brief Behavioural flag: disable renegotiation. + * + * If this flag is set, then renegotiations are rejected unconditionally: + * they won't be honoured if asked for programmatically, and requests from + * the peer are rejected. + */ +#define BR_OPT_NO_RENEGOTIATION ((uint32_t)1 << 1) + +/** + * \brief Behavioural flag: tolerate lack of client authentication. + * + * If this flag is set in a server and the server requests a client + * certificate, but the authentication fails (the client does not send + * a certificate, or the client's certificate chain cannot be validated), + * then the connection keeps on. Without this flag, a failed client + * authentication terminates the connection. + * + * Notes: + * + * - If the client's certificate can be validated and its public key is + * supported, then a wrong signature value terminates the connection + * regardless of that flag. + * + * - If using full-static ECDH, then a failure to validate the client's + * certificate prevents the handshake from succeeding. + */ +#define BR_OPT_TOLERATE_NO_CLIENT_AUTH ((uint32_t)1 << 2) + +/** + * \brief Behavioural flag: fail on application protocol mismatch. + * + * The ALPN extension ([RFC 7301](https://tools.ietf.org/html/rfc7301)) + * allows the client to send a list of application protocol names, and + * the server to select one. A mismatch is one of the following occurrences: + * + * - On the client: the client sends a list of names, the server + * responds with a protocol name which is _not_ part of the list of + * names sent by the client. + * + * - On the server: the client sends a list of names, and the server + * is also configured with a list of names, but there is no common + * protocol name between the two lists. + * + * Normal behaviour in case of mismatch is to report no matching name + * (`br_ssl_engine_get_selected_protocol()` returns `NULL`) and carry on. + * If the flag is set, then a mismatch implies a protocol failure (if + * the mismatch is detected by the server, it will send a fatal alert). + * + * Note: even with this flag, `br_ssl_engine_get_selected_protocol()` + * may still return `NULL` if the client or the server does not send an + * ALPN extension at all. + */ +#define BR_OPT_FAIL_ON_ALPN_MISMATCH ((uint32_t)1 << 3) + +/** + * \brief Set the minimum and maximum supported protocol versions. + * + * The two provided versions MUST be supported by the implementation + * (i.e. TLS 1.0, 1.1 and 1.2), and `version_max` MUST NOT be lower + * than `version_min`. + * + * \param cc SSL engine context. + * \param version_min minimum supported TLS version. + * \param version_max maximum supported TLS version. + */ +static inline void +br_ssl_engine_set_versions(br_ssl_engine_context *cc, + unsigned version_min, unsigned version_max) +{ + cc->version_min = version_min; + cc->version_max = version_max; +} + +/** + * \brief Set the list of cipher suites advertised by this context. + * + * The provided array is copied into the context. It is the caller + * responsibility to ensure that all provided suites will be supported + * by the context. The engine context has enough room to receive _all_ + * suites supported by the implementation. The provided array MUST NOT + * contain duplicates. + * + * If the engine is for a client, the "signaling" pseudo-cipher suite + * `TLS_FALLBACK_SCSV` can be added at the end of the list, if the + * calling application is performing a voluntary downgrade (voluntary + * downgrades are not recommended, but if such a downgrade is done, then + * adding the fallback pseudo-suite is a good idea). + * + * \param cc SSL engine context. + * \param suites cipher suites. + * \param suites_num number of cipher suites. + */ +void br_ssl_engine_set_suites(br_ssl_engine_context *cc, + const uint16_t *suites, size_t suites_num); + +/** + * \brief Set the X.509 engine. + * + * The caller shall ensure that the X.509 engine is properly initialised. + * + * \param cc SSL engine context. + * \param x509ctx X.509 certificate validation context. + */ +static inline void +br_ssl_engine_set_x509(br_ssl_engine_context *cc, const br_x509_class **x509ctx) +{ + cc->x509ctx = x509ctx; +} + +/** + * \brief Set the supported protocol names. + * + * Protocol names are part of the ALPN extension ([RFC + * 7301](https://tools.ietf.org/html/rfc7301)). Each protocol name is a + * character string, containing no more than 255 characters (256 with the + * terminating zero). When names are set, then: + * + * - The client will send an ALPN extension, containing the names. If + * the server responds with an ALPN extension, the client will verify + * that the response contains one of its name, and report that name + * through `br_ssl_engine_get_selected_protocol()`. + * + * - The server will parse incoming ALPN extension (from clients), and + * try to find a common protocol; if none is found, the connection + * is aborted with a fatal alert. On match, a response ALPN extension + * is sent, and name is reported through + * `br_ssl_engine_get_selected_protocol()`. + * + * The provided array is linked in, and must remain valid while the + * connection is live. + * + * Names MUST NOT be empty. Names MUST NOT be longer than 255 characters + * (excluding the terminating 0). + * + * \param ctx SSL engine context. + * \param names list of protocol names (zero-terminated). + * \param num number of protocol names (MUST be 1 or more). + */ +static inline void +br_ssl_engine_set_protocol_names(br_ssl_engine_context *ctx, + const char **names, size_t num) +{ + ctx->protocol_names = names; + ctx->protocol_names_num = num; +} + +/** + * \brief Get the selected protocol. + * + * If this context was initialised with a non-empty list of protocol + * names, and both client and server sent ALPN extensions during the + * handshake, and a common name was found, then that name is returned. + * Otherwise, `NULL` is returned. + * + * The returned pointer is one of the pointers provided to the context + * with `br_ssl_engine_set_protocol_names()`. + * + * \return the selected protocol, or `NULL`. + */ +static inline const char * +br_ssl_engine_get_selected_protocol(br_ssl_engine_context *ctx) +{ + unsigned k; + + k = ctx->selected_protocol; + return (k == 0 || k == 0xFFFF) ? NULL : ctx->protocol_names[k - 1]; +} + +/** + * \brief Set a hash function implementation (by ID). + * + * Hash functions set with this call will be used for SSL/TLS specific + * usages, not X.509 certificate validation. Only "standard" hash functions + * may be set (MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512). If `impl` + * is `NULL`, then the hash function support is removed, not added. + * + * \param ctx SSL engine context. + * \param id hash function identifier. + * \param impl hash function implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_hash(br_ssl_engine_context *ctx, + int id, const br_hash_class *impl) +{ + br_multihash_setimpl(&ctx->mhash, id, impl); +} + +/** + * \brief Get a hash function implementation (by ID). + * + * This function retrieves a hash function implementation which was + * set with `br_ssl_engine_set_hash()`. + * + * \param ctx SSL engine context. + * \param id hash function identifier. + * \return the hash function implementation (or `NULL`). + */ +static inline const br_hash_class * +br_ssl_engine_get_hash(br_ssl_engine_context *ctx, int id) +{ + return br_multihash_getimpl(&ctx->mhash, id); +} + +/** + * \brief Set the PRF implementation (for TLS 1.0 and 1.1). + * + * This function sets (or removes, if `impl` is `NULL`) the implementation + * for the PRF used in TLS 1.0 and 1.1. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_prf10(br_ssl_engine_context *cc, br_tls_prf_impl impl) +{ + cc->prf10 = impl; +} + +/** + * \brief Set the PRF implementation with SHA-256 (for TLS 1.2). + * + * This function sets (or removes, if `impl` is `NULL`) the implementation + * for the SHA-256 variant of the PRF used in TLS 1.2. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_prf_sha256(br_ssl_engine_context *cc, br_tls_prf_impl impl) +{ + cc->prf_sha256 = impl; +} + +/** + * \brief Set the PRF implementation with SHA-384 (for TLS 1.2). + * + * This function sets (or removes, if `impl` is `NULL`) the implementation + * for the SHA-384 variant of the PRF used in TLS 1.2. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_prf_sha384(br_ssl_engine_context *cc, br_tls_prf_impl impl) +{ + cc->prf_sha384 = impl; +} + +/** + * \brief Set the AES/CBC implementations. + * + * \param cc SSL engine context. + * \param impl_enc AES/CBC encryption implementation (or `NULL`). + * \param impl_dec AES/CBC decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_aes_cbc(br_ssl_engine_context *cc, + const br_block_cbcenc_class *impl_enc, + const br_block_cbcdec_class *impl_dec) +{ + cc->iaes_cbcenc = impl_enc; + cc->iaes_cbcdec = impl_dec; +} + +/** + * \brief Set the "default" AES/CBC implementations. + * + * This function configures in the engine the AES implementations that + * should provide best runtime performance on the local system, while + * still being safe (in particular, constant-time). It also sets the + * handlers for CBC records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_aes_cbc(br_ssl_engine_context *cc); + +/** + * \brief Set the AES/CTR implementation. + * + * \param cc SSL engine context. + * \param impl AES/CTR encryption/decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_aes_ctr(br_ssl_engine_context *cc, + const br_block_ctr_class *impl) +{ + cc->iaes_ctr = impl; +} + +/** + * \brief Set the "default" implementations for AES/GCM (AES/CTR + GHASH). + * + * This function configures in the engine the AES/CTR and GHASH + * implementation that should provide best runtime performance on the local + * system, while still being safe (in particular, constant-time). It also + * sets the handlers for GCM records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_aes_gcm(br_ssl_engine_context *cc); + +/** + * \brief Set the DES/CBC implementations. + * + * \param cc SSL engine context. + * \param impl_enc DES/CBC encryption implementation (or `NULL`). + * \param impl_dec DES/CBC decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_des_cbc(br_ssl_engine_context *cc, + const br_block_cbcenc_class *impl_enc, + const br_block_cbcdec_class *impl_dec) +{ + cc->ides_cbcenc = impl_enc; + cc->ides_cbcdec = impl_dec; +} + +/** + * \brief Set the "default" DES/CBC implementations. + * + * This function configures in the engine the DES implementations that + * should provide best runtime performance on the local system, while + * still being safe (in particular, constant-time). It also sets the + * handlers for CBC records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_des_cbc(br_ssl_engine_context *cc); + +/** + * \brief Set the GHASH implementation (used in GCM mode). + * + * \param cc SSL engine context. + * \param impl GHASH implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_ghash(br_ssl_engine_context *cc, br_ghash impl) +{ + cc->ighash = impl; +} + +/** + * \brief Set the ChaCha20 implementation. + * + * \param cc SSL engine context. + * \param ichacha ChaCha20 implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_chacha20(br_ssl_engine_context *cc, + br_chacha20_run ichacha) +{ + cc->ichacha = ichacha; +} + +/** + * \brief Set the Poly1305 implementation. + * + * \param cc SSL engine context. + * \param ipoly Poly1305 implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_poly1305(br_ssl_engine_context *cc, + br_poly1305_run ipoly) +{ + cc->ipoly = ipoly; +} + +/** + * \brief Set the "default" ChaCha20 and Poly1305 implementations. + * + * This function configures in the engine the ChaCha20 and Poly1305 + * implementations that should provide best runtime performance on the + * local system, while still being safe (in particular, constant-time). + * It also sets the handlers for ChaCha20+Poly1305 records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_chapol(br_ssl_engine_context *cc); + +/** + * \brief Set the AES/CTR+CBC implementation. + * + * \param cc SSL engine context. + * \param impl AES/CTR+CBC encryption/decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_aes_ctrcbc(br_ssl_engine_context *cc, + const br_block_ctrcbc_class *impl) +{ + cc->iaes_ctrcbc = impl; +} + +/** + * \brief Set the "default" implementations for AES/CCM. + * + * This function configures in the engine the AES/CTR+CBC + * implementation that should provide best runtime performance on the local + * system, while still being safe (in particular, constant-time). It also + * sets the handlers for CCM records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_aes_ccm(br_ssl_engine_context *cc); + +/** + * \brief Set the record encryption and decryption engines for CBC + HMAC. + * + * \param cc SSL engine context. + * \param impl_in record CBC decryption implementation (or `NULL`). + * \param impl_out record CBC encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_cbc(br_ssl_engine_context *cc, + const br_sslrec_in_cbc_class *impl_in, + const br_sslrec_out_cbc_class *impl_out) +{ + cc->icbc_in = impl_in; + cc->icbc_out = impl_out; +} + +/** + * \brief Set the record encryption and decryption engines for GCM. + * + * \param cc SSL engine context. + * \param impl_in record GCM decryption implementation (or `NULL`). + * \param impl_out record GCM encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_gcm(br_ssl_engine_context *cc, + const br_sslrec_in_gcm_class *impl_in, + const br_sslrec_out_gcm_class *impl_out) +{ + cc->igcm_in = impl_in; + cc->igcm_out = impl_out; +} + +/** + * \brief Set the record encryption and decryption engines for CCM. + * + * \param cc SSL engine context. + * \param impl_in record CCM decryption implementation (or `NULL`). + * \param impl_out record CCM encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_ccm(br_ssl_engine_context *cc, + const br_sslrec_in_ccm_class *impl_in, + const br_sslrec_out_ccm_class *impl_out) +{ + cc->iccm_in = impl_in; + cc->iccm_out = impl_out; +} + +/** + * \brief Set the record encryption and decryption engines for + * ChaCha20+Poly1305. + * + * \param cc SSL engine context. + * \param impl_in record ChaCha20 decryption implementation (or `NULL`). + * \param impl_out record ChaCha20 encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_chapol(br_ssl_engine_context *cc, + const br_sslrec_in_chapol_class *impl_in, + const br_sslrec_out_chapol_class *impl_out) +{ + cc->ichapol_in = impl_in; + cc->ichapol_out = impl_out; +} + +/** + * \brief Set the EC implementation. + * + * The elliptic curve implementation will be used for ECDH and ECDHE + * cipher suites, and for ECDSA support. + * + * \param cc SSL engine context. + * \param iec EC implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec) +{ + cc->iec = iec; +} + +/** + * \brief Set the "default" EC implementation. + * + * This function sets the elliptic curve implementation for ECDH and + * ECDHE cipher suites, and for ECDSA support. It selects the fastest + * implementation on the current system. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_ec(br_ssl_engine_context *cc); + +/** + * \brief Get the EC implementation configured in the provided engine. + * + * \param cc SSL engine context. + * \return the EC implementation. + */ +static inline const br_ec_impl * +br_ssl_engine_get_ec(br_ssl_engine_context *cc) +{ + return cc->iec; +} + +/** + * \brief Set the RSA signature verification implementation. + * + * On the client, this is used to verify the server's signature on its + * ServerKeyExchange message (for ECDHE_RSA cipher suites). On the server, + * this is used to verify the client's CertificateVerify message (if a + * client certificate is requested, and that certificate contains a RSA key). + * + * \param cc SSL engine context. + * \param irsavrfy RSA signature verification implementation. + */ +static inline void +br_ssl_engine_set_rsavrfy(br_ssl_engine_context *cc, br_rsa_pkcs1_vrfy irsavrfy) +{ + cc->irsavrfy = irsavrfy; +} + +/** + * \brief Set the "default" RSA implementation (signature verification). + * + * This function sets the RSA implementation (signature verification) + * to the fastest implementation available on the current platform. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_rsavrfy(br_ssl_engine_context *cc); + +/** + * \brief Get the RSA implementation (signature verification) configured + * in the provided engine. + * + * \param cc SSL engine context. + * \return the RSA signature verification implementation. + */ +static inline br_rsa_pkcs1_vrfy +br_ssl_engine_get_rsavrfy(br_ssl_engine_context *cc) +{ + return cc->irsavrfy; +} + +/* + * \brief Set the ECDSA implementation (signature verification). + * + * On the client, this is used to verify the server's signature on its + * ServerKeyExchange message (for ECDHE_ECDSA cipher suites). On the server, + * this is used to verify the client's CertificateVerify message (if a + * client certificate is requested, that certificate contains an EC key, + * and full-static ECDH is not used). + * + * The ECDSA implementation will use the EC core implementation configured + * in the engine context. + * + * \param cc client context. + * \param iecdsa ECDSA verification implementation. + */ +static inline void +br_ssl_engine_set_ecdsa(br_ssl_engine_context *cc, br_ecdsa_vrfy iecdsa) +{ + cc->iecdsa = iecdsa; +} + +/** + * \brief Set the "default" ECDSA implementation (signature verification). + * + * This function sets the ECDSA implementation (signature verification) + * to the fastest implementation available on the current platform. This + * call also sets the elliptic curve implementation itself, there again + * to the fastest EC implementation available. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_ecdsa(br_ssl_engine_context *cc); + +/** + * \brief Get the ECDSA implementation (signature verification) configured + * in the provided engine. + * + * \param cc SSL engine context. + * \return the ECDSA signature verification implementation. + */ +static inline br_ecdsa_vrfy +br_ssl_engine_get_ecdsa(br_ssl_engine_context *cc) +{ + return cc->iecdsa; +} + +/** + * \brief Set the I/O buffer for the SSL engine. + * + * Once this call has been made, `br_ssl_client_reset()` or + * `br_ssl_server_reset()` MUST be called before using the context. + * + * The provided buffer will be used as long as the engine context is + * used. The caller is responsible for keeping it available. + * + * If `bidi` is 0, then the engine will operate in half-duplex mode + * (it won't be able to send data while there is unprocessed incoming + * data in the buffer, and it won't be able to receive data while there + * is unsent data in the buffer). The optimal buffer size in half-duplex + * mode is `BR_SSL_BUFSIZE_MONO`; if the buffer is larger, then extra + * bytes are ignored. If the buffer is smaller, then this limits the + * capacity of the engine to support all allowed record sizes. + * + * If `bidi` is 1, then the engine will split the buffer into two + * parts, for separate handling of outgoing and incoming data. This + * enables full-duplex processing, but requires more RAM. The optimal + * buffer size in full-duplex mode is `BR_SSL_BUFSIZE_BIDI`; if the + * buffer is larger, then extra bytes are ignored. If the buffer is + * smaller, then the split will favour the incoming part, so that + * interoperability is maximised. + * + * \param cc SSL engine context + * \param iobuf I/O buffer. + * \param iobuf_len I/O buffer length (in bytes). + * \param bidi non-zero for full-duplex mode. + */ +void br_ssl_engine_set_buffer(br_ssl_engine_context *cc, + void *iobuf, size_t iobuf_len, int bidi); + +/** + * \brief Set the I/O buffers for the SSL engine. + * + * Once this call has been made, `br_ssl_client_reset()` or + * `br_ssl_server_reset()` MUST be called before using the context. + * + * This function is similar to `br_ssl_engine_set_buffer()`, except + * that it enforces full-duplex mode, and the two I/O buffers are + * provided as separate chunks. + * + * The macros `BR_SSL_BUFSIZE_INPUT` and `BR_SSL_BUFSIZE_OUTPUT` + * evaluate to the optimal (maximum) sizes for the input and output + * buffer, respectively. + * + * \param cc SSL engine context + * \param ibuf input buffer. + * \param ibuf_len input buffer length (in bytes). + * \param obuf output buffer. + * \param obuf_len output buffer length (in bytes). + */ +void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc, + void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len); + +/** + * \brief Inject some "initial entropy" in the context. + * + * This entropy will be added to what can be obtained from the + * underlying operating system, if that OS is supported. + * + * This function may be called several times; all injected entropy chunks + * are cumulatively mixed. + * + * If entropy gathering from the OS is supported and compiled in, then this + * step is optional. Otherwise, it is mandatory to inject randomness, and + * the caller MUST take care to push (as one or several successive calls) + * enough entropy to achieve cryptographic resistance (at least 80 bits, + * preferably 128 or more). The engine will report an error if no entropy + * was provided and none can be obtained from the OS. + * + * Take care that this function cannot assess the cryptographic quality of + * the provided bytes. + * + * In all generality, "entropy" must here be considered to mean "that + * which the attacker cannot predict". If your OS/architecture does not + * have a suitable source of randomness, then you can make do with the + * combination of a large enough secret value (possibly a copy of an + * asymmetric private key that you also store on the system) AND a + * non-repeating value (e.g. current time, provided that the local clock + * cannot be reset or altered by the attacker). + * + * \param cc SSL engine context. + * \param data extra entropy to inject. + * \param len length of the extra data (in bytes). + */ +void br_ssl_engine_inject_entropy(br_ssl_engine_context *cc, + const void *data, size_t len); + +/** + * \brief Get the "server name" in this engine. + * + * For clients, this is the name provided with `br_ssl_client_reset()`; + * for servers, this is the name received from the client as part of the + * ClientHello message. If there is no such name (e.g. the client did + * not send an SNI extension) then the returned string is empty + * (returned pointer points to a byte of value 0). + * + * The returned pointer refers to a buffer inside the context, which may + * be overwritten as part of normal SSL activity (even within the same + * connection, if a renegotiation occurs). + * + * \param cc SSL engine context. + * \return the server name (possibly empty). + */ +static inline const char * +br_ssl_engine_get_server_name(const br_ssl_engine_context *cc) +{ + return cc->server_name; +} + +/** + * \brief Get the protocol version. + * + * This function returns the protocol version that is used by the + * engine. That value is set after sending (for a server) or receiving + * (for a client) the ServerHello message. + * + * \param cc SSL engine context. + * \return the protocol version. + */ +static inline unsigned +br_ssl_engine_get_version(const br_ssl_engine_context *cc) +{ + return cc->session.version; +} + +/** + * \brief Get a copy of the session parameters. + * + * The session parameters are filled during the handshake, so this + * function shall not be called before completion of the handshake. + * The initial handshake is completed when the context first allows + * application data to be injected. + * + * This function copies the current session parameters into the provided + * structure. Beware that the session parameters include the master + * secret, which is sensitive data, to handle with great care. + * + * \param cc SSL engine context. + * \param pp destination structure for the session parameters. + */ +static inline void +br_ssl_engine_get_session_parameters(const br_ssl_engine_context *cc, + br_ssl_session_parameters *pp) +{ + memcpy(pp, &cc->session, sizeof *pp); +} + +/** + * \brief Set the session parameters to the provided values. + * + * This function is meant to be used in the client, before doing a new + * handshake; a session resumption will be attempted with these + * parameters. In the server, this function has no effect. + * + * \param cc SSL engine context. + * \param pp source structure for the session parameters. + */ +static inline void +br_ssl_engine_set_session_parameters(br_ssl_engine_context *cc, + const br_ssl_session_parameters *pp) +{ + memcpy(&cc->session, pp, sizeof *pp); +} + +/** + * \brief Get identifier for the curve used for key exchange. + * + * If the cipher suite uses ECDHE, then this function returns the + * identifier for the curve used for transient parameters. This is + * defined during the course of the handshake, when the ServerKeyExchange + * is sent (on the server) or received (on the client). If the + * cipher suite does not use ECDHE (e.g. static ECDH, or RSA key + * exchange), then this value is indeterminate. + * + * @param cc SSL engine context. + * @return the ECDHE curve identifier. + */ +static inline int +br_ssl_engine_get_ecdhe_curve(br_ssl_engine_context *cc) +{ + return cc->ecdhe_curve; +} + +/** + * \brief Get the current engine state. + * + * An SSL engine (client or server) has, at any time, a state which is + * the combination of zero, one or more of these flags: + * + * - `BR_SSL_CLOSED` + * + * Engine is finished, no more I/O (until next reset). + * + * - `BR_SSL_SENDREC` + * + * Engine has some bytes to send to the peer. + * + * - `BR_SSL_RECVREC` + * + * Engine expects some bytes from the peer. + * + * - `BR_SSL_SENDAPP` + * + * Engine may receive application data to send (or flush). + * + * - `BR_SSL_RECVAPP` + * + * Engine has obtained some application data from the peer, + * that should be read by the caller. + * + * If no flag at all is set (state value is 0), then the engine is not + * fully initialised yet. + * + * The `BR_SSL_CLOSED` flag is exclusive; when it is set, no other flag + * is set. To distinguish between a normal closure and an error, use + * `br_ssl_engine_last_error()`. + * + * Generally speaking, `BR_SSL_SENDREC` and `BR_SSL_SENDAPP` are mutually + * exclusive: the input buffer, at any point, either accumulates + * plaintext data, or contains an assembled record that is being sent. + * Similarly, `BR_SSL_RECVREC` and `BR_SSL_RECVAPP` are mutually exclusive. + * This may change in a future library version. + * + * \param cc SSL engine context. + * \return the current engine state. + */ +unsigned br_ssl_engine_current_state(const br_ssl_engine_context *cc); + +/** \brief SSL engine state: closed or failed. */ +#define BR_SSL_CLOSED 0x0001 +/** \brief SSL engine state: record data is ready to be sent to the peer. */ +#define BR_SSL_SENDREC 0x0002 +/** \brief SSL engine state: engine may receive records from the peer. */ +#define BR_SSL_RECVREC 0x0004 +/** \brief SSL engine state: engine may accept application data to send. */ +#define BR_SSL_SENDAPP 0x0008 +/** \brief SSL engine state: engine has received application data. */ +#define BR_SSL_RECVAPP 0x0010 + +/** + * \brief Get the engine error indicator. + * + * The error indicator is `BR_ERR_OK` (0) if no error was encountered + * since the last call to `br_ssl_client_reset()` or + * `br_ssl_server_reset()`. Other status values are "sticky": they + * remain set, and prevent all I/O activity, until cleared. Only the + * reset calls clear the error indicator. + * + * \param cc SSL engine context. + * \return 0, or a non-zero error code. + */ +static inline int +br_ssl_engine_last_error(const br_ssl_engine_context *cc) +{ + return cc->err; +} + +/* + * There are four I/O operations, each identified by a symbolic name: + * + * sendapp inject application data in the engine + * recvapp retrieving application data from the engine + * sendrec sending records on the transport medium + * recvrec receiving records from the transport medium + * + * Terminology works thus: in a layered model where the SSL engine sits + * between the application and the network, "send" designates operations + * where bytes flow from application to network, and "recv" for the + * reverse operation. Application data (the plaintext that is to be + * conveyed through SSL) is "app", while encrypted records are "rec". + * Note that from the SSL engine point of view, "sendapp" and "recvrec" + * designate bytes that enter the engine ("inject" operation), while + * "recvapp" and "sendrec" designate bytes that exit the engine + * ("extract" operation). + * + * For the operation 'xxx', two functions are defined: + * + * br_ssl_engine_xxx_buf + * Returns a pointer and length to the buffer to use for that + * operation. '*len' is set to the number of bytes that may be read + * from the buffer (extract operation) or written to the buffer + * (inject operation). If no byte may be exchanged for that operation + * at that point, then '*len' is set to zero, and NULL is returned. + * The engine state is unmodified by this call. + * + * br_ssl_engine_xxx_ack + * Informs the engine that 'len' bytes have been read from the buffer + * (extract operation) or written to the buffer (inject operation). + * The 'len' value MUST NOT be zero. The 'len' value MUST NOT exceed + * that which was obtained from a preceding br_ssl_engine_xxx_buf() + * call. + */ + +/** + * \brief Get buffer for application data to send. + * + * If the engine is ready to accept application data to send to the + * peer, then this call returns a pointer to the buffer where such + * data shall be written, and its length is written in `*len`. + * Otherwise, `*len` is set to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the application data output buffer length, or 0. + * \return the application data output buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_sendapp_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Inform the engine of some new application data. + * + * After writing `len` bytes in the buffer returned by + * `br_ssl_engine_sendapp_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_sendapp_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes pushed (not zero). + */ +void br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Get buffer for received application data. + * + * If the engine has received application data from the peer, hen this + * call returns a pointer to the buffer from where such data shall be + * read, and its length is written in `*len`. Otherwise, `*len` is set + * to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the application data input buffer length, or 0. + * \return the application data input buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_recvapp_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Acknowledge some received application data. + * + * After reading `len` bytes from the buffer returned by + * `br_ssl_engine_recvapp_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_recvapp_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes read (not zero). + */ +void br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Get buffer for record data to send. + * + * If the engine has prepared some records to send to the peer, then this + * call returns a pointer to the buffer from where such data shall be + * read, and its length is written in `*len`. Otherwise, `*len` is set + * to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the record data output buffer length, or 0. + * \return the record data output buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_sendrec_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Acknowledge some sent record data. + * + * After reading `len` bytes from the buffer returned by + * `br_ssl_engine_sendrec_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_sendrec_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes read (not zero). + */ +void br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Get buffer for incoming records. + * + * If the engine is ready to accept records from the peer, then this + * call returns a pointer to the buffer where such data shall be + * written, and its length is written in `*len`. Otherwise, `*len` is + * set to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the record data input buffer length, or 0. + * \return the record data input buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_recvrec_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Inform the engine of some new record data. + * + * After writing `len` bytes in the buffer returned by + * `br_ssl_engine_recvrec_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_recvrec_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes pushed (not zero). + */ +void br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Flush buffered application data. + * + * If some application data has been buffered in the engine, then wrap + * it into a record and mark it for sending. If no application data has + * been buffered but the engine would be ready to accept some, AND the + * `force` parameter is non-zero, then an empty record is assembled and + * marked for sending. In all other cases, this function does nothing. + * + * Empty records are technically legal, but not all existing SSL/TLS + * implementations support them. Empty records can be useful as a + * transparent "keep-alive" mechanism to maintain some low-level + * network activity. + * + * \param cc SSL engine context. + * \param force non-zero to force sending an empty record. + */ +void br_ssl_engine_flush(br_ssl_engine_context *cc, int force); + +/** + * \brief Initiate a closure. + * + * If, at that point, the context is open and in ready state, then a + * `close_notify` alert is assembled and marked for sending; this + * triggers the closure protocol. Otherwise, no such alert is assembled. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_close(br_ssl_engine_context *cc); + +/** + * \brief Initiate a renegotiation. + * + * If the engine is failed or closed, or if the peer is known not to + * support secure renegotiation (RFC 5746), or if renegotiations have + * been disabled with the `BR_OPT_NO_RENEGOTIATION` flag, or if there + * is buffered incoming application data, then this function returns 0 + * and nothing else happens. + * + * Otherwise, this function returns 1, and a renegotiation attempt is + * triggered (if a handshake is already ongoing at that point, then + * no new handshake is triggered). + * + * \param cc SSL engine context. + * \return 1 on success, 0 on error. + */ +int br_ssl_engine_renegotiate(br_ssl_engine_context *cc); + +/** + * \brief Export key material from a connected SSL engine (RFC 5705). + * + * This calls compute a secret key of arbitrary length from the master + * secret of a connected SSL engine. If the provided context is not + * currently in "application data" state (initial handshake is not + * finished, another handshake is ongoing, or the connection failed or + * was closed), then this function returns 0. Otherwise, a secret key of + * length `len` bytes is computed and written in the buffer pointed to + * by `dst`, and 1 is returned. + * + * The computed key follows the specification described in RFC 5705. + * That RFC includes two key computations, with and without a "context + * value". If `context` is `NULL`, then the variant without context is + * used; otherwise, the `context_len` bytes located at the address + * pointed to by `context` are used in the computation. Note that it + * is possible to have a "with context" key with a context length of + * zero bytes, by setting `context` to a non-`NULL` value but + * `context_len` to 0. + * + * When context bytes are used, the context length MUST NOT exceed + * 65535 bytes. + * + * \param cc SSL engine context. + * \param dst destination buffer for exported key. + * \param len exported key length (in bytes). + * \param label disambiguation label. + * \param context context value (or `NULL`). + * \param context_len context length (in bytes). + * \return 1 on success, 0 on error. + */ +int br_ssl_key_export(br_ssl_engine_context *cc, + void *dst, size_t len, const char *label, + const void *context, size_t context_len); + +/* + * Pre-declaration for the SSL client context. + */ +typedef struct br_ssl_client_context_ br_ssl_client_context; + +/** + * \brief Type for the client certificate, if requested by the server. + */ +typedef struct { + /** + * \brief Authentication type. + * + * This is either `BR_AUTH_RSA` (RSA signature), `BR_AUTH_ECDSA` + * (ECDSA signature), or `BR_AUTH_ECDH` (static ECDH key exchange). + */ + int auth_type; + + /** + * \brief Hash function for computing the CertificateVerify. + * + * This is the symbolic identifier for the hash function that + * will be used to produce the hash of handshake messages, to + * be signed into the CertificateVerify. For full static ECDH + * (client and server certificates are both EC in the same + * curve, and static ECDH is used), this value is set to -1. + * + * Take care that with TLS 1.0 and 1.1, that value MUST match + * the protocol requirements: value must be 0 (MD5+SHA-1) for + * a RSA signature, or 2 (SHA-1) for an ECDSA signature. Only + * TLS 1.2 allows for other hash functions. + */ + int hash_id; + + /** + * \brief Certificate chain to send to the server. + * + * This is an array of `br_x509_certificate` objects, each + * normally containing a DER-encoded certificate. The client + * code does not try to decode these elements. If there is no + * chain to send to the server, then this pointer shall be + * set to `NULL`. + */ + const br_x509_certificate *chain; + + /** + * \brief Certificate chain length (number of certificates). + * + * If there is no chain to send to the server, then this value + * shall be set to 0. + */ + size_t chain_len; + +} br_ssl_client_certificate; + +/* + * Note: the constants below for signatures match the TLS constants. + */ + +/** \brief Client authentication type: static ECDH. */ +#define BR_AUTH_ECDH 0 +/** \brief Client authentication type: RSA signature. */ +#define BR_AUTH_RSA 1 +/** \brief Client authentication type: ECDSA signature. */ +#define BR_AUTH_ECDSA 3 + +/** + * \brief Class type for a certificate handler (client side). + * + * A certificate handler selects a client certificate chain to send to + * the server, upon explicit request from that server. It receives + * the list of trust anchor DN from the server, and supported types + * of certificates and signatures, and returns the chain to use. It + * is also invoked to perform the corresponding private key operation + * (a signature, or an ECDH computation). + * + * The SSL client engine will first push the trust anchor DN with + * `start_name_list()`, `start_name()`, `append_name()`, `end_name()` + * and `end_name_list()`. Then it will call `choose()`, to select the + * actual chain (and signature/hash algorithms). Finally, it will call + * either `do_sign()` or `do_keyx()`, depending on the algorithm choices. + */ +typedef struct br_ssl_client_certificate_class_ br_ssl_client_certificate_class; +struct br_ssl_client_certificate_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Begin reception of a list of trust anchor names. This + * is called while parsing the incoming CertificateRequest. + * + * \param pctx certificate handler context. + */ + void (*start_name_list)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief Begin reception of a new trust anchor name. + * + * The total encoded name length is provided; it is less than + * 65535 bytes. + * + * \param pctx certificate handler context. + * \param len encoded name length (in bytes). + */ + void (*start_name)(const br_ssl_client_certificate_class **pctx, + size_t len); + + /** + * \brief Receive some more bytes for the current trust anchor name. + * + * The provided reference (`data`) points to a transient buffer + * they may be reused as soon as this function returns. The chunk + * length (`len`) is never zero. + * + * \param pctx certificate handler context. + * \param data anchor name chunk. + * \param len anchor name chunk length (in bytes). + */ + void (*append_name)(const br_ssl_client_certificate_class **pctx, + const unsigned char *data, size_t len); + + /** + * \brief End current trust anchor name. + * + * This function is called when all the encoded anchor name data + * has been provided. + * + * \param pctx certificate handler context. + */ + void (*end_name)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief End list of trust anchor names. + * + * This function is called when all the anchor names in the + * CertificateRequest message have been obtained. + * + * \param pctx certificate handler context. + */ + void (*end_name_list)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief Select client certificate and algorithms. + * + * This callback function shall fill the provided `choices` + * structure with the selected algorithms and certificate chain. + * The `hash_id`, `chain` and `chain_len` fields must be set. If + * the client cannot or does not wish to send a certificate, + * then it shall set `chain` to `NULL` and `chain_len` to 0. + * + * The `auth_types` parameter describes the authentication types, + * signature algorithms and hash functions that are supported by + * both the client context and the server, and compatible with + * the current protocol version. This is a bit field with the + * following contents: + * + * - If RSA signatures with hash function x are supported, then + * bit x is set. + * + * - If ECDSA signatures with hash function x are supported, + * then bit 8+x is set. + * + * - If static ECDH is supported, with a RSA-signed certificate, + * then bit 16 is set. + * + * - If static ECDH is supported, with an ECDSA-signed certificate, + * then bit 17 is set. + * + * Notes: + * + * - When using TLS 1.0 or 1.1, the hash function for RSA + * signatures is always the special MD5+SHA-1 (id 0), and the + * hash function for ECDSA signatures is always SHA-1 (id 2). + * + * - When using TLS 1.2, the list of hash functions is trimmed + * down to include only hash functions that the client context + * can support. The actual server list can be obtained with + * `br_ssl_client_get_server_hashes()`; that list may be used + * to select the certificate chain to send to the server. + * + * \param pctx certificate handler context. + * \param cc SSL client context. + * \param auth_types supported authentication types and algorithms. + * \param choices destination structure for the policy choices. + */ + void (*choose)(const br_ssl_client_certificate_class **pctx, + const br_ssl_client_context *cc, uint32_t auth_types, + br_ssl_client_certificate *choices); + + /** + * \brief Perform key exchange (client part). + * + * This callback is invoked in case of a full static ECDH key + * exchange: + * + * - the cipher suite uses `ECDH_RSA` or `ECDH_ECDSA`; + * + * - the server requests a client certificate; + * + * - the client has, and sends, a client certificate that + * uses an EC key in the same curve as the server's key, + * and chooses static ECDH (the `hash_id` field in the choice + * structure was set to -1). + * + * In that situation, this callback is invoked to compute the + * client-side ECDH: the provided `data` (of length `*len` bytes) + * is the server's public key point (as decoded from its + * certificate), and the client shall multiply that point with + * its own private key, and write back the X coordinate of the + * resulting point in the same buffer, starting at offset 0. + * The `*len` value shall be modified to designate the actual + * length of the X coordinate. + * + * The callback must uphold the following: + * + * - If the input array does not have the proper length for + * an encoded curve point, then an error (0) shall be reported. + * + * - If the input array has the proper length, then processing + * MUST be constant-time, even if the data is not a valid + * encoded point. + * + * - This callback MUST check that the input point is valid. + * + * Returned value is 1 on success, 0 on error. + * + * \param pctx certificate handler context. + * \param data server public key point. + * \param len public key point length / X coordinate length. + * \return 1 on success, 0 on error. + */ + uint32_t (*do_keyx)(const br_ssl_client_certificate_class **pctx, + unsigned char *data, size_t *len); + + /** + * \brief Perform a signature (client authentication). + * + * This callback is invoked when a client certificate was sent, + * and static ECDH is not used. It shall compute a signature, + * using the client's private key, over the provided hash value + * (which is the hash of all previous handshake messages). + * + * On input, the hash value to sign is in `data`, of size + * `hv_len`; the involved hash function is identified by + * `hash_id`. The signature shall be computed and written + * back into `data`; the total size of that buffer is `len` + * bytes. + * + * This callback shall verify that the signature length does not + * exceed `len` bytes, and abstain from writing the signature if + * it does not fit. + * + * For RSA signatures, the `hash_id` may be 0, in which case + * this is the special header-less signature specified in TLS 1.0 + * and 1.1, with a 36-byte hash value. Otherwise, normal PKCS#1 + * v1.5 signatures shall be computed. + * + * For ECDSA signatures, the signature value shall use the ASN.1 + * based encoding. + * + * Returned value is the signature length (in bytes), or 0 on error. + * + * \param pctx certificate handler context. + * \param hash_id hash function identifier. + * \param hv_len hash value length (in bytes). + * \param data input/output buffer (hash value, then signature). + * \param len total buffer length (in bytes). + * \return signature length (in bytes) on success, or 0 on error. + */ + size_t (*do_sign)(const br_ssl_client_certificate_class **pctx, + int hash_id, size_t hv_len, unsigned char *data, size_t len); +}; + +/** + * \brief A single-chain RSA client certificate handler. + * + * This handler uses a single certificate chain, with a RSA + * signature. The list of trust anchor DN is ignored. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_client_certificate_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_rsa_private_key *sk; + br_rsa_pkcs1_sign irsasign; +#endif +} br_ssl_client_certificate_rsa_context; + +/** + * \brief A single-chain EC client certificate handler. + * + * This handler uses a single certificate chain, with a RSA + * signature. The list of trust anchor DN is ignored. + * + * This handler may support both static ECDH, and ECDSA signatures + * (either usage may be selectively disabled). + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_client_certificate_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_ec_private_key *sk; + unsigned allowed_usages; + unsigned issuer_key_type; + const br_multihash_context *mhash; + const br_ec_impl *iec; + br_ecdsa_sign iecdsa; +#endif +} br_ssl_client_certificate_ec_context; + +/** + * \brief Context structure for a SSL client. + * + * The first field (called `eng`) is the SSL engine; all functions that + * work on a `br_ssl_engine_context` structure shall take as parameter + * a pointer to that field. The other structure fields are opaque and + * must not be accessed directly. + */ +struct br_ssl_client_context_ { + /** + * \brief The encapsulated engine context. + */ + br_ssl_engine_context eng; + +#ifndef BR_DOXYGEN_IGNORE + /* + * Minimum ClientHello length; padding with an extension (RFC + * 7685) is added if necessary to match at least that length. + * Such padding is nominally unnecessary, but it has been used + * to work around some server implementation bugs. + */ + uint16_t min_clienthello_len; + + /* + * Bit field for algoithms (hash + signature) supported by the + * server when requesting a client certificate. + */ + uint32_t hashes; + + /* + * Server's public key curve. + */ + int server_curve; + + /* + * Context for certificate handler. + */ + const br_ssl_client_certificate_class **client_auth_vtable; + + /* + * Client authentication type. + */ + unsigned char auth_type; + + /* + * Hash function to use for the client signature. This is 0xFF + * if static ECDH is used. + */ + unsigned char hash_id; + + /* + * For the core certificate handlers, thus avoiding (in most + * cases) the need for an externally provided policy context. + */ + union { + const br_ssl_client_certificate_class *vtable; + br_ssl_client_certificate_rsa_context single_rsa; + br_ssl_client_certificate_ec_context single_ec; + } client_auth; + + /* + * Implementations. + */ + br_rsa_public irsapub; +#endif +}; + +/** + * \brief Get the hash functions and signature algorithms supported by + * the server. + * + * This value is a bit field: + * + * - If RSA (PKCS#1 v1.5) is supported with hash function of ID `x`, + * then bit `x` is set (hash function ID is 0 for the special MD5+SHA-1, + * or 2 to 6 for the SHA family). + * + * - If ECDSA is supported with hash function of ID `x`, then bit `8+x` + * is set. + * + * - Newer algorithms are symbolic 16-bit identifiers that do not + * represent signature algorithm and hash function separately. If + * the TLS-level identifier is `0x0800+x` for a `x` in the 0..15 + * range, then bit `16+x` is set. + * + * "New algorithms" are currently defined only in draft documents, so + * this support is subject to possible change. Right now (early 2017), + * this maps ed25519 (EdDSA on Curve25519) to bit 23, and ed448 (EdDSA + * on Curve448) to bit 24. If the identifiers on the wire change in + * future document, then the decoding mechanism in BearSSL will be + * amended to keep mapping ed25519 and ed448 on bits 23 and 24, + * respectively. Mapping of other new algorithms (e.g. RSA/PSS) is not + * guaranteed yet. + * + * \param cc client context. + * \return the server-supported hash functions and signature algorithms. + */ +static inline uint32_t +br_ssl_client_get_server_hashes(const br_ssl_client_context *cc) +{ + return cc->hashes; +} + +/** + * \brief Get the server key curve. + * + * This function returns the ID for the curve used by the server's public + * key. This is set when the server's certificate chain is processed; + * this value is 0 if the server's key is not an EC key. + * + * \return the server's public key curve ID, or 0. + */ +static inline int +br_ssl_client_get_server_curve(const br_ssl_client_context *cc) +{ + return cc->server_curve; +} + +/* + * Each br_ssl_client_init_xxx() function sets the list of supported + * cipher suites and used implementations, as specified by the profile + * name 'xxx'. Defined profile names are: + * + * full all supported versions and suites; constant-time implementations + * TODO: add other profiles + */ + +/** + * \brief SSL client profile: full. + * + * This function initialises the provided SSL client context with + * all supported algorithms and cipher suites. It also initialises + * a companion X.509 validation engine with all supported algorithms, + * and the provided trust anchors; the X.509 engine will be used by + * the client context to validate the server's certificate. + * + * \param cc client context to initialise. + * \param xc X.509 validation context to initialise. + * \param trust_anchors trust anchors to use. + * \param trust_anchors_num number of trust anchors. + */ +void br_ssl_client_init_full(br_ssl_client_context *cc, + br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + +/** + * \brief Clear the complete contents of a SSL client context. + * + * Everything is cleared, including the reference to the configured buffer, + * implementations, cipher suites and state. This is a preparatory step + * to assembling a custom profile. + * + * \param cc client context to clear. + */ +void br_ssl_client_zero(br_ssl_client_context *cc); + +/** + * \brief Set an externally provided client certificate handler context. + * + * The handler's methods are invoked when the server requests a client + * certificate. + * + * \param cc client context. + * \param pctx certificate handler context (pointer to its vtable field). + */ +static inline void +br_ssl_client_set_client_certificate(br_ssl_client_context *cc, + const br_ssl_client_certificate_class **pctx) +{ + cc->client_auth_vtable = pctx; +} + +/** + * \brief Set the RSA public-key operations implementation. + * + * This will be used to encrypt the pre-master secret with the server's + * RSA public key (RSA-encryption cipher suites only). + * + * \param cc client context. + * \param irsapub RSA public-key encryption implementation. + */ +static inline void +br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub) +{ + cc->irsapub = irsapub; +} + +/** + * \brief Set the "default" RSA implementation for public-key operations. + * + * This sets the RSA implementation in the client context (for encrypting + * the pre-master secret, in `TLS_RSA_*` cipher suites) to the fastest + * available on the current platform. + * + * \param cc client context. + */ +void br_ssl_client_set_default_rsapub(br_ssl_client_context *cc); + +/** + * \brief Set the minimum ClientHello length (RFC 7685 padding). + * + * If this value is set and the ClientHello would be shorter, then + * the Pad ClientHello extension will be added with enough padding bytes + * to reach the target size. Because of the extension header, the resulting + * size will sometimes be slightly more than `len` bytes if the target + * size cannot be exactly met. + * + * The target length relates to the _contents_ of the ClientHello, not + * counting its 4-byte header. For instance, if `len` is set to 512, + * then the padding will bring the ClientHello size to 516 bytes with its + * header, and 521 bytes when counting the 5-byte record header. + * + * \param cc client context. + * \param len minimum ClientHello length (in bytes). + */ +static inline void +br_ssl_client_set_min_clienthello_len(br_ssl_client_context *cc, uint16_t len) +{ + cc->min_clienthello_len = len; +} + +/** + * \brief Prepare or reset a client context for a new connection. + * + * The `server_name` parameter is used to fill the SNI extension; the + * X.509 "minimal" engine will also match that name against the server + * names included in the server's certificate. If the parameter is + * `NULL` then no SNI extension will be sent, and the X.509 "minimal" + * engine (if used for server certificate validation) will not check + * presence of any specific name in the received certificate. + * + * Therefore, setting the `server_name` to `NULL` shall be reserved + * to cases where alternate or additional methods are used to ascertain + * that the right server public key is used (e.g. a "known key" model). + * + * If `resume_session` is non-zero and the context was previously used + * then the session parameters may be reused (depending on whether the + * server previously sent a non-empty session ID, and accepts the session + * resumption). The session parameters for session resumption can also + * be set explicitly with `br_ssl_engine_set_session_parameters()`. + * + * On failure, the context is marked as failed, and this function + * returns 0. A possible failure condition is when no initial entropy + * was injected, and none could be obtained from the OS (either OS + * randomness gathering is not supported, or it failed). + * + * \param cc client context. + * \param server_name target server name, or `NULL`. + * \param resume_session non-zero to try session resumption. + * \return 0 on failure, 1 on success. + */ +int br_ssl_client_reset(br_ssl_client_context *cc, + const char *server_name, int resume_session); + +/** + * \brief Forget any session in the context. + * + * This means that the next handshake that uses this context will + * necessarily be a full handshake (this applies both to new connections + * and to renegotiations). + * + * \param cc client context. + */ +static inline void +br_ssl_client_forget_session(br_ssl_client_context *cc) +{ + cc->eng.session.session_id_len = 0; +} + +/** + * \brief Set client certificate chain and key (single RSA case). + * + * This function sets a client certificate chain, that the client will + * send to the server whenever a client certificate is requested. This + * certificate uses an RSA public key; the corresponding private key is + * invoked for authentication. Trust anchor names sent by the server are + * ignored. + * + * The provided chain and private key are linked in the client context; + * they must remain valid as long as they may be used, i.e. normally + * for the duration of the connection, since they might be invoked + * again upon renegotiations. + * + * \param cc SSL client context. + * \param chain client certificate chain (SSL order: EE comes first). + * \param chain_len client chain length (number of certificates). + * \param sk client private key. + * \param irsasign RSA signature implementation (PKCS#1 v1.5). + */ +void br_ssl_client_set_single_rsa(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign); + +/* + * \brief Set the client certificate chain and key (single EC case). + * + * This function sets a client certificate chain, that the client will + * send to the server whenever a client certificate is requested. This + * certificate uses an EC public key; the corresponding private key is + * invoked for authentication. Trust anchor names sent by the server are + * ignored. + * + * The provided chain and private key are linked in the client context; + * they must remain valid as long as they may be used, i.e. normally + * for the duration of the connection, since they might be invoked + * again upon renegotiations. + * + * The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`. The `BR_KEYTYPE_KEYX` + * value allows full static ECDH, while the `BR_KEYTYPE_SIGN` value + * allows ECDSA signatures. If ECDSA signatures are used, then an ECDSA + * signature implementation must be provided; otherwise, the `iecdsa` + * parameter may be 0. + * + * The `cert_issuer_key_type` value is either `BR_KEYTYPE_RSA` or + * `BR_KEYTYPE_EC`; it is the type of the public key used the the CA + * that issued (signed) the client certificate. That value is used with + * full static ECDH: support of the certificate by the server depends + * on how the certificate was signed. (Note: when using TLS 1.2, this + * parameter is ignored; but its value matters for TLS 1.0 and 1.1.) + * + * \param cc server context. + * \param chain server certificate chain to send. + * \param chain_len chain length (number of certificates). + * \param sk server private key (EC). + * \param allowed_usages allowed private key usages. + * \param cert_issuer_key_type issuing CA's key type. + * \param iec EC core implementation. + * \param iecdsa ECDSA signature implementation ("asn1" format). + */ +void br_ssl_client_set_single_ec(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk, unsigned allowed_usages, + unsigned cert_issuer_key_type, + const br_ec_impl *iec, br_ecdsa_sign iecdsa); + +/** + * \brief Type for a "translated cipher suite", as an array of two + * 16-bit integers. + * + * The first element is the cipher suite identifier (as used on the wire). + * The second element is the concatenation of four 4-bit elements which + * characterise the cipher suite contents. In most to least significant + * order, these 4-bit elements are: + * + * - Bits 12 to 15: key exchange + server key type + * + * | val | symbolic constant | suite type | details | + * | :-- | :----------------------- | :---------- | :----------------------------------------------- | + * | 0 | `BR_SSLKEYX_RSA` | RSA | RSA key exchange, key is RSA (encryption) | + * | 1 | `BR_SSLKEYX_ECDHE_RSA` | ECDHE_RSA | ECDHE key exchange, key is RSA (signature) | + * | 2 | `BR_SSLKEYX_ECDHE_ECDSA` | ECDHE_ECDSA | ECDHE key exchange, key is EC (signature) | + * | 3 | `BR_SSLKEYX_ECDH_RSA` | ECDH_RSA | Key is EC (key exchange), cert signed with RSA | + * | 4 | `BR_SSLKEYX_ECDH_ECDSA` | ECDH_ECDSA | Key is EC (key exchange), cert signed with ECDSA | + * + * - Bits 8 to 11: symmetric encryption algorithm + * + * | val | symbolic constant | symmetric encryption | key strength (bits) | + * | :-- | :--------------------- | :------------------- | :------------------ | + * | 0 | `BR_SSLENC_3DES_CBC` | 3DES/CBC | 168 | + * | 1 | `BR_SSLENC_AES128_CBC` | AES-128/CBC | 128 | + * | 2 | `BR_SSLENC_AES256_CBC` | AES-256/CBC | 256 | + * | 3 | `BR_SSLENC_AES128_GCM` | AES-128/GCM | 128 | + * | 4 | `BR_SSLENC_AES256_GCM` | AES-256/GCM | 256 | + * | 5 | `BR_SSLENC_CHACHA20` | ChaCha20/Poly1305 | 256 | + * + * - Bits 4 to 7: MAC algorithm + * + * | val | symbolic constant | MAC type | details | + * | :-- | :----------------- | :----------- | :------------------------------------ | + * | 0 | `BR_SSLMAC_AEAD` | AEAD | No dedicated MAC (encryption is AEAD) | + * | 2 | `BR_SSLMAC_SHA1` | HMAC/SHA-1 | Value matches `br_sha1_ID` | + * | 4 | `BR_SSLMAC_SHA256` | HMAC/SHA-256 | Value matches `br_sha256_ID` | + * | 5 | `BR_SSLMAC_SHA384` | HMAC/SHA-384 | Value matches `br_sha384_ID` | + * + * - Bits 0 to 3: hash function for PRF when used with TLS-1.2 + * + * | val | symbolic constant | hash function | details | + * | :-- | :----------------- | :------------ | :----------------------------------- | + * | 4 | `BR_SSLPRF_SHA256` | SHA-256 | Value matches `br_sha256_ID` | + * | 5 | `BR_SSLPRF_SHA384` | SHA-384 | Value matches `br_sha384_ID` | + * + * For instance, cipher suite `TLS_RSA_WITH_AES_128_GCM_SHA256` has + * standard identifier 0x009C, and is translated to 0x0304, for, in + * that order: RSA key exchange (0), AES-128/GCM (3), AEAD integrity (0), + * SHA-256 in the TLS PRF (4). + */ +typedef uint16_t br_suite_translated[2]; + +#ifndef BR_DOXYGEN_IGNORE +/* + * Constants are already documented in the br_suite_translated type. + */ + +#define BR_SSLKEYX_RSA 0 +#define BR_SSLKEYX_ECDHE_RSA 1 +#define BR_SSLKEYX_ECDHE_ECDSA 2 +#define BR_SSLKEYX_ECDH_RSA 3 +#define BR_SSLKEYX_ECDH_ECDSA 4 + +#define BR_SSLENC_3DES_CBC 0 +#define BR_SSLENC_AES128_CBC 1 +#define BR_SSLENC_AES256_CBC 2 +#define BR_SSLENC_AES128_GCM 3 +#define BR_SSLENC_AES256_GCM 4 +#define BR_SSLENC_CHACHA20 5 + +#define BR_SSLMAC_AEAD 0 +#define BR_SSLMAC_SHA1 br_sha1_ID +#define BR_SSLMAC_SHA256 br_sha256_ID +#define BR_SSLMAC_SHA384 br_sha384_ID + +#define BR_SSLPRF_SHA256 br_sha256_ID +#define BR_SSLPRF_SHA384 br_sha384_ID + +#endif + +/* + * Pre-declaration for the SSL server context. + */ +typedef struct br_ssl_server_context_ br_ssl_server_context; + +/** + * \brief Type for the server policy choices, taken after analysis of + * the client message (ClientHello). + */ +typedef struct { + /** + * \brief Cipher suite to use with that client. + */ + uint16_t cipher_suite; + + /** + * \brief Hash function or algorithm for signing the ServerKeyExchange. + * + * This parameter is ignored for `TLS_RSA_*` and `TLS_ECDH_*` + * cipher suites; it is used only for `TLS_ECDHE_*` suites, in + * which the server _signs_ the ephemeral EC Diffie-Hellman + * parameters sent to the client. + * + * This identifier must be one of the following values: + * + * - `0xFF00 + id`, where `id` is a hash function identifier + * (0 for MD5+SHA-1, or 2 to 6 for one of the SHA functions); + * + * - a full 16-bit identifier, lower than `0xFF00`. + * + * If the first option is used, then the SSL engine will + * compute the hash of the data that is to be signed, with the + * designated hash function. The `do_sign()` method will be + * invoked with that hash value provided in the the `data` + * buffer. + * + * If the second option is used, then the SSL engine will NOT + * compute a hash on the data; instead, it will provide the + * to-be-signed data itself in `data`, i.e. the concatenation of + * the client random, server random, and encoded ECDH + * parameters. Furthermore, with TLS-1.2 and later, the 16-bit + * identifier will be used "as is" in the protocol, in the + * SignatureAndHashAlgorithm; for instance, `0x0401` stands for + * RSA PKCS#1 v1.5 signature (the `01`) with SHA-256 as hash + * function (the `04`). + * + * Take care that with TLS 1.0 and 1.1, the hash function is + * constrainted by the protocol: RSA signature must use + * MD5+SHA-1 (so use `0xFF00`), while ECDSA must use SHA-1 + * (`0xFF02`). Since TLS 1.0 and 1.1 don't include a + * SignatureAndHashAlgorithm field in their ServerKeyExchange + * messages, any value below `0xFF00` will be usable to send the + * raw ServerKeyExchange data to the `do_sign()` callback, but + * that callback must still follow the protocol requirements + * when generating the signature. + */ + unsigned algo_id; + + /** + * \brief Certificate chain to send to the client. + * + * This is an array of `br_x509_certificate` objects, each + * normally containing a DER-encoded certificate. The server + * code does not try to decode these elements. + */ + const br_x509_certificate *chain; + + /** + * \brief Certificate chain length (number of certificates). + */ + size_t chain_len; + +} br_ssl_server_choices; + +/** + * \brief Class type for a policy handler (server side). + * + * A policy handler selects the policy parameters for a connection + * (cipher suite and other algorithms, and certificate chain to send to + * the client); it also performs the server-side computations involving + * its permanent private key. + * + * The SSL server engine will invoke first `choose()`, once the + * ClientHello message has been received, then either `do_keyx()` + * `do_sign()`, depending on the cipher suite. + */ +typedef struct br_ssl_server_policy_class_ br_ssl_server_policy_class; +struct br_ssl_server_policy_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Select algorithms and certificates for this connection. + * + * This callback function shall fill the provided `choices` + * structure with the policy choices for this connection. This + * entails selecting the cipher suite, hash function for signing + * the ServerKeyExchange (applicable only to ECDHE cipher suites), + * and certificate chain to send. + * + * The callback receives a pointer to the server context that + * contains the relevant data. In particular, the functions + * `br_ssl_server_get_client_suites()`, + * `br_ssl_server_get_client_hashes()` and + * `br_ssl_server_get_client_curves()` can be used to obtain + * the cipher suites, hash functions and elliptic curves + * supported by both the client and server, respectively. The + * `br_ssl_engine_get_version()` and `br_ssl_engine_get_server_name()` + * functions yield the protocol version and requested server name + * (SNI), respectively. + * + * This function may modify its context structure (`pctx`) in + * arbitrary ways to keep track of its own choices. + * + * This function shall return 1 if appropriate policy choices + * could be made, or 0 if this connection cannot be pursued. + * + * \param pctx policy context. + * \param cc SSL server context. + * \param choices destination structure for the policy choices. + * \return 1 on success, 0 on error. + */ + int (*choose)(const br_ssl_server_policy_class **pctx, + const br_ssl_server_context *cc, + br_ssl_server_choices *choices); + + /** + * \brief Perform key exchange (server part). + * + * This callback is invoked to perform the server-side cryptographic + * operation for a key exchange that is not ECDHE. This callback + * uses the private key. + * + * **For RSA key exchange**, the provided `data` (of length `*len` + * bytes) shall be decrypted with the server's private key, and + * the 48-byte premaster secret copied back to the first 48 bytes + * of `data`. + * + * - The caller makes sure that `*len` is at least 59 bytes. + * + * - This callback MUST check that the provided length matches + * that of the key modulus; it shall report an error otherwise. + * + * - If the length matches that of the RSA key modulus, then + * processing MUST be constant-time, even if decryption fails, + * or the padding is incorrect, or the plaintext message length + * is not exactly 48 bytes. + * + * - This callback needs not check the two first bytes of the + * obtained pre-master secret (the caller will do that). + * + * - If an error is reported (0), then what the callback put + * in the first 48 bytes of `data` is unimportant (the caller + * will use random bytes instead). + * + * **For ECDH key exchange**, the provided `data` (of length `*len` + * bytes) is the elliptic curve point from the client. The + * callback shall multiply it with its private key, and store + * the resulting X coordinate in `data`, starting at offset 0, + * and set `*len` to the length of the X coordinate. + * + * - If the input array does not have the proper length for + * an encoded curve point, then an error (0) shall be reported. + * + * - If the input array has the proper length, then processing + * MUST be constant-time, even if the data is not a valid + * encoded point. + * + * - This callback MUST check that the input point is valid. + * + * Returned value is 1 on success, 0 on error. + * + * \param pctx policy context. + * \param data key exchange data from the client. + * \param len key exchange data length (in bytes). + * \return 1 on success, 0 on error. + */ + uint32_t (*do_keyx)(const br_ssl_server_policy_class **pctx, + unsigned char *data, size_t *len); + + /** + * \brief Perform a signature (for a ServerKeyExchange message). + * + * This callback function is invoked for ECDHE cipher suites. On + * input, the hash value or message to sign is in `data`, of + * size `hv_len`; the involved hash function or algorithm is + * identified by `algo_id`. The signature shall be computed and + * written back into `data`; the total size of that buffer is + * `len` bytes. + * + * This callback shall verify that the signature length does not + * exceed `len` bytes, and abstain from writing the signature if + * it does not fit. + * + * The `algo_id` value matches that which was written in the + * `choices` structures by the `choose()` callback. This will be + * one of the following: + * + * - `0xFF00 + id` for a hash function identifier `id`. In + * that case, the `data` buffer contains a hash value + * already computed over the data that is to be signed, + * of length `hv_len`. The `id` may be 0 to designate the + * special MD5+SHA-1 concatenation (old-style RSA signing). + * + * - Another value, lower than `0xFF00`. The `data` buffer + * then contains the raw, non-hashed data to be signed + * (concatenation of the client and server randoms and + * ECDH parameters). The callback is responsible to apply + * any relevant hashing as part of the signing process. + * + * Returned value is the signature length (in bytes), or 0 on error. + * + * \param pctx policy context. + * \param algo_id hash function / algorithm identifier. + * \param data input/output buffer (message/hash, then signature). + * \param hv_len hash value or message length (in bytes). + * \param len total buffer length (in bytes). + * \return signature length (in bytes) on success, or 0 on error. + */ + size_t (*do_sign)(const br_ssl_server_policy_class **pctx, + unsigned algo_id, + unsigned char *data, size_t hv_len, size_t len); +}; + +/** + * \brief A single-chain RSA policy handler. + * + * This policy context uses a single certificate chain, and a RSA + * private key. The context can be restricted to only signatures or + * only key exchange. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_server_policy_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_rsa_private_key *sk; + unsigned allowed_usages; + br_rsa_private irsacore; + br_rsa_pkcs1_sign irsasign; +#endif +} br_ssl_server_policy_rsa_context; + +/** + * \brief A single-chain EC policy handler. + * + * This policy context uses a single certificate chain, and an EC + * private key. The context can be restricted to only signatures or + * only key exchange. + * + * Due to how TLS is defined, this context must be made aware whether + * the server certificate was itself signed with RSA or ECDSA. The code + * does not try to decode the certificate to obtain that information. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_server_policy_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_ec_private_key *sk; + unsigned allowed_usages; + unsigned cert_issuer_key_type; + const br_multihash_context *mhash; + const br_ec_impl *iec; + br_ecdsa_sign iecdsa; +#endif +} br_ssl_server_policy_ec_context; + +/** + * \brief Class type for a session parameter cache. + * + * Session parameters are saved in the cache with `save()`, and + * retrieved with `load()`. The cache implementation can apply any + * storage and eviction strategy that it sees fit. The SSL server + * context that performs the request is provided, so that its + * functionalities may be used by the implementation (e.g. hash + * functions or random number generation). + */ +typedef struct br_ssl_session_cache_class_ br_ssl_session_cache_class; +struct br_ssl_session_cache_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Record a session. + * + * This callback should record the provided session parameters. + * The `params` structure is transient, so its contents shall + * be copied into the cache. The session ID has been randomly + * generated and always has length exactly 32 bytes. + * + * \param ctx session cache context. + * \param server_ctx SSL server context. + * \param params session parameters to save. + */ + void (*save)(const br_ssl_session_cache_class **ctx, + br_ssl_server_context *server_ctx, + const br_ssl_session_parameters *params); + + /** + * \brief Lookup a session in the cache. + * + * The session ID to lookup is in `params` and always has length + * exactly 32 bytes. If the session parameters are found in the + * cache, then the parameters shall be copied into the `params` + * structure. Returned value is 1 on successful lookup, 0 + * otherwise. + * + * \param ctx session cache context. + * \param server_ctx SSL server context. + * \param params destination for session parameters. + * \return 1 if found, 0 otherwise. + */ + int (*load)(const br_ssl_session_cache_class **ctx, + br_ssl_server_context *server_ctx, + br_ssl_session_parameters *params); +}; + +/** + * \brief Context for a basic cache system. + * + * The system stores session parameters in a buffer provided at + * initialisation time. Each entry uses exactly 100 bytes, and + * buffer sizes up to 4294967295 bytes are supported. + * + * Entries are evicted with a LRU (Least Recently Used) policy. A + * search tree is maintained to keep lookups fast even with large + * caches. + * + * Apart from the first field (vtable pointer), the structure + * contents are opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_session_cache_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char *store; + size_t store_len, store_ptr; + unsigned char index_key[32]; + const br_hash_class *hash; + int init_done; + uint32_t head, tail, root; +#endif +} br_ssl_session_cache_lru; + +/** + * \brief Initialise a LRU session cache with the provided storage space. + * + * The provided storage space must remain valid as long as the cache + * is used. Arbitrary lengths are supported, up to 4294967295 bytes; + * each entry uses up exactly 100 bytes. + * + * \param cc session cache context. + * \param store storage space for cached entries. + * \param store_len storage space length (in bytes). + */ +void br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc, + unsigned char *store, size_t store_len); + +/** + * \brief Forget an entry in an LRU session cache. + * + * The session cache context must have been initialised. The entry + * with the provided session ID (of exactly 32 bytes) is looked for + * in the cache; if located, it is disabled. + * + * \param cc session cache context. + * \param id session ID to forget. + */ +void br_ssl_session_cache_lru_forget( + br_ssl_session_cache_lru *cc, const unsigned char *id); + +/** + * \brief Context structure for a SSL server. + * + * The first field (called `eng`) is the SSL engine; all functions that + * work on a `br_ssl_engine_context` structure shall take as parameter + * a pointer to that field. The other structure fields are opaque and + * must not be accessed directly. + */ +struct br_ssl_server_context_ { + /** + * \brief The encapsulated engine context. + */ + br_ssl_engine_context eng; + +#ifndef BR_DOXYGEN_IGNORE + /* + * Maximum version from the client. + */ + uint16_t client_max_version; + + /* + * Session cache. + */ + const br_ssl_session_cache_class **cache_vtable; + + /* + * Translated cipher suites supported by the client. The list + * is trimmed to include only the cipher suites that the + * server also supports; they are in the same order as in the + * client message. + */ + br_suite_translated client_suites[BR_MAX_CIPHER_SUITES]; + unsigned char client_suites_num; + + /* + * Hash functions supported by the client, with ECDSA and RSA + * (bit mask). For hash function with id 'x', set bit index is + * x for RSA, x+8 for ECDSA. For newer algorithms, with ID + * 0x08**, bit 16+k is set for algorithm 0x0800+k. + */ + uint32_t hashes; + + /* + * Curves supported by the client (bit mask, for named curves). + */ + uint32_t curves; + + /* + * Context for chain handler. + */ + const br_ssl_server_policy_class **policy_vtable; + uint16_t sign_hash_id; + + /* + * For the core handlers, thus avoiding (in most cases) the + * need for an externally provided policy context. + */ + union { + const br_ssl_server_policy_class *vtable; + br_ssl_server_policy_rsa_context single_rsa; + br_ssl_server_policy_ec_context single_ec; + } chain_handler; + + /* + * Buffer for the ECDHE private key. + */ + unsigned char ecdhe_key[70]; + size_t ecdhe_key_len; + + /* + * Trust anchor names for client authentication. "ta_names" and + * "tas" cannot be both non-NULL. + */ + const br_x500_name *ta_names; + const br_x509_trust_anchor *tas; + size_t num_tas; + size_t cur_dn_index; + const unsigned char *cur_dn; + size_t cur_dn_len; + + /* + * Buffer for the hash value computed over all handshake messages + * prior to CertificateVerify, and identifier for the hash function. + */ + unsigned char hash_CV[64]; + size_t hash_CV_len; + int hash_CV_id; + + /* + * Server-specific implementations. + * (none for now) + */ +#endif +}; + +/* + * Each br_ssl_server_init_xxx() function sets the list of supported + * cipher suites and used implementations, as specified by the profile + * name 'xxx'. Defined profile names are: + * + * full_rsa all supported algorithm, server key type is RSA + * full_ec all supported algorithm, server key type is EC + * TODO: add other profiles + * + * Naming scheme for "minimal" profiles: min123 + * + * -- character 1: key exchange + * r = RSA + * e = ECDHE_RSA + * f = ECDHE_ECDSA + * u = ECDH_RSA + * v = ECDH_ECDSA + * -- character 2: version / PRF + * 0 = TLS 1.0 / 1.1 with MD5+SHA-1 + * 2 = TLS 1.2 with SHA-256 + * 3 = TLS 1.2 with SHA-384 + * -- character 3: encryption + * a = AES/CBC + * d = 3DES/CBC + * g = AES/GCM + * c = ChaCha20+Poly1305 + */ + +/** + * \brief SSL server profile: full_rsa. + * + * This function initialises the provided SSL server context with + * all supported algorithms and cipher suites that rely on a RSA + * key pair. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_full_rsa(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: full_ec. + * + * This function initialises the provided SSL server context with + * all supported algorithms and cipher suites that rely on an EC + * key pair. + * + * The key type of the CA that issued the server's certificate must + * be provided, since it matters for ECDH cipher suites (ECDH_RSA + * suites require a RSA-powered CA). The key type is either + * `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len chain length (number of certificates). + * \param cert_issuer_key_type certificate issuer's key type. + * \param sk EC private key. + */ +void br_ssl_server_init_full_ec(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + unsigned cert_issuer_key_type, const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minr2g. + * + * This profile uses only TLS_RSA_WITH_AES_128_GCM_SHA256. Server key is + * RSA, and RSA key exchange is used (not forward secure, but uses little + * CPU in the client). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_minr2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: mine2g. + * + * This profile uses only TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. Server key + * is RSA, and ECDHE key exchange is used. This suite provides forward + * security, with a higher CPU expense on the client, and a somewhat + * larger code footprint (compared to "minr2g"). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_mine2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: minf2g. + * + * This profile uses only TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDHE key exchange is used. This suite provides + * forward security, with a higher CPU expense on the client and server + * (by a factor of about 3 to 4), and a somewhat larger code footprint + * (compared to "minu2g" and "minv2g"). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minf2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minu2g. + * + * This profile uses only TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDH key exchange is used; the issuing CA used + * a RSA key. + * + * The "minu2g" and "minv2g" profiles do not provide forward secrecy, + * but are the lightest on the server (for CPU usage), and are rather + * inexpensive on the client as well. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minu2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minv2g. + * + * This profile uses only TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDH key exchange is used; the issuing CA used + * an EC key. + * + * The "minu2g" and "minv2g" profiles do not provide forward secrecy, + * but are the lightest on the server (for CPU usage), and are rather + * inexpensive on the client as well. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minv2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief SSL server profile: mine2c. + * + * This profile uses only TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256. + * Server key is RSA, and ECDHE key exchange is used. This suite + * provides forward security. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_mine2c(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: minf2c. + * + * This profile uses only TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. + * Server key is EC, and ECDHE key exchange is used. This suite provides + * forward security. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minf2c(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief Get the supported client suites. + * + * This function shall be called only after the ClientHello has been + * processed, typically from the policy engine. The returned array + * contains the cipher suites that are supported by both the client + * and the server; these suites are in client preference order, unless + * the `BR_OPT_ENFORCE_SERVER_PREFERENCES` flag was set, in which case + * they are in server preference order. + * + * The suites are _translated_, which means that each suite is given + * as two 16-bit integers: the standard suite identifier, and its + * translated version, broken down into its individual components, + * as explained with the `br_suite_translated` type. + * + * The returned array is allocated in the context and will be rewritten + * by each handshake. + * + * \param cc server context. + * \param num receives the array size (number of suites). + * \return the translated common cipher suites, in preference order. + */ +static inline const br_suite_translated * +br_ssl_server_get_client_suites(const br_ssl_server_context *cc, size_t *num) +{ + *num = cc->client_suites_num; + return cc->client_suites; +} + +/** + * \brief Get the hash functions and signature algorithms supported by + * the client. + * + * This value is a bit field: + * + * - If RSA (PKCS#1 v1.5) is supported with hash function of ID `x`, + * then bit `x` is set (hash function ID is 0 for the special MD5+SHA-1, + * or 2 to 6 for the SHA family). + * + * - If ECDSA is supported with hash function of ID `x`, then bit `8+x` + * is set. + * + * - Newer algorithms are symbolic 16-bit identifiers that do not + * represent signature algorithm and hash function separately. If + * the TLS-level identifier is `0x0800+x` for a `x` in the 0..15 + * range, then bit `16+x` is set. + * + * "New algorithms" are currently defined only in draft documents, so + * this support is subject to possible change. Right now (early 2017), + * this maps ed25519 (EdDSA on Curve25519) to bit 23, and ed448 (EdDSA + * on Curve448) to bit 24. If the identifiers on the wire change in + * future document, then the decoding mechanism in BearSSL will be + * amended to keep mapping ed25519 and ed448 on bits 23 and 24, + * respectively. Mapping of other new algorithms (e.g. RSA/PSS) is not + * guaranteed yet. + * + * \param cc server context. + * \return the client-supported hash functions and signature algorithms. + */ +static inline uint32_t +br_ssl_server_get_client_hashes(const br_ssl_server_context *cc) +{ + return cc->hashes; +} + +/** + * \brief Get the elliptic curves supported by the client. + * + * This is a bit field (bit x is set if curve of ID x is supported). + * + * \param cc server context. + * \return the client-supported elliptic curves. + */ +static inline uint32_t +br_ssl_server_get_client_curves(const br_ssl_server_context *cc) +{ + return cc->curves; +} + +/** + * \brief Clear the complete contents of a SSL server context. + * + * Everything is cleared, including the reference to the configured buffer, + * implementations, cipher suites and state. This is a preparatory step + * to assembling a custom profile. + * + * \param cc server context to clear. + */ +void br_ssl_server_zero(br_ssl_server_context *cc); + +/** + * \brief Set an externally provided policy context. + * + * The policy context's methods are invoked to decide the cipher suite + * and certificate chain, and to perform operations involving the server's + * private key. + * + * \param cc server context. + * \param pctx policy context (pointer to its vtable field). + */ +static inline void +br_ssl_server_set_policy(br_ssl_server_context *cc, + const br_ssl_server_policy_class **pctx) +{ + cc->policy_vtable = pctx; +} + +/** + * \brief Set the server certificate chain and key (single RSA case). + * + * This function uses a policy context included in the server context. + * It configures use of a single server certificate chain with a RSA + * private key. The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables + * the corresponding cipher suites (i.e. `TLS_RSA_*` use the RSA key for + * key exchange, while `TLS_ECDHE_RSA_*` use the RSA key for signatures). + * + * \param cc server context. + * \param chain server certificate chain to send to the client. + * \param chain_len chain length (number of certificates). + * \param sk server private key (RSA). + * \param allowed_usages allowed private key usages. + * \param irsacore RSA core implementation. + * \param irsasign RSA signature implementation (PKCS#1 v1.5). + */ +void br_ssl_server_set_single_rsa(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk, unsigned allowed_usages, + br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign); + +/** + * \brief Set the server certificate chain and key (single EC case). + * + * This function uses a policy context included in the server context. + * It configures use of a single server certificate chain with an EC + * private key. The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables + * the corresponding cipher suites (i.e. `TLS_ECDH_*` use the EC key for + * key exchange, while `TLS_ECDHE_ECDSA_*` use the EC key for signatures). + * + * In order to support `TLS_ECDH_*` cipher suites (non-ephemeral ECDH), + * the algorithm type of the key used by the issuing CA to sign the + * server's certificate must be provided, as `cert_issuer_key_type` + * parameter (this value is either `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`). + * + * \param cc server context. + * \param chain server certificate chain to send. + * \param chain_len chain length (number of certificates). + * \param sk server private key (EC). + * \param allowed_usages allowed private key usages. + * \param cert_issuer_key_type issuing CA's key type. + * \param iec EC core implementation. + * \param iecdsa ECDSA signature implementation ("asn1" format). + */ +void br_ssl_server_set_single_ec(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk, unsigned allowed_usages, + unsigned cert_issuer_key_type, + const br_ec_impl *iec, br_ecdsa_sign iecdsa); + +/** + * \brief Activate client certificate authentication. + * + * The trust anchor encoded X.500 names (DN) to send to the client are + * provided. A client certificate will be requested and validated through + * the X.509 validator configured in the SSL engine. If `num` is 0, then + * client certificate authentication is disabled. + * + * If the client does not send a certificate, or on validation failure, + * the handshake aborts. Unauthenticated clients can be tolerated by + * setting the `BR_OPT_TOLERATE_NO_CLIENT_AUTH` flag. + * + * The provided array is linked in, not copied, so that pointer must + * remain valid as long as anchor names may be used. + * + * \param cc server context. + * \param ta_names encoded trust anchor names. + * \param num number of encoded trust anchor names. + */ +static inline void +br_ssl_server_set_trust_anchor_names(br_ssl_server_context *cc, + const br_x500_name *ta_names, size_t num) +{ + cc->ta_names = ta_names; + cc->tas = NULL; + cc->num_tas = num; +} + +/** + * \brief Activate client certificate authentication. + * + * This is a variant for `br_ssl_server_set_trust_anchor_names()`: the + * trust anchor names are provided not as an array of stand-alone names + * (`br_x500_name` structures), but as an array of trust anchors + * (`br_x509_trust_anchor` structures). The server engine itself will + * only use the `dn` field of each trust anchor. This is meant to allow + * defining a single array of trust anchors, to be used here and in the + * X.509 validation engine itself. + * + * The provided array is linked in, not copied, so that pointer must + * remain valid as long as anchor names may be used. + * + * \param cc server context. + * \param tas trust anchors (only names are used). + * \param num number of trust anchors. + */ +static inline void +br_ssl_server_set_trust_anchor_names_alt(br_ssl_server_context *cc, + const br_x509_trust_anchor *tas, size_t num) +{ + cc->ta_names = NULL; + cc->tas = tas; + cc->num_tas = num; +} + +/** + * \brief Configure the cache for session parameters. + * + * The cache context is provided as a pointer to its first field (vtable + * pointer). + * + * \param cc server context. + * \param vtable session cache context. + */ +static inline void +br_ssl_server_set_cache(br_ssl_server_context *cc, + const br_ssl_session_cache_class **vtable) +{ + cc->cache_vtable = vtable; +} + +/** + * \brief Prepare or reset a server context for handling an incoming client. + * + * \param cc server context. + * \return 1 on success, 0 on error. + */ +int br_ssl_server_reset(br_ssl_server_context *cc); + +/* ===================================================================== */ + +/* + * Context for the simplified I/O context. The transport medium is accessed + * through the low_read() and low_write() callback functions, each with + * its own opaque context pointer. + * + * low_read() read some bytes, at most 'len' bytes, into data[]. The + * returned value is the number of read bytes, or -1 on error. + * The 'len' parameter is guaranteed never to exceed 20000, + * so the length always fits in an 'int' on all platforms. + * + * low_write() write up to 'len' bytes, to be read from data[]. The + * returned value is the number of written bytes, or -1 on + * error. The 'len' parameter is guaranteed never to exceed + * 20000, so the length always fits in an 'int' on all + * parameters. + * + * A socket closure (if the transport medium is a socket) should be reported + * as an error (-1). The callbacks shall endeavour to block until at least + * one byte can be read or written; a callback returning 0 at times is + * acceptable, but this normally leads to the callback being immediately + * called again, so the callback should at least always try to block for + * some time if no I/O can take place. + * + * The SSL engine naturally applies some buffering, so the callbacks need + * not apply buffers of their own. + */ +/** + * \brief Context structure for the simplified SSL I/O wrapper. + * + * This structure is initialised with `br_sslio_init()`. Its contents + * are opaque and shall not be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + br_ssl_engine_context *engine; + int (*low_read)(void *read_context, + unsigned char *data, size_t len); + void *read_context; + int (*low_write)(void *write_context, + const unsigned char *data, size_t len); + void *write_context; +#endif +} br_sslio_context; + +/** + * \brief Initialise a simplified I/O wrapper context. + * + * The simplified I/O wrapper offers a simpler read/write API for a SSL + * engine (client or server), using the provided callback functions for + * reading data from, or writing data to, the transport medium. + * + * The callback functions have the following semantics: + * + * - Each callback receives an opaque context value (of type `void *`) + * that the callback may use arbitrarily (or possibly ignore). + * + * - `low_read()` reads at least one byte, at most `len` bytes, from + * the transport medium. Read bytes shall be written in `data`. + * + * - `low_write()` writes at least one byte, at most `len` bytes, unto + * the transport medium. The bytes to write are read from `data`. + * + * - The `len` parameter is never zero, and is always lower than 20000. + * + * - The number of processed bytes (read or written) is returned. Since + * that number is less than 20000, it always fits on an `int`. + * + * - On error, the callbacks return -1. Reaching end-of-stream is an + * error. Errors are permanent: the SSL connection is terminated. + * + * - Callbacks SHOULD NOT return 0. This is tolerated, as long as + * callbacks endeavour to block for some non-negligible amount of + * time until at least one byte can be sent or received (if a + * callback returns 0, then the wrapper invokes it again + * immediately). + * + * - Callbacks MAY return as soon as at least one byte is processed; + * they MAY also insist on reading or writing _all_ requested bytes. + * Since SSL is a self-terminated protocol (each record has a length + * header), this does not change semantics. + * + * - Callbacks need not apply any buffering (for performance) since SSL + * itself uses buffers. + * + * \param ctx wrapper context to initialise. + * \param engine SSL engine to wrap. + * \param low_read callback for reading data from the transport. + * \param read_context context pointer for `low_read()`. + * \param low_write callback for writing data on the transport. + * \param write_context context pointer for `low_write()`. + */ +void br_sslio_init(br_sslio_context *ctx, + br_ssl_engine_context *engine, + int (*low_read)(void *read_context, + unsigned char *data, size_t len), + void *read_context, + int (*low_write)(void *write_context, + const unsigned char *data, size_t len), + void *write_context); + +/** + * \brief Read some application data from a SSL connection. + * + * If `len` is zero, then this function returns 0 immediately. In + * all other cases, it never returns 0. + * + * This call returns only when at least one byte has been obtained. + * Returned value is the number of bytes read, or -1 on error. The + * number of bytes always fits on an 'int' (data from a single SSL/TLS + * record is returned). + * + * On error or SSL closure, this function returns -1. The caller should + * inspect the error status on the SSL engine to distinguish between + * normal closure and error. + * + * \param cc SSL wrapper context. + * \param dst destination buffer for application data. + * \param len maximum number of bytes to obtain. + * \return number of bytes obtained, or -1 on error. + */ +int br_sslio_read(br_sslio_context *cc, void *dst, size_t len); + +/** + * \brief Read application data from a SSL connection. + * + * This calls returns only when _all_ requested `len` bytes are read, + * or an error is reached. Returned value is 0 on success, -1 on error. + * A normal (verified) SSL closure before that many bytes are obtained + * is reported as an error by this function. + * + * \param cc SSL wrapper context. + * \param dst destination buffer for application data. + * \param len number of bytes to obtain. + * \return 0 on success, or -1 on error. + */ +int br_sslio_read_all(br_sslio_context *cc, void *dst, size_t len); + +/** + * \brief Write some application data unto a SSL connection. + * + * If `len` is zero, then this function returns 0 immediately. In + * all other cases, it never returns 0. + * + * This call returns only when at least one byte has been written. + * Returned value is the number of bytes written, or -1 on error. The + * number of bytes always fits on an 'int' (less than 20000). + * + * On error or SSL closure, this function returns -1. The caller should + * inspect the error status on the SSL engine to distinguish between + * normal closure and error. + * + * **Important:** SSL is buffered; a "written" byte is a byte that was + * injected into the wrapped SSL engine, but this does not necessarily mean + * that it has been scheduled for sending. Use `br_sslio_flush()` to + * ensure that all pending data has been sent to the transport medium. + * + * \param cc SSL wrapper context. + * \param src source buffer for application data. + * \param len maximum number of bytes to write. + * \return number of bytes written, or -1 on error. + */ +int br_sslio_write(br_sslio_context *cc, const void *src, size_t len); + +/** + * \brief Write application data unto a SSL connection. + * + * This calls returns only when _all_ requested `len` bytes have been + * written, or an error is reached. Returned value is 0 on success, -1 + * on error. A normal (verified) SSL closure before that many bytes are + * written is reported as an error by this function. + * + * **Important:** SSL is buffered; a "written" byte is a byte that was + * injected into the wrapped SSL engine, but this does not necessarily mean + * that it has been scheduled for sending. Use `br_sslio_flush()` to + * ensure that all pending data has been sent to the transport medium. + * + * \param cc SSL wrapper context. + * \param src source buffer for application data. + * \param len number of bytes to write. + * \return 0 on success, or -1 on error. + */ +int br_sslio_write_all(br_sslio_context *cc, const void *src, size_t len); + +/** + * \brief Flush pending data. + * + * This call makes sure that any buffered application data in the + * provided context (including the wrapped SSL engine) has been sent + * to the transport medium (i.e. accepted by the `low_write()` callback + * method). If there is no such pending data, then this function does + * nothing (and returns a success, i.e. 0). + * + * If the underlying transport medium has its own buffers, then it is + * up to the caller to ensure the corresponding flushing. + * + * Returned value is 0 on success, -1 on error. + * + * \param cc SSL wrapper context. + * \return 0 on success, or -1 on error. + */ +int br_sslio_flush(br_sslio_context *cc); + +/** + * \brief Close the SSL connection. + * + * This call runs the SSL closure protocol (sending a `close_notify`, + * receiving the response `close_notify`). When it returns, the SSL + * connection is finished. It is still up to the caller to manage the + * possible transport-level termination, if applicable (alternatively, + * the underlying transport stream may be reused for non-SSL messages). + * + * Returned value is 0 on success, -1 on error. A failure by the peer + * to process the complete closure protocol (i.e. sending back the + * `close_notify`) is an error. + * + * \param cc SSL wrapper context. + * \return 0 on success, or -1 on error. + */ +int br_sslio_close(br_sslio_context *cc); + +/* ===================================================================== */ + +/* + * Symbolic constants for cipher suites. + */ + +/* From RFC 5246 */ +#define BR_TLS_NULL_WITH_NULL_NULL 0x0000 +#define BR_TLS_RSA_WITH_NULL_MD5 0x0001 +#define BR_TLS_RSA_WITH_NULL_SHA 0x0002 +#define BR_TLS_RSA_WITH_NULL_SHA256 0x003B +#define BR_TLS_RSA_WITH_RC4_128_MD5 0x0004 +#define BR_TLS_RSA_WITH_RC4_128_SHA 0x0005 +#define BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A +#define BR_TLS_RSA_WITH_AES_128_CBC_SHA 0x002F +#define BR_TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 +#define BR_TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C +#define BR_TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D +#define BR_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D +#define BR_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 +#define BR_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 +#define BR_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 +#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 +#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 +#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 +#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 +#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 +#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 +#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 +#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 +#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E +#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F +#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040 +#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 +#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068 +#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069 +#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A +#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B +#define BR_TLS_DH_anon_WITH_RC4_128_MD5 0x0018 +#define BR_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B +#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 +#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A +#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C +#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D + +/* From RFC 4492 */ +#define BR_TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 +#define BR_TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 +#define BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 +#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 +#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 +#define BR_TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006 +#define BR_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007 +#define BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A +#define BR_TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B +#define BR_TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C +#define BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D +#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E +#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F +#define BR_TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010 +#define BR_TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011 +#define BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 +#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 +#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 +#define BR_TLS_ECDH_anon_WITH_NULL_SHA 0xC015 +#define BR_TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016 +#define BR_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017 +#define BR_TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018 +#define BR_TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019 + +/* From RFC 5288 */ +#define BR_TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C +#define BR_TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D +#define BR_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E +#define BR_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F +#define BR_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 0x00A0 +#define BR_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 0x00A1 +#define BR_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 0x00A2 +#define BR_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 0x00A3 +#define BR_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 0x00A4 +#define BR_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 0x00A5 +#define BR_TLS_DH_anon_WITH_AES_128_GCM_SHA256 0x00A6 +#define BR_TLS_DH_anon_WITH_AES_256_GCM_SHA384 0x00A7 + +/* From RFC 5289 */ +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024 +#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025 +#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026 +#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 +#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028 +#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029 +#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C +#define BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D +#define BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E +#define BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F +#define BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030 +#define BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 +#define BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 + +/* From RFC 6655 and 7251 */ +#define BR_TLS_RSA_WITH_AES_128_CCM 0xC09C +#define BR_TLS_RSA_WITH_AES_256_CCM 0xC09D +#define BR_TLS_RSA_WITH_AES_128_CCM_8 0xC0A0 +#define BR_TLS_RSA_WITH_AES_256_CCM_8 0xC0A1 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM 0xC0AD +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF + +/* From RFC 7905 */ +#define BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8 +#define BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9 +#define BR_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA +#define BR_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAB +#define BR_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAC +#define BR_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD +#define BR_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE + +/* From RFC 7507 */ +#define BR_TLS_FALLBACK_SCSV 0x5600 + +/* + * Symbolic constants for alerts. + */ +#define BR_ALERT_CLOSE_NOTIFY 0 +#define BR_ALERT_UNEXPECTED_MESSAGE 10 +#define BR_ALERT_BAD_RECORD_MAC 20 +#define BR_ALERT_RECORD_OVERFLOW 22 +#define BR_ALERT_DECOMPRESSION_FAILURE 30 +#define BR_ALERT_HANDSHAKE_FAILURE 40 +#define BR_ALERT_BAD_CERTIFICATE 42 +#define BR_ALERT_UNSUPPORTED_CERTIFICATE 43 +#define BR_ALERT_CERTIFICATE_REVOKED 44 +#define BR_ALERT_CERTIFICATE_EXPIRED 45 +#define BR_ALERT_CERTIFICATE_UNKNOWN 46 +#define BR_ALERT_ILLEGAL_PARAMETER 47 +#define BR_ALERT_UNKNOWN_CA 48 +#define BR_ALERT_ACCESS_DENIED 49 +#define BR_ALERT_DECODE_ERROR 50 +#define BR_ALERT_DECRYPT_ERROR 51 +#define BR_ALERT_PROTOCOL_VERSION 70 +#define BR_ALERT_INSUFFICIENT_SECURITY 71 +#define BR_ALERT_INTERNAL_ERROR 80 +#define BR_ALERT_USER_CANCELED 90 +#define BR_ALERT_NO_RENEGOTIATION 100 +#define BR_ALERT_UNSUPPORTED_EXTENSION 110 +#define BR_ALERT_NO_APPLICATION_PROTOCOL 120 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bearssl_x509.h b/bearssl_x509.h new file mode 100644 index 0000000..49d2fba --- /dev/null +++ b/bearssl_x509.h @@ -0,0 +1,1397 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BR_BEARSSL_X509_H__ +#define BR_BEARSSL_X509_H__ + +#include +#include + +#include "bearssl_ec.h" +#include "bearssl_hash.h" +#include "bearssl_rsa.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_x509.h + * + * # X.509 Certificate Chain Processing + * + * An X.509 processing engine receives an X.509 chain, chunk by chunk, + * as received from a SSL/TLS client or server (the client receives the + * server's certificate chain, and the server receives the client's + * certificate chain if it requested a client certificate). The chain + * is thus injected in the engine in SSL order (end-entity first). + * + * The engine's job is to return the public key to use for SSL/TLS. + * How exactly that key is obtained and verified is entirely up to the + * engine. + * + * **The "known key" engine** returns a public key which is already known + * from out-of-band information (e.g. the client _remembers_ the key from + * a previous connection, as in the usual SSH model). This is the simplest + * engine since it simply ignores the chain, thereby avoiding the need + * for any decoding logic. + * + * **The "minimal" engine** implements minimal X.509 decoding and chain + * validation: + * + * - The provided chain should validate "as is". There is no attempt + * at reordering, skipping or downloading extra certificates. + * + * - X.509 v1, v2 and v3 certificates are supported. + * + * - Trust anchors are a DN and a public key. Each anchor is either a + * "CA" anchor, or a non-CA. + * + * - If the end-entity certificate matches a non-CA anchor (subject DN + * is equal to the non-CA name, and public key is also identical to + * the anchor key), then this is a _direct trust_ case and the + * remaining certificates are ignored. + * + * - Unless direct trust is applied, the chain must be verifiable up to + * a certificate whose issuer DN matches the DN from a "CA" trust anchor, + * and whose signature is verifiable against that anchor's public key. + * Subsequent certificates in the chain are ignored. + * + * - The engine verifies subject/issuer DN matching, and enforces + * processing of Basic Constraints and Key Usage extensions. The + * Authority Key Identifier, Subject Key Identifier, Issuer Alt Name, + * Subject Directory Attribute, CRL Distribution Points, Freshest CRL, + * Authority Info Access and Subject Info Access extensions are + * ignored. The Subject Alt Name is decoded for the end-entity + * certificate under some conditions (see below). Other extensions + * are ignored if non-critical, or imply chain rejection if critical. + * + * - The Subject Alt Name extension is parsed for names of type `dNSName` + * when decoding the end-entity certificate, and only if there is a + * server name to match. If there is no SAN extension, then the + * Common Name from the subjectDN is used. That name matching is + * case-insensitive and honours a single starting wildcard (i.e. if + * the name in the certificate starts with "`*.`" then this matches + * any word as first element). Note: this name matching is performed + * also in the "direct trust" model. + * + * - DN matching is byte-to-byte equality (a future version might + * include some limited processing for case-insensitive matching and + * whitespace normalisation). + * + * - Successful validation produces a public key type but also a set + * of allowed usages (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * The caller is responsible for checking that the key type and + * usages are compatible with the expected values (e.g. with the + * selected cipher suite, when the client validates the server's + * certificate). + * + * **Important caveats:** + * + * - The "minimal" engine does not check revocation status. The relevant + * extensions are ignored, and CRL or OCSP responses are not gathered + * or checked. + * + * - The "minimal" engine does not currently support Name Constraints + * (some basic functionality to handle sub-domains may be added in a + * later version). + * + * - The decoder is not "validating" in the sense that it won't reject + * some certificates with invalid field values when these fields are + * not actually processed. + */ + +/* + * X.509 error codes are in the 32..63 range. + */ + +/** \brief X.509 status: validation was successful; this is not actually + an error. */ +#define BR_ERR_X509_OK 32 + +/** \brief X.509 status: invalid value in an ASN.1 structure. */ +#define BR_ERR_X509_INVALID_VALUE 33 + +/** \brief X.509 status: truncated certificate. */ +#define BR_ERR_X509_TRUNCATED 34 + +/** \brief X.509 status: empty certificate chain (no certificate at all). */ +#define BR_ERR_X509_EMPTY_CHAIN 35 + +/** \brief X.509 status: decoding error: inner element extends beyond + outer element size. */ +#define BR_ERR_X509_INNER_TRUNC 36 + +/** \brief X.509 status: decoding error: unsupported tag class (application + or private). */ +#define BR_ERR_X509_BAD_TAG_CLASS 37 + +/** \brief X.509 status: decoding error: unsupported tag value. */ +#define BR_ERR_X509_BAD_TAG_VALUE 38 + +/** \brief X.509 status: decoding error: indefinite length. */ +#define BR_ERR_X509_INDEFINITE_LENGTH 39 + +/** \brief X.509 status: decoding error: extraneous element. */ +#define BR_ERR_X509_EXTRA_ELEMENT 40 + +/** \brief X.509 status: decoding error: unexpected element. */ +#define BR_ERR_X509_UNEXPECTED 41 + +/** \brief X.509 status: decoding error: expected constructed element, but + is primitive. */ +#define BR_ERR_X509_NOT_CONSTRUCTED 42 + +/** \brief X.509 status: decoding error: expected primitive element, but + is constructed. */ +#define BR_ERR_X509_NOT_PRIMITIVE 43 + +/** \brief X.509 status: decoding error: BIT STRING length is not multiple + of 8. */ +#define BR_ERR_X509_PARTIAL_BYTE 44 + +/** \brief X.509 status: decoding error: BOOLEAN value has invalid length. */ +#define BR_ERR_X509_BAD_BOOLEAN 45 + +/** \brief X.509 status: decoding error: value is off-limits. */ +#define BR_ERR_X509_OVERFLOW 46 + +/** \brief X.509 status: invalid distinguished name. */ +#define BR_ERR_X509_BAD_DN 47 + +/** \brief X.509 status: invalid date/time representation. */ +#define BR_ERR_X509_BAD_TIME 48 + +/** \brief X.509 status: certificate contains unsupported features that + cannot be ignored. */ +#define BR_ERR_X509_UNSUPPORTED 49 + +/** \brief X.509 status: key or signature size exceeds internal limits. */ +#define BR_ERR_X509_LIMIT_EXCEEDED 50 + +/** \brief X.509 status: key type does not match that which was expected. */ +#define BR_ERR_X509_WRONG_KEY_TYPE 51 + +/** \brief X.509 status: signature is invalid. */ +#define BR_ERR_X509_BAD_SIGNATURE 52 + +/** \brief X.509 status: validation time is unknown. */ +#define BR_ERR_X509_TIME_UNKNOWN 53 + +/** \brief X.509 status: certificate is expired or not yet valid. */ +#define BR_ERR_X509_EXPIRED 54 + +/** \brief X.509 status: issuer/subject DN mismatch in the chain. */ +#define BR_ERR_X509_DN_MISMATCH 55 + +/** \brief X.509 status: expected server name was not found in the chain. */ +#define BR_ERR_X509_BAD_SERVER_NAME 56 + +/** \brief X.509 status: unknown critical extension in certificate. */ +#define BR_ERR_X509_CRITICAL_EXTENSION 57 + +/** \brief X.509 status: not a CA, or path length constraint violation */ +#define BR_ERR_X509_NOT_CA 58 + +/** \brief X.509 status: Key Usage extension prohibits intended usage. */ +#define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59 + +/** \brief X.509 status: public key found in certificate is too small. */ +#define BR_ERR_X509_WEAK_PUBLIC_KEY 60 + +/** \brief X.509 status: chain could not be linked to a trust anchor. */ +#define BR_ERR_X509_NOT_TRUSTED 62 + +/** + * \brief Aggregate structure for public keys. + */ +typedef struct { + /** \brief Key type: `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC` */ + unsigned char key_type; + /** \brief Actual public key. */ + union { + /** \brief RSA public key. */ + br_rsa_public_key rsa; + /** \brief EC public key. */ + br_ec_public_key ec; + } key; +} br_x509_pkey; + +/** + * \brief Distinguished Name (X.500) structure. + * + * The DN is DER-encoded. + */ +typedef struct { + /** \brief Encoded DN data. */ + unsigned char *data; + /** \brief Encoded DN length (in bytes). */ + size_t len; +} br_x500_name; + +/** + * \brief Trust anchor structure. + */ +typedef struct { + /** \brief Encoded DN (X.500 name). */ + br_x500_name dn; + /** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */ + unsigned flags; + /** \brief Anchor public key. */ + br_x509_pkey pkey; +} br_x509_trust_anchor; + +/** + * \brief Trust anchor flag: CA. + * + * A "CA" anchor is deemed fit to verify signatures on certificates. + * A "non-CA" anchor is accepted only for direct trust (server's + * certificate name and key match the anchor). + */ +#define BR_X509_TA_CA 0x0001 + +/* + * Key type: combination of a basic key type (low 4 bits) and some + * optional flags. + * + * For a public key, the basic key type only is set. + * + * For an expected key type, the flags indicate the intended purpose(s) + * for the key; the basic key type may be set to 0 to indicate that any + * key type compatible with the indicated purpose is acceptable. + */ +/** \brief Key type: algorithm is RSA. */ +#define BR_KEYTYPE_RSA 1 +/** \brief Key type: algorithm is EC. */ +#define BR_KEYTYPE_EC 2 + +/** + * \brief Key type: usage is "key exchange". + * + * This value is combined (with bitwise OR) with the algorithm + * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509 + * validation engine that it should find a public key of that type, + * fit for key exchanges (e.g. `TLS_RSA_*` and `TLS_ECDH_*` cipher + * suites). + */ +#define BR_KEYTYPE_KEYX 0x10 + +/** + * \brief Key type: usage is "signature". + * + * This value is combined (with bitwise OR) with the algorithm + * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509 + * validation engine that it should find a public key of that type, + * fit for signatures (e.g. `TLS_ECDHE_*` cipher suites). + */ +#define BR_KEYTYPE_SIGN 0x20 + +/* + * start_chain Called when a new chain is started. If 'server_name' + * is not NULL and non-empty, then it is a name that + * should be looked for in the EE certificate (in the + * SAN extension as dNSName, or in the subjectDN's CN + * if there is no SAN extension). + * The caller ensures that the provided 'server_name' + * pointer remains valid throughout validation. + * + * start_cert Begins a new certificate in the chain. The provided + * length is in bytes; this is the total certificate length. + * + * append Get some additional bytes for the current certificate. + * + * end_cert Ends the current certificate. + * + * end_chain Called at the end of the chain. Returned value is + * 0 on success, or a non-zero error code. + * + * get_pkey Returns the EE certificate public key. + * + * For a complete chain, start_chain() and end_chain() are always + * called. For each certificate, start_cert(), some append() calls, then + * end_cert() are called, in that order. There may be no append() call + * at all if the certificate is empty (which is not valid but may happen + * if the peer sends exactly that). + * + * get_pkey() shall return a pointer to a structure that is valid as + * long as a new chain is not started. This may be a sub-structure + * within the context for the engine. This function MAY return a valid + * pointer to a public key even in some cases of validation failure, + * depending on the validation engine. + */ + +/** + * \brief Class type for an X.509 engine. + * + * A certificate chain validation uses a caller-allocated context, which + * contains the running state for that validation. Methods are called + * in due order: + * + * - `start_chain()` is called at the start of the validation. + * - Certificates are processed one by one, in SSL order (end-entity + * comes first). For each certificate, the following methods are + * called: + * + * - `start_cert()` at the beginning of the certificate. + * - `append()` is called zero, one or more times, to provide + * the certificate (possibly in chunks). + * - `end_cert()` at the end of the certificate. + * + * - `end_chain()` is called when the last certificate in the chain + * was processed. + * - `get_pkey()` is called after chain processing, if the chain + * validation was successful. + * + * A context structure may be reused; the `start_chain()` method shall + * ensure (re)initialisation. + */ +typedef struct br_x509_class_ br_x509_class; +struct br_x509_class_ { + /** + * \brief X.509 context size, in bytes. + */ + size_t context_size; + + /** + * \brief Start a new chain. + * + * This method shall set the vtable (first field) of the context + * structure. + * + * The `server_name`, if not `NULL`, will be considered as a + * fully qualified domain name, to be matched against the `dNSName` + * elements of the end-entity certificate's SAN extension (if there + * is no SAN, then the Common Name from the subjectDN will be used). + * If `server_name` is `NULL` then no such matching is performed. + * + * \param ctx validation context. + * \param server_name server name to match (or `NULL`). + */ + void (*start_chain)(const br_x509_class **ctx, + const char *server_name); + + /** + * \brief Start a new certificate. + * + * \param ctx validation context. + * \param length new certificate length (in bytes). + */ + void (*start_cert)(const br_x509_class **ctx, uint32_t length); + + /** + * \brief Receive some bytes for the current certificate. + * + * This function may be called several times in succession for + * a given certificate. The caller guarantees that for each + * call, `len` is not zero, and the sum of all chunk lengths + * for a certificate matches the total certificate length which + * was provided in the previous `start_cert()` call. + * + * If the new certificate is empty (no byte at all) then this + * function won't be called at all. + * + * \param ctx validation context. + * \param buf certificate data chunk. + * \param len certificate data chunk length (in bytes). + */ + void (*append)(const br_x509_class **ctx, + const unsigned char *buf, size_t len); + + /** + * \brief Finish the current certificate. + * + * This function is called when the end of the current certificate + * is reached. + * + * \param ctx validation context. + */ + void (*end_cert)(const br_x509_class **ctx); + + /** + * \brief Finish the chain. + * + * This function is called at the end of the chain. It shall + * return either 0 if the validation was successful, or a + * non-zero error code. The `BR_ERR_X509_*` constants are + * error codes, though other values may be possible. + * + * \param ctx validation context. + * \return 0 on success, or a non-zero error code. + */ + unsigned (*end_chain)(const br_x509_class **ctx); + + /** + * \brief Get the resulting end-entity public key. + * + * The decoded public key is returned. The returned pointer + * may be valid only as long as the context structure is + * unmodified, i.e. it may cease to be valid if the context + * is released or reused. + * + * This function _may_ return `NULL` if the validation failed. + * However, returning a public key does not mean that the + * validation was wholly successful; some engines may return + * a decoded public key even if the chain did not end on a + * trusted anchor. + * + * If validation succeeded and `usage` is not `NULL`, then + * `*usage` is filled with a combination of `BR_KEYTYPE_SIGN` + * and/or `BR_KEYTYPE_KEYX` that specifies the validated key + * usage types. It is the caller's responsibility to check + * that value against the intended use of the public key. + * + * \param ctx validation context. + * \return the end-entity public key, or `NULL`. + */ + const br_x509_pkey *(*get_pkey)( + const br_x509_class *const *ctx, unsigned *usages); +}; + +/** + * \brief The "known key" X.509 engine structure. + * + * The structure contents are opaque (they shall not be accessed directly), + * except for the first field (the vtable). + * + * The "known key" engine returns an externally configured public key, + * and totally ignores the certificate contents. + */ +typedef struct { + /** \brief Reference to the context vtable. */ + const br_x509_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + br_x509_pkey pkey; + unsigned usages; +#endif +} br_x509_knownkey_context; + +/** + * \brief Class instance for the "known key" X.509 engine. + */ +extern const br_x509_class br_x509_knownkey_vtable; + +/** + * \brief Initialize a "known key" X.509 engine with a known RSA public key. + * + * The `usages` parameter indicates the allowed key usages for that key + * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * + * The provided pointers are linked in, not copied, so they must remain + * valid while the public key may be in usage. + * + * \param ctx context to initialise. + * \param pk known public key. + * \param usages allowed key usages. + */ +void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx, + const br_rsa_public_key *pk, unsigned usages); + +/** + * \brief Initialize a "known key" X.509 engine with a known EC public key. + * + * The `usages` parameter indicates the allowed key usages for that key + * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * + * The provided pointers are linked in, not copied, so they must remain + * valid while the public key may be in usage. + * + * \param ctx context to initialise. + * \param pk known public key. + * \param usages allowed key usages. + */ +void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, + const br_ec_public_key *pk, unsigned usages); + +#ifndef BR_DOXYGEN_IGNORE +/* + * The minimal X.509 engine has some state buffers which must be large + * enough to simultaneously accommodate: + * -- the public key extracted from the current certificate; + * -- the signature on the current certificate or on the previous + * certificate; + * -- the public key extracted from the EE certificate. + * + * We store public key elements in their raw unsigned big-endian + * encoding. We want to support up to RSA-4096 with a short (up to 64 + * bits) public exponent, thus a buffer for a public key must have + * length at least 520 bytes. Similarly, a RSA-4096 signature has length + * 512 bytes. + * + * Though RSA public exponents can formally be as large as the modulus + * (mathematically, even larger exponents would work, but PKCS#1 forbids + * them), exponents that do not fit on 32 bits are extremely rare, + * notably because some widespread implementations (e.g. Microsoft's + * CryptoAPI) don't support them. Moreover, large public exponent do not + * seem to imply any tangible security benefit, and they increase the + * cost of public key operations. The X.509 "minimal" engine will tolerate + * public exponents of arbitrary size as long as the modulus and the + * exponent can fit together in the dedicated buffer. + * + * EC public keys are shorter than RSA public keys; even with curve + * NIST P-521 (the largest curve we care to support), a public key is + * encoded over 133 bytes only. + */ +#define BR_X509_BUFSIZE_KEY 520 +#define BR_X509_BUFSIZE_SIG 512 +#endif + +/** + * \brief Type for receiving a name element. + * + * An array of such structures can be provided to the X.509 decoding + * engines. If the specified elements are found in the certificate + * subject DN or the SAN extension, then the name contents are copied + * as zero-terminated strings into the buffer. + * + * The decoder converts TeletexString and BMPString to UTF8String, and + * ensures that the resulting string is zero-terminated. If the string + * does not fit in the provided buffer, then the copy is aborted and an + * error is reported. + */ +typedef struct { + /** + * \brief Element OID. + * + * For X.500 name elements (to be extracted from the subject DN), + * this is the encoded OID for the requested name element; the + * first byte shall contain the length of the DER-encoded OID + * value, followed by the OID value (for instance, OID 2.5.4.3, + * for id-at-commonName, will be `03 55 04 03`). This is + * equivalent to full DER encoding with the length but without + * the tag. + * + * For SAN name elements, the first byte (`oid[0]`) has value 0, + * followed by another byte that matches the expected GeneralName + * tag. Allowed second byte values are then: + * + * - 1: `rfc822Name` + * + * - 2: `dNSName` + * + * - 6: `uniformResourceIdentifier` + * + * - 0: `otherName` + * + * If first and second byte are 0, then this is a SAN element of + * type `otherName`; the `oid[]` array should then contain, right + * after the two bytes of value 0, an encoded OID (with the same + * conventions as for X.500 name elements). If a match is found + * for that OID, then the corresponding name element will be + * extracted, as long as it is a supported string type. + */ + const unsigned char *oid; + + /** + * \brief Destination buffer. + */ + char *buf; + + /** + * \brief Length (in bytes) of the destination buffer. + * + * The buffer MUST NOT be smaller than 1 byte. + */ + size_t len; + + /** + * \brief Decoding status. + * + * Status is 0 if the name element was not found, 1 if it was + * found and decoded, or -1 on error. Error conditions include + * an unrecognised encoding, an invalid encoding, or a string + * too large for the destination buffer. + */ + int status; + +} br_name_element; + +/** + * \brief The "minimal" X.509 engine structure. + * + * The structure contents are opaque (they shall not be accessed directly), + * except for the first field (the vtable). + * + * The "minimal" engine performs a rudimentary but serviceable X.509 path + * validation. + */ +typedef struct { + const br_x509_class *vtable; + +#ifndef BR_DOXYGEN_IGNORE + /* Structure for returning the EE public key. */ + br_x509_pkey pkey; + + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + /* Server name to match with the SAN / CN of the EE certificate. */ + const char *server_name; + + /* Validated key usages. */ + unsigned char key_usages; + + /* Explicitly set date and time. */ + uint32_t days, seconds; + + /* Current certificate length (in bytes). Set to 0 when the + certificate has been fully processed. */ + uint32_t cert_length; + + /* Number of certificates processed so far in the current chain. + It is incremented at the end of the processing of a certificate, + so it is 0 for the EE. */ + uint32_t num_certs; + + /* Certificate data chunk. */ + const unsigned char *hbuf; + size_t hlen; + + /* The pad serves as destination for various operations. */ + unsigned char pad[256]; + + /* Buffer for EE public key data. */ + unsigned char ee_pkey_data[BR_X509_BUFSIZE_KEY]; + + /* Buffer for currently decoded public key. */ + unsigned char pkey_data[BR_X509_BUFSIZE_KEY]; + + /* Signature type: signer key type, offset to the hash + function OID (in the T0 data block) and hash function + output length (TBS hash length). */ + unsigned char cert_signer_key_type; + uint16_t cert_sig_hash_oid; + unsigned char cert_sig_hash_len; + + /* Current/last certificate signature. */ + unsigned char cert_sig[BR_X509_BUFSIZE_SIG]; + uint16_t cert_sig_len; + + /* Minimum RSA key length (difference in bytes from 128). */ + int16_t min_rsa_size; + + /* Configured trust anchors. */ + const br_x509_trust_anchor *trust_anchors; + size_t trust_anchors_num; + + /* + * Multi-hasher for the TBS. + */ + unsigned char do_mhash; + br_multihash_context mhash; + unsigned char tbs_hash[64]; + + /* + * Simple hasher for the subject/issuer DN. + */ + unsigned char do_dn_hash; + const br_hash_class *dn_hash_impl; + br_hash_compat_context dn_hash; + unsigned char current_dn_hash[64]; + unsigned char next_dn_hash[64]; + unsigned char saved_dn_hash[64]; + + /* + * Name elements to gather. + */ + br_name_element *name_elts; + size_t num_name_elts; + + /* + * Public key cryptography implementations (signature verification). + */ + br_rsa_pkcs1_vrfy irsa; + br_ecdsa_vrfy iecdsa; + const br_ec_impl *iec; +#endif + +} br_x509_minimal_context; + +/** + * \brief Class instance for the "minimal" X.509 engine. + */ +extern const br_x509_class br_x509_minimal_vtable; + +/** + * \brief Initialise a "minimal" X.509 engine. + * + * The `dn_hash_impl` parameter shall be a hash function internally used + * to match X.500 names (subject/issuer DN, and anchor names). Any standard + * hash function may be used, but a collision-resistant hash function is + * advised. + * + * After initialization, some implementations for signature verification + * (hash functions and signature algorithms) MUST be added. + * + * \param ctx context to initialise. + * \param dn_hash_impl hash function for DN comparisons. + * \param trust_anchors trust anchors. + * \param trust_anchors_num number of trust anchors. + */ +void br_x509_minimal_init(br_x509_minimal_context *ctx, + const br_hash_class *dn_hash_impl, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + +/** + * \brief Set a supported hash function in an X.509 "minimal" engine. + * + * Hash functions are used with signature verification algorithms. + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the hash functions it shall support for that + * purpose. The hash function identifier MUST be one of the standard + * hash function identifiers (1 to 6, for MD5, SHA-1, SHA-224, SHA-256, + * SHA-384 and SHA-512). + * + * If `impl` is `NULL`, this _removes_ support for the designated + * hash function. + * + * \param ctx validation context. + * \param id hash function identifier (from 1 to 6). + * \param impl hash function implementation (or `NULL`). + */ +static inline void +br_x509_minimal_set_hash(br_x509_minimal_context *ctx, + int id, const br_hash_class *impl) +{ + br_multihash_setimpl(&ctx->mhash, id, impl); +} + +/** + * \brief Set a RSA signature verification implementation in the X.509 + * "minimal" engine. + * + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the signature verification implementations that + * it is supposed to support. If `irsa` is `0`, then the RSA support + * is disabled. + * + * \param ctx validation context. + * \param irsa RSA signature verification implementation (or `0`). + */ +static inline void +br_x509_minimal_set_rsa(br_x509_minimal_context *ctx, + br_rsa_pkcs1_vrfy irsa) +{ + ctx->irsa = irsa; +} + +/** + * \brief Set a ECDSA signature verification implementation in the X.509 + * "minimal" engine. + * + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the signature verification implementations that + * it is supposed to support. + * + * If `iecdsa` is `0`, then this call disables ECDSA support; in that + * case, `iec` may be `NULL`. Otherwise, `iecdsa` MUST point to a function + * that verifies ECDSA signatures with format "asn1", and it will use + * `iec` as underlying elliptic curve support. + * + * \param ctx validation context. + * \param iec elliptic curve implementation (or `NULL`). + * \param iecdsa ECDSA implementation (or `0`). + */ +static inline void +br_x509_minimal_set_ecdsa(br_x509_minimal_context *ctx, + const br_ec_impl *iec, br_ecdsa_vrfy iecdsa) +{ + ctx->iecdsa = iecdsa; + ctx->iec = iec; +} + +/** + * \brief Initialise a "minimal" X.509 engine with default algorithms. + * + * This function performs the same job as `br_x509_minimal_init()`, but + * also sets implementations for RSA, ECDSA, and the standard hash + * functions. + * + * \param ctx context to initialise. + * \param trust_anchors trust anchors. + * \param trust_anchors_num number of trust anchors. + */ +void br_x509_minimal_init_full(br_x509_minimal_context *ctx, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + +/** + * \brief Set the validation time for the X.509 "minimal" engine. + * + * The validation time is set as two 32-bit integers, for days and + * seconds since a fixed epoch: + * + * - Days are counted in a proleptic Gregorian calendar since + * January 1st, 0 AD. Year "0 AD" is the one that preceded "1 AD"; + * it is also traditionally known as "1 BC". + * + * - Seconds are counted since midnight, from 0 to 86400 (a count of + * 86400 is possible only if a leap second happened). + * + * The validation date and time is understood in the UTC time zone. + * + * If the validation date and time are not explicitly set, but BearSSL + * was compiled with support for the system clock on the underlying + * platform, then the current time will automatically be used. Otherwise, + * not setting the validation date and time implies a validation + * failure (except in case of direct trust of the EE key). + * + * \param ctx validation context. + * \param days days since January 1st, 0 AD (Gregorian calendar). + * \param seconds seconds since midnight (0 to 86400). + */ +static inline void +br_x509_minimal_set_time(br_x509_minimal_context *ctx, + uint32_t days, uint32_t seconds) +{ + ctx->days = days; + ctx->seconds = seconds; +} + +/** + * \brief Set the minimal acceptable length for RSA keys (X.509 "minimal" + * engine). + * + * The RSA key length is expressed in bytes. The default minimum key + * length is 128 bytes, corresponding to 1017 bits. RSA keys shorter + * than the configured length will be rejected, implying validation + * failure. This setting applies to keys extracted from certificates + * (both end-entity, and intermediate CA) but not to "CA" trust anchors. + * + * \param ctx validation context. + * \param byte_length minimum RSA key length, **in bytes** (not bits). + */ +static inline void +br_x509_minimal_set_minrsa(br_x509_minimal_context *ctx, int byte_length) +{ + ctx->min_rsa_size = (int16_t)(byte_length - 128); +} + +/** + * \brief Set the name elements to gather. + * + * The provided array is linked in the context. The elements are + * gathered from the EE certificate. If the same element type is + * requested several times, then the relevant structures will be filled + * in the order the matching values are encountered in the certificate. + * + * \param ctx validation context. + * \param elts array of name element structures to fill. + * \param num_elts number of name element structures to fill. + */ +static inline void +br_x509_minimal_set_name_elements(br_x509_minimal_context *ctx, + br_name_element *elts, size_t num_elts) +{ + ctx->name_elts = elts; + ctx->num_name_elts = num_elts; +} + +/** + * \brief X.509 decoder context. + * + * This structure is _not_ for X.509 validation, but for extracting + * names and public keys from encoded certificates. Intended usage is + * to use (self-signed) certificates as trust anchors. + * + * Contents are opaque and shall not be accessed directly. + */ +typedef struct { + +#ifndef BR_DOXYGEN_IGNORE + /* Structure for returning the public key. */ + br_x509_pkey pkey; + + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + /* The pad serves as destination for various operations. */ + unsigned char pad[256]; + + /* Flag set when decoding succeeds. */ + unsigned char decoded; + + /* Validity dates. */ + uint32_t notbefore_days, notbefore_seconds; + uint32_t notafter_days, notafter_seconds; + + /* The "CA" flag. This is set to true if the certificate contains + a Basic Constraints extension that asserts CA status. */ + unsigned char isCA; + + /* DN processing: the subject DN is extracted and pushed to the + provided callback. */ + unsigned char copy_dn; + void *append_dn_ctx; + void (*append_dn)(void *ctx, const void *buf, size_t len); + + /* Certificate data chunk. */ + const unsigned char *hbuf; + size_t hlen; + + /* Buffer for decoded public key. */ + unsigned char pkey_data[BR_X509_BUFSIZE_KEY]; + + /* Type of key and hash function used in the certificate signature. */ + unsigned char signer_key_type; + unsigned char signer_hash_id; +#endif + +} br_x509_decoder_context; + +/** + * \brief Initialise an X.509 decoder context for processing a new + * certificate. + * + * The `append_dn()` callback (with opaque context `append_dn_ctx`) + * will be invoked to receive, chunk by chunk, the certificate's + * subject DN. If `append_dn` is `0` then the subject DN will be + * ignored. + * + * \param ctx X.509 decoder context to initialise. + * \param append_dn DN receiver callback (or `0`). + * \param append_dn_ctx context for the DN receiver callback. + */ +void br_x509_decoder_init(br_x509_decoder_context *ctx, + void (*append_dn)(void *ctx, const void *buf, size_t len), + void *append_dn_ctx); + +/** + * \brief Push some certificate bytes into a decoder context. + * + * If `len` is non-zero, then that many bytes are pushed, from address + * `data`, into the provided decoder context. + * + * \param ctx X.509 decoder context. + * \param data certificate data chunk. + * \param len certificate data chunk length (in bytes). + */ +void br_x509_decoder_push(br_x509_decoder_context *ctx, + const void *data, size_t len); + +/** + * \brief Obtain the decoded public key. + * + * Returned value is a pointer to a structure internal to the decoder + * context; releasing or reusing the decoder context invalidates that + * structure. + * + * If decoding was not finished, or failed, then `NULL` is returned. + * + * \param ctx X.509 decoder context. + * \return the public key, or `NULL` on unfinished/error. + */ +static inline br_x509_pkey * +br_x509_decoder_get_pkey(br_x509_decoder_context *ctx) +{ + if (ctx->decoded && ctx->err == 0) { + return &ctx->pkey; + } else { + return NULL; + } +} + +/** + * \brief Get decoder error status. + * + * If no error was reported yet but the certificate decoding is not + * finished, then the error code is `BR_ERR_X509_TRUNCATED`. If decoding + * was successful, then 0 is returned. + * + * \param ctx X.509 decoder context. + * \return 0 on successful decoding, or a non-zero error code. + */ +static inline int +br_x509_decoder_last_error(br_x509_decoder_context *ctx) +{ + if (ctx->err != 0) { + return ctx->err; + } + if (!ctx->decoded) { + return BR_ERR_X509_TRUNCATED; + } + return 0; +} + +/** + * \brief Get the "isCA" flag from an X.509 decoder context. + * + * This flag is set if the decoded certificate claims to be a CA through + * a Basic Constraints extension. This flag should not be read before + * decoding completed successfully. + * + * \param ctx X.509 decoder context. + * \return the "isCA" flag. + */ +static inline int +br_x509_decoder_isCA(br_x509_decoder_context *ctx) +{ + return ctx->isCA; +} + +/** + * \brief Get the issuing CA key type (type of algorithm used to sign the + * decoded certificate). + * + * This is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. The value 0 is returned + * if the signature type was not recognised. + * + * \param ctx X.509 decoder context. + * \return the issuing CA key type. + */ +static inline int +br_x509_decoder_get_signer_key_type(br_x509_decoder_context *ctx) +{ + return ctx->signer_key_type; +} + +/** + * \brief Get the identifier for the hash function used to sign the decoded + * certificate. + * + * This is 0 if the hash function was not recognised. + * + * \param ctx X.509 decoder context. + * \return the signature hash function identifier. + */ +static inline int +br_x509_decoder_get_signer_hash_id(br_x509_decoder_context *ctx) +{ + return ctx->signer_hash_id; +} + +/** + * \brief Type for an X.509 certificate (DER-encoded). + */ +typedef struct { + /** \brief The DER-encoded certificate data. */ + unsigned char *data; + /** \brief The DER-encoded certificate length (in bytes). */ + size_t data_len; +} br_x509_certificate; + +/** + * \brief Private key decoder context. + * + * The private key decoder recognises RSA and EC private keys, either in + * their raw, DER-encoded format, or wrapped in an unencrypted PKCS#8 + * archive (again DER-encoded). + * + * Structure contents are opaque and shall not be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + /* Structure for returning the private key. */ + union { + br_rsa_private_key rsa; + br_ec_private_key ec; + } key; + + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + /* Private key data chunk. */ + const unsigned char *hbuf; + size_t hlen; + + /* The pad serves as destination for various operations. */ + unsigned char pad[256]; + + /* Decoded key type; 0 until decoding is complete. */ + unsigned char key_type; + + /* Buffer for the private key elements. It shall be large enough + to accommodate all elements for a RSA-4096 private key (roughly + five 2048-bit integers, possibly a bit more). */ + unsigned char key_data[3 * BR_X509_BUFSIZE_SIG]; +#endif +} br_skey_decoder_context; + +/** + * \brief Initialise a private key decoder context. + * + * \param ctx key decoder context to initialise. + */ +void br_skey_decoder_init(br_skey_decoder_context *ctx); + +/** + * \brief Push some data bytes into a private key decoder context. + * + * If `len` is non-zero, then that many data bytes, starting at address + * `data`, are pushed into the decoder. + * + * \param ctx key decoder context. + * \param data private key data chunk. + * \param len private key data chunk length (in bytes). + */ +void br_skey_decoder_push(br_skey_decoder_context *ctx, + const void *data, size_t len); + +/** + * \brief Get the decoding status for a private key. + * + * Decoding status is 0 on success, or a non-zero error code. If the + * decoding is unfinished when this function is called, then the + * status code `BR_ERR_X509_TRUNCATED` is returned. + * + * \param ctx key decoder context. + * \return 0 on successful decoding, or a non-zero error code. + */ +static inline int +br_skey_decoder_last_error(const br_skey_decoder_context *ctx) +{ + if (ctx->err != 0) { + return ctx->err; + } + if (ctx->key_type == 0) { + return BR_ERR_X509_TRUNCATED; + } + return 0; +} + +/** + * \brief Get the decoded private key type. + * + * Private key type is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. If decoding is + * not finished or failed, then 0 is returned. + * + * \param ctx key decoder context. + * \return decoded private key type, or 0. + */ +static inline int +br_skey_decoder_key_type(const br_skey_decoder_context *ctx) +{ + if (ctx->err == 0) { + return ctx->key_type; + } else { + return 0; + } +} + +/** + * \brief Get the decoded RSA private key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not RSA. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded RSA private key, or `NULL`. + */ +static inline const br_rsa_private_key * +br_skey_decoder_get_rsa(const br_skey_decoder_context *ctx) +{ + if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_RSA) { + return &ctx->key.rsa; + } else { + return NULL; + } +} + +/** + * \brief Get the decoded EC private key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not EC. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded EC private key, or `NULL`. + */ +static inline const br_ec_private_key * +br_skey_decoder_get_ec(const br_skey_decoder_context *ctx) +{ + if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_EC) { + return &ctx->key.ec; + } else { + return NULL; + } +} + +/** + * \brief Encode an RSA private key (raw DER format). + * + * This function encodes the provided key into the "raw" format specified + * in PKCS#1 (RFC 8017, Appendix C, type `RSAPrivateKey`), with DER + * encoding rules. + * + * The key elements are: + * + * - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`) + * + * - `pk`: the public key (`n` and `e`) + * + * - `d` (size: `dlen` bytes): the private exponent + * + * The public key elements, and the private exponent `d`, can be + * recomputed from the private key (see `br_rsa_compute_modulus()`, + * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the RSA private key. + * \param pk the RSA public key. + * \param d the RSA private exponent. + * \param dlen the RSA private exponent length (in bytes). + * \return the encoded key length (in bytes). + */ +size_t br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk, + const br_rsa_public_key *pk, const void *d, size_t dlen); + +/** + * \brief Encode an RSA private key (PKCS#8 DER format). + * + * This function encodes the provided key into the PKCS#8 format + * (RFC 5958, type `OneAsymmetricKey`). It wraps around the "raw DER" + * format for the RSA key, as implemented by `br_encode_rsa_raw_der()`. + * + * The key elements are: + * + * - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`) + * + * - `pk`: the public key (`n` and `e`) + * + * - `d` (size: `dlen` bytes): the private exponent + * + * The public key elements, and the private exponent `d`, can be + * recomputed from the private key (see `br_rsa_compute_modulus()`, + * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the RSA private key. + * \param pk the RSA public key. + * \param d the RSA private exponent. + * \param dlen the RSA private exponent length (in bytes). + * \return the encoded key length (in bytes). + */ +size_t br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk, + const br_rsa_public_key *pk, const void *d, size_t dlen); + +/** + * \brief Encode an EC private key (raw DER format). + * + * This function encodes the provided key into the "raw" format specified + * in RFC 5915 (type `ECPrivateKey`), with DER encoding rules. + * + * The private key is provided in `sk`, the public key being `pk`. If + * `pk` is `NULL`, then the encoded key will not include the public key + * in its `publicKey` field (which is nominally optional). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * If the key cannot be encoded (e.g. because there is no known OBJECT + * IDENTIFIER for the used curve), then 0 is returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the EC private key. + * \param pk the EC public key (or `NULL`). + * \return the encoded key length (in bytes), or 0. + */ +size_t br_encode_ec_raw_der(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk); + +/** + * \brief Encode an EC private key (PKCS#8 DER format). + * + * This function encodes the provided key into the PKCS#8 format + * (RFC 5958, type `OneAsymmetricKey`). The curve is identified + * by an OID provided as parameters to the `privateKeyAlgorithm` + * field. The private key value (contents of the `privateKey` field) + * contains the DER encoding of the `ECPrivateKey` type defined in + * RFC 5915, without the `parameters` field (since they would be + * redundant with the information in `privateKeyAlgorithm`). + * + * The private key is provided in `sk`, the public key being `pk`. If + * `pk` is not `NULL`, then the encoded public key is included in the + * `publicKey` field of the private key value (but not in the `publicKey` + * field of the PKCS#8 `OneAsymmetricKey` wrapper). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * If the key cannot be encoded (e.g. because there is no known OBJECT + * IDENTIFIER for the used curve), then 0 is returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the EC private key. + * \param pk the EC public key (or `NULL`). + * \return the encoded key length (in bytes), or 0. + */ +size_t br_encode_ec_pkcs8_der(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk); + +/** + * \brief PEM banner for RSA private key (raw). + */ +#define BR_ENCODE_PEM_RSA_RAW "RSA PRIVATE KEY" + +/** + * \brief PEM banner for EC private key (raw). + */ +#define BR_ENCODE_PEM_EC_RAW "EC PRIVATE KEY" + +/** + * \brief PEM banner for an RSA or EC private key in PKCS#8 format. + */ +#define BR_ENCODE_PEM_PKCS8 "PRIVATE KEY" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/config.h b/config.h new file mode 100644 index 0000000..8ea4d8a --- /dev/null +++ b/config.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CONFIG_H__ +#define CONFIG_H__ + +/* + * This file contains compile-time flags that can override the + * autodetection performed in relevant files. Each flag is a macro; it + * deactivates the feature if defined to 0, activates it if defined to a + * non-zero integer (normally 1). If the macro is not defined, then + * autodetection applies. + */ + +/* + * When BR_64 is enabled, 64-bit integer types are assumed to be + * efficient (i.e. the architecture has 64-bit registers and can + * do 64-bit operations as fast as 32-bit operations). + * +#define BR_64 1 + */ + +/* + * When BR_LOMUL is enabled, then multiplications of 32-bit values whose + * result are truncated to the low 32 bits are assumed to be + * substantially more efficient than 32-bit multiplications that yield + * 64-bit results. This is typically the case on low-end ARM Cortex M + * systems (M0, M0+, M1, and arguably M3 and M4 as well). + * +#define BR_LOMUL 1 + */ + +/* + * When BR_SLOW_MUL is enabled, multiplications are assumed to be + * substantially slow with regards to other integer operations, thus + * making it worth to make more operations for a given task if it allows + * using less multiplications. + * +#define BR_SLOW_MUL 1 + */ + +/* + * When BR_SLOW_MUL15 is enabled, short multplications (on 15-bit words) + * are assumed to be substantially slow with regards to other integer + * operations, thus making it worth to make more integer operations if + * it allows using less multiplications. + * +#define BR_SLOW_MUL15 1 + */ + +/* + * When BR_CT_MUL31 is enabled, multiplications of 31-bit values (used + * in the "i31" big integer implementation) use an alternate implementation + * which is slower and larger than the normal multiplication, but should + * ensure constant-time multiplications even on architectures where the + * multiplication opcode takes a variable number of cycles to complete. + * +#define BR_CT_MUL31 1 + */ + +/* + * When BR_CT_MUL15 is enabled, multiplications of 15-bit values (held + * in 32-bit words) use an alternate implementation which is slower and + * larger than the normal multiplication, but should ensure + * constant-time multiplications on most/all architectures where the + * basic multiplication is not constant-time. +#define BR_CT_MUL15 1 + */ + +/* + * When BR_NO_ARITH_SHIFT is enabled, arithmetic right shifts (with sign + * extension) are performed with a sequence of operations which is bigger + * and slower than a simple right shift on a signed value. This avoids + * relying on an implementation-defined behaviour. However, most if not + * all C compilers use sign extension for right shifts on signed values, + * so this alternate macro is disabled by default. +#define BR_NO_ARITH_SHIFT 1 + */ + +/* + * When BR_RDRAND is enabled, the SSL engine will use the RDRAND opcode + * to automatically obtain quality randomness for seeding its internal + * PRNG. Since that opcode is present only in recent x86 CPU, its + * support is dynamically tested; if the current CPU does not support + * it, then another random source will be used, such as /dev/urandom or + * CryptGenRandom(). + * +#define BR_RDRAND 1 + */ + +/* + * When BR_USE_URANDOM is enabled, the SSL engine will use /dev/urandom + * to automatically obtain quality randomness for seedings its internal + * PRNG. + * +#define BR_USE_URANDOM 1 + */ + +/* + * When BR_USE_WIN32_RAND is enabled, the SSL engine will use the Win32 + * (CryptoAPI) functions (CryptAcquireContext(), CryptGenRandom()...) to + * automatically obtain quality randomness for seedings its internal PRNG. + * + * Note: if both BR_USE_URANDOM and BR_USE_WIN32_RAND are defined, the + * former takes precedence. + * +#define BR_USE_WIN32_RAND 1 + */ + +/* + * When BR_USE_UNIX_TIME is enabled, the X.509 validation engine obtains + * the current time from the OS by calling time(), and assuming that the + * returned value (a 'time_t') is an integer that counts time in seconds + * since the Unix Epoch (Jan 1st, 1970, 00:00 UTC). + * +#define BR_USE_UNIX_TIME 1 + */ + +/* + * When BR_USE_WIN32_TIME is enabled, the X.509 validation engine obtains + * the current time from the OS by calling the Win32 function + * GetSystemTimeAsFileTime(). + * + * Note: if both BR_USE_UNIX_TIME and BR_USE_WIN32_TIME are defined, the + * former takes precedence. + * +#define BR_USE_WIN32_TIME 1 + */ + +/* + * When BR_ARMEL_CORTEXM_GCC is enabled, some operations are replaced with + * inline assembly which is shorter and/or faster. This should be used + * only when all of the following are true: + * - target architecture is ARM in Thumb mode + * - target endianness is little-endian + * - compiler is GCC (or GCC-compatible for inline assembly syntax) + * + * This is meant for the low-end cores (Cortex M0, M0+, M1, M3). + * Note: if BR_LOMUL is not explicitly enabled or disabled, then + * enabling BR_ARMEL_CORTEXM_GCC also enables BR_LOMUL. + * +#define BR_ARMEL_CORTEXM_GCC 1 + */ + +/* + * When BR_AES_X86NI is enabled, the AES implementation using the x86 "NI" + * instructions (dedicated AES opcodes) will be compiled. If this is not + * enabled explicitly, then that AES implementation will be compiled only + * if a compatible compiler is detected. If set explicitly to 0, the + * implementation will not be compiled at all. + * +#define BR_AES_X86NI 1 + */ + +/* + * When BR_SSE2 is enabled, SSE2 intrinsics will be used for some + * algorithm implementations that use them (e.g. chacha20_sse2). If this + * is not enabled explicitly, then support for SSE2 intrinsics will be + * automatically detected. If set explicitly to 0, then SSE2 code will + * not be compiled at all. + * +#define BR_SSE2 1 + */ + +/* + * When BR_POWER8 is enabled, the AES implementation using the POWER ISA + * 2.07 opcodes (available on POWER8 processors and later) is compiled. + * If this is not enabled explicitly, then that implementation will be + * compiled only if a compatible compiler is detected, _and_ the target + * architecture is POWER8 or later. + * +#define BR_POWER8 1 + */ + +/* + * When BR_INT128 is enabled, then code using the 'unsigned __int64' + * and 'unsigned __int128' types will be used to leverage 64x64->128 + * unsigned multiplications. This should work with GCC and compatible + * compilers on 64-bit architectures. + * +#define BR_INT128 1 + */ + +/* + * When BR_UMUL128 is enabled, then code using the '_umul128()' and + * '_addcarry_u64()' intrinsics will be used to implement 64x64->128 + * unsigned multiplications. This should work on Visual C on x64 systems. + * +#define BR_UMUL128 1 + */ + +/* + * When BR_LE_UNALIGNED is enabled, then the current architecture is + * assumed to use little-endian encoding for integers, and to tolerate + * unaligned accesses with no or minimal time penalty. + * +#define BR_LE_UNALIGNED 1 + */ + +/* + * When BR_BE_UNALIGNED is enabled, then the current architecture is + * assumed to use big-endian encoding for integers, and to tolerate + * unaligned accesses with no or minimal time penalty. + * +#define BR_BE_UNALIGNED 1 + */ + +#endif diff --git a/inner.h b/inner.h new file mode 100644 index 0000000..8c7f04e --- /dev/null +++ b/inner.h @@ -0,0 +1,2532 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INNER_H__ +#define INNER_H__ + +#include +#include + +#include "config.h" +#include "bearssl.h" + +/* + * On MSVC, disable the warning about applying unary minus on an + * unsigned type: it is standard, we do it all the time, and for + * good reasons. + */ +#if _MSC_VER +#pragma warning( disable : 4146 ) +#endif + +/* + * Maximum size for a RSA modulus (in bits). Allocated stack buffers + * depend on that size, so this value should be kept small. Currently, + * 2048-bit RSA keys offer adequate security, and should still do so for + * the next few decades; however, a number of widespread PKI have + * already set their root keys to RSA-4096, so we should be able to + * process such keys. + * + * This value MUST be a multiple of 64. This value MUST NOT exceed 47666 + * (some computations in RSA key generation rely on the factor size being + * no more than 23833 bits). RSA key sizes beyond 3072 bits don't make a + * lot of sense anyway. + */ +#define BR_MAX_RSA_SIZE 4096 + +/* + * Minimum size for a RSA modulus (in bits); this value is used only to + * filter out invalid parameters for key pair generation. Normally, + * applications should not use RSA keys smaller than 2048 bits; but some + * specific cases might need shorter keys, for legacy or research + * purposes. + */ +#define BR_MIN_RSA_SIZE 512 + +/* + * Maximum size for a RSA factor (in bits). This is for RSA private-key + * operations. Default is to support factors up to a bit more than half + * the maximum modulus size. + * + * This value MUST be a multiple of 32. + */ +#define BR_MAX_RSA_FACTOR ((BR_MAX_RSA_SIZE + 64) >> 1) + +/* + * Maximum size for an EC curve (modulus or order), in bits. Size of + * stack buffers depends on that parameter. This size MUST be a multiple + * of 8 (so that decoding an integer with that many bytes does not + * overflow). + */ +#define BR_MAX_EC_SIZE 528 + +/* + * Some macros to recognize the current architecture. Right now, we are + * interested into automatically recognizing architecture with efficient + * 64-bit types so that we may automatically use implementations that + * use 64-bit registers in that case. Future versions may detect, e.g., + * availability of SSE2 intrinsics. + * + * If 'unsigned long' is a 64-bit type, then we assume that 64-bit types + * are efficient. Otherwise, we rely on macros that depend on compiler, + * OS and architecture. In any case, failure to detect the architecture + * as 64-bit means that the 32-bit code will be used, and that code + * works also on 64-bit architectures (the 64-bit code may simply be + * more efficient). + * + * The test on 'unsigned long' should already catch most cases, the one + * notable exception being Windows code where 'unsigned long' is kept to + * 32-bit for compatibility with all the legacy code that liberally uses + * the 'DWORD' type for 32-bit values. + * + * Macro names are taken from: http://nadeausoftware.com/articles/2012/02/c_c_tip_how_detect_processor_type_using_compiler_predefined_macros + */ +#ifndef BR_64 +#if ((ULONG_MAX >> 31) >> 31) == 3 +#define BR_64 1 +#elif defined(__ia64) || defined(__itanium__) || defined(_M_IA64) +#define BR_64 1 +#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \ + || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) +#define BR_64 1 +#elif defined(__sparc64__) +#define BR_64 1 +#elif defined(__x86_64__) || defined(_M_X64) +#define BR_64 1 +#endif +#endif + +/* + * Set BR_LOMUL on platforms where it makes sense. + */ +#ifndef BR_LOMUL +#if BR_ARMEL_CORTEXM_GCC +#define BR_LOMUL 1 +#endif +#endif + +/* + * Architecture detection. + */ +#ifndef BR_i386 +#if __i386__ || _M_IX86 +#define BR_i386 1 +#endif +#endif + +#ifndef BR_amd64 +#if __x86_64__ || _M_X64 +#define BR_amd64 1 +#endif +#endif + +/* + * Compiler brand and version. + * + * Implementations that use intrinsics need to detect the compiler type + * and version because some specific actions may be needed to activate + * the corresponding opcodes, both for header inclusion, and when using + * them in a function. + * + * BR_GCC, BR_CLANG and BR_MSC will be set to 1 for, respectively, GCC, + * Clang and MS Visual C. For each of them, sub-macros will be defined + * for versions; each sub-macro is set whenever the compiler version is + * at least as recent as the one corresponding to the macro. + */ + +/* + * GCC thresholds are on versions 4.4 to 4.9 and 5.0. + */ +#ifndef BR_GCC +#if __GNUC__ && !__clang__ +#define BR_GCC 1 + +#if __GNUC__ > 4 +#define BR_GCC_5_0 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 +#define BR_GCC_4_9 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 8 +#define BR_GCC_4_8 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 7 +#define BR_GCC_4_7 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 +#define BR_GCC_4_6 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 5 +#define BR_GCC_4_5 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 4 +#define BR_GCC_4_4 1 +#endif + +#if BR_GCC_5_0 +#define BR_GCC_4_9 1 +#endif +#if BR_GCC_4_9 +#define BR_GCC_4_8 1 +#endif +#if BR_GCC_4_8 +#define BR_GCC_4_7 1 +#endif +#if BR_GCC_4_7 +#define BR_GCC_4_6 1 +#endif +#if BR_GCC_4_6 +#define BR_GCC_4_5 1 +#endif +#if BR_GCC_4_5 +#define BR_GCC_4_4 1 +#endif + +#endif +#endif + +/* + * Clang thresholds are on versions 3.7.0 and 3.8.0. + */ +#ifndef BR_CLANG +#if __clang__ +#define BR_CLANG 1 + +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8) +#define BR_CLANG_3_8 1 +#elif __clang_major__ == 3 && __clang_minor__ >= 7 +#define BR_CLANG_3_7 1 +#endif + +#if BR_CLANG_3_8 +#define BR_CLANG_3_7 1 +#endif + +#endif +#endif + +/* + * MS Visual C thresholds are on Visual Studio 2005 to 2015. + */ +#ifndef BR_MSC +#if _MSC_VER +#define BR_MSC 1 + +#if _MSC_VER >= 1900 +#define BR_MSC_2015 1 +#elif _MSC_VER >= 1800 +#define BR_MSC_2013 1 +#elif _MSC_VER >= 1700 +#define BR_MSC_2012 1 +#elif _MSC_VER >= 1600 +#define BR_MSC_2010 1 +#elif _MSC_VER >= 1500 +#define BR_MSC_2008 1 +#elif _MSC_VER >= 1400 +#define BR_MSC_2005 1 +#endif + +#if BR_MSC_2015 +#define BR_MSC_2013 1 +#endif +#if BR_MSC_2013 +#define BR_MSC_2012 1 +#endif +#if BR_MSC_2012 +#define BR_MSC_2010 1 +#endif +#if BR_MSC_2010 +#define BR_MSC_2008 1 +#endif +#if BR_MSC_2008 +#define BR_MSC_2005 1 +#endif + +#endif +#endif + +/* + * GCC 4.4+ and Clang 3.7+ allow tagging specific functions with a + * 'target' attribute that activates support for specific opcodes. + */ +#if BR_GCC_4_4 || BR_CLANG_3_7 +#define BR_TARGET(x) __attribute__((target(x))) +#else +#define BR_TARGET(x) +#endif + +/* + * AES-NI intrinsics are available on x86 (32-bit and 64-bit) with + * GCC 4.8+, Clang 3.7+ and MSC 2012+. + */ +#ifndef BR_AES_X86NI +#if (BR_i386 || BR_amd64) && (BR_GCC_4_8 || BR_CLANG_3_7 || BR_MSC_2012) +#define BR_AES_X86NI 1 +#endif +#endif + +/* + * SSE2 intrinsics are available on x86 (32-bit and 64-bit) with + * GCC 4.4+, Clang 3.7+ and MSC 2005+. + */ +#ifndef BR_SSE2 +#if (BR_i386 || BR_amd64) && (BR_GCC_4_4 || BR_CLANG_3_7 || BR_MSC_2005) +#define BR_SSE2 1 +#endif +#endif + +/* + * RDRAND intrinsics are available on x86 (32-bit and 64-bit) with + * GCC 4.6+, Clang 3.7+ and MSC 2012+. + */ +#ifndef BR_RDRAND +#if (BR_i386 || BR_amd64) && (BR_GCC_4_6 || BR_CLANG_3_7 || BR_MSC_2012) +#define BR_RDRAND 1 +#endif +#endif + +/* + * Determine type of OS for random number generation. Macro names and + * values are documented on: + * https://sourceforge.net/p/predef/wiki/OperatingSystems/ + * + * TODO: enrich the list of detected system. Also add detection for + * alternate system calls like getentropy(), which are usually + * preferable when available. + */ + +#ifndef BR_USE_URANDOM +#if defined _AIX \ + || defined __ANDROID__ \ + || defined __FreeBSD__ \ + || defined __NetBSD__ \ + || defined __OpenBSD__ \ + || defined __DragonFly__ \ + || defined __linux__ \ + || (defined __sun && (defined __SVR4 || defined __svr4__)) \ + || (defined __APPLE__ && defined __MACH__) +#define BR_USE_URANDOM 1 +#endif +#endif + +#ifndef BR_USE_WIN32_RAND +#if defined _WIN32 || defined _WIN64 +#define BR_USE_WIN32_RAND 1 +#endif +#endif + +/* + * POWER8 crypto support. We rely on compiler macros for the + * architecture, since we do not have a reliable, simple way to detect + * the required support at runtime (we could try running an opcode, and + * trapping the exception or signal on illegal instruction, but this + * induces some non-trivial OS dependencies that we would prefer to + * avoid if possible). + */ +#ifndef BR_POWER8 +#if __GNUC__ && ((_ARCH_PWR8 || _ARCH_PPC) && __CRYPTO__) +#define BR_POWER8 1 +#endif +#endif + +/* + * Detect endinanness on POWER8. + */ +#if BR_POWER8 +#if defined BR_POWER8_LE +#undef BR_POWER8_BE +#if BR_POWER8_LE +#define BR_POWER8_BE 0 +#else +#define BR_POWER8_BE 1 +#endif +#elif defined BR_POWER8_BE +#undef BR_POWER8_LE +#if BR_POWER8_BE +#define BR_POWER8_LE 0 +#else +#define BR_POWER8_LE 1 +#endif +#else +#if __LITTLE_ENDIAN__ +#define BR_POWER8_LE 1 +#define BR_POWER8_BE 0 +#else +#define BR_POWER8_LE 0 +#define BR_POWER8_BE 1 +#endif +#endif +#endif + +/* + * Detect support for 128-bit integers. + */ +#if !defined BR_INT128 && !defined BR_UMUL128 +#ifdef __SIZEOF_INT128__ +#define BR_INT128 1 +#elif _M_X64 +#define BR_UMUL128 1 +#endif +#endif + +/* + * Detect support for unaligned accesses with known endianness. + * + * x86 (both 32-bit and 64-bit) is little-endian and allows unaligned + * accesses. + * + * POWER/PowerPC allows unaligned accesses when big-endian. POWER8 and + * later also allow unaligned accesses when little-endian. + */ +#if !defined BR_LE_UNALIGNED && !defined BR_BE_UNALIGNED + +#if __i386 || __i386__ || __x86_64__ || _M_IX86 || _M_X64 +#define BR_LE_UNALIGNED 1 +#elif BR_POWER8_BE +#define BR_BE_UNALIGNED 1 +#elif BR_POWER8_LE +#define BR_LE_UNALIGNED 1 +#elif (__powerpc__ || __powerpc64__ || _M_PPC || _ARCH_PPC || _ARCH_PPC64) \ + && __BIG_ENDIAN__ +#define BR_BE_UNALIGNED 1 +#endif + +#endif + +/* + * Detect support for an OS-provided time source. + */ + +#ifndef BR_USE_UNIX_TIME +#if defined __unix__ || defined __linux__ \ + || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \ + || (defined __APPLE__ && defined __MACH__) +#define BR_USE_UNIX_TIME 1 +#endif +#endif + +#ifndef BR_USE_WIN32_TIME +#if defined _WIN32 || defined _WIN64 +#define BR_USE_WIN32_TIME 1 +#endif +#endif + +/* ==================================================================== */ +/* + * Encoding/decoding functions. + * + * 32-bit and 64-bit decoding, both little-endian and big-endian, is + * implemented with the inline functions below. + * + * When allowed by some compile-time options (autodetected or provided), + * optimised code is used, to perform direct memory access when the + * underlying architecture supports it, both for endianness and + * alignment. This, however, may trigger strict aliasing issues; the + * code below uses unions to perform (supposedly) safe type punning. + * Since the C aliasing rules are relatively complex and were amended, + * or at least re-explained with different phrasing, in all successive + * versions of the C standard, it is always a bit risky to bet that any + * specific version of a C compiler got it right, for some notion of + * "right". + */ + +typedef union { + uint16_t u; + unsigned char b[sizeof(uint16_t)]; +} br_union_u16; + +typedef union { + uint32_t u; + unsigned char b[sizeof(uint32_t)]; +} br_union_u32; + +typedef union { + uint64_t u; + unsigned char b[sizeof(uint64_t)]; +} br_union_u64; + +static inline void +br_enc16le(void *dst, unsigned x) +{ +#if BR_LE_UNALIGNED + ((br_union_u16 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)x; + buf[1] = (unsigned char)(x >> 8); +#endif +} + +static inline void +br_enc16be(void *dst, unsigned x) +{ +#if BR_BE_UNALIGNED + ((br_union_u16 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)(x >> 8); + buf[1] = (unsigned char)x; +#endif +} + +static inline unsigned +br_dec16le(const void *src) +{ +#if BR_LE_UNALIGNED + return ((const br_union_u16 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return (unsigned)buf[0] | ((unsigned)buf[1] << 8); +#endif +} + +static inline unsigned +br_dec16be(const void *src) +{ +#if BR_BE_UNALIGNED + return ((const br_union_u16 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((unsigned)buf[0] << 8) | (unsigned)buf[1]; +#endif +} + +static inline void +br_enc32le(void *dst, uint32_t x) +{ +#if BR_LE_UNALIGNED + ((br_union_u32 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)x; + buf[1] = (unsigned char)(x >> 8); + buf[2] = (unsigned char)(x >> 16); + buf[3] = (unsigned char)(x >> 24); +#endif +} + +static inline void +br_enc32be(void *dst, uint32_t x) +{ +#if BR_BE_UNALIGNED + ((br_union_u32 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)(x >> 24); + buf[1] = (unsigned char)(x >> 16); + buf[2] = (unsigned char)(x >> 8); + buf[3] = (unsigned char)x; +#endif +} + +static inline uint32_t +br_dec32le(const void *src) +{ +#if BR_LE_UNALIGNED + return ((const br_union_u32 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return (uint32_t)buf[0] + | ((uint32_t)buf[1] << 8) + | ((uint32_t)buf[2] << 16) + | ((uint32_t)buf[3] << 24); +#endif +} + +static inline uint32_t +br_dec32be(const void *src) +{ +#if BR_BE_UNALIGNED + return ((const br_union_u32 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((uint32_t)buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | (uint32_t)buf[3]; +#endif +} + +static inline void +br_enc64le(void *dst, uint64_t x) +{ +#if BR_LE_UNALIGNED + ((br_union_u64 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + br_enc32le(buf, (uint32_t)x); + br_enc32le(buf + 4, (uint32_t)(x >> 32)); +#endif +} + +static inline void +br_enc64be(void *dst, uint64_t x) +{ +#if BR_BE_UNALIGNED + ((br_union_u64 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + br_enc32be(buf, (uint32_t)(x >> 32)); + br_enc32be(buf + 4, (uint32_t)x); +#endif +} + +static inline uint64_t +br_dec64le(const void *src) +{ +#if BR_LE_UNALIGNED + return ((const br_union_u64 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return (uint64_t)br_dec32le(buf) + | ((uint64_t)br_dec32le(buf + 4) << 32); +#endif +} + +static inline uint64_t +br_dec64be(const void *src) +{ +#if BR_BE_UNALIGNED + return ((const br_union_u64 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((uint64_t)br_dec32be(buf) << 32) + | (uint64_t)br_dec32be(buf + 4); +#endif +} + +/* + * Range decoding and encoding (for several successive values). + */ +void br_range_dec16le(uint16_t *v, size_t num, const void *src); +void br_range_dec16be(uint16_t *v, size_t num, const void *src); +void br_range_enc16le(void *dst, const uint16_t *v, size_t num); +void br_range_enc16be(void *dst, const uint16_t *v, size_t num); + +void br_range_dec32le(uint32_t *v, size_t num, const void *src); +void br_range_dec32be(uint32_t *v, size_t num, const void *src); +void br_range_enc32le(void *dst, const uint32_t *v, size_t num); +void br_range_enc32be(void *dst, const uint32_t *v, size_t num); + +void br_range_dec64le(uint64_t *v, size_t num, const void *src); +void br_range_dec64be(uint64_t *v, size_t num, const void *src); +void br_range_enc64le(void *dst, const uint64_t *v, size_t num); +void br_range_enc64be(void *dst, const uint64_t *v, size_t num); + +/* + * Byte-swap a 32-bit integer. + */ +static inline uint32_t +br_swap32(uint32_t x) +{ + x = ((x & (uint32_t)0x00FF00FF) << 8) + | ((x >> 8) & (uint32_t)0x00FF00FF); + return (x << 16) | (x >> 16); +} + +/* ==================================================================== */ +/* + * Support code for hash functions. + */ + +/* + * IV for MD5, SHA-1, SHA-224 and SHA-256. + */ +extern const uint32_t br_md5_IV[]; +extern const uint32_t br_sha1_IV[]; +extern const uint32_t br_sha224_IV[]; +extern const uint32_t br_sha256_IV[]; + +/* + * Round functions for MD5, SHA-1, SHA-224 and SHA-256 (SHA-224 and + * SHA-256 use the same round function). + */ +void br_md5_round(const unsigned char *buf, uint32_t *val); +void br_sha1_round(const unsigned char *buf, uint32_t *val); +void br_sha2small_round(const unsigned char *buf, uint32_t *val); + +/* + * The core function for the TLS PRF. It computes + * P_hash(secret, label + seed), and XORs the result into the dst buffer. + */ +void br_tls_phash(void *dst, size_t len, + const br_hash_class *dig, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/* + * Copy all configured hash implementations from a multihash context + * to another. + */ +static inline void +br_multihash_copyimpl(br_multihash_context *dst, + const br_multihash_context *src) +{ + memcpy((void *)dst->impl, src->impl, sizeof src->impl); +} + +/* ==================================================================== */ +/* + * Constant-time primitives. These functions manipulate 32-bit values in + * order to provide constant-time comparisons and multiplexers. + * + * Boolean values (the "ctl" bits) MUST have value 0 or 1. + * + * Implementation notes: + * ===================== + * + * The uintN_t types are unsigned and with width exactly N bits; the C + * standard guarantees that computations are performed modulo 2^N, and + * there can be no overflow. Negation (unary '-') works on unsigned types + * as well. + * + * The intN_t types are guaranteed to have width exactly N bits, with no + * padding bit, and using two's complement representation. Casting + * intN_t to uintN_t really is conversion modulo 2^N. Beware that intN_t + * types, being signed, trigger implementation-defined behaviour on + * overflow (including raising some signal): with GCC, while modular + * arithmetics are usually applied, the optimizer may assume that + * overflows don't occur (unless the -fwrapv command-line option is + * added); Clang has the additional -ftrapv option to explicitly trap on + * integer overflow or underflow. + */ + +/* + * Negate a boolean. + */ +static inline uint32_t +NOT(uint32_t ctl) +{ + return ctl ^ 1; +} + +/* + * Multiplexer: returns x if ctl == 1, y if ctl == 0. + */ +static inline uint32_t +MUX(uint32_t ctl, uint32_t x, uint32_t y) +{ + return y ^ (-ctl & (x ^ y)); +} + +/* + * Equality check: returns 1 if x == y, 0 otherwise. + */ +static inline uint32_t +EQ(uint32_t x, uint32_t y) +{ + uint32_t q; + + q = x ^ y; + return NOT((q | -q) >> 31); +} + +/* + * Inequality check: returns 1 if x != y, 0 otherwise. + */ +static inline uint32_t +NEQ(uint32_t x, uint32_t y) +{ + uint32_t q; + + q = x ^ y; + return (q | -q) >> 31; +} + +/* + * Comparison: returns 1 if x > y, 0 otherwise. + */ +static inline uint32_t +GT(uint32_t x, uint32_t y) +{ + /* + * If both x < 2^31 and x < 2^31, then y-x will have its high + * bit set if x > y, cleared otherwise. + * + * If either x >= 2^31 or y >= 2^31 (but not both), then the + * result is the high bit of x. + * + * If both x >= 2^31 and y >= 2^31, then we can virtually + * subtract 2^31 from both, and we are back to the first case. + * Since (y-2^31)-(x-2^31) = y-x, the subtraction is already + * fine. + */ + uint32_t z; + + z = y - x; + return (z ^ ((x ^ y) & (x ^ z))) >> 31; +} + +/* + * Other comparisons (greater-or-equal, lower-than, lower-or-equal). + */ +#define GE(x, y) NOT(GT(y, x)) +#define LT(x, y) GT(y, x) +#define LE(x, y) NOT(GT(x, y)) + +/* + * General comparison: returned value is -1, 0 or 1, depending on + * whether x is lower than, equal to, or greater than y. + */ +static inline int32_t +CMP(uint32_t x, uint32_t y) +{ + return (int32_t)GT(x, y) | -(int32_t)GT(y, x); +} + +/* + * Returns 1 if x == 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +EQ0(int32_t x) +{ + uint32_t q; + + q = (uint32_t)x; + return ~(q | -q) >> 31; +} + +/* + * Returns 1 if x > 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +GT0(int32_t x) +{ + /* + * High bit of -x is 0 if x == 0, but 1 if x > 0. + */ + uint32_t q; + + q = (uint32_t)x; + return (~q & -q) >> 31; +} + +/* + * Returns 1 if x >= 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +GE0(int32_t x) +{ + return ~(uint32_t)x >> 31; +} + +/* + * Returns 1 if x < 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +LT0(int32_t x) +{ + return (uint32_t)x >> 31; +} + +/* + * Returns 1 if x <= 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +LE0(int32_t x) +{ + uint32_t q; + + /* + * ~-x has its high bit set if and only if -x is nonnegative (as + * a signed int), i.e. x is in the -(2^31-1) to 0 range. We must + * do an OR with x itself to account for x = -2^31. + */ + q = (uint32_t)x; + return (q | ~-q) >> 31; +} + +/* + * Conditional copy: src[] is copied into dst[] if and only if ctl is 1. + * dst[] and src[] may overlap completely (but not partially). + */ +void br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len); + +#define CCOPY br_ccopy + +/* + * Compute the bit length of a 32-bit integer. Returned value is between 0 + * and 32 (inclusive). + */ +static inline uint32_t +BIT_LENGTH(uint32_t x) +{ + uint32_t k, c; + + k = NEQ(x, 0); + c = GT(x, 0xFFFF); x = MUX(c, x >> 16, x); k += c << 4; + c = GT(x, 0x00FF); x = MUX(c, x >> 8, x); k += c << 3; + c = GT(x, 0x000F); x = MUX(c, x >> 4, x); k += c << 2; + c = GT(x, 0x0003); x = MUX(c, x >> 2, x); k += c << 1; + k += GT(x, 0x0001); + return k; +} + +/* + * Compute the minimum of x and y. + */ +static inline uint32_t +MIN(uint32_t x, uint32_t y) +{ + return MUX(GT(x, y), y, x); +} + +/* + * Compute the maximum of x and y. + */ +static inline uint32_t +MAX(uint32_t x, uint32_t y) +{ + return MUX(GT(x, y), x, y); +} + +/* + * Multiply two 32-bit integers, with a 64-bit result. This default + * implementation assumes that the basic multiplication operator + * yields constant-time code. + */ +#define MUL(x, y) ((uint64_t)(x) * (uint64_t)(y)) + +#if BR_CT_MUL31 + +/* + * Alternate implementation of MUL31, that will be constant-time on some + * (old) platforms where the default MUL31 is not. Unfortunately, it is + * also substantially slower, and yields larger code, on more modern + * platforms, which is why it is deactivated by default. + * + * MUL31_lo() must do some extra work because on some platforms, the + * _signed_ multiplication may return early if the top bits are 1. + * Simply truncating (casting) the output of MUL31() would not be + * sufficient, because the compiler may notice that we keep only the low + * word, and then replace automatically the unsigned multiplication with + * a signed multiplication opcode. + */ +#define MUL31(x, y) ((uint64_t)((x) | (uint32_t)0x80000000) \ + * (uint64_t)((y) | (uint32_t)0x80000000) \ + - ((uint64_t)(x) << 31) - ((uint64_t)(y) << 31) \ + - ((uint64_t)1 << 62)) +static inline uint32_t +MUL31_lo(uint32_t x, uint32_t y) +{ + uint32_t xl, xh; + uint32_t yl, yh; + + xl = (x & 0xFFFF) | (uint32_t)0x80000000; + xh = (x >> 16) | (uint32_t)0x80000000; + yl = (y & 0xFFFF) | (uint32_t)0x80000000; + yh = (y >> 16) | (uint32_t)0x80000000; + return (xl * yl + ((xl * yh + xh * yl) << 16)) & (uint32_t)0x7FFFFFFF; +} + +#else + +/* + * Multiply two 31-bit integers, with a 62-bit result. This default + * implementation assumes that the basic multiplication operator + * yields constant-time code. + * The MUL31_lo() macro returns only the low 31 bits of the product. + */ +#define MUL31(x, y) ((uint64_t)(x) * (uint64_t)(y)) +#define MUL31_lo(x, y) (((uint32_t)(x) * (uint32_t)(y)) & (uint32_t)0x7FFFFFFF) + +#endif + +/* + * Multiply two words together; the sum of the lengths of the two + * operands must not exceed 31 (for instance, one operand may use 16 + * bits if the other fits on 15). If BR_CT_MUL15 is non-zero, then the + * macro will contain some extra operations that help in making the + * operation constant-time on some platforms, where the basic 32-bit + * multiplication is not constant-time. + */ +#if BR_CT_MUL15 +#define MUL15(x, y) (((uint32_t)(x) | (uint32_t)0x80000000) \ + * ((uint32_t)(y) | (uint32_t)0x80000000) \ + & (uint32_t)0x7FFFFFFF) +#else +#define MUL15(x, y) ((uint32_t)(x) * (uint32_t)(y)) +#endif + +/* + * Arithmetic right shift (sign bit is copied). What happens when + * right-shifting a negative value is _implementation-defined_, so it + * does not trigger undefined behaviour, but it is still up to each + * compiler to define (and document) what it does. Most/all compilers + * will do an arithmetic shift, the sign bit being used to fill the + * holes; this is a native operation on the underlying CPU, and it would + * make little sense for the compiler to do otherwise. GCC explicitly + * documents that it follows that convention. + * + * Still, if BR_NO_ARITH_SHIFT is defined (and non-zero), then an + * alternate version will be used, that does not rely on such + * implementation-defined behaviour. Unfortunately, it is also slower + * and yields bigger code, which is why it is deactivated by default. + */ +#if BR_NO_ARITH_SHIFT +#define ARSH(x, n) (((uint32_t)(x) >> (n)) \ + | ((-((uint32_t)(x) >> 31)) << (32 - (n)))) +#else +#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n)) +#endif + +/* + * Constant-time division. The dividend hi:lo is divided by the + * divisor d; the quotient is returned and the remainder is written + * in *r. If hi == d, then the quotient does not fit on 32 bits; + * returned value is thus truncated. If hi > d, returned values are + * indeterminate. + */ +uint32_t br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r); + +/* + * Wrapper for br_divrem(); the remainder is returned, and the quotient + * is discarded. + */ +static inline uint32_t +br_rem(uint32_t hi, uint32_t lo, uint32_t d) +{ + uint32_t r; + + br_divrem(hi, lo, d, &r); + return r; +} + +/* + * Wrapper for br_divrem(); the quotient is returned, and the remainder + * is discarded. + */ +static inline uint32_t +br_div(uint32_t hi, uint32_t lo, uint32_t d) +{ + uint32_t r; + + return br_divrem(hi, lo, d, &r); +} + +/* ==================================================================== */ + +/* + * Integers 'i32' + * -------------- + * + * The 'i32' functions implement computations on big integers using + * an internal representation as an array of 32-bit integers. For + * an array x[]: + * -- x[0] contains the "announced bit length" of the integer + * -- x[1], x[2]... contain the value in little-endian order (x[1] + * contains the least significant 32 bits) + * + * Multiplications rely on the elementary 32x32->64 multiplication. + * + * The announced bit length specifies the number of bits that are + * significant in the subsequent 32-bit words. Unused bits in the + * last (most significant) word are set to 0; subsequent words are + * uninitialized and need not exist at all. + * + * The execution time and memory access patterns of all computations + * depend on the announced bit length, but not on the actual word + * values. For modular integers, the announced bit length of any integer + * modulo n is equal to the actual bit length of n; thus, computations + * on modular integers are "constant-time" (only the modulus length may + * leak). + */ + +/* + * Compute the actual bit length of an integer. The argument x should + * point to the first (least significant) value word of the integer. + * The len 'xlen' contains the number of 32-bit words to access. + * + * CT: value or length of x does not leak. + */ +uint32_t br_i32_bit_length(uint32_t *x, size_t xlen); + +/* + * Decode an integer from its big-endian unsigned representation. The + * "true" bit length of the integer is computed, but all words of x[] + * corresponding to the full 'len' bytes of the source are set. + * + * CT: value or length of x does not leak. + */ +void br_i32_decode(uint32_t *x, const void *src, size_t len); + +/* + * Decode an integer from its big-endian unsigned representation. The + * integer MUST be lower than m[]; the announced bit length written in + * x[] will be equal to that of m[]. All 'len' bytes from the source are + * read. + * + * Returned value is 1 if the decode value fits within the modulus, 0 + * otherwise. In the latter case, the x[] buffer will be set to 0 (but + * still with the announced bit length of m[]). + * + * CT: value or length of x does not leak. Memory access pattern depends + * only of 'len' and the announced bit length of m. Whether x fits or + * not does not leak either. + */ +uint32_t br_i32_decode_mod(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Reduce an integer (a[]) modulo another (m[]). The result is written + * in x[] and its announced bit length is set to be equal to that of m[]. + * + * x[] MUST be distinct from a[] and m[]. + * + * CT: only announced bit lengths leak, not values of x, a or m. + */ +void br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m); + +/* + * Decode an integer from its big-endian unsigned representation, and + * reduce it modulo the provided modulus m[]. The announced bit length + * of the result is set to be equal to that of the modulus. + * + * x[] MUST be distinct from m[]. + */ +void br_i32_decode_reduce(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Encode an integer into its big-endian unsigned representation. The + * output length in bytes is provided (parameter 'len'); if the length + * is too short then the integer is appropriately truncated; if it is + * too long then the extra bytes are set to 0. + */ +void br_i32_encode(void *dst, size_t len, const uint32_t *x); + +/* + * Multiply x[] by 2^32 and then add integer z, modulo m[]. This + * function assumes that x[] and m[] have the same announced bit + * length, and the announced bit length of m[] matches its true + * bit length. + * + * x[] and m[] MUST be distinct arrays. + * + * CT: only the common announced bit length of x and m leaks, not + * the values of x, z or m. + */ +void br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m); + +/* + * Extract one word from an integer. The offset is counted in bits. + * The word MUST entirely fit within the word elements corresponding + * to the announced bit length of a[]. + */ +static inline uint32_t +br_i32_word(const uint32_t *a, uint32_t off) +{ + size_t u; + unsigned j; + + u = (size_t)(off >> 5) + 1; + j = (unsigned)off & 31; + if (j == 0) { + return a[u]; + } else { + return (a[u] >> j) | (a[u + 1] << (32 - j)); + } +} + +/* + * Test whether an integer is zero. + */ +uint32_t br_i32_iszero(const uint32_t *x); + +/* + * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[] + * is unmodified, but the carry is still computed and returned. The + * arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0, + * then a[] is unmodified, but the carry is still computed and returned. + * The arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Compute d+a*b, result in d. The initial announced bit length of d[] + * MUST match that of a[]. The d[] array MUST be large enough to + * accommodate the full result, plus (possibly) an extra word. The + * resulting announced bit length of d[] will be the sum of the announced + * bit lengths of a[] and b[] (therefore, it may be larger than the actual + * bit length of the numerical result). + * + * a[] and b[] may be the same array. d[] must be disjoint from both a[] + * and b[]. + */ +void br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b); + +/* + * Zeroize an integer. The announced bit length is set to the provided + * value, and the corresponding words are set to 0. + */ +static inline void +br_i32_zero(uint32_t *x, uint32_t bit_len) +{ + *x ++ = bit_len; + memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x); +} + +/* + * Compute -(1/x) mod 2^32. If x is even, then this function returns 0. + */ +uint32_t br_i32_ninv32(uint32_t x); + +/* + * Convert a modular integer to Montgomery representation. The integer x[] + * MUST be lower than m[], but with the same announced bit length. + */ +void br_i32_to_monty(uint32_t *x, const uint32_t *m); + +/* + * Convert a modular integer back from Montgomery representation. The + * integer x[] MUST be lower than m[], but with the same announced bit + * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is + * the least significant value word of m[] (this works only if m[] is + * an odd integer). + */ +void br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i); + +/* + * Compute a modular Montgomery multiplication. d[] is filled with the + * value of x*y/R modulo m[] (where R is the Montgomery factor). The + * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be + * numerically lower than m[]. x[] and y[] MAY be the same array. The + * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). + */ +void br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i); + +/* + * Compute a modular exponentiation. x[] MUST be an integer modulo m[] + * (same announced bit length, lower value). m[] MUST be odd. The + * exponent is in big-endian unsigned notation, over 'elen' bytes. The + * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). The t1[] and t2[] parameters must be temporary arrays, + * each large enough to accommodate an integer with the same size as m[]. + */ +void br_i32_modpow(uint32_t *x, const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2); + +/* ==================================================================== */ + +/* + * Integers 'i31' + * -------------- + * + * The 'i31' functions implement computations on big integers using + * an internal representation as an array of 32-bit integers. For + * an array x[]: + * -- x[0] encodes the array length and the "announced bit length" + * of the integer: namely, if the announced bit length is k, + * then x[0] = ((k / 31) << 5) + (k % 31). + * -- x[1], x[2]... contain the value in little-endian order, 31 + * bits per word (x[1] contains the least significant 31 bits). + * The upper bit of each word is 0. + * + * Multiplications rely on the elementary 32x32->64 multiplication. + * + * The announced bit length specifies the number of bits that are + * significant in the subsequent 32-bit words. Unused bits in the + * last (most significant) word are set to 0; subsequent words are + * uninitialized and need not exist at all. + * + * The execution time and memory access patterns of all computations + * depend on the announced bit length, but not on the actual word + * values. For modular integers, the announced bit length of any integer + * modulo n is equal to the actual bit length of n; thus, computations + * on modular integers are "constant-time" (only the modulus length may + * leak). + */ + +/* + * Test whether an integer is zero. + */ +uint32_t br_i31_iszero(const uint32_t *x); + +/* + * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[] + * is unmodified, but the carry is still computed and returned. The + * arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0, + * then a[] is unmodified, but the carry is still computed and returned. + * The arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Compute the ENCODED actual bit length of an integer. The argument x + * should point to the first (least significant) value word of the + * integer. The len 'xlen' contains the number of 32-bit words to + * access. The upper bit of each value word MUST be 0. + * Returned value is ((k / 31) << 5) + (k % 31) if the bit length is k. + * + * CT: value or length of x does not leak. + */ +uint32_t br_i31_bit_length(uint32_t *x, size_t xlen); + +/* + * Decode an integer from its big-endian unsigned representation. The + * "true" bit length of the integer is computed and set in the encoded + * announced bit length (x[0]), but all words of x[] corresponding to + * the full 'len' bytes of the source are set. + * + * CT: value or length of x does not leak. + */ +void br_i31_decode(uint32_t *x, const void *src, size_t len); + +/* + * Decode an integer from its big-endian unsigned representation. The + * integer MUST be lower than m[]; the (encoded) announced bit length + * written in x[] will be equal to that of m[]. All 'len' bytes from the + * source are read. + * + * Returned value is 1 if the decode value fits within the modulus, 0 + * otherwise. In the latter case, the x[] buffer will be set to 0 (but + * still with the announced bit length of m[]). + * + * CT: value or length of x does not leak. Memory access pattern depends + * only of 'len' and the announced bit length of m. Whether x fits or + * not does not leak either. + */ +uint32_t br_i31_decode_mod(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Zeroize an integer. The announced bit length is set to the provided + * value, and the corresponding words are set to 0. The ENCODED bit length + * is expected here. + */ +static inline void +br_i31_zero(uint32_t *x, uint32_t bit_len) +{ + *x ++ = bit_len; + memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x); +} + +/* + * Right-shift an integer. The shift amount must be lower than 31 + * bits. + */ +void br_i31_rshift(uint32_t *x, int count); + +/* + * Reduce an integer (a[]) modulo another (m[]). The result is written + * in x[] and its announced bit length is set to be equal to that of m[]. + * + * x[] MUST be distinct from a[] and m[]. + * + * CT: only announced bit lengths leak, not values of x, a or m. + */ +void br_i31_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m); + +/* + * Decode an integer from its big-endian unsigned representation, and + * reduce it modulo the provided modulus m[]. The announced bit length + * of the result is set to be equal to that of the modulus. + * + * x[] MUST be distinct from m[]. + */ +void br_i31_decode_reduce(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Multiply x[] by 2^31 and then add integer z, modulo m[]. This + * function assumes that x[] and m[] have the same announced bit + * length, the announced bit length of m[] matches its true + * bit length. + * + * x[] and m[] MUST be distinct arrays. z MUST fit in 31 bits (upper + * bit set to 0). + * + * CT: only the common announced bit length of x and m leaks, not + * the values of x, z or m. + */ +void br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m); + +/* + * Encode an integer into its big-endian unsigned representation. The + * output length in bytes is provided (parameter 'len'); if the length + * is too short then the integer is appropriately truncated; if it is + * too long then the extra bytes are set to 0. + */ +void br_i31_encode(void *dst, size_t len, const uint32_t *x); + +/* + * Compute -(1/x) mod 2^31. If x is even, then this function returns 0. + */ +uint32_t br_i31_ninv31(uint32_t x); + +/* + * Compute a modular Montgomery multiplication. d[] is filled with the + * value of x*y/R modulo m[] (where R is the Montgomery factor). The + * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be + * numerically lower than m[]. x[] and y[] MAY be the same array. The + * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). + */ +void br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i); + +/* + * Convert a modular integer to Montgomery representation. The integer x[] + * MUST be lower than m[], but with the same announced bit length. + */ +void br_i31_to_monty(uint32_t *x, const uint32_t *m); + +/* + * Convert a modular integer back from Montgomery representation. The + * integer x[] MUST be lower than m[], but with the same announced bit + * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is + * the least significant value word of m[] (this works only if m[] is + * an odd integer). + */ +void br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i); + +/* + * Compute a modular exponentiation. x[] MUST be an integer modulo m[] + * (same announced bit length, lower value). m[] MUST be odd. The + * exponent is in big-endian unsigned notation, over 'elen' bytes. The + * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). The t1[] and t2[] parameters must be temporary arrays, + * each large enough to accommodate an integer with the same size as m[]. + */ +void br_i31_modpow(uint32_t *x, const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2); + +/* + * Compute a modular exponentiation. x[] MUST be an integer modulo m[] + * (same announced bit length, lower value). m[] MUST be odd. The + * exponent is in big-endian unsigned notation, over 'elen' bytes. The + * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). The tmp[] array is used for temporaries, and has size + * 'twlen' words; it must be large enough to accommodate at least two + * temporary values with the same size as m[] (including the leading + * "bit length" word). If there is room for more temporaries, then this + * function may use the extra room for window-based optimisation, + * resulting in faster computations. + * + * Returned value is 1 on success, 0 on error. An error is reported if + * the provided tmp[] array is too short. + */ +uint32_t br_i31_modpow_opt(uint32_t *x, const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen); + +/* + * Compute d+a*b, result in d. The initial announced bit length of d[] + * MUST match that of a[]. The d[] array MUST be large enough to + * accommodate the full result, plus (possibly) an extra word. The + * resulting announced bit length of d[] will be the sum of the announced + * bit lengths of a[] and b[] (therefore, it may be larger than the actual + * bit length of the numerical result). + * + * a[] and b[] may be the same array. d[] must be disjoint from both a[] + * and b[]. + */ +void br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b); + +/* + * Compute x/y mod m, result in x. Values x and y must be between 0 and + * m-1, and have the same announced bit length as m. Modulus m must be + * odd. The "m0i" parameter is equal to -1/m mod 2^31. The array 't' + * must point to a temporary area that can hold at least three integers + * of the size of m. + * + * m may not overlap x and y. x and y may overlap each other (this can + * be useful to test whether a value is invertible modulo m). t must be + * disjoint from all other arrays. + * + * Returned value is 1 on success, 0 otherwise. Success is attained if + * y is invertible modulo m. + */ +uint32_t br_i31_moddiv(uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i, uint32_t *t); + +/* ==================================================================== */ + +/* + * FIXME: document "i15" functions. + */ + +static inline void +br_i15_zero(uint16_t *x, uint16_t bit_len) +{ + *x ++ = bit_len; + memset(x, 0, ((bit_len + 15) >> 4) * sizeof *x); +} + +uint32_t br_i15_iszero(const uint16_t *x); + +uint16_t br_i15_ninv15(uint16_t x); + +uint32_t br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl); + +uint32_t br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl); + +void br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m); + +void br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y, + const uint16_t *m, uint16_t m0i); + +void br_i15_to_monty(uint16_t *x, const uint16_t *m); + +void br_i15_modpow(uint16_t *x, const unsigned char *e, size_t elen, + const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2); + +uint32_t br_i15_modpow_opt(uint16_t *x, const unsigned char *e, size_t elen, + const uint16_t *m, uint16_t m0i, uint16_t *tmp, size_t twlen); + +void br_i15_encode(void *dst, size_t len, const uint16_t *x); + +uint32_t br_i15_decode_mod(uint16_t *x, + const void *src, size_t len, const uint16_t *m); + +void br_i15_rshift(uint16_t *x, int count); + +uint32_t br_i15_bit_length(uint16_t *x, size_t xlen); + +void br_i15_decode(uint16_t *x, const void *src, size_t len); + +void br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i); + +void br_i15_decode_reduce(uint16_t *x, + const void *src, size_t len, const uint16_t *m); + +void br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m); + +void br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b); + +uint32_t br_i15_moddiv(uint16_t *x, const uint16_t *y, + const uint16_t *m, uint16_t m0i, uint16_t *t); + +/* + * Variant of br_i31_modpow_opt() that internally uses 64x64->128 + * multiplications. It expects the same parameters as br_i31_modpow_opt(), + * except that the temporaries should be 64-bit integers, not 32-bit + * integers. + */ +uint32_t br_i62_modpow_opt(uint32_t *x31, const unsigned char *e, size_t elen, + const uint32_t *m31, uint32_t m0i31, uint64_t *tmp, size_t twlen); + +/* + * Type for a function with the same API as br_i31_modpow_opt() (some + * implementations of this type may have stricter alignment requirements + * on the temporaries). + */ +typedef uint32_t (*br_i31_modpow_opt_type)(uint32_t *x, + const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen); + +/* + * Wrapper for br_i62_modpow_opt() that uses the same type as + * br_i31_modpow_opt(); however, it requires its 'tmp' argument to the + * 64-bit aligned. + */ +uint32_t br_i62_modpow_opt_as_i31(uint32_t *x, + const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen); + +/* ==================================================================== */ + +static inline size_t +br_digest_size(const br_hash_class *digest_class) +{ + return (size_t)(digest_class->desc >> BR_HASHDESC_OUT_OFF) + & BR_HASHDESC_OUT_MASK; +} + +/* + * Get the output size (in bytes) of a hash function. + */ +size_t br_digest_size_by_ID(int digest_id); + +/* + * Get the OID (encoded OBJECT IDENTIFIER value, without tag and length) + * for a hash function. If digest_id is not a supported digest identifier + * (in particular if it is equal to 0, i.e. br_md5sha1_ID), then NULL is + * returned and *len is set to 0. + */ +const unsigned char *br_digest_OID(int digest_id, size_t *len); + +/* ==================================================================== */ +/* + * DES support functions. + */ + +/* + * Apply DES Initial Permutation. + */ +void br_des_do_IP(uint32_t *xl, uint32_t *xr); + +/* + * Apply DES Final Permutation (inverse of IP). + */ +void br_des_do_invIP(uint32_t *xl, uint32_t *xr); + +/* + * Key schedule unit: for a DES key (8 bytes), compute 16 subkeys. Each + * subkey is two 28-bit words represented as two 32-bit words; the PC-2 + * bit extration is NOT applied. + */ +void br_des_keysched_unit(uint32_t *skey, const void *key); + +/* + * Reversal of 16 DES sub-keys (for decryption). + */ +void br_des_rev_skey(uint32_t *skey); + +/* + * DES/3DES key schedule for 'des_tab' (encryption direction). Returned + * value is the number of rounds. + */ +unsigned br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len); + +/* + * DES/3DES key schedule for 'des_ct' (encryption direction). Returned + * value is the number of rounds. + */ +unsigned br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len); + +/* + * DES/3DES subkey decompression (from the compressed bitsliced subkeys). + */ +void br_des_ct_skey_expand(uint32_t *sk_exp, + unsigned num_rounds, const uint32_t *skey); + +/* + * DES/3DES block encryption/decryption ('des_tab'). + */ +void br_des_tab_process_block(unsigned num_rounds, + const uint32_t *skey, void *block); + +/* + * DES/3DES block encryption/decryption ('des_ct'). + */ +void br_des_ct_process_block(unsigned num_rounds, + const uint32_t *skey, void *block); + +/* ==================================================================== */ +/* + * AES support functions. + */ + +/* + * The AES S-box (256-byte table). + */ +extern const unsigned char br_aes_S[]; + +/* + * AES key schedule. skey[] is filled with n+1 128-bit subkeys, where n + * is the number of rounds (10 to 14, depending on key size). The number + * of rounds is returned. If the key size is invalid (not 16, 24 or 32), + * then 0 is returned. + * + * This implementation uses a 256-byte table and is NOT constant-time. + */ +unsigned br_aes_keysched(uint32_t *skey, const void *key, size_t key_len); + +/* + * AES key schedule for decryption ('aes_big' implementation). + */ +unsigned br_aes_big_keysched_inv(uint32_t *skey, + const void *key, size_t key_len); + +/* + * AES block encryption with the 'aes_big' implementation (fast, but + * not constant-time). This function encrypts a single block "in place". + */ +void br_aes_big_encrypt(unsigned num_rounds, const uint32_t *skey, void *data); + +/* + * AES block decryption with the 'aes_big' implementation (fast, but + * not constant-time). This function decrypts a single block "in place". + */ +void br_aes_big_decrypt(unsigned num_rounds, const uint32_t *skey, void *data); + +/* + * AES block encryption with the 'aes_small' implementation (small, but + * slow and not constant-time). This function encrypts a single block + * "in place". + */ +void br_aes_small_encrypt(unsigned num_rounds, + const uint32_t *skey, void *data); + +/* + * AES block decryption with the 'aes_small' implementation (small, but + * slow and not constant-time). This function decrypts a single block + * "in place". + */ +void br_aes_small_decrypt(unsigned num_rounds, + const uint32_t *skey, void *data); + +/* + * The constant-time implementation is "bitsliced": the 128-bit state is + * split over eight 32-bit words q* in the following way: + * + * -- Input block consists in 16 bytes: + * a00 a10 a20 a30 a01 a11 a21 a31 a02 a12 a22 a32 a03 a13 a23 a33 + * In the terminology of FIPS 197, this is a 4x4 matrix which is read + * column by column. + * + * -- Each byte is split into eight bits which are distributed over the + * eight words, at the same rank. Thus, for a byte x at rank k, bit 0 + * (least significant) of x will be at rank k in q0 (if that bit is b, + * then it contributes "b << k" to the value of q0), bit 1 of x will be + * at rank k in q1, and so on. + * + * -- Ranks given to bits are in "row order" and are either all even, or + * all odd. Two independent AES states are thus interleaved, one using + * the even ranks, the other the odd ranks. Row order means: + * a00 a01 a02 a03 a10 a11 a12 a13 a20 a21 a22 a23 a30 a31 a32 a33 + * + * Converting input bytes from two AES blocks to bitslice representation + * is done in the following way: + * -- Decode first block into the four words q0 q2 q4 q6, in that order, + * using little-endian convention. + * -- Decode second block into the four words q1 q3 q5 q7, in that order, + * using little-endian convention. + * -- Call br_aes_ct_ortho(). + * + * Converting back to bytes is done by using the reverse operations. Note + * that br_aes_ct_ortho() is its own inverse. + */ + +/* + * Perform bytewise orthogonalization of eight 32-bit words. Bytes + * of q0..q7 are spread over all words: for a byte x that occurs + * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit + * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j. + * + * This operation is an involution. + */ +void br_aes_ct_ortho(uint32_t *q); + +/* + * The AES S-box, as a bitsliced constant-time version. The input array + * consists in eight 32-bit words; 32 S-box instances are computed in + * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant) + * are spread over the words 0 to 7, at the same rank. + */ +void br_aes_ct_bitslice_Sbox(uint32_t *q); + +/* + * Like br_aes_bitslice_Sbox(), but for the inverse S-box. + */ +void br_aes_ct_bitslice_invSbox(uint32_t *q); + +/* + * Compute AES encryption on bitsliced data. Since input is stored on + * eight 32-bit words, two block encryptions are actually performed + * in parallel. + */ +void br_aes_ct_bitslice_encrypt(unsigned num_rounds, + const uint32_t *skey, uint32_t *q); + +/* + * Compute AES decryption on bitsliced data. Since input is stored on + * eight 32-bit words, two block decryptions are actually performed + * in parallel. + */ +void br_aes_ct_bitslice_decrypt(unsigned num_rounds, + const uint32_t *skey, uint32_t *q); + +/* + * AES key schedule, constant-time version. skey[] is filled with n+1 + * 128-bit subkeys, where n is the number of rounds (10 to 14, depending + * on key size). The number of rounds is returned. If the key size is + * invalid (not 16, 24 or 32), then 0 is returned. + */ +unsigned br_aes_ct_keysched(uint32_t *comp_skey, + const void *key, size_t key_len); + +/* + * Expand AES subkeys as produced by br_aes_ct_keysched(), into + * a larger array suitable for br_aes_ct_bitslice_encrypt() and + * br_aes_ct_bitslice_decrypt(). + */ +void br_aes_ct_skey_expand(uint32_t *skey, + unsigned num_rounds, const uint32_t *comp_skey); + +/* + * For the ct64 implementation, the same bitslicing technique is used, + * but four instances are interleaved. First instance uses bits 0, 4, + * 8, 12,... of each word; second instance uses bits 1, 5, 9, 13,... + * and so on. + */ + +/* + * Perform bytewise orthogonalization of eight 64-bit words. Bytes + * of q0..q7 are spread over all words: for a byte x that occurs + * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit + * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j. + * + * This operation is an involution. + */ +void br_aes_ct64_ortho(uint64_t *q); + +/* + * Interleave bytes for an AES input block. If input bytes are + * denoted 0123456789ABCDEF, and have been decoded with little-endian + * convention (w[0] contains 0123, with '3' being most significant; + * w[1] contains 4567, and so on), then output word q0 will be + * set to 08192A3B (again little-endian convention) and q1 will + * be set to 4C5D6E7F. + */ +void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w); + +/* + * Perform the opposite of br_aes_ct64_interleave_in(). + */ +void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1); + +/* + * The AES S-box, as a bitsliced constant-time version. The input array + * consists in eight 64-bit words; 64 S-box instances are computed in + * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant) + * are spread over the words 0 to 7, at the same rank. + */ +void br_aes_ct64_bitslice_Sbox(uint64_t *q); + +/* + * Like br_aes_bitslice_Sbox(), but for the inverse S-box. + */ +void br_aes_ct64_bitslice_invSbox(uint64_t *q); + +/* + * Compute AES encryption on bitsliced data. Since input is stored on + * eight 64-bit words, four block encryptions are actually performed + * in parallel. + */ +void br_aes_ct64_bitslice_encrypt(unsigned num_rounds, + const uint64_t *skey, uint64_t *q); + +/* + * Compute AES decryption on bitsliced data. Since input is stored on + * eight 64-bit words, four block decryptions are actually performed + * in parallel. + */ +void br_aes_ct64_bitslice_decrypt(unsigned num_rounds, + const uint64_t *skey, uint64_t *q); + +/* + * AES key schedule, constant-time version. skey[] is filled with n+1 + * 128-bit subkeys, where n is the number of rounds (10 to 14, depending + * on key size). The number of rounds is returned. If the key size is + * invalid (not 16, 24 or 32), then 0 is returned. + */ +unsigned br_aes_ct64_keysched(uint64_t *comp_skey, + const void *key, size_t key_len); + +/* + * Expand AES subkeys as produced by br_aes_ct64_keysched(), into + * a larger array suitable for br_aes_ct64_bitslice_encrypt() and + * br_aes_ct64_bitslice_decrypt(). + */ +void br_aes_ct64_skey_expand(uint64_t *skey, + unsigned num_rounds, const uint64_t *comp_skey); + +/* + * Test support for AES-NI opcodes. + */ +int br_aes_x86ni_supported(void); + +/* + * AES key schedule, using x86 AES-NI instructions. This yields the + * subkeys in the encryption direction. Number of rounds is returned. + * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned. + */ +unsigned br_aes_x86ni_keysched_enc(unsigned char *skni, + const void *key, size_t len); + +/* + * AES key schedule, using x86 AES-NI instructions. This yields the + * subkeys in the decryption direction. Number of rounds is returned. + * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned. + */ +unsigned br_aes_x86ni_keysched_dec(unsigned char *skni, + const void *key, size_t len); + +/* + * Test support for AES POWER8 opcodes. + */ +int br_aes_pwr8_supported(void); + +/* + * AES key schedule, using POWER8 instructions. This yields the + * subkeys in the encryption direction. Number of rounds is returned. + * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned. + */ +unsigned br_aes_pwr8_keysched(unsigned char *skni, + const void *key, size_t len); + +/* ==================================================================== */ +/* + * RSA. + */ + +/* + * Apply proper PKCS#1 v1.5 padding (for signatures). 'hash_oid' is + * the encoded hash function OID, or NULL. + */ +uint32_t br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + uint32_t n_bitlen, unsigned char *x); + +/* + * Check PKCS#1 v1.5 padding (for signatures). 'hash_oid' is the encoded + * hash function OID, or NULL. The provided 'sig' value is _after_ the + * modular exponentiation, i.e. it should be the padded hash. On + * success, the hashed message is extracted. + */ +uint32_t br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len, + const unsigned char *hash_oid, size_t hash_len, + unsigned char *hash_out); + +/* + * Apply OAEP padding. Returned value is the actual padded string length, + * or zero on error. + */ +size_t br_rsa_oaep_pad(const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, const br_rsa_public_key *pk, + void *dst, size_t dst_nax_len, const void *src, size_t src_len); + +/* + * Unravel and check OAEP padding. If the padding is correct, then 1 is + * returned, '*len' is adjusted to the length of the message, and the + * data is moved to the start of the 'data' buffer. If the padding is + * incorrect, then 0 is returned and '*len' is untouched. Either way, + * the complete buffer contents are altered. + */ +uint32_t br_rsa_oaep_unpad(const br_hash_class *dig, + const void *label, size_t label_len, void *data, size_t *len); + +/* + * Compute MGF1 for a given seed, and XOR the output into the provided + * buffer. + */ +void br_mgf1_xor(void *data, size_t len, + const br_hash_class *dig, const void *seed, size_t seed_len); + +/* + * Inner function for RSA key generation; used by the "i31" and "i62" + * implementations. + */ +uint32_t br_rsa_i31_keygen_inner(const br_prng_class **rng, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp, br_i31_modpow_opt_type mp31); + +/* ==================================================================== */ +/* + * Elliptic curves. + */ + +/* + * Type for generic EC parameters: curve order (unsigned big-endian + * encoding) and encoded conventional generator. + */ +typedef struct { + int curve; + const unsigned char *order; + size_t order_len; + const unsigned char *generator; + size_t generator_len; +} br_ec_curve_def; + +extern const br_ec_curve_def br_secp256r1; +extern const br_ec_curve_def br_secp384r1; +extern const br_ec_curve_def br_secp521r1; + +/* + * For Curve25519, the advertised "order" really is 2^255-1, since the + * point multipliction function really works over arbitrary 255-bit + * scalars. This value is only meant as a hint for ECDH key generation; + * only ECDSA uses the exact curve order, and ECDSA is not used with + * that specific curve. + */ +extern const br_ec_curve_def br_curve25519; + +/* + * Decode some bytes as an i31 integer, with truncation (corresponding + * to the 'bits2int' operation in RFC 6979). The target ENCODED bit + * length is provided as last parameter. The resulting value will have + * this declared bit length, and consists the big-endian unsigned decoding + * of exactly that many bits in the source (capped at the source length). + */ +void br_ecdsa_i31_bits2int(uint32_t *x, + const void *src, size_t len, uint32_t ebitlen); + +/* + * Decode some bytes as an i15 integer, with truncation (corresponding + * to the 'bits2int' operation in RFC 6979). The target ENCODED bit + * length is provided as last parameter. The resulting value will have + * this declared bit length, and consists the big-endian unsigned decoding + * of exactly that many bits in the source (capped at the source length). + */ +void br_ecdsa_i15_bits2int(uint16_t *x, + const void *src, size_t len, uint32_t ebitlen); + +/* ==================================================================== */ +/* + * ASN.1 support functions. + */ + +/* + * A br_asn1_uint structure contains encoding information about an + * INTEGER nonnegative value: pointer to the integer contents (unsigned + * big-endian representation), length of the integer contents, + * and length of the encoded value. The data shall have minimal length: + * - If the integer value is zero, then 'len' must be zero. + * - If the integer value is not zero, then data[0] must be non-zero. + * + * Under these conditions, 'asn1len' is necessarily equal to either len + * or len+1. + */ +typedef struct { + const unsigned char *data; + size_t len; + size_t asn1len; +} br_asn1_uint; + +/* + * Given an encoded integer (unsigned big-endian, with possible leading + * bytes of value 0), returned the "prepared INTEGER" structure. + */ +br_asn1_uint br_asn1_uint_prepare(const void *xdata, size_t xlen); + +/* + * Encode an ASN.1 length. The length of the encoded length is returned. + * If 'dest' is NULL, then no encoding is performed, but the length of + * the encoded length is still computed and returned. + */ +size_t br_asn1_encode_length(void *dest, size_t len); + +/* + * Convenient macro for computing lengths of lengths. + */ +#define len_of_len(len) br_asn1_encode_length(NULL, len) + +/* + * Encode a (prepared) ASN.1 INTEGER. The encoded length is returned. + * If 'dest' is NULL, then no encoding is performed, but the length of + * the encoded integer is still computed and returned. + */ +size_t br_asn1_encode_uint(void *dest, br_asn1_uint pp); + +/* + * Get the OID that identifies an elliptic curve. Returned value is + * the DER-encoded OID, with the length (always one byte) but without + * the tag. Thus, the first byte of the returned buffer contains the + * number of subsequent bytes in the value. If the curve is not + * recognised, NULL is returned. + */ +const unsigned char *br_get_curve_OID(int curve); + +/* + * Inner function for EC private key encoding. This is equivalent to + * the API function br_encode_ec_raw_der(), except for an extra + * parameter: if 'include_curve_oid' is zero, then the curve OID is + * _not_ included in the output blob (this is for PKCS#8 support). + */ +size_t br_encode_ec_raw_der_inner(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk, + int include_curve_oid); + +/* ==================================================================== */ +/* + * SSL/TLS support functions. + */ + +/* + * Record types. + */ +#define BR_SSL_CHANGE_CIPHER_SPEC 20 +#define BR_SSL_ALERT 21 +#define BR_SSL_HANDSHAKE 22 +#define BR_SSL_APPLICATION_DATA 23 + +/* + * Handshake message types. + */ +#define BR_SSL_HELLO_REQUEST 0 +#define BR_SSL_CLIENT_HELLO 1 +#define BR_SSL_SERVER_HELLO 2 +#define BR_SSL_CERTIFICATE 11 +#define BR_SSL_SERVER_KEY_EXCHANGE 12 +#define BR_SSL_CERTIFICATE_REQUEST 13 +#define BR_SSL_SERVER_HELLO_DONE 14 +#define BR_SSL_CERTIFICATE_VERIFY 15 +#define BR_SSL_CLIENT_KEY_EXCHANGE 16 +#define BR_SSL_FINISHED 20 + +/* + * Alert levels. + */ +#define BR_LEVEL_WARNING 1 +#define BR_LEVEL_FATAL 2 + +/* + * Low-level I/O state. + */ +#define BR_IO_FAILED 0 +#define BR_IO_IN 1 +#define BR_IO_OUT 2 +#define BR_IO_INOUT 3 + +/* + * Mark a SSL engine as failed. The provided error code is recorded if + * the engine was not already marked as failed. If 'err' is 0, then the + * engine is marked as closed (without error). + */ +void br_ssl_engine_fail(br_ssl_engine_context *cc, int err); + +/* + * Test whether the engine is closed (normally or as a failure). + */ +static inline int +br_ssl_engine_closed(const br_ssl_engine_context *cc) +{ + return cc->iomode == BR_IO_FAILED; +} + +/* + * Configure a new maximum fragment length. If possible, the maximum + * length for outgoing records is immediately adjusted (if there are + * not already too many buffered bytes for that). + */ +void br_ssl_engine_new_max_frag_len( + br_ssl_engine_context *rc, unsigned max_frag_len); + +/* + * Test whether the current incoming record has been fully received + * or not. This functions returns 0 only if a complete record header + * has been received, but some of the (possibly encrypted) payload + * has not yet been obtained. + */ +int br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc); + +/* + * Flush the current record (if not empty). This is meant to be called + * from the handshake processor only. + */ +void br_ssl_engine_flush_record(br_ssl_engine_context *cc); + +/* + * Test whether there is some accumulated payload to send. + */ +static inline int +br_ssl_engine_has_pld_to_send(const br_ssl_engine_context *rc) +{ + return rc->oxa != rc->oxb && rc->oxa != rc->oxc; +} + +/* + * Initialize RNG in engine. Returned value is 1 on success, 0 on error. + * This function will try to use the OS-provided RNG, if available. If + * there is no OS-provided RNG, or if it failed, and no entropy was + * injected by the caller, then a failure will be reported. On error, + * the context error code is set. + */ +int br_ssl_engine_init_rand(br_ssl_engine_context *cc); + +/* + * Reset the handshake-related parts of the engine. + */ +void br_ssl_engine_hs_reset(br_ssl_engine_context *cc, + void (*hsinit)(void *), void (*hsrun)(void *)); + +/* + * Get the PRF to use for this context, for the provided PRF hash + * function ID. + */ +br_tls_prf_impl br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id); + +/* + * Consume the provided pre-master secret and compute the corresponding + * master secret. The 'prf_id' is the ID of the hash function to use + * with the TLS 1.2 PRF (ignored if the version is TLS 1.0 or 1.1). + */ +void br_ssl_engine_compute_master(br_ssl_engine_context *cc, + int prf_id, const void *pms, size_t len); + +/* + * Switch to CBC decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF (ignored if not TLS 1.2+) + * mac_id id of hash function for HMAC + * bc_impl block cipher implementation (CBC decryption) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc, + int is_client, int prf_id, int mac_id, + const br_block_cbcdec_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to CBC encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF (ignored if not TLS 1.2+) + * mac_id id of hash function for HMAC + * bc_impl block cipher implementation (CBC encryption) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc, + int is_client, int prf_id, int mac_id, + const br_block_cbcenc_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to GCM decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctr_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to GCM encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctr_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to ChaCha20+Poly1305 decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + */ +void br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc, + int is_client, int prf_id); + +/* + * Switch to ChaCha20+Poly1305 encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + */ +void br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc, + int is_client, int prf_id); + +/* + * Switch to CCM decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR+CBC) + * cipher_key_len block cipher key length (in bytes) + * tag_len tag length (in bytes) + */ +void br_ssl_engine_switch_ccm_in(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctrcbc_class *bc_impl, + size_t cipher_key_len, size_t tag_len); + +/* + * Switch to GCM encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR+CBC) + * cipher_key_len block cipher key length (in bytes) + * tag_len tag length (in bytes) + */ +void br_ssl_engine_switch_ccm_out(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctrcbc_class *bc_impl, + size_t cipher_key_len, size_t tag_len); + +/* + * Calls to T0-generated code. + */ +void br_ssl_hs_client_init_main(void *ctx); +void br_ssl_hs_client_run(void *ctx); +void br_ssl_hs_server_init_main(void *ctx); +void br_ssl_hs_server_run(void *ctx); + +/* + * Get the hash function to use for signatures, given a bit mask of + * supported hash functions. This implements a strict choice order + * (namely SHA-256, SHA-384, SHA-512, SHA-224, SHA-1). If the mask + * does not document support of any of these hash functions, then this + * functions returns 0. + */ +int br_ssl_choose_hash(unsigned bf); + +/* ==================================================================== */ + +/* + * PowerPC / POWER assembly stuff. The special BR_POWER_ASM_MACROS macro + * must be defined before including this file; this is done by source + * files that use some inline assembly for PowerPC / POWER machines. + */ + +#if BR_POWER_ASM_MACROS + +#define lxvw4x(xt, ra, rb) lxvw4x_(xt, ra, rb) +#define stxvw4x(xt, ra, rb) stxvw4x_(xt, ra, rb) + +#define bdnz(foo) bdnz_(foo) +#define bdz(foo) bdz_(foo) +#define beq(foo) beq_(foo) + +#define li(rx, value) li_(rx, value) +#define addi(rx, ra, imm) addi_(rx, ra, imm) +#define cmpldi(rx, imm) cmpldi_(rx, imm) +#define mtctr(rx) mtctr_(rx) +#define vspltb(vrt, vrb, uim) vspltb_(vrt, vrb, uim) +#define vspltw(vrt, vrb, uim) vspltw_(vrt, vrb, uim) +#define vspltisb(vrt, imm) vspltisb_(vrt, imm) +#define vspltisw(vrt, imm) vspltisw_(vrt, imm) +#define vrlw(vrt, vra, vrb) vrlw_(vrt, vra, vrb) +#define vsbox(vrt, vra) vsbox_(vrt, vra) +#define vxor(vrt, vra, vrb) vxor_(vrt, vra, vrb) +#define vand(vrt, vra, vrb) vand_(vrt, vra, vrb) +#define vsro(vrt, vra, vrb) vsro_(vrt, vra, vrb) +#define vsl(vrt, vra, vrb) vsl_(vrt, vra, vrb) +#define vsldoi(vt, va, vb, sh) vsldoi_(vt, va, vb, sh) +#define vsr(vrt, vra, vrb) vsr_(vrt, vra, vrb) +#define vaddcuw(vrt, vra, vrb) vaddcuw_(vrt, vra, vrb) +#define vadduwm(vrt, vra, vrb) vadduwm_(vrt, vra, vrb) +#define vsububm(vrt, vra, vrb) vsububm_(vrt, vra, vrb) +#define vsubuwm(vrt, vra, vrb) vsubuwm_(vrt, vra, vrb) +#define vsrw(vrt, vra, vrb) vsrw_(vrt, vra, vrb) +#define vcipher(vt, va, vb) vcipher_(vt, va, vb) +#define vcipherlast(vt, va, vb) vcipherlast_(vt, va, vb) +#define vncipher(vt, va, vb) vncipher_(vt, va, vb) +#define vncipherlast(vt, va, vb) vncipherlast_(vt, va, vb) +#define vperm(vt, va, vb, vc) vperm_(vt, va, vb, vc) +#define vpmsumd(vt, va, vb) vpmsumd_(vt, va, vb) +#define xxpermdi(vt, va, vb, d) xxpermdi_(vt, va, vb, d) + +#define lxvw4x_(xt, ra, rb) "\tlxvw4x\t" #xt "," #ra "," #rb "\n" +#define stxvw4x_(xt, ra, rb) "\tstxvw4x\t" #xt "," #ra "," #rb "\n" + +#define label(foo) #foo "%=:\n" +#define bdnz_(foo) "\tbdnz\t" #foo "%=\n" +#define bdz_(foo) "\tbdz\t" #foo "%=\n" +#define beq_(foo) "\tbeq\t" #foo "%=\n" + +#define li_(rx, value) "\tli\t" #rx "," #value "\n" +#define addi_(rx, ra, imm) "\taddi\t" #rx "," #ra "," #imm "\n" +#define cmpldi_(rx, imm) "\tcmpldi\t" #rx "," #imm "\n" +#define mtctr_(rx) "\tmtctr\t" #rx "\n" +#define vspltb_(vrt, vrb, uim) "\tvspltb\t" #vrt "," #vrb "," #uim "\n" +#define vspltw_(vrt, vrb, uim) "\tvspltw\t" #vrt "," #vrb "," #uim "\n" +#define vspltisb_(vrt, imm) "\tvspltisb\t" #vrt "," #imm "\n" +#define vspltisw_(vrt, imm) "\tvspltisw\t" #vrt "," #imm "\n" +#define vrlw_(vrt, vra, vrb) "\tvrlw\t" #vrt "," #vra "," #vrb "\n" +#define vsbox_(vrt, vra) "\tvsbox\t" #vrt "," #vra "\n" +#define vxor_(vrt, vra, vrb) "\tvxor\t" #vrt "," #vra "," #vrb "\n" +#define vand_(vrt, vra, vrb) "\tvand\t" #vrt "," #vra "," #vrb "\n" +#define vsro_(vrt, vra, vrb) "\tvsro\t" #vrt "," #vra "," #vrb "\n" +#define vsl_(vrt, vra, vrb) "\tvsl\t" #vrt "," #vra "," #vrb "\n" +#define vsldoi_(vt, va, vb, sh) "\tvsldoi\t" #vt "," #va "," #vb "," #sh "\n" +#define vsr_(vrt, vra, vrb) "\tvsr\t" #vrt "," #vra "," #vrb "\n" +#define vaddcuw_(vrt, vra, vrb) "\tvaddcuw\t" #vrt "," #vra "," #vrb "\n" +#define vadduwm_(vrt, vra, vrb) "\tvadduwm\t" #vrt "," #vra "," #vrb "\n" +#define vsububm_(vrt, vra, vrb) "\tvsububm\t" #vrt "," #vra "," #vrb "\n" +#define vsubuwm_(vrt, vra, vrb) "\tvsubuwm\t" #vrt "," #vra "," #vrb "\n" +#define vsrw_(vrt, vra, vrb) "\tvsrw\t" #vrt "," #vra "," #vrb "\n" +#define vcipher_(vt, va, vb) "\tvcipher\t" #vt "," #va "," #vb "\n" +#define vcipherlast_(vt, va, vb) "\tvcipherlast\t" #vt "," #va "," #vb "\n" +#define vncipher_(vt, va, vb) "\tvncipher\t" #vt "," #va "," #vb "\n" +#define vncipherlast_(vt, va, vb) "\tvncipherlast\t" #vt "," #va "," #vb "\n" +#define vperm_(vt, va, vb, vc) "\tvperm\t" #vt "," #va "," #vb "," #vc "\n" +#define vpmsumd_(vt, va, vb) "\tvpmsumd\t" #vt "," #va "," #vb "\n" +#define xxpermdi_(vt, va, vb, d) "\txxpermdi\t" #vt "," #va "," #vb "," #d "\n" + +#endif + +/* ==================================================================== */ +/* + * Special "activate intrinsics" code, needed for some compiler versions. + * This is defined at the end of this file, so that it won't impact any + * of the inline functions defined previously; and it is controlled by + * a specific macro defined in the caller code. + * + * Calling code conventions: + * + * - Caller must define BR_ENABLE_INTRINSICS before including "inner.h". + * - Functions that use intrinsics must be enclosed in an "enabled" + * region (between BR_TARGETS_X86_UP and BR_TARGETS_X86_DOWN). + * - Functions that use intrinsics must be tagged with the appropriate + * BR_TARGET(). + */ + +#if BR_ENABLE_INTRINSICS && (BR_GCC_4_4 || BR_CLANG_3_7 || BR_MSC_2005) + +/* + * x86 intrinsics (both 32-bit and 64-bit). + */ +#if BR_i386 || BR_amd64 + +/* + * On GCC before version 5.0, we need to use the pragma to enable the + * target options globally, because the 'target' function attribute + * appears to be unreliable. Before 4.6 we must also avoid the + * push_options / pop_options mechanism, because it tends to trigger + * some internal compiler errors. + */ +#if BR_GCC && !BR_GCC_5_0 +#if BR_GCC_4_6 +#define BR_TARGETS_X86_UP \ + _Pragma("GCC push_options") \ + _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul,rdrnd\")") +#define BR_TARGETS_X86_DOWN \ + _Pragma("GCC pop_options") +#else +#define BR_TARGETS_X86_UP \ + _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")") +#endif +#define BR_TARGETS_X86_DOWN +#pragma GCC diagnostic ignored "-Wpsabi" +#endif + +#if BR_CLANG && !BR_CLANG_3_8 +#undef __SSE2__ +#undef __SSE3__ +#undef __SSSE3__ +#undef __SSE4_1__ +#undef __AES__ +#undef __PCLMUL__ +#undef __RDRND__ +#define __SSE2__ 1 +#define __SSE3__ 1 +#define __SSSE3__ 1 +#define __SSE4_1__ 1 +#define __AES__ 1 +#define __PCLMUL__ 1 +#define __RDRND__ 1 +#endif + +#ifndef BR_TARGETS_X86_UP +#define BR_TARGETS_X86_UP +#endif +#ifndef BR_TARGETS_X86_DOWN +#define BR_TARGETS_X86_DOWN +#endif + +#if BR_GCC || BR_CLANG +BR_TARGETS_X86_UP +#include +#include +#define br_bswap32 __builtin_bswap32 +BR_TARGETS_X86_DOWN +#endif + +#if BR_MSC +#include +#include +#include +#define br_bswap32 _byteswap_ulong +#endif + +static inline int +br_cpuid(uint32_t mask_eax, uint32_t mask_ebx, + uint32_t mask_ecx, uint32_t mask_edx) +{ +#if BR_GCC || BR_CLANG + unsigned eax, ebx, ecx, edx; + + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { + if ((eax & mask_eax) == mask_eax + && (ebx & mask_ebx) == mask_ebx + && (ecx & mask_ecx) == mask_ecx + && (edx & mask_edx) == mask_edx) + { + return 1; + } + } +#elif BR_MSC + int info[4]; + + __cpuid(info, 1); + if (((uint32_t)info[0] & mask_eax) == mask_eax + && ((uint32_t)info[1] & mask_ebx) == mask_ebx + && ((uint32_t)info[2] & mask_ecx) == mask_ecx + && ((uint32_t)info[3] & mask_edx) == mask_edx) + { + return 1; + } +#endif + return 0; +} + +#endif + +#endif + +/* ==================================================================== */ + +#endif diff --git a/src/keywords.txt b/keywords.txt similarity index 100% rename from src/keywords.txt rename to keywords.txt diff --git a/src/bearssl/src/aead/ccm.c b/src/bearssl/src/aead/ccm.c new file mode 100644 index 0000000..68cc913 --- /dev/null +++ b/src/bearssl/src/aead/ccm.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Implementation Notes + * ==================== + * + * The combined CTR + CBC-MAC functions can only handle full blocks, + * so some buffering is necessary. + * + * - 'ptr' contains a value from 0 to 15, which is the number of bytes + * accumulated in buf[] that still needs to be processed with the + * current CBC-MAC computation. + * + * - When processing the message itself, CTR encryption/decryption is + * also done at the same time. The first 'ptr' bytes of buf[] then + * contains the plaintext bytes, while the last '16 - ptr' bytes of + * buf[] are the remnants of the stream block, to be used against + * the next input bytes, when available. When 'ptr' is 0, the + * contents of buf[] are to be ignored. + * + * - The current counter and running CBC-MAC values are kept in 'ctr' + * and 'cbcmac', respectively. + */ + +/* see bearssl_block.h */ +void +br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx) +{ + ctx->bctx = bctx; +} + +/* see bearssl_block.h */ +int +br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len, + uint64_t aad_len, uint64_t data_len, size_t tag_len) +{ + unsigned char tmp[16]; + unsigned u, q; + + if (nonce_len < 7 || nonce_len > 13) { + return 0; + } + if (tag_len < 4 || tag_len > 16 || (tag_len & 1) != 0) { + return 0; + } + q = 15 - (unsigned)nonce_len; + ctx->tag_len = tag_len; + + /* + * Block B0, to start CBC-MAC. + */ + tmp[0] = (aad_len > 0 ? 0x40 : 0x00) + | (((unsigned)tag_len - 2) << 2) + | (q - 1); + memcpy(tmp + 1, nonce, nonce_len); + for (u = 0; u < q; u ++) { + tmp[15 - u] = (unsigned char)data_len; + data_len >>= 8; + } + if (data_len != 0) { + /* + * If the data length was not entirely consumed in the + * loop above, then it exceeds the maximum limit of + * q bytes (when encoded). + */ + return 0; + } + + /* + * Start CBC-MAC. + */ + memset(ctx->cbcmac, 0, sizeof ctx->cbcmac); + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, tmp, sizeof tmp); + + /* + * Assemble AAD length header. + */ + if ((aad_len >> 32) != 0) { + ctx->buf[0] = 0xFF; + ctx->buf[1] = 0xFF; + br_enc64be(ctx->buf + 2, aad_len); + ctx->ptr = 10; + } else if (aad_len >= 0xFF00) { + ctx->buf[0] = 0xFF; + ctx->buf[1] = 0xFE; + br_enc32be(ctx->buf + 2, (uint32_t)aad_len); + ctx->ptr = 6; + } else if (aad_len > 0) { + br_enc16be(ctx->buf, (unsigned)aad_len); + ctx->ptr = 2; + } else { + ctx->ptr = 0; + } + + /* + * Make initial counter value and compute tag mask. + */ + ctx->ctr[0] = q - 1; + memcpy(ctx->ctr + 1, nonce, nonce_len); + memset(ctx->ctr + 1 + nonce_len, 0, q); + memset(ctx->tagmask, 0, sizeof ctx->tagmask); + (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, + ctx->tagmask, sizeof ctx->tagmask); + + return 1; +} + +/* see bearssl_block.h */ +void +br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len) +{ + const unsigned char *dbuf; + size_t ptr; + + dbuf = data; + + /* + * Complete partial block, if needed. + */ + ptr = ctx->ptr; + if (ptr != 0) { + size_t clen; + + clen = (sizeof ctx->buf) - ptr; + if (clen > len) { + memcpy(ctx->buf + ptr, dbuf, len); + ctx->ptr = ptr + len; + return; + } + memcpy(ctx->buf + ptr, dbuf, clen); + dbuf += clen; + len -= clen; + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, + ctx->buf, sizeof ctx->buf); + } + + /* + * Process complete blocks. + */ + ptr = len & 15; + len -= ptr; + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, dbuf, len); + dbuf += len; + + /* + * Copy last partial block in the context buffer. + */ + memcpy(ctx->buf, dbuf, ptr); + ctx->ptr = ptr; +} + +/* see bearssl_block.h */ +void +br_ccm_flip(br_ccm_context *ctx) +{ + size_t ptr; + + /* + * Complete AAD partial block with zeros, if necessary. + */ + ptr = ctx->ptr; + if (ptr != 0) { + memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr); + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, + ctx->buf, sizeof ctx->buf); + ctx->ptr = 0; + } + + /* + * Counter was already set by br_ccm_reset(). + */ +} + +/* see bearssl_block.h */ +void +br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len) +{ + unsigned char *dbuf; + size_t ptr; + + dbuf = data; + + /* + * Complete a partial block, if any: ctx->buf[] contains + * ctx->ptr plaintext bytes (already reported), and the other + * bytes are CTR stream output. + */ + ptr = ctx->ptr; + if (ptr != 0) { + size_t clen; + size_t u; + + clen = (sizeof ctx->buf) - ptr; + if (clen > len) { + clen = len; + } + if (encrypt) { + for (u = 0; u < clen; u ++) { + unsigned w, x; + + w = ctx->buf[ptr + u]; + x = dbuf[u]; + ctx->buf[ptr + u] = x; + dbuf[u] = w ^ x; + } + } else { + for (u = 0; u < clen; u ++) { + unsigned w; + + w = ctx->buf[ptr + u] ^ dbuf[u]; + dbuf[u] = w; + ctx->buf[ptr + u] = w; + } + } + dbuf += clen; + len -= clen; + ptr += clen; + if (ptr < sizeof ctx->buf) { + ctx->ptr = ptr; + return; + } + (*ctx->bctx)->mac(ctx->bctx, + ctx->cbcmac, ctx->buf, sizeof ctx->buf); + } + + /* + * Process all complete blocks. Note that the ctrcbc API is for + * encrypt-then-MAC (CBC-MAC is computed over the encrypted + * blocks) while CCM uses MAC-and-encrypt (CBC-MAC is computed + * over the plaintext blocks). Therefore, we need to use the + * _decryption_ function for encryption, and the encryption + * function for decryption (this works because CTR encryption + * and decryption are identical, so the choice really is about + * computing the CBC-MAC before or after XORing with the CTR + * stream). + */ + ptr = len & 15; + len -= ptr; + if (encrypt) { + (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac, + dbuf, len); + } else { + (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac, + dbuf, len); + } + dbuf += len; + + /* + * If there is some remaining data, then we need to compute an + * extra block of CTR stream. + */ + if (ptr != 0) { + size_t u; + + memset(ctx->buf, 0, sizeof ctx->buf); + (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, + ctx->buf, sizeof ctx->buf); + if (encrypt) { + for (u = 0; u < ptr; u ++) { + unsigned w, x; + + w = ctx->buf[u]; + x = dbuf[u]; + ctx->buf[u] = x; + dbuf[u] = w ^ x; + } + } else { + for (u = 0; u < ptr; u ++) { + unsigned w; + + w = ctx->buf[u] ^ dbuf[u]; + dbuf[u] = w; + ctx->buf[u] = w; + } + } + } + ctx->ptr = ptr; +} + +/* see bearssl_block.h */ +size_t +br_ccm_get_tag(br_ccm_context *ctx, void *tag) +{ + size_t ptr; + size_t u; + + /* + * If there is some buffered data, then we need to pad it with + * zeros and finish up CBC-MAC. + */ + ptr = ctx->ptr; + if (ptr != 0) { + memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr); + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, + ctx->buf, sizeof ctx->buf); + } + + /* + * XOR the tag mask into the CBC-MAC output. + */ + for (u = 0; u < ctx->tag_len; u ++) { + ctx->cbcmac[u] ^= ctx->tagmask[u]; + } + memcpy(tag, ctx->cbcmac, ctx->tag_len); + return ctx->tag_len; +} + +/* see bearssl_block.h */ +uint32_t +br_ccm_check_tag(br_ccm_context *ctx, const void *tag) +{ + unsigned char tmp[16]; + size_t u, tag_len; + uint32_t z; + + tag_len = br_ccm_get_tag(ctx, tmp); + z = 0; + for (u = 0; u < tag_len; u ++) { + z |= tmp[u] ^ ((const unsigned char *)tag)[u]; + } + return EQ0(z); +} diff --git a/src/bearssl/src/aead/eax.c b/src/bearssl/src/aead/eax.c new file mode 100644 index 0000000..bcc704a --- /dev/null +++ b/src/bearssl/src/aead/eax.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Implementation Notes + * ==================== + * + * The combined CTR + CBC-MAC functions can only handle full blocks, + * so some buffering is necessary. Moreover, EAX has a special padding + * rule for CBC-MAC, which implies that we cannot compute the MAC over + * the last received full block until we know whether we are at the + * end of the data or not. + * + * - 'ptr' contains a value from 1 to 16, which is the number of bytes + * accumulated in buf[] that still needs to be processed with the + * current OMAC computation. Beware that this can go to 16: a + * complete block cannot be processed until it is known whether it + * is the last block or not. However, it can never be 0, because + * OMAC^t works on an input that is at least one-block long. + * + * - When processing the message itself, CTR encryption/decryption is + * also done at the same time. The first 'ptr' bytes of buf[] then + * contains the encrypted bytes, while the last '16 - ptr' bytes of + * buf[] are the remnants of the stream block, to be used against + * the next input bytes, when available. + * + * - The current counter and running CBC-MAC values are kept in 'ctr' + * and 'cbcmac', respectively. + * + * - The derived keys for padding are kept in L2 and L4 (double and + * quadruple of Enc_K(0^n), in GF(2^128), respectively). + */ + +/* + * Start an OMAC computation; the first block is the big-endian + * representation of the provided value ('val' must fit on one byte). + * We make it a delayed block because it may also be the last one, + */ +static void +omac_start(br_eax_context *ctx, unsigned val) +{ + memset(ctx->cbcmac, 0, sizeof ctx->cbcmac); + memset(ctx->buf, 0, sizeof ctx->buf); + ctx->buf[15] = val; + ctx->ptr = 16; +} + +/* + * Double a value in finite field GF(2^128), defined with modulus + * X^128+X^7+X^2+X+1. + */ +static void +double_gf128(unsigned char *dst, const unsigned char *src) +{ + unsigned cc; + int i; + + cc = 0x87 & -((unsigned)src[0] >> 7); + for (i = 15; i >= 0; i --) { + unsigned z; + + z = (src[i] << 1) ^ cc; + cc = z >> 8; + dst[i] = (unsigned char)z; + } +} + +/* + * Apply padding to the last block, currently in ctx->buf (with + * ctx->ptr bytes), and finalize OMAC computation. + */ +static void +do_pad(br_eax_context *ctx) +{ + unsigned char *pad; + size_t ptr, u; + + ptr = ctx->ptr; + if (ptr == 16) { + pad = ctx->L2; + } else { + ctx->buf[ptr ++] = 0x80; + memset(ctx->buf + ptr, 0x00, 16 - ptr); + pad = ctx->L4; + } + for (u = 0; u < sizeof ctx->buf; u ++) { + ctx->buf[u] ^= pad[u]; + } + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf); +} + +/* + * Apply CBC-MAC on the provided data, with buffering management. + * + * Upon entry, two situations are acceptable: + * + * ctx->ptr == 0: there is no data to process in ctx->buf + * ctx->ptr == 16: there is a full block of unprocessed data in ctx->buf + * + * Upon exit, ctx->ptr may be zero only if it was already zero on entry, + * and len == 0. In all other situations, ctx->ptr will be non-zero on + * exit (and may have value 16). + */ +static void +do_cbcmac_chunk(br_eax_context *ctx, const void *data, size_t len) +{ + size_t ptr; + + if (len == 0) { + return; + } + ptr = len & (size_t)15; + if (ptr == 0) { + len -= 16; + ptr = 16; + } else { + len -= ptr; + } + if (ctx->ptr == 16) { + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, + ctx->buf, sizeof ctx->buf); + } + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, data, len); + memcpy(ctx->buf, (const unsigned char *)data + len, ptr); + ctx->ptr = ptr; +} + +/* see bearssl_aead.h */ +void +br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx) +{ + unsigned char tmp[16], iv[16]; + + ctx->vtable = &br_eax_vtable; + ctx->bctx = bctx; + + /* + * Encrypt a whole-zero block to compute L2 and L4. + */ + memset(tmp, 0, sizeof tmp); + memset(iv, 0, sizeof iv); + (*bctx)->ctr(bctx, iv, tmp, sizeof tmp); + double_gf128(ctx->L2, tmp); + double_gf128(ctx->L4, ctx->L2); +} + +/* see bearssl_aead.h */ +void +br_eax_capture(const br_eax_context *ctx, br_eax_state *st) +{ + /* + * We capture the three OMAC* states _after_ processing the + * initial block (assuming that nonce, message and AAD are + * all non-empty). + */ + int i; + + memset(st->st, 0, sizeof st->st); + for (i = 0; i < 3; i ++) { + unsigned char tmp[16]; + + memset(tmp, 0, sizeof tmp); + tmp[15] = (unsigned char)i; + (*ctx->bctx)->mac(ctx->bctx, st->st[i], tmp, sizeof tmp); + } +} + +/* see bearssl_aead.h */ +void +br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len) +{ + /* + * Process nonce with OMAC^0. + */ + omac_start(ctx, 0); + do_cbcmac_chunk(ctx, nonce, len); + do_pad(ctx); + memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac); + + /* + * Start OMAC^1 for the AAD ("header" in the EAX specification). + */ + omac_start(ctx, 1); + + /* + * We use ctx->head[0] as temporary flag to mark that we are + * using a "normal" reset(). + */ + ctx->head[0] = 0; +} + +/* see bearssl_aead.h */ +void +br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st, + const void *nonce, size_t len) +{ + if (len == 0) { + omac_start(ctx, 0); + } else { + memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac); + ctx->ptr = 0; + do_cbcmac_chunk(ctx, nonce, len); + } + do_pad(ctx); + memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac); + + memcpy(ctx->cbcmac, st->st[1], sizeof ctx->cbcmac); + ctx->ptr = 0; + + memcpy(ctx->ctr, st->st[2], sizeof ctx->ctr); + + /* + * We use ctx->head[0] as a flag to indicate that we use a + * a recorded state, with ctx->ctr containing the preprocessed + * first block for OMAC^2. + */ + ctx->head[0] = 1; +} + +/* see bearssl_aead.h */ +void +br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st, + const void *nonce, size_t len) +{ + if (len == 0) { + omac_start(ctx, 0); + } else { + memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac); + ctx->ptr = 0; + do_cbcmac_chunk(ctx, nonce, len); + } + do_pad(ctx); + memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac); + memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce); + + memcpy(ctx->head, st->st[1], sizeof ctx->head); + + memcpy(ctx->cbcmac, st->st[2], sizeof ctx->cbcmac); + ctx->ptr = 0; +} + +/* see bearssl_aead.h */ +void +br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len) +{ + size_t ptr; + + ptr = ctx->ptr; + + /* + * If there is a partial block, first complete it. + */ + if (ptr < 16) { + size_t clen; + + clen = 16 - ptr; + if (len <= clen) { + memcpy(ctx->buf + ptr, data, len); + ctx->ptr = ptr + len; + return; + } + memcpy(ctx->buf + ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + } + + /* + * We now have a full block in buf[], and this is not the last + * block. + */ + do_cbcmac_chunk(ctx, data, len); +} + +/* see bearssl_aead.h */ +void +br_eax_flip(br_eax_context *ctx) +{ + int from_capture; + + /* + * ctx->head[0] may be non-zero if the context was reset with + * a pre-AAD captured state. In that case, ctx->ctr[] contains + * the state for OMAC^2 _after_ processing the first block. + */ + from_capture = ctx->head[0]; + + /* + * Complete the OMAC computation on the AAD. + */ + do_pad(ctx); + memcpy(ctx->head, ctx->cbcmac, sizeof ctx->cbcmac); + + /* + * Start OMAC^2 for the encrypted data. + * If the context was initialized from a captured state, then + * the OMAC^2 value is in the ctr[] array. + */ + if (from_capture) { + memcpy(ctx->cbcmac, ctx->ctr, sizeof ctx->cbcmac); + ctx->ptr = 0; + } else { + omac_start(ctx, 2); + } + + /* + * Initial counter value for CTR is the processed nonce. + */ + memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce); +} + +/* see bearssl_aead.h */ +void +br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len) +{ + unsigned char *dbuf; + size_t ptr; + + /* + * Ensure that there is actual data to process. + */ + if (len == 0) { + return; + } + + dbuf = data; + ptr = ctx->ptr; + + /* + * We may have ptr == 0 here if we initialized from a captured + * state. In that case, there is no partially consumed block + * or unprocessed data. + */ + if (ptr != 0 && ptr != 16) { + /* + * We have a partially consumed block. + */ + size_t u, clen; + + clen = 16 - ptr; + if (len <= clen) { + clen = len; + } + if (encrypt) { + for (u = 0; u < clen; u ++) { + ctx->buf[ptr + u] ^= dbuf[u]; + } + memcpy(dbuf, ctx->buf + ptr, clen); + } else { + for (u = 0; u < clen; u ++) { + unsigned dx, sx; + + sx = ctx->buf[ptr + u]; + dx = dbuf[u]; + ctx->buf[ptr + u] = dx; + dbuf[u] = sx ^ dx; + } + } + + if (len <= clen) { + ctx->ptr = ptr + clen; + return; + } + dbuf += clen; + len -= clen; + } + + /* + * We now have a complete encrypted block in buf[] that must still + * be processed with OMAC, and this is not the final buf. + * Exception: when ptr == 0, no block has been produced yet. + */ + if (ptr != 0) { + (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, + ctx->buf, sizeof ctx->buf); + } + + /* + * Do CTR encryption or decryption and CBC-MAC for all full blocks + * except the last. + */ + ptr = len & (size_t)15; + if (ptr == 0) { + len -= 16; + ptr = 16; + } else { + len -= ptr; + } + if (encrypt) { + (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac, + dbuf, len); + } else { + (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac, + dbuf, len); + } + dbuf += len; + + /* + * Compute next block of CTR stream, and use it to finish + * encrypting or decrypting the data. + */ + memset(ctx->buf, 0, sizeof ctx->buf); + (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, ctx->buf, sizeof ctx->buf); + if (encrypt) { + size_t u; + + for (u = 0; u < ptr; u ++) { + ctx->buf[u] ^= dbuf[u]; + } + memcpy(dbuf, ctx->buf, ptr); + } else { + size_t u; + + for (u = 0; u < ptr; u ++) { + unsigned dx, sx; + + sx = ctx->buf[u]; + dx = dbuf[u]; + ctx->buf[u] = dx; + dbuf[u] = sx ^ dx; + } + } + ctx->ptr = ptr; +} + +/* + * Complete tag computation. The final tag is written in ctx->cbcmac. + */ +static void +do_final(br_eax_context *ctx) +{ + size_t u; + + do_pad(ctx); + + /* + * Authentication tag is the XOR of the three OMAC outputs for + * the nonce, AAD and encrypted data. + */ + for (u = 0; u < 16; u ++) { + ctx->cbcmac[u] ^= ctx->nonce[u] ^ ctx->head[u]; + } +} + +/* see bearssl_aead.h */ +void +br_eax_get_tag(br_eax_context *ctx, void *tag) +{ + do_final(ctx); + memcpy(tag, ctx->cbcmac, sizeof ctx->cbcmac); +} + +/* see bearssl_aead.h */ +void +br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len) +{ + do_final(ctx); + memcpy(tag, ctx->cbcmac, len); +} + +/* see bearssl_aead.h */ +uint32_t +br_eax_check_tag_trunc(br_eax_context *ctx, const void *tag, size_t len) +{ + unsigned char tmp[16]; + size_t u; + int x; + + br_eax_get_tag(ctx, tmp); + x = 0; + for (u = 0; u < len; u ++) { + x |= tmp[u] ^ ((const unsigned char *)tag)[u]; + } + return EQ0(x); +} + +/* see bearssl_aead.h */ +uint32_t +br_eax_check_tag(br_eax_context *ctx, const void *tag) +{ + return br_eax_check_tag_trunc(ctx, tag, 16); +} + +/* see bearssl_aead.h */ +const br_aead_class br_eax_vtable = { + 16, + (void (*)(const br_aead_class **, const void *, size_t)) + &br_eax_reset, + (void (*)(const br_aead_class **, const void *, size_t)) + &br_eax_aad_inject, + (void (*)(const br_aead_class **)) + &br_eax_flip, + (void (*)(const br_aead_class **, int, void *, size_t)) + &br_eax_run, + (void (*)(const br_aead_class **, void *)) + &br_eax_get_tag, + (uint32_t (*)(const br_aead_class **, const void *)) + &br_eax_check_tag, + (void (*)(const br_aead_class **, void *, size_t)) + &br_eax_get_tag_trunc, + (uint32_t (*)(const br_aead_class **, const void *, size_t)) + &br_eax_check_tag_trunc +}; diff --git a/src/bearssl/src/aead/gcm.c b/src/bearssl/src/aead/gcm.c new file mode 100644 index 0000000..ede5f08 --- /dev/null +++ b/src/bearssl/src/aead/gcm.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Implementation Notes + * ==================== + * + * Since CTR and GHASH implementations can handle only full blocks, a + * 16-byte buffer (buf[]) is maintained in the context: + * + * - When processing AAD, buf[] contains the 0-15 unprocessed bytes. + * + * - When doing CTR encryption / decryption, buf[] contains the AES output + * for the last partial block, to be used with the next few bytes of + * data, as well as the already encrypted bytes. For instance, if the + * processed data length so far is 21 bytes, then buf[0..4] contains + * the five last encrypted bytes, and buf[5..15] contains the next 11 + * AES output bytes to be XORed with the next 11 bytes of input. + * + * The recorded AES output bytes are used to complete the block when + * the corresponding bytes are obtained. Note that buf[] always + * contains the _encrypted_ bytes, whether we apply encryption or + * decryption: these bytes are used as input to GHASH when the block + * is complete. + * + * In both cases, the low bits of the data length counters (count_aad, + * count_ctr) are used to work out the current situation. + */ + +/* see bearssl_aead.h */ +void +br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh) +{ + unsigned char iv[12]; + + ctx->vtable = &br_gcm_vtable; + ctx->bctx = bctx; + ctx->gh = gh; + + /* + * The GHASH key h[] is the raw encryption of the all-zero + * block. Since we only have a CTR implementation, we use it + * with an all-zero IV and a zero counter, to CTR-encrypt an + * all-zero block. + */ + memset(ctx->h, 0, sizeof ctx->h); + memset(iv, 0, sizeof iv); + (*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h); +} + +/* see bearssl_aead.h */ +void +br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len) +{ + /* + * If the provided nonce is 12 bytes, then this is the initial + * IV for CTR mode; it will be used with a counter that starts + * at 2 (value 1 is for encrypting the GHASH output into the tag). + * + * If the provided nonce has any other length, then it is hashed + * (with GHASH) into a 16-byte value that will be the IV for CTR + * (both 12-byte IV and 32-bit counter). + */ + if (len == 12) { + memcpy(ctx->j0_1, iv, 12); + ctx->j0_2 = 1; + } else { + unsigned char ty[16], tmp[16]; + + memset(ty, 0, sizeof ty); + ctx->gh(ty, ctx->h, iv, len); + memset(tmp, 0, 8); + br_enc64be(tmp + 8, (uint64_t)len << 3); + ctx->gh(ty, ctx->h, tmp, 16); + memcpy(ctx->j0_1, ty, 12); + ctx->j0_2 = br_dec32be(ty + 12); + } + ctx->jc = ctx->j0_2 + 1; + memset(ctx->y, 0, sizeof ctx->y); + ctx->count_aad = 0; + ctx->count_ctr = 0; +} + +/* see bearssl_aead.h */ +void +br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len) +{ + size_t ptr, dlen; + + ptr = (size_t)ctx->count_aad & (size_t)15; + if (ptr != 0) { + /* + * If there is a partial block, then we first try to + * complete it. + */ + size_t clen; + + clen = 16 - ptr; + if (len < clen) { + memcpy(ctx->buf + ptr, data, len); + ctx->count_aad += (uint64_t)len; + return; + } + memcpy(ctx->buf + ptr, data, clen); + ctx->gh(ctx->y, ctx->h, ctx->buf, 16); + data = (const unsigned char *)data + clen; + len -= clen; + ctx->count_aad += (uint64_t)clen; + } + + /* + * Now AAD is aligned on a 16-byte block (with regards to GHASH). + * We process all complete blocks, and save the last partial + * block. + */ + dlen = len & ~(size_t)15; + ctx->gh(ctx->y, ctx->h, data, dlen); + memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen); + ctx->count_aad += (uint64_t)len; +} + +/* see bearssl_aead.h */ +void +br_gcm_flip(br_gcm_context *ctx) +{ + /* + * We complete the GHASH computation if there is a partial block. + * The GHASH implementation automatically applies padding with + * zeros. + */ + size_t ptr; + + ptr = (size_t)ctx->count_aad & (size_t)15; + if (ptr != 0) { + ctx->gh(ctx->y, ctx->h, ctx->buf, ptr); + } +} + +/* see bearssl_aead.h */ +void +br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len) +{ + unsigned char *buf; + size_t ptr, dlen; + + buf = data; + ptr = (size_t)ctx->count_ctr & (size_t)15; + if (ptr != 0) { + /* + * If we have a partial block, then we try to complete it. + */ + size_t u, clen; + + clen = 16 - ptr; + if (len < clen) { + clen = len; + } + for (u = 0; u < clen; u ++) { + unsigned x, y; + + x = buf[u]; + y = x ^ ctx->buf[ptr + u]; + ctx->buf[ptr + u] = encrypt ? y : x; + buf[u] = y; + } + ctx->count_ctr += (uint64_t)clen; + buf += clen; + len -= clen; + if (ptr + clen < 16) { + return; + } + ctx->gh(ctx->y, ctx->h, ctx->buf, 16); + } + + /* + * Process full blocks. + */ + dlen = len & ~(size_t)15; + if (!encrypt) { + ctx->gh(ctx->y, ctx->h, buf, dlen); + } + ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen); + if (encrypt) { + ctx->gh(ctx->y, ctx->h, buf, dlen); + } + buf += dlen; + len -= dlen; + ctx->count_ctr += (uint64_t)dlen; + + if (len > 0) { + /* + * There is a partial block. + */ + size_t u; + + memset(ctx->buf, 0, sizeof ctx->buf); + ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, + ctx->jc, ctx->buf, 16); + for (u = 0; u < len; u ++) { + unsigned x, y; + + x = buf[u]; + y = x ^ ctx->buf[u]; + ctx->buf[u] = encrypt ? y : x; + buf[u] = y; + } + ctx->count_ctr += (uint64_t)len; + } +} + +/* see bearssl_aead.h */ +void +br_gcm_get_tag(br_gcm_context *ctx, void *tag) +{ + size_t ptr; + unsigned char tmp[16]; + + ptr = (size_t)ctx->count_ctr & (size_t)15; + if (ptr > 0) { + /* + * There is a partial block: encrypted/decrypted data has + * been produced, but the encrypted bytes must still be + * processed by GHASH. + */ + ctx->gh(ctx->y, ctx->h, ctx->buf, ptr); + } + + /* + * Final block for GHASH: the AAD and plaintext lengths (in bits). + */ + br_enc64be(tmp, ctx->count_aad << 3); + br_enc64be(tmp + 8, ctx->count_ctr << 3); + ctx->gh(ctx->y, ctx->h, tmp, 16); + + /* + * Tag is the GHASH output XORed with the encryption of the + * nonce with the initial counter value. + */ + memcpy(tag, ctx->y, 16); + (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16); +} + +/* see bearssl_aead.h */ +void +br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len) +{ + unsigned char tmp[16]; + + br_gcm_get_tag(ctx, tmp); + memcpy(tag, tmp, len); +} + +/* see bearssl_aead.h */ +uint32_t +br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len) +{ + unsigned char tmp[16]; + size_t u; + int x; + + br_gcm_get_tag(ctx, tmp); + x = 0; + for (u = 0; u < len; u ++) { + x |= tmp[u] ^ ((const unsigned char *)tag)[u]; + } + return EQ0(x); +} + +/* see bearssl_aead.h */ +uint32_t +br_gcm_check_tag(br_gcm_context *ctx, const void *tag) +{ + return br_gcm_check_tag_trunc(ctx, tag, 16); +} + +/* see bearssl_aead.h */ +const br_aead_class br_gcm_vtable = { + 16, + (void (*)(const br_aead_class **, const void *, size_t)) + &br_gcm_reset, + (void (*)(const br_aead_class **, const void *, size_t)) + &br_gcm_aad_inject, + (void (*)(const br_aead_class **)) + &br_gcm_flip, + (void (*)(const br_aead_class **, int, void *, size_t)) + &br_gcm_run, + (void (*)(const br_aead_class **, void *)) + &br_gcm_get_tag, + (uint32_t (*)(const br_aead_class **, const void *)) + &br_gcm_check_tag, + (void (*)(const br_aead_class **, void *, size_t)) + &br_gcm_get_tag_trunc, + (uint32_t (*)(const br_aead_class **, const void *, size_t)) + &br_gcm_check_tag_trunc +}; diff --git a/src/bearssl/src/codec/ccopy.c b/src/bearssl/src/codec/ccopy.c new file mode 100644 index 0000000..2beace7 --- /dev/null +++ b/src/bearssl/src/codec/ccopy.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + uint32_t x, y; + + x = *s ++; + y = *d; + *d = MUX(ctl, x, y); + d ++; + } +} diff --git a/src/bearssl/src/codec/dec16be.c b/src/bearssl/src/codec/dec16be.c new file mode 100644 index 0000000..4f3f7f4 --- /dev/null +++ b/src/bearssl/src/codec/dec16be.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_dec16be(uint16_t *v, size_t num, const void *src) +{ + const unsigned char *buf; + + buf = src; + while (num -- > 0) { + *v ++ = br_dec16be(buf); + buf += 2; + } +} diff --git a/src/bearssl/src/codec/dec16le.c b/src/bearssl/src/codec/dec16le.c new file mode 100644 index 0000000..84d8536 --- /dev/null +++ b/src/bearssl/src/codec/dec16le.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_dec16le(uint16_t *v, size_t num, const void *src) +{ + const unsigned char *buf; + + buf = src; + while (num -- > 0) { + *v ++ = br_dec16le(buf); + buf += 2; + } +} diff --git a/src/bearssl/src/codec/dec32be.c b/src/bearssl/src/codec/dec32be.c new file mode 100644 index 0000000..5a8fc59 --- /dev/null +++ b/src/bearssl/src/codec/dec32be.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_dec32be(uint32_t *v, size_t num, const void *src) +{ + const unsigned char *buf; + + buf = src; + while (num -- > 0) { + *v ++ = br_dec32be(buf); + buf += 4; + } +} diff --git a/src/bearssl/src/codec/dec32le.c b/src/bearssl/src/codec/dec32le.c new file mode 100644 index 0000000..ed36e71 --- /dev/null +++ b/src/bearssl/src/codec/dec32le.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_dec32le(uint32_t *v, size_t num, const void *src) +{ + const unsigned char *buf; + + buf = src; + while (num -- > 0) { + *v ++ = br_dec32le(buf); + buf += 4; + } +} diff --git a/src/bearssl/src/codec/dec64be.c b/src/bearssl/src/codec/dec64be.c new file mode 100644 index 0000000..0c40a76 --- /dev/null +++ b/src/bearssl/src/codec/dec64be.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_dec64be(uint64_t *v, size_t num, const void *src) +{ + const unsigned char *buf; + + buf = src; + while (num -- > 0) { + *v ++ = br_dec64be(buf); + buf += 8; + } +} diff --git a/src/bearssl/src/codec/dec64le.c b/src/bearssl/src/codec/dec64le.c new file mode 100644 index 0000000..cbd02c2 --- /dev/null +++ b/src/bearssl/src/codec/dec64le.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_dec64le(uint64_t *v, size_t num, const void *src) +{ + const unsigned char *buf; + + buf = src; + while (num -- > 0) { + *v ++ = br_dec64le(buf); + buf += 8; + } +} diff --git a/src/bearssl/src/codec/enc16be.c b/src/bearssl/src/codec/enc16be.c new file mode 100644 index 0000000..6e06652 --- /dev/null +++ b/src/bearssl/src/codec/enc16be.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_enc16be(void *dst, const uint16_t *v, size_t num) +{ + unsigned char *buf; + + buf = dst; + while (num -- > 0) { + br_enc16be(buf, *v ++); + buf += 2; + } +} diff --git a/src/bearssl/src/codec/enc16le.c b/src/bearssl/src/codec/enc16le.c new file mode 100644 index 0000000..3e5049a --- /dev/null +++ b/src/bearssl/src/codec/enc16le.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_enc16le(void *dst, const uint16_t *v, size_t num) +{ + unsigned char *buf; + + buf = dst; + while (num -- > 0) { + br_enc16le(buf, *v ++); + buf += 2; + } +} diff --git a/src/bearssl/src/codec/enc32be.c b/src/bearssl/src/codec/enc32be.c new file mode 100644 index 0000000..97298b5 --- /dev/null +++ b/src/bearssl/src/codec/enc32be.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_enc32be(void *dst, const uint32_t *v, size_t num) +{ + unsigned char *buf; + + buf = dst; + while (num -- > 0) { + br_enc32be(buf, *v ++); + buf += 4; + } +} diff --git a/src/bearssl/src/codec/enc32le.c b/src/bearssl/src/codec/enc32le.c new file mode 100644 index 0000000..9e9c856 --- /dev/null +++ b/src/bearssl/src/codec/enc32le.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_enc32le(void *dst, const uint32_t *v, size_t num) +{ + unsigned char *buf; + + buf = dst; + while (num -- > 0) { + br_enc32le(buf, *v ++); + buf += 4; + } +} diff --git a/src/bearssl/src/codec/enc64be.c b/src/bearssl/src/codec/enc64be.c new file mode 100644 index 0000000..d548944 --- /dev/null +++ b/src/bearssl/src/codec/enc64be.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_enc64be(void *dst, const uint64_t *v, size_t num) +{ + unsigned char *buf; + + buf = dst; + while (num -- > 0) { + br_enc64be(buf, *v ++); + buf += 8; + } +} diff --git a/src/bearssl/src/codec/enc64le.c b/src/bearssl/src/codec/enc64le.c new file mode 100644 index 0000000..1f1d68e --- /dev/null +++ b/src/bearssl/src/codec/enc64le.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_range_enc64le(void *dst, const uint64_t *v, size_t num) +{ + unsigned char *buf; + + buf = dst; + while (num -- > 0) { + br_enc64le(buf, *v ++); + buf += 8; + } +} diff --git a/src/bearssl/src/codec/pemdec.c b/src/bearssl/src/codec/pemdec.c new file mode 100644 index 0000000..8e54e6d --- /dev/null +++ b/src/bearssl/src/codec/pemdec.c @@ -0,0 +1,526 @@ +/* Automatically generated code; do not modify directly. */ + +#include +#include + +typedef struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; +} t0_context; + +static uint32_t +t0_parse7E_unsigned(const unsigned char **p) +{ + uint32_t x; + + x = 0; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + return x; + } + } +} + +static int32_t +t0_parse7E_signed(const unsigned char **p) +{ + int neg; + uint32_t x; + + neg = ((**p) >> 6) & 1; + x = (uint32_t)-neg; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + if (neg) { + return -(int32_t)~x - 1; + } else { + return (int32_t)x; + } + } + } +} + +#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80) +#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F) +#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8) +#define T0_INT1(x) T0_FBYTE(x, 0) +#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) + +/* static const unsigned char t0_datablock[]; */ + + +void br_pem_decoder_init_main(void *t0ctx); + +void br_pem_decoder_run(void *t0ctx); + + + +#include "inner.h" + +#define CTX ((br_pem_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu))) + +/* see bearssl_pem.h */ +void +br_pem_decoder_init(br_pem_decoder_context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + ctx->cpu.dp = &ctx->dp_stack[0]; + ctx->cpu.rp = &ctx->rp_stack[0]; + br_pem_decoder_init_main(&ctx->cpu); + br_pem_decoder_run(&ctx->cpu); +} + +/* see bearssl_pem.h */ +size_t +br_pem_decoder_push(br_pem_decoder_context *ctx, + const void *data, size_t len) +{ + if (ctx->event) { + return 0; + } + ctx->hbuf = data; + ctx->hlen = len; + br_pem_decoder_run(&ctx->cpu); + return len - ctx->hlen; +} + +/* see bearssl_pem.h */ +int +br_pem_decoder_event(br_pem_decoder_context *ctx) +{ + int event; + + event = ctx->event; + ctx->event = 0; + return event; +} + + + +static const unsigned char t0_datablock[] = { + 0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, + 0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x00 +}; + +static const unsigned char t0_codeblock[] = { + 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x01, + 0x01, 0x08, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_pem_decoder_context, event)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_pem_decoder_context, name)), 0x00, 0x00, 0x05, + 0x14, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x03, 0x13, 0x04, 0x76, 0x01, + 0x2D, 0x0C, 0x06, 0x05, 0x2E, 0x01, 0x03, 0x2D, 0x00, 0x01, 0x0D, 0x27, + 0x05, 0x04, 0x01, 0x03, 0x2D, 0x00, 0x15, 0x2E, 0x01, 0x02, 0x2D, 0x00, + 0x01, 0x01, 0x7F, 0x03, 0x00, 0x25, 0x01, 0x00, 0x18, 0x0D, 0x06, 0x03, + 0x13, 0x04, 0x3C, 0x01, 0x7F, 0x18, 0x0D, 0x06, 0x13, 0x13, 0x02, 0x00, + 0x05, 0x06, 0x2E, 0x01, 0x03, 0x2D, 0x04, 0x03, 0x01, 0x7F, 0x23, 0x01, + 0x00, 0x00, 0x04, 0x23, 0x01, 0x01, 0x18, 0x0D, 0x06, 0x09, 0x13, 0x01, + 0x00, 0x23, 0x01, 0x00, 0x00, 0x04, 0x14, 0x01, 0x02, 0x18, 0x0D, 0x06, + 0x06, 0x13, 0x01, 0x7F, 0x00, 0x04, 0x08, 0x13, 0x01, 0x03, 0x2D, 0x01, + 0x00, 0x00, 0x13, 0x01, 0x00, 0x03, 0x00, 0x04, 0xFF, 0x33, 0x01, 0x2C, + 0x14, 0x01, 0x2D, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x7F, 0x00, 0x14, 0x31, + 0x06, 0x02, 0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, + 0x02, 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, + 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03, + 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02, + 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, + 0x06, 0x04, 0x13, 0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x2E, + 0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03, 0x00, + 0x2F, 0x05, 0x04, 0x13, 0x01, 0x03, 0x00, 0x01, 0x3D, 0x0C, 0x06, 0x03, + 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x0F, 0x10, 0x06, 0x03, 0x01, 0x03, + 0x00, 0x02, 0x00, 0x01, 0x04, 0x0F, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14, + 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06, + 0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, + 0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x20, 0x13, 0x2F, 0x05, + 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x03, 0x10, 0x06, 0x03, 0x01, + 0x03, 0x00, 0x02, 0x00, 0x01, 0x0A, 0x0F, 0x1C, 0x02, 0x00, 0x01, 0x02, + 0x0F, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, + 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x02, + 0x00, 0x01, 0x10, 0x0F, 0x1C, 0x02, 0x00, 0x01, 0x08, 0x0F, 0x1C, 0x02, + 0x00, 0x1C, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, 0x01, 0x2D, 0x24, 0x06, + 0x02, 0x04, 0x7B, 0x04, 0x75, 0x00, 0x14, 0x12, 0x2A, 0x14, 0x05, 0x04, + 0x20, 0x01, 0x7F, 0x00, 0x2C, 0x2A, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x05, + 0x13, 0x20, 0x01, 0x00, 0x00, 0x0D, 0x05, 0x05, 0x13, 0x2E, 0x01, 0x00, + 0x00, 0x1E, 0x04, 0x5E, 0x00, 0x01, 0x01, 0x27, 0x06, 0x0B, 0x22, 0x01, + 0x80, 0x7F, 0x2B, 0x14, 0x06, 0x02, 0x30, 0x00, 0x13, 0x04, 0x6E, 0x00, + 0x2C, 0x14, 0x31, 0x05, 0x01, 0x00, 0x13, 0x04, 0x77, 0x00, 0x14, 0x14, + 0x01, 0x80, 0x61, 0x0E, 0x1B, 0x01, 0x80, 0x7A, 0x0B, 0x10, 0x06, 0x03, + 0x01, 0x20, 0x08, 0x00, 0x01, 0x14, 0x03, 0x00, 0x1B, 0x18, 0x05, 0x05, + 0x20, 0x2E, 0x01, 0x00, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x06, + 0x20, 0x02, 0x00, 0x1B, 0x08, 0x00, 0x14, 0x01, 0x0D, 0x0D, 0x06, 0x03, + 0x13, 0x04, 0x03, 0x2A, 0x18, 0x1A, 0x1E, 0x1B, 0x1F, 0x1B, 0x04, 0x59, + 0x00, 0x19, 0x14, 0x1D, 0x05, 0x01, 0x00, 0x13, 0x11, 0x04, 0x76, 0x00, + 0x21, 0x1A, 0x11, 0x00, 0x00, 0x2C, 0x01, 0x0A, 0x0C, 0x06, 0x02, 0x04, + 0x78, 0x00, 0x01, 0x01, 0x7F, 0x03, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0C, + 0x06, 0x09, 0x31, 0x05, 0x04, 0x01, 0x00, 0x03, 0x00, 0x04, 0x70, 0x13, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x06, 0x14, 0x1F, 0x14, 0x22, 0x07, 0x17, + 0x01, 0x2D, 0x0C, 0x06, 0x08, 0x22, 0x07, 0x1E, 0x01, 0x00, 0x1B, 0x1A, + 0x00, 0x04, 0x69, 0x22, 0x1A, 0x00, 0x00, 0x14, 0x01, 0x0A, 0x0C, 0x1B, + 0x01, 0x20, 0x0B, 0x10, 0x00 +}; + +static const uint16_t t0_caddr[] = { + 0, + 5, + 10, + 15, + 19, + 24, + 29, + 67, + 149, + 384, + 396, + 431, + 450, + 460, + 479, + 523, + 534, + 539, + 549, + 574, + 601 +}; + +#define T0_INTERPRETED 29 + +#define T0_ENTER(ip, rp, slot) do { \ + const unsigned char *t0_newip; \ + uint32_t t0_lnum; \ + t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \ + t0_lnum = t0_parse7E_unsigned(&t0_newip); \ + (rp) += t0_lnum; \ + *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \ + (ip) = t0_newip; \ + } while (0) + +#define T0_DEFENTRY(name, slot) \ +void \ +name(void *ctx) \ +{ \ + t0_context *t0ctx = ctx; \ + t0ctx->ip = &t0_codeblock[0]; \ + T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ +} + +T0_DEFENTRY(br_pem_decoder_init_main, 38) + +#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++) + +void +br_pem_decoder_run(void *t0ctx) +{ + uint32_t *dp, *rp; + const unsigned char *ip; + +#define T0_LOCAL(x) (*(rp - 2 - (x))) +#define T0_POP() (*-- dp) +#define T0_POPi() (*(int32_t *)(-- dp)) +#define T0_PEEK(x) (*(dp - 1 - (x))) +#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x))) +#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0) +#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0) +#define T0_RPOP() (*-- rp) +#define T0_RPOPi() (*(int32_t *)(-- rp)) +#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0) +#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0) +#define T0_ROLL(x) do { \ + size_t t0len = (size_t)(x); \ + uint32_t t0tmp = *(dp - 1 - t0len); \ + memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_SWAP() do { \ + uint32_t t0tmp = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_ROT() do { \ + uint32_t t0tmp = *(dp - 3); \ + *(dp - 3) = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_NROT() do { \ + uint32_t t0tmp = *(dp - 1); \ + *(dp - 1) = *(dp - 2); \ + *(dp - 2) = *(dp - 3); \ + *(dp - 3) = t0tmp; \ +} while (0) +#define T0_PICK(x) do { \ + uint32_t t0depth = (x); \ + T0_PUSH(T0_PEEK(t0depth)); \ +} while (0) +#define T0_CO() do { \ + goto t0_exit; \ +} while (0) +#define T0_RET() goto t0_next + + dp = ((t0_context *)t0ctx)->dp; + rp = ((t0_context *)t0ctx)->rp; + ip = ((t0_context *)t0ctx)->ip; + goto t0_next; + for (;;) { + uint32_t t0x; + + t0_next: + t0x = T0_NEXT(&ip); + if (t0x < T0_INTERPRETED) { + switch (t0x) { + int32_t t0off; + + case 0: /* ret */ + t0x = T0_RPOP(); + rp -= (t0x >> 16); + t0x &= 0xFFFF; + if (t0x == 0) { + ip = NULL; + goto t0_exit; + } + ip = &t0_codeblock[t0x]; + break; + case 1: /* literal constant */ + T0_PUSHi(t0_parse7E_signed(&ip)); + break; + case 2: /* read local */ + T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip))); + break; + case 3: /* write local */ + T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP(); + break; + case 4: /* jump */ + t0off = t0_parse7E_signed(&ip); + ip += t0off; + break; + case 5: /* jump if */ + t0off = t0_parse7E_signed(&ip); + if (T0_POP()) { + ip += t0off; + } + break; + case 6: /* jump if not */ + t0off = t0_parse7E_signed(&ip); + if (!T0_POP()) { + ip += t0off; + } + break; + case 7: { + /* + */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a + b); + + } + break; + case 8: { + /* - */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a - b); + + } + break; + case 9: { + /* < */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 10: { + /* << */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x << c); + + } + break; + case 11: { + /* <= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a <= b)); + + } + break; + case 12: { + /* <> */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a != b)); + + } + break; + case 13: { + /* = */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a == b)); + + } + break; + case 14: { + /* >= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a >= b)); + + } + break; + case 15: { + /* >> */ + + int c = (int)T0_POPi(); + int32_t x = T0_POPi(); + T0_PUSHi(x >> c); + + } + break; + case 16: { + /* and */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a & b); + + } + break; + case 17: { + /* co */ + T0_CO(); + } + break; + case 18: { + /* data-get8 */ + + size_t addr = T0_POP(); + T0_PUSH(t0_datablock[addr]); + + } + break; + case 19: { + /* drop */ + (void)T0_POP(); + } + break; + case 20: { + /* dup */ + T0_PUSH(T0_PEEK(0)); + } + break; + case 21: { + /* flush-buf */ + + if (CTX->ptr > 0) { + if (CTX->dest) { + CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr); + } + CTX->ptr = 0; + } + + } + break; + case 22: { + /* from-base64 */ + + uint32_t c = T0_POP(); + uint32_t p, q, r, z; + p = c - 0x41; + q = c - 0x61; + r = c - 0x30; + + z = ((p + 2) & -LT(p, 26)) + | ((q + 28) & -LT(q, 26)) + | ((r + 54) & -LT(r, 10)) + | (64 & -EQ(c, 0x2B)) + | (65 & -EQ(c, 0x2F)) + | EQ(c, 0x3D); + T0_PUSHi((int32_t)z - 2); + + } + break; + case 23: { + /* get8 */ + + size_t addr = T0_POP(); + T0_PUSH(*((unsigned char *)CTX + addr)); + + } + break; + case 24: { + /* over */ + T0_PUSH(T0_PEEK(1)); + } + break; + case 25: { + /* read8-native */ + + if (CTX->hlen > 0) { + T0_PUSH(*CTX->hbuf ++); + CTX->hlen --; + } else { + T0_PUSHi(-1); + } + + } + break; + case 26: { + /* set8 */ + + size_t addr = T0_POP(); + unsigned x = T0_POP(); + *((unsigned char *)CTX + addr) = x; + + } + break; + case 27: { + /* swap */ + T0_SWAP(); + } + break; + case 28: { + /* write8 */ + + unsigned char x = (unsigned char)T0_POP(); + CTX->buf[CTX->ptr ++] = x; + if (CTX->ptr == sizeof CTX->buf) { + if (CTX->dest) { + CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf); + } + CTX->ptr = 0; + } + + } + break; + } + + } else { + T0_ENTER(ip, rp, t0x); + } + } +t0_exit: + ((t0_context *)t0ctx)->dp = dp; + ((t0_context *)t0ctx)->rp = rp; + ((t0_context *)t0ctx)->ip = ip; +} diff --git a/src/bearssl/src/codec/pemdec.t0 b/src/bearssl/src/codec/pemdec.t0 new file mode 100644 index 0000000..2237abb --- /dev/null +++ b/src/bearssl/src/codec/pemdec.t0 @@ -0,0 +1,314 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +preamble { + +#include "inner.h" + +#define CTX ((br_pem_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu))) + +/* see bearssl_pem.h */ +void +br_pem_decoder_init(br_pem_decoder_context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + ctx->cpu.dp = &ctx->dp_stack[0]; + ctx->cpu.rp = &ctx->rp_stack[0]; + br_pem_decoder_init_main(&ctx->cpu); + br_pem_decoder_run(&ctx->cpu); +} + +/* see bearssl_pem.h */ +size_t +br_pem_decoder_push(br_pem_decoder_context *ctx, + const void *data, size_t len) +{ + if (ctx->event) { + return 0; + } + ctx->hbuf = data; + ctx->hlen = len; + br_pem_decoder_run(&ctx->cpu); + return len - ctx->hlen; +} + +/* see bearssl_pem.h */ +int +br_pem_decoder_event(br_pem_decoder_context *ctx) +{ + int event; + + event = ctx->event; + ctx->event = 0; + return event; +} + +} + +\ Define a word that evaluates to the address of a field within the +\ decoder context. +: addr: + next-word { field } + "addr-" field + 0 1 define-word + 0 8191 "offsetof(br_pem_decoder_context, " field + ")" + make-CX + postpone literal postpone ; ; + +addr: event +addr: name +addr: buf +addr: ptr + +\ Set a byte at a specific address (offset within the context). +cc: set8 ( value addr -- ) { + size_t addr = T0_POP(); + unsigned x = T0_POP(); + *((unsigned char *)CTX + addr) = x; +} + +\ Get a byte at a specific address (offset within the context). +cc: get8 ( addr -- value ) { + size_t addr = T0_POP(); + T0_PUSH(*((unsigned char *)CTX + addr)); +} + +\ Send an event. +: send-event ( event -- ) + addr-event set8 co ; + +\ Low-level function to read a single byte. Returned value is the byte +\ (0 to 255), or -1 if there is no available data. +cc: read8-native ( -- x ) { + if (CTX->hlen > 0) { + T0_PUSH(*CTX->hbuf ++); + CTX->hlen --; + } else { + T0_PUSHi(-1); + } +} + +\ Read next byte. Block until the next byte is available. +: read8 ( -- x ) + begin read8-native dup 0< ifnot ret then drop co again ; + +\ Read bytes until next end-of-line. +: skip-newline ( -- ) + begin read8 `\n <> while repeat ; + +\ Read bytes until next end-of-line; verify that they are all whitespace. +\ This returns -1 if they were all whitespace, 0 otherwise. +: skip-newline-ws ( -- bool ) + -1 { r } + begin read8 dup `\n <> while ws? ifnot 0 >r then repeat + drop r ; + +\ Normalise a byte to uppercase (ASCII only). +: norm-upper ( x -- x ) + dup dup `a >= swap `z <= and if 32 - then ; + +\ Read bytes and compare with the provided string. On mismatch, the +\ rest of the line is consumed. Matching is not case sensitive. +: match-string ( str -- bool ) + begin + dup data-get8 norm-upper dup ifnot 2drop -1 ret then + read8 norm-upper dup `\n = if drop 2drop 0 ret then + = ifnot drop skip-newline 0 ret then + 1+ + again ; + +\ Read bytes into the provided buffer, but no more than the provided +\ count. Reading stops when end-of-line is reached. Returned value +\ is the count of bytes written to the buffer, or 0 if the buffer size +\ was exceeded. All bytes are normalised to uppercase (ASCII only). +: read-bytes ( addr len -- len ) + dup { orig-len } + swap + begin + over ifnot 2drop skip-newline 0 ret then + read8 dup `\n = if 2drop orig-len swap - ret then + dup `\r = if drop else norm-upper over set8 then + 1+ swap 1- swap + again ; + +\ Remove trailing dashes from the name buffer. +: trim-dashes ( len -- ) + begin dup while + 1- + dup addr-name + get8 `- <> if + addr-name + 1+ 0 swap set8 ret + then + repeat + addr-name set8 ; + +\ Scan input for next "begin" banner. +: next-banner-begin ( -- ) + begin + "-----BEGIN " match-string if + addr-name 127 read-bytes + dup if trim-dashes ret then + drop + then + again ; + +\ Convert a Base64 character to its numerical value. Returned value is +\ 0 to 63 for Base64 characters, -1 for '=', and -2 for all other characters. +cc: from-base64 ( char -- x ) { + uint32_t c = T0_POP(); + uint32_t p, q, r, z; + p = c - 0x41; + q = c - 0x61; + r = c - 0x30; + + z = ((p + 2) & -LT(p, 26)) + | ((q + 28) & -LT(q, 26)) + | ((r + 54) & -LT(r, 10)) + | (64 & -EQ(c, 0x2B)) + | (65 & -EQ(c, 0x2F)) + | EQ(c, 0x3D); + T0_PUSHi((int32_t)z - 2); +} + +\ Test whether a character is whitespace (but not a newline). +: ws? ( x -- bool ) + dup `\n <> swap 32 <= and ; + +\ Read next character, skipping whitespace (except newline). +: next-nonws ( -- x ) + begin + read8 dup ws? ifnot ret then + drop + again ; + +\ Write one byte in the output buffer. +cc: write8 ( x -- ) { + unsigned char x = (unsigned char)T0_POP(); + CTX->buf[CTX->ptr ++] = x; + if (CTX->ptr == sizeof CTX->buf) { + if (CTX->dest) { + CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf); + } + CTX->ptr = 0; + } +} + +\ Flush the output buffer. +cc: flush-buf ( -- ) { + if (CTX->ptr > 0) { + if (CTX->dest) { + CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr); + } + CTX->ptr = 0; + } +} + +\ Decode the four next Base64 characters. Returned value is: +\ 0 quartet processed, three bytes produced. +\ -1 dash encountered as first character (no leading whitespace). +\ 1 quartet processed, one or two bytes produced, terminator reached. +\ 2 end-of-line reached. +\ 3 error. +\ For all positive return values, the remaining of the current line has been +\ consumed. +: decode-next-quartet ( -- r ) + \ Process first character. It may be a dash. + read8 dup `- = if drop -1 ret then + dup ws? if drop next-nonws then + dup `\n = if drop 2 ret then + from-base64 dup 0< if drop skip-newline 3 ret then + { acc } + + \ Second character. + next-nonws dup `\n = if drop 3 ret then + from-base64 dup 0< if drop skip-newline 3 ret then + acc 6 << + >acc + + \ Third character: may be an equal sign. + next-nonws dup `\n = if drop 3 ret then + dup `= = if + \ Fourth character must be an equal sign. + drop + next-nonws dup `\n = if drop 3 ret then + skip-newline-ws ifnot drop 3 ret then + `= <> if 3 ret then + acc 0x0F and if 3 ret then + acc 4 >> write8 + 1 ret + then + from-base64 dup 0< if drop skip-newline 3 ret then + acc 6 << + >acc + + \ Fourth character: may be an equal sign. + next-nonws dup `\n = if drop 3 ret then + dup `= = if + drop skip-newline-ws ifnot 3 ret then + acc 0x03 and if 3 ret then + acc 10 >> write8 + acc 2 >> write8 + 1 ret + then + from-base64 dup 0< if drop skip-newline 3 ret then + acc 6 << + >acc + acc 16 >> write8 + acc 8 >> write8 + acc write8 + 0 ; + +\ Check trailer line (possibly, the leading dash has been read). This +\ sends the appropriate event. +: check-trailer ( bool -- ) + ifnot + begin read8 dup `\n = while drop repeat + `- <> if skip-newline 3 send-event ret then + then + "----END " match-string ifnot 3 send-event ret then + flush-buf + skip-newline 2 send-event ; + +\ Decode one line worth of characters. Returned value is 0 if the end of the +\ object is reached, -1 otherwise. The end of object or error event is sent. +: decode-line ( -- bool ) + -1 { first } + begin + decode-next-quartet + case + 0 of endof + -1 of + first ifnot + skip-newline 3 send-event + else + -1 check-trailer + then + 0 ret + endof + 1 of 0 check-trailer 0 ret endof + 2 of -1 ret endof + + \ On decoding error + drop 3 send-event 0 ret + endcase + 0 >first + again ; + +: main ( -- ! ) + begin + next-banner-begin 1 send-event + begin decode-line while repeat + again ; diff --git a/src/bearssl/src/codec/pemenc.c b/src/bearssl/src/codec/pemenc.c new file mode 100644 index 0000000..236601e --- /dev/null +++ b/src/bearssl/src/codec/pemenc.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Get the appropriate Base64 character for a numeric value in the + * 0..63 range. This is constant-time. + */ +static char +b64char(uint32_t x) +{ + /* + * Values 0 to 25 map to 0x41..0x5A ('A' to 'Z') + * Values 26 to 51 map to 0x61..0x7A ('a' to 'z') + * Values 52 to 61 map to 0x30..0x39 ('0' to '9') + * Value 62 maps to 0x2B ('+') + * Value 63 maps to 0x2F ('/') + */ + uint32_t a, b, c; + + a = x - 26; + b = x - 52; + c = x - 62; + + /* + * Looking at bits 8..15 of values a, b and c: + * + * x a b c + * --------------------- + * 0..25 FF FF FF + * 26..51 00 FF FF + * 52..61 00 00 FF + * 62..63 00 00 00 + */ + return (char)(((x + 0x41) & ((a & b & c) >> 8)) + | ((x + (0x61 - 26)) & ((~a & b & c) >> 8)) + | ((x - (52 - 0x30)) & ((~a & ~b & c) >> 8)) + | ((0x2B + ((x & 1) << 2)) & (~(a | b | c) >> 8))); +} + +/* see bearssl_pem.h */ +size_t +br_pem_encode(void *dest, const void *data, size_t len, + const char *banner, unsigned flags) +{ + size_t dlen, banner_len, lines; + char *d; + unsigned char *buf; + size_t u; + int off, lim; + + banner_len = strlen(banner); + /* FIXME: try to avoid divisions here, as they may pull + an extra libc function. */ + if ((flags & BR_PEM_LINE64) != 0) { + lines = (len + 47) / 48; + } else { + lines = (len + 56) / 57; + } + dlen = (banner_len << 1) + 30 + (((len + 2) / 3) << 2) + + lines + 2; + if ((flags & BR_PEM_CRLF) != 0) { + dlen += lines + 2; + } + + if (dest == NULL) { + return dlen; + } + + d = dest; + + /* + * We always move the source data to the end of output buffer; + * the encoding process never "catches up" except at the very + * end. This also handles all conditions of partial or total + * overlap. + */ + buf = (unsigned char *)d + dlen - len; + memmove(buf, data, len); + + memcpy(d, "-----BEGIN ", 11); + d += 11; + memcpy(d, banner, banner_len); + d += banner_len; + memcpy(d, "-----", 5); + d += 5; + if ((flags & BR_PEM_CRLF) != 0) { + *d ++ = 0x0D; + } + *d ++ = 0x0A; + + off = 0; + lim = (flags & BR_PEM_LINE64) != 0 ? 16 : 19; + for (u = 0; (u + 2) < len; u += 3) { + uint32_t w; + + w = ((uint32_t)buf[u] << 16) + | ((uint32_t)buf[u + 1] << 8) + | (uint32_t)buf[u + 2]; + *d ++ = b64char(w >> 18); + *d ++ = b64char((w >> 12) & 0x3F); + *d ++ = b64char((w >> 6) & 0x3F); + *d ++ = b64char(w & 0x3F); + if (++ off == lim) { + off = 0; + if ((flags & BR_PEM_CRLF) != 0) { + *d ++ = 0x0D; + } + *d ++ = 0x0A; + } + } + if (u < len) { + uint32_t w; + + w = (uint32_t)buf[u] << 16; + if (u + 1 < len) { + w |= (uint32_t)buf[u + 1] << 8; + } + *d ++ = b64char(w >> 18); + *d ++ = b64char((w >> 12) & 0x3F); + if (u + 1 < len) { + *d ++ = b64char((w >> 6) & 0x3F); + } else { + *d ++ = 0x3D; + } + *d ++ = 0x3D; + off ++; + } + if (off != 0) { + if ((flags & BR_PEM_CRLF) != 0) { + *d ++ = 0x0D; + } + *d ++ = 0x0A; + } + + memcpy(d, "-----END ", 9); + d += 9; + memcpy(d, banner, banner_len); + d += banner_len; + memcpy(d, "-----", 5); + d += 5; + if ((flags & BR_PEM_CRLF) != 0) { + *d ++ = 0x0D; + } + *d ++ = 0x0A; + + /* Final zero, not counted in returned length. */ + *d ++ = 0x00; + + return dlen; +} diff --git a/src/bearssl/src/ec/ec_all_m15.c b/src/bearssl/src/ec/ec_all_m15.c new file mode 100644 index 0000000..bb550e1 --- /dev/null +++ b/src/bearssl/src/ec/ec_all_m15.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m15.generator(curve, len); + case BR_EC_curve25519: + return br_ec_c25519_m15.generator(curve, len); + default: + return br_ec_prime_i15.generator(curve, len); + } +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m15.order(curve, len); + case BR_EC_curve25519: + return br_ec_c25519_m15.order(curve, len); + default: + return br_ec_prime_i15.order(curve, len); + } +} + +static size_t +api_xoff(int curve, size_t *len) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m15.xoff(curve, len); + case BR_EC_curve25519: + return br_ec_c25519_m15.xoff(curve, len); + default: + return br_ec_prime_i15.xoff(curve, len); + } +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m15.mul(G, Glen, kb, kblen, curve); + case BR_EC_curve25519: + return br_ec_c25519_m15.mul(G, Glen, kb, kblen, curve); + default: + return br_ec_prime_i15.mul(G, Glen, kb, kblen, curve); + } +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m15.mulgen(R, x, xlen, curve); + case BR_EC_curve25519: + return br_ec_c25519_m15.mulgen(R, x, xlen, curve); + default: + return br_ec_prime_i15.mulgen(R, x, xlen, curve); + } +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m15.muladd(A, B, len, + x, xlen, y, ylen, curve); + case BR_EC_curve25519: + return br_ec_c25519_m15.muladd(A, B, len, + x, xlen, y, ylen, curve); + default: + return br_ec_prime_i15.muladd(A, B, len, + x, xlen, y, ylen, curve); + } +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_all_m15 = { + (uint32_t)0x23800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_all_m31.c b/src/bearssl/src/ec/ec_all_m31.c new file mode 100644 index 0000000..0552c4b --- /dev/null +++ b/src/bearssl/src/ec/ec_all_m31.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m31.generator(curve, len); + case BR_EC_curve25519: + return br_ec_c25519_m31.generator(curve, len); + default: + return br_ec_prime_i31.generator(curve, len); + } +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m31.order(curve, len); + case BR_EC_curve25519: + return br_ec_c25519_m31.order(curve, len); + default: + return br_ec_prime_i31.order(curve, len); + } +} + +static size_t +api_xoff(int curve, size_t *len) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m31.xoff(curve, len); + case BR_EC_curve25519: + return br_ec_c25519_m31.xoff(curve, len); + default: + return br_ec_prime_i31.xoff(curve, len); + } +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m31.mul(G, Glen, kb, kblen, curve); + case BR_EC_curve25519: + return br_ec_c25519_m31.mul(G, Glen, kb, kblen, curve); + default: + return br_ec_prime_i31.mul(G, Glen, kb, kblen, curve); + } +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m31.mulgen(R, x, xlen, curve); + case BR_EC_curve25519: + return br_ec_c25519_m31.mulgen(R, x, xlen, curve); + default: + return br_ec_prime_i31.mulgen(R, x, xlen, curve); + } +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return br_ec_p256_m31.muladd(A, B, len, + x, xlen, y, ylen, curve); + case BR_EC_curve25519: + return br_ec_c25519_m31.muladd(A, B, len, + x, xlen, y, ylen, curve); + default: + return br_ec_prime_i31.muladd(A, B, len, + x, xlen, y, ylen, curve); + } +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_all_m31 = { + (uint32_t)0x23800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_c25519_i15.c b/src/bearssl/src/ec/ec_c25519_i15.c new file mode 100644 index 0000000..361e75f --- /dev/null +++ b/src/bearssl/src/ec/ec_c25519_i15.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Parameters for the field: + * - field modulus p = 2^255-19 + * - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p) + */ + +static const uint16_t C255_P[] = { + 0x0110, + 0x7FED, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF +}; + +#define P0I 0x4A1B + +static const uint16_t C255_R2[] = { + 0x0110, + 0x0169, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000 +}; + +/* obsolete +#include +#include +static void +print_int_mont(const char *name, const uint16_t *x) +{ + uint16_t y[18]; + unsigned char tmp[32]; + size_t u; + + printf("%s = ", name); + memcpy(y, x, sizeof y); + br_i15_from_monty(y, C255_P, P0I); + br_i15_encode(tmp, sizeof tmp, y); + for (u = 0; u < sizeof tmp; u ++) { + printf("%02X", tmp[u]); + } + printf("\n"); +} +*/ + +static const uint16_t C255_A24[] = { + 0x0110, + 0x45D3, 0x0046, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000 +}; + +static const unsigned char GEN[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ORDER[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return GEN; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return ORDER; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 0; +} + +static void +cswap(uint16_t *a, uint16_t *b, uint32_t ctl) +{ + int i; + + ctl = -ctl; + for (i = 0; i < 18; i ++) { + uint32_t aw, bw, tw; + + aw = a[i]; + bw = b[i]; + tw = ctl & (aw ^ bw); + a[i] = aw ^ tw; + b[i] = bw ^ tw; + } +} + +static void +c255_add(uint16_t *d, const uint16_t *a, const uint16_t *b) +{ + uint32_t ctl; + uint16_t t[18]; + + memcpy(t, a, sizeof t); + ctl = br_i15_add(t, b, 1); + ctl |= NOT(br_i15_sub(t, C255_P, 0)); + br_i15_sub(t, C255_P, ctl); + memcpy(d, t, sizeof t); +} + +static void +c255_sub(uint16_t *d, const uint16_t *a, const uint16_t *b) +{ + uint16_t t[18]; + + memcpy(t, a, sizeof t); + br_i15_add(t, C255_P, br_i15_sub(t, b, 1)); + memcpy(d, t, sizeof t); +} + +static void +c255_mul(uint16_t *d, const uint16_t *a, const uint16_t *b) +{ + uint16_t t[18]; + + br_i15_montymul(t, a, b, C255_P, P0I); + memcpy(d, t, sizeof t); +} + +static void +byteswap(unsigned char *G) +{ + int i; + + for (i = 0; i < 16; i ++) { + unsigned char t; + + t = G[i]; + G[i] = G[31 - i]; + G[31 - i] = t; + } +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ +#define ILEN (18 * sizeof(uint16_t)) + + /* + * The a[] and b[] arrays have an extra word to allow for + * decoding without using br_i15_decode_reduce(). + */ + uint16_t x1[18], x2[18], x3[18], z2[18], z3[18]; + uint16_t a[19], aa[18], b[19], bb[18]; + uint16_t c[18], d[18], e[18], da[18], cb[18]; + unsigned char k[32]; + uint32_t swap; + int i; + + (void)curve; + + /* + * Points are encoded over exactly 32 bytes. Multipliers must fit + * in 32 bytes as well. + * RFC 7748 mandates that the high bit of the last point byte must + * be ignored/cleared. + */ + if (Glen != 32 || kblen > 32) { + return 0; + } + G[31] &= 0x7F; + + /* + * Byteswap the point encoding, because it uses little-endian, and + * the generic decoding routine uses big-endian. + */ + byteswap(G); + + /* + * Decode the point ('u' coordinate). This should be reduced + * modulo p, but we prefer to avoid the dependency on + * br_i15_decode_reduce(). Instead, we use br_i15_decode_mod() + * with a synthetic modulus of value 2^255 (this must work + * since G was truncated to 255 bits), then use a conditional + * subtraction. We use br_i15_decode_mod() and not + * br_i15_decode(), because the ec_prime_i15 implementation uses + * the former but not the latter. + * br_i15_decode_reduce(a, G, 32, C255_P); + */ + br_i15_zero(b, 0x111); + b[18] = 1; + br_i15_decode_mod(a, G, 32, b); + a[0] = 0x110; + br_i15_sub(a, C255_P, NOT(br_i15_sub(a, C255_P, 0))); + + /* + * Initialise variables x1, x2, z2, x3 and z3. We set all of them + * into Montgomery representation. + */ + br_i15_montymul(x1, a, C255_R2, C255_P, P0I); + memcpy(x3, x1, ILEN); + br_i15_zero(z2, C255_P[0]); + memcpy(x2, z2, ILEN); + x2[1] = 19; + memcpy(z3, x2, ILEN); + + memcpy(k, kb, kblen); + memset(k + kblen, 0, (sizeof k) - kblen); + k[0] &= 0xF8; + k[31] &= 0x7F; + k[31] |= 0x40; + + /* obsolete + print_int_mont("x1", x1); + */ + + swap = 0; + for (i = 254; i >= 0; i --) { + uint32_t kt; + + kt = (k[i >> 3] >> (i & 7)) & 1; + swap ^= kt; + cswap(x2, x3, swap); + cswap(z2, z3, swap); + swap = kt; + + /* obsolete + print_int_mont("x2", x2); + print_int_mont("z2", z2); + print_int_mont("x3", x3); + print_int_mont("z3", z3); + */ + + c255_add(a, x2, z2); + c255_mul(aa, a, a); + c255_sub(b, x2, z2); + c255_mul(bb, b, b); + c255_sub(e, aa, bb); + c255_add(c, x3, z3); + c255_sub(d, x3, z3); + c255_mul(da, d, a); + c255_mul(cb, c, b); + + /* obsolete + print_int_mont("a ", a); + print_int_mont("aa", aa); + print_int_mont("b ", b); + print_int_mont("bb", bb); + print_int_mont("e ", e); + print_int_mont("c ", c); + print_int_mont("d ", d); + print_int_mont("da", da); + print_int_mont("cb", cb); + */ + + c255_add(x3, da, cb); + c255_mul(x3, x3, x3); + c255_sub(z3, da, cb); + c255_mul(z3, z3, z3); + c255_mul(z3, z3, x1); + c255_mul(x2, aa, bb); + c255_mul(z2, C255_A24, e); + c255_add(z2, z2, aa); + c255_mul(z2, e, z2); + + /* obsolete + print_int_mont("x2", x2); + print_int_mont("z2", z2); + print_int_mont("x3", x3); + print_int_mont("z3", z3); + */ + } + cswap(x2, x3, swap); + cswap(z2, z3, swap); + + /* + * Inverse z2 with a modular exponentiation. This is a simple + * square-and-multiply algorithm; we mutualise most non-squarings + * since the exponent contains almost only ones. + */ + memcpy(a, z2, ILEN); + for (i = 0; i < 15; i ++) { + c255_mul(a, a, a); + c255_mul(a, a, z2); + } + memcpy(b, a, ILEN); + for (i = 0; i < 14; i ++) { + int j; + + for (j = 0; j < 16; j ++) { + c255_mul(b, b, b); + } + c255_mul(b, b, a); + } + for (i = 14; i >= 0; i --) { + c255_mul(b, b, b); + if ((0xFFEB >> i) & 1) { + c255_mul(b, z2, b); + } + } + c255_mul(b, x2, b); + + /* + * To avoid a dependency on br_i15_from_monty(), we use a + * Montgomery multiplication with 1. + * memcpy(x2, b, ILEN); + * br_i15_from_monty(x2, C255_P, P0I); + */ + br_i15_zero(a, C255_P[0]); + a[1] = 1; + br_i15_montymul(x2, a, b, C255_P, P0I); + + br_i15_encode(G, 32, x2); + byteswap(G); + return 1; + +#undef ILEN +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We don't implement this method, since it is used for ECDSA + * only, and there is no ECDSA over Curve25519 (which instead + * uses EdDSA). + */ + (void)A; + (void)B; + (void)len; + (void)x; + (void)xlen; + (void)y; + (void)ylen; + (void)curve; + return 0; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_c25519_i15 = { + (uint32_t)0x20000000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_c25519_i31.c b/src/bearssl/src/ec/ec_c25519_i31.c new file mode 100644 index 0000000..aa88dd6 --- /dev/null +++ b/src/bearssl/src/ec/ec_c25519_i31.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Parameters for the field: + * - field modulus p = 2^255-19 + * - R^2 mod p (R = 2^(31k) for the smallest k such that R >= p) + */ + +static const uint32_t C255_P[] = { + 0x00000107, + 0x7FFFFFED, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, + 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x0000007F +}; + +#define P0I 0x286BCA1B + +static const uint32_t C255_R2[] = { + 0x00000107, + 0x00000000, 0x02D20000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +static const uint32_t C255_A24[] = { + 0x00000107, + 0x53000000, 0x0000468B, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +/* obsolete +#include +#include +static void +print_int_mont(const char *name, const uint32_t *x) +{ + uint32_t y[10]; + unsigned char tmp[32]; + size_t u; + + printf("%s = ", name); + memcpy(y, x, sizeof y); + br_i31_from_monty(y, C255_P, P0I); + br_i31_encode(tmp, sizeof tmp, y); + for (u = 0; u < sizeof tmp; u ++) { + printf("%02X", tmp[u]); + } + printf("\n"); +} +*/ + +static const unsigned char GEN[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ORDER[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return GEN; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return ORDER; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 0; +} + +static void +cswap(uint32_t *a, uint32_t *b, uint32_t ctl) +{ + int i; + + ctl = -ctl; + for (i = 0; i < 10; i ++) { + uint32_t aw, bw, tw; + + aw = a[i]; + bw = b[i]; + tw = ctl & (aw ^ bw); + a[i] = aw ^ tw; + b[i] = bw ^ tw; + } +} + +static void +c255_add(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t ctl; + uint32_t t[10]; + + memcpy(t, a, sizeof t); + ctl = br_i31_add(t, b, 1); + ctl |= NOT(br_i31_sub(t, C255_P, 0)); + br_i31_sub(t, C255_P, ctl); + memcpy(d, t, sizeof t); +} + +static void +c255_sub(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t t[10]; + + memcpy(t, a, sizeof t); + br_i31_add(t, C255_P, br_i31_sub(t, b, 1)); + memcpy(d, t, sizeof t); +} + +static void +c255_mul(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t t[10]; + + br_i31_montymul(t, a, b, C255_P, P0I); + memcpy(d, t, sizeof t); +} + +static void +byteswap(unsigned char *G) +{ + int i; + + for (i = 0; i < 16; i ++) { + unsigned char t; + + t = G[i]; + G[i] = G[31 - i]; + G[31 - i] = t; + } +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + uint32_t x1[10], x2[10], x3[10], z2[10], z3[10]; + uint32_t a[10], aa[10], b[10], bb[10]; + uint32_t c[10], d[10], e[10], da[10], cb[10]; + unsigned char k[32]; + uint32_t swap; + int i; + + (void)curve; + + /* + * Points are encoded over exactly 32 bytes. Multipliers must fit + * in 32 bytes as well. + * RFC 7748 mandates that the high bit of the last point byte must + * be ignored/cleared. + */ + if (Glen != 32 || kblen > 32) { + return 0; + } + G[31] &= 0x7F; + + /* + * Byteswap the point encoding, because it uses little-endian, and + * the generic decoding routine uses big-endian. + */ + byteswap(G); + + /* + * Decode the point ('u' coordinate). This should be reduced + * modulo p, but we prefer to avoid the dependency on + * br_i31_decode_reduce(). Instead, we use br_i31_decode_mod() + * with a synthetic modulus of value 2^255 (this must work + * since G was truncated to 255 bits), then use a conditional + * subtraction. We use br_i31_decode_mod() and not + * br_i31_decode(), because the ec_prime_i31 implementation uses + * the former but not the latter. + * br_i31_decode_reduce(a, G, 32, C255_P); + */ + br_i31_zero(b, 0x108); + b[9] = 0x0100; + br_i31_decode_mod(a, G, 32, b); + a[0] = 0x107; + br_i31_sub(a, C255_P, NOT(br_i31_sub(a, C255_P, 0))); + + /* + * Initialise variables x1, x2, z2, x3 and z3. We set all of them + * into Montgomery representation. + */ + br_i31_montymul(x1, a, C255_R2, C255_P, P0I); + memcpy(x3, x1, sizeof x1); + br_i31_zero(z2, C255_P[0]); + memcpy(x2, z2, sizeof z2); + x2[1] = 0x13000000; + memcpy(z3, x2, sizeof x2); + + memcpy(k, kb, kblen); + memset(k + kblen, 0, (sizeof k) - kblen); + k[0] &= 0xF8; + k[31] &= 0x7F; + k[31] |= 0x40; + + /* obsolete + print_int_mont("x1", x1); + */ + + swap = 0; + for (i = 254; i >= 0; i --) { + uint32_t kt; + + kt = (k[i >> 3] >> (i & 7)) & 1; + swap ^= kt; + cswap(x2, x3, swap); + cswap(z2, z3, swap); + swap = kt; + + /* obsolete + print_int_mont("x2", x2); + print_int_mont("z2", z2); + print_int_mont("x3", x3); + print_int_mont("z3", z3); + */ + + c255_add(a, x2, z2); + c255_mul(aa, a, a); + c255_sub(b, x2, z2); + c255_mul(bb, b, b); + c255_sub(e, aa, bb); + c255_add(c, x3, z3); + c255_sub(d, x3, z3); + c255_mul(da, d, a); + c255_mul(cb, c, b); + + /* obsolete + print_int_mont("a ", a); + print_int_mont("aa", aa); + print_int_mont("b ", b); + print_int_mont("bb", bb); + print_int_mont("e ", e); + print_int_mont("c ", c); + print_int_mont("d ", d); + print_int_mont("da", da); + print_int_mont("cb", cb); + */ + + c255_add(x3, da, cb); + c255_mul(x3, x3, x3); + c255_sub(z3, da, cb); + c255_mul(z3, z3, z3); + c255_mul(z3, z3, x1); + c255_mul(x2, aa, bb); + c255_mul(z2, C255_A24, e); + c255_add(z2, z2, aa); + c255_mul(z2, e, z2); + + /* obsolete + print_int_mont("x2", x2); + print_int_mont("z2", z2); + print_int_mont("x3", x3); + print_int_mont("z3", z3); + */ + } + cswap(x2, x3, swap); + cswap(z2, z3, swap); + + /* + * Inverse z2 with a modular exponentiation. This is a simple + * square-and-multiply algorithm; we mutualise most non-squarings + * since the exponent contains almost only ones. + */ + memcpy(a, z2, sizeof z2); + for (i = 0; i < 15; i ++) { + c255_mul(a, a, a); + c255_mul(a, a, z2); + } + memcpy(b, a, sizeof a); + for (i = 0; i < 14; i ++) { + int j; + + for (j = 0; j < 16; j ++) { + c255_mul(b, b, b); + } + c255_mul(b, b, a); + } + for (i = 14; i >= 0; i --) { + c255_mul(b, b, b); + if ((0xFFEB >> i) & 1) { + c255_mul(b, z2, b); + } + } + c255_mul(b, x2, b); + + /* + * To avoid a dependency on br_i31_from_monty(), we use + * a Montgomery multiplication with 1. + * memcpy(x2, b, sizeof b); + * br_i31_from_monty(x2, C255_P, P0I); + */ + br_i31_zero(a, C255_P[0]); + a[1] = 1; + br_i31_montymul(x2, a, b, C255_P, P0I); + + br_i31_encode(G, 32, x2); + byteswap(G); + return 1; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We don't implement this method, since it is used for ECDSA + * only, and there is no ECDSA over Curve25519 (which instead + * uses EdDSA). + */ + (void)A; + (void)B; + (void)len; + (void)x; + (void)xlen; + (void)y; + (void)ylen; + (void)curve; + return 0; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_c25519_i31 = { + (uint32_t)0x20000000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_c25519_m15.c b/src/bearssl/src/ec/ec_c25519_m15.c new file mode 100644 index 0000000..0373197 --- /dev/null +++ b/src/bearssl/src/ec/ec_c25519_m15.c @@ -0,0 +1,1478 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* obsolete +#include +#include +static void +print_int(const char *name, const uint32_t *x) +{ + size_t u; + unsigned char tmp[36]; + + printf("%s = ", name); + for (u = 0; u < 20; u ++) { + if (x[u] > 0x1FFF) { + printf("INVALID:"); + for (u = 0; u < 20; u ++) { + printf(" %04X", x[u]); + } + printf("\n"); + return; + } + } + memset(tmp, 0, sizeof tmp); + for (u = 0; u < 20; u ++) { + uint32_t w; + int j, k; + + w = x[u]; + j = 13 * (int)u; + k = j & 7; + if (k != 0) { + w <<= k; + j -= k; + } + k = j >> 3; + tmp[35 - k] |= (unsigned char)w; + tmp[34 - k] |= (unsigned char)(w >> 8); + tmp[33 - k] |= (unsigned char)(w >> 16); + tmp[32 - k] |= (unsigned char)(w >> 24); + } + for (u = 4; u < 36; u ++) { + printf("%02X", tmp[u]); + } + printf("\n"); +} +*/ + +/* + * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_ + * that right-shifting a signed negative integer copies the sign bit + * (arithmetic right-shift). This is "implementation-defined behaviour", + * i.e. it is not undefined, but it may differ between compilers. Each + * compiler is supposed to document its behaviour in that respect. GCC + * explicitly defines that an arithmetic right shift is used. We expect + * all other compilers to do the same, because underlying CPU offer an + * arithmetic right shift opcode that could not be used otherwise. + */ +#if BR_NO_ARITH_SHIFT +#define ARSH(x, n) (((uint32_t)(x) >> (n)) \ + | ((-((uint32_t)(x) >> 31)) << (32 - (n)))) +#else +#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n)) +#endif + +/* + * Convert an integer from unsigned little-endian encoding to a sequence of + * 13-bit words in little-endian order. The final "partial" word is + * returned. + */ +static uint32_t +le8_to_le13(uint32_t *dst, const unsigned char *src, size_t len) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + acc |= (uint32_t)(*src ++) << acc_len; + acc_len += 8; + if (acc_len >= 13) { + *dst ++ = acc & 0x1FFF; + acc >>= 13; + acc_len -= 13; + } + } + return acc; +} + +/* + * Convert an integer (13-bit words, little-endian) to unsigned + * little-endian encoding. The total encoding length is provided; all + * the destination bytes will be filled. + */ +static void +le13_to_le8(unsigned char *dst, size_t len, const uint32_t *src) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + if (acc_len < 8) { + acc |= (*src ++) << acc_len; + acc_len += 13; + } + *dst ++ = (unsigned char)acc; + acc >>= 8; + acc_len -= 8; + } +} + +/* + * Normalise an array of words to a strict 13 bits per word. Returned + * value is the resulting carry. The source (w) and destination (d) + * arrays may be identical, but shall not overlap partially. + */ +static inline uint32_t +norm13(uint32_t *d, const uint32_t *w, size_t len) +{ + size_t u; + uint32_t cc; + + cc = 0; + for (u = 0; u < len; u ++) { + int32_t z; + + z = w[u] + cc; + d[u] = z & 0x1FFF; + cc = ARSH(z, 13); + } + return cc; +} + +/* + * mul20() multiplies two 260-bit integers together. Each word must fit + * on 13 bits; source operands use 20 words, destination operand + * receives 40 words. All overlaps allowed. + * + * square20() computes the square of a 260-bit integer. Each word must + * fit on 13 bits; source operand uses 20 words, destination operand + * receives 40 words. All overlaps allowed. + */ + +#if BR_SLOW_MUL15 + +static void +mul20(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + /* + * Two-level Karatsuba: turns a 20x20 multiplication into + * nine 5x5 multiplications. We use 13-bit words but do not + * propagate carries immediately, so words may expand: + * + * - First Karatsuba decomposition turns the 20x20 mul on + * 13-bit words into three 10x10 muls, two on 13-bit words + * and one on 14-bit words. + * + * - Second Karatsuba decomposition further splits these into: + * + * * four 5x5 muls on 13-bit words + * * four 5x5 muls on 14-bit words + * * one 5x5 mul on 15-bit words + * + * Highest word value is 8191, 16382 or 32764, for 13-bit, 14-bit + * or 15-bit words, respectively. + */ + uint32_t u[45], v[45], w[90]; + uint32_t cc; + int i; + +#define ZADD(dw, d_off, s1w, s1_off, s2w, s2_off) do { \ + (dw)[5 * (d_off) + 0] = (s1w)[5 * (s1_off) + 0] \ + + (s2w)[5 * (s2_off) + 0]; \ + (dw)[5 * (d_off) + 1] = (s1w)[5 * (s1_off) + 1] \ + + (s2w)[5 * (s2_off) + 1]; \ + (dw)[5 * (d_off) + 2] = (s1w)[5 * (s1_off) + 2] \ + + (s2w)[5 * (s2_off) + 2]; \ + (dw)[5 * (d_off) + 3] = (s1w)[5 * (s1_off) + 3] \ + + (s2w)[5 * (s2_off) + 3]; \ + (dw)[5 * (d_off) + 4] = (s1w)[5 * (s1_off) + 4] \ + + (s2w)[5 * (s2_off) + 4]; \ + } while (0) + +#define ZADDT(dw, d_off, sw, s_off) do { \ + (dw)[5 * (d_off) + 0] += (sw)[5 * (s_off) + 0]; \ + (dw)[5 * (d_off) + 1] += (sw)[5 * (s_off) + 1]; \ + (dw)[5 * (d_off) + 2] += (sw)[5 * (s_off) + 2]; \ + (dw)[5 * (d_off) + 3] += (sw)[5 * (s_off) + 3]; \ + (dw)[5 * (d_off) + 4] += (sw)[5 * (s_off) + 4]; \ + } while (0) + +#define ZSUB2F(dw, d_off, s1w, s1_off, s2w, s2_off) do { \ + (dw)[5 * (d_off) + 0] -= (s1w)[5 * (s1_off) + 0] \ + + (s2w)[5 * (s2_off) + 0]; \ + (dw)[5 * (d_off) + 1] -= (s1w)[5 * (s1_off) + 1] \ + + (s2w)[5 * (s2_off) + 1]; \ + (dw)[5 * (d_off) + 2] -= (s1w)[5 * (s1_off) + 2] \ + + (s2w)[5 * (s2_off) + 2]; \ + (dw)[5 * (d_off) + 3] -= (s1w)[5 * (s1_off) + 3] \ + + (s2w)[5 * (s2_off) + 3]; \ + (dw)[5 * (d_off) + 4] -= (s1w)[5 * (s1_off) + 4] \ + + (s2w)[5 * (s2_off) + 4]; \ + } while (0) + +#define CPR1(w, cprcc) do { \ + uint32_t cprz = (w) + cprcc; \ + (w) = cprz & 0x1FFF; \ + cprcc = cprz >> 13; \ + } while (0) + +#define CPR(dw, d_off) do { \ + uint32_t cprcc; \ + cprcc = 0; \ + CPR1((dw)[(d_off) + 0], cprcc); \ + CPR1((dw)[(d_off) + 1], cprcc); \ + CPR1((dw)[(d_off) + 2], cprcc); \ + CPR1((dw)[(d_off) + 3], cprcc); \ + CPR1((dw)[(d_off) + 4], cprcc); \ + CPR1((dw)[(d_off) + 5], cprcc); \ + CPR1((dw)[(d_off) + 6], cprcc); \ + CPR1((dw)[(d_off) + 7], cprcc); \ + CPR1((dw)[(d_off) + 8], cprcc); \ + (dw)[(d_off) + 9] = cprcc; \ + } while (0) + + memcpy(u, a, 20 * sizeof *a); + ZADD(u, 4, a, 0, a, 1); + ZADD(u, 5, a, 2, a, 3); + ZADD(u, 6, a, 0, a, 2); + ZADD(u, 7, a, 1, a, 3); + ZADD(u, 8, u, 6, u, 7); + + memcpy(v, b, 20 * sizeof *b); + ZADD(v, 4, b, 0, b, 1); + ZADD(v, 5, b, 2, b, 3); + ZADD(v, 6, b, 0, b, 2); + ZADD(v, 7, b, 1, b, 3); + ZADD(v, 8, v, 6, v, 7); + + /* + * Do the eight first 8x8 muls. Source words are at most 16382 + * each, so we can add product results together "as is" in 32-bit + * words. + */ + for (i = 0; i < 40; i += 5) { + w[(i << 1) + 0] = MUL15(u[i + 0], v[i + 0]); + w[(i << 1) + 1] = MUL15(u[i + 0], v[i + 1]) + + MUL15(u[i + 1], v[i + 0]); + w[(i << 1) + 2] = MUL15(u[i + 0], v[i + 2]) + + MUL15(u[i + 1], v[i + 1]) + + MUL15(u[i + 2], v[i + 0]); + w[(i << 1) + 3] = MUL15(u[i + 0], v[i + 3]) + + MUL15(u[i + 1], v[i + 2]) + + MUL15(u[i + 2], v[i + 1]) + + MUL15(u[i + 3], v[i + 0]); + w[(i << 1) + 4] = MUL15(u[i + 0], v[i + 4]) + + MUL15(u[i + 1], v[i + 3]) + + MUL15(u[i + 2], v[i + 2]) + + MUL15(u[i + 3], v[i + 1]) + + MUL15(u[i + 4], v[i + 0]); + w[(i << 1) + 5] = MUL15(u[i + 1], v[i + 4]) + + MUL15(u[i + 2], v[i + 3]) + + MUL15(u[i + 3], v[i + 2]) + + MUL15(u[i + 4], v[i + 1]); + w[(i << 1) + 6] = MUL15(u[i + 2], v[i + 4]) + + MUL15(u[i + 3], v[i + 3]) + + MUL15(u[i + 4], v[i + 2]); + w[(i << 1) + 7] = MUL15(u[i + 3], v[i + 4]) + + MUL15(u[i + 4], v[i + 3]); + w[(i << 1) + 8] = MUL15(u[i + 4], v[i + 4]); + w[(i << 1) + 9] = 0; + } + + /* + * For the 9th multiplication, source words are up to 32764, + * so we must do some carry propagation. If we add up to + * 4 products and the carry is no more than 524224, then the + * result fits in 32 bits, and the next carry will be no more + * than 524224 (because 4*(32764^2)+524224 < 8192*524225). + * + * We thus just skip one of the products in the middle word, + * then do a carry propagation (this reduces words to 13 bits + * each, except possibly the last, which may use up to 17 bits + * or so), then add the missing product. + */ + w[80 + 0] = MUL15(u[40 + 0], v[40 + 0]); + w[80 + 1] = MUL15(u[40 + 0], v[40 + 1]) + + MUL15(u[40 + 1], v[40 + 0]); + w[80 + 2] = MUL15(u[40 + 0], v[40 + 2]) + + MUL15(u[40 + 1], v[40 + 1]) + + MUL15(u[40 + 2], v[40 + 0]); + w[80 + 3] = MUL15(u[40 + 0], v[40 + 3]) + + MUL15(u[40 + 1], v[40 + 2]) + + MUL15(u[40 + 2], v[40 + 1]) + + MUL15(u[40 + 3], v[40 + 0]); + w[80 + 4] = MUL15(u[40 + 0], v[40 + 4]) + + MUL15(u[40 + 1], v[40 + 3]) + + MUL15(u[40 + 2], v[40 + 2]) + + MUL15(u[40 + 3], v[40 + 1]); + /* + MUL15(u[40 + 4], v[40 + 0]) */ + w[80 + 5] = MUL15(u[40 + 1], v[40 + 4]) + + MUL15(u[40 + 2], v[40 + 3]) + + MUL15(u[40 + 3], v[40 + 2]) + + MUL15(u[40 + 4], v[40 + 1]); + w[80 + 6] = MUL15(u[40 + 2], v[40 + 4]) + + MUL15(u[40 + 3], v[40 + 3]) + + MUL15(u[40 + 4], v[40 + 2]); + w[80 + 7] = MUL15(u[40 + 3], v[40 + 4]) + + MUL15(u[40 + 4], v[40 + 3]); + w[80 + 8] = MUL15(u[40 + 4], v[40 + 4]); + + CPR(w, 80); + + w[80 + 4] += MUL15(u[40 + 4], v[40 + 0]); + + /* + * The products on 14-bit words in slots 6 and 7 yield values + * up to 5*(16382^2) each, and we need to subtract two such + * values from the higher word. We need the subtraction to fit + * in a _signed_ 32-bit integer, i.e. 31 bits + a sign bit. + * However, 10*(16382^2) does not fit. So we must perform a + * bit of reduction here. + */ + CPR(w, 60); + CPR(w, 70); + + /* + * Recompose results. + */ + + /* 0..1*0..1 into 0..3 */ + ZSUB2F(w, 8, w, 0, w, 2); + ZSUB2F(w, 9, w, 1, w, 3); + ZADDT(w, 1, w, 8); + ZADDT(w, 2, w, 9); + + /* 2..3*2..3 into 4..7 */ + ZSUB2F(w, 10, w, 4, w, 6); + ZSUB2F(w, 11, w, 5, w, 7); + ZADDT(w, 5, w, 10); + ZADDT(w, 6, w, 11); + + /* (0..1+2..3)*(0..1+2..3) into 12..15 */ + ZSUB2F(w, 16, w, 12, w, 14); + ZSUB2F(w, 17, w, 13, w, 15); + ZADDT(w, 13, w, 16); + ZADDT(w, 14, w, 17); + + /* first-level recomposition */ + ZSUB2F(w, 12, w, 0, w, 4); + ZSUB2F(w, 13, w, 1, w, 5); + ZSUB2F(w, 14, w, 2, w, 6); + ZSUB2F(w, 15, w, 3, w, 7); + ZADDT(w, 2, w, 12); + ZADDT(w, 3, w, 13); + ZADDT(w, 4, w, 14); + ZADDT(w, 5, w, 15); + + /* + * Perform carry propagation to bring all words down to 13 bits. + */ + cc = norm13(d, w, 40); + d[39] += (cc << 13); + +#undef ZADD +#undef ZADDT +#undef ZSUB2F +#undef CPR1 +#undef CPR +} + +static inline void +square20(uint32_t *d, const uint32_t *a) +{ + mul20(d, a, a); +} + +#else + +static void +mul20(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t t[39]; + + t[ 0] = MUL15(a[ 0], b[ 0]); + t[ 1] = MUL15(a[ 0], b[ 1]) + + MUL15(a[ 1], b[ 0]); + t[ 2] = MUL15(a[ 0], b[ 2]) + + MUL15(a[ 1], b[ 1]) + + MUL15(a[ 2], b[ 0]); + t[ 3] = MUL15(a[ 0], b[ 3]) + + MUL15(a[ 1], b[ 2]) + + MUL15(a[ 2], b[ 1]) + + MUL15(a[ 3], b[ 0]); + t[ 4] = MUL15(a[ 0], b[ 4]) + + MUL15(a[ 1], b[ 3]) + + MUL15(a[ 2], b[ 2]) + + MUL15(a[ 3], b[ 1]) + + MUL15(a[ 4], b[ 0]); + t[ 5] = MUL15(a[ 0], b[ 5]) + + MUL15(a[ 1], b[ 4]) + + MUL15(a[ 2], b[ 3]) + + MUL15(a[ 3], b[ 2]) + + MUL15(a[ 4], b[ 1]) + + MUL15(a[ 5], b[ 0]); + t[ 6] = MUL15(a[ 0], b[ 6]) + + MUL15(a[ 1], b[ 5]) + + MUL15(a[ 2], b[ 4]) + + MUL15(a[ 3], b[ 3]) + + MUL15(a[ 4], b[ 2]) + + MUL15(a[ 5], b[ 1]) + + MUL15(a[ 6], b[ 0]); + t[ 7] = MUL15(a[ 0], b[ 7]) + + MUL15(a[ 1], b[ 6]) + + MUL15(a[ 2], b[ 5]) + + MUL15(a[ 3], b[ 4]) + + MUL15(a[ 4], b[ 3]) + + MUL15(a[ 5], b[ 2]) + + MUL15(a[ 6], b[ 1]) + + MUL15(a[ 7], b[ 0]); + t[ 8] = MUL15(a[ 0], b[ 8]) + + MUL15(a[ 1], b[ 7]) + + MUL15(a[ 2], b[ 6]) + + MUL15(a[ 3], b[ 5]) + + MUL15(a[ 4], b[ 4]) + + MUL15(a[ 5], b[ 3]) + + MUL15(a[ 6], b[ 2]) + + MUL15(a[ 7], b[ 1]) + + MUL15(a[ 8], b[ 0]); + t[ 9] = MUL15(a[ 0], b[ 9]) + + MUL15(a[ 1], b[ 8]) + + MUL15(a[ 2], b[ 7]) + + MUL15(a[ 3], b[ 6]) + + MUL15(a[ 4], b[ 5]) + + MUL15(a[ 5], b[ 4]) + + MUL15(a[ 6], b[ 3]) + + MUL15(a[ 7], b[ 2]) + + MUL15(a[ 8], b[ 1]) + + MUL15(a[ 9], b[ 0]); + t[10] = MUL15(a[ 0], b[10]) + + MUL15(a[ 1], b[ 9]) + + MUL15(a[ 2], b[ 8]) + + MUL15(a[ 3], b[ 7]) + + MUL15(a[ 4], b[ 6]) + + MUL15(a[ 5], b[ 5]) + + MUL15(a[ 6], b[ 4]) + + MUL15(a[ 7], b[ 3]) + + MUL15(a[ 8], b[ 2]) + + MUL15(a[ 9], b[ 1]) + + MUL15(a[10], b[ 0]); + t[11] = MUL15(a[ 0], b[11]) + + MUL15(a[ 1], b[10]) + + MUL15(a[ 2], b[ 9]) + + MUL15(a[ 3], b[ 8]) + + MUL15(a[ 4], b[ 7]) + + MUL15(a[ 5], b[ 6]) + + MUL15(a[ 6], b[ 5]) + + MUL15(a[ 7], b[ 4]) + + MUL15(a[ 8], b[ 3]) + + MUL15(a[ 9], b[ 2]) + + MUL15(a[10], b[ 1]) + + MUL15(a[11], b[ 0]); + t[12] = MUL15(a[ 0], b[12]) + + MUL15(a[ 1], b[11]) + + MUL15(a[ 2], b[10]) + + MUL15(a[ 3], b[ 9]) + + MUL15(a[ 4], b[ 8]) + + MUL15(a[ 5], b[ 7]) + + MUL15(a[ 6], b[ 6]) + + MUL15(a[ 7], b[ 5]) + + MUL15(a[ 8], b[ 4]) + + MUL15(a[ 9], b[ 3]) + + MUL15(a[10], b[ 2]) + + MUL15(a[11], b[ 1]) + + MUL15(a[12], b[ 0]); + t[13] = MUL15(a[ 0], b[13]) + + MUL15(a[ 1], b[12]) + + MUL15(a[ 2], b[11]) + + MUL15(a[ 3], b[10]) + + MUL15(a[ 4], b[ 9]) + + MUL15(a[ 5], b[ 8]) + + MUL15(a[ 6], b[ 7]) + + MUL15(a[ 7], b[ 6]) + + MUL15(a[ 8], b[ 5]) + + MUL15(a[ 9], b[ 4]) + + MUL15(a[10], b[ 3]) + + MUL15(a[11], b[ 2]) + + MUL15(a[12], b[ 1]) + + MUL15(a[13], b[ 0]); + t[14] = MUL15(a[ 0], b[14]) + + MUL15(a[ 1], b[13]) + + MUL15(a[ 2], b[12]) + + MUL15(a[ 3], b[11]) + + MUL15(a[ 4], b[10]) + + MUL15(a[ 5], b[ 9]) + + MUL15(a[ 6], b[ 8]) + + MUL15(a[ 7], b[ 7]) + + MUL15(a[ 8], b[ 6]) + + MUL15(a[ 9], b[ 5]) + + MUL15(a[10], b[ 4]) + + MUL15(a[11], b[ 3]) + + MUL15(a[12], b[ 2]) + + MUL15(a[13], b[ 1]) + + MUL15(a[14], b[ 0]); + t[15] = MUL15(a[ 0], b[15]) + + MUL15(a[ 1], b[14]) + + MUL15(a[ 2], b[13]) + + MUL15(a[ 3], b[12]) + + MUL15(a[ 4], b[11]) + + MUL15(a[ 5], b[10]) + + MUL15(a[ 6], b[ 9]) + + MUL15(a[ 7], b[ 8]) + + MUL15(a[ 8], b[ 7]) + + MUL15(a[ 9], b[ 6]) + + MUL15(a[10], b[ 5]) + + MUL15(a[11], b[ 4]) + + MUL15(a[12], b[ 3]) + + MUL15(a[13], b[ 2]) + + MUL15(a[14], b[ 1]) + + MUL15(a[15], b[ 0]); + t[16] = MUL15(a[ 0], b[16]) + + MUL15(a[ 1], b[15]) + + MUL15(a[ 2], b[14]) + + MUL15(a[ 3], b[13]) + + MUL15(a[ 4], b[12]) + + MUL15(a[ 5], b[11]) + + MUL15(a[ 6], b[10]) + + MUL15(a[ 7], b[ 9]) + + MUL15(a[ 8], b[ 8]) + + MUL15(a[ 9], b[ 7]) + + MUL15(a[10], b[ 6]) + + MUL15(a[11], b[ 5]) + + MUL15(a[12], b[ 4]) + + MUL15(a[13], b[ 3]) + + MUL15(a[14], b[ 2]) + + MUL15(a[15], b[ 1]) + + MUL15(a[16], b[ 0]); + t[17] = MUL15(a[ 0], b[17]) + + MUL15(a[ 1], b[16]) + + MUL15(a[ 2], b[15]) + + MUL15(a[ 3], b[14]) + + MUL15(a[ 4], b[13]) + + MUL15(a[ 5], b[12]) + + MUL15(a[ 6], b[11]) + + MUL15(a[ 7], b[10]) + + MUL15(a[ 8], b[ 9]) + + MUL15(a[ 9], b[ 8]) + + MUL15(a[10], b[ 7]) + + MUL15(a[11], b[ 6]) + + MUL15(a[12], b[ 5]) + + MUL15(a[13], b[ 4]) + + MUL15(a[14], b[ 3]) + + MUL15(a[15], b[ 2]) + + MUL15(a[16], b[ 1]) + + MUL15(a[17], b[ 0]); + t[18] = MUL15(a[ 0], b[18]) + + MUL15(a[ 1], b[17]) + + MUL15(a[ 2], b[16]) + + MUL15(a[ 3], b[15]) + + MUL15(a[ 4], b[14]) + + MUL15(a[ 5], b[13]) + + MUL15(a[ 6], b[12]) + + MUL15(a[ 7], b[11]) + + MUL15(a[ 8], b[10]) + + MUL15(a[ 9], b[ 9]) + + MUL15(a[10], b[ 8]) + + MUL15(a[11], b[ 7]) + + MUL15(a[12], b[ 6]) + + MUL15(a[13], b[ 5]) + + MUL15(a[14], b[ 4]) + + MUL15(a[15], b[ 3]) + + MUL15(a[16], b[ 2]) + + MUL15(a[17], b[ 1]) + + MUL15(a[18], b[ 0]); + t[19] = MUL15(a[ 0], b[19]) + + MUL15(a[ 1], b[18]) + + MUL15(a[ 2], b[17]) + + MUL15(a[ 3], b[16]) + + MUL15(a[ 4], b[15]) + + MUL15(a[ 5], b[14]) + + MUL15(a[ 6], b[13]) + + MUL15(a[ 7], b[12]) + + MUL15(a[ 8], b[11]) + + MUL15(a[ 9], b[10]) + + MUL15(a[10], b[ 9]) + + MUL15(a[11], b[ 8]) + + MUL15(a[12], b[ 7]) + + MUL15(a[13], b[ 6]) + + MUL15(a[14], b[ 5]) + + MUL15(a[15], b[ 4]) + + MUL15(a[16], b[ 3]) + + MUL15(a[17], b[ 2]) + + MUL15(a[18], b[ 1]) + + MUL15(a[19], b[ 0]); + t[20] = MUL15(a[ 1], b[19]) + + MUL15(a[ 2], b[18]) + + MUL15(a[ 3], b[17]) + + MUL15(a[ 4], b[16]) + + MUL15(a[ 5], b[15]) + + MUL15(a[ 6], b[14]) + + MUL15(a[ 7], b[13]) + + MUL15(a[ 8], b[12]) + + MUL15(a[ 9], b[11]) + + MUL15(a[10], b[10]) + + MUL15(a[11], b[ 9]) + + MUL15(a[12], b[ 8]) + + MUL15(a[13], b[ 7]) + + MUL15(a[14], b[ 6]) + + MUL15(a[15], b[ 5]) + + MUL15(a[16], b[ 4]) + + MUL15(a[17], b[ 3]) + + MUL15(a[18], b[ 2]) + + MUL15(a[19], b[ 1]); + t[21] = MUL15(a[ 2], b[19]) + + MUL15(a[ 3], b[18]) + + MUL15(a[ 4], b[17]) + + MUL15(a[ 5], b[16]) + + MUL15(a[ 6], b[15]) + + MUL15(a[ 7], b[14]) + + MUL15(a[ 8], b[13]) + + MUL15(a[ 9], b[12]) + + MUL15(a[10], b[11]) + + MUL15(a[11], b[10]) + + MUL15(a[12], b[ 9]) + + MUL15(a[13], b[ 8]) + + MUL15(a[14], b[ 7]) + + MUL15(a[15], b[ 6]) + + MUL15(a[16], b[ 5]) + + MUL15(a[17], b[ 4]) + + MUL15(a[18], b[ 3]) + + MUL15(a[19], b[ 2]); + t[22] = MUL15(a[ 3], b[19]) + + MUL15(a[ 4], b[18]) + + MUL15(a[ 5], b[17]) + + MUL15(a[ 6], b[16]) + + MUL15(a[ 7], b[15]) + + MUL15(a[ 8], b[14]) + + MUL15(a[ 9], b[13]) + + MUL15(a[10], b[12]) + + MUL15(a[11], b[11]) + + MUL15(a[12], b[10]) + + MUL15(a[13], b[ 9]) + + MUL15(a[14], b[ 8]) + + MUL15(a[15], b[ 7]) + + MUL15(a[16], b[ 6]) + + MUL15(a[17], b[ 5]) + + MUL15(a[18], b[ 4]) + + MUL15(a[19], b[ 3]); + t[23] = MUL15(a[ 4], b[19]) + + MUL15(a[ 5], b[18]) + + MUL15(a[ 6], b[17]) + + MUL15(a[ 7], b[16]) + + MUL15(a[ 8], b[15]) + + MUL15(a[ 9], b[14]) + + MUL15(a[10], b[13]) + + MUL15(a[11], b[12]) + + MUL15(a[12], b[11]) + + MUL15(a[13], b[10]) + + MUL15(a[14], b[ 9]) + + MUL15(a[15], b[ 8]) + + MUL15(a[16], b[ 7]) + + MUL15(a[17], b[ 6]) + + MUL15(a[18], b[ 5]) + + MUL15(a[19], b[ 4]); + t[24] = MUL15(a[ 5], b[19]) + + MUL15(a[ 6], b[18]) + + MUL15(a[ 7], b[17]) + + MUL15(a[ 8], b[16]) + + MUL15(a[ 9], b[15]) + + MUL15(a[10], b[14]) + + MUL15(a[11], b[13]) + + MUL15(a[12], b[12]) + + MUL15(a[13], b[11]) + + MUL15(a[14], b[10]) + + MUL15(a[15], b[ 9]) + + MUL15(a[16], b[ 8]) + + MUL15(a[17], b[ 7]) + + MUL15(a[18], b[ 6]) + + MUL15(a[19], b[ 5]); + t[25] = MUL15(a[ 6], b[19]) + + MUL15(a[ 7], b[18]) + + MUL15(a[ 8], b[17]) + + MUL15(a[ 9], b[16]) + + MUL15(a[10], b[15]) + + MUL15(a[11], b[14]) + + MUL15(a[12], b[13]) + + MUL15(a[13], b[12]) + + MUL15(a[14], b[11]) + + MUL15(a[15], b[10]) + + MUL15(a[16], b[ 9]) + + MUL15(a[17], b[ 8]) + + MUL15(a[18], b[ 7]) + + MUL15(a[19], b[ 6]); + t[26] = MUL15(a[ 7], b[19]) + + MUL15(a[ 8], b[18]) + + MUL15(a[ 9], b[17]) + + MUL15(a[10], b[16]) + + MUL15(a[11], b[15]) + + MUL15(a[12], b[14]) + + MUL15(a[13], b[13]) + + MUL15(a[14], b[12]) + + MUL15(a[15], b[11]) + + MUL15(a[16], b[10]) + + MUL15(a[17], b[ 9]) + + MUL15(a[18], b[ 8]) + + MUL15(a[19], b[ 7]); + t[27] = MUL15(a[ 8], b[19]) + + MUL15(a[ 9], b[18]) + + MUL15(a[10], b[17]) + + MUL15(a[11], b[16]) + + MUL15(a[12], b[15]) + + MUL15(a[13], b[14]) + + MUL15(a[14], b[13]) + + MUL15(a[15], b[12]) + + MUL15(a[16], b[11]) + + MUL15(a[17], b[10]) + + MUL15(a[18], b[ 9]) + + MUL15(a[19], b[ 8]); + t[28] = MUL15(a[ 9], b[19]) + + MUL15(a[10], b[18]) + + MUL15(a[11], b[17]) + + MUL15(a[12], b[16]) + + MUL15(a[13], b[15]) + + MUL15(a[14], b[14]) + + MUL15(a[15], b[13]) + + MUL15(a[16], b[12]) + + MUL15(a[17], b[11]) + + MUL15(a[18], b[10]) + + MUL15(a[19], b[ 9]); + t[29] = MUL15(a[10], b[19]) + + MUL15(a[11], b[18]) + + MUL15(a[12], b[17]) + + MUL15(a[13], b[16]) + + MUL15(a[14], b[15]) + + MUL15(a[15], b[14]) + + MUL15(a[16], b[13]) + + MUL15(a[17], b[12]) + + MUL15(a[18], b[11]) + + MUL15(a[19], b[10]); + t[30] = MUL15(a[11], b[19]) + + MUL15(a[12], b[18]) + + MUL15(a[13], b[17]) + + MUL15(a[14], b[16]) + + MUL15(a[15], b[15]) + + MUL15(a[16], b[14]) + + MUL15(a[17], b[13]) + + MUL15(a[18], b[12]) + + MUL15(a[19], b[11]); + t[31] = MUL15(a[12], b[19]) + + MUL15(a[13], b[18]) + + MUL15(a[14], b[17]) + + MUL15(a[15], b[16]) + + MUL15(a[16], b[15]) + + MUL15(a[17], b[14]) + + MUL15(a[18], b[13]) + + MUL15(a[19], b[12]); + t[32] = MUL15(a[13], b[19]) + + MUL15(a[14], b[18]) + + MUL15(a[15], b[17]) + + MUL15(a[16], b[16]) + + MUL15(a[17], b[15]) + + MUL15(a[18], b[14]) + + MUL15(a[19], b[13]); + t[33] = MUL15(a[14], b[19]) + + MUL15(a[15], b[18]) + + MUL15(a[16], b[17]) + + MUL15(a[17], b[16]) + + MUL15(a[18], b[15]) + + MUL15(a[19], b[14]); + t[34] = MUL15(a[15], b[19]) + + MUL15(a[16], b[18]) + + MUL15(a[17], b[17]) + + MUL15(a[18], b[16]) + + MUL15(a[19], b[15]); + t[35] = MUL15(a[16], b[19]) + + MUL15(a[17], b[18]) + + MUL15(a[18], b[17]) + + MUL15(a[19], b[16]); + t[36] = MUL15(a[17], b[19]) + + MUL15(a[18], b[18]) + + MUL15(a[19], b[17]); + t[37] = MUL15(a[18], b[19]) + + MUL15(a[19], b[18]); + t[38] = MUL15(a[19], b[19]); + + d[39] = norm13(d, t, 39); +} + +static void +square20(uint32_t *d, const uint32_t *a) +{ + uint32_t t[39]; + + t[ 0] = MUL15(a[ 0], a[ 0]); + t[ 1] = ((MUL15(a[ 0], a[ 1])) << 1); + t[ 2] = MUL15(a[ 1], a[ 1]) + + ((MUL15(a[ 0], a[ 2])) << 1); + t[ 3] = ((MUL15(a[ 0], a[ 3]) + + MUL15(a[ 1], a[ 2])) << 1); + t[ 4] = MUL15(a[ 2], a[ 2]) + + ((MUL15(a[ 0], a[ 4]) + + MUL15(a[ 1], a[ 3])) << 1); + t[ 5] = ((MUL15(a[ 0], a[ 5]) + + MUL15(a[ 1], a[ 4]) + + MUL15(a[ 2], a[ 3])) << 1); + t[ 6] = MUL15(a[ 3], a[ 3]) + + ((MUL15(a[ 0], a[ 6]) + + MUL15(a[ 1], a[ 5]) + + MUL15(a[ 2], a[ 4])) << 1); + t[ 7] = ((MUL15(a[ 0], a[ 7]) + + MUL15(a[ 1], a[ 6]) + + MUL15(a[ 2], a[ 5]) + + MUL15(a[ 3], a[ 4])) << 1); + t[ 8] = MUL15(a[ 4], a[ 4]) + + ((MUL15(a[ 0], a[ 8]) + + MUL15(a[ 1], a[ 7]) + + MUL15(a[ 2], a[ 6]) + + MUL15(a[ 3], a[ 5])) << 1); + t[ 9] = ((MUL15(a[ 0], a[ 9]) + + MUL15(a[ 1], a[ 8]) + + MUL15(a[ 2], a[ 7]) + + MUL15(a[ 3], a[ 6]) + + MUL15(a[ 4], a[ 5])) << 1); + t[10] = MUL15(a[ 5], a[ 5]) + + ((MUL15(a[ 0], a[10]) + + MUL15(a[ 1], a[ 9]) + + MUL15(a[ 2], a[ 8]) + + MUL15(a[ 3], a[ 7]) + + MUL15(a[ 4], a[ 6])) << 1); + t[11] = ((MUL15(a[ 0], a[11]) + + MUL15(a[ 1], a[10]) + + MUL15(a[ 2], a[ 9]) + + MUL15(a[ 3], a[ 8]) + + MUL15(a[ 4], a[ 7]) + + MUL15(a[ 5], a[ 6])) << 1); + t[12] = MUL15(a[ 6], a[ 6]) + + ((MUL15(a[ 0], a[12]) + + MUL15(a[ 1], a[11]) + + MUL15(a[ 2], a[10]) + + MUL15(a[ 3], a[ 9]) + + MUL15(a[ 4], a[ 8]) + + MUL15(a[ 5], a[ 7])) << 1); + t[13] = ((MUL15(a[ 0], a[13]) + + MUL15(a[ 1], a[12]) + + MUL15(a[ 2], a[11]) + + MUL15(a[ 3], a[10]) + + MUL15(a[ 4], a[ 9]) + + MUL15(a[ 5], a[ 8]) + + MUL15(a[ 6], a[ 7])) << 1); + t[14] = MUL15(a[ 7], a[ 7]) + + ((MUL15(a[ 0], a[14]) + + MUL15(a[ 1], a[13]) + + MUL15(a[ 2], a[12]) + + MUL15(a[ 3], a[11]) + + MUL15(a[ 4], a[10]) + + MUL15(a[ 5], a[ 9]) + + MUL15(a[ 6], a[ 8])) << 1); + t[15] = ((MUL15(a[ 0], a[15]) + + MUL15(a[ 1], a[14]) + + MUL15(a[ 2], a[13]) + + MUL15(a[ 3], a[12]) + + MUL15(a[ 4], a[11]) + + MUL15(a[ 5], a[10]) + + MUL15(a[ 6], a[ 9]) + + MUL15(a[ 7], a[ 8])) << 1); + t[16] = MUL15(a[ 8], a[ 8]) + + ((MUL15(a[ 0], a[16]) + + MUL15(a[ 1], a[15]) + + MUL15(a[ 2], a[14]) + + MUL15(a[ 3], a[13]) + + MUL15(a[ 4], a[12]) + + MUL15(a[ 5], a[11]) + + MUL15(a[ 6], a[10]) + + MUL15(a[ 7], a[ 9])) << 1); + t[17] = ((MUL15(a[ 0], a[17]) + + MUL15(a[ 1], a[16]) + + MUL15(a[ 2], a[15]) + + MUL15(a[ 3], a[14]) + + MUL15(a[ 4], a[13]) + + MUL15(a[ 5], a[12]) + + MUL15(a[ 6], a[11]) + + MUL15(a[ 7], a[10]) + + MUL15(a[ 8], a[ 9])) << 1); + t[18] = MUL15(a[ 9], a[ 9]) + + ((MUL15(a[ 0], a[18]) + + MUL15(a[ 1], a[17]) + + MUL15(a[ 2], a[16]) + + MUL15(a[ 3], a[15]) + + MUL15(a[ 4], a[14]) + + MUL15(a[ 5], a[13]) + + MUL15(a[ 6], a[12]) + + MUL15(a[ 7], a[11]) + + MUL15(a[ 8], a[10])) << 1); + t[19] = ((MUL15(a[ 0], a[19]) + + MUL15(a[ 1], a[18]) + + MUL15(a[ 2], a[17]) + + MUL15(a[ 3], a[16]) + + MUL15(a[ 4], a[15]) + + MUL15(a[ 5], a[14]) + + MUL15(a[ 6], a[13]) + + MUL15(a[ 7], a[12]) + + MUL15(a[ 8], a[11]) + + MUL15(a[ 9], a[10])) << 1); + t[20] = MUL15(a[10], a[10]) + + ((MUL15(a[ 1], a[19]) + + MUL15(a[ 2], a[18]) + + MUL15(a[ 3], a[17]) + + MUL15(a[ 4], a[16]) + + MUL15(a[ 5], a[15]) + + MUL15(a[ 6], a[14]) + + MUL15(a[ 7], a[13]) + + MUL15(a[ 8], a[12]) + + MUL15(a[ 9], a[11])) << 1); + t[21] = ((MUL15(a[ 2], a[19]) + + MUL15(a[ 3], a[18]) + + MUL15(a[ 4], a[17]) + + MUL15(a[ 5], a[16]) + + MUL15(a[ 6], a[15]) + + MUL15(a[ 7], a[14]) + + MUL15(a[ 8], a[13]) + + MUL15(a[ 9], a[12]) + + MUL15(a[10], a[11])) << 1); + t[22] = MUL15(a[11], a[11]) + + ((MUL15(a[ 3], a[19]) + + MUL15(a[ 4], a[18]) + + MUL15(a[ 5], a[17]) + + MUL15(a[ 6], a[16]) + + MUL15(a[ 7], a[15]) + + MUL15(a[ 8], a[14]) + + MUL15(a[ 9], a[13]) + + MUL15(a[10], a[12])) << 1); + t[23] = ((MUL15(a[ 4], a[19]) + + MUL15(a[ 5], a[18]) + + MUL15(a[ 6], a[17]) + + MUL15(a[ 7], a[16]) + + MUL15(a[ 8], a[15]) + + MUL15(a[ 9], a[14]) + + MUL15(a[10], a[13]) + + MUL15(a[11], a[12])) << 1); + t[24] = MUL15(a[12], a[12]) + + ((MUL15(a[ 5], a[19]) + + MUL15(a[ 6], a[18]) + + MUL15(a[ 7], a[17]) + + MUL15(a[ 8], a[16]) + + MUL15(a[ 9], a[15]) + + MUL15(a[10], a[14]) + + MUL15(a[11], a[13])) << 1); + t[25] = ((MUL15(a[ 6], a[19]) + + MUL15(a[ 7], a[18]) + + MUL15(a[ 8], a[17]) + + MUL15(a[ 9], a[16]) + + MUL15(a[10], a[15]) + + MUL15(a[11], a[14]) + + MUL15(a[12], a[13])) << 1); + t[26] = MUL15(a[13], a[13]) + + ((MUL15(a[ 7], a[19]) + + MUL15(a[ 8], a[18]) + + MUL15(a[ 9], a[17]) + + MUL15(a[10], a[16]) + + MUL15(a[11], a[15]) + + MUL15(a[12], a[14])) << 1); + t[27] = ((MUL15(a[ 8], a[19]) + + MUL15(a[ 9], a[18]) + + MUL15(a[10], a[17]) + + MUL15(a[11], a[16]) + + MUL15(a[12], a[15]) + + MUL15(a[13], a[14])) << 1); + t[28] = MUL15(a[14], a[14]) + + ((MUL15(a[ 9], a[19]) + + MUL15(a[10], a[18]) + + MUL15(a[11], a[17]) + + MUL15(a[12], a[16]) + + MUL15(a[13], a[15])) << 1); + t[29] = ((MUL15(a[10], a[19]) + + MUL15(a[11], a[18]) + + MUL15(a[12], a[17]) + + MUL15(a[13], a[16]) + + MUL15(a[14], a[15])) << 1); + t[30] = MUL15(a[15], a[15]) + + ((MUL15(a[11], a[19]) + + MUL15(a[12], a[18]) + + MUL15(a[13], a[17]) + + MUL15(a[14], a[16])) << 1); + t[31] = ((MUL15(a[12], a[19]) + + MUL15(a[13], a[18]) + + MUL15(a[14], a[17]) + + MUL15(a[15], a[16])) << 1); + t[32] = MUL15(a[16], a[16]) + + ((MUL15(a[13], a[19]) + + MUL15(a[14], a[18]) + + MUL15(a[15], a[17])) << 1); + t[33] = ((MUL15(a[14], a[19]) + + MUL15(a[15], a[18]) + + MUL15(a[16], a[17])) << 1); + t[34] = MUL15(a[17], a[17]) + + ((MUL15(a[15], a[19]) + + MUL15(a[16], a[18])) << 1); + t[35] = ((MUL15(a[16], a[19]) + + MUL15(a[17], a[18])) << 1); + t[36] = MUL15(a[18], a[18]) + + ((MUL15(a[17], a[19])) << 1); + t[37] = ((MUL15(a[18], a[19])) << 1); + t[38] = MUL15(a[19], a[19]); + + d[39] = norm13(d, t, 39); +} + +#endif + +/* + * Perform a "final reduction" in field F255 (field for Curve25519) + * The source value must be less than twice the modulus. If the value + * is not lower than the modulus, then the modulus is subtracted and + * this function returns 1; otherwise, it leaves it untouched and it + * returns 0. + */ +static uint32_t +reduce_final_f255(uint32_t *d) +{ + uint32_t t[20]; + uint32_t cc; + int i; + + memcpy(t, d, sizeof t); + cc = 19; + for (i = 0; i < 20; i ++) { + uint32_t w; + + w = t[i] + cc; + cc = w >> 13; + t[i] = w & 0x1FFF; + } + cc = t[19] >> 8; + t[19] &= 0xFF; + CCOPY(cc, d, t, sizeof t); + return cc; +} + +static void +f255_mulgen(uint32_t *d, const uint32_t *a, const uint32_t *b, int square) +{ + uint32_t t[40], cc, w; + + /* + * Compute raw multiplication. All result words fit in 13 bits + * each; upper word (t[39]) must fit on 5 bits, since the product + * of two 256-bit integers must fit on 512 bits. + */ + if (square) { + square20(t, a); + } else { + mul20(t, a, b); + } + + /* + * Modular reduction: each high word is added where necessary. + * Since the modulus is 2^255-19 and word 20 corresponds to + * offset 20*13 = 260, word 20+k must be added to word k with + * a factor of 19*2^5 = 608. The extra bits in word 19 are also + * added that way. + */ + cc = MUL15(t[19] >> 8, 19); + t[19] &= 0xFF; + +#define MM1(x) do { \ + w = t[x] + cc + MUL15(t[(x) + 20], 608); \ + t[x] = w & 0x1FFF; \ + cc = w >> 13; \ + } while (0) + + MM1( 0); + MM1( 1); + MM1( 2); + MM1( 3); + MM1( 4); + MM1( 5); + MM1( 6); + MM1( 7); + MM1( 8); + MM1( 9); + MM1(10); + MM1(11); + MM1(12); + MM1(13); + MM1(14); + MM1(15); + MM1(16); + MM1(17); + MM1(18); + MM1(19); + +#undef MM1 + + cc = MUL15(w >> 8, 19); + t[19] &= 0xFF; + +#define MM2(x) do { \ + w = t[x] + cc; \ + d[x] = w & 0x1FFF; \ + cc = w >> 13; \ + } while (0) + + MM2( 0); + MM2( 1); + MM2( 2); + MM2( 3); + MM2( 4); + MM2( 5); + MM2( 6); + MM2( 7); + MM2( 8); + MM2( 9); + MM2(10); + MM2(11); + MM2(12); + MM2(13); + MM2(14); + MM2(15); + MM2(16); + MM2(17); + MM2(18); + MM2(19); + +#undef MM2 +} + +/* + * Perform a multiplication of two integers modulo 2^255-19. + * Operands are arrays of 20 words, each containing 13 bits of data, in + * little-endian order. Input value may be up to 2^256-1; on output, value + * fits on 256 bits and is lower than twice the modulus. + * + * f255_mul() is the general multiplication, f255_square() is specialised + * for squarings. + */ +#define f255_mul(d, a, b) f255_mulgen(d, a, b, 0) +#define f255_square(d, a) f255_mulgen(d, a, a, 1) + +/* + * Add two values in F255. Partial reduction is performed (down to less + * than twice the modulus). + */ +static void +f255_add(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + int i; + uint32_t cc, w; + + cc = 0; + for (i = 0; i < 20; i ++) { + w = a[i] + b[i] + cc; + d[i] = w & 0x1FFF; + cc = w >> 13; + } + cc = MUL15(w >> 8, 19); + d[19] &= 0xFF; + for (i = 0; i < 20; i ++) { + w = d[i] + cc; + d[i] = w & 0x1FFF; + cc = w >> 13; + } +} + +/* + * Subtract one value from another in F255. Partial reduction is + * performed (down to less than twice the modulus). + */ +static void +f255_sub(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + /* + * We actually compute a - b + 2*p, so that the final value is + * necessarily positive. + */ + int i; + uint32_t cc, w; + + cc = (uint32_t)-38; + for (i = 0; i < 20; i ++) { + w = a[i] - b[i] + cc; + d[i] = w & 0x1FFF; + cc = ARSH(w, 13); + } + cc = MUL15((w + 0x200) >> 8, 19); + d[19] &= 0xFF; + for (i = 0; i < 20; i ++) { + w = d[i] + cc; + d[i] = w & 0x1FFF; + cc = w >> 13; + } +} + +/* + * Multiply an integer by the 'A24' constant (121665). Partial reduction + * is performed (down to less than twice the modulus). + */ +static void +f255_mul_a24(uint32_t *d, const uint32_t *a) +{ + int i; + uint32_t cc, w; + + cc = 0; + for (i = 0; i < 20; i ++) { + w = MUL15(a[i], 121665) + cc; + d[i] = w & 0x1FFF; + cc = w >> 13; + } + cc = MUL15(w >> 8, 19); + d[19] &= 0xFF; + for (i = 0; i < 20; i ++) { + w = d[i] + cc; + d[i] = w & 0x1FFF; + cc = w >> 13; + } +} + +static const unsigned char GEN[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ORDER[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return GEN; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return ORDER; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 0; +} + +static void +cswap(uint32_t *a, uint32_t *b, uint32_t ctl) +{ + int i; + + ctl = -ctl; + for (i = 0; i < 20; i ++) { + uint32_t aw, bw, tw; + + aw = a[i]; + bw = b[i]; + tw = ctl & (aw ^ bw); + a[i] = aw ^ tw; + b[i] = bw ^ tw; + } +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + uint32_t x1[20], x2[20], x3[20], z2[20], z3[20]; + uint32_t a[20], aa[20], b[20], bb[20]; + uint32_t c[20], d[20], e[20], da[20], cb[20]; + unsigned char k[32]; + uint32_t swap; + int i; + + (void)curve; + + /* + * Points are encoded over exactly 32 bytes. Multipliers must fit + * in 32 bytes as well. + * RFC 7748 mandates that the high bit of the last point byte must + * be ignored/cleared. + */ + if (Glen != 32 || kblen > 32) { + return 0; + } + G[31] &= 0x7F; + + /* + * Initialise variables x1, x2, z2, x3 and z3. We set all of them + * into Montgomery representation. + */ + x1[19] = le8_to_le13(x1, G, 32); + memcpy(x3, x1, sizeof x1); + memset(z2, 0, sizeof z2); + memset(x2, 0, sizeof x2); + x2[0] = 1; + memset(z3, 0, sizeof z3); + z3[0] = 1; + + memcpy(k, kb, kblen); + memset(k + kblen, 0, (sizeof k) - kblen); + k[0] &= 0xF8; + k[31] &= 0x7F; + k[31] |= 0x40; + + /* obsolete + print_int("x1", x1); + */ + + swap = 0; + for (i = 254; i >= 0; i --) { + uint32_t kt; + + kt = (k[i >> 3] >> (i & 7)) & 1; + swap ^= kt; + cswap(x2, x3, swap); + cswap(z2, z3, swap); + swap = kt; + + /* obsolete + print_int("x2", x2); + print_int("z2", z2); + print_int("x3", x3); + print_int("z3", z3); + */ + + f255_add(a, x2, z2); + f255_square(aa, a); + f255_sub(b, x2, z2); + f255_square(bb, b); + f255_sub(e, aa, bb); + f255_add(c, x3, z3); + f255_sub(d, x3, z3); + f255_mul(da, d, a); + f255_mul(cb, c, b); + + /* obsolete + print_int("a ", a); + print_int("aa", aa); + print_int("b ", b); + print_int("bb", bb); + print_int("e ", e); + print_int("c ", c); + print_int("d ", d); + print_int("da", da); + print_int("cb", cb); + */ + + f255_add(x3, da, cb); + f255_square(x3, x3); + f255_sub(z3, da, cb); + f255_square(z3, z3); + f255_mul(z3, z3, x1); + f255_mul(x2, aa, bb); + f255_mul_a24(z2, e); + f255_add(z2, z2, aa); + f255_mul(z2, e, z2); + + /* obsolete + print_int("x2", x2); + print_int("z2", z2); + print_int("x3", x3); + print_int("z3", z3); + */ + } + cswap(x2, x3, swap); + cswap(z2, z3, swap); + + /* + * Inverse z2 with a modular exponentiation. This is a simple + * square-and-multiply algorithm; we mutualise most non-squarings + * since the exponent contains almost only ones. + */ + memcpy(a, z2, sizeof z2); + for (i = 0; i < 15; i ++) { + f255_square(a, a); + f255_mul(a, a, z2); + } + memcpy(b, a, sizeof a); + for (i = 0; i < 14; i ++) { + int j; + + for (j = 0; j < 16; j ++) { + f255_square(b, b); + } + f255_mul(b, b, a); + } + for (i = 14; i >= 0; i --) { + f255_square(b, b); + if ((0xFFEB >> i) & 1) { + f255_mul(b, z2, b); + } + } + f255_mul(x2, x2, b); + reduce_final_f255(x2); + le13_to_le8(G, 32, x2); + return 1; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We don't implement this method, since it is used for ECDSA + * only, and there is no ECDSA over Curve25519 (which instead + * uses EdDSA). + */ + (void)A; + (void)B; + (void)len; + (void)x; + (void)xlen; + (void)y; + (void)ylen; + (void)curve; + return 0; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_c25519_m15 = { + (uint32_t)0x20000000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_c25519_m31.c b/src/bearssl/src/ec/ec_c25519_m31.c new file mode 100644 index 0000000..b249634 --- /dev/null +++ b/src/bearssl/src/ec/ec_c25519_m31.c @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* obsolete +#include +#include +static void +print_int(const char *name, const uint32_t *x) +{ + size_t u; + unsigned char tmp[40]; + + printf("%s = ", name); + for (u = 0; u < 9; u ++) { + if (x[u] > 0x3FFFFFFF) { + printf("INVALID:"); + for (u = 0; u < 9; u ++) { + printf(" %08X", x[u]); + } + printf("\n"); + return; + } + } + memset(tmp, 0, sizeof tmp); + for (u = 0; u < 9; u ++) { + uint64_t w; + int j, k; + + w = x[u]; + j = 30 * (int)u; + k = j & 7; + if (k != 0) { + w <<= k; + j -= k; + } + k = j >> 3; + for (j = 0; j < 8; j ++) { + tmp[39 - k - j] |= (unsigned char)w; + w >>= 8; + } + } + for (u = 8; u < 40; u ++) { + printf("%02X", tmp[u]); + } + printf("\n"); +} +*/ + +/* + * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_ + * that right-shifting a signed negative integer copies the sign bit + * (arithmetic right-shift). This is "implementation-defined behaviour", + * i.e. it is not undefined, but it may differ between compilers. Each + * compiler is supposed to document its behaviour in that respect. GCC + * explicitly defines that an arithmetic right shift is used. We expect + * all other compilers to do the same, because underlying CPU offer an + * arithmetic right shift opcode that could not be used otherwise. + */ +#if BR_NO_ARITH_SHIFT +#define ARSH(x, n) (((uint32_t)(x) >> (n)) \ + | ((-((uint32_t)(x) >> 31)) << (32 - (n)))) +#else +#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n)) +#endif + +/* + * Convert an integer from unsigned little-endian encoding to a sequence of + * 30-bit words in little-endian order. The final "partial" word is + * returned. + */ +static uint32_t +le8_to_le30(uint32_t *dst, const unsigned char *src, size_t len) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + uint32_t b; + + b = *src ++; + if (acc_len < 22) { + acc |= b << acc_len; + acc_len += 8; + } else { + *dst ++ = (acc | (b << acc_len)) & 0x3FFFFFFF; + acc = b >> (30 - acc_len); + acc_len -= 22; + } + } + return acc; +} + +/* + * Convert an integer (30-bit words, little-endian) to unsigned + * little-endian encoding. The total encoding length is provided; all + * the destination bytes will be filled. + */ +static void +le30_to_le8(unsigned char *dst, size_t len, const uint32_t *src) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + if (acc_len < 8) { + uint32_t w; + + w = *src ++; + *dst ++ = (unsigned char)(acc | (w << acc_len)); + acc = w >> (8 - acc_len); + acc_len += 22; + } else { + *dst ++ = (unsigned char)acc; + acc >>= 8; + acc_len -= 8; + } + } +} + +/* + * Multiply two integers. Source integers are represented as arrays of + * nine 30-bit words, for values up to 2^270-1. Result is encoded over + * 18 words of 30 bits each. + */ +static void +mul9(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + /* + * Maximum intermediate result is no more than + * 10376293531797946367, which fits in 64 bits. Reason: + * + * 10376293531797946367 = 9 * (2^30-1)^2 + 9663676406 + * 10376293531797946367 < 9663676407 * 2^30 + * + * Thus, adding together 9 products of 30-bit integers, with + * a carry of at most 9663676406, yields an integer that fits + * on 64 bits and generates a carry of at most 9663676406. + */ + uint64_t t[17]; + uint64_t cc; + int i; + + t[ 0] = MUL31(a[0], b[0]); + t[ 1] = MUL31(a[0], b[1]) + + MUL31(a[1], b[0]); + t[ 2] = MUL31(a[0], b[2]) + + MUL31(a[1], b[1]) + + MUL31(a[2], b[0]); + t[ 3] = MUL31(a[0], b[3]) + + MUL31(a[1], b[2]) + + MUL31(a[2], b[1]) + + MUL31(a[3], b[0]); + t[ 4] = MUL31(a[0], b[4]) + + MUL31(a[1], b[3]) + + MUL31(a[2], b[2]) + + MUL31(a[3], b[1]) + + MUL31(a[4], b[0]); + t[ 5] = MUL31(a[0], b[5]) + + MUL31(a[1], b[4]) + + MUL31(a[2], b[3]) + + MUL31(a[3], b[2]) + + MUL31(a[4], b[1]) + + MUL31(a[5], b[0]); + t[ 6] = MUL31(a[0], b[6]) + + MUL31(a[1], b[5]) + + MUL31(a[2], b[4]) + + MUL31(a[3], b[3]) + + MUL31(a[4], b[2]) + + MUL31(a[5], b[1]) + + MUL31(a[6], b[0]); + t[ 7] = MUL31(a[0], b[7]) + + MUL31(a[1], b[6]) + + MUL31(a[2], b[5]) + + MUL31(a[3], b[4]) + + MUL31(a[4], b[3]) + + MUL31(a[5], b[2]) + + MUL31(a[6], b[1]) + + MUL31(a[7], b[0]); + t[ 8] = MUL31(a[0], b[8]) + + MUL31(a[1], b[7]) + + MUL31(a[2], b[6]) + + MUL31(a[3], b[5]) + + MUL31(a[4], b[4]) + + MUL31(a[5], b[3]) + + MUL31(a[6], b[2]) + + MUL31(a[7], b[1]) + + MUL31(a[8], b[0]); + t[ 9] = MUL31(a[1], b[8]) + + MUL31(a[2], b[7]) + + MUL31(a[3], b[6]) + + MUL31(a[4], b[5]) + + MUL31(a[5], b[4]) + + MUL31(a[6], b[3]) + + MUL31(a[7], b[2]) + + MUL31(a[8], b[1]); + t[10] = MUL31(a[2], b[8]) + + MUL31(a[3], b[7]) + + MUL31(a[4], b[6]) + + MUL31(a[5], b[5]) + + MUL31(a[6], b[4]) + + MUL31(a[7], b[3]) + + MUL31(a[8], b[2]); + t[11] = MUL31(a[3], b[8]) + + MUL31(a[4], b[7]) + + MUL31(a[5], b[6]) + + MUL31(a[6], b[5]) + + MUL31(a[7], b[4]) + + MUL31(a[8], b[3]); + t[12] = MUL31(a[4], b[8]) + + MUL31(a[5], b[7]) + + MUL31(a[6], b[6]) + + MUL31(a[7], b[5]) + + MUL31(a[8], b[4]); + t[13] = MUL31(a[5], b[8]) + + MUL31(a[6], b[7]) + + MUL31(a[7], b[6]) + + MUL31(a[8], b[5]); + t[14] = MUL31(a[6], b[8]) + + MUL31(a[7], b[7]) + + MUL31(a[8], b[6]); + t[15] = MUL31(a[7], b[8]) + + MUL31(a[8], b[7]); + t[16] = MUL31(a[8], b[8]); + + /* + * Propagate carries. + */ + cc = 0; + for (i = 0; i < 17; i ++) { + uint64_t w; + + w = t[i] + cc; + d[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } + d[17] = (uint32_t)cc; +} + +/* + * Square a 270-bit integer, represented as an array of nine 30-bit words. + * Result uses 18 words of 30 bits each. + */ +static void +square9(uint32_t *d, const uint32_t *a) +{ + uint64_t t[17]; + uint64_t cc; + int i; + + t[ 0] = MUL31(a[0], a[0]); + t[ 1] = ((MUL31(a[0], a[1])) << 1); + t[ 2] = MUL31(a[1], a[1]) + + ((MUL31(a[0], a[2])) << 1); + t[ 3] = ((MUL31(a[0], a[3]) + + MUL31(a[1], a[2])) << 1); + t[ 4] = MUL31(a[2], a[2]) + + ((MUL31(a[0], a[4]) + + MUL31(a[1], a[3])) << 1); + t[ 5] = ((MUL31(a[0], a[5]) + + MUL31(a[1], a[4]) + + MUL31(a[2], a[3])) << 1); + t[ 6] = MUL31(a[3], a[3]) + + ((MUL31(a[0], a[6]) + + MUL31(a[1], a[5]) + + MUL31(a[2], a[4])) << 1); + t[ 7] = ((MUL31(a[0], a[7]) + + MUL31(a[1], a[6]) + + MUL31(a[2], a[5]) + + MUL31(a[3], a[4])) << 1); + t[ 8] = MUL31(a[4], a[4]) + + ((MUL31(a[0], a[8]) + + MUL31(a[1], a[7]) + + MUL31(a[2], a[6]) + + MUL31(a[3], a[5])) << 1); + t[ 9] = ((MUL31(a[1], a[8]) + + MUL31(a[2], a[7]) + + MUL31(a[3], a[6]) + + MUL31(a[4], a[5])) << 1); + t[10] = MUL31(a[5], a[5]) + + ((MUL31(a[2], a[8]) + + MUL31(a[3], a[7]) + + MUL31(a[4], a[6])) << 1); + t[11] = ((MUL31(a[3], a[8]) + + MUL31(a[4], a[7]) + + MUL31(a[5], a[6])) << 1); + t[12] = MUL31(a[6], a[6]) + + ((MUL31(a[4], a[8]) + + MUL31(a[5], a[7])) << 1); + t[13] = ((MUL31(a[5], a[8]) + + MUL31(a[6], a[7])) << 1); + t[14] = MUL31(a[7], a[7]) + + ((MUL31(a[6], a[8])) << 1); + t[15] = ((MUL31(a[7], a[8])) << 1); + t[16] = MUL31(a[8], a[8]); + + /* + * Propagate carries. + */ + cc = 0; + for (i = 0; i < 17; i ++) { + uint64_t w; + + w = t[i] + cc; + d[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } + d[17] = (uint32_t)cc; +} + +/* + * Perform a "final reduction" in field F255 (field for Curve25519) + * The source value must be less than twice the modulus. If the value + * is not lower than the modulus, then the modulus is subtracted and + * this function returns 1; otherwise, it leaves it untouched and it + * returns 0. + */ +static uint32_t +reduce_final_f255(uint32_t *d) +{ + uint32_t t[9]; + uint32_t cc; + int i; + + memcpy(t, d, sizeof t); + cc = 19; + for (i = 0; i < 9; i ++) { + uint32_t w; + + w = t[i] + cc; + cc = w >> 30; + t[i] = w & 0x3FFFFFFF; + } + cc = t[8] >> 15; + t[8] &= 0x7FFF; + CCOPY(cc, d, t, sizeof t); + return cc; +} + +/* + * Perform a multiplication of two integers modulo 2^255-19. + * Operands are arrays of 9 words, each containing 30 bits of data, in + * little-endian order. Input value may be up to 2^256-1; on output, value + * fits on 256 bits and is lower than twice the modulus. + */ +static void +f255_mul(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t t[18]; + uint64_t cc, w; + int i; + + /* + * Compute raw multiplication. All result words fit in 30 bits + * each; upper word (t[17]) must fit on 2 bits, since the product + * of two 256-bit integers must fit on 512 bits. + */ + mul9(t, a, b); + + /* + * Modular reduction: each high word is added where necessary. + * Since the modulus is 2^255-19 and word 9 corresponds to + * offset 9*30 = 270, word 9+k must be added to word k with + * a factor of 19*2^15 = 622592. The extra bits in word 8 are also + * added that way. + */ + cc = MUL31(t[8] >> 15, 19); + t[8] &= 0x7FFF; + for (i = 0; i < 9; i ++) { + w = (uint64_t)t[i] + cc + MUL31(t[i + 9], 622592); + t[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } + cc = MUL31(w >> 15, 19); + t[8] &= 0x7FFF; + for (i = 0; i < 9; i ++) { + w = t[i] + cc; + d[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } +} + +/* + * Perform a squaring of an integer modulo 2^255-19. + * Operands are arrays of 9 words, each containing 30 bits of data, in + * little-endian order. Input value may be up to 2^256-1; on output, value + * fits on 256 bits and is lower than twice the modulus. + */ +static void +f255_square(uint32_t *d, const uint32_t *a) +{ + uint32_t t[18]; + uint64_t cc, w; + int i; + + /* + * Compute raw squaring. All result words fit in 30 bits + * each; upper word (t[17]) must fit on 2 bits, since the square + * of a 256-bit integers must fit on 512 bits. + */ + square9(t, a); + + /* + * Modular reduction: each high word is added where necessary. + * Since the modulus is 2^255-19 and word 9 corresponds to + * offset 9*30 = 270, word 9+k must be added to word k with + * a factor of 19*2^15 = 622592. The extra bits in word 8 are also + * added that way. + */ + cc = MUL31(t[8] >> 15, 19); + t[8] &= 0x7FFF; + for (i = 0; i < 9; i ++) { + w = (uint64_t)t[i] + cc + MUL31(t[i + 9], 622592); + t[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } + cc = MUL31(w >> 15, 19); + t[8] &= 0x7FFF; + for (i = 0; i < 9; i ++) { + w = t[i] + cc; + d[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } +} + +/* + * Add two values in F255. Partial reduction is performed (down to less + * than twice the modulus). + */ +static void +f255_add(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + /* + * Since operand words fit on 30 bits, we can use 32-bit + * variables throughout. + */ + int i; + uint32_t cc, w; + + cc = 0; + for (i = 0; i < 9; i ++) { + w = a[i] + b[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = w >> 30; + } + cc = MUL15(w >> 15, 19); + d[8] &= 0x7FFF; + for (i = 0; i < 9; i ++) { + w = d[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = w >> 30; + } +} + +/* + * Subtract one value from another in F255. Partial reduction is + * performed (down to less than twice the modulus). + */ +static void +f255_sub(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + /* + * We actually compute a - b + 2*p, so that the final value is + * necessarily positive. + */ + int i; + uint32_t cc, w; + + cc = (uint32_t)-38; + for (i = 0; i < 9; i ++) { + w = a[i] - b[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = ARSH(w, 30); + } + cc = MUL15((w + 0x10000) >> 15, 19); + d[8] &= 0x7FFF; + for (i = 0; i < 9; i ++) { + w = d[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = w >> 30; + } +} + +/* + * Multiply an integer by the 'A24' constant (121665). Partial reduction + * is performed (down to less than twice the modulus). + */ +static void +f255_mul_a24(uint32_t *d, const uint32_t *a) +{ + int i; + uint64_t cc, w; + + cc = 0; + for (i = 0; i < 9; i ++) { + w = MUL31(a[i], 121665) + cc; + d[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } + cc = MUL31((uint32_t)(w >> 15), 19); + d[8] &= 0x7FFF; + for (i = 0; i < 9; i ++) { + w = (uint64_t)d[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = w >> 30; + } +} + +static const unsigned char GEN[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ORDER[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return GEN; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return ORDER; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 0; +} + +static void +cswap(uint32_t *a, uint32_t *b, uint32_t ctl) +{ + int i; + + ctl = -ctl; + for (i = 0; i < 9; i ++) { + uint32_t aw, bw, tw; + + aw = a[i]; + bw = b[i]; + tw = ctl & (aw ^ bw); + a[i] = aw ^ tw; + b[i] = bw ^ tw; + } +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + uint32_t x1[9], x2[9], x3[9], z2[9], z3[9]; + uint32_t a[9], aa[9], b[9], bb[9]; + uint32_t c[9], d[9], e[9], da[9], cb[9]; + unsigned char k[32]; + uint32_t swap; + int i; + + (void)curve; + + /* + * Points are encoded over exactly 32 bytes. Multipliers must fit + * in 32 bytes as well. + * RFC 7748 mandates that the high bit of the last point byte must + * be ignored/cleared. + */ + if (Glen != 32 || kblen > 32) { + return 0; + } + G[31] &= 0x7F; + + /* + * Initialise variables x1, x2, z2, x3 and z3. We set all of them + * into Montgomery representation. + */ + x1[8] = le8_to_le30(x1, G, 32); + memcpy(x3, x1, sizeof x1); + memset(z2, 0, sizeof z2); + memset(x2, 0, sizeof x2); + x2[0] = 1; + memset(z3, 0, sizeof z3); + z3[0] = 1; + + memcpy(k, kb, kblen); + memset(k + kblen, 0, (sizeof k) - kblen); + k[0] &= 0xF8; + k[31] &= 0x7F; + k[31] |= 0x40; + + /* obsolete + print_int("x1", x1); + */ + + swap = 0; + for (i = 254; i >= 0; i --) { + uint32_t kt; + + kt = (k[i >> 3] >> (i & 7)) & 1; + swap ^= kt; + cswap(x2, x3, swap); + cswap(z2, z3, swap); + swap = kt; + + /* obsolete + print_int("x2", x2); + print_int("z2", z2); + print_int("x3", x3); + print_int("z3", z3); + */ + + f255_add(a, x2, z2); + f255_square(aa, a); + f255_sub(b, x2, z2); + f255_square(bb, b); + f255_sub(e, aa, bb); + f255_add(c, x3, z3); + f255_sub(d, x3, z3); + f255_mul(da, d, a); + f255_mul(cb, c, b); + + /* obsolete + print_int("a ", a); + print_int("aa", aa); + print_int("b ", b); + print_int("bb", bb); + print_int("e ", e); + print_int("c ", c); + print_int("d ", d); + print_int("da", da); + print_int("cb", cb); + */ + + f255_add(x3, da, cb); + f255_square(x3, x3); + f255_sub(z3, da, cb); + f255_square(z3, z3); + f255_mul(z3, z3, x1); + f255_mul(x2, aa, bb); + f255_mul_a24(z2, e); + f255_add(z2, z2, aa); + f255_mul(z2, e, z2); + + /* obsolete + print_int("x2", x2); + print_int("z2", z2); + print_int("x3", x3); + print_int("z3", z3); + */ + } + cswap(x2, x3, swap); + cswap(z2, z3, swap); + + /* + * Inverse z2 with a modular exponentiation. This is a simple + * square-and-multiply algorithm; we mutualise most non-squarings + * since the exponent contains almost only ones. + */ + memcpy(a, z2, sizeof z2); + for (i = 0; i < 15; i ++) { + f255_square(a, a); + f255_mul(a, a, z2); + } + memcpy(b, a, sizeof a); + for (i = 0; i < 14; i ++) { + int j; + + for (j = 0; j < 16; j ++) { + f255_square(b, b); + } + f255_mul(b, b, a); + } + for (i = 14; i >= 0; i --) { + f255_square(b, b); + if ((0xFFEB >> i) & 1) { + f255_mul(b, z2, b); + } + } + f255_mul(x2, x2, b); + reduce_final_f255(x2); + le30_to_le8(G, 32, x2); + return 1; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We don't implement this method, since it is used for ECDSA + * only, and there is no ECDSA over Curve25519 (which instead + * uses EdDSA). + */ + (void)A; + (void)B; + (void)len; + (void)x; + (void)xlen; + (void)y; + (void)ylen; + (void)curve; + return 0; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_c25519_m31 = { + (uint32_t)0x20000000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_curve25519.c b/src/bearssl/src/ec/ec_curve25519.c new file mode 100644 index 0000000..a47d215 --- /dev/null +++ b/src/bearssl/src/ec/ec_curve25519.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char GEN[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ORDER[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* see inner.h */ +const br_ec_curve_def br_curve25519 = { + BR_EC_curve25519, + ORDER, sizeof ORDER, + GEN, sizeof GEN +}; diff --git a/src/bearssl/src/ec/ec_default.c b/src/bearssl/src/ec/ec_default.c new file mode 100644 index 0000000..7bb6e0c --- /dev/null +++ b/src/bearssl/src/ec/ec_default.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_get_default(void) +{ +#if BR_LOMUL + return &br_ec_all_m15; +#else + return &br_ec_all_m31; +#endif +} diff --git a/src/bearssl/src/ec/ec_keygen.c b/src/bearssl/src/ec/ec_keygen.c new file mode 100644 index 0000000..02a3096 --- /dev/null +++ b/src/bearssl/src/ec/ec_keygen.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ec.h */ +size_t +br_ec_keygen(const br_prng_class **rng_ctx, + const br_ec_impl *impl, br_ec_private_key *sk, + void *kbuf, int curve) +{ + const unsigned char *order; + unsigned char *buf; + size_t len; + unsigned mask; + + if (curve < 0 || curve >= 32 + || ((impl->supported_curves >> curve) & 1) == 0) + { + return 0; + } + order = impl->order(curve, &len); + while (len > 0 && *order == 0) { + order ++; + len --; + } + if (kbuf == NULL || len == 0) { + return len; + } + mask = order[0]; + mask |= (mask >> 1); + mask |= (mask >> 2); + mask |= (mask >> 4); + + /* + * We generate sequences of random bits of the right size, until + * the value is strictly lower than the curve order (we also + * check for all-zero values, which are invalid). + */ + buf = kbuf; + for (;;) { + size_t u; + unsigned cc, zz; + + (*rng_ctx)->generate(rng_ctx, buf, len); + buf[0] &= mask; + cc = 0; + u = len; + zz = 0; + while (u -- > 0) { + cc = ((unsigned)(buf[u] - order[u] - cc) >> 8) & 1; + zz |= buf[u]; + } + if (cc != 0 && zz != 0) { + break; + } + } + + if (sk != NULL) { + sk->curve = curve; + sk->x = buf; + sk->xlen = len; + } + return len; +} diff --git a/src/bearssl/src/ec/ec_p256_m15.c b/src/bearssl/src/ec/ec_p256_m15.c new file mode 100644 index 0000000..6ce57e0 --- /dev/null +++ b/src/bearssl/src/ec/ec_p256_m15.c @@ -0,0 +1,2130 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_ + * that right-shifting a signed negative integer copies the sign bit + * (arithmetic right-shift). This is "implementation-defined behaviour", + * i.e. it is not undefined, but it may differ between compilers. Each + * compiler is supposed to document its behaviour in that respect. GCC + * explicitly defines that an arithmetic right shift is used. We expect + * all other compilers to do the same, because underlying CPU offer an + * arithmetic right shift opcode that could not be used otherwise. + */ +#if BR_NO_ARITH_SHIFT +#define ARSH(x, n) (((uint32_t)(x) >> (n)) \ + | ((-((uint32_t)(x) >> 31)) << (32 - (n)))) +#else +#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n)) +#endif + +/* + * Convert an integer from unsigned big-endian encoding to a sequence of + * 13-bit words in little-endian order. The final "partial" word is + * returned. + */ +static uint32_t +be8_to_le13(uint32_t *dst, const unsigned char *src, size_t len) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + acc |= (uint32_t)src[len] << acc_len; + acc_len += 8; + if (acc_len >= 13) { + *dst ++ = acc & 0x1FFF; + acc >>= 13; + acc_len -= 13; + } + } + return acc; +} + +/* + * Convert an integer (13-bit words, little-endian) to unsigned + * big-endian encoding. The total encoding length is provided; all + * the destination bytes will be filled. + */ +static void +le13_to_be8(unsigned char *dst, size_t len, const uint32_t *src) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + if (acc_len < 8) { + acc |= (*src ++) << acc_len; + acc_len += 13; + } + dst[len] = (unsigned char)acc; + acc >>= 8; + acc_len -= 8; + } +} + +/* + * Normalise an array of words to a strict 13 bits per word. Returned + * value is the resulting carry. The source (w) and destination (d) + * arrays may be identical, but shall not overlap partially. + */ +static inline uint32_t +norm13(uint32_t *d, const uint32_t *w, size_t len) +{ + size_t u; + uint32_t cc; + + cc = 0; + for (u = 0; u < len; u ++) { + int32_t z; + + z = w[u] + cc; + d[u] = z & 0x1FFF; + cc = ARSH(z, 13); + } + return cc; +} + +/* + * mul20() multiplies two 260-bit integers together. Each word must fit + * on 13 bits; source operands use 20 words, destination operand + * receives 40 words. All overlaps allowed. + * + * square20() computes the square of a 260-bit integer. Each word must + * fit on 13 bits; source operand uses 20 words, destination operand + * receives 40 words. All overlaps allowed. + */ + +#if BR_SLOW_MUL15 + +static void +mul20(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + /* + * Two-level Karatsuba: turns a 20x20 multiplication into + * nine 5x5 multiplications. We use 13-bit words but do not + * propagate carries immediately, so words may expand: + * + * - First Karatsuba decomposition turns the 20x20 mul on + * 13-bit words into three 10x10 muls, two on 13-bit words + * and one on 14-bit words. + * + * - Second Karatsuba decomposition further splits these into: + * + * * four 5x5 muls on 13-bit words + * * four 5x5 muls on 14-bit words + * * one 5x5 mul on 15-bit words + * + * Highest word value is 8191, 16382 or 32764, for 13-bit, 14-bit + * or 15-bit words, respectively. + */ + uint32_t u[45], v[45], w[90]; + uint32_t cc; + int i; + +#define ZADD(dw, d_off, s1w, s1_off, s2w, s2_off) do { \ + (dw)[5 * (d_off) + 0] = (s1w)[5 * (s1_off) + 0] \ + + (s2w)[5 * (s2_off) + 0]; \ + (dw)[5 * (d_off) + 1] = (s1w)[5 * (s1_off) + 1] \ + + (s2w)[5 * (s2_off) + 1]; \ + (dw)[5 * (d_off) + 2] = (s1w)[5 * (s1_off) + 2] \ + + (s2w)[5 * (s2_off) + 2]; \ + (dw)[5 * (d_off) + 3] = (s1w)[5 * (s1_off) + 3] \ + + (s2w)[5 * (s2_off) + 3]; \ + (dw)[5 * (d_off) + 4] = (s1w)[5 * (s1_off) + 4] \ + + (s2w)[5 * (s2_off) + 4]; \ + } while (0) + +#define ZADDT(dw, d_off, sw, s_off) do { \ + (dw)[5 * (d_off) + 0] += (sw)[5 * (s_off) + 0]; \ + (dw)[5 * (d_off) + 1] += (sw)[5 * (s_off) + 1]; \ + (dw)[5 * (d_off) + 2] += (sw)[5 * (s_off) + 2]; \ + (dw)[5 * (d_off) + 3] += (sw)[5 * (s_off) + 3]; \ + (dw)[5 * (d_off) + 4] += (sw)[5 * (s_off) + 4]; \ + } while (0) + +#define ZSUB2F(dw, d_off, s1w, s1_off, s2w, s2_off) do { \ + (dw)[5 * (d_off) + 0] -= (s1w)[5 * (s1_off) + 0] \ + + (s2w)[5 * (s2_off) + 0]; \ + (dw)[5 * (d_off) + 1] -= (s1w)[5 * (s1_off) + 1] \ + + (s2w)[5 * (s2_off) + 1]; \ + (dw)[5 * (d_off) + 2] -= (s1w)[5 * (s1_off) + 2] \ + + (s2w)[5 * (s2_off) + 2]; \ + (dw)[5 * (d_off) + 3] -= (s1w)[5 * (s1_off) + 3] \ + + (s2w)[5 * (s2_off) + 3]; \ + (dw)[5 * (d_off) + 4] -= (s1w)[5 * (s1_off) + 4] \ + + (s2w)[5 * (s2_off) + 4]; \ + } while (0) + +#define CPR1(w, cprcc) do { \ + uint32_t cprz = (w) + cprcc; \ + (w) = cprz & 0x1FFF; \ + cprcc = cprz >> 13; \ + } while (0) + +#define CPR(dw, d_off) do { \ + uint32_t cprcc; \ + cprcc = 0; \ + CPR1((dw)[(d_off) + 0], cprcc); \ + CPR1((dw)[(d_off) + 1], cprcc); \ + CPR1((dw)[(d_off) + 2], cprcc); \ + CPR1((dw)[(d_off) + 3], cprcc); \ + CPR1((dw)[(d_off) + 4], cprcc); \ + CPR1((dw)[(d_off) + 5], cprcc); \ + CPR1((dw)[(d_off) + 6], cprcc); \ + CPR1((dw)[(d_off) + 7], cprcc); \ + CPR1((dw)[(d_off) + 8], cprcc); \ + (dw)[(d_off) + 9] = cprcc; \ + } while (0) + + memcpy(u, a, 20 * sizeof *a); + ZADD(u, 4, a, 0, a, 1); + ZADD(u, 5, a, 2, a, 3); + ZADD(u, 6, a, 0, a, 2); + ZADD(u, 7, a, 1, a, 3); + ZADD(u, 8, u, 6, u, 7); + + memcpy(v, b, 20 * sizeof *b); + ZADD(v, 4, b, 0, b, 1); + ZADD(v, 5, b, 2, b, 3); + ZADD(v, 6, b, 0, b, 2); + ZADD(v, 7, b, 1, b, 3); + ZADD(v, 8, v, 6, v, 7); + + /* + * Do the eight first 8x8 muls. Source words are at most 16382 + * each, so we can add product results together "as is" in 32-bit + * words. + */ + for (i = 0; i < 40; i += 5) { + w[(i << 1) + 0] = MUL15(u[i + 0], v[i + 0]); + w[(i << 1) + 1] = MUL15(u[i + 0], v[i + 1]) + + MUL15(u[i + 1], v[i + 0]); + w[(i << 1) + 2] = MUL15(u[i + 0], v[i + 2]) + + MUL15(u[i + 1], v[i + 1]) + + MUL15(u[i + 2], v[i + 0]); + w[(i << 1) + 3] = MUL15(u[i + 0], v[i + 3]) + + MUL15(u[i + 1], v[i + 2]) + + MUL15(u[i + 2], v[i + 1]) + + MUL15(u[i + 3], v[i + 0]); + w[(i << 1) + 4] = MUL15(u[i + 0], v[i + 4]) + + MUL15(u[i + 1], v[i + 3]) + + MUL15(u[i + 2], v[i + 2]) + + MUL15(u[i + 3], v[i + 1]) + + MUL15(u[i + 4], v[i + 0]); + w[(i << 1) + 5] = MUL15(u[i + 1], v[i + 4]) + + MUL15(u[i + 2], v[i + 3]) + + MUL15(u[i + 3], v[i + 2]) + + MUL15(u[i + 4], v[i + 1]); + w[(i << 1) + 6] = MUL15(u[i + 2], v[i + 4]) + + MUL15(u[i + 3], v[i + 3]) + + MUL15(u[i + 4], v[i + 2]); + w[(i << 1) + 7] = MUL15(u[i + 3], v[i + 4]) + + MUL15(u[i + 4], v[i + 3]); + w[(i << 1) + 8] = MUL15(u[i + 4], v[i + 4]); + w[(i << 1) + 9] = 0; + } + + /* + * For the 9th multiplication, source words are up to 32764, + * so we must do some carry propagation. If we add up to + * 4 products and the carry is no more than 524224, then the + * result fits in 32 bits, and the next carry will be no more + * than 524224 (because 4*(32764^2)+524224 < 8192*524225). + * + * We thus just skip one of the products in the middle word, + * then do a carry propagation (this reduces words to 13 bits + * each, except possibly the last, which may use up to 17 bits + * or so), then add the missing product. + */ + w[80 + 0] = MUL15(u[40 + 0], v[40 + 0]); + w[80 + 1] = MUL15(u[40 + 0], v[40 + 1]) + + MUL15(u[40 + 1], v[40 + 0]); + w[80 + 2] = MUL15(u[40 + 0], v[40 + 2]) + + MUL15(u[40 + 1], v[40 + 1]) + + MUL15(u[40 + 2], v[40 + 0]); + w[80 + 3] = MUL15(u[40 + 0], v[40 + 3]) + + MUL15(u[40 + 1], v[40 + 2]) + + MUL15(u[40 + 2], v[40 + 1]) + + MUL15(u[40 + 3], v[40 + 0]); + w[80 + 4] = MUL15(u[40 + 0], v[40 + 4]) + + MUL15(u[40 + 1], v[40 + 3]) + + MUL15(u[40 + 2], v[40 + 2]) + + MUL15(u[40 + 3], v[40 + 1]); + /* + MUL15(u[40 + 4], v[40 + 0]) */ + w[80 + 5] = MUL15(u[40 + 1], v[40 + 4]) + + MUL15(u[40 + 2], v[40 + 3]) + + MUL15(u[40 + 3], v[40 + 2]) + + MUL15(u[40 + 4], v[40 + 1]); + w[80 + 6] = MUL15(u[40 + 2], v[40 + 4]) + + MUL15(u[40 + 3], v[40 + 3]) + + MUL15(u[40 + 4], v[40 + 2]); + w[80 + 7] = MUL15(u[40 + 3], v[40 + 4]) + + MUL15(u[40 + 4], v[40 + 3]); + w[80 + 8] = MUL15(u[40 + 4], v[40 + 4]); + + CPR(w, 80); + + w[80 + 4] += MUL15(u[40 + 4], v[40 + 0]); + + /* + * The products on 14-bit words in slots 6 and 7 yield values + * up to 5*(16382^2) each, and we need to subtract two such + * values from the higher word. We need the subtraction to fit + * in a _signed_ 32-bit integer, i.e. 31 bits + a sign bit. + * However, 10*(16382^2) does not fit. So we must perform a + * bit of reduction here. + */ + CPR(w, 60); + CPR(w, 70); + + /* + * Recompose results. + */ + + /* 0..1*0..1 into 0..3 */ + ZSUB2F(w, 8, w, 0, w, 2); + ZSUB2F(w, 9, w, 1, w, 3); + ZADDT(w, 1, w, 8); + ZADDT(w, 2, w, 9); + + /* 2..3*2..3 into 4..7 */ + ZSUB2F(w, 10, w, 4, w, 6); + ZSUB2F(w, 11, w, 5, w, 7); + ZADDT(w, 5, w, 10); + ZADDT(w, 6, w, 11); + + /* (0..1+2..3)*(0..1+2..3) into 12..15 */ + ZSUB2F(w, 16, w, 12, w, 14); + ZSUB2F(w, 17, w, 13, w, 15); + ZADDT(w, 13, w, 16); + ZADDT(w, 14, w, 17); + + /* first-level recomposition */ + ZSUB2F(w, 12, w, 0, w, 4); + ZSUB2F(w, 13, w, 1, w, 5); + ZSUB2F(w, 14, w, 2, w, 6); + ZSUB2F(w, 15, w, 3, w, 7); + ZADDT(w, 2, w, 12); + ZADDT(w, 3, w, 13); + ZADDT(w, 4, w, 14); + ZADDT(w, 5, w, 15); + + /* + * Perform carry propagation to bring all words down to 13 bits. + */ + cc = norm13(d, w, 40); + d[39] += (cc << 13); + +#undef ZADD +#undef ZADDT +#undef ZSUB2F +#undef CPR1 +#undef CPR +} + +static inline void +square20(uint32_t *d, const uint32_t *a) +{ + mul20(d, a, a); +} + +#else + +static void +mul20(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t t[39]; + + t[ 0] = MUL15(a[ 0], b[ 0]); + t[ 1] = MUL15(a[ 0], b[ 1]) + + MUL15(a[ 1], b[ 0]); + t[ 2] = MUL15(a[ 0], b[ 2]) + + MUL15(a[ 1], b[ 1]) + + MUL15(a[ 2], b[ 0]); + t[ 3] = MUL15(a[ 0], b[ 3]) + + MUL15(a[ 1], b[ 2]) + + MUL15(a[ 2], b[ 1]) + + MUL15(a[ 3], b[ 0]); + t[ 4] = MUL15(a[ 0], b[ 4]) + + MUL15(a[ 1], b[ 3]) + + MUL15(a[ 2], b[ 2]) + + MUL15(a[ 3], b[ 1]) + + MUL15(a[ 4], b[ 0]); + t[ 5] = MUL15(a[ 0], b[ 5]) + + MUL15(a[ 1], b[ 4]) + + MUL15(a[ 2], b[ 3]) + + MUL15(a[ 3], b[ 2]) + + MUL15(a[ 4], b[ 1]) + + MUL15(a[ 5], b[ 0]); + t[ 6] = MUL15(a[ 0], b[ 6]) + + MUL15(a[ 1], b[ 5]) + + MUL15(a[ 2], b[ 4]) + + MUL15(a[ 3], b[ 3]) + + MUL15(a[ 4], b[ 2]) + + MUL15(a[ 5], b[ 1]) + + MUL15(a[ 6], b[ 0]); + t[ 7] = MUL15(a[ 0], b[ 7]) + + MUL15(a[ 1], b[ 6]) + + MUL15(a[ 2], b[ 5]) + + MUL15(a[ 3], b[ 4]) + + MUL15(a[ 4], b[ 3]) + + MUL15(a[ 5], b[ 2]) + + MUL15(a[ 6], b[ 1]) + + MUL15(a[ 7], b[ 0]); + t[ 8] = MUL15(a[ 0], b[ 8]) + + MUL15(a[ 1], b[ 7]) + + MUL15(a[ 2], b[ 6]) + + MUL15(a[ 3], b[ 5]) + + MUL15(a[ 4], b[ 4]) + + MUL15(a[ 5], b[ 3]) + + MUL15(a[ 6], b[ 2]) + + MUL15(a[ 7], b[ 1]) + + MUL15(a[ 8], b[ 0]); + t[ 9] = MUL15(a[ 0], b[ 9]) + + MUL15(a[ 1], b[ 8]) + + MUL15(a[ 2], b[ 7]) + + MUL15(a[ 3], b[ 6]) + + MUL15(a[ 4], b[ 5]) + + MUL15(a[ 5], b[ 4]) + + MUL15(a[ 6], b[ 3]) + + MUL15(a[ 7], b[ 2]) + + MUL15(a[ 8], b[ 1]) + + MUL15(a[ 9], b[ 0]); + t[10] = MUL15(a[ 0], b[10]) + + MUL15(a[ 1], b[ 9]) + + MUL15(a[ 2], b[ 8]) + + MUL15(a[ 3], b[ 7]) + + MUL15(a[ 4], b[ 6]) + + MUL15(a[ 5], b[ 5]) + + MUL15(a[ 6], b[ 4]) + + MUL15(a[ 7], b[ 3]) + + MUL15(a[ 8], b[ 2]) + + MUL15(a[ 9], b[ 1]) + + MUL15(a[10], b[ 0]); + t[11] = MUL15(a[ 0], b[11]) + + MUL15(a[ 1], b[10]) + + MUL15(a[ 2], b[ 9]) + + MUL15(a[ 3], b[ 8]) + + MUL15(a[ 4], b[ 7]) + + MUL15(a[ 5], b[ 6]) + + MUL15(a[ 6], b[ 5]) + + MUL15(a[ 7], b[ 4]) + + MUL15(a[ 8], b[ 3]) + + MUL15(a[ 9], b[ 2]) + + MUL15(a[10], b[ 1]) + + MUL15(a[11], b[ 0]); + t[12] = MUL15(a[ 0], b[12]) + + MUL15(a[ 1], b[11]) + + MUL15(a[ 2], b[10]) + + MUL15(a[ 3], b[ 9]) + + MUL15(a[ 4], b[ 8]) + + MUL15(a[ 5], b[ 7]) + + MUL15(a[ 6], b[ 6]) + + MUL15(a[ 7], b[ 5]) + + MUL15(a[ 8], b[ 4]) + + MUL15(a[ 9], b[ 3]) + + MUL15(a[10], b[ 2]) + + MUL15(a[11], b[ 1]) + + MUL15(a[12], b[ 0]); + t[13] = MUL15(a[ 0], b[13]) + + MUL15(a[ 1], b[12]) + + MUL15(a[ 2], b[11]) + + MUL15(a[ 3], b[10]) + + MUL15(a[ 4], b[ 9]) + + MUL15(a[ 5], b[ 8]) + + MUL15(a[ 6], b[ 7]) + + MUL15(a[ 7], b[ 6]) + + MUL15(a[ 8], b[ 5]) + + MUL15(a[ 9], b[ 4]) + + MUL15(a[10], b[ 3]) + + MUL15(a[11], b[ 2]) + + MUL15(a[12], b[ 1]) + + MUL15(a[13], b[ 0]); + t[14] = MUL15(a[ 0], b[14]) + + MUL15(a[ 1], b[13]) + + MUL15(a[ 2], b[12]) + + MUL15(a[ 3], b[11]) + + MUL15(a[ 4], b[10]) + + MUL15(a[ 5], b[ 9]) + + MUL15(a[ 6], b[ 8]) + + MUL15(a[ 7], b[ 7]) + + MUL15(a[ 8], b[ 6]) + + MUL15(a[ 9], b[ 5]) + + MUL15(a[10], b[ 4]) + + MUL15(a[11], b[ 3]) + + MUL15(a[12], b[ 2]) + + MUL15(a[13], b[ 1]) + + MUL15(a[14], b[ 0]); + t[15] = MUL15(a[ 0], b[15]) + + MUL15(a[ 1], b[14]) + + MUL15(a[ 2], b[13]) + + MUL15(a[ 3], b[12]) + + MUL15(a[ 4], b[11]) + + MUL15(a[ 5], b[10]) + + MUL15(a[ 6], b[ 9]) + + MUL15(a[ 7], b[ 8]) + + MUL15(a[ 8], b[ 7]) + + MUL15(a[ 9], b[ 6]) + + MUL15(a[10], b[ 5]) + + MUL15(a[11], b[ 4]) + + MUL15(a[12], b[ 3]) + + MUL15(a[13], b[ 2]) + + MUL15(a[14], b[ 1]) + + MUL15(a[15], b[ 0]); + t[16] = MUL15(a[ 0], b[16]) + + MUL15(a[ 1], b[15]) + + MUL15(a[ 2], b[14]) + + MUL15(a[ 3], b[13]) + + MUL15(a[ 4], b[12]) + + MUL15(a[ 5], b[11]) + + MUL15(a[ 6], b[10]) + + MUL15(a[ 7], b[ 9]) + + MUL15(a[ 8], b[ 8]) + + MUL15(a[ 9], b[ 7]) + + MUL15(a[10], b[ 6]) + + MUL15(a[11], b[ 5]) + + MUL15(a[12], b[ 4]) + + MUL15(a[13], b[ 3]) + + MUL15(a[14], b[ 2]) + + MUL15(a[15], b[ 1]) + + MUL15(a[16], b[ 0]); + t[17] = MUL15(a[ 0], b[17]) + + MUL15(a[ 1], b[16]) + + MUL15(a[ 2], b[15]) + + MUL15(a[ 3], b[14]) + + MUL15(a[ 4], b[13]) + + MUL15(a[ 5], b[12]) + + MUL15(a[ 6], b[11]) + + MUL15(a[ 7], b[10]) + + MUL15(a[ 8], b[ 9]) + + MUL15(a[ 9], b[ 8]) + + MUL15(a[10], b[ 7]) + + MUL15(a[11], b[ 6]) + + MUL15(a[12], b[ 5]) + + MUL15(a[13], b[ 4]) + + MUL15(a[14], b[ 3]) + + MUL15(a[15], b[ 2]) + + MUL15(a[16], b[ 1]) + + MUL15(a[17], b[ 0]); + t[18] = MUL15(a[ 0], b[18]) + + MUL15(a[ 1], b[17]) + + MUL15(a[ 2], b[16]) + + MUL15(a[ 3], b[15]) + + MUL15(a[ 4], b[14]) + + MUL15(a[ 5], b[13]) + + MUL15(a[ 6], b[12]) + + MUL15(a[ 7], b[11]) + + MUL15(a[ 8], b[10]) + + MUL15(a[ 9], b[ 9]) + + MUL15(a[10], b[ 8]) + + MUL15(a[11], b[ 7]) + + MUL15(a[12], b[ 6]) + + MUL15(a[13], b[ 5]) + + MUL15(a[14], b[ 4]) + + MUL15(a[15], b[ 3]) + + MUL15(a[16], b[ 2]) + + MUL15(a[17], b[ 1]) + + MUL15(a[18], b[ 0]); + t[19] = MUL15(a[ 0], b[19]) + + MUL15(a[ 1], b[18]) + + MUL15(a[ 2], b[17]) + + MUL15(a[ 3], b[16]) + + MUL15(a[ 4], b[15]) + + MUL15(a[ 5], b[14]) + + MUL15(a[ 6], b[13]) + + MUL15(a[ 7], b[12]) + + MUL15(a[ 8], b[11]) + + MUL15(a[ 9], b[10]) + + MUL15(a[10], b[ 9]) + + MUL15(a[11], b[ 8]) + + MUL15(a[12], b[ 7]) + + MUL15(a[13], b[ 6]) + + MUL15(a[14], b[ 5]) + + MUL15(a[15], b[ 4]) + + MUL15(a[16], b[ 3]) + + MUL15(a[17], b[ 2]) + + MUL15(a[18], b[ 1]) + + MUL15(a[19], b[ 0]); + t[20] = MUL15(a[ 1], b[19]) + + MUL15(a[ 2], b[18]) + + MUL15(a[ 3], b[17]) + + MUL15(a[ 4], b[16]) + + MUL15(a[ 5], b[15]) + + MUL15(a[ 6], b[14]) + + MUL15(a[ 7], b[13]) + + MUL15(a[ 8], b[12]) + + MUL15(a[ 9], b[11]) + + MUL15(a[10], b[10]) + + MUL15(a[11], b[ 9]) + + MUL15(a[12], b[ 8]) + + MUL15(a[13], b[ 7]) + + MUL15(a[14], b[ 6]) + + MUL15(a[15], b[ 5]) + + MUL15(a[16], b[ 4]) + + MUL15(a[17], b[ 3]) + + MUL15(a[18], b[ 2]) + + MUL15(a[19], b[ 1]); + t[21] = MUL15(a[ 2], b[19]) + + MUL15(a[ 3], b[18]) + + MUL15(a[ 4], b[17]) + + MUL15(a[ 5], b[16]) + + MUL15(a[ 6], b[15]) + + MUL15(a[ 7], b[14]) + + MUL15(a[ 8], b[13]) + + MUL15(a[ 9], b[12]) + + MUL15(a[10], b[11]) + + MUL15(a[11], b[10]) + + MUL15(a[12], b[ 9]) + + MUL15(a[13], b[ 8]) + + MUL15(a[14], b[ 7]) + + MUL15(a[15], b[ 6]) + + MUL15(a[16], b[ 5]) + + MUL15(a[17], b[ 4]) + + MUL15(a[18], b[ 3]) + + MUL15(a[19], b[ 2]); + t[22] = MUL15(a[ 3], b[19]) + + MUL15(a[ 4], b[18]) + + MUL15(a[ 5], b[17]) + + MUL15(a[ 6], b[16]) + + MUL15(a[ 7], b[15]) + + MUL15(a[ 8], b[14]) + + MUL15(a[ 9], b[13]) + + MUL15(a[10], b[12]) + + MUL15(a[11], b[11]) + + MUL15(a[12], b[10]) + + MUL15(a[13], b[ 9]) + + MUL15(a[14], b[ 8]) + + MUL15(a[15], b[ 7]) + + MUL15(a[16], b[ 6]) + + MUL15(a[17], b[ 5]) + + MUL15(a[18], b[ 4]) + + MUL15(a[19], b[ 3]); + t[23] = MUL15(a[ 4], b[19]) + + MUL15(a[ 5], b[18]) + + MUL15(a[ 6], b[17]) + + MUL15(a[ 7], b[16]) + + MUL15(a[ 8], b[15]) + + MUL15(a[ 9], b[14]) + + MUL15(a[10], b[13]) + + MUL15(a[11], b[12]) + + MUL15(a[12], b[11]) + + MUL15(a[13], b[10]) + + MUL15(a[14], b[ 9]) + + MUL15(a[15], b[ 8]) + + MUL15(a[16], b[ 7]) + + MUL15(a[17], b[ 6]) + + MUL15(a[18], b[ 5]) + + MUL15(a[19], b[ 4]); + t[24] = MUL15(a[ 5], b[19]) + + MUL15(a[ 6], b[18]) + + MUL15(a[ 7], b[17]) + + MUL15(a[ 8], b[16]) + + MUL15(a[ 9], b[15]) + + MUL15(a[10], b[14]) + + MUL15(a[11], b[13]) + + MUL15(a[12], b[12]) + + MUL15(a[13], b[11]) + + MUL15(a[14], b[10]) + + MUL15(a[15], b[ 9]) + + MUL15(a[16], b[ 8]) + + MUL15(a[17], b[ 7]) + + MUL15(a[18], b[ 6]) + + MUL15(a[19], b[ 5]); + t[25] = MUL15(a[ 6], b[19]) + + MUL15(a[ 7], b[18]) + + MUL15(a[ 8], b[17]) + + MUL15(a[ 9], b[16]) + + MUL15(a[10], b[15]) + + MUL15(a[11], b[14]) + + MUL15(a[12], b[13]) + + MUL15(a[13], b[12]) + + MUL15(a[14], b[11]) + + MUL15(a[15], b[10]) + + MUL15(a[16], b[ 9]) + + MUL15(a[17], b[ 8]) + + MUL15(a[18], b[ 7]) + + MUL15(a[19], b[ 6]); + t[26] = MUL15(a[ 7], b[19]) + + MUL15(a[ 8], b[18]) + + MUL15(a[ 9], b[17]) + + MUL15(a[10], b[16]) + + MUL15(a[11], b[15]) + + MUL15(a[12], b[14]) + + MUL15(a[13], b[13]) + + MUL15(a[14], b[12]) + + MUL15(a[15], b[11]) + + MUL15(a[16], b[10]) + + MUL15(a[17], b[ 9]) + + MUL15(a[18], b[ 8]) + + MUL15(a[19], b[ 7]); + t[27] = MUL15(a[ 8], b[19]) + + MUL15(a[ 9], b[18]) + + MUL15(a[10], b[17]) + + MUL15(a[11], b[16]) + + MUL15(a[12], b[15]) + + MUL15(a[13], b[14]) + + MUL15(a[14], b[13]) + + MUL15(a[15], b[12]) + + MUL15(a[16], b[11]) + + MUL15(a[17], b[10]) + + MUL15(a[18], b[ 9]) + + MUL15(a[19], b[ 8]); + t[28] = MUL15(a[ 9], b[19]) + + MUL15(a[10], b[18]) + + MUL15(a[11], b[17]) + + MUL15(a[12], b[16]) + + MUL15(a[13], b[15]) + + MUL15(a[14], b[14]) + + MUL15(a[15], b[13]) + + MUL15(a[16], b[12]) + + MUL15(a[17], b[11]) + + MUL15(a[18], b[10]) + + MUL15(a[19], b[ 9]); + t[29] = MUL15(a[10], b[19]) + + MUL15(a[11], b[18]) + + MUL15(a[12], b[17]) + + MUL15(a[13], b[16]) + + MUL15(a[14], b[15]) + + MUL15(a[15], b[14]) + + MUL15(a[16], b[13]) + + MUL15(a[17], b[12]) + + MUL15(a[18], b[11]) + + MUL15(a[19], b[10]); + t[30] = MUL15(a[11], b[19]) + + MUL15(a[12], b[18]) + + MUL15(a[13], b[17]) + + MUL15(a[14], b[16]) + + MUL15(a[15], b[15]) + + MUL15(a[16], b[14]) + + MUL15(a[17], b[13]) + + MUL15(a[18], b[12]) + + MUL15(a[19], b[11]); + t[31] = MUL15(a[12], b[19]) + + MUL15(a[13], b[18]) + + MUL15(a[14], b[17]) + + MUL15(a[15], b[16]) + + MUL15(a[16], b[15]) + + MUL15(a[17], b[14]) + + MUL15(a[18], b[13]) + + MUL15(a[19], b[12]); + t[32] = MUL15(a[13], b[19]) + + MUL15(a[14], b[18]) + + MUL15(a[15], b[17]) + + MUL15(a[16], b[16]) + + MUL15(a[17], b[15]) + + MUL15(a[18], b[14]) + + MUL15(a[19], b[13]); + t[33] = MUL15(a[14], b[19]) + + MUL15(a[15], b[18]) + + MUL15(a[16], b[17]) + + MUL15(a[17], b[16]) + + MUL15(a[18], b[15]) + + MUL15(a[19], b[14]); + t[34] = MUL15(a[15], b[19]) + + MUL15(a[16], b[18]) + + MUL15(a[17], b[17]) + + MUL15(a[18], b[16]) + + MUL15(a[19], b[15]); + t[35] = MUL15(a[16], b[19]) + + MUL15(a[17], b[18]) + + MUL15(a[18], b[17]) + + MUL15(a[19], b[16]); + t[36] = MUL15(a[17], b[19]) + + MUL15(a[18], b[18]) + + MUL15(a[19], b[17]); + t[37] = MUL15(a[18], b[19]) + + MUL15(a[19], b[18]); + t[38] = MUL15(a[19], b[19]); + d[39] = norm13(d, t, 39); +} + +static void +square20(uint32_t *d, const uint32_t *a) +{ + uint32_t t[39]; + + t[ 0] = MUL15(a[ 0], a[ 0]); + t[ 1] = ((MUL15(a[ 0], a[ 1])) << 1); + t[ 2] = MUL15(a[ 1], a[ 1]) + + ((MUL15(a[ 0], a[ 2])) << 1); + t[ 3] = ((MUL15(a[ 0], a[ 3]) + + MUL15(a[ 1], a[ 2])) << 1); + t[ 4] = MUL15(a[ 2], a[ 2]) + + ((MUL15(a[ 0], a[ 4]) + + MUL15(a[ 1], a[ 3])) << 1); + t[ 5] = ((MUL15(a[ 0], a[ 5]) + + MUL15(a[ 1], a[ 4]) + + MUL15(a[ 2], a[ 3])) << 1); + t[ 6] = MUL15(a[ 3], a[ 3]) + + ((MUL15(a[ 0], a[ 6]) + + MUL15(a[ 1], a[ 5]) + + MUL15(a[ 2], a[ 4])) << 1); + t[ 7] = ((MUL15(a[ 0], a[ 7]) + + MUL15(a[ 1], a[ 6]) + + MUL15(a[ 2], a[ 5]) + + MUL15(a[ 3], a[ 4])) << 1); + t[ 8] = MUL15(a[ 4], a[ 4]) + + ((MUL15(a[ 0], a[ 8]) + + MUL15(a[ 1], a[ 7]) + + MUL15(a[ 2], a[ 6]) + + MUL15(a[ 3], a[ 5])) << 1); + t[ 9] = ((MUL15(a[ 0], a[ 9]) + + MUL15(a[ 1], a[ 8]) + + MUL15(a[ 2], a[ 7]) + + MUL15(a[ 3], a[ 6]) + + MUL15(a[ 4], a[ 5])) << 1); + t[10] = MUL15(a[ 5], a[ 5]) + + ((MUL15(a[ 0], a[10]) + + MUL15(a[ 1], a[ 9]) + + MUL15(a[ 2], a[ 8]) + + MUL15(a[ 3], a[ 7]) + + MUL15(a[ 4], a[ 6])) << 1); + t[11] = ((MUL15(a[ 0], a[11]) + + MUL15(a[ 1], a[10]) + + MUL15(a[ 2], a[ 9]) + + MUL15(a[ 3], a[ 8]) + + MUL15(a[ 4], a[ 7]) + + MUL15(a[ 5], a[ 6])) << 1); + t[12] = MUL15(a[ 6], a[ 6]) + + ((MUL15(a[ 0], a[12]) + + MUL15(a[ 1], a[11]) + + MUL15(a[ 2], a[10]) + + MUL15(a[ 3], a[ 9]) + + MUL15(a[ 4], a[ 8]) + + MUL15(a[ 5], a[ 7])) << 1); + t[13] = ((MUL15(a[ 0], a[13]) + + MUL15(a[ 1], a[12]) + + MUL15(a[ 2], a[11]) + + MUL15(a[ 3], a[10]) + + MUL15(a[ 4], a[ 9]) + + MUL15(a[ 5], a[ 8]) + + MUL15(a[ 6], a[ 7])) << 1); + t[14] = MUL15(a[ 7], a[ 7]) + + ((MUL15(a[ 0], a[14]) + + MUL15(a[ 1], a[13]) + + MUL15(a[ 2], a[12]) + + MUL15(a[ 3], a[11]) + + MUL15(a[ 4], a[10]) + + MUL15(a[ 5], a[ 9]) + + MUL15(a[ 6], a[ 8])) << 1); + t[15] = ((MUL15(a[ 0], a[15]) + + MUL15(a[ 1], a[14]) + + MUL15(a[ 2], a[13]) + + MUL15(a[ 3], a[12]) + + MUL15(a[ 4], a[11]) + + MUL15(a[ 5], a[10]) + + MUL15(a[ 6], a[ 9]) + + MUL15(a[ 7], a[ 8])) << 1); + t[16] = MUL15(a[ 8], a[ 8]) + + ((MUL15(a[ 0], a[16]) + + MUL15(a[ 1], a[15]) + + MUL15(a[ 2], a[14]) + + MUL15(a[ 3], a[13]) + + MUL15(a[ 4], a[12]) + + MUL15(a[ 5], a[11]) + + MUL15(a[ 6], a[10]) + + MUL15(a[ 7], a[ 9])) << 1); + t[17] = ((MUL15(a[ 0], a[17]) + + MUL15(a[ 1], a[16]) + + MUL15(a[ 2], a[15]) + + MUL15(a[ 3], a[14]) + + MUL15(a[ 4], a[13]) + + MUL15(a[ 5], a[12]) + + MUL15(a[ 6], a[11]) + + MUL15(a[ 7], a[10]) + + MUL15(a[ 8], a[ 9])) << 1); + t[18] = MUL15(a[ 9], a[ 9]) + + ((MUL15(a[ 0], a[18]) + + MUL15(a[ 1], a[17]) + + MUL15(a[ 2], a[16]) + + MUL15(a[ 3], a[15]) + + MUL15(a[ 4], a[14]) + + MUL15(a[ 5], a[13]) + + MUL15(a[ 6], a[12]) + + MUL15(a[ 7], a[11]) + + MUL15(a[ 8], a[10])) << 1); + t[19] = ((MUL15(a[ 0], a[19]) + + MUL15(a[ 1], a[18]) + + MUL15(a[ 2], a[17]) + + MUL15(a[ 3], a[16]) + + MUL15(a[ 4], a[15]) + + MUL15(a[ 5], a[14]) + + MUL15(a[ 6], a[13]) + + MUL15(a[ 7], a[12]) + + MUL15(a[ 8], a[11]) + + MUL15(a[ 9], a[10])) << 1); + t[20] = MUL15(a[10], a[10]) + + ((MUL15(a[ 1], a[19]) + + MUL15(a[ 2], a[18]) + + MUL15(a[ 3], a[17]) + + MUL15(a[ 4], a[16]) + + MUL15(a[ 5], a[15]) + + MUL15(a[ 6], a[14]) + + MUL15(a[ 7], a[13]) + + MUL15(a[ 8], a[12]) + + MUL15(a[ 9], a[11])) << 1); + t[21] = ((MUL15(a[ 2], a[19]) + + MUL15(a[ 3], a[18]) + + MUL15(a[ 4], a[17]) + + MUL15(a[ 5], a[16]) + + MUL15(a[ 6], a[15]) + + MUL15(a[ 7], a[14]) + + MUL15(a[ 8], a[13]) + + MUL15(a[ 9], a[12]) + + MUL15(a[10], a[11])) << 1); + t[22] = MUL15(a[11], a[11]) + + ((MUL15(a[ 3], a[19]) + + MUL15(a[ 4], a[18]) + + MUL15(a[ 5], a[17]) + + MUL15(a[ 6], a[16]) + + MUL15(a[ 7], a[15]) + + MUL15(a[ 8], a[14]) + + MUL15(a[ 9], a[13]) + + MUL15(a[10], a[12])) << 1); + t[23] = ((MUL15(a[ 4], a[19]) + + MUL15(a[ 5], a[18]) + + MUL15(a[ 6], a[17]) + + MUL15(a[ 7], a[16]) + + MUL15(a[ 8], a[15]) + + MUL15(a[ 9], a[14]) + + MUL15(a[10], a[13]) + + MUL15(a[11], a[12])) << 1); + t[24] = MUL15(a[12], a[12]) + + ((MUL15(a[ 5], a[19]) + + MUL15(a[ 6], a[18]) + + MUL15(a[ 7], a[17]) + + MUL15(a[ 8], a[16]) + + MUL15(a[ 9], a[15]) + + MUL15(a[10], a[14]) + + MUL15(a[11], a[13])) << 1); + t[25] = ((MUL15(a[ 6], a[19]) + + MUL15(a[ 7], a[18]) + + MUL15(a[ 8], a[17]) + + MUL15(a[ 9], a[16]) + + MUL15(a[10], a[15]) + + MUL15(a[11], a[14]) + + MUL15(a[12], a[13])) << 1); + t[26] = MUL15(a[13], a[13]) + + ((MUL15(a[ 7], a[19]) + + MUL15(a[ 8], a[18]) + + MUL15(a[ 9], a[17]) + + MUL15(a[10], a[16]) + + MUL15(a[11], a[15]) + + MUL15(a[12], a[14])) << 1); + t[27] = ((MUL15(a[ 8], a[19]) + + MUL15(a[ 9], a[18]) + + MUL15(a[10], a[17]) + + MUL15(a[11], a[16]) + + MUL15(a[12], a[15]) + + MUL15(a[13], a[14])) << 1); + t[28] = MUL15(a[14], a[14]) + + ((MUL15(a[ 9], a[19]) + + MUL15(a[10], a[18]) + + MUL15(a[11], a[17]) + + MUL15(a[12], a[16]) + + MUL15(a[13], a[15])) << 1); + t[29] = ((MUL15(a[10], a[19]) + + MUL15(a[11], a[18]) + + MUL15(a[12], a[17]) + + MUL15(a[13], a[16]) + + MUL15(a[14], a[15])) << 1); + t[30] = MUL15(a[15], a[15]) + + ((MUL15(a[11], a[19]) + + MUL15(a[12], a[18]) + + MUL15(a[13], a[17]) + + MUL15(a[14], a[16])) << 1); + t[31] = ((MUL15(a[12], a[19]) + + MUL15(a[13], a[18]) + + MUL15(a[14], a[17]) + + MUL15(a[15], a[16])) << 1); + t[32] = MUL15(a[16], a[16]) + + ((MUL15(a[13], a[19]) + + MUL15(a[14], a[18]) + + MUL15(a[15], a[17])) << 1); + t[33] = ((MUL15(a[14], a[19]) + + MUL15(a[15], a[18]) + + MUL15(a[16], a[17])) << 1); + t[34] = MUL15(a[17], a[17]) + + ((MUL15(a[15], a[19]) + + MUL15(a[16], a[18])) << 1); + t[35] = ((MUL15(a[16], a[19]) + + MUL15(a[17], a[18])) << 1); + t[36] = MUL15(a[18], a[18]) + + ((MUL15(a[17], a[19])) << 1); + t[37] = ((MUL15(a[18], a[19])) << 1); + t[38] = MUL15(a[19], a[19]); + d[39] = norm13(d, t, 39); +} + +#endif + +/* + * Modulus for field F256 (field for point coordinates in curve P-256). + */ +static const uint32_t F256[] = { + 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x001F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0400, 0x0000, + 0x0000, 0x1FF8, 0x1FFF, 0x01FF +}; + +/* + * The 'b' curve equation coefficient for P-256. + */ +static const uint32_t P256_B[] = { + 0x004B, 0x1E93, 0x0F89, 0x1C78, 0x03BC, 0x187B, 0x114E, 0x1619, + 0x1D06, 0x0328, 0x01AF, 0x0D31, 0x1557, 0x15DE, 0x1ECF, 0x127C, + 0x0A3A, 0x0EC5, 0x118D, 0x00B5 +}; + +/* + * Perform a "short reduction" in field F256 (field for curve P-256). + * The source value should be less than 262 bits; on output, it will + * be at most 257 bits, and less than twice the modulus. + */ +static void +reduce_f256(uint32_t *d) +{ + uint32_t x; + + x = d[19] >> 9; + d[19] &= 0x01FF; + d[17] += x << 3; + d[14] -= x << 10; + d[7] -= x << 5; + d[0] += x; + norm13(d, d, 20); +} + +/* + * Perform a "final reduction" in field F256 (field for curve P-256). + * The source value must be less than twice the modulus. If the value + * is not lower than the modulus, then the modulus is subtracted and + * this function returns 1; otherwise, it leaves it untouched and it + * returns 0. + */ +static uint32_t +reduce_final_f256(uint32_t *d) +{ + uint32_t t[20]; + uint32_t cc; + int i; + + memcpy(t, d, sizeof t); + cc = 0; + for (i = 0; i < 20; i ++) { + uint32_t w; + + w = t[i] - F256[i] - cc; + cc = w >> 31; + t[i] = w & 0x1FFF; + } + cc ^= 1; + CCOPY(cc, d, t, sizeof t); + return cc; +} + +/* + * Perform a multiplication of two integers modulo + * 2^256-2^224+2^192+2^96-1 (for NIST curve P-256). Operands are arrays + * of 20 words, each containing 13 bits of data, in little-endian order. + * On input, upper word may be up to 13 bits (hence value up to 2^260-1); + * on output, value fits on 257 bits and is lower than twice the modulus. + */ +static void +mul_f256(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t t[40], cc; + int i; + + /* + * Compute raw multiplication. All result words fit in 13 bits + * each. + */ + mul20(t, a, b); + + /* + * Modular reduction: each high word in added/subtracted where + * necessary. + * + * The modulus is: + * p = 2^256 - 2^224 + 2^192 + 2^96 - 1 + * Therefore: + * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p + * + * For a word x at bit offset n (n >= 256), we have: + * x*2^n = x*2^(n-32) - x*2^(n-64) + * - x*2^(n - 160) + x*2^(n-256) mod p + * + * Thus, we can nullify the high word if we reinject it at some + * proper emplacements. + */ + for (i = 39; i >= 20; i --) { + uint32_t x; + + x = t[i]; + t[i - 2] += ARSH(x, 6); + t[i - 3] += (x << 7) & 0x1FFF; + t[i - 4] -= ARSH(x, 12); + t[i - 5] -= (x << 1) & 0x1FFF; + t[i - 12] -= ARSH(x, 4); + t[i - 13] -= (x << 9) & 0x1FFF; + t[i - 19] += ARSH(x, 9); + t[i - 20] += (x << 4) & 0x1FFF; + } + + /* + * Propagate carries. This is a signed propagation, and the + * result may be negative. The loop above may enlarge values, + * but not two much: worst case is the chain involving t[i - 3], + * in which a value may be added to itself up to 7 times. Since + * starting values are 13-bit each, all words fit on 20 bits + * (21 to account for the sign bit). + */ + cc = norm13(t, t, 20); + + /* + * Perform modular reduction again for the bits beyond 256 (the carry + * and the bits 256..259). Since the largest shift below is by 10 + * bits, and the values fit on 21 bits, values fit in 32-bit words, + * thereby allowing injecting full word values. + */ + cc = (cc << 4) | (t[19] >> 9); + t[19] &= 0x01FF; + t[17] += cc << 3; + t[14] -= cc << 10; + t[7] -= cc << 5; + t[0] += cc; + + /* + * If the carry is negative, then after carry propagation, we may + * end up with a value which is negative, and we don't want that. + * Thus, in that case, we add the modulus. Note that the subtraction + * result, when the carry is negative, is always smaller than the + * modulus, so the extra addition will not make the value exceed + * twice the modulus. + */ + cc >>= 31; + t[0] -= cc; + t[7] += cc << 5; + t[14] += cc << 10; + t[17] -= cc << 3; + t[19] += cc << 9; + + norm13(d, t, 20); +} + +/* + * Square an integer modulo 2^256-2^224+2^192+2^96-1 (for NIST curve + * P-256). Operand is an array of 20 words, each containing 13 bits of + * data, in little-endian order. On input, upper word may be up to 13 + * bits (hence value up to 2^260-1); on output, value fits on 257 bits + * and is lower than twice the modulus. + */ +static void +square_f256(uint32_t *d, const uint32_t *a) +{ + uint32_t t[40], cc; + int i; + + /* + * Compute raw square. All result words fit in 13 bits each. + */ + square20(t, a); + + /* + * Modular reduction: each high word in added/subtracted where + * necessary. + * + * The modulus is: + * p = 2^256 - 2^224 + 2^192 + 2^96 - 1 + * Therefore: + * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p + * + * For a word x at bit offset n (n >= 256), we have: + * x*2^n = x*2^(n-32) - x*2^(n-64) + * - x*2^(n - 160) + x*2^(n-256) mod p + * + * Thus, we can nullify the high word if we reinject it at some + * proper emplacements. + */ + for (i = 39; i >= 20; i --) { + uint32_t x; + + x = t[i]; + t[i - 2] += ARSH(x, 6); + t[i - 3] += (x << 7) & 0x1FFF; + t[i - 4] -= ARSH(x, 12); + t[i - 5] -= (x << 1) & 0x1FFF; + t[i - 12] -= ARSH(x, 4); + t[i - 13] -= (x << 9) & 0x1FFF; + t[i - 19] += ARSH(x, 9); + t[i - 20] += (x << 4) & 0x1FFF; + } + + /* + * Propagate carries. This is a signed propagation, and the + * result may be negative. The loop above may enlarge values, + * but not two much: worst case is the chain involving t[i - 3], + * in which a value may be added to itself up to 7 times. Since + * starting values are 13-bit each, all words fit on 20 bits + * (21 to account for the sign bit). + */ + cc = norm13(t, t, 20); + + /* + * Perform modular reduction again for the bits beyond 256 (the carry + * and the bits 256..259). Since the largest shift below is by 10 + * bits, and the values fit on 21 bits, values fit in 32-bit words, + * thereby allowing injecting full word values. + */ + cc = (cc << 4) | (t[19] >> 9); + t[19] &= 0x01FF; + t[17] += cc << 3; + t[14] -= cc << 10; + t[7] -= cc << 5; + t[0] += cc; + + /* + * If the carry is negative, then after carry propagation, we may + * end up with a value which is negative, and we don't want that. + * Thus, in that case, we add the modulus. Note that the subtraction + * result, when the carry is negative, is always smaller than the + * modulus, so the extra addition will not make the value exceed + * twice the modulus. + */ + cc >>= 31; + t[0] -= cc; + t[7] += cc << 5; + t[14] += cc << 10; + t[17] -= cc << 3; + t[19] += cc << 9; + + norm13(d, t, 20); +} + +/* + * Jacobian coordinates for a point in P-256: affine coordinates (X,Y) + * are such that: + * X = x / z^2 + * Y = y / z^3 + * For the point at infinity, z = 0. + * Each point thus admits many possible representations. + * + * Coordinates are represented in arrays of 32-bit integers, each holding + * 13 bits of data. Values may also be slightly greater than the modulus, + * but they will always be lower than twice the modulus. + */ +typedef struct { + uint32_t x[20]; + uint32_t y[20]; + uint32_t z[20]; +} p256_jacobian; + +/* + * Convert a point to affine coordinates: + * - If the point is the point at infinity, then all three coordinates + * are set to 0. + * - Otherwise, the 'z' coordinate is set to 1, and the 'x' and 'y' + * coordinates are the 'X' and 'Y' affine coordinates. + * The coordinates are guaranteed to be lower than the modulus. + */ +static void +p256_to_affine(p256_jacobian *P) +{ + uint32_t t1[20], t2[20]; + int i; + + /* + * Invert z with a modular exponentiation: the modulus is + * p = 2^256 - 2^224 + 2^192 + 2^96 - 1, and the exponent is + * p-2. Exponent bit pattern (from high to low) is: + * - 32 bits of value 1 + * - 31 bits of value 0 + * - 1 bit of value 1 + * - 96 bits of value 0 + * - 94 bits of value 1 + * - 1 bit of value 0 + * - 1 bit of value 1 + * Thus, we precompute z^(2^31-1) to speed things up. + * + * If z = 0 (point at infinity) then the modular exponentiation + * will yield 0, which leads to the expected result (all three + * coordinates set to 0). + */ + + /* + * A simple square-and-multiply for z^(2^31-1). We could save about + * two dozen multiplications here with an addition chain, but + * this would require a bit more code, and extra stack buffers. + */ + memcpy(t1, P->z, sizeof P->z); + for (i = 0; i < 30; i ++) { + square_f256(t1, t1); + mul_f256(t1, t1, P->z); + } + + /* + * Square-and-multiply. Apart from the squarings, we have a few + * multiplications to set bits to 1; we multiply by the original z + * for setting 1 bit, and by t1 for setting 31 bits. + */ + memcpy(t2, P->z, sizeof P->z); + for (i = 1; i < 256; i ++) { + square_f256(t2, t2); + switch (i) { + case 31: + case 190: + case 221: + case 252: + mul_f256(t2, t2, t1); + break; + case 63: + case 253: + case 255: + mul_f256(t2, t2, P->z); + break; + } + } + + /* + * Now that we have 1/z, multiply x by 1/z^2 and y by 1/z^3. + */ + mul_f256(t1, t2, t2); + mul_f256(P->x, t1, P->x); + mul_f256(t1, t1, t2); + mul_f256(P->y, t1, P->y); + reduce_final_f256(P->x); + reduce_final_f256(P->y); + + /* + * Multiply z by 1/z. If z = 0, then this will yield 0, otherwise + * this will set z to 1. + */ + mul_f256(P->z, P->z, t2); + reduce_final_f256(P->z); +} + +/* + * Double a point in P-256. This function works for all valid points, + * including the point at infinity. + */ +static void +p256_double(p256_jacobian *Q) +{ + /* + * Doubling formulas are: + * + * s = 4*x*y^2 + * m = 3*(x + z^2)*(x - z^2) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y^4 + * z' = 2*y*z + * + * These formulas work for all points, including points of order 2 + * and points at infinity: + * - If y = 0 then z' = 0. But there is no such point in P-256 + * anyway. + * - If z = 0 then z' = 0. + */ + uint32_t t1[20], t2[20], t3[20], t4[20]; + int i; + + /* + * Compute z^2 in t1. + */ + square_f256(t1, Q->z); + + /* + * Compute x-z^2 in t2 and x+z^2 in t1. + */ + for (i = 0; i < 20; i ++) { + t2[i] = (F256[i] << 1) + Q->x[i] - t1[i]; + t1[i] += Q->x[i]; + } + norm13(t1, t1, 20); + norm13(t2, t2, 20); + + /* + * Compute 3*(x+z^2)*(x-z^2) in t1. + */ + mul_f256(t3, t1, t2); + for (i = 0; i < 20; i ++) { + t1[i] = MUL15(3, t3[i]); + } + norm13(t1, t1, 20); + + /* + * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3). + */ + square_f256(t3, Q->y); + for (i = 0; i < 20; i ++) { + t3[i] <<= 1; + } + norm13(t3, t3, 20); + mul_f256(t2, Q->x, t3); + for (i = 0; i < 20; i ++) { + t2[i] <<= 1; + } + norm13(t2, t2, 20); + reduce_f256(t2); + + /* + * Compute x' = m^2 - 2*s. + */ + square_f256(Q->x, t1); + for (i = 0; i < 20; i ++) { + Q->x[i] += (F256[i] << 2) - (t2[i] << 1); + } + norm13(Q->x, Q->x, 20); + reduce_f256(Q->x); + + /* + * Compute z' = 2*y*z. + */ + mul_f256(t4, Q->y, Q->z); + for (i = 0; i < 20; i ++) { + Q->z[i] = t4[i] << 1; + } + norm13(Q->z, Q->z, 20); + reduce_f256(Q->z); + + /* + * Compute y' = m*(s - x') - 8*y^4. Note that we already have + * 2*y^2 in t3. + */ + for (i = 0; i < 20; i ++) { + t2[i] += (F256[i] << 1) - Q->x[i]; + } + norm13(t2, t2, 20); + mul_f256(Q->y, t1, t2); + square_f256(t4, t3); + for (i = 0; i < 20; i ++) { + Q->y[i] += (F256[i] << 2) - (t4[i] << 1); + } + norm13(Q->y, Q->y, 20); + reduce_f256(Q->y); +} + +/* + * Add point P2 to point P1. + * + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 but P2 != 0 + * - If P1 != 0 but P2 == 0 + * - If P1 == P2 + * + * In all three cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y coordinate + * - P1 == 0 and P2 == 0 + * - The Y coordinate of one of the points is 0 and the other point is + * the point at infinity. + * + * The third case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + */ +static uint32_t +p256_add(p256_jacobian *P1, const p256_jacobian *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 * z2^2 + * u2 = x2 * z1^2 + * s1 = y1 * z2^3 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 * z2 + */ + uint32_t t1[20], t2[20], t3[20], t4[20], t5[20], t6[20], t7[20]; + uint32_t ret; + int i; + + /* + * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). + */ + square_f256(t3, P2->z); + mul_f256(t1, P1->x, t3); + mul_f256(t4, P2->z, t3); + mul_f256(t3, P1->y, t4); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + square_f256(t4, P1->z); + mul_f256(t2, P2->x, t4); + mul_f256(t5, P1->z, t4); + mul_f256(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + for (i = 0; i < 20; i ++) { + t2[i] += (F256[i] << 1) - t1[i]; + t4[i] += (F256[i] << 1) - t3[i]; + } + norm13(t2, t2, 20); + norm13(t4, t4, 20); + reduce_f256(t4); + reduce_final_f256(t4); + ret = 0; + for (i = 0; i < 20; i ++) { + ret |= t4[i]; + } + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + square_f256(t7, t2); + mul_f256(t6, t1, t7); + mul_f256(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + square_f256(P1->x, t4); + for (i = 0; i < 20; i ++) { + P1->x[i] += (F256[i] << 3) - t5[i] - (t6[i] << 1); + } + norm13(P1->x, P1->x, 20); + reduce_f256(P1->x); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + for (i = 0; i < 20; i ++) { + t6[i] += (F256[i] << 1) - P1->x[i]; + } + norm13(t6, t6, 20); + mul_f256(P1->y, t4, t6); + mul_f256(t1, t5, t3); + for (i = 0; i < 20; i ++) { + P1->y[i] += (F256[i] << 1) - t1[i]; + } + norm13(P1->y, P1->y, 20); + reduce_f256(P1->y); + + /* + * Compute z3 = h*z1*z2. + */ + mul_f256(t1, P1->z, P2->z); + mul_f256(P1->z, t1, t2); + + return ret; +} + +/* + * Add point P2 to point P1. This is a specialised function for the + * case when P2 is a non-zero point in affine coordinate. + * + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 + * - If P1 == P2 + * + * In both cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y coordinate + * - The Y coordinate of P2 is 0 and P1 is the point at infinity. + * + * The second case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + */ +static uint32_t +p256_add_mixed(p256_jacobian *P1, const p256_jacobian *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 + * u2 = x2 * z1^2 + * s1 = y1 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 + */ + uint32_t t1[20], t2[20], t3[20], t4[20], t5[20], t6[20], t7[20]; + uint32_t ret; + int i; + + /* + * Compute u1 = x1 (in t1) and s1 = y1 (in t3). + */ + memcpy(t1, P1->x, sizeof t1); + memcpy(t3, P1->y, sizeof t3); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + square_f256(t4, P1->z); + mul_f256(t2, P2->x, t4); + mul_f256(t5, P1->z, t4); + mul_f256(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + for (i = 0; i < 20; i ++) { + t2[i] += (F256[i] << 1) - t1[i]; + t4[i] += (F256[i] << 1) - t3[i]; + } + norm13(t2, t2, 20); + norm13(t4, t4, 20); + reduce_f256(t4); + reduce_final_f256(t4); + ret = 0; + for (i = 0; i < 20; i ++) { + ret |= t4[i]; + } + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + square_f256(t7, t2); + mul_f256(t6, t1, t7); + mul_f256(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + square_f256(P1->x, t4); + for (i = 0; i < 20; i ++) { + P1->x[i] += (F256[i] << 3) - t5[i] - (t6[i] << 1); + } + norm13(P1->x, P1->x, 20); + reduce_f256(P1->x); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + for (i = 0; i < 20; i ++) { + t6[i] += (F256[i] << 1) - P1->x[i]; + } + norm13(t6, t6, 20); + mul_f256(P1->y, t4, t6); + mul_f256(t1, t5, t3); + for (i = 0; i < 20; i ++) { + P1->y[i] += (F256[i] << 1) - t1[i]; + } + norm13(P1->y, P1->y, 20); + reduce_f256(P1->y); + + /* + * Compute z3 = h*z1*z2. + */ + mul_f256(P1->z, P1->z, t2); + + return ret; +} + +/* + * Decode a P-256 point. This function does not support the point at + * infinity. Returned value is 0 if the point is invalid, 1 otherwise. + */ +static uint32_t +p256_decode(p256_jacobian *P, const void *src, size_t len) +{ + const unsigned char *buf; + uint32_t tx[20], ty[20], t1[20], t2[20]; + uint32_t bad; + int i; + + if (len != 65) { + return 0; + } + buf = src; + + /* + * First byte must be 0x04 (uncompressed format). We could support + * "hybrid format" (first byte is 0x06 or 0x07, and encodes the + * least significant bit of the Y coordinate), but it is explicitly + * forbidden by RFC 5480 (section 2.2). + */ + bad = NEQ(buf[0], 0x04); + + /* + * Decode the coordinates, and check that they are both lower + * than the modulus. + */ + tx[19] = be8_to_le13(tx, buf + 1, 32); + ty[19] = be8_to_le13(ty, buf + 33, 32); + bad |= reduce_final_f256(tx); + bad |= reduce_final_f256(ty); + + /* + * Check curve equation. + */ + square_f256(t1, tx); + mul_f256(t1, tx, t1); + square_f256(t2, ty); + for (i = 0; i < 20; i ++) { + t1[i] += (F256[i] << 3) - MUL15(3, tx[i]) + P256_B[i] - t2[i]; + } + norm13(t1, t1, 20); + reduce_f256(t1); + reduce_final_f256(t1); + for (i = 0; i < 20; i ++) { + bad |= t1[i]; + } + + /* + * Copy coordinates to the point structure. + */ + memcpy(P->x, tx, sizeof tx); + memcpy(P->y, ty, sizeof ty); + memset(P->z, 0, sizeof P->z); + P->z[0] = 1; + return NEQ(bad, 0) ^ 1; +} + +/* + * Encode a point into a buffer. This function assumes that the point is + * valid, in affine coordinates, and not the point at infinity. + */ +static void +p256_encode(void *dst, const p256_jacobian *P) +{ + unsigned char *buf; + + buf = dst; + buf[0] = 0x04; + le13_to_be8(buf + 1, 32, P->x); + le13_to_be8(buf + 33, 32, P->y); +} + +/* + * Multiply a curve point by an integer. The integer is assumed to be + * lower than the curve order, and the base point must not be the point + * at infinity. + */ +static void +p256_mul(p256_jacobian *P, const unsigned char *x, size_t xlen) +{ + /* + * qz is a flag that is initially 1, and remains equal to 1 + * as long as the point is the point at infinity. + * + * We use a 2-bit window to handle multiplier bits by pairs. + * The precomputed window really is the points P2 and P3. + */ + uint32_t qz; + p256_jacobian P2, P3, Q, T, U; + + /* + * Compute window values. + */ + P2 = *P; + p256_double(&P2); + P3 = *P; + p256_add(&P3, &P2); + + /* + * We start with Q = 0. We process multiplier bits 2 by 2. + */ + memset(&Q, 0, sizeof Q); + qz = 1; + while (xlen -- > 0) { + int k; + + for (k = 6; k >= 0; k -= 2) { + uint32_t bits; + uint32_t bnz; + + p256_double(&Q); + p256_double(&Q); + T = *P; + U = Q; + bits = (*x >> k) & (uint32_t)3; + bnz = NEQ(bits, 0); + CCOPY(EQ(bits, 2), &T, &P2, sizeof T); + CCOPY(EQ(bits, 3), &T, &P3, sizeof T); + p256_add(&U, &T); + CCOPY(bnz & qz, &Q, &T, sizeof Q); + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + } + x ++; + } + *P = Q; +} + +/* + * Precomputed window: k*G points, where G is the curve generator, and k + * is an integer from 1 to 15 (inclusive). The X and Y coordinates of + * the point are encoded as 20 words of 13 bits each (little-endian + * order); 13-bit words are then grouped 2-by-2 into 32-bit words + * (little-endian order within each word). + */ +static const uint32_t Gwin[15][20] = { + + { 0x04C60296, 0x02721176, 0x19D00F4A, 0x102517AC, + 0x13B8037D, 0x0748103C, 0x1E730E56, 0x08481FE2, + 0x0F97012C, 0x00D605F4, 0x1DFA11F5, 0x0C801A0D, + 0x0F670CBB, 0x0AED0CC5, 0x115E0E33, 0x181F0785, + 0x13F514A7, 0x0FF30E3B, 0x17171E1A, 0x009F18D0 }, + + { 0x1B341978, 0x16911F11, 0x0D9A1A60, 0x1C4E1FC8, + 0x1E040969, 0x096A06B0, 0x091C0030, 0x09EF1A29, + 0x18C40D03, 0x00F91C9E, 0x13C313D1, 0x096F0748, + 0x011419E0, 0x1CC713A6, 0x1DD31DAD, 0x1EE80C36, + 0x1ECD0C69, 0x1A0800A4, 0x08861B8E, 0x000E1DD5 }, + + { 0x173F1D6C, 0x02CC06F1, 0x14C21FB4, 0x043D1EB6, + 0x0F3606B7, 0x1A971C59, 0x1BF71951, 0x01481323, + 0x068D0633, 0x00BD12F9, 0x13EA1032, 0x136209E8, + 0x1C1E19A7, 0x06C7013E, 0x06C10AB0, 0x14C908BB, + 0x05830CE1, 0x1FEF18DD, 0x00620998, 0x010E0D19 }, + + { 0x18180852, 0x0604111A, 0x0B771509, 0x1B6F0156, + 0x00181FE2, 0x1DCC0AF4, 0x16EF0659, 0x11F70E80, + 0x11A912D0, 0x01C414D2, 0x027618C6, 0x05840FC6, + 0x100215C4, 0x187E0C3B, 0x12771C96, 0x150C0B5D, + 0x0FF705FD, 0x07981C67, 0x1AD20C63, 0x01C11C55 }, + + { 0x1E8113ED, 0x0A940370, 0x12920215, 0x1FA31D6F, + 0x1F7C0C82, 0x10CD03F7, 0x02640560, 0x081A0B5E, + 0x1BD21151, 0x00A21642, 0x0D0B0DA4, 0x0176113F, + 0x04440D1D, 0x001A1360, 0x1068012F, 0x1F141E49, + 0x10DF136B, 0x0E4F162B, 0x0D44104A, 0x01C1105F }, + + { 0x011411A9, 0x01551A4F, 0x0ADA0C6B, 0x01BD0EC8, + 0x18120C74, 0x112F1778, 0x099202CB, 0x0C05124B, + 0x195316A4, 0x01600685, 0x1E3B1FE2, 0x189014E3, + 0x0B5E1FD7, 0x0E0311F8, 0x08E000F7, 0x174E00DE, + 0x160702DF, 0x1B5A15BF, 0x03A11237, 0x01D01704 }, + + { 0x0C3D12A3, 0x0C501C0C, 0x17AD1300, 0x1715003F, + 0x03F719F8, 0x18031ED8, 0x1D980667, 0x0F681896, + 0x1B7D00BF, 0x011C14CE, 0x0FA000B4, 0x1C3501B0, + 0x0D901C55, 0x06790C10, 0x029E0736, 0x0DEB0400, + 0x034F183A, 0x030619B4, 0x0DEF0033, 0x00E71AC7 }, + + { 0x1B7D1393, 0x1B3B1076, 0x0BED1B4D, 0x13011F3A, + 0x0E0E1238, 0x156A132B, 0x013A02D3, 0x160A0D01, + 0x1CED1EE9, 0x00C5165D, 0x184C157E, 0x08141A83, + 0x153C0DA5, 0x1ED70F9D, 0x05170D51, 0x02CF13B8, + 0x18AE1771, 0x1B04113F, 0x05EC11E9, 0x015A16B3 }, + + { 0x04A41EE0, 0x1D1412E4, 0x1C591D79, 0x118511B7, + 0x14F00ACB, 0x1AE31E1C, 0x049C0D51, 0x016E061E, + 0x1DB71EDF, 0x01D41A35, 0x0E8208FA, 0x14441293, + 0x011F1E85, 0x1D54137A, 0x026B114F, 0x151D0832, + 0x00A50964, 0x1F9C1E1C, 0x064B12C9, 0x005409D1 }, + + { 0x062B123F, 0x0C0D0501, 0x183704C3, 0x08E31120, + 0x0A2E0A6C, 0x14440FED, 0x090A0D1E, 0x13271964, + 0x0B590A3A, 0x019D1D9B, 0x05780773, 0x09770A91, + 0x0F770CA3, 0x053F19D4, 0x02C80DED, 0x1A761304, + 0x091E0DD9, 0x15D201B8, 0x151109AA, 0x010F0198 }, + + { 0x05E101D1, 0x072314DD, 0x045F1433, 0x1A041541, + 0x10B3142E, 0x01840736, 0x1C1B19DB, 0x098B0418, + 0x1DBC083B, 0x007D1444, 0x01511740, 0x11DD1F3A, + 0x04ED0E2F, 0x1B4B1A62, 0x10480D04, 0x09E911A2, + 0x04211AFA, 0x19140893, 0x04D60CC4, 0x01210648 }, + + { 0x112703C4, 0x018B1BA1, 0x164C1D50, 0x05160BE0, + 0x0BCC1830, 0x01CB1554, 0x13291732, 0x1B2B1918, + 0x0DED0817, 0x00E80775, 0x0A2401D3, 0x0BFE08B3, + 0x0E531199, 0x058616E9, 0x04770B91, 0x110F0C55, + 0x19C11554, 0x0BFB1159, 0x03541C38, 0x000E1C2D }, + + { 0x10390C01, 0x02BB0751, 0x0AC5098E, 0x096C17AB, + 0x03C90E28, 0x10BD18BF, 0x002E1F2D, 0x092B0986, + 0x1BD700AC, 0x002E1F20, 0x1E3D1FD8, 0x077718BB, + 0x06F919C4, 0x187407ED, 0x11370E14, 0x081E139C, + 0x00481ADB, 0x14AB0289, 0x066A0EBE, 0x00C70ED6 }, + + { 0x0694120B, 0x124E1CC9, 0x0E2F0570, 0x17CF081A, + 0x078906AC, 0x066D17CF, 0x1B3207F4, 0x0C5705E9, + 0x10001C38, 0x00A919DE, 0x06851375, 0x0F900BD8, + 0x080401BA, 0x0EEE0D42, 0x1B8B11EA, 0x0B4519F0, + 0x090F18C0, 0x062E1508, 0x0DD909F4, 0x01EB067C }, + + { 0x0CDC1D5F, 0x0D1818F9, 0x07781636, 0x125B18E8, + 0x0D7003AF, 0x13110099, 0x1D9B1899, 0x175C1EB7, + 0x0E34171A, 0x01E01153, 0x081A0F36, 0x0B391783, + 0x1D1F147E, 0x19CE16D7, 0x11511B21, 0x1F2C10F9, + 0x12CA0E51, 0x05A31D39, 0x171A192E, 0x016B0E4F } +}; + +/* + * Lookup one of the Gwin[] values, by index. This is constant-time. + */ +static void +lookup_Gwin(p256_jacobian *T, uint32_t idx) +{ + uint32_t xy[20]; + uint32_t k; + size_t u; + + memset(xy, 0, sizeof xy); + for (k = 0; k < 15; k ++) { + uint32_t m; + + m = -EQ(idx, k + 1); + for (u = 0; u < 20; u ++) { + xy[u] |= m & Gwin[k][u]; + } + } + for (u = 0; u < 10; u ++) { + T->x[(u << 1) + 0] = xy[u] & 0xFFFF; + T->x[(u << 1) + 1] = xy[u] >> 16; + T->y[(u << 1) + 0] = xy[u + 10] & 0xFFFF; + T->y[(u << 1) + 1] = xy[u + 10] >> 16; + } + memset(T->z, 0, sizeof T->z); + T->z[0] = 1; +} + +/* + * Multiply the generator by an integer. The integer is assumed non-zero + * and lower than the curve order. + */ +static void +p256_mulgen(p256_jacobian *P, const unsigned char *x, size_t xlen) +{ + /* + * qz is a flag that is initially 1, and remains equal to 1 + * as long as the point is the point at infinity. + * + * We use a 4-bit window to handle multiplier bits by groups + * of 4. The precomputed window is constant static data, with + * points in affine coordinates; we use a constant-time lookup. + */ + p256_jacobian Q; + uint32_t qz; + + memset(&Q, 0, sizeof Q); + qz = 1; + while (xlen -- > 0) { + int k; + unsigned bx; + + bx = *x ++; + for (k = 0; k < 2; k ++) { + uint32_t bits; + uint32_t bnz; + p256_jacobian T, U; + + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + bits = (bx >> 4) & 0x0F; + bnz = NEQ(bits, 0); + lookup_Gwin(&T, bits); + U = Q; + p256_add_mixed(&U, &T); + CCOPY(bnz & qz, &Q, &T, sizeof Q); + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + bx <<= 4; + } + } + *P = Q; +} + +static const unsigned char P256_G[] = { + 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, + 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, + 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, + 0x98, 0xC2, 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, + 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, + 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, + 0x68, 0x37, 0xBF, 0x51, 0xF5 +}; + +static const unsigned char P256_N[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, + 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, + 0x25, 0x51 +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_G; + return P256_G; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_N; + return P256_N; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 1; +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *x, size_t xlen, int curve) +{ + uint32_t r; + p256_jacobian P; + + (void)curve; + r = p256_decode(&P, G, Glen); + p256_mul(&P, x, xlen); + if (Glen >= 65) { + p256_to_affine(&P); + p256_encode(G, &P); + } + return r; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + p256_jacobian P; + + (void)curve; + p256_mulgen(&P, x, xlen); + p256_to_affine(&P); + p256_encode(R, &P); + return 65; + + /* + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; + */ +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + p256_jacobian P, Q; + uint32_t r, t, z; + int i; + + (void)curve; + r = p256_decode(&P, A, len); + p256_mul(&P, x, xlen); + if (B == NULL) { + p256_mulgen(&Q, y, ylen); + } else { + r &= p256_decode(&Q, B, len); + p256_mul(&Q, y, ylen); + } + + /* + * The final addition may fail in case both points are equal. + */ + t = p256_add(&P, &Q); + reduce_final_f256(P.z); + z = 0; + for (i = 0; i < 20; i ++) { + z |= P.z[i]; + } + z = EQ(z, 0); + p256_double(&Q); + + /* + * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we + * have the following: + * + * z = 0, t = 0 return P (normal addition) + * z = 0, t = 1 return P (normal addition) + * z = 1, t = 0 return Q (a 'double' case) + * z = 1, t = 1 report an error (P+Q = 0) + */ + CCOPY(z & ~t, &P, &Q, sizeof Q); + p256_to_affine(&P); + p256_encode(A, &P); + r &= ~(z & t); + return r; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_p256_m15 = { + (uint32_t)0x00800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_p256_m31.c b/src/bearssl/src/ec/ec_p256_m31.c new file mode 100644 index 0000000..ec22c3e --- /dev/null +++ b/src/bearssl/src/ec/ec_p256_m31.c @@ -0,0 +1,1475 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_ + * that right-shifting a signed negative integer copies the sign bit + * (arithmetic right-shift). This is "implementation-defined behaviour", + * i.e. it is not undefined, but it may differ between compilers. Each + * compiler is supposed to document its behaviour in that respect. GCC + * explicitly defines that an arithmetic right shift is used. We expect + * all other compilers to do the same, because underlying CPU offer an + * arithmetic right shift opcode that could not be used otherwise. + */ +#if BR_NO_ARITH_SHIFT +#define ARSH(x, n) (((uint32_t)(x) >> (n)) \ + | ((-((uint32_t)(x) >> 31)) << (32 - (n)))) +#define ARSHW(x, n) (((uint64_t)(x) >> (n)) \ + | ((-((uint64_t)(x) >> 63)) << (64 - (n)))) +#else +#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n)) +#define ARSHW(x, n) ((*(int64_t *)&(x)) >> (n)) +#endif + +/* + * Convert an integer from unsigned big-endian encoding to a sequence of + * 30-bit words in little-endian order. The final "partial" word is + * returned. + */ +static uint32_t +be8_to_le30(uint32_t *dst, const unsigned char *src, size_t len) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + uint32_t b; + + b = src[len]; + if (acc_len < 22) { + acc |= b << acc_len; + acc_len += 8; + } else { + *dst ++ = (acc | (b << acc_len)) & 0x3FFFFFFF; + acc = b >> (30 - acc_len); + acc_len -= 22; + } + } + return acc; +} + +/* + * Convert an integer (30-bit words, little-endian) to unsigned + * big-endian encoding. The total encoding length is provided; all + * the destination bytes will be filled. + */ +static void +le30_to_be8(unsigned char *dst, size_t len, const uint32_t *src) +{ + uint32_t acc; + int acc_len; + + acc = 0; + acc_len = 0; + while (len -- > 0) { + if (acc_len < 8) { + uint32_t w; + + w = *src ++; + dst[len] = (unsigned char)(acc | (w << acc_len)); + acc = w >> (8 - acc_len); + acc_len += 22; + } else { + dst[len] = (unsigned char)acc; + acc >>= 8; + acc_len -= 8; + } + } +} + +/* + * Multiply two integers. Source integers are represented as arrays of + * nine 30-bit words, for values up to 2^270-1. Result is encoded over + * 18 words of 30 bits each. + */ +static void +mul9(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + /* + * Maximum intermediate result is no more than + * 10376293531797946367, which fits in 64 bits. Reason: + * + * 10376293531797946367 = 9 * (2^30-1)^2 + 9663676406 + * 10376293531797946367 < 9663676407 * 2^30 + * + * Thus, adding together 9 products of 30-bit integers, with + * a carry of at most 9663676406, yields an integer that fits + * on 64 bits and generates a carry of at most 9663676406. + */ + uint64_t t[17]; + uint64_t cc; + int i; + + t[ 0] = MUL31(a[0], b[0]); + t[ 1] = MUL31(a[0], b[1]) + + MUL31(a[1], b[0]); + t[ 2] = MUL31(a[0], b[2]) + + MUL31(a[1], b[1]) + + MUL31(a[2], b[0]); + t[ 3] = MUL31(a[0], b[3]) + + MUL31(a[1], b[2]) + + MUL31(a[2], b[1]) + + MUL31(a[3], b[0]); + t[ 4] = MUL31(a[0], b[4]) + + MUL31(a[1], b[3]) + + MUL31(a[2], b[2]) + + MUL31(a[3], b[1]) + + MUL31(a[4], b[0]); + t[ 5] = MUL31(a[0], b[5]) + + MUL31(a[1], b[4]) + + MUL31(a[2], b[3]) + + MUL31(a[3], b[2]) + + MUL31(a[4], b[1]) + + MUL31(a[5], b[0]); + t[ 6] = MUL31(a[0], b[6]) + + MUL31(a[1], b[5]) + + MUL31(a[2], b[4]) + + MUL31(a[3], b[3]) + + MUL31(a[4], b[2]) + + MUL31(a[5], b[1]) + + MUL31(a[6], b[0]); + t[ 7] = MUL31(a[0], b[7]) + + MUL31(a[1], b[6]) + + MUL31(a[2], b[5]) + + MUL31(a[3], b[4]) + + MUL31(a[4], b[3]) + + MUL31(a[5], b[2]) + + MUL31(a[6], b[1]) + + MUL31(a[7], b[0]); + t[ 8] = MUL31(a[0], b[8]) + + MUL31(a[1], b[7]) + + MUL31(a[2], b[6]) + + MUL31(a[3], b[5]) + + MUL31(a[4], b[4]) + + MUL31(a[5], b[3]) + + MUL31(a[6], b[2]) + + MUL31(a[7], b[1]) + + MUL31(a[8], b[0]); + t[ 9] = MUL31(a[1], b[8]) + + MUL31(a[2], b[7]) + + MUL31(a[3], b[6]) + + MUL31(a[4], b[5]) + + MUL31(a[5], b[4]) + + MUL31(a[6], b[3]) + + MUL31(a[7], b[2]) + + MUL31(a[8], b[1]); + t[10] = MUL31(a[2], b[8]) + + MUL31(a[3], b[7]) + + MUL31(a[4], b[6]) + + MUL31(a[5], b[5]) + + MUL31(a[6], b[4]) + + MUL31(a[7], b[3]) + + MUL31(a[8], b[2]); + t[11] = MUL31(a[3], b[8]) + + MUL31(a[4], b[7]) + + MUL31(a[5], b[6]) + + MUL31(a[6], b[5]) + + MUL31(a[7], b[4]) + + MUL31(a[8], b[3]); + t[12] = MUL31(a[4], b[8]) + + MUL31(a[5], b[7]) + + MUL31(a[6], b[6]) + + MUL31(a[7], b[5]) + + MUL31(a[8], b[4]); + t[13] = MUL31(a[5], b[8]) + + MUL31(a[6], b[7]) + + MUL31(a[7], b[6]) + + MUL31(a[8], b[5]); + t[14] = MUL31(a[6], b[8]) + + MUL31(a[7], b[7]) + + MUL31(a[8], b[6]); + t[15] = MUL31(a[7], b[8]) + + MUL31(a[8], b[7]); + t[16] = MUL31(a[8], b[8]); + + /* + * Propagate carries. + */ + cc = 0; + for (i = 0; i < 17; i ++) { + uint64_t w; + + w = t[i] + cc; + d[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } + d[17] = (uint32_t)cc; +} + +/* + * Square a 270-bit integer, represented as an array of nine 30-bit words. + * Result uses 18 words of 30 bits each. + */ +static void +square9(uint32_t *d, const uint32_t *a) +{ + uint64_t t[17]; + uint64_t cc; + int i; + + t[ 0] = MUL31(a[0], a[0]); + t[ 1] = ((MUL31(a[0], a[1])) << 1); + t[ 2] = MUL31(a[1], a[1]) + + ((MUL31(a[0], a[2])) << 1); + t[ 3] = ((MUL31(a[0], a[3]) + + MUL31(a[1], a[2])) << 1); + t[ 4] = MUL31(a[2], a[2]) + + ((MUL31(a[0], a[4]) + + MUL31(a[1], a[3])) << 1); + t[ 5] = ((MUL31(a[0], a[5]) + + MUL31(a[1], a[4]) + + MUL31(a[2], a[3])) << 1); + t[ 6] = MUL31(a[3], a[3]) + + ((MUL31(a[0], a[6]) + + MUL31(a[1], a[5]) + + MUL31(a[2], a[4])) << 1); + t[ 7] = ((MUL31(a[0], a[7]) + + MUL31(a[1], a[6]) + + MUL31(a[2], a[5]) + + MUL31(a[3], a[4])) << 1); + t[ 8] = MUL31(a[4], a[4]) + + ((MUL31(a[0], a[8]) + + MUL31(a[1], a[7]) + + MUL31(a[2], a[6]) + + MUL31(a[3], a[5])) << 1); + t[ 9] = ((MUL31(a[1], a[8]) + + MUL31(a[2], a[7]) + + MUL31(a[3], a[6]) + + MUL31(a[4], a[5])) << 1); + t[10] = MUL31(a[5], a[5]) + + ((MUL31(a[2], a[8]) + + MUL31(a[3], a[7]) + + MUL31(a[4], a[6])) << 1); + t[11] = ((MUL31(a[3], a[8]) + + MUL31(a[4], a[7]) + + MUL31(a[5], a[6])) << 1); + t[12] = MUL31(a[6], a[6]) + + ((MUL31(a[4], a[8]) + + MUL31(a[5], a[7])) << 1); + t[13] = ((MUL31(a[5], a[8]) + + MUL31(a[6], a[7])) << 1); + t[14] = MUL31(a[7], a[7]) + + ((MUL31(a[6], a[8])) << 1); + t[15] = ((MUL31(a[7], a[8])) << 1); + t[16] = MUL31(a[8], a[8]); + + /* + * Propagate carries. + */ + cc = 0; + for (i = 0; i < 17; i ++) { + uint64_t w; + + w = t[i] + cc; + d[i] = (uint32_t)w & 0x3FFFFFFF; + cc = w >> 30; + } + d[17] = (uint32_t)cc; +} + +/* + * Base field modulus for P-256. + */ +static const uint32_t F256[] = { + + 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x0000003F, 0x00000000, + 0x00000000, 0x00001000, 0x3FFFC000, 0x0000FFFF +}; + +/* + * The 'b' curve equation coefficient for P-256. + */ +static const uint32_t P256_B[] = { + + 0x27D2604B, 0x2F38F0F8, 0x053B0F63, 0x0741AC33, 0x1886BC65, + 0x2EF555DA, 0x293E7B3E, 0x0D762A8E, 0x00005AC6 +}; + +/* + * Addition in the field. Source operands shall fit on 257 bits; output + * will be lower than twice the modulus. + */ +static void +add_f256(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t w, cc; + int i; + + cc = 0; + for (i = 0; i < 9; i ++) { + w = a[i] + b[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = w >> 30; + } + w >>= 16; + d[8] &= 0xFFFF; + d[3] -= w << 6; + d[6] -= w << 12; + d[7] += w << 14; + cc = w; + for (i = 0; i < 9; i ++) { + w = d[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = ARSH(w, 30); + } +} + +/* + * Subtraction in the field. Source operands shall be smaller than twice + * the modulus; the result will fulfil the same property. + */ +static void +sub_f256(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t w, cc; + int i; + + /* + * We really compute a - b + 2*p to make sure that the result is + * positive. + */ + w = a[0] - b[0] - 0x00002; + d[0] = w & 0x3FFFFFFF; + w = a[1] - b[1] + ARSH(w, 30); + d[1] = w & 0x3FFFFFFF; + w = a[2] - b[2] + ARSH(w, 30); + d[2] = w & 0x3FFFFFFF; + w = a[3] - b[3] + ARSH(w, 30) + 0x00080; + d[3] = w & 0x3FFFFFFF; + w = a[4] - b[4] + ARSH(w, 30); + d[4] = w & 0x3FFFFFFF; + w = a[5] - b[5] + ARSH(w, 30); + d[5] = w & 0x3FFFFFFF; + w = a[6] - b[6] + ARSH(w, 30) + 0x02000; + d[6] = w & 0x3FFFFFFF; + w = a[7] - b[7] + ARSH(w, 30) - 0x08000; + d[7] = w & 0x3FFFFFFF; + w = a[8] - b[8] + ARSH(w, 30) + 0x20000; + d[8] = w & 0xFFFF; + w >>= 16; + d[8] &= 0xFFFF; + d[3] -= w << 6; + d[6] -= w << 12; + d[7] += w << 14; + cc = w; + for (i = 0; i < 9; i ++) { + w = d[i] + cc; + d[i] = w & 0x3FFFFFFF; + cc = ARSH(w, 30); + } +} + +/* + * Compute a multiplication in F256. Source operands shall be less than + * twice the modulus. + */ +static void +mul_f256(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + uint32_t t[18]; + uint64_t s[18]; + uint64_t cc, x; + uint32_t z, c; + int i; + + mul9(t, a, b); + + /* + * Modular reduction: each high word in added/subtracted where + * necessary. + * + * The modulus is: + * p = 2^256 - 2^224 + 2^192 + 2^96 - 1 + * Therefore: + * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p + * + * For a word x at bit offset n (n >= 256), we have: + * x*2^n = x*2^(n-32) - x*2^(n-64) + * - x*2^(n - 160) + x*2^(n-256) mod p + * + * Thus, we can nullify the high word if we reinject it at some + * proper emplacements. + * + * We use 64-bit intermediate words to allow for carries to + * accumulate easily, before performing the final propagation. + */ + for (i = 0; i < 18; i ++) { + s[i] = t[i]; + } + + for (i = 17; i >= 9; i --) { + uint64_t y; + + y = s[i]; + s[i - 1] += ARSHW(y, 2); + s[i - 2] += (y << 28) & 0x3FFFFFFF; + s[i - 2] -= ARSHW(y, 4); + s[i - 3] -= (y << 26) & 0x3FFFFFFF; + s[i - 5] -= ARSHW(y, 10); + s[i - 6] -= (y << 20) & 0x3FFFFFFF; + s[i - 8] += ARSHW(y, 16); + s[i - 9] += (y << 14) & 0x3FFFFFFF; + } + + /* + * Carry propagation must be signed. Moreover, we may have overdone + * it a bit, and obtain a negative result. + * + * The loop above ran 9 times; each time, each word was augmented + * by at most one extra word (in absolute value). Thus, the top + * word must in fine fit in 39 bits, so the carry below will fit + * on 9 bits. + */ + cc = 0; + for (i = 0; i < 9; i ++) { + x = s[i] + cc; + d[i] = (uint32_t)x & 0x3FFFFFFF; + cc = ARSHW(x, 30); + } + + /* + * All nine words fit on 30 bits, but there may be an extra + * carry for a few bits (at most 9), and that carry may be + * negative. Moreover, we want the result to fit on 257 bits. + * The two lines below ensure that the word in d[] has length + * 256 bits, and the (signed) carry (beyond 2^256) is in cc. The + * significant length of cc is less than 24 bits, so we will be + * able to switch to 32-bit operations. + */ + cc = ARSHW(x, 16); + d[8] &= 0xFFFF; + + /* + * One extra round of reduction, for cc*2^256, which means + * adding cc*(2^224-2^192-2^96+1) to a 256-bit (nonnegative) + * value. If cc is negative, then it may happen (rarely, but + * not neglectibly so) that the result would be negative. In + * order to avoid that, if cc is negative, then we add the + * modulus once. Note that if cc is negative, then propagating + * that carry must yield a value lower than the modulus, so + * adding the modulus once will keep the final result under + * twice the modulus. + */ + z = (uint32_t)cc; + d[3] -= z << 6; + d[6] -= (z << 12) & 0x3FFFFFFF; + d[7] -= ARSH(z, 18); + d[7] += (z << 14) & 0x3FFFFFFF; + d[8] += ARSH(z, 16); + c = z >> 31; + d[0] -= c; + d[3] += c << 6; + d[6] += c << 12; + d[7] -= c << 14; + d[8] += c << 16; + for (i = 0; i < 9; i ++) { + uint32_t w; + + w = d[i] + z; + d[i] = w & 0x3FFFFFFF; + z = ARSH(w, 30); + } +} + +/* + * Compute a square in F256. Source operand shall be less than + * twice the modulus. + */ +static void +square_f256(uint32_t *d, const uint32_t *a) +{ + uint32_t t[18]; + uint64_t s[18]; + uint64_t cc, x; + uint32_t z, c; + int i; + + square9(t, a); + + /* + * Modular reduction: each high word in added/subtracted where + * necessary. + * + * The modulus is: + * p = 2^256 - 2^224 + 2^192 + 2^96 - 1 + * Therefore: + * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p + * + * For a word x at bit offset n (n >= 256), we have: + * x*2^n = x*2^(n-32) - x*2^(n-64) + * - x*2^(n - 160) + x*2^(n-256) mod p + * + * Thus, we can nullify the high word if we reinject it at some + * proper emplacements. + * + * We use 64-bit intermediate words to allow for carries to + * accumulate easily, before performing the final propagation. + */ + for (i = 0; i < 18; i ++) { + s[i] = t[i]; + } + + for (i = 17; i >= 9; i --) { + uint64_t y; + + y = s[i]; + s[i - 1] += ARSHW(y, 2); + s[i - 2] += (y << 28) & 0x3FFFFFFF; + s[i - 2] -= ARSHW(y, 4); + s[i - 3] -= (y << 26) & 0x3FFFFFFF; + s[i - 5] -= ARSHW(y, 10); + s[i - 6] -= (y << 20) & 0x3FFFFFFF; + s[i - 8] += ARSHW(y, 16); + s[i - 9] += (y << 14) & 0x3FFFFFFF; + } + + /* + * Carry propagation must be signed. Moreover, we may have overdone + * it a bit, and obtain a negative result. + * + * The loop above ran 9 times; each time, each word was augmented + * by at most one extra word (in absolute value). Thus, the top + * word must in fine fit in 39 bits, so the carry below will fit + * on 9 bits. + */ + cc = 0; + for (i = 0; i < 9; i ++) { + x = s[i] + cc; + d[i] = (uint32_t)x & 0x3FFFFFFF; + cc = ARSHW(x, 30); + } + + /* + * All nine words fit on 30 bits, but there may be an extra + * carry for a few bits (at most 9), and that carry may be + * negative. Moreover, we want the result to fit on 257 bits. + * The two lines below ensure that the word in d[] has length + * 256 bits, and the (signed) carry (beyond 2^256) is in cc. The + * significant length of cc is less than 24 bits, so we will be + * able to switch to 32-bit operations. + */ + cc = ARSHW(x, 16); + d[8] &= 0xFFFF; + + /* + * One extra round of reduction, for cc*2^256, which means + * adding cc*(2^224-2^192-2^96+1) to a 256-bit (nonnegative) + * value. If cc is negative, then it may happen (rarely, but + * not neglectibly so) that the result would be negative. In + * order to avoid that, if cc is negative, then we add the + * modulus once. Note that if cc is negative, then propagating + * that carry must yield a value lower than the modulus, so + * adding the modulus once will keep the final result under + * twice the modulus. + */ + z = (uint32_t)cc; + d[3] -= z << 6; + d[6] -= (z << 12) & 0x3FFFFFFF; + d[7] -= ARSH(z, 18); + d[7] += (z << 14) & 0x3FFFFFFF; + d[8] += ARSH(z, 16); + c = z >> 31; + d[0] -= c; + d[3] += c << 6; + d[6] += c << 12; + d[7] -= c << 14; + d[8] += c << 16; + for (i = 0; i < 9; i ++) { + uint32_t w; + + w = d[i] + z; + d[i] = w & 0x3FFFFFFF; + z = ARSH(w, 30); + } +} + +/* + * Perform a "final reduction" in field F256 (field for curve P-256). + * The source value must be less than twice the modulus. If the value + * is not lower than the modulus, then the modulus is subtracted and + * this function returns 1; otherwise, it leaves it untouched and it + * returns 0. + */ +static uint32_t +reduce_final_f256(uint32_t *d) +{ + uint32_t t[9]; + uint32_t cc; + int i; + + cc = 0; + for (i = 0; i < 9; i ++) { + uint32_t w; + + w = d[i] - F256[i] - cc; + cc = w >> 31; + t[i] = w & 0x3FFFFFFF; + } + cc ^= 1; + CCOPY(cc, d, t, sizeof t); + return cc; +} + +/* + * Jacobian coordinates for a point in P-256: affine coordinates (X,Y) + * are such that: + * X = x / z^2 + * Y = y / z^3 + * For the point at infinity, z = 0. + * Each point thus admits many possible representations. + * + * Coordinates are represented in arrays of 32-bit integers, each holding + * 30 bits of data. Values may also be slightly greater than the modulus, + * but they will always be lower than twice the modulus. + */ +typedef struct { + uint32_t x[9]; + uint32_t y[9]; + uint32_t z[9]; +} p256_jacobian; + +/* + * Convert a point to affine coordinates: + * - If the point is the point at infinity, then all three coordinates + * are set to 0. + * - Otherwise, the 'z' coordinate is set to 1, and the 'x' and 'y' + * coordinates are the 'X' and 'Y' affine coordinates. + * The coordinates are guaranteed to be lower than the modulus. + */ +static void +p256_to_affine(p256_jacobian *P) +{ + uint32_t t1[9], t2[9]; + int i; + + /* + * Invert z with a modular exponentiation: the modulus is + * p = 2^256 - 2^224 + 2^192 + 2^96 - 1, and the exponent is + * p-2. Exponent bit pattern (from high to low) is: + * - 32 bits of value 1 + * - 31 bits of value 0 + * - 1 bit of value 1 + * - 96 bits of value 0 + * - 94 bits of value 1 + * - 1 bit of value 0 + * - 1 bit of value 1 + * Thus, we precompute z^(2^31-1) to speed things up. + * + * If z = 0 (point at infinity) then the modular exponentiation + * will yield 0, which leads to the expected result (all three + * coordinates set to 0). + */ + + /* + * A simple square-and-multiply for z^(2^31-1). We could save about + * two dozen multiplications here with an addition chain, but + * this would require a bit more code, and extra stack buffers. + */ + memcpy(t1, P->z, sizeof P->z); + for (i = 0; i < 30; i ++) { + square_f256(t1, t1); + mul_f256(t1, t1, P->z); + } + + /* + * Square-and-multiply. Apart from the squarings, we have a few + * multiplications to set bits to 1; we multiply by the original z + * for setting 1 bit, and by t1 for setting 31 bits. + */ + memcpy(t2, P->z, sizeof P->z); + for (i = 1; i < 256; i ++) { + square_f256(t2, t2); + switch (i) { + case 31: + case 190: + case 221: + case 252: + mul_f256(t2, t2, t1); + break; + case 63: + case 253: + case 255: + mul_f256(t2, t2, P->z); + break; + } + } + + /* + * Now that we have 1/z, multiply x by 1/z^2 and y by 1/z^3. + */ + mul_f256(t1, t2, t2); + mul_f256(P->x, t1, P->x); + mul_f256(t1, t1, t2); + mul_f256(P->y, t1, P->y); + reduce_final_f256(P->x); + reduce_final_f256(P->y); + + /* + * Multiply z by 1/z. If z = 0, then this will yield 0, otherwise + * this will set z to 1. + */ + mul_f256(P->z, P->z, t2); + reduce_final_f256(P->z); +} + +/* + * Double a point in P-256. This function works for all valid points, + * including the point at infinity. + */ +static void +p256_double(p256_jacobian *Q) +{ + /* + * Doubling formulas are: + * + * s = 4*x*y^2 + * m = 3*(x + z^2)*(x - z^2) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y^4 + * z' = 2*y*z + * + * These formulas work for all points, including points of order 2 + * and points at infinity: + * - If y = 0 then z' = 0. But there is no such point in P-256 + * anyway. + * - If z = 0 then z' = 0. + */ + uint32_t t1[9], t2[9], t3[9], t4[9]; + + /* + * Compute z^2 in t1. + */ + square_f256(t1, Q->z); + + /* + * Compute x-z^2 in t2 and x+z^2 in t1. + */ + add_f256(t2, Q->x, t1); + sub_f256(t1, Q->x, t1); + + /* + * Compute 3*(x+z^2)*(x-z^2) in t1. + */ + mul_f256(t3, t1, t2); + add_f256(t1, t3, t3); + add_f256(t1, t3, t1); + + /* + * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3). + */ + square_f256(t3, Q->y); + add_f256(t3, t3, t3); + mul_f256(t2, Q->x, t3); + add_f256(t2, t2, t2); + + /* + * Compute x' = m^2 - 2*s. + */ + square_f256(Q->x, t1); + sub_f256(Q->x, Q->x, t2); + sub_f256(Q->x, Q->x, t2); + + /* + * Compute z' = 2*y*z. + */ + mul_f256(t4, Q->y, Q->z); + add_f256(Q->z, t4, t4); + + /* + * Compute y' = m*(s - x') - 8*y^4. Note that we already have + * 2*y^2 in t3. + */ + sub_f256(t2, t2, Q->x); + mul_f256(Q->y, t1, t2); + square_f256(t4, t3); + add_f256(t4, t4, t4); + sub_f256(Q->y, Q->y, t4); +} + +/* + * Add point P2 to point P1. + * + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 but P2 != 0 + * - If P1 != 0 but P2 == 0 + * - If P1 == P2 + * + * In all three cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y coordinate + * - P1 == 0 and P2 == 0 + * - The Y coordinate of one of the points is 0 and the other point is + * the point at infinity. + * + * The third case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + */ +static uint32_t +p256_add(p256_jacobian *P1, const p256_jacobian *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 * z2^2 + * u2 = x2 * z1^2 + * s1 = y1 * z2^3 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 * z2 + */ + uint32_t t1[9], t2[9], t3[9], t4[9], t5[9], t6[9], t7[9]; + uint32_t ret; + int i; + + /* + * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). + */ + square_f256(t3, P2->z); + mul_f256(t1, P1->x, t3); + mul_f256(t4, P2->z, t3); + mul_f256(t3, P1->y, t4); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + square_f256(t4, P1->z); + mul_f256(t2, P2->x, t4); + mul_f256(t5, P1->z, t4); + mul_f256(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + sub_f256(t2, t2, t1); + sub_f256(t4, t4, t3); + reduce_final_f256(t4); + ret = 0; + for (i = 0; i < 9; i ++) { + ret |= t4[i]; + } + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + square_f256(t7, t2); + mul_f256(t6, t1, t7); + mul_f256(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + square_f256(P1->x, t4); + sub_f256(P1->x, P1->x, t5); + sub_f256(P1->x, P1->x, t6); + sub_f256(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + sub_f256(t6, t6, P1->x); + mul_f256(P1->y, t4, t6); + mul_f256(t1, t5, t3); + sub_f256(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1*z2. + */ + mul_f256(t1, P1->z, P2->z); + mul_f256(P1->z, t1, t2); + + return ret; +} + +/* + * Add point P2 to point P1. This is a specialised function for the + * case when P2 is a non-zero point in affine coordinate. + * + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 + * - If P1 == P2 + * + * In both cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y coordinate + * - The Y coordinate of P2 is 0 and P1 is the point at infinity. + * + * The second case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + */ +static uint32_t +p256_add_mixed(p256_jacobian *P1, const p256_jacobian *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 + * u2 = x2 * z1^2 + * s1 = y1 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 + */ + uint32_t t1[9], t2[9], t3[9], t4[9], t5[9], t6[9], t7[9]; + uint32_t ret; + int i; + + /* + * Compute u1 = x1 (in t1) and s1 = y1 (in t3). + */ + memcpy(t1, P1->x, sizeof t1); + memcpy(t3, P1->y, sizeof t3); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + square_f256(t4, P1->z); + mul_f256(t2, P2->x, t4); + mul_f256(t5, P1->z, t4); + mul_f256(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + sub_f256(t2, t2, t1); + sub_f256(t4, t4, t3); + reduce_final_f256(t4); + ret = 0; + for (i = 0; i < 9; i ++) { + ret |= t4[i]; + } + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + square_f256(t7, t2); + mul_f256(t6, t1, t7); + mul_f256(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + square_f256(P1->x, t4); + sub_f256(P1->x, P1->x, t5); + sub_f256(P1->x, P1->x, t6); + sub_f256(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + sub_f256(t6, t6, P1->x); + mul_f256(P1->y, t4, t6); + mul_f256(t1, t5, t3); + sub_f256(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1*z2. + */ + mul_f256(P1->z, P1->z, t2); + + return ret; +} + +/* + * Decode a P-256 point. This function does not support the point at + * infinity. Returned value is 0 if the point is invalid, 1 otherwise. + */ +static uint32_t +p256_decode(p256_jacobian *P, const void *src, size_t len) +{ + const unsigned char *buf; + uint32_t tx[9], ty[9], t1[9], t2[9]; + uint32_t bad; + int i; + + if (len != 65) { + return 0; + } + buf = src; + + /* + * First byte must be 0x04 (uncompressed format). We could support + * "hybrid format" (first byte is 0x06 or 0x07, and encodes the + * least significant bit of the Y coordinate), but it is explicitly + * forbidden by RFC 5480 (section 2.2). + */ + bad = NEQ(buf[0], 0x04); + + /* + * Decode the coordinates, and check that they are both lower + * than the modulus. + */ + tx[8] = be8_to_le30(tx, buf + 1, 32); + ty[8] = be8_to_le30(ty, buf + 33, 32); + bad |= reduce_final_f256(tx); + bad |= reduce_final_f256(ty); + + /* + * Check curve equation. + */ + square_f256(t1, tx); + mul_f256(t1, tx, t1); + square_f256(t2, ty); + sub_f256(t1, t1, tx); + sub_f256(t1, t1, tx); + sub_f256(t1, t1, tx); + add_f256(t1, t1, P256_B); + sub_f256(t1, t1, t2); + reduce_final_f256(t1); + for (i = 0; i < 9; i ++) { + bad |= t1[i]; + } + + /* + * Copy coordinates to the point structure. + */ + memcpy(P->x, tx, sizeof tx); + memcpy(P->y, ty, sizeof ty); + memset(P->z, 0, sizeof P->z); + P->z[0] = 1; + return NEQ(bad, 0) ^ 1; +} + +/* + * Encode a point into a buffer. This function assumes that the point is + * valid, in affine coordinates, and not the point at infinity. + */ +static void +p256_encode(void *dst, const p256_jacobian *P) +{ + unsigned char *buf; + + buf = dst; + buf[0] = 0x04; + le30_to_be8(buf + 1, 32, P->x); + le30_to_be8(buf + 33, 32, P->y); +} + +/* + * Multiply a curve point by an integer. The integer is assumed to be + * lower than the curve order, and the base point must not be the point + * at infinity. + */ +static void +p256_mul(p256_jacobian *P, const unsigned char *x, size_t xlen) +{ + /* + * qz is a flag that is initially 1, and remains equal to 1 + * as long as the point is the point at infinity. + * + * We use a 2-bit window to handle multiplier bits by pairs. + * The precomputed window really is the points P2 and P3. + */ + uint32_t qz; + p256_jacobian P2, P3, Q, T, U; + + /* + * Compute window values. + */ + P2 = *P; + p256_double(&P2); + P3 = *P; + p256_add(&P3, &P2); + + /* + * We start with Q = 0. We process multiplier bits 2 by 2. + */ + memset(&Q, 0, sizeof Q); + qz = 1; + while (xlen -- > 0) { + int k; + + for (k = 6; k >= 0; k -= 2) { + uint32_t bits; + uint32_t bnz; + + p256_double(&Q); + p256_double(&Q); + T = *P; + U = Q; + bits = (*x >> k) & (uint32_t)3; + bnz = NEQ(bits, 0); + CCOPY(EQ(bits, 2), &T, &P2, sizeof T); + CCOPY(EQ(bits, 3), &T, &P3, sizeof T); + p256_add(&U, &T); + CCOPY(bnz & qz, &Q, &T, sizeof Q); + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + } + x ++; + } + *P = Q; +} + +/* + * Precomputed window: k*G points, where G is the curve generator, and k + * is an integer from 1 to 15 (inclusive). The X and Y coordinates of + * the point are encoded as 9 words of 30 bits each (little-endian + * order). + */ +static const uint32_t Gwin[15][18] = { + + { 0x1898C296, 0x1284E517, 0x1EB33A0F, 0x00DF604B, + 0x2440F277, 0x339B958E, 0x04247F8B, 0x347CB84B, + 0x00006B17, 0x37BF51F5, 0x2ED901A0, 0x3315ECEC, + 0x338CD5DA, 0x0F9E162B, 0x1FAD29F0, 0x27F9B8EE, + 0x10B8BF86, 0x00004FE3 }, + + { 0x07669978, 0x182D23F1, 0x3F21B35A, 0x225A789D, + 0x351AC3C0, 0x08E00C12, 0x34F7E8A5, 0x1EC62340, + 0x00007CF2, 0x227873D1, 0x3812DE74, 0x0E982299, + 0x1F6B798F, 0x3430DBBA, 0x366B1A7D, 0x2D040293, + 0x154436E3, 0x00000777 }, + + { 0x06E7FD6C, 0x2D05986F, 0x3ADA985F, 0x31ADC87B, + 0x0BF165E6, 0x1FBE5475, 0x30A44C8F, 0x3934698C, + 0x00005ECB, 0x227D5032, 0x29E6C49E, 0x04FB83D9, + 0x0AAC0D8E, 0x24A2ECD8, 0x2C1B3869, 0x0FF7E374, + 0x19031266, 0x00008734 }, + + { 0x2B030852, 0x024C0911, 0x05596EF5, 0x07F8B6DE, + 0x262BD003, 0x3779967B, 0x08FBBA02, 0x128D4CB4, + 0x0000E253, 0x184ED8C6, 0x310B08FC, 0x30EE0055, + 0x3F25B0FC, 0x062D764E, 0x3FB97F6A, 0x33CC719D, + 0x15D69318, 0x0000E0F1 }, + + { 0x03D033ED, 0x05552837, 0x35BE5242, 0x2320BF47, + 0x268FDFEF, 0x13215821, 0x140D2D78, 0x02DE9454, + 0x00005159, 0x3DA16DA4, 0x0742ED13, 0x0D80888D, + 0x004BC035, 0x0A79260D, 0x06FCDAFE, 0x2727D8AE, + 0x1F6A2412, 0x0000E0C1 }, + + { 0x3C2291A9, 0x1AC2ABA4, 0x3B215B4C, 0x131D037A, + 0x17DDE302, 0x0C90B2E2, 0x0602C92D, 0x05CA9DA9, + 0x0000B01A, 0x0FC77FE2, 0x35F1214E, 0x07E16BDF, + 0x003DDC07, 0x2703791C, 0x3038B7EE, 0x3DAD56FE, + 0x041D0C8D, 0x0000E85C }, + + { 0x3187B2A3, 0x0018A1C0, 0x00FEF5B3, 0x3E7E2E2A, + 0x01FB607E, 0x2CC199F0, 0x37B4625B, 0x0EDBE82F, + 0x00008E53, 0x01F400B4, 0x15786A1B, 0x3041B21C, + 0x31CD8CF2, 0x35900053, 0x1A7E0E9B, 0x318366D0, + 0x076F780C, 0x000073EB }, + + { 0x1B6FB393, 0x13767707, 0x3CE97DBB, 0x348E2603, + 0x354CADC1, 0x09D0B4EA, 0x1B053404, 0x1DE76FBA, + 0x000062D9, 0x0F09957E, 0x295029A8, 0x3E76A78D, + 0x3B547DAE, 0x27CEE0A2, 0x0575DC45, 0x1D8244FF, + 0x332F647A, 0x0000AD5A }, + + { 0x10949EE0, 0x1E7A292E, 0x06DF8B3D, 0x02B2E30B, + 0x31F8729E, 0x24E35475, 0x30B71878, 0x35EDBFB7, + 0x0000EA68, 0x0DD048FA, 0x21688929, 0x0DE823FE, + 0x1C53FAA9, 0x0EA0C84D, 0x052A592A, 0x1FCE7870, + 0x11325CB2, 0x00002A27 }, + + { 0x04C5723F, 0x30D81A50, 0x048306E4, 0x329B11C7, + 0x223FB545, 0x085347A8, 0x2993E591, 0x1B5ACA8E, + 0x0000CEF6, 0x04AF0773, 0x28D2EEA9, 0x2751EEEC, + 0x037B4A7F, 0x3B4C1059, 0x08F37674, 0x2AE906E1, + 0x18A88A6A, 0x00008786 }, + + { 0x34BC21D1, 0x0CCE474D, 0x15048BF4, 0x1D0BB409, + 0x021CDA16, 0x20DE76C3, 0x34C59063, 0x04EDE20E, + 0x00003ED1, 0x282A3740, 0x0BE3BBF3, 0x29889DAE, + 0x03413697, 0x34C68A09, 0x210EBE93, 0x0C8A224C, + 0x0826B331, 0x00009099 }, + + { 0x0624E3C4, 0x140317BA, 0x2F82C99D, 0x260C0A2C, + 0x25D55179, 0x194DCC83, 0x3D95E462, 0x356F6A05, + 0x0000741D, 0x0D4481D3, 0x2657FC8B, 0x1BA5CA71, + 0x3AE44B0D, 0x07B1548E, 0x0E0D5522, 0x05FDC567, + 0x2D1AA70E, 0x00000770 }, + + { 0x06072C01, 0x23857675, 0x1EAD58A9, 0x0B8A12D9, + 0x1EE2FC79, 0x0177CB61, 0x0495A618, 0x20DEB82B, + 0x0000177C, 0x2FC7BFD8, 0x310EEF8B, 0x1FB4DF39, + 0x3B8530E8, 0x0F4E7226, 0x0246B6D0, 0x2A558A24, + 0x163353AF, 0x000063BB }, + + { 0x24D2920B, 0x1C249DCC, 0x2069C5E5, 0x09AB2F9E, + 0x36DF3CF1, 0x1991FD0C, 0x062B97A7, 0x1E80070E, + 0x000054E7, 0x20D0B375, 0x2E9F20BD, 0x35090081, + 0x1C7A9DDC, 0x22E7C371, 0x087E3016, 0x03175421, + 0x3C6ECA7D, 0x0000F599 }, + + { 0x259B9D5F, 0x0D9A318F, 0x23A0EF16, 0x00EBE4B7, + 0x088265AE, 0x2CDE2666, 0x2BAE7ADF, 0x1371A5C6, + 0x0000F045, 0x0D034F36, 0x1F967378, 0x1B5FA3F4, + 0x0EC8739D, 0x1643E62A, 0x1653947E, 0x22D1F4E6, + 0x0FB8D64B, 0x0000B5B9 } +}; + +/* + * Lookup one of the Gwin[] values, by index. This is constant-time. + */ +static void +lookup_Gwin(p256_jacobian *T, uint32_t idx) +{ + uint32_t xy[18]; + uint32_t k; + size_t u; + + memset(xy, 0, sizeof xy); + for (k = 0; k < 15; k ++) { + uint32_t m; + + m = -EQ(idx, k + 1); + for (u = 0; u < 18; u ++) { + xy[u] |= m & Gwin[k][u]; + } + } + memcpy(T->x, &xy[0], sizeof T->x); + memcpy(T->y, &xy[9], sizeof T->y); + memset(T->z, 0, sizeof T->z); + T->z[0] = 1; +} + +/* + * Multiply the generator by an integer. The integer is assumed non-zero + * and lower than the curve order. + */ +static void +p256_mulgen(p256_jacobian *P, const unsigned char *x, size_t xlen) +{ + /* + * qz is a flag that is initially 1, and remains equal to 1 + * as long as the point is the point at infinity. + * + * We use a 4-bit window to handle multiplier bits by groups + * of 4. The precomputed window is constant static data, with + * points in affine coordinates; we use a constant-time lookup. + */ + p256_jacobian Q; + uint32_t qz; + + memset(&Q, 0, sizeof Q); + qz = 1; + while (xlen -- > 0) { + int k; + unsigned bx; + + bx = *x ++; + for (k = 0; k < 2; k ++) { + uint32_t bits; + uint32_t bnz; + p256_jacobian T, U; + + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + bits = (bx >> 4) & 0x0F; + bnz = NEQ(bits, 0); + lookup_Gwin(&T, bits); + U = Q; + p256_add_mixed(&U, &T); + CCOPY(bnz & qz, &Q, &T, sizeof Q); + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + bx <<= 4; + } + } + *P = Q; +} + +static const unsigned char P256_G[] = { + 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, + 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, + 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, + 0x98, 0xC2, 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, + 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, + 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, + 0x68, 0x37, 0xBF, 0x51, 0xF5 +}; + +static const unsigned char P256_N[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, + 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, + 0x25, 0x51 +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_G; + return P256_G; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_N; + return P256_N; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 1; +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *x, size_t xlen, int curve) +{ + uint32_t r; + p256_jacobian P; + + (void)curve; + r = p256_decode(&P, G, Glen); + p256_mul(&P, x, xlen); + if (Glen >= 65) { + p256_to_affine(&P); + p256_encode(G, &P); + } + return r; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + p256_jacobian P; + + (void)curve; + p256_mulgen(&P, x, xlen); + p256_to_affine(&P); + p256_encode(R, &P); + return 65; + + /* + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; + */ +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + p256_jacobian P, Q; + uint32_t r, t, z; + int i; + + (void)curve; + r = p256_decode(&P, A, len); + p256_mul(&P, x, xlen); + if (B == NULL) { + p256_mulgen(&Q, y, ylen); + } else { + r &= p256_decode(&Q, B, len); + p256_mul(&Q, y, ylen); + } + + /* + * The final addition may fail in case both points are equal. + */ + t = p256_add(&P, &Q); + reduce_final_f256(P.z); + z = 0; + for (i = 0; i < 9; i ++) { + z |= P.z[i]; + } + z = EQ(z, 0); + p256_double(&Q); + + /* + * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we + * have the following: + * + * z = 0, t = 0 return P (normal addition) + * z = 0, t = 1 return P (normal addition) + * z = 1, t = 0 return Q (a 'double' case) + * z = 1, t = 1 report an error (P+Q = 0) + */ + CCOPY(z & ~t, &P, &Q, sizeof Q); + p256_to_affine(&P); + p256_encode(A, &P); + r &= ~(z & t); + return r; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_p256_m31 = { + (uint32_t)0x00800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_prime_i15.c b/src/bearssl/src/ec/ec_prime_i15.c new file mode 100644 index 0000000..0f210f2 --- /dev/null +++ b/src/bearssl/src/ec/ec_prime_i15.c @@ -0,0 +1,820 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Parameters for supported curves: + * - field modulus p + * - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p) + * - b*R mod p (b is the second curve equation parameter) + */ + +static const uint16_t P256_P[] = { + 0x0111, + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x003F, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x4000, 0x7FFF, + 0x7FFF, 0x0001 +}; + +static const uint16_t P256_R2[] = { + 0x0111, + 0x0000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFC, 0x7FFF, + 0x7FBF, 0x7FFF, 0x7FBF, 0x7FFF, 0x7FFF, 0x7FFF, 0x77FF, 0x7FFF, + 0x4FFF, 0x0000 +}; + +static const uint16_t P256_B[] = { + 0x0111, + 0x770C, 0x5EEF, 0x29C4, 0x3EC4, 0x6273, 0x0486, 0x4543, 0x3993, + 0x3C01, 0x6B56, 0x212E, 0x57EE, 0x4882, 0x204B, 0x7483, 0x3C16, + 0x0187, 0x0000 +}; + +static const uint16_t P384_P[] = { + 0x0199, + 0x7FFF, 0x7FFF, 0x0003, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FFF, + 0x7EFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF, 0x01FF +}; + +static const uint16_t P384_R2[] = { + 0x0199, + 0x1000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x0001, 0x0000, 0x0010, + 0x0000, 0x0000, 0x0000, 0x7F00, 0x7FFF, 0x01FF, 0x0000, 0x1000, + 0x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000 +}; + +static const uint16_t P384_B[] = { + 0x0199, + 0x7333, 0x2096, 0x70D1, 0x2310, 0x3020, 0x6197, 0x1464, 0x35BB, + 0x70CA, 0x0117, 0x1920, 0x4136, 0x5FC8, 0x5713, 0x4938, 0x7DD2, + 0x4DD2, 0x4A71, 0x0220, 0x683E, 0x2C87, 0x4DB1, 0x7BFF, 0x6C09, + 0x0452, 0x0084 +}; + +static const uint16_t P521_P[] = { + 0x022B, + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0x7FFF, 0x7FFF, 0x07FF +}; + +static const uint16_t P521_R2[] = { + 0x022B, + 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000 +}; + +static const uint16_t P521_B[] = { + 0x022B, + 0x7002, 0x6A07, 0x751A, 0x228F, 0x71EF, 0x5869, 0x20F4, 0x1EFC, + 0x7357, 0x37E0, 0x4EEC, 0x605E, 0x1652, 0x26F6, 0x31FA, 0x4A8F, + 0x6193, 0x3C2A, 0x3C42, 0x48C7, 0x3489, 0x6771, 0x4C57, 0x5CCD, + 0x2725, 0x545B, 0x503B, 0x5B42, 0x21A0, 0x2534, 0x687E, 0x70E4, + 0x1618, 0x27D7, 0x0465 +}; + +typedef struct { + const uint16_t *p; + const uint16_t *b; + const uint16_t *R2; + uint16_t p0i; + size_t point_len; +} curve_params; + +static inline const curve_params * +id_to_curve(int curve) +{ + static const curve_params pp[] = { + { P256_P, P256_B, P256_R2, 0x0001, 65 }, + { P384_P, P384_B, P384_R2, 0x0001, 97 }, + { P521_P, P521_B, P521_R2, 0x0001, 133 } + }; + + return &pp[curve - BR_EC_secp256r1]; +} + +#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15) + +/* + * Type for a point in Jacobian coordinates: + * -- three values, x, y and z, in Montgomery representation + * -- affine coordinates are X = x / z^2 and Y = y / z^3 + * -- for the point at infinity, z = 0 + */ +typedef struct { + uint16_t c[3][I15_LEN]; +} jacobian; + +/* + * We use a custom interpreter that uses a dozen registers, and + * only six operations: + * MSET(d, a) copy a into d + * MADD(d, a) d = d+a (modular) + * MSUB(d, a) d = d-a (modular) + * MMUL(d, a, b) d = a*b (Montgomery multiplication) + * MINV(d, a, b) invert d modulo p; a and b are used as scratch registers + * MTZ(d) clear return value if d = 0 + * Destination of MMUL (d) must be distinct from operands (a and b). + * There is no such constraint for MSUB and MADD. + * + * Registers include the operand coordinates, and temporaries. + */ +#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4)) +#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4)) +#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4)) +#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b)) +#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b)) +#define MTZ(d) (0x5000 + ((d) << 8)) +#define ENDCODE 0 + +/* + * Registers for the input operands. + */ +#define P1x 0 +#define P1y 1 +#define P1z 2 +#define P2x 3 +#define P2y 4 +#define P2z 5 + +/* + * Alternate names for the first input operand. + */ +#define Px 0 +#define Py 1 +#define Pz 2 + +/* + * Temporaries. + */ +#define t1 6 +#define t2 7 +#define t3 8 +#define t4 9 +#define t5 10 +#define t6 11 +#define t7 12 + +/* + * Extra scratch registers available when there is no second operand (e.g. + * for "double" and "affine"). + */ +#define t8 3 +#define t9 4 +#define t10 5 + +/* + * Doubling formulas are: + * + * s = 4*x*y^2 + * m = 3*(x + z^2)*(x - z^2) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y^4 + * z' = 2*y*z + * + * If y = 0 (P has order 2) then this yields infinity (z' = 0), as it + * should. This case should not happen anyway, because our curves have + * prime order, and thus do not contain any point of order 2. + * + * If P is infinity (z = 0), then again the formulas yield infinity, + * which is correct. Thus, this code works for all points. + * + * Cost: 8 multiplications + */ +static const uint16_t code_double[] = { + /* + * Compute z^2 (in t1). + */ + MMUL(t1, Pz, Pz), + + /* + * Compute x-z^2 (in t2) and then x+z^2 (in t1). + */ + MSET(t2, Px), + MSUB(t2, t1), + MADD(t1, Px), + + /* + * Compute m = 3*(x+z^2)*(x-z^2) (in t1). + */ + MMUL(t3, t1, t2), + MSET(t1, t3), + MADD(t1, t3), + MADD(t1, t3), + + /* + * Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3). + */ + MMUL(t3, Py, Py), + MADD(t3, t3), + MMUL(t2, Px, t3), + MADD(t2, t2), + + /* + * Compute x' = m^2 - 2*s. + */ + MMUL(Px, t1, t1), + MSUB(Px, t2), + MSUB(Px, t2), + + /* + * Compute z' = 2*y*z. + */ + MMUL(t4, Py, Pz), + MSET(Pz, t4), + MADD(Pz, t4), + + /* + * Compute y' = m*(s - x') - 8*y^4. Note that we already have + * 2*y^2 in t3. + */ + MSUB(t2, Px), + MMUL(Py, t1, t2), + MMUL(t4, t3, t3), + MSUB(Py, t4), + MSUB(Py, t4), + + ENDCODE +}; + +/* + * Addtions formulas are: + * + * u1 = x1 * z2^2 + * u2 = x2 * z1^2 + * s1 = y1 * z2^3 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 * z2 + * + * If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that + * z3 == 0, so the result is correct. + * If either of P1 or P2 is infinity, but not both, then z3 == 0, which is + * not correct. + * h == 0 only if u1 == u2; this happens in two cases: + * -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2 + * -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity) + * + * Thus, the following situations are not handled correctly: + * -- P1 = 0 and P2 != 0 + * -- P1 != 0 and P2 = 0 + * -- P1 = P2 + * All other cases are properly computed. However, even in "incorrect" + * situations, the three coordinates still are properly formed field + * elements. + * + * The returned flag is cleared if r == 0. This happens in the following + * cases: + * -- Both points are on the same horizontal line (same Y coordinate). + * -- Both points are infinity. + * -- One point is infinity and the other is on line Y = 0. + * The third case cannot happen with our curves (there is no valid point + * on line Y = 0 since that would be a point of order 2). If the two + * source points are non-infinity, then remains only the case where the + * two points are on the same horizontal line. + * + * This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and + * P2 != 0: + * -- If the returned value is not the point at infinity, then it was properly + * computed. + * -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result + * is indeed the point at infinity. + * -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should + * use the 'double' code. + * + * Cost: 16 multiplications + */ +static const uint16_t code_add[] = { + /* + * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). + */ + MMUL(t3, P2z, P2z), + MMUL(t1, P1x, t3), + MMUL(t4, P2z, t3), + MMUL(t3, P1y, t4), + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + MMUL(t4, P1z, P1z), + MMUL(t2, P2x, t4), + MMUL(t5, P1z, t4), + MMUL(t4, P2y, t5), + + /* + * Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4). + */ + MSUB(t2, t1), + MSUB(t4, t3), + + /* + * Report cases where r = 0 through the returned flag. + */ + MTZ(t4), + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5). + */ + MMUL(t7, t2, t2), + MMUL(t6, t1, t7), + MMUL(t5, t7, t2), + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + * t1 and t7 can be used as scratch registers. + */ + MMUL(P1x, t4, t4), + MSUB(P1x, t5), + MSUB(P1x, t6), + MSUB(P1x, t6), + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + MSUB(t6, P1x), + MMUL(P1y, t4, t6), + MMUL(t1, t5, t3), + MSUB(P1y, t1), + + /* + * Compute z3 = h*z1*z2. + */ + MMUL(t1, P1z, P2z), + MMUL(P1z, t1, t2), + + ENDCODE +}; + +/* + * Check that the point is on the curve. This code snippet assumes the + * following conventions: + * -- Coordinates x and y have been freshly decoded in P1 (but not + * converted to Montgomery coordinates yet). + * -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1. + */ +static const uint16_t code_check[] = { + + /* Convert x and y to Montgomery representation. */ + MMUL(t1, P1x, P2x), + MMUL(t2, P1y, P2x), + MSET(P1x, t1), + MSET(P1y, t2), + + /* Compute x^3 in t1. */ + MMUL(t2, P1x, P1x), + MMUL(t1, P1x, t2), + + /* Subtract 3*x from t1. */ + MSUB(t1, P1x), + MSUB(t1, P1x), + MSUB(t1, P1x), + + /* Add b. */ + MADD(t1, P2y), + + /* Compute y^2 in t2. */ + MMUL(t2, P1y, P1y), + + /* Compare y^2 with x^3 - 3*x + b; they must match. */ + MSUB(t1, t2), + MTZ(t1), + + /* Set z to 1 (in Montgomery representation). */ + MMUL(P1z, P2x, P2z), + + ENDCODE +}; + +/* + * Conversion back to affine coordinates. This code snippet assumes that + * the z coordinate of P2 is set to 1 (not in Montgomery representation). + */ +static const uint16_t code_affine[] = { + + /* Save z*R in t1. */ + MSET(t1, P1z), + + /* Compute z^3 in t2. */ + MMUL(t2, P1z, P1z), + MMUL(t3, P1z, t2), + MMUL(t2, t3, P2z), + + /* Invert to (1/z^3) in t2. */ + MINV(t2, t3, t4), + + /* Compute y. */ + MSET(t3, P1y), + MMUL(P1y, t2, t3), + + /* Compute (1/z^2) in t3. */ + MMUL(t3, t2, t1), + + /* Compute x. */ + MSET(t2, P1x), + MMUL(P1x, t2, t3), + + ENDCODE +}; + +static uint32_t +run_code(jacobian *P1, const jacobian *P2, + const curve_params *cc, const uint16_t *code) +{ + uint32_t r; + uint16_t t[13][I15_LEN]; + size_t u; + + r = 1; + + /* + * Copy the two operands in the dedicated registers. + */ + memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t)); + memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_t)); + + /* + * Run formulas. + */ + for (u = 0;; u ++) { + unsigned op, d, a, b; + + op = code[u]; + if (op == 0) { + break; + } + d = (op >> 8) & 0x0F; + a = (op >> 4) & 0x0F; + b = op & 0x0F; + op >>= 12; + switch (op) { + uint32_t ctl; + size_t plen; + unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3]; + + case 0: + memcpy(t[d], t[a], I15_LEN * sizeof(uint16_t)); + break; + case 1: + ctl = br_i15_add(t[d], t[a], 1); + ctl |= NOT(br_i15_sub(t[d], cc->p, 0)); + br_i15_sub(t[d], cc->p, ctl); + break; + case 2: + br_i15_add(t[d], cc->p, br_i15_sub(t[d], t[a], 1)); + break; + case 3: + br_i15_montymul(t[d], t[a], t[b], cc->p, cc->p0i); + break; + case 4: + plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3; + br_i15_encode(tp, plen, cc->p); + tp[plen - 1] -= 2; + br_i15_modpow(t[d], tp, plen, + cc->p, cc->p0i, t[a], t[b]); + break; + default: + r &= ~br_i15_iszero(t[d]); + break; + } + } + + /* + * Copy back result. + */ + memcpy(P1->c, t[P1x], 3 * I15_LEN * sizeof(uint16_t)); + return r; +} + +static void +set_one(uint16_t *x, const uint16_t *p) +{ + size_t plen; + + plen = (p[0] + 31) >> 4; + memset(x, 0, plen * sizeof *x); + x[0] = p[0]; + x[1] = 0x0001; +} + +static void +point_zero(jacobian *P, const curve_params *cc) +{ + memset(P, 0, sizeof *P); + P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0]; +} + +static inline void +point_double(jacobian *P, const curve_params *cc) +{ + run_code(P, P, cc, code_double); +} + +static inline uint32_t +point_add(jacobian *P1, const jacobian *P2, const curve_params *cc) +{ + return run_code(P1, P2, cc, code_add); +} + +static void +point_mul(jacobian *P, const unsigned char *x, size_t xlen, + const curve_params *cc) +{ + /* + * We do a simple double-and-add ladder with a 2-bit window + * to make only one add every two doublings. We thus first + * precompute 2P and 3P in some local buffers. + * + * We always perform two doublings and one addition; the + * addition is with P, 2P and 3P and is done in a temporary + * array. + * + * The addition code cannot handle cases where one of the + * operands is infinity, which is the case at the start of the + * ladder. We therefore need to maintain a flag that controls + * this situation. + */ + uint32_t qz; + jacobian P2, P3, Q, T, U; + + memcpy(&P2, P, sizeof P2); + point_double(&P2, cc); + memcpy(&P3, P, sizeof P3); + point_add(&P3, &P2, cc); + + point_zero(&Q, cc); + qz = 1; + while (xlen -- > 0) { + int k; + + for (k = 6; k >= 0; k -= 2) { + uint32_t bits; + uint32_t bnz; + + point_double(&Q, cc); + point_double(&Q, cc); + memcpy(&T, P, sizeof T); + memcpy(&U, &Q, sizeof U); + bits = (*x >> k) & (uint32_t)3; + bnz = NEQ(bits, 0); + CCOPY(EQ(bits, 2), &T, &P2, sizeof T); + CCOPY(EQ(bits, 3), &T, &P3, sizeof T); + point_add(&U, &T, cc); + CCOPY(bnz & qz, &Q, &T, sizeof Q); + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + } + x ++; + } + memcpy(P, &Q, sizeof Q); +} + +/* + * Decode point into Jacobian coordinates. This function does not support + * the point at infinity. If the point is invalid then this returns 0, but + * the coordinates are still set to properly formed field elements. + */ +static uint32_t +point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc) +{ + /* + * Points must use uncompressed format: + * -- first byte is 0x04; + * -- coordinates X and Y use unsigned big-endian, with the same + * length as the field modulus. + * + * We don't support hybrid format (uncompressed, but first byte + * has value 0x06 or 0x07, depending on the least significant bit + * of Y) because it is rather useless, and explicitly forbidden + * by PKIX (RFC 5480, section 2.2). + * + * We don't support compressed format either, because it is not + * much used in practice (there are or were patent-related + * concerns about point compression, which explains the lack of + * generalised support). Also, point compression support would + * need a bit more code. + */ + const unsigned char *buf; + size_t plen, zlen; + uint32_t r; + jacobian Q; + + buf = src; + point_zero(P, cc); + plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3; + if (len != 1 + (plen << 1)) { + return 0; + } + r = br_i15_decode_mod(P->c[0], buf + 1, plen, cc->p); + r &= br_i15_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p); + + /* + * Check first byte. + */ + r &= EQ(buf[0], 0x04); + /* obsolete + r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06) + & ~(uint32_t)(buf[0] ^ buf[plen << 1])); + */ + + /* + * Convert coordinates and check that the point is valid. + */ + zlen = ((cc->p[0] + 31) >> 4) * sizeof(uint16_t); + memcpy(Q.c[0], cc->R2, zlen); + memcpy(Q.c[1], cc->b, zlen); + set_one(Q.c[2], cc->p); + r &= ~run_code(P, &Q, cc, code_check); + return r; +} + +/* + * Encode a point. This method assumes that the point is correct and is + * not the point at infinity. Encoded size is always 1+2*plen, where + * plen is the field modulus length, in bytes. + */ +static void +point_encode(void *dst, const jacobian *P, const curve_params *cc) +{ + unsigned char *buf; + size_t plen; + jacobian Q, T; + + buf = dst; + plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3; + buf[0] = 0x04; + memcpy(&Q, P, sizeof *P); + set_one(T.c[2], cc->p); + run_code(&Q, &T, cc, code_affine); + br_i15_encode(buf + 1, plen, Q.c[0]); + br_i15_encode(buf + 1 + plen, plen, Q.c[1]); +} + +static const br_ec_curve_def * +id_to_curve_def(int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return &br_secp256r1; + case BR_EC_secp384r1: + return &br_secp384r1; + case BR_EC_secp521r1: + return &br_secp521r1; + } + return NULL; +} + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + const br_ec_curve_def *cd; + + cd = id_to_curve_def(curve); + *len = cd->generator_len; + return cd->generator; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + const br_ec_curve_def *cd; + + cd = id_to_curve_def(curve); + *len = cd->order_len; + return cd->order; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + api_generator(curve, len); + *len >>= 1; + return 1; +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *x, size_t xlen, int curve) +{ + uint32_t r; + const curve_params *cc; + jacobian P; + + cc = id_to_curve(curve); + r = point_decode(&P, G, Glen, cc); + point_mul(&P, x, xlen, cc); + if (Glen == cc->point_len) { + point_encode(G, &P, cc); + } + return r; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + uint32_t r, t, z; + const curve_params *cc; + jacobian P, Q; + + /* + * TODO: see about merging the two ladders. Right now, we do + * two independent point multiplications, which is a bit + * wasteful of CPU resources (but yields short code). + */ + + cc = id_to_curve(curve); + r = point_decode(&P, A, len, cc); + if (B == NULL) { + size_t Glen; + + B = api_generator(curve, &Glen); + } + r &= point_decode(&Q, B, len, cc); + point_mul(&P, x, xlen, cc); + point_mul(&Q, y, ylen, cc); + + /* + * We want to compute P+Q. Since the base points A and B are distinct + * from infinity, and the multipliers are non-zero and lower than the + * curve order, then we know that P and Q are non-infinity. This + * leaves two special situations to test for: + * -- If P = Q then we must use point_double(). + * -- If P+Q = 0 then we must report an error. + */ + t = point_add(&P, &Q, cc); + point_double(&Q, cc); + z = br_i15_iszero(P.c[2]); + + /* + * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we + * have the following: + * + * z = 0, t = 0 return P (normal addition) + * z = 0, t = 1 return P (normal addition) + * z = 1, t = 0 return Q (a 'double' case) + * z = 1, t = 1 report an error (P+Q = 0) + */ + CCOPY(z & ~t, &P, &Q, sizeof Q); + point_encode(A, &P, cc); + r &= ~(z & t); + + return r; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_prime_i15 = { + (uint32_t)0x03800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_prime_i31.c b/src/bearssl/src/ec/ec_prime_i31.c new file mode 100644 index 0000000..0586a3b --- /dev/null +++ b/src/bearssl/src/ec/ec_prime_i31.c @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Parameters for supported curves (field modulus, and 'b' equation + * parameter; both values use the 'i31' format, and 'b' is in Montgomery + * representation). + */ + +static const uint32_t P256_P[] = { + 0x00000108, + 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000007, + 0x00000000, 0x00000000, 0x00000040, 0x7FFFFF80, + 0x000000FF +}; + +static const uint32_t P256_R2[] = { + 0x00000108, + 0x00014000, 0x00018000, 0x00000000, 0x7FF40000, + 0x7FEFFFFF, 0x7FF7FFFF, 0x7FAFFFFF, 0x005FFFFF, + 0x00000000 +}; + +static const uint32_t P256_B[] = { + 0x00000108, + 0x6FEE1803, 0x6229C4BD, 0x21B139BE, 0x327150AA, + 0x3567802E, 0x3F7212ED, 0x012E4355, 0x782DD38D, + 0x0000000E +}; + +static const uint32_t P384_P[] = { + 0x0000018C, + 0x7FFFFFFF, 0x00000001, 0x00000000, 0x7FFFFFF8, + 0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, + 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, + 0x00000FFF +}; + +static const uint32_t P384_R2[] = { + 0x0000018C, + 0x00000000, 0x00000080, 0x7FFFFE00, 0x000001FF, + 0x00000800, 0x00000000, 0x7FFFE000, 0x00001FFF, + 0x00008000, 0x00008000, 0x00000000, 0x00000000, + 0x00000000 +}; + +static const uint32_t P384_B[] = { + 0x0000018C, + 0x6E666840, 0x070D0392, 0x5D810231, 0x7651D50C, + 0x17E218D6, 0x1B192002, 0x44EFE441, 0x3A524E2B, + 0x2719BA5F, 0x41F02209, 0x36C5643E, 0x5813EFFE, + 0x000008A5 +}; + +static const uint32_t P521_P[] = { + 0x00000219, + 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, + 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, + 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, + 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, + 0x01FFFFFF +}; + +static const uint32_t P521_R2[] = { + 0x00000219, + 0x00001000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000 +}; + +static const uint32_t P521_B[] = { + 0x00000219, + 0x540FC00A, 0x228FEA35, 0x2C34F1EF, 0x67BF107A, + 0x46FC1CD5, 0x1605E9DD, 0x6937B165, 0x272A3D8F, + 0x42785586, 0x44C8C778, 0x15F3B8B4, 0x64B73366, + 0x03BA8B69, 0x0D05B42A, 0x21F929A2, 0x2C31C393, + 0x00654FAE +}; + +typedef struct { + const uint32_t *p; + const uint32_t *b; + const uint32_t *R2; + uint32_t p0i; +} curve_params; + +static inline const curve_params * +id_to_curve(int curve) +{ + static const curve_params pp[] = { + { P256_P, P256_B, P256_R2, 0x00000001 }, + { P384_P, P384_B, P384_R2, 0x00000001 }, + { P521_P, P521_B, P521_R2, 0x00000001 } + }; + + return &pp[curve - BR_EC_secp256r1]; +} + +#define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31) + +/* + * Type for a point in Jacobian coordinates: + * -- three values, x, y and z, in Montgomery representation + * -- affine coordinates are X = x / z^2 and Y = y / z^3 + * -- for the point at infinity, z = 0 + */ +typedef struct { + uint32_t c[3][I31_LEN]; +} jacobian; + +/* + * We use a custom interpreter that uses a dozen registers, and + * only six operations: + * MSET(d, a) copy a into d + * MADD(d, a) d = d+a (modular) + * MSUB(d, a) d = d-a (modular) + * MMUL(d, a, b) d = a*b (Montgomery multiplication) + * MINV(d, a, b) invert d modulo p; a and b are used as scratch registers + * MTZ(d) clear return value if d = 0 + * Destination of MMUL (d) must be distinct from operands (a and b). + * There is no such constraint for MSUB and MADD. + * + * Registers include the operand coordinates, and temporaries. + */ +#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4)) +#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4)) +#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4)) +#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b)) +#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b)) +#define MTZ(d) (0x5000 + ((d) << 8)) +#define ENDCODE 0 + +/* + * Registers for the input operands. + */ +#define P1x 0 +#define P1y 1 +#define P1z 2 +#define P2x 3 +#define P2y 4 +#define P2z 5 + +/* + * Alternate names for the first input operand. + */ +#define Px 0 +#define Py 1 +#define Pz 2 + +/* + * Temporaries. + */ +#define t1 6 +#define t2 7 +#define t3 8 +#define t4 9 +#define t5 10 +#define t6 11 +#define t7 12 + +/* + * Extra scratch registers available when there is no second operand (e.g. + * for "double" and "affine"). + */ +#define t8 3 +#define t9 4 +#define t10 5 + +/* + * Doubling formulas are: + * + * s = 4*x*y^2 + * m = 3*(x + z^2)*(x - z^2) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y^4 + * z' = 2*y*z + * + * If y = 0 (P has order 2) then this yields infinity (z' = 0), as it + * should. This case should not happen anyway, because our curves have + * prime order, and thus do not contain any point of order 2. + * + * If P is infinity (z = 0), then again the formulas yield infinity, + * which is correct. Thus, this code works for all points. + * + * Cost: 8 multiplications + */ +static const uint16_t code_double[] = { + /* + * Compute z^2 (in t1). + */ + MMUL(t1, Pz, Pz), + + /* + * Compute x-z^2 (in t2) and then x+z^2 (in t1). + */ + MSET(t2, Px), + MSUB(t2, t1), + MADD(t1, Px), + + /* + * Compute m = 3*(x+z^2)*(x-z^2) (in t1). + */ + MMUL(t3, t1, t2), + MSET(t1, t3), + MADD(t1, t3), + MADD(t1, t3), + + /* + * Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3). + */ + MMUL(t3, Py, Py), + MADD(t3, t3), + MMUL(t2, Px, t3), + MADD(t2, t2), + + /* + * Compute x' = m^2 - 2*s. + */ + MMUL(Px, t1, t1), + MSUB(Px, t2), + MSUB(Px, t2), + + /* + * Compute z' = 2*y*z. + */ + MMUL(t4, Py, Pz), + MSET(Pz, t4), + MADD(Pz, t4), + + /* + * Compute y' = m*(s - x') - 8*y^4. Note that we already have + * 2*y^2 in t3. + */ + MSUB(t2, Px), + MMUL(Py, t1, t2), + MMUL(t4, t3, t3), + MSUB(Py, t4), + MSUB(Py, t4), + + ENDCODE +}; + +/* + * Addtions formulas are: + * + * u1 = x1 * z2^2 + * u2 = x2 * z1^2 + * s1 = y1 * z2^3 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 * z2 + * + * If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that + * z3 == 0, so the result is correct. + * If either of P1 or P2 is infinity, but not both, then z3 == 0, which is + * not correct. + * h == 0 only if u1 == u2; this happens in two cases: + * -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2 + * -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity) + * + * Thus, the following situations are not handled correctly: + * -- P1 = 0 and P2 != 0 + * -- P1 != 0 and P2 = 0 + * -- P1 = P2 + * All other cases are properly computed. However, even in "incorrect" + * situations, the three coordinates still are properly formed field + * elements. + * + * The returned flag is cleared if r == 0. This happens in the following + * cases: + * -- Both points are on the same horizontal line (same Y coordinate). + * -- Both points are infinity. + * -- One point is infinity and the other is on line Y = 0. + * The third case cannot happen with our curves (there is no valid point + * on line Y = 0 since that would be a point of order 2). If the two + * source points are non-infinity, then remains only the case where the + * two points are on the same horizontal line. + * + * This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and + * P2 != 0: + * -- If the returned value is not the point at infinity, then it was properly + * computed. + * -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result + * is indeed the point at infinity. + * -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should + * use the 'double' code. + * + * Cost: 16 multiplications + */ +static const uint16_t code_add[] = { + /* + * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). + */ + MMUL(t3, P2z, P2z), + MMUL(t1, P1x, t3), + MMUL(t4, P2z, t3), + MMUL(t3, P1y, t4), + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + MMUL(t4, P1z, P1z), + MMUL(t2, P2x, t4), + MMUL(t5, P1z, t4), + MMUL(t4, P2y, t5), + + /* + * Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4). + */ + MSUB(t2, t1), + MSUB(t4, t3), + + /* + * Report cases where r = 0 through the returned flag. + */ + MTZ(t4), + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5). + */ + MMUL(t7, t2, t2), + MMUL(t6, t1, t7), + MMUL(t5, t7, t2), + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + * t1 and t7 can be used as scratch registers. + */ + MMUL(P1x, t4, t4), + MSUB(P1x, t5), + MSUB(P1x, t6), + MSUB(P1x, t6), + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + MSUB(t6, P1x), + MMUL(P1y, t4, t6), + MMUL(t1, t5, t3), + MSUB(P1y, t1), + + /* + * Compute z3 = h*z1*z2. + */ + MMUL(t1, P1z, P2z), + MMUL(P1z, t1, t2), + + ENDCODE +}; + +/* + * Check that the point is on the curve. This code snippet assumes the + * following conventions: + * -- Coordinates x and y have been freshly decoded in P1 (but not + * converted to Montgomery coordinates yet). + * -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1. + */ +static const uint16_t code_check[] = { + + /* Convert x and y to Montgomery representation. */ + MMUL(t1, P1x, P2x), + MMUL(t2, P1y, P2x), + MSET(P1x, t1), + MSET(P1y, t2), + + /* Compute x^3 in t1. */ + MMUL(t2, P1x, P1x), + MMUL(t1, P1x, t2), + + /* Subtract 3*x from t1. */ + MSUB(t1, P1x), + MSUB(t1, P1x), + MSUB(t1, P1x), + + /* Add b. */ + MADD(t1, P2y), + + /* Compute y^2 in t2. */ + MMUL(t2, P1y, P1y), + + /* Compare y^2 with x^3 - 3*x + b; they must match. */ + MSUB(t1, t2), + MTZ(t1), + + /* Set z to 1 (in Montgomery representation). */ + MMUL(P1z, P2x, P2z), + + ENDCODE +}; + +/* + * Conversion back to affine coordinates. This code snippet assumes that + * the z coordinate of P2 is set to 1 (not in Montgomery representation). + */ +static const uint16_t code_affine[] = { + + /* Save z*R in t1. */ + MSET(t1, P1z), + + /* Compute z^3 in t2. */ + MMUL(t2, P1z, P1z), + MMUL(t3, P1z, t2), + MMUL(t2, t3, P2z), + + /* Invert to (1/z^3) in t2. */ + MINV(t2, t3, t4), + + /* Compute y. */ + MSET(t3, P1y), + MMUL(P1y, t2, t3), + + /* Compute (1/z^2) in t3. */ + MMUL(t3, t2, t1), + + /* Compute x. */ + MSET(t2, P1x), + MMUL(P1x, t2, t3), + + ENDCODE +}; + +static uint32_t +run_code(jacobian *P1, const jacobian *P2, + const curve_params *cc, const uint16_t *code) +{ + uint32_t r; + uint32_t t[13][I31_LEN]; + size_t u; + + r = 1; + + /* + * Copy the two operands in the dedicated registers. + */ + memcpy(t[P1x], P1->c, 3 * I31_LEN * sizeof(uint32_t)); + memcpy(t[P2x], P2->c, 3 * I31_LEN * sizeof(uint32_t)); + + /* + * Run formulas. + */ + for (u = 0;; u ++) { + unsigned op, d, a, b; + + op = code[u]; + if (op == 0) { + break; + } + d = (op >> 8) & 0x0F; + a = (op >> 4) & 0x0F; + b = op & 0x0F; + op >>= 12; + switch (op) { + uint32_t ctl; + size_t plen; + unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3]; + + case 0: + memcpy(t[d], t[a], I31_LEN * sizeof(uint32_t)); + break; + case 1: + ctl = br_i31_add(t[d], t[a], 1); + ctl |= NOT(br_i31_sub(t[d], cc->p, 0)); + br_i31_sub(t[d], cc->p, ctl); + break; + case 2: + br_i31_add(t[d], cc->p, br_i31_sub(t[d], t[a], 1)); + break; + case 3: + br_i31_montymul(t[d], t[a], t[b], cc->p, cc->p0i); + break; + case 4: + plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3; + br_i31_encode(tp, plen, cc->p); + tp[plen - 1] -= 2; + br_i31_modpow(t[d], tp, plen, + cc->p, cc->p0i, t[a], t[b]); + break; + default: + r &= ~br_i31_iszero(t[d]); + break; + } + } + + /* + * Copy back result. + */ + memcpy(P1->c, t[P1x], 3 * I31_LEN * sizeof(uint32_t)); + return r; +} + +static void +set_one(uint32_t *x, const uint32_t *p) +{ + size_t plen; + + plen = (p[0] + 63) >> 5; + memset(x, 0, plen * sizeof *x); + x[0] = p[0]; + x[1] = 0x00000001; +} + +static void +point_zero(jacobian *P, const curve_params *cc) +{ + memset(P, 0, sizeof *P); + P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0]; +} + +static inline void +point_double(jacobian *P, const curve_params *cc) +{ + run_code(P, P, cc, code_double); +} + +static inline uint32_t +point_add(jacobian *P1, const jacobian *P2, const curve_params *cc) +{ + return run_code(P1, P2, cc, code_add); +} + +static void +point_mul(jacobian *P, const unsigned char *x, size_t xlen, + const curve_params *cc) +{ + /* + * We do a simple double-and-add ladder with a 2-bit window + * to make only one add every two doublings. We thus first + * precompute 2P and 3P in some local buffers. + * + * We always perform two doublings and one addition; the + * addition is with P, 2P and 3P and is done in a temporary + * array. + * + * The addition code cannot handle cases where one of the + * operands is infinity, which is the case at the start of the + * ladder. We therefore need to maintain a flag that controls + * this situation. + */ + uint32_t qz; + jacobian P2, P3, Q, T, U; + + memcpy(&P2, P, sizeof P2); + point_double(&P2, cc); + memcpy(&P3, P, sizeof P3); + point_add(&P3, &P2, cc); + + point_zero(&Q, cc); + qz = 1; + while (xlen -- > 0) { + int k; + + for (k = 6; k >= 0; k -= 2) { + uint32_t bits; + uint32_t bnz; + + point_double(&Q, cc); + point_double(&Q, cc); + memcpy(&T, P, sizeof T); + memcpy(&U, &Q, sizeof U); + bits = (*x >> k) & (uint32_t)3; + bnz = NEQ(bits, 0); + CCOPY(EQ(bits, 2), &T, &P2, sizeof T); + CCOPY(EQ(bits, 3), &T, &P3, sizeof T); + point_add(&U, &T, cc); + CCOPY(bnz & qz, &Q, &T, sizeof Q); + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + } + x ++; + } + memcpy(P, &Q, sizeof Q); +} + +/* + * Decode point into Jacobian coordinates. This function does not support + * the point at infinity. If the point is invalid then this returns 0, but + * the coordinates are still set to properly formed field elements. + */ +static uint32_t +point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc) +{ + /* + * Points must use uncompressed format: + * -- first byte is 0x04; + * -- coordinates X and Y use unsigned big-endian, with the same + * length as the field modulus. + * + * We don't support hybrid format (uncompressed, but first byte + * has value 0x06 or 0x07, depending on the least significant bit + * of Y) because it is rather useless, and explicitly forbidden + * by PKIX (RFC 5480, section 2.2). + * + * We don't support compressed format either, because it is not + * much used in practice (there are or were patent-related + * concerns about point compression, which explains the lack of + * generalised support). Also, point compression support would + * need a bit more code. + */ + const unsigned char *buf; + size_t plen, zlen; + uint32_t r; + jacobian Q; + + buf = src; + point_zero(P, cc); + plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3; + if (len != 1 + (plen << 1)) { + return 0; + } + r = br_i31_decode_mod(P->c[0], buf + 1, plen, cc->p); + r &= br_i31_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p); + + /* + * Check first byte. + */ + r &= EQ(buf[0], 0x04); + /* obsolete + r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06) + & ~(uint32_t)(buf[0] ^ buf[plen << 1])); + */ + + /* + * Convert coordinates and check that the point is valid. + */ + zlen = ((cc->p[0] + 63) >> 5) * sizeof(uint32_t); + memcpy(Q.c[0], cc->R2, zlen); + memcpy(Q.c[1], cc->b, zlen); + set_one(Q.c[2], cc->p); + r &= ~run_code(P, &Q, cc, code_check); + return r; +} + +/* + * Encode a point. This method assumes that the point is correct and is + * not the point at infinity. Encoded size is always 1+2*plen, where + * plen is the field modulus length, in bytes. + */ +static void +point_encode(void *dst, const jacobian *P, const curve_params *cc) +{ + unsigned char *buf; + uint32_t xbl; + size_t plen; + jacobian Q, T; + + buf = dst; + xbl = cc->p[0]; + xbl -= (xbl >> 5); + plen = (xbl + 7) >> 3; + buf[0] = 0x04; + memcpy(&Q, P, sizeof *P); + set_one(T.c[2], cc->p); + run_code(&Q, &T, cc, code_affine); + br_i31_encode(buf + 1, plen, Q.c[0]); + br_i31_encode(buf + 1 + plen, plen, Q.c[1]); +} + +static const br_ec_curve_def * +id_to_curve_def(int curve) +{ + switch (curve) { + case BR_EC_secp256r1: + return &br_secp256r1; + case BR_EC_secp384r1: + return &br_secp384r1; + case BR_EC_secp521r1: + return &br_secp521r1; + } + return NULL; +} + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + const br_ec_curve_def *cd; + + cd = id_to_curve_def(curve); + *len = cd->generator_len; + return cd->generator; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + const br_ec_curve_def *cd; + + cd = id_to_curve_def(curve); + *len = cd->order_len; + return cd->order; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + api_generator(curve, len); + *len >>= 1; + return 1; +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *x, size_t xlen, int curve) +{ + uint32_t r; + const curve_params *cc; + jacobian P; + + cc = id_to_curve(curve); + r = point_decode(&P, G, Glen, cc); + point_mul(&P, x, xlen, cc); + point_encode(G, &P, cc); + return r; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + uint32_t r, t, z; + const curve_params *cc; + jacobian P, Q; + + /* + * TODO: see about merging the two ladders. Right now, we do + * two independent point multiplications, which is a bit + * wasteful of CPU resources (but yields short code). + */ + + cc = id_to_curve(curve); + r = point_decode(&P, A, len, cc); + if (B == NULL) { + size_t Glen; + + B = api_generator(curve, &Glen); + } + r &= point_decode(&Q, B, len, cc); + point_mul(&P, x, xlen, cc); + point_mul(&Q, y, ylen, cc); + + /* + * We want to compute P+Q. Since the base points A and B are distinct + * from infinity, and the multipliers are non-zero and lower than the + * curve order, then we know that P and Q are non-infinity. This + * leaves two special situations to test for: + * -- If P = Q then we must use point_double(). + * -- If P+Q = 0 then we must report an error. + */ + t = point_add(&P, &Q, cc); + point_double(&Q, cc); + z = br_i31_iszero(P.c[2]); + + /* + * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we + * have the following: + * + * z = 0, t = 0 return P (normal addition) + * z = 0, t = 1 return P (normal addition) + * z = 1, t = 0 return Q (a 'double' case) + * z = 1, t = 1 report an error (P+Q = 0) + */ + CCOPY(z & ~t, &P, &Q, sizeof Q); + point_encode(A, &P, cc); + r &= ~(z & t); + + return r; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_prime_i31 = { + (uint32_t)0x03800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; diff --git a/src/bearssl/src/ec/ec_pubkey.c b/src/bearssl/src/ec/ec_pubkey.c new file mode 100644 index 0000000..383ff28 --- /dev/null +++ b/src/bearssl/src/ec/ec_pubkey.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char POINT_LEN[] = { + 0, /* 0: not a valid curve ID */ + 43, /* sect163k1 */ + 43, /* sect163r1 */ + 43, /* sect163r2 */ + 51, /* sect193r1 */ + 51, /* sect193r2 */ + 61, /* sect233k1 */ + 61, /* sect233r1 */ + 61, /* sect239k1 */ + 73, /* sect283k1 */ + 73, /* sect283r1 */ + 105, /* sect409k1 */ + 105, /* sect409r1 */ + 145, /* sect571k1 */ + 145, /* sect571r1 */ + 41, /* secp160k1 */ + 41, /* secp160r1 */ + 41, /* secp160r2 */ + 49, /* secp192k1 */ + 49, /* secp192r1 */ + 57, /* secp224k1 */ + 57, /* secp224r1 */ + 65, /* secp256k1 */ + 65, /* secp256r1 */ + 97, /* secp384r1 */ + 133, /* secp521r1 */ + 65, /* brainpoolP256r1 */ + 97, /* brainpoolP384r1 */ + 129, /* brainpoolP512r1 */ + 32, /* curve25519 */ + 56, /* curve448 */ +}; + +/* see bearssl_ec.h */ +size_t +br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk, + void *kbuf, const br_ec_private_key *sk) +{ + int curve; + size_t len; + + curve = sk->curve; + if (curve < 0 || curve >= 32 || curve >= (int)(sizeof POINT_LEN) + || ((impl->supported_curves >> curve) & 1) == 0) + { + return 0; + } + if (kbuf == NULL) { + return POINT_LEN[curve]; + } + len = impl->mulgen(kbuf, sk->x, sk->xlen, curve); + if (pk != NULL) { + pk->curve = curve; + pk->q = kbuf; + pk->qlen = len; + } + return len; +} diff --git a/src/bearssl/src/ec/ec_secp256r1.c b/src/bearssl/src/ec/ec_secp256r1.c new file mode 100644 index 0000000..a9d6c45 --- /dev/null +++ b/src/bearssl/src/ec/ec_secp256r1.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char P256_N[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 +}; + +static const unsigned char P256_G[] = { + 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, + 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, + 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, + 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, + 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, + 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, + 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, + 0xF5 +}; + +/* see inner.h */ +const br_ec_curve_def br_secp256r1 = { + BR_EC_secp256r1, + P256_N, sizeof P256_N, + P256_G, sizeof P256_G +}; diff --git a/src/bearssl/src/ec/ec_secp384r1.c b/src/bearssl/src/ec/ec_secp384r1.c new file mode 100644 index 0000000..693d93e --- /dev/null +++ b/src/bearssl/src/ec/ec_secp384r1.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char P384_N[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, + 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, + 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73 +}; + +static const unsigned char P384_G[] = { + 0x04, 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, + 0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, + 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, + 0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, + 0x38, 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, + 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, + 0xB7, 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, + 0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, + 0x29, 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, + 0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, + 0xC0, 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, + 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, + 0x5F +}; + +/* see inner.h */ +const br_ec_curve_def br_secp384r1 = { + BR_EC_secp384r1, + P384_N, sizeof P384_N, + P384_G, sizeof P384_G +}; diff --git a/src/bearssl/src/ec/ec_secp521r1.c b/src/bearssl/src/ec/ec_secp521r1.c new file mode 100644 index 0000000..161acd0 --- /dev/null +++ b/src/bearssl/src/ec/ec_secp521r1.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char P521_N[] = { + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F, + 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09, + 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, + 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38, + 0x64, 0x09 +}; + +static const unsigned char P521_G[] = { + 0x04, 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, + 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23, + 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, + 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, + 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF, + 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, + 0xFF, 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, + 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2, + 0xE5, 0xBD, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6A, + 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F, + 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44, + 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD, + 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, 0x72, + 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, + 0x01, 0x3F, 0xAD, 0x07, 0x61, 0x35, 0x3C, 0x70, + 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94, + 0x76, 0x9F, 0xD1, 0x66, 0x50 +}; + +/* see inner.h */ +const br_ec_curve_def br_secp521r1 = { + BR_EC_secp521r1, + P521_N, sizeof P521_N, + P521_G, sizeof P521_G +}; diff --git a/src/bearssl/src/ec/ecdsa_atr.c b/src/bearssl/src/ec/ecdsa_atr.c new file mode 100644 index 0000000..3a11226 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_atr.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ec.h */ +size_t +br_ecdsa_asn1_to_raw(void *sig, size_t sig_len) +{ + /* + * Note: this code is a bit lenient in that it accepts a few + * deviations to DER with regards to minimality of encoding of + * lengths and integer values. These deviations are still + * unambiguous. + * + * Signature format is a SEQUENCE of two INTEGER values. We + * support only integers of less than 127 bytes each (signed + * encoding) so the resulting raw signature will have length + * at most 254 bytes. + */ + + unsigned char *buf, *r, *s; + size_t zlen, rlen, slen, off; + unsigned char tmp[254]; + + buf = sig; + if (sig_len < 8) { + return 0; + } + + /* + * First byte is SEQUENCE tag. + */ + if (buf[0] != 0x30) { + return 0; + } + + /* + * The SEQUENCE length will be encoded over one or two bytes. We + * limit the total SEQUENCE contents to 255 bytes, because it + * makes things simpler; this is enough for subgroup orders up + * to 999 bits. + */ + zlen = buf[1]; + if (zlen > 0x80) { + if (zlen != 0x81) { + return 0; + } + zlen = buf[2]; + if (zlen != sig_len - 3) { + return 0; + } + off = 3; + } else { + if (zlen != sig_len - 2) { + return 0; + } + off = 2; + } + + /* + * First INTEGER (r). + */ + if (buf[off ++] != 0x02) { + return 0; + } + rlen = buf[off ++]; + if (rlen >= 0x80) { + return 0; + } + r = buf + off; + off += rlen; + + /* + * Second INTEGER (s). + */ + if (off + 2 > sig_len) { + return 0; + } + if (buf[off ++] != 0x02) { + return 0; + } + slen = buf[off ++]; + if (slen >= 0x80 || slen != sig_len - off) { + return 0; + } + s = buf + off; + + /* + * Removing leading zeros from r and s. + */ + while (rlen > 0 && *r == 0) { + rlen --; + r ++; + } + while (slen > 0 && *s == 0) { + slen --; + s ++; + } + + /* + * Compute common length for the two integers, then copy integers + * into the temporary buffer, and finally copy it back over the + * signature buffer. + */ + zlen = rlen > slen ? rlen : slen; + sig_len = zlen << 1; + memset(tmp, 0, sig_len); + memcpy(tmp + zlen - rlen, r, rlen); + memcpy(tmp + sig_len - slen, s, slen); + memcpy(sig, tmp, sig_len); + return sig_len; +} diff --git a/src/bearssl/src/ec/ecdsa_default_sign_asn1.c b/src/bearssl/src/ec/ecdsa_default_sign_asn1.c new file mode 100644 index 0000000..afbf8ac --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_default_sign_asn1.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ec.h */ +br_ecdsa_sign +br_ecdsa_sign_asn1_get_default(void) +{ +#if BR_LOMUL + return &br_ecdsa_i15_sign_asn1; +#else + return &br_ecdsa_i31_sign_asn1; +#endif +} diff --git a/src/bearssl/src/ec/ecdsa_default_sign_raw.c b/src/bearssl/src/ec/ecdsa_default_sign_raw.c new file mode 100644 index 0000000..287c970 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_default_sign_raw.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ec.h */ +br_ecdsa_sign +br_ecdsa_sign_raw_get_default(void) +{ +#if BR_LOMUL + return &br_ecdsa_i15_sign_raw; +#else + return &br_ecdsa_i31_sign_raw; +#endif +} diff --git a/src/bearssl/src/ec/ecdsa_default_vrfy_asn1.c b/src/bearssl/src/ec/ecdsa_default_vrfy_asn1.c new file mode 100644 index 0000000..fe0996e --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_default_vrfy_asn1.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ec.h */ +br_ecdsa_vrfy +br_ecdsa_vrfy_asn1_get_default(void) +{ +#if BR_LOMUL + return &br_ecdsa_i15_vrfy_asn1; +#else + return &br_ecdsa_i31_vrfy_asn1; +#endif +} diff --git a/src/bearssl/src/ec/ecdsa_default_vrfy_raw.c b/src/bearssl/src/ec/ecdsa_default_vrfy_raw.c new file mode 100644 index 0000000..e564a10 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_default_vrfy_raw.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ec.h */ +br_ecdsa_vrfy +br_ecdsa_vrfy_raw_get_default(void) +{ +#if BR_LOMUL + return &br_ecdsa_i15_vrfy_raw; +#else + return &br_ecdsa_i31_vrfy_raw; +#endif +} diff --git a/src/bearssl/src/ec/ecdsa_i15_bits.c b/src/bearssl/src/ec/ecdsa_i15_bits.c new file mode 100644 index 0000000..402d14a --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i15_bits.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_ecdsa_i15_bits2int(uint16_t *x, + const void *src, size_t len, uint32_t ebitlen) +{ + uint32_t bitlen, hbitlen; + int sc; + + bitlen = ebitlen - (ebitlen >> 4); + hbitlen = (uint32_t)len << 3; + if (hbitlen > bitlen) { + len = (bitlen + 7) >> 3; + sc = (int)((hbitlen - bitlen) & 7); + } else { + sc = 0; + } + br_i15_zero(x, ebitlen); + br_i15_decode(x, src, len); + br_i15_rshift(x, sc); + x[0] = ebitlen; +} diff --git a/src/bearssl/src/ec/ecdsa_i15_sign_asn1.c b/src/bearssl/src/ec/ecdsa_i15_sign_asn1.c new file mode 100644 index 0000000..ab4a283 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i15_sign_asn1.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3) + +/* see bearssl_ec.h */ +size_t +br_ecdsa_i15_sign_asn1(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig) +{ + unsigned char rsig[(ORDER_LEN << 1) + 12]; + size_t sig_len; + + sig_len = br_ecdsa_i15_sign_raw(impl, hf, hash_value, sk, rsig); + if (sig_len == 0) { + return 0; + } + sig_len = br_ecdsa_raw_to_asn1(rsig, sig_len); + memcpy(sig, rsig, sig_len); + return sig_len; +} diff --git a/src/bearssl/src/ec/ecdsa_i15_sign_raw.c b/src/bearssl/src/ec/ecdsa_i15_sign_raw.c new file mode 100644 index 0000000..39b2e1d --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i15_sign_raw.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15) +#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1)) +#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3) + +/* see bearssl_ec.h */ +size_t +br_ecdsa_i15_sign_raw(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig) +{ + /* + * IMPORTANT: this code is fit only for curves with a prime + * order. This is needed so that modular reduction of the X + * coordinate of a point can be done with a simple subtraction. + * We also rely on the last byte of the curve order to be distinct + * from 0 and 1. + */ + const br_ec_curve_def *cd; + uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], x[I15_LEN]; + uint16_t m[I15_LEN], k[I15_LEN], t1[I15_LEN], t2[I15_LEN]; + unsigned char tt[ORDER_LEN << 1]; + unsigned char eU[POINT_LEN]; + size_t hash_len, nlen, ulen; + uint16_t n0i; + uint32_t ctl; + br_hmac_drbg_context drbg; + + /* + * If the curve is not supported, then exit with an error. + */ + if (((impl->supported_curves >> sk->curve) & 1) == 0) { + return 0; + } + + /* + * Get the curve parameters (generator and order). + */ + switch (sk->curve) { + case BR_EC_secp256r1: + cd = &br_secp256r1; + break; + case BR_EC_secp384r1: + cd = &br_secp384r1; + break; + case BR_EC_secp521r1: + cd = &br_secp521r1; + break; + default: + return 0; + } + + /* + * Get modulus. + */ + nlen = cd->order_len; + br_i15_decode(n, cd->order, nlen); + n0i = br_i15_ninv15(n[1]); + + /* + * Get private key as an i15 integer. This also checks that the + * private key is well-defined (not zero, and less than the + * curve order). + */ + if (!br_i15_decode_mod(x, sk->x, sk->xlen, n)) { + return 0; + } + if (br_i15_iszero(x)) { + return 0; + } + + /* + * Get hash length. + */ + hash_len = (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + + /* + * Truncate and reduce the hash value modulo the curve order. + */ + br_ecdsa_i15_bits2int(m, hash_value, hash_len, n[0]); + br_i15_sub(m, n, br_i15_sub(m, n, 0) ^ 1); + + /* + * RFC 6979 generation of the "k" value. + * + * The process uses HMAC_DRBG (with the hash function used to + * process the message that is to be signed). The seed is the + * concatenation of the encodings of the private key and + * the hash value (after truncation and modular reduction). + */ + br_i15_encode(tt, nlen, x); + br_i15_encode(tt + nlen, nlen, m); + br_hmac_drbg_init(&drbg, hf, tt, nlen << 1); + for (;;) { + br_hmac_drbg_generate(&drbg, tt, nlen); + br_ecdsa_i15_bits2int(k, tt, nlen, n[0]); + if (br_i15_iszero(k)) { + continue; + } + if (br_i15_sub(k, n, 0)) { + break; + } + } + + /* + * Compute k*G and extract the X coordinate, then reduce it + * modulo the curve order. Since we support only curves with + * prime order, that reduction is only a matter of computing + * a subtraction. + */ + br_i15_encode(tt, nlen, k); + ulen = impl->mulgen(eU, tt, nlen, sk->curve); + br_i15_zero(r, n[0]); + br_i15_decode(r, &eU[1], ulen >> 1); + r[0] = n[0]; + br_i15_sub(r, n, br_i15_sub(r, n, 0) ^ 1); + + /* + * Compute 1/k in double-Montgomery representation. We do so by + * first converting _from_ Montgomery representation (twice), + * then using a modular exponentiation. + */ + br_i15_from_monty(k, n, n0i); + br_i15_from_monty(k, n, n0i); + memcpy(tt, cd->order, nlen); + tt[nlen - 1] -= 2; + br_i15_modpow(k, tt, nlen, n, n0i, t1, t2); + + /* + * Compute s = (m+xr)/k (mod n). + * The k[] array contains R^2/k (double-Montgomery representation); + * we thus can use direct Montgomery multiplications and conversions + * from Montgomery, avoiding any call to br_i15_to_monty() (which + * is slower). + */ + br_i15_from_monty(m, n, n0i); + br_i15_montymul(t1, x, r, n, n0i); + ctl = br_i15_add(t1, m, 1); + ctl |= br_i15_sub(t1, n, 0) ^ 1; + br_i15_sub(t1, n, ctl); + br_i15_montymul(s, t1, k, n, n0i); + + /* + * Encode r and s in the signature. + */ + br_i15_encode(sig, nlen, r); + br_i15_encode((unsigned char *)sig + nlen, nlen, s); + return nlen << 1; +} diff --git a/src/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c b/src/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c new file mode 100644 index 0000000..f4bef99 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define FIELD_LEN ((BR_MAX_EC_SIZE + 7) >> 3) + +/* see bearssl_ec.h */ +uint32_t +br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, + const void *sig, size_t sig_len) +{ + /* + * We use a double-sized buffer because a malformed ASN.1 signature + * may trigger a size expansion when converting to "raw" format. + */ + unsigned char rsig[(FIELD_LEN << 2) + 24]; + + if (sig_len > ((sizeof rsig) >> 1)) { + return 0; + } + memcpy(rsig, sig, sig_len); + sig_len = br_ecdsa_asn1_to_raw(rsig, sig_len); + return br_ecdsa_i15_vrfy_raw(impl, hash, hash_len, pk, rsig, sig_len); +} diff --git a/src/bearssl/src/ec/ecdsa_i15_vrfy_raw.c b/src/bearssl/src/ec/ecdsa_i15_vrfy_raw.c new file mode 100644 index 0000000..14dd5e4 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i15_vrfy_raw.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15) +#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1)) + +/* see bearssl_ec.h */ +uint32_t +br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, + const void *sig, size_t sig_len) +{ + /* + * IMPORTANT: this code is fit only for curves with a prime + * order. This is needed so that modular reduction of the X + * coordinate of a point can be done with a simple subtraction. + */ + const br_ec_curve_def *cd; + uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], t1[I15_LEN], t2[I15_LEN]; + unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3]; + unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3]; + unsigned char eU[POINT_LEN]; + size_t nlen, rlen, ulen; + uint16_t n0i; + uint32_t res; + + /* + * If the curve is not supported, then report an error. + */ + if (((impl->supported_curves >> pk->curve) & 1) == 0) { + return 0; + } + + /* + * Get the curve parameters (generator and order). + */ + switch (pk->curve) { + case BR_EC_secp256r1: + cd = &br_secp256r1; + break; + case BR_EC_secp384r1: + cd = &br_secp384r1; + break; + case BR_EC_secp521r1: + cd = &br_secp521r1; + break; + default: + return 0; + } + + /* + * Signature length must be even. + */ + if (sig_len & 1) { + return 0; + } + rlen = sig_len >> 1; + + /* + * Public key point must have the proper size for this curve. + */ + if (pk->qlen != cd->generator_len) { + return 0; + } + + /* + * Get modulus; then decode the r and s values. They must be + * lower than the modulus, and s must not be null. + */ + nlen = cd->order_len; + br_i15_decode(n, cd->order, nlen); + n0i = br_i15_ninv15(n[1]); + if (!br_i15_decode_mod(r, sig, rlen, n)) { + return 0; + } + if (!br_i15_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) { + return 0; + } + if (br_i15_iszero(s)) { + return 0; + } + + /* + * Invert s. We do that with a modular exponentiation; we use + * the fact that for all the curves we support, the least + * significant byte is not 0 or 1, so we can subtract 2 without + * any carry to process. + * We also want 1/s in Montgomery representation, which can be + * done by converting _from_ Montgomery representation before + * the inversion (because (1/s)*R = 1/(s/R)). + */ + br_i15_from_monty(s, n, n0i); + memcpy(tx, cd->order, nlen); + tx[nlen - 1] -= 2; + br_i15_modpow(s, tx, nlen, n, n0i, t1, t2); + + /* + * Truncate the hash to the modulus length (in bits) and reduce + * it modulo the curve order. The modular reduction can be done + * with a subtraction since the truncation already reduced the + * value to the modulus bit length. + */ + br_ecdsa_i15_bits2int(t1, hash, hash_len, n[0]); + br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1); + + /* + * Multiply the (truncated, reduced) hash value with 1/s, result in + * t2, encoded in ty. + */ + br_i15_montymul(t2, t1, s, n, n0i); + br_i15_encode(ty, nlen, t2); + + /* + * Multiply r with 1/s, result in t1, encoded in tx. + */ + br_i15_montymul(t1, r, s, n, n0i); + br_i15_encode(tx, nlen, t1); + + /* + * Compute the point x*Q + y*G. + */ + ulen = cd->generator_len; + memcpy(eU, pk->q, ulen); + res = impl->muladd(eU, NULL, ulen, + tx, nlen, ty, nlen, cd->curve); + + /* + * Get the X coordinate, reduce modulo the curve order, and + * compare with the 'r' value. + * + * The modular reduction can be done with subtractions because + * we work with curves of prime order, so the curve order is + * close to the field order (Hasse's theorem). + */ + br_i15_zero(t1, n[0]); + br_i15_decode(t1, &eU[1], ulen >> 1); + t1[0] = n[0]; + br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1); + res &= ~br_i15_sub(t1, r, 1); + res &= br_i15_iszero(t1); + return res; +} diff --git a/src/bearssl/src/ec/ecdsa_i31_bits.c b/src/bearssl/src/ec/ecdsa_i31_bits.c new file mode 100644 index 0000000..9a8d673 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i31_bits.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_ecdsa_i31_bits2int(uint32_t *x, + const void *src, size_t len, uint32_t ebitlen) +{ + uint32_t bitlen, hbitlen; + int sc; + + bitlen = ebitlen - (ebitlen >> 5); + hbitlen = (uint32_t)len << 3; + if (hbitlen > bitlen) { + len = (bitlen + 7) >> 3; + sc = (int)((hbitlen - bitlen) & 7); + } else { + sc = 0; + } + br_i31_zero(x, ebitlen); + br_i31_decode(x, src, len); + br_i31_rshift(x, sc); + x[0] = ebitlen; +} diff --git a/src/bearssl/src/ec/ecdsa_i31_sign_asn1.c b/src/bearssl/src/ec/ecdsa_i31_sign_asn1.c new file mode 100644 index 0000000..cf0d351 --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i31_sign_asn1.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3) + +/* see bearssl_ec.h */ +size_t +br_ecdsa_i31_sign_asn1(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig) +{ + unsigned char rsig[(ORDER_LEN << 1) + 12]; + size_t sig_len; + + sig_len = br_ecdsa_i31_sign_raw(impl, hf, hash_value, sk, rsig); + if (sig_len == 0) { + return 0; + } + sig_len = br_ecdsa_raw_to_asn1(rsig, sig_len); + memcpy(sig, rsig, sig_len); + return sig_len; +} diff --git a/src/bearssl/src/ec/ecdsa_i31_sign_raw.c b/src/bearssl/src/ec/ecdsa_i31_sign_raw.c new file mode 100644 index 0000000..1df98fe --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i31_sign_raw.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31) +#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1)) +#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3) + +/* see bearssl_ec.h */ +size_t +br_ecdsa_i31_sign_raw(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig) +{ + /* + * IMPORTANT: this code is fit only for curves with a prime + * order. This is needed so that modular reduction of the X + * coordinate of a point can be done with a simple subtraction. + * We also rely on the last byte of the curve order to be distinct + * from 0 and 1. + */ + const br_ec_curve_def *cd; + uint32_t n[I31_LEN], r[I31_LEN], s[I31_LEN], x[I31_LEN]; + uint32_t m[I31_LEN], k[I31_LEN], t1[I31_LEN], t2[I31_LEN]; + unsigned char tt[ORDER_LEN << 1]; + unsigned char eU[POINT_LEN]; + size_t hash_len, nlen, ulen; + uint32_t n0i, ctl; + br_hmac_drbg_context drbg; + + /* + * If the curve is not supported, then exit with an error. + */ + if (((impl->supported_curves >> sk->curve) & 1) == 0) { + return 0; + } + + /* + * Get the curve parameters (generator and order). + */ + switch (sk->curve) { + case BR_EC_secp256r1: + cd = &br_secp256r1; + break; + case BR_EC_secp384r1: + cd = &br_secp384r1; + break; + case BR_EC_secp521r1: + cd = &br_secp521r1; + break; + default: + return 0; + } + + /* + * Get modulus. + */ + nlen = cd->order_len; + br_i31_decode(n, cd->order, nlen); + n0i = br_i31_ninv31(n[1]); + + /* + * Get private key as an i31 integer. This also checks that the + * private key is well-defined (not zero, and less than the + * curve order). + */ + if (!br_i31_decode_mod(x, sk->x, sk->xlen, n)) { + return 0; + } + if (br_i31_iszero(x)) { + return 0; + } + + /* + * Get hash length. + */ + hash_len = (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + + /* + * Truncate and reduce the hash value modulo the curve order. + */ + br_ecdsa_i31_bits2int(m, hash_value, hash_len, n[0]); + br_i31_sub(m, n, br_i31_sub(m, n, 0) ^ 1); + + /* + * RFC 6979 generation of the "k" value. + * + * The process uses HMAC_DRBG (with the hash function used to + * process the message that is to be signed). The seed is the + * concatenation of the encodings of the private key and + * the hash value (after truncation and modular reduction). + */ + br_i31_encode(tt, nlen, x); + br_i31_encode(tt + nlen, nlen, m); + br_hmac_drbg_init(&drbg, hf, tt, nlen << 1); + for (;;) { + br_hmac_drbg_generate(&drbg, tt, nlen); + br_ecdsa_i31_bits2int(k, tt, nlen, n[0]); + if (br_i31_iszero(k)) { + continue; + } + if (br_i31_sub(k, n, 0)) { + break; + } + } + + /* + * Compute k*G and extract the X coordinate, then reduce it + * modulo the curve order. Since we support only curves with + * prime order, that reduction is only a matter of computing + * a subtraction. + */ + br_i31_encode(tt, nlen, k); + ulen = impl->mulgen(eU, tt, nlen, sk->curve); + br_i31_zero(r, n[0]); + br_i31_decode(r, &eU[1], ulen >> 1); + r[0] = n[0]; + br_i31_sub(r, n, br_i31_sub(r, n, 0) ^ 1); + + /* + * Compute 1/k in double-Montgomery representation. We do so by + * first converting _from_ Montgomery representation (twice), + * then using a modular exponentiation. + */ + br_i31_from_monty(k, n, n0i); + br_i31_from_monty(k, n, n0i); + memcpy(tt, cd->order, nlen); + tt[nlen - 1] -= 2; + br_i31_modpow(k, tt, nlen, n, n0i, t1, t2); + + /* + * Compute s = (m+xr)/k (mod n). + * The k[] array contains R^2/k (double-Montgomery representation); + * we thus can use direct Montgomery multiplications and conversions + * from Montgomery, avoiding any call to br_i31_to_monty() (which + * is slower). + */ + br_i31_from_monty(m, n, n0i); + br_i31_montymul(t1, x, r, n, n0i); + ctl = br_i31_add(t1, m, 1); + ctl |= br_i31_sub(t1, n, 0) ^ 1; + br_i31_sub(t1, n, ctl); + br_i31_montymul(s, t1, k, n, n0i); + + /* + * Encode r and s in the signature. + */ + br_i31_encode(sig, nlen, r); + br_i31_encode((unsigned char *)sig + nlen, nlen, s); + return nlen << 1; +} diff --git a/src/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c b/src/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c new file mode 100644 index 0000000..4161aaa --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define FIELD_LEN ((BR_MAX_EC_SIZE + 7) >> 3) + +/* see bearssl_ec.h */ +uint32_t +br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, + const void *sig, size_t sig_len) +{ + /* + * We use a double-sized buffer because a malformed ASN.1 signature + * may trigger a size expansion when converting to "raw" format. + */ + unsigned char rsig[(FIELD_LEN << 2) + 24]; + + if (sig_len > ((sizeof rsig) >> 1)) { + return 0; + } + memcpy(rsig, sig, sig_len); + sig_len = br_ecdsa_asn1_to_raw(rsig, sig_len); + return br_ecdsa_i31_vrfy_raw(impl, hash, hash_len, pk, rsig, sig_len); +} diff --git a/src/bearssl/src/ec/ecdsa_i31_vrfy_raw.c b/src/bearssl/src/ec/ecdsa_i31_vrfy_raw.c new file mode 100644 index 0000000..259477f --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_i31_vrfy_raw.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31) +#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1)) + +/* see bearssl_ec.h */ +uint32_t +br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, + const void *sig, size_t sig_len) +{ + /* + * IMPORTANT: this code is fit only for curves with a prime + * order. This is needed so that modular reduction of the X + * coordinate of a point can be done with a simple subtraction. + */ + const br_ec_curve_def *cd; + uint32_t n[I31_LEN], r[I31_LEN], s[I31_LEN], t1[I31_LEN], t2[I31_LEN]; + unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3]; + unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3]; + unsigned char eU[POINT_LEN]; + size_t nlen, rlen, ulen; + uint32_t n0i, res; + + /* + * If the curve is not supported, then report an error. + */ + if (((impl->supported_curves >> pk->curve) & 1) == 0) { + return 0; + } + + /* + * Get the curve parameters (generator and order). + */ + switch (pk->curve) { + case BR_EC_secp256r1: + cd = &br_secp256r1; + break; + case BR_EC_secp384r1: + cd = &br_secp384r1; + break; + case BR_EC_secp521r1: + cd = &br_secp521r1; + break; + default: + return 0; + } + + /* + * Signature length must be even. + */ + if (sig_len & 1) { + return 0; + } + rlen = sig_len >> 1; + + /* + * Public key point must have the proper size for this curve. + */ + if (pk->qlen != cd->generator_len) { + return 0; + } + + /* + * Get modulus; then decode the r and s values. They must be + * lower than the modulus, and s must not be null. + */ + nlen = cd->order_len; + br_i31_decode(n, cd->order, nlen); + n0i = br_i31_ninv31(n[1]); + if (!br_i31_decode_mod(r, sig, rlen, n)) { + return 0; + } + if (!br_i31_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) { + return 0; + } + if (br_i31_iszero(s)) { + return 0; + } + + /* + * Invert s. We do that with a modular exponentiation; we use + * the fact that for all the curves we support, the least + * significant byte is not 0 or 1, so we can subtract 2 without + * any carry to process. + * We also want 1/s in Montgomery representation, which can be + * done by converting _from_ Montgomery representation before + * the inversion (because (1/s)*R = 1/(s/R)). + */ + br_i31_from_monty(s, n, n0i); + memcpy(tx, cd->order, nlen); + tx[nlen - 1] -= 2; + br_i31_modpow(s, tx, nlen, n, n0i, t1, t2); + + /* + * Truncate the hash to the modulus length (in bits) and reduce + * it modulo the curve order. The modular reduction can be done + * with a subtraction since the truncation already reduced the + * value to the modulus bit length. + */ + br_ecdsa_i31_bits2int(t1, hash, hash_len, n[0]); + br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1); + + /* + * Multiply the (truncated, reduced) hash value with 1/s, result in + * t2, encoded in ty. + */ + br_i31_montymul(t2, t1, s, n, n0i); + br_i31_encode(ty, nlen, t2); + + /* + * Multiply r with 1/s, result in t1, encoded in tx. + */ + br_i31_montymul(t1, r, s, n, n0i); + br_i31_encode(tx, nlen, t1); + + /* + * Compute the point x*Q + y*G. + */ + ulen = cd->generator_len; + memcpy(eU, pk->q, ulen); + res = impl->muladd(eU, NULL, ulen, + tx, nlen, ty, nlen, cd->curve); + + /* + * Get the X coordinate, reduce modulo the curve order, and + * compare with the 'r' value. + * + * The modular reduction can be done with subtractions because + * we work with curves of prime order, so the curve order is + * close to the field order (Hasse's theorem). + */ + br_i31_zero(t1, n[0]); + br_i31_decode(t1, &eU[1], ulen >> 1); + t1[0] = n[0]; + br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1); + res &= ~br_i31_sub(t1, r, 1); + res &= br_i31_iszero(t1); + return res; +} diff --git a/src/bearssl/src/ec/ecdsa_rta.c b/src/bearssl/src/ec/ecdsa_rta.c new file mode 100644 index 0000000..005c62c --- /dev/null +++ b/src/bearssl/src/ec/ecdsa_rta.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Compute ASN.1 encoded length for the provided integer. The ASN.1 + * encoding is signed, so its leading bit must have value 0; it must + * also be of minimal length (so leading bytes of value 0 must be + * removed, except if that would contradict the rule about the sign + * bit). + */ +static size_t +asn1_int_length(const unsigned char *x, size_t xlen) +{ + while (xlen > 0 && *x == 0) { + x ++; + xlen --; + } + if (xlen == 0 || *x >= 0x80) { + xlen ++; + } + return xlen; +} + +/* see bearssl_ec.h */ +size_t +br_ecdsa_raw_to_asn1(void *sig, size_t sig_len) +{ + /* + * Internal buffer is large enough to accommodate a signature + * such that r and s fit on 125 bytes each (signed encoding), + * meaning a curve order of up to 999 bits. This is the limit + * that ensures "simple" length encodings. + */ + unsigned char *buf; + size_t hlen, rlen, slen, zlen, off; + unsigned char tmp[257]; + + buf = sig; + if ((sig_len & 1) != 0) { + return 0; + } + + /* + * Compute lengths for the two integers. + */ + hlen = sig_len >> 1; + rlen = asn1_int_length(buf, hlen); + slen = asn1_int_length(buf + hlen, hlen); + if (rlen > 125 || slen > 125) { + return 0; + } + + /* + * SEQUENCE header. + */ + tmp[0] = 0x30; + zlen = rlen + slen + 4; + if (zlen >= 0x80) { + tmp[1] = 0x81; + tmp[2] = zlen; + off = 3; + } else { + tmp[1] = zlen; + off = 2; + } + + /* + * First INTEGER (r). + */ + tmp[off ++] = 0x02; + tmp[off ++] = rlen; + if (rlen > hlen) { + tmp[off] = 0x00; + memcpy(tmp + off + 1, buf, hlen); + } else { + memcpy(tmp + off, buf + hlen - rlen, rlen); + } + off += rlen; + + /* + * Second INTEGER (s). + */ + tmp[off ++] = 0x02; + tmp[off ++] = slen; + if (slen > hlen) { + tmp[off] = 0x00; + memcpy(tmp + off + 1, buf + hlen, hlen); + } else { + memcpy(tmp + off, buf + sig_len - slen, slen); + } + off += slen; + + /* + * Return ASN.1 signature. + */ + memcpy(sig, tmp, off); + return off; +} diff --git a/src/bearssl/src/hash/dig_oid.c b/src/bearssl/src/hash/dig_oid.c new file mode 100644 index 0000000..cd9692c --- /dev/null +++ b/src/bearssl/src/hash/dig_oid.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * This file contains the encoded OID for the standard hash functions. + * Such OID appear in, for instance, the PKCS#1 v1.5 padding for RSA + * signatures. + */ + +static const unsigned char md5_OID[] = { + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05 +}; + +static const unsigned char sha1_OID[] = { + 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char sha224_OID[] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char sha256_OID[] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char sha384_OID[] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char sha512_OID[] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +/* see inner.h */ +const unsigned char * +br_digest_OID(int digest_id, size_t *len) +{ + switch (digest_id) { + case br_md5_ID: + *len = sizeof md5_OID; + return md5_OID; + case br_sha1_ID: + *len = sizeof sha1_OID; + return sha1_OID; + case br_sha224_ID: + *len = sizeof sha224_OID; + return sha224_OID; + case br_sha256_ID: + *len = sizeof sha256_OID; + return sha256_OID; + case br_sha384_ID: + *len = sizeof sha384_OID; + return sha384_OID; + case br_sha512_ID: + *len = sizeof sha512_OID; + return sha512_OID; + default: + *len = 0; + return NULL; + } +} diff --git a/src/bearssl/src/hash/dig_size.c b/src/bearssl/src/hash/dig_size.c new file mode 100644 index 0000000..4625d2c --- /dev/null +++ b/src/bearssl/src/hash/dig_size.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +size_t +br_digest_size_by_ID(int digest_id) +{ + switch (digest_id) { + case br_md5sha1_ID: + return br_md5_SIZE + br_sha1_SIZE; + case br_md5_ID: + return br_md5_SIZE; + case br_sha1_ID: + return br_sha1_SIZE; + case br_sha224_ID: + return br_sha224_SIZE; + case br_sha256_ID: + return br_sha256_SIZE; + case br_sha384_ID: + return br_sha384_SIZE; + case br_sha512_ID: + return br_sha512_SIZE; + default: + /* abort(); */ + return 0; + } +} diff --git a/src/bearssl/src/hash/ghash_ctmul.c b/src/bearssl/src/hash/ghash_ctmul.c new file mode 100644 index 0000000..3623202 --- /dev/null +++ b/src/bearssl/src/hash/ghash_ctmul.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * We compute "carryless multiplications" through normal integer + * multiplications, masking out enough bits to create "holes" in which + * carries may expand without altering our bits; we really use 8 data + * bits per 32-bit word, spaced every fourth bit. Accumulated carries + * may not exceed 8 in total, which fits in 4 bits. + * + * It would be possible to use a 3-bit spacing, allowing two operands, + * one with 7 non-zero data bits, the other one with 10 or 11 non-zero + * data bits; this asymmetric splitting makes the overall code more + * complex with thresholds and exceptions, and does not appear to be + * worth the effort. + */ + +/* + * We cannot really autodetect whether multiplications are "slow" or + * not. A typical example is the ARM Cortex M0+, which exists in two + * versions: one with a 1-cycle multiplication opcode, the other with + * a 32-cycle multiplication opcode. They both use exactly the same + * architecture and ABI, and cannot be distinguished from each other + * at compile-time. + * + * Since most modern CPU (even embedded CPU) still have fast + * multiplications, we use the "fast mul" code by default. + */ + +#if BR_SLOW_MUL + +/* + * This implementation uses Karatsuba-like reduction to make fewer + * integer multiplications (9 instead of 16), at the expense of extra + * logical operations (XOR, shifts...). On modern x86 CPU that offer + * fast, pipelined multiplications, this code is about twice slower than + * the simpler code with 16 multiplications. This tendency may be + * reversed on low-end platforms with expensive multiplications. + */ + +#define MUL32(h, l, x, y) do { \ + uint64_t mul32tmp = MUL(x, y); \ + (h) = (uint32_t)(mul32tmp >> 32); \ + (l) = (uint32_t)mul32tmp; \ + } while (0) + +static inline void +bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y) +{ + uint32_t x0, x1, x2, x3; + uint32_t y0, y1, y2, y3; + uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8; + uint32_t b0, b1, b2, b3, b4, b5, b6, b7, b8; + + x0 = x & (uint32_t)0x11111111; + x1 = x & (uint32_t)0x22222222; + x2 = x & (uint32_t)0x44444444; + x3 = x & (uint32_t)0x88888888; + y0 = y & (uint32_t)0x11111111; + y1 = y & (uint32_t)0x22222222; + y2 = y & (uint32_t)0x44444444; + y3 = y & (uint32_t)0x88888888; + + /* + * (x0+W*x1)*(y0+W*y1) -> a0:b0 + * (x2+W*x3)*(y2+W*y3) -> a3:b3 + * ((x0+x2)+W*(x1+x3))*((y0+y2)+W*(y1+y3)) -> a6:b6 + */ + a0 = x0; + b0 = y0; + a1 = x1 >> 1; + b1 = y1 >> 1; + a2 = a0 ^ a1; + b2 = b0 ^ b1; + a3 = x2 >> 2; + b3 = y2 >> 2; + a4 = x3 >> 3; + b4 = y3 >> 3; + a5 = a3 ^ a4; + b5 = b3 ^ b4; + a6 = a0 ^ a3; + b6 = b0 ^ b3; + a7 = a1 ^ a4; + b7 = b1 ^ b4; + a8 = a6 ^ a7; + b8 = b6 ^ b7; + + MUL32(b0, a0, b0, a0); + MUL32(b1, a1, b1, a1); + MUL32(b2, a2, b2, a2); + MUL32(b3, a3, b3, a3); + MUL32(b4, a4, b4, a4); + MUL32(b5, a5, b5, a5); + MUL32(b6, a6, b6, a6); + MUL32(b7, a7, b7, a7); + MUL32(b8, a8, b8, a8); + + a0 &= (uint32_t)0x11111111; + a1 &= (uint32_t)0x11111111; + a2 &= (uint32_t)0x11111111; + a3 &= (uint32_t)0x11111111; + a4 &= (uint32_t)0x11111111; + a5 &= (uint32_t)0x11111111; + a6 &= (uint32_t)0x11111111; + a7 &= (uint32_t)0x11111111; + a8 &= (uint32_t)0x11111111; + b0 &= (uint32_t)0x11111111; + b1 &= (uint32_t)0x11111111; + b2 &= (uint32_t)0x11111111; + b3 &= (uint32_t)0x11111111; + b4 &= (uint32_t)0x11111111; + b5 &= (uint32_t)0x11111111; + b6 &= (uint32_t)0x11111111; + b7 &= (uint32_t)0x11111111; + b8 &= (uint32_t)0x11111111; + + a2 ^= a0 ^ a1; + b2 ^= b0 ^ b1; + a0 ^= (a2 << 1) ^ (a1 << 2); + b0 ^= (b2 << 1) ^ (b1 << 2); + a5 ^= a3 ^ a4; + b5 ^= b3 ^ b4; + a3 ^= (a5 << 1) ^ (a4 << 2); + b3 ^= (b5 << 1) ^ (b4 << 2); + a8 ^= a6 ^ a7; + b8 ^= b6 ^ b7; + a6 ^= (a8 << 1) ^ (a7 << 2); + b6 ^= (b8 << 1) ^ (b7 << 2); + a6 ^= a0 ^ a3; + b6 ^= b0 ^ b3; + *lo = a0 ^ (a6 << 2) ^ (a3 << 4); + *hi = b0 ^ (b6 << 2) ^ (b3 << 4) ^ (a6 >> 30) ^ (a3 >> 28); +} + +#else + +/* + * Simple multiplication in GF(2)[X], using 16 integer multiplications. + */ + +static inline void +bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y) +{ + uint32_t x0, x1, x2, x3; + uint32_t y0, y1, y2, y3; + uint64_t z0, z1, z2, z3; + uint64_t z; + + x0 = x & (uint32_t)0x11111111; + x1 = x & (uint32_t)0x22222222; + x2 = x & (uint32_t)0x44444444; + x3 = x & (uint32_t)0x88888888; + y0 = y & (uint32_t)0x11111111; + y1 = y & (uint32_t)0x22222222; + y2 = y & (uint32_t)0x44444444; + y3 = y & (uint32_t)0x88888888; + z0 = MUL(x0, y0) ^ MUL(x1, y3) ^ MUL(x2, y2) ^ MUL(x3, y1); + z1 = MUL(x0, y1) ^ MUL(x1, y0) ^ MUL(x2, y3) ^ MUL(x3, y2); + z2 = MUL(x0, y2) ^ MUL(x1, y1) ^ MUL(x2, y0) ^ MUL(x3, y3); + z3 = MUL(x0, y3) ^ MUL(x1, y2) ^ MUL(x2, y1) ^ MUL(x3, y0); + z0 &= (uint64_t)0x1111111111111111; + z1 &= (uint64_t)0x2222222222222222; + z2 &= (uint64_t)0x4444444444444444; + z3 &= (uint64_t)0x8888888888888888; + z = z0 | z1 | z2 | z3; + *lo = (uint32_t)z; + *hi = (uint32_t)(z >> 32); +} + +#endif + +/* see bearssl_hash.h */ +void +br_ghash_ctmul(void *y, const void *h, const void *data, size_t len) +{ + const unsigned char *buf, *hb; + unsigned char *yb; + uint32_t yw[4]; + uint32_t hw[4]; + + /* + * Throughout the loop we handle the y and h values as arrays + * of 32-bit words. + */ + buf = data; + yb = y; + hb = h; + yw[3] = br_dec32be(yb); + yw[2] = br_dec32be(yb + 4); + yw[1] = br_dec32be(yb + 8); + yw[0] = br_dec32be(yb + 12); + hw[3] = br_dec32be(hb); + hw[2] = br_dec32be(hb + 4); + hw[1] = br_dec32be(hb + 8); + hw[0] = br_dec32be(hb + 12); + while (len > 0) { + const unsigned char *src; + unsigned char tmp[16]; + int i; + uint32_t a[9], b[9], zw[8]; + uint32_t c0, c1, c2, c3, d0, d1, d2, d3, e0, e1, e2, e3; + + /* + * Get the next 16-byte block (using zero-padding if + * necessary). + */ + if (len >= 16) { + src = buf; + buf += 16; + len -= 16; + } else { + memcpy(tmp, buf, len); + memset(tmp + len, 0, (sizeof tmp) - len); + src = tmp; + len = 0; + } + + /* + * Decode the block. The GHASH standard mandates + * big-endian encoding. + */ + yw[3] ^= br_dec32be(src); + yw[2] ^= br_dec32be(src + 4); + yw[1] ^= br_dec32be(src + 8); + yw[0] ^= br_dec32be(src + 12); + + /* + * We multiply two 128-bit field elements. We use + * Karatsuba to turn that into three 64-bit + * multiplications, which are themselves done with a + * total of nine 32-bit multiplications. + */ + + /* + * y[0,1]*h[0,1] -> 0..2 + * y[2,3]*h[2,3] -> 3..5 + * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6..8 + */ + a[0] = yw[0]; + b[0] = hw[0]; + a[1] = yw[1]; + b[1] = hw[1]; + a[2] = a[0] ^ a[1]; + b[2] = b[0] ^ b[1]; + + a[3] = yw[2]; + b[3] = hw[2]; + a[4] = yw[3]; + b[4] = hw[3]; + a[5] = a[3] ^ a[4]; + b[5] = b[3] ^ b[4]; + + a[6] = a[0] ^ a[3]; + b[6] = b[0] ^ b[3]; + a[7] = a[1] ^ a[4]; + b[7] = b[1] ^ b[4]; + a[8] = a[6] ^ a[7]; + b[8] = b[6] ^ b[7]; + + for (i = 0; i < 9; i ++) { + bmul(&b[i], &a[i], b[i], a[i]); + } + + c0 = a[0]; + c1 = b[0] ^ a[2] ^ a[0] ^ a[1]; + c2 = a[1] ^ b[2] ^ b[0] ^ b[1]; + c3 = b[1]; + d0 = a[3]; + d1 = b[3] ^ a[5] ^ a[3] ^ a[4]; + d2 = a[4] ^ b[5] ^ b[3] ^ b[4]; + d3 = b[4]; + e0 = a[6]; + e1 = b[6] ^ a[8] ^ a[6] ^ a[7]; + e2 = a[7] ^ b[8] ^ b[6] ^ b[7]; + e3 = b[7]; + + e0 ^= c0 ^ d0; + e1 ^= c1 ^ d1; + e2 ^= c2 ^ d2; + e3 ^= c3 ^ d3; + c2 ^= e0; + c3 ^= e1; + d0 ^= e2; + d1 ^= e3; + + /* + * GHASH specification has the bits "reversed" (most + * significant is in fact least significant), which does + * not matter for a carryless multiplication, except that + * the 255-bit result must be shifted by 1 bit. + */ + zw[0] = c0 << 1; + zw[1] = (c1 << 1) | (c0 >> 31); + zw[2] = (c2 << 1) | (c1 >> 31); + zw[3] = (c3 << 1) | (c2 >> 31); + zw[4] = (d0 << 1) | (c3 >> 31); + zw[5] = (d1 << 1) | (d0 >> 31); + zw[6] = (d2 << 1) | (d1 >> 31); + zw[7] = (d3 << 1) | (d2 >> 31); + + /* + * We now do the reduction modulo the field polynomial + * to get back to 128 bits. + */ + for (i = 0; i < 4; i ++) { + uint32_t lw; + + lw = zw[i]; + zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7); + zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25); + } + memcpy(yw, zw + 4, sizeof yw); + } + + /* + * Encode back the result. + */ + br_enc32be(yb, yw[3]); + br_enc32be(yb + 4, yw[2]); + br_enc32be(yb + 8, yw[1]); + br_enc32be(yb + 12, yw[0]); +} diff --git a/src/bearssl/src/hash/ghash_ctmul32.c b/src/bearssl/src/hash/ghash_ctmul32.c new file mode 100644 index 0000000..c66af46 --- /dev/null +++ b/src/bearssl/src/hash/ghash_ctmul32.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * This implementation uses 32-bit multiplications, and only the low + * 32 bits for each multiplication result. This is meant primarily for + * the ARM Cortex M0 and M0+, whose multiplication opcode does not yield + * the upper 32 bits; but it might also be useful on architectures where + * access to the upper 32 bits requires use of specific registers that + * create contention (e.g. on i386, "mul" necessarily outputs the result + * in edx:eax, while "imul" can use any registers but is limited to the + * low 32 bits). + * + * The implementation trick that is used here is bit-reversing (bit 0 + * is swapped with bit 31, bit 1 with bit 30, and so on). In GF(2)[X], + * for all values x and y, we have: + * rev32(x) * rev32(y) = rev64(x * y) + * In other words, if we bit-reverse (over 32 bits) the operands, then we + * bit-reverse (over 64 bits) the result. + */ + +/* + * Multiplication in GF(2)[X], truncated to its low 32 bits. + */ +static inline uint32_t +bmul32(uint32_t x, uint32_t y) +{ + uint32_t x0, x1, x2, x3; + uint32_t y0, y1, y2, y3; + uint32_t z0, z1, z2, z3; + + x0 = x & (uint32_t)0x11111111; + x1 = x & (uint32_t)0x22222222; + x2 = x & (uint32_t)0x44444444; + x3 = x & (uint32_t)0x88888888; + y0 = y & (uint32_t)0x11111111; + y1 = y & (uint32_t)0x22222222; + y2 = y & (uint32_t)0x44444444; + y3 = y & (uint32_t)0x88888888; + z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1); + z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2); + z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3); + z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0); + z0 &= (uint32_t)0x11111111; + z1 &= (uint32_t)0x22222222; + z2 &= (uint32_t)0x44444444; + z3 &= (uint32_t)0x88888888; + return z0 | z1 | z2 | z3; +} + +/* + * Bit-reverse a 32-bit word. + */ +static uint32_t +rev32(uint32_t x) +{ +#define RMS(m, s) do { \ + x = ((x & (uint32_t)(m)) << (s)) \ + | ((x >> (s)) & (uint32_t)(m)); \ + } while (0) + + RMS(0x55555555, 1); + RMS(0x33333333, 2); + RMS(0x0F0F0F0F, 4); + RMS(0x00FF00FF, 8); + return (x << 16) | (x >> 16); + +#undef RMS +} + +/* see bearssl_hash.h */ +void +br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len) +{ + /* + * This implementation is similar to br_ghash_ctmul() except + * that we have to do the multiplication twice, with the + * "normal" and "bit reversed" operands. Hence we end up with + * eighteen 32-bit multiplications instead of nine. + */ + + const unsigned char *buf, *hb; + unsigned char *yb; + uint32_t yw[4]; + uint32_t hw[4], hwr[4]; + + buf = data; + yb = y; + hb = h; + yw[3] = br_dec32be(yb); + yw[2] = br_dec32be(yb + 4); + yw[1] = br_dec32be(yb + 8); + yw[0] = br_dec32be(yb + 12); + hw[3] = br_dec32be(hb); + hw[2] = br_dec32be(hb + 4); + hw[1] = br_dec32be(hb + 8); + hw[0] = br_dec32be(hb + 12); + hwr[3] = rev32(hw[3]); + hwr[2] = rev32(hw[2]); + hwr[1] = rev32(hw[1]); + hwr[0] = rev32(hw[0]); + while (len > 0) { + const unsigned char *src; + unsigned char tmp[16]; + int i; + uint32_t a[18], b[18], c[18]; + uint32_t d0, d1, d2, d3, d4, d5, d6, d7; + uint32_t zw[8]; + + if (len >= 16) { + src = buf; + buf += 16; + len -= 16; + } else { + memcpy(tmp, buf, len); + memset(tmp + len, 0, (sizeof tmp) - len); + src = tmp; + len = 0; + } + yw[3] ^= br_dec32be(src); + yw[2] ^= br_dec32be(src + 4); + yw[1] ^= br_dec32be(src + 8); + yw[0] ^= br_dec32be(src + 12); + + /* + * We are using Karatsuba: the 128x128 multiplication is + * reduced to three 64x64 multiplications, hence nine + * 32x32 multiplications. With the bit-reversal trick, + * we have to perform 18 32x32 multiplications. + */ + + /* + * y[0,1]*h[0,1] -> 0,1,4 + * y[2,3]*h[2,3] -> 2,3,5 + * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,7,8 + */ + + a[0] = yw[0]; + a[1] = yw[1]; + a[2] = yw[2]; + a[3] = yw[3]; + a[4] = a[0] ^ a[1]; + a[5] = a[2] ^ a[3]; + a[6] = a[0] ^ a[2]; + a[7] = a[1] ^ a[3]; + a[8] = a[6] ^ a[7]; + + a[ 9] = rev32(yw[0]); + a[10] = rev32(yw[1]); + a[11] = rev32(yw[2]); + a[12] = rev32(yw[3]); + a[13] = a[ 9] ^ a[10]; + a[14] = a[11] ^ a[12]; + a[15] = a[ 9] ^ a[11]; + a[16] = a[10] ^ a[12]; + a[17] = a[15] ^ a[16]; + + b[0] = hw[0]; + b[1] = hw[1]; + b[2] = hw[2]; + b[3] = hw[3]; + b[4] = b[0] ^ b[1]; + b[5] = b[2] ^ b[3]; + b[6] = b[0] ^ b[2]; + b[7] = b[1] ^ b[3]; + b[8] = b[6] ^ b[7]; + + b[ 9] = hwr[0]; + b[10] = hwr[1]; + b[11] = hwr[2]; + b[12] = hwr[3]; + b[13] = b[ 9] ^ b[10]; + b[14] = b[11] ^ b[12]; + b[15] = b[ 9] ^ b[11]; + b[16] = b[10] ^ b[12]; + b[17] = b[15] ^ b[16]; + + for (i = 0; i < 18; i ++) { + c[i] = bmul32(a[i], b[i]); + } + + c[4] ^= c[0] ^ c[1]; + c[5] ^= c[2] ^ c[3]; + c[8] ^= c[6] ^ c[7]; + + c[13] ^= c[ 9] ^ c[10]; + c[14] ^= c[11] ^ c[12]; + c[17] ^= c[15] ^ c[16]; + + /* + * y[0,1]*h[0,1] -> 0,9^4,1^13,10 + * y[2,3]*h[2,3] -> 2,11^5,3^14,12 + * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,15^8,7^17,16 + */ + d0 = c[0]; + d1 = c[4] ^ (rev32(c[9]) >> 1); + d2 = c[1] ^ c[0] ^ c[2] ^ c[6] ^ (rev32(c[13]) >> 1); + d3 = c[4] ^ c[5] ^ c[8] + ^ (rev32(c[10] ^ c[9] ^ c[11] ^ c[15]) >> 1); + d4 = c[2] ^ c[1] ^ c[3] ^ c[7] + ^ (rev32(c[13] ^ c[14] ^ c[17]) >> 1); + d5 = c[5] ^ (rev32(c[11] ^ c[10] ^ c[12] ^ c[16]) >> 1); + d6 = c[3] ^ (rev32(c[14]) >> 1); + d7 = rev32(c[12]) >> 1; + + zw[0] = d0 << 1; + zw[1] = (d1 << 1) | (d0 >> 31); + zw[2] = (d2 << 1) | (d1 >> 31); + zw[3] = (d3 << 1) | (d2 >> 31); + zw[4] = (d4 << 1) | (d3 >> 31); + zw[5] = (d5 << 1) | (d4 >> 31); + zw[6] = (d6 << 1) | (d5 >> 31); + zw[7] = (d7 << 1) | (d6 >> 31); + + for (i = 0; i < 4; i ++) { + uint32_t lw; + + lw = zw[i]; + zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7); + zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25); + } + memcpy(yw, zw + 4, sizeof yw); + } + br_enc32be(yb, yw[3]); + br_enc32be(yb + 4, yw[2]); + br_enc32be(yb + 8, yw[1]); + br_enc32be(yb + 12, yw[0]); +} diff --git a/src/bearssl/src/hash/ghash_ctmul64.c b/src/bearssl/src/hash/ghash_ctmul64.c new file mode 100644 index 0000000..a46f16f --- /dev/null +++ b/src/bearssl/src/hash/ghash_ctmul64.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * This is the 64-bit variant of br_ghash_ctmul32(), with 64-bit operands + * and bit reversal of 64-bit words. + */ + +static inline uint64_t +bmul64(uint64_t x, uint64_t y) +{ + uint64_t x0, x1, x2, x3; + uint64_t y0, y1, y2, y3; + uint64_t z0, z1, z2, z3; + + x0 = x & (uint64_t)0x1111111111111111; + x1 = x & (uint64_t)0x2222222222222222; + x2 = x & (uint64_t)0x4444444444444444; + x3 = x & (uint64_t)0x8888888888888888; + y0 = y & (uint64_t)0x1111111111111111; + y1 = y & (uint64_t)0x2222222222222222; + y2 = y & (uint64_t)0x4444444444444444; + y3 = y & (uint64_t)0x8888888888888888; + z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1); + z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2); + z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3); + z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0); + z0 &= (uint64_t)0x1111111111111111; + z1 &= (uint64_t)0x2222222222222222; + z2 &= (uint64_t)0x4444444444444444; + z3 &= (uint64_t)0x8888888888888888; + return z0 | z1 | z2 | z3; +} + +static uint64_t +rev64(uint64_t x) +{ +#define RMS(m, s) do { \ + x = ((x & (uint64_t)(m)) << (s)) \ + | ((x >> (s)) & (uint64_t)(m)); \ + } while (0) + + RMS(0x5555555555555555, 1); + RMS(0x3333333333333333, 2); + RMS(0x0F0F0F0F0F0F0F0F, 4); + RMS(0x00FF00FF00FF00FF, 8); + RMS(0x0000FFFF0000FFFF, 16); + return (x << 32) | (x >> 32); + +#undef RMS +} + +/* see bearssl_ghash.h */ +void +br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len) +{ + const unsigned char *buf, *hb; + unsigned char *yb; + uint64_t y0, y1; + uint64_t h0, h1, h2, h0r, h1r, h2r; + + buf = data; + yb = y; + hb = h; + y1 = br_dec64be(yb); + y0 = br_dec64be(yb + 8); + h1 = br_dec64be(hb); + h0 = br_dec64be(hb + 8); + h0r = rev64(h0); + h1r = rev64(h1); + h2 = h0 ^ h1; + h2r = h0r ^ h1r; + while (len > 0) { + const unsigned char *src; + unsigned char tmp[16]; + uint64_t y0r, y1r, y2, y2r; + uint64_t z0, z1, z2, z0h, z1h, z2h; + uint64_t v0, v1, v2, v3; + + if (len >= 16) { + src = buf; + buf += 16; + len -= 16; + } else { + memcpy(tmp, buf, len); + memset(tmp + len, 0, (sizeof tmp) - len); + src = tmp; + len = 0; + } + y1 ^= br_dec64be(src); + y0 ^= br_dec64be(src + 8); + + y0r = rev64(y0); + y1r = rev64(y1); + y2 = y0 ^ y1; + y2r = y0r ^ y1r; + + z0 = bmul64(y0, h0); + z1 = bmul64(y1, h1); + z2 = bmul64(y2, h2); + z0h = bmul64(y0r, h0r); + z1h = bmul64(y1r, h1r); + z2h = bmul64(y2r, h2r); + z2 ^= z0 ^ z1; + z2h ^= z0h ^ z1h; + z0h = rev64(z0h) >> 1; + z1h = rev64(z1h) >> 1; + z2h = rev64(z2h) >> 1; + + v0 = z0; + v1 = z0h ^ z2; + v2 = z1 ^ z2h; + v3 = z1h; + + v3 = (v3 << 1) | (v2 >> 63); + v2 = (v2 << 1) | (v1 >> 63); + v1 = (v1 << 1) | (v0 >> 63); + v0 = (v0 << 1); + + v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7); + v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57); + v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7); + v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57); + + y0 = v2; + y1 = v3; + } + + br_enc64be(yb, y1); + br_enc64be(yb + 8, y0); +} diff --git a/src/bearssl/src/hash/ghash_pclmul.c b/src/bearssl/src/hash/ghash_pclmul.c new file mode 100644 index 0000000..a58e7dc --- /dev/null +++ b/src/bearssl/src/hash/ghash_pclmul.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +/* + * This is the GHASH implementation that leverages the pclmulqdq opcode + * (from the AES-NI instructions). + */ + +#if BR_AES_X86NI + +/* + * Test CPU support for PCLMULQDQ. + */ +static inline int +pclmul_supported(void) +{ + /* + * Bit mask for features in ECX: + * 1 PCLMULQDQ support + */ + return br_cpuid(0, 0, 0x00000002, 0); +} + +/* see bearssl_hash.h */ +br_ghash +br_ghash_pclmul_get(void) +{ + return pclmul_supported() ? &br_ghash_pclmul : 0; +} + +BR_TARGETS_X86_UP + +/* + * GHASH is defined over elements of GF(2^128) with "full little-endian" + * representation: leftmost byte is least significant, and, within each + * byte, leftmost _bit_ is least significant. The natural ordering in + * x86 is "mixed little-endian": bytes are ordered from least to most + * significant, but bits within a byte are in most-to-least significant + * order. Going to full little-endian representation would require + * reversing bits within each byte, which is doable but expensive. + * + * Instead, we go to full big-endian representation, by swapping bytes + * around, which is done with a single _mm_shuffle_epi8() opcode (it + * comes with SSSE3; all CPU that offer pclmulqdq also have SSSE3). We + * can use a full big-endian representation because in a carryless + * multiplication, we have a nice bit reversal property: + * + * rev_128(x) * rev_128(y) = rev_255(x * y) + * + * So by using full big-endian, we still get the right result, except + * that it is right-shifted by 1 bit. The left-shift is relatively + * inexpensive, and it can be mutualised. + * + * + * Since SSE2 opcodes do not have facilities for shitfting full 128-bit + * values with bit precision, we have to break down values into 64-bit + * chunks. We number chunks from 0 to 3 in left to right order. + */ + +/* + * Byte-swap a complete 128-bit value. This normally uses + * _mm_shuffle_epi8(), which gets translated to pshufb (an SSSE3 opcode). + * However, this crashes old Clang versions, so, for Clang before 3.8, + * we use an alternate (and less efficient) version. + */ +#if BR_CLANG && !BR_CLANG_3_8 +#define BYTESWAP_DECL +#define BYTESWAP_PREP (void)0 +#define BYTESWAP(x) do { \ + __m128i byteswap1, byteswap2; \ + byteswap1 = (x); \ + byteswap2 = _mm_srli_epi16(byteswap1, 8); \ + byteswap1 = _mm_slli_epi16(byteswap1, 8); \ + byteswap1 = _mm_or_si128(byteswap1, byteswap2); \ + byteswap1 = _mm_shufflelo_epi16(byteswap1, 0x1B); \ + byteswap1 = _mm_shufflehi_epi16(byteswap1, 0x1B); \ + (x) = _mm_shuffle_epi32(byteswap1, 0x4E); \ + } while (0) +#else +#define BYTESWAP_DECL __m128i byteswap_index; +#define BYTESWAP_PREP do { \ + byteswap_index = _mm_set_epi8( \ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); \ + } while (0) +#define BYTESWAP(x) do { \ + (x) = _mm_shuffle_epi8((x), byteswap_index); \ + } while (0) +#endif + +/* + * Call pclmulqdq. Clang appears to have trouble with the intrinsic, so, + * for that compiler, we use inline assembly. Inline assembly is + * potentially a bit slower because the compiler does not understand + * what the opcode does, and thus cannot optimize instruction + * scheduling. + * + * We use a target of "sse2" only, so that Clang may still handle the + * '__m128i' type and allocate SSE2 registers. + */ +#if BR_CLANG +BR_TARGET("sse2") +static inline __m128i +pclmulqdq00(__m128i x, __m128i y) +{ + __asm__ ("pclmulqdq $0x00, %1, %0" : "+x" (x) : "x" (y)); + return x; +} +BR_TARGET("sse2") +static inline __m128i +pclmulqdq11(__m128i x, __m128i y) +{ + __asm__ ("pclmulqdq $0x11, %1, %0" : "+x" (x) : "x" (y)); + return x; +} +#else +#define pclmulqdq00(x, y) _mm_clmulepi64_si128(x, y, 0x00) +#define pclmulqdq11(x, y) _mm_clmulepi64_si128(x, y, 0x11) +#endif + +/* + * From a 128-bit value kw, compute kx as the XOR of the two 64-bit + * halves of kw (into the right half of kx; left half is unspecified). + */ +#define BK(kw, kx) do { \ + kx = _mm_xor_si128(kw, _mm_shuffle_epi32(kw, 0x0E)); \ + } while (0) + +/* + * Combine two 64-bit values (k0:k1) into a 128-bit (kw) value and + * the XOR of the two values (kx). + */ +#define PBK(k0, k1, kw, kx) do { \ + kw = _mm_unpacklo_epi64(k1, k0); \ + kx = _mm_xor_si128(k0, k1); \ + } while (0) + +/* + * Left-shift by 1 bit a 256-bit value (in four 64-bit words). + */ +#define SL_256(x0, x1, x2, x3) do { \ + x0 = _mm_or_si128( \ + _mm_slli_epi64(x0, 1), \ + _mm_srli_epi64(x1, 63)); \ + x1 = _mm_or_si128( \ + _mm_slli_epi64(x1, 1), \ + _mm_srli_epi64(x2, 63)); \ + x2 = _mm_or_si128( \ + _mm_slli_epi64(x2, 1), \ + _mm_srli_epi64(x3, 63)); \ + x3 = _mm_slli_epi64(x3, 1); \ + } while (0) + +/* + * Perform reduction in GF(2^128). The 256-bit value is in x0..x3; + * result is written in x0..x1. + */ +#define REDUCE_F128(x0, x1, x2, x3) do { \ + x1 = _mm_xor_si128( \ + x1, \ + _mm_xor_si128( \ + _mm_xor_si128( \ + x3, \ + _mm_srli_epi64(x3, 1)), \ + _mm_xor_si128( \ + _mm_srli_epi64(x3, 2), \ + _mm_srli_epi64(x3, 7)))); \ + x2 = _mm_xor_si128( \ + _mm_xor_si128( \ + x2, \ + _mm_slli_epi64(x3, 63)), \ + _mm_xor_si128( \ + _mm_slli_epi64(x3, 62), \ + _mm_slli_epi64(x3, 57))); \ + x0 = _mm_xor_si128( \ + x0, \ + _mm_xor_si128( \ + _mm_xor_si128( \ + x2, \ + _mm_srli_epi64(x2, 1)), \ + _mm_xor_si128( \ + _mm_srli_epi64(x2, 2), \ + _mm_srli_epi64(x2, 7)))); \ + x1 = _mm_xor_si128( \ + _mm_xor_si128( \ + x1, \ + _mm_slli_epi64(x2, 63)), \ + _mm_xor_si128( \ + _mm_slli_epi64(x2, 62), \ + _mm_slli_epi64(x2, 57))); \ + } while (0) + +/* + * Square value kw into (dw,dx). + */ +#define SQUARE_F128(kw, dw, dx) do { \ + __m128i z0, z1, z2, z3; \ + z1 = pclmulqdq11(kw, kw); \ + z3 = pclmulqdq00(kw, kw); \ + z0 = _mm_shuffle_epi32(z1, 0x0E); \ + z2 = _mm_shuffle_epi32(z3, 0x0E); \ + SL_256(z0, z1, z2, z3); \ + REDUCE_F128(z0, z1, z2, z3); \ + PBK(z0, z1, dw, dx); \ + } while (0) + +/* see bearssl_hash.h */ +BR_TARGET("ssse3,pclmul") +void +br_ghash_pclmul(void *y, const void *h, const void *data, size_t len) +{ + const unsigned char *buf1, *buf2; + unsigned char tmp[64]; + size_t num4, num1; + __m128i yw, h1w, h1x; + BYTESWAP_DECL + + /* + * We split data into two chunks. First chunk starts at buf1 + * and contains num4 blocks of 64-byte values. Second chunk + * starts at buf2 and contains num1 blocks of 16-byte values. + * We want the first chunk to be as large as possible. + */ + buf1 = data; + num4 = len >> 6; + len &= 63; + buf2 = buf1 + (num4 << 6); + num1 = (len + 15) >> 4; + if ((len & 15) != 0) { + memcpy(tmp, buf2, len); + memset(tmp + len, 0, (num1 << 4) - len); + buf2 = tmp; + } + + /* + * Preparatory step for endian conversions. + */ + BYTESWAP_PREP; + + /* + * Load y and h. + */ + yw = _mm_loadu_si128(y); + h1w = _mm_loadu_si128(h); + BYTESWAP(yw); + BYTESWAP(h1w); + BK(h1w, h1x); + + if (num4 > 0) { + __m128i h2w, h2x, h3w, h3x, h4w, h4x; + __m128i t0, t1, t2, t3; + + /* + * Compute h2 = h^2. + */ + SQUARE_F128(h1w, h2w, h2x); + + /* + * Compute h3 = h^3 = h*(h^2). + */ + t1 = pclmulqdq11(h1w, h2w); + t3 = pclmulqdq00(h1w, h2w); + t2 = _mm_xor_si128(pclmulqdq00(h1x, h2x), + _mm_xor_si128(t1, t3)); + t0 = _mm_shuffle_epi32(t1, 0x0E); + t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E)); + t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E)); + SL_256(t0, t1, t2, t3); + REDUCE_F128(t0, t1, t2, t3); + PBK(t0, t1, h3w, h3x); + + /* + * Compute h4 = h^4 = (h^2)^2. + */ + SQUARE_F128(h2w, h4w, h4x); + + while (num4 -- > 0) { + __m128i aw0, aw1, aw2, aw3; + __m128i ax0, ax1, ax2, ax3; + + aw0 = _mm_loadu_si128((void *)(buf1 + 0)); + aw1 = _mm_loadu_si128((void *)(buf1 + 16)); + aw2 = _mm_loadu_si128((void *)(buf1 + 32)); + aw3 = _mm_loadu_si128((void *)(buf1 + 48)); + BYTESWAP(aw0); + BYTESWAP(aw1); + BYTESWAP(aw2); + BYTESWAP(aw3); + buf1 += 64; + + aw0 = _mm_xor_si128(aw0, yw); + BK(aw1, ax1); + BK(aw2, ax2); + BK(aw3, ax3); + BK(aw0, ax0); + + t1 = _mm_xor_si128( + _mm_xor_si128( + pclmulqdq11(aw0, h4w), + pclmulqdq11(aw1, h3w)), + _mm_xor_si128( + pclmulqdq11(aw2, h2w), + pclmulqdq11(aw3, h1w))); + t3 = _mm_xor_si128( + _mm_xor_si128( + pclmulqdq00(aw0, h4w), + pclmulqdq00(aw1, h3w)), + _mm_xor_si128( + pclmulqdq00(aw2, h2w), + pclmulqdq00(aw3, h1w))); + t2 = _mm_xor_si128( + _mm_xor_si128( + pclmulqdq00(ax0, h4x), + pclmulqdq00(ax1, h3x)), + _mm_xor_si128( + pclmulqdq00(ax2, h2x), + pclmulqdq00(ax3, h1x))); + t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3)); + t0 = _mm_shuffle_epi32(t1, 0x0E); + t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E)); + t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E)); + SL_256(t0, t1, t2, t3); + REDUCE_F128(t0, t1, t2, t3); + yw = _mm_unpacklo_epi64(t1, t0); + } + } + + while (num1 -- > 0) { + __m128i aw, ax; + __m128i t0, t1, t2, t3; + + aw = _mm_loadu_si128((void *)buf2); + BYTESWAP(aw); + buf2 += 16; + + aw = _mm_xor_si128(aw, yw); + BK(aw, ax); + + t1 = pclmulqdq11(aw, h1w); + t3 = pclmulqdq00(aw, h1w); + t2 = pclmulqdq00(ax, h1x); + t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3)); + t0 = _mm_shuffle_epi32(t1, 0x0E); + t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E)); + t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E)); + SL_256(t0, t1, t2, t3); + REDUCE_F128(t0, t1, t2, t3); + yw = _mm_unpacklo_epi64(t1, t0); + } + + BYTESWAP(yw); + _mm_storeu_si128(y, yw); +} + +BR_TARGETS_X86_DOWN + +#else + +/* see bearssl_hash.h */ +br_ghash +br_ghash_pclmul_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/hash/ghash_pwr8.c b/src/bearssl/src/hash/ghash_pwr8.c new file mode 100644 index 0000000..2e7b0f4 --- /dev/null +++ b/src/bearssl/src/hash/ghash_pwr8.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_POWER_ASM_MACROS 1 +#include "inner.h" + +/* + * This is the GHASH implementation that leverages the POWER8 opcodes. + */ + +#if BR_POWER8 + +/* + * Some symbolic names for registers. + * HB0 = 16 bytes of value 0 + * HB1 = 16 bytes of value 1 + * HB2 = 16 bytes of value 2 + * HB6 = 16 bytes of value 6 + * HB7 = 16 bytes of value 7 + * TT0, TT1 and TT2 are temporaries + * + * BSW holds the pattern for byteswapping 32-bit words; this is set only + * on little-endian systems. XBSW is the same register with the +32 offset + * for access with the VSX opcodes. + */ +#define HB0 0 +#define HB1 1 +#define HB2 2 +#define HB6 3 +#define HB7 4 +#define TT0 5 +#define TT1 6 +#define TT2 7 + +#define BSW 8 +#define XBSW 40 + +/* + * Macro to initialise the constants. + */ +#define INIT \ + vxor(HB0, HB0, HB0) \ + vspltisb(HB1, 1) \ + vspltisb(HB2, 2) \ + vspltisb(HB6, 6) \ + vspltisb(HB7, 7) \ + INIT_BSW + +/* + * Fix endianness of a value after reading it or before writing it, if + * necessary. + */ +#if BR_POWER8_LE +#define INIT_BSW lxvw4x(XBSW, 0, %[idx2be]) +#define FIX_ENDIAN(xx) vperm(xx, xx, xx, BSW) +#else +#define INIT_BSW +#define FIX_ENDIAN(xx) +#endif + +/* + * Left-shift x0:x1 by one bit to the left. This is a corrective action + * needed because GHASH is defined in full little-endian specification, + * while the opcodes use full big-endian convention, so the 255-bit product + * ends up one bit to the right. + */ +#define SL_256(x0, x1) \ + vsldoi(TT0, HB0, x1, 1) \ + vsl(x0, x0, HB1) \ + vsr(TT0, TT0, HB7) \ + vsl(x1, x1, HB1) \ + vxor(x0, x0, TT0) + +/* + * Reduce x0:x1 in GF(2^128), result in xd (register xd may be the same as + * x0 or x1, or a different register). x0 and x1 are modified. + */ +#define REDUCE_F128(xd, x0, x1) \ + vxor(x0, x0, x1) \ + vsr(TT0, x1, HB1) \ + vsr(TT1, x1, HB2) \ + vsr(TT2, x1, HB7) \ + vxor(x0, x0, TT0) \ + vxor(TT1, TT1, TT2) \ + vxor(x0, x0, TT1) \ + vsldoi(x1, x1, HB0, 15) \ + vsl(TT1, x1, HB6) \ + vsl(TT2, x1, HB1) \ + vxor(x1, TT1, TT2) \ + vsr(TT0, x1, HB1) \ + vsr(TT1, x1, HB2) \ + vsr(TT2, x1, HB7) \ + vxor(x0, x0, x1) \ + vxor(x0, x0, TT0) \ + vxor(TT1, TT1, TT2) \ + vxor(xd, x0, TT1) + +/* see bearssl_hash.h */ +void +br_ghash_pwr8(void *y, const void *h, const void *data, size_t len) +{ + const unsigned char *buf1, *buf2; + size_t num4, num1; + unsigned char tmp[64]; + long cc0, cc1, cc2, cc3; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + buf1 = data; + + /* + * Assembly code requires data into two chunks; first chunk + * must contain a number of blocks which is a multiple of 4. + * Since the processing for the first chunk is faster, we want + * to make it as big as possible. + * + * For the remainder, there are two possibilities: + * -- if the remainder size is a multiple of 16, then use it + * in place; + * -- otherwise, copy it to the tmp[] array and pad it with + * zeros. + */ + num4 = len >> 6; + buf2 = buf1 + (num4 << 6); + len &= 63; + num1 = (len + 15) >> 4; + if ((len & 15) != 0) { + memcpy(tmp, buf2, len); + memset(tmp + len, 0, (num1 << 4) - len); + buf2 = tmp; + } + + cc0 = 0; + cc1 = 16; + cc2 = 32; + cc3 = 48; + asm volatile ( + INIT + + /* + * Load current h (denoted hereafter h1) in v9. + */ + lxvw4x(41, 0, %[h]) + FIX_ENDIAN(9) + + /* + * Load current y into v28. + */ + lxvw4x(60, 0, %[y]) + FIX_ENDIAN(28) + + /* + * Split h1 into three registers: + * v17 = h1_1:h1_0 + * v18 = 0:h1_0 + * v19 = h1_1:0 + */ + xxpermdi(49, 41, 41, 2) + vsldoi(18, HB0, 9, 8) + vsldoi(19, 9, HB0, 8) + + /* + * If num4 is 0, skip directly to the second chunk. + */ + cmpldi(%[num4], 0) + beq(chunk1) + + /* + * Compute h2 = h*h in v10. + */ + vpmsumd(10, 18, 18) + vpmsumd(11, 19, 19) + SL_256(10, 11) + REDUCE_F128(10, 10, 11) + + /* + * Compute h3 = h*h*h in v11. + * We first split h2 into: + * v10 = h2_0:h2_1 + * v11 = 0:h2_0 + * v12 = h2_1:0 + * Then we do the product with h1, and reduce into v11. + */ + vsldoi(11, HB0, 10, 8) + vsldoi(12, 10, HB0, 8) + vpmsumd(13, 10, 17) + vpmsumd(11, 11, 18) + vpmsumd(12, 12, 19) + vsldoi(14, HB0, 13, 8) + vsldoi(15, 13, HB0, 8) + vxor(11, 11, 14) + vxor(12, 12, 15) + SL_256(11, 12) + REDUCE_F128(11, 11, 12) + + /* + * Compute h4 = h*h*h*h in v12. This is done by squaring h2. + */ + vsldoi(12, HB0, 10, 8) + vsldoi(13, 10, HB0, 8) + vpmsumd(12, 12, 12) + vpmsumd(13, 13, 13) + SL_256(12, 13) + REDUCE_F128(12, 12, 13) + + /* + * Repack h1, h2, h3 and h4: + * v13 = h4_0:h3_0 + * v14 = h4_1:h3_1 + * v15 = h2_0:h1_0 + * v16 = h2_1:h1_1 + */ + xxpermdi(45, 44, 43, 0) + xxpermdi(46, 44, 43, 3) + xxpermdi(47, 42, 41, 0) + xxpermdi(48, 42, 41, 3) + + /* + * Loop for each group of four blocks. + */ + mtctr(%[num4]) + label(loop4) + /* + * Read the four next blocks. + * v20 = y + a0 = b0 + * v21 = a1 = b1 + * v22 = a2 = b2 + * v23 = a3 = b3 + */ + lxvw4x(52, %[cc0], %[buf1]) + lxvw4x(53, %[cc1], %[buf1]) + lxvw4x(54, %[cc2], %[buf1]) + lxvw4x(55, %[cc3], %[buf1]) + FIX_ENDIAN(20) + FIX_ENDIAN(21) + FIX_ENDIAN(22) + FIX_ENDIAN(23) + addi(%[buf1], %[buf1], 64) + vxor(20, 20, 28) + + /* + * Repack the blocks into v9, v10, v11 and v12. + * v9 = b0_0:b1_0 + * v10 = b0_1:b1_1 + * v11 = b2_0:b3_0 + * v12 = b2_1:b3_1 + */ + xxpermdi(41, 52, 53, 0) + xxpermdi(42, 52, 53, 3) + xxpermdi(43, 54, 55, 0) + xxpermdi(44, 54, 55, 3) + + /* + * Compute the products. + * v20 = b0_0*h4_0 + b1_0*h3_0 + * v21 = b0_1*h4_0 + b1_1*h3_0 + * v22 = b0_0*h4_1 + b1_0*h3_1 + * v23 = b0_1*h4_1 + b1_1*h3_1 + * v24 = b2_0*h2_0 + b3_0*h1_0 + * v25 = b2_1*h2_0 + b3_1*h1_0 + * v26 = b2_0*h2_1 + b3_0*h1_1 + * v27 = b2_1*h2_1 + b3_1*h1_1 + */ + vpmsumd(20, 13, 9) + vpmsumd(21, 13, 10) + vpmsumd(22, 14, 9) + vpmsumd(23, 14, 10) + vpmsumd(24, 15, 11) + vpmsumd(25, 15, 12) + vpmsumd(26, 16, 11) + vpmsumd(27, 16, 12) + + /* + * Sum products into a single 256-bit result in v11:v12. + */ + vxor(11, 20, 24) + vxor(12, 23, 27) + vxor( 9, 21, 22) + vxor(10, 25, 26) + vxor(20, 9, 10) + vsldoi( 9, HB0, 20, 8) + vsldoi(10, 20, HB0, 8) + vxor(11, 11, 9) + vxor(12, 12, 10) + + /* + * Fix and reduce in GF(2^128); this is the new y (in v28). + */ + SL_256(11, 12) + REDUCE_F128(28, 11, 12) + + /* + * Loop for next group of four blocks. + */ + bdnz(loop4) + + /* + * Process second chunk, one block at a time. + */ + label(chunk1) + cmpldi(%[num1], 0) + beq(done) + + mtctr(%[num1]) + label(loop1) + /* + * Load next data block and XOR it into y. + */ + lxvw4x(41, 0, %[buf2]) +#if BR_POWER8_LE + FIX_ENDIAN(9) +#endif + addi(%[buf2], %[buf2], 16) + vxor(9, 28, 9) + + /* + * Split y into doublewords: + * v9 = y_0:y_1 + * v10 = 0:y_0 + * v11 = y_1:0 + */ + vsldoi(10, HB0, 9, 8) + vsldoi(11, 9, HB0, 8) + + /* + * Compute products with h: + * v12 = y_0 * h_0 + * v13 = y_1 * h_1 + * v14 = y_1 * h_0 + y_0 * h_1 + */ + vpmsumd(14, 9, 17) + vpmsumd(12, 10, 18) + vpmsumd(13, 11, 19) + + /* + * Propagate v14 into v12:v13 to finalise product. + */ + vsldoi(10, HB0, 14, 8) + vsldoi(11, 14, HB0, 8) + vxor(12, 12, 10) + vxor(13, 13, 11) + + /* + * Fix result and reduce into v28 (next value for y). + */ + SL_256(12, 13) + REDUCE_F128(28, 12, 13) + bdnz(loop1) + + label(done) + /* + * Write back the new y. + */ + FIX_ENDIAN(28) + stxvw4x(60, 0, %[y]) + +: [buf1] "+b" (buf1), [buf2] "+b" (buf2) +: [y] "b" (y), [h] "b" (h), [num4] "b" (num4), [num1] "b" (num1), + [cc0] "b" (cc0), [cc1] "b" (cc1), [cc2] "b" (cc2), [cc3] "b" (cc3) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", + "ctr", "memory" + ); +} + +/* see bearssl_hash.h */ +br_ghash +br_ghash_pwr8_get(void) +{ + return &br_ghash_pwr8; +} + +#else + +/* see bearssl_hash.h */ +br_ghash +br_ghash_pwr8_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/hash/md5.c b/src/bearssl/src/hash/md5.c new file mode 100644 index 0000000..0df7abe --- /dev/null +++ b/src/bearssl/src/hash/md5.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D)) +#define G(B, C, D) ((((C) ^ (B)) & (D)) ^ (C)) +#define H(B, C, D) ((B) ^ (C) ^ (D)) +#define I(B, C, D) ((C) ^ ((B) | ~(D))) + +#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +/* see inner.h */ +const uint32_t br_md5_IV[4] = { + 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 +}; + +static const uint32_t K[64] = { + 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, + 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, + 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, + 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821, + + 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, + 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, + 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, + 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A, + + 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, + 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, + 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, + 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665, + + 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, + 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, + 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, + 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391 +}; + +static const unsigned char MP[48] = { + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 +}; + +/* see inner.h */ +void +br_md5_round(const unsigned char *buf, uint32_t *val) +{ + uint32_t m[16]; + uint32_t a, b, c, d; + int i; + + a = val[0]; + b = val[1]; + c = val[2]; + d = val[3]; + /* obsolete + for (i = 0; i < 16; i ++) { + m[i] = br_dec32le(buf + (i << 2)); + } + */ + br_range_dec32le(m, 16, buf); + + for (i = 0; i < 16; i += 4) { + a = b + ROTL(a + F(b, c, d) + m[i + 0] + K[i + 0], 7); + d = a + ROTL(d + F(a, b, c) + m[i + 1] + K[i + 1], 12); + c = d + ROTL(c + F(d, a, b) + m[i + 2] + K[i + 2], 17); + b = c + ROTL(b + F(c, d, a) + m[i + 3] + K[i + 3], 22); + } + for (i = 16; i < 32; i += 4) { + a = b + ROTL(a + G(b, c, d) + m[MP[i - 16]] + K[i + 0], 5); + d = a + ROTL(d + G(a, b, c) + m[MP[i - 15]] + K[i + 1], 9); + c = d + ROTL(c + G(d, a, b) + m[MP[i - 14]] + K[i + 2], 14); + b = c + ROTL(b + G(c, d, a) + m[MP[i - 13]] + K[i + 3], 20); + } + for (i = 32; i < 48; i += 4) { + a = b + ROTL(a + H(b, c, d) + m[MP[i - 16]] + K[i + 0], 4); + d = a + ROTL(d + H(a, b, c) + m[MP[i - 15]] + K[i + 1], 11); + c = d + ROTL(c + H(d, a, b) + m[MP[i - 14]] + K[i + 2], 16); + b = c + ROTL(b + H(c, d, a) + m[MP[i - 13]] + K[i + 3], 23); + } + for (i = 48; i < 64; i += 4) { + a = b + ROTL(a + I(b, c, d) + m[MP[i - 16]] + K[i + 0], 6); + d = a + ROTL(d + I(a, b, c) + m[MP[i - 15]] + K[i + 1], 10); + c = d + ROTL(c + I(d, a, b) + m[MP[i - 14]] + K[i + 2], 15); + b = c + ROTL(b + I(c, d, a) + m[MP[i - 13]] + K[i + 3], 21); + } + + val[0] += a; + val[1] += b; + val[2] += c; + val[3] += d; +} + +/* see bearssl.h */ +void +br_md5_init(br_md5_context *cc) +{ + cc->vtable = &br_md5_vtable; + memcpy(cc->val, br_md5_IV, sizeof cc->val); + cc->count = 0; +} + +/* see bearssl.h */ +void +br_md5_update(br_md5_context *cc, const void *data, size_t len) +{ + const unsigned char *buf; + size_t ptr; + + buf = data; + ptr = (size_t)cc->count & 63; + while (len > 0) { + size_t clen; + + clen = 64 - ptr; + if (clen > len) { + clen = len; + } + memcpy(cc->buf + ptr, buf, clen); + ptr += clen; + buf += clen; + len -= clen; + cc->count += (uint64_t)clen; + if (ptr == 64) { + br_md5_round(cc->buf, cc->val); + ptr = 0; + } + } +} + +/* see bearssl.h */ +void +br_md5_out(const br_md5_context *cc, void *dst) +{ + unsigned char buf[64]; + uint32_t val[4]; + size_t ptr; + + ptr = (size_t)cc->count & 63; + memcpy(buf, cc->buf, ptr); + memcpy(val, cc->val, sizeof val); + buf[ptr ++] = 0x80; + if (ptr > 56) { + memset(buf + ptr, 0, 64 - ptr); + br_md5_round(buf, val); + memset(buf, 0, 56); + } else { + memset(buf + ptr, 0, 56 - ptr); + } + br_enc64le(buf + 56, cc->count << 3); + br_md5_round(buf, val); + br_range_enc32le(dst, val, 4); +} + +/* see bearssl.h */ +uint64_t +br_md5_state(const br_md5_context *cc, void *dst) +{ + br_range_enc32le(dst, cc->val, 4); + return cc->count; +} + +/* see bearssl.h */ +void +br_md5_set_state(br_md5_context *cc, const void *stb, uint64_t count) +{ + br_range_dec32le(cc->val, 4, stb); + cc->count = count; +} + +/* see bearssl.h */ +const br_hash_class br_md5_vtable = { + sizeof(br_md5_context), + BR_HASHDESC_ID(br_md5_ID) + | BR_HASHDESC_OUT(16) + | BR_HASHDESC_STATE(16) + | BR_HASHDESC_LBLEN(6) + | BR_HASHDESC_MD_PADDING, + (void (*)(const br_hash_class **))&br_md5_init, + (void (*)(const br_hash_class **, const void *, size_t))&br_md5_update, + (void (*)(const br_hash_class *const *, void *))&br_md5_out, + (uint64_t (*)(const br_hash_class *const *, void *))&br_md5_state, + (void (*)(const br_hash_class **, const void *, uint64_t)) + &br_md5_set_state +}; diff --git a/src/bearssl/src/hash/md5sha1.c b/src/bearssl/src/hash/md5sha1.c new file mode 100644 index 0000000..f701aee --- /dev/null +++ b/src/bearssl/src/hash/md5sha1.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl.h */ +void +br_md5sha1_init(br_md5sha1_context *cc) +{ + cc->vtable = &br_md5sha1_vtable; + memcpy(cc->val_md5, br_md5_IV, sizeof cc->val_md5); + memcpy(cc->val_sha1, br_sha1_IV, sizeof cc->val_sha1); + cc->count = 0; +} + +/* see bearssl.h */ +void +br_md5sha1_update(br_md5sha1_context *cc, const void *data, size_t len) +{ + const unsigned char *buf; + size_t ptr; + + buf = data; + ptr = (size_t)cc->count & 63; + while (len > 0) { + size_t clen; + + clen = 64 - ptr; + if (clen > len) { + clen = len; + } + memcpy(cc->buf + ptr, buf, clen); + ptr += clen; + buf += clen; + len -= clen; + cc->count += (uint64_t)clen; + if (ptr == 64) { + br_md5_round(cc->buf, cc->val_md5); + br_sha1_round(cc->buf, cc->val_sha1); + ptr = 0; + } + } +} + +/* see bearssl.h */ +void +br_md5sha1_out(const br_md5sha1_context *cc, void *dst) +{ + unsigned char buf[64]; + uint32_t val_md5[4]; + uint32_t val_sha1[5]; + size_t ptr; + unsigned char *out; + uint64_t count; + + count = cc->count; + ptr = (size_t)count & 63; + memcpy(buf, cc->buf, ptr); + memcpy(val_md5, cc->val_md5, sizeof val_md5); + memcpy(val_sha1, cc->val_sha1, sizeof val_sha1); + buf[ptr ++] = 0x80; + if (ptr > 56) { + memset(buf + ptr, 0, 64 - ptr); + br_md5_round(buf, val_md5); + br_sha1_round(buf, val_sha1); + memset(buf, 0, 56); + } else { + memset(buf + ptr, 0, 56 - ptr); + } + count <<= 3; + br_enc64le(buf + 56, count); + br_md5_round(buf, val_md5); + br_enc64be(buf + 56, count); + br_sha1_round(buf, val_sha1); + out = dst; + br_range_enc32le(out, val_md5, 4); + br_range_enc32be(out + 16, val_sha1, 5); +} + +/* see bearssl.h */ +uint64_t +br_md5sha1_state(const br_md5sha1_context *cc, void *dst) +{ + unsigned char *out; + + out = dst; + br_range_enc32le(out, cc->val_md5, 4); + br_range_enc32be(out + 16, cc->val_sha1, 5); + return cc->count; +} + +/* see bearssl.h */ +void +br_md5sha1_set_state(br_md5sha1_context *cc, const void *stb, uint64_t count) +{ + const unsigned char *buf; + + buf = stb; + br_range_dec32le(cc->val_md5, 4, buf); + br_range_dec32be(cc->val_sha1, 5, buf + 16); + cc->count = count; +} + +/* see bearssl.h */ +const br_hash_class br_md5sha1_vtable = { + sizeof(br_md5sha1_context), + BR_HASHDESC_ID(br_md5sha1_ID) + | BR_HASHDESC_OUT(36) + | BR_HASHDESC_STATE(36) + | BR_HASHDESC_LBLEN(6), + (void (*)(const br_hash_class **))&br_md5sha1_init, + (void (*)(const br_hash_class **, const void *, size_t)) + &br_md5sha1_update, + (void (*)(const br_hash_class *const *, void *)) + &br_md5sha1_out, + (uint64_t (*)(const br_hash_class *const *, void *)) + &br_md5sha1_state, + (void (*)(const br_hash_class **, const void *, uint64_t)) + &br_md5sha1_set_state +}; diff --git a/src/bearssl/src/hash/mgf1.c b/src/bearssl/src/hash/mgf1.c new file mode 100644 index 0000000..7a23588 --- /dev/null +++ b/src/bearssl/src/hash/mgf1.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_mgf1_xor(void *data, size_t len, + const br_hash_class *dig, const void *seed, size_t seed_len) +{ + unsigned char *buf; + size_t u, hlen; + uint32_t c; + + buf = data; + hlen = br_digest_size(dig); + for (u = 0, c = 0; u < len; u += hlen, c ++) { + br_hash_compat_context hc; + unsigned char tmp[64]; + size_t v; + + hc.vtable = dig; + dig->init(&hc.vtable); + dig->update(&hc.vtable, seed, seed_len); + br_enc32be(tmp, c); + dig->update(&hc.vtable, tmp, 4); + dig->out(&hc.vtable, tmp); + for (v = 0; v < hlen; v ++) { + if ((u + v) >= len) { + break; + } + buf[u + v] ^= tmp[v]; + } + } +} diff --git a/src/bearssl/src/hash/multihash.c b/src/bearssl/src/hash/multihash.c new file mode 100644 index 0000000..b6df2e0 --- /dev/null +++ b/src/bearssl/src/hash/multihash.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * An aggregate context that is large enough for all supported hash + * functions. + */ +typedef union { + const br_hash_class *vtable; + br_md5_context md5; + br_sha1_context sha1; + br_sha224_context sha224; + br_sha256_context sha256; + br_sha384_context sha384; + br_sha512_context sha512; +} gen_hash_context; + +/* + * Get the offset to the state for a specific hash function within the + * context structure. This shall be called only for the supported hash + * functions, + */ +static size_t +get_state_offset(int id) +{ + if (id >= 5) { + /* + * SHA-384 has id 5, and SHA-512 has id 6. Both use + * eight 64-bit words for their state. + */ + return offsetof(br_multihash_context, val_64) + + ((size_t)(id - 5) * (8 * sizeof(uint64_t))); + } else { + /* + * MD5 has id 1, SHA-1 has id 2, SHA-224 has id 3 and + * SHA-256 has id 4. They use 32-bit words for their + * states (4 words for MD5, 5 for SHA-1, 8 for SHA-224 + * and 8 for SHA-256). + */ + unsigned x; + + x = id - 1; + x = ((x + (x & (x >> 1))) << 2) + (x >> 1); + return offsetof(br_multihash_context, val_32) + + x * sizeof(uint32_t); + } +} + +/* see bearssl_hash.h */ +void +br_multihash_zero(br_multihash_context *ctx) +{ + /* + * This is not standard, but yields very short and efficient code, + * and it works "everywhere". + */ + memset(ctx, 0, sizeof *ctx); +} + +/* see bearssl_hash.h */ +void +br_multihash_init(br_multihash_context *ctx) +{ + int i; + + ctx->count = 0; + for (i = 1; i <= 6; i ++) { + const br_hash_class *hc; + + hc = ctx->impl[i - 1]; + if (hc != NULL) { + gen_hash_context g; + + hc->init(&g.vtable); + hc->state(&g.vtable, + (unsigned char *)ctx + get_state_offset(i)); + } + } +} + +/* see bearssl_hash.h */ +void +br_multihash_update(br_multihash_context *ctx, const void *data, size_t len) +{ + const unsigned char *buf; + size_t ptr; + + buf = data; + ptr = (size_t)ctx->count & 127; + while (len > 0) { + size_t clen; + + clen = 128 - ptr; + if (clen > len) { + clen = len; + } + memcpy(ctx->buf + ptr, buf, clen); + ptr += clen; + buf += clen; + len -= clen; + ctx->count += (uint64_t)clen; + if (ptr == 128) { + int i; + + for (i = 1; i <= 6; i ++) { + const br_hash_class *hc; + + hc = ctx->impl[i - 1]; + if (hc != NULL) { + gen_hash_context g; + unsigned char *state; + + state = (unsigned char *)ctx + + get_state_offset(i); + hc->set_state(&g.vtable, + state, ctx->count - 128); + hc->update(&g.vtable, ctx->buf, 128); + hc->state(&g.vtable, state); + } + } + ptr = 0; + } + } +} + +/* see bearssl_hash.h */ +size_t +br_multihash_out(const br_multihash_context *ctx, int id, void *dst) +{ + const br_hash_class *hc; + gen_hash_context g; + const unsigned char *state; + + hc = ctx->impl[id - 1]; + if (hc == NULL) { + return 0; + } + state = (const unsigned char *)ctx + get_state_offset(id); + hc->set_state(&g.vtable, state, ctx->count & ~(uint64_t)127); + hc->update(&g.vtable, ctx->buf, ctx->count & (uint64_t)127); + hc->out(&g.vtable, dst); + return (hc->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; +} diff --git a/src/bearssl/src/hash/sha1.c b/src/bearssl/src/hash/sha1.c new file mode 100644 index 0000000..4f65d84 --- /dev/null +++ b/src/bearssl/src/hash/sha1.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D)) +#define G(B, C, D) ((B) ^ (C) ^ (D)) +#define H(B, C, D) (((D) & (C)) | (((D) | (C)) & (B))) +#define I(B, C, D) G(B, C, D) + +#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define K1 ((uint32_t)0x5A827999) +#define K2 ((uint32_t)0x6ED9EBA1) +#define K3 ((uint32_t)0x8F1BBCDC) +#define K4 ((uint32_t)0xCA62C1D6) + +/* see inner.h */ +const uint32_t br_sha1_IV[5] = { + 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 +}; + +/* see inner.h */ +void +br_sha1_round(const unsigned char *buf, uint32_t *val) +{ + uint32_t m[80]; + uint32_t a, b, c, d, e; + int i; + + a = val[0]; + b = val[1]; + c = val[2]; + d = val[3]; + e = val[4]; + br_range_dec32be(m, 16, buf); + for (i = 16; i < 80; i ++) { + uint32_t x = m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]; + m[i] = ROTL(x, 1); + } + + for (i = 0; i < 20; i += 5) { + e += ROTL(a, 5) + F(b, c, d) + K1 + m[i + 0]; b = ROTL(b, 30); + d += ROTL(e, 5) + F(a, b, c) + K1 + m[i + 1]; a = ROTL(a, 30); + c += ROTL(d, 5) + F(e, a, b) + K1 + m[i + 2]; e = ROTL(e, 30); + b += ROTL(c, 5) + F(d, e, a) + K1 + m[i + 3]; d = ROTL(d, 30); + a += ROTL(b, 5) + F(c, d, e) + K1 + m[i + 4]; c = ROTL(c, 30); + } + for (i = 20; i < 40; i += 5) { + e += ROTL(a, 5) + G(b, c, d) + K2 + m[i + 0]; b = ROTL(b, 30); + d += ROTL(e, 5) + G(a, b, c) + K2 + m[i + 1]; a = ROTL(a, 30); + c += ROTL(d, 5) + G(e, a, b) + K2 + m[i + 2]; e = ROTL(e, 30); + b += ROTL(c, 5) + G(d, e, a) + K2 + m[i + 3]; d = ROTL(d, 30); + a += ROTL(b, 5) + G(c, d, e) + K2 + m[i + 4]; c = ROTL(c, 30); + } + for (i = 40; i < 60; i += 5) { + e += ROTL(a, 5) + H(b, c, d) + K3 + m[i + 0]; b = ROTL(b, 30); + d += ROTL(e, 5) + H(a, b, c) + K3 + m[i + 1]; a = ROTL(a, 30); + c += ROTL(d, 5) + H(e, a, b) + K3 + m[i + 2]; e = ROTL(e, 30); + b += ROTL(c, 5) + H(d, e, a) + K3 + m[i + 3]; d = ROTL(d, 30); + a += ROTL(b, 5) + H(c, d, e) + K3 + m[i + 4]; c = ROTL(c, 30); + } + for (i = 60; i < 80; i += 5) { + e += ROTL(a, 5) + I(b, c, d) + K4 + m[i + 0]; b = ROTL(b, 30); + d += ROTL(e, 5) + I(a, b, c) + K4 + m[i + 1]; a = ROTL(a, 30); + c += ROTL(d, 5) + I(e, a, b) + K4 + m[i + 2]; e = ROTL(e, 30); + b += ROTL(c, 5) + I(d, e, a) + K4 + m[i + 3]; d = ROTL(d, 30); + a += ROTL(b, 5) + I(c, d, e) + K4 + m[i + 4]; c = ROTL(c, 30); + } + + val[0] += a; + val[1] += b; + val[2] += c; + val[3] += d; + val[4] += e; +} + +/* see bearssl.h */ +void +br_sha1_init(br_sha1_context *cc) +{ + cc->vtable = &br_sha1_vtable; + memcpy(cc->val, br_sha1_IV, sizeof cc->val); + cc->count = 0; +} + +/* see bearssl.h */ +void +br_sha1_update(br_sha1_context *cc, const void *data, size_t len) +{ + const unsigned char *buf; + size_t ptr; + + buf = data; + ptr = (size_t)cc->count & 63; + while (len > 0) { + size_t clen; + + clen = 64 - ptr; + if (clen > len) { + clen = len; + } + memcpy(cc->buf + ptr, buf, clen); + ptr += clen; + buf += clen; + len -= clen; + cc->count += (uint64_t)clen; + if (ptr == 64) { + br_sha1_round(cc->buf, cc->val); + ptr = 0; + } + } +} + +/* see bearssl.h */ +void +br_sha1_out(const br_sha1_context *cc, void *dst) +{ + unsigned char buf[64]; + uint32_t val[5]; + size_t ptr; + + ptr = (size_t)cc->count & 63; + memcpy(buf, cc->buf, ptr); + memcpy(val, cc->val, sizeof val); + buf[ptr ++] = 0x80; + if (ptr > 56) { + memset(buf + ptr, 0, 64 - ptr); + br_sha1_round(buf, val); + memset(buf, 0, 56); + } else { + memset(buf + ptr, 0, 56 - ptr); + } + br_enc64be(buf + 56, cc->count << 3); + br_sha1_round(buf, val); + br_range_enc32be(dst, val, 5); +} + +/* see bearssl.h */ +uint64_t +br_sha1_state(const br_sha1_context *cc, void *dst) +{ + br_range_enc32be(dst, cc->val, 5); + return cc->count; +} + +/* see bearssl.h */ +void +br_sha1_set_state(br_sha1_context *cc, const void *stb, uint64_t count) +{ + br_range_dec32be(cc->val, 5, stb); + cc->count = count; +} + +/* see bearssl.h */ +const br_hash_class br_sha1_vtable = { + sizeof(br_sha1_context), + BR_HASHDESC_ID(br_sha1_ID) + | BR_HASHDESC_OUT(20) + | BR_HASHDESC_STATE(20) + | BR_HASHDESC_LBLEN(6) + | BR_HASHDESC_MD_PADDING + | BR_HASHDESC_MD_PADDING_BE, + (void (*)(const br_hash_class **))&br_sha1_init, + (void (*)(const br_hash_class **, const void *, size_t))&br_sha1_update, + (void (*)(const br_hash_class *const *, void *))&br_sha1_out, + (uint64_t (*)(const br_hash_class *const *, void *))&br_sha1_state, + (void (*)(const br_hash_class **, const void *, uint64_t)) + &br_sha1_set_state +}; diff --git a/src/bearssl/src/hash/sha2big.c b/src/bearssl/src/hash/sha2big.c new file mode 100644 index 0000000..5be92ed --- /dev/null +++ b/src/bearssl/src/hash/sha2big.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z)) +#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X))) + +#define ROTR(x, n) (((uint64_t)(x) << (64 - (n))) | ((uint64_t)(x) >> (n))) + +#define BSG5_0(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define BSG5_1(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) +#define SSG5_0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ (uint64_t)((x) >> 7)) +#define SSG5_1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ (uint64_t)((x) >> 6)) + +static const uint64_t IV384[8] = { + 0xCBBB9D5DC1059ED8, 0x629A292A367CD507, + 0x9159015A3070DD17, 0x152FECD8F70E5939, + 0x67332667FFC00B31, 0x8EB44A8768581511, + 0xDB0C2E0D64F98FA7, 0x47B5481DBEFA4FA4 +}; + +static const uint64_t IV512[8] = { + 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, + 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, + 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, + 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 +}; + +static const uint64_t K[80] = { + 0x428A2F98D728AE22, 0x7137449123EF65CD, + 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC, + 0x3956C25BF348B538, 0x59F111F1B605D019, + 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118, + 0xD807AA98A3030242, 0x12835B0145706FBE, + 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2, + 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, + 0x9BDC06A725C71235, 0xC19BF174CF692694, + 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, + 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65, + 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, + 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5, + 0x983E5152EE66DFAB, 0xA831C66D2DB43210, + 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4, + 0xC6E00BF33DA88FC2, 0xD5A79147930AA725, + 0x06CA6351E003826F, 0x142929670A0E6E70, + 0x27B70A8546D22FFC, 0x2E1B21385C26C926, + 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF, + 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, + 0x81C2C92E47EDAEE6, 0x92722C851482353B, + 0xA2BFE8A14CF10364, 0xA81A664BBC423001, + 0xC24B8B70D0F89791, 0xC76C51A30654BE30, + 0xD192E819D6EF5218, 0xD69906245565A910, + 0xF40E35855771202A, 0x106AA07032BBD1B8, + 0x19A4C116B8D2D0C8, 0x1E376C085141AB53, + 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8, + 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, + 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3, + 0x748F82EE5DEFB2FC, 0x78A5636F43172F60, + 0x84C87814A1F0AB72, 0x8CC702081A6439EC, + 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, + 0xBEF9A3F7B2C67915, 0xC67178F2E372532B, + 0xCA273ECEEA26619C, 0xD186B8C721C0C207, + 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178, + 0x06F067AA72176FBA, 0x0A637DC5A2C898A6, + 0x113F9804BEF90DAE, 0x1B710B35131C471B, + 0x28DB77F523047D84, 0x32CAAB7B40C72493, + 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C, + 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, + 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817 +}; + +static void +sha2big_round(const unsigned char *buf, uint64_t *val) +{ + +#define SHA2BIG_STEP(A, B, C, D, E, F, G, H, j) do { \ + uint64_t T1, T2; \ + T1 = H + BSG5_1(E) + CH(E, F, G) + K[j] + w[j]; \ + T2 = BSG5_0(A) + MAJ(A, B, C); \ + D += T1; \ + H = T1 + T2; \ + } while (0) + + int i; + uint64_t a, b, c, d, e, f, g, h; + uint64_t w[80]; + + br_range_dec64be(w, 16, buf); + for (i = 16; i < 80; i ++) { + w[i] = SSG5_1(w[i - 2]) + w[i - 7] + + SSG5_0(w[i - 15]) + w[i - 16]; + } + a = val[0]; + b = val[1]; + c = val[2]; + d = val[3]; + e = val[4]; + f = val[5]; + g = val[6]; + h = val[7]; + for (i = 0; i < 80; i += 8) { + SHA2BIG_STEP(a, b, c, d, e, f, g, h, i + 0); + SHA2BIG_STEP(h, a, b, c, d, e, f, g, i + 1); + SHA2BIG_STEP(g, h, a, b, c, d, e, f, i + 2); + SHA2BIG_STEP(f, g, h, a, b, c, d, e, i + 3); + SHA2BIG_STEP(e, f, g, h, a, b, c, d, i + 4); + SHA2BIG_STEP(d, e, f, g, h, a, b, c, i + 5); + SHA2BIG_STEP(c, d, e, f, g, h, a, b, i + 6); + SHA2BIG_STEP(b, c, d, e, f, g, h, a, i + 7); + } + val[0] += a; + val[1] += b; + val[2] += c; + val[3] += d; + val[4] += e; + val[5] += f; + val[6] += g; + val[7] += h; +} + +static void +sha2big_update(br_sha384_context *cc, const void *data, size_t len) +{ + const unsigned char *buf; + size_t ptr; + + buf = data; + ptr = (size_t)cc->count & 127; + cc->count += (uint64_t)len; + while (len > 0) { + size_t clen; + + clen = 128 - ptr; + if (clen > len) { + clen = len; + } + memcpy(cc->buf + ptr, buf, clen); + ptr += clen; + buf += clen; + len -= clen; + if (ptr == 128) { + sha2big_round(cc->buf, cc->val); + ptr = 0; + } + } +} + +static void +sha2big_out(const br_sha384_context *cc, void *dst, int num) +{ + unsigned char buf[128]; + uint64_t val[8]; + size_t ptr; + + ptr = (size_t)cc->count & 127; + memcpy(buf, cc->buf, ptr); + memcpy(val, cc->val, sizeof val); + buf[ptr ++] = 0x80; + if (ptr > 112) { + memset(buf + ptr, 0, 128 - ptr); + sha2big_round(buf, val); + memset(buf, 0, 112); + } else { + memset(buf + ptr, 0, 112 - ptr); + } + br_enc64be(buf + 112, cc->count >> 61); + br_enc64be(buf + 120, cc->count << 3); + sha2big_round(buf, val); + br_range_enc64be(dst, val, num); +} + +/* see bearssl.h */ +void +br_sha384_init(br_sha384_context *cc) +{ + cc->vtable = &br_sha384_vtable; + memcpy(cc->val, IV384, sizeof IV384); + cc->count = 0; +} + +/* see bearssl.h */ +void +br_sha384_update(br_sha384_context *cc, const void *data, size_t len) +{ + sha2big_update(cc, data, len); +} + +/* see bearssl.h */ +void +br_sha384_out(const br_sha384_context *cc, void *dst) +{ + sha2big_out(cc, dst, 6); +} + +/* see bearssl.h */ +uint64_t +br_sha384_state(const br_sha384_context *cc, void *dst) +{ + br_range_enc64be(dst, cc->val, 8); + return cc->count; +} + +/* see bearssl.h */ +void +br_sha384_set_state(br_sha384_context *cc, const void *stb, uint64_t count) +{ + br_range_dec64be(cc->val, 8, stb); + cc->count = count; +} + +/* see bearssl.h */ +void +br_sha512_init(br_sha512_context *cc) +{ + cc->vtable = &br_sha512_vtable; + memcpy(cc->val, IV512, sizeof IV512); + cc->count = 0; +} + +/* see bearssl.h */ +void +br_sha512_out(const br_sha512_context *cc, void *dst) +{ + sha2big_out(cc, dst, 8); +} + +/* see bearssl.h */ +const br_hash_class br_sha384_vtable = { + sizeof(br_sha384_context), + BR_HASHDESC_ID(br_sha384_ID) + | BR_HASHDESC_OUT(48) + | BR_HASHDESC_STATE(64) + | BR_HASHDESC_LBLEN(7) + | BR_HASHDESC_MD_PADDING + | BR_HASHDESC_MD_PADDING_BE + | BR_HASHDESC_MD_PADDING_128, + (void (*)(const br_hash_class **))&br_sha384_init, + (void (*)(const br_hash_class **, const void *, size_t)) + &br_sha384_update, + (void (*)(const br_hash_class *const *, void *))&br_sha384_out, + (uint64_t (*)(const br_hash_class *const *, void *))&br_sha384_state, + (void (*)(const br_hash_class **, const void *, uint64_t)) + &br_sha384_set_state +}; + +/* see bearssl.h */ +const br_hash_class br_sha512_vtable = { + sizeof(br_sha512_context), + BR_HASHDESC_ID(br_sha512_ID) + | BR_HASHDESC_OUT(64) + | BR_HASHDESC_STATE(64) + | BR_HASHDESC_LBLEN(7) + | BR_HASHDESC_MD_PADDING + | BR_HASHDESC_MD_PADDING_BE + | BR_HASHDESC_MD_PADDING_128, + (void (*)(const br_hash_class **))&br_sha512_init, + (void (*)(const br_hash_class **, const void *, size_t)) + &br_sha512_update, + (void (*)(const br_hash_class *const *, void *))&br_sha512_out, + (uint64_t (*)(const br_hash_class *const *, void *))&br_sha512_state, + (void (*)(const br_hash_class **, const void *, uint64_t)) + &br_sha512_set_state +}; diff --git a/src/bearssl/src/hash/sha2small.c b/src/bearssl/src/hash/sha2small.c new file mode 100644 index 0000000..ca19655 --- /dev/null +++ b/src/bearssl/src/hash/sha2small.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z)) +#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X))) + +#define ROTR(x, n) (((uint32_t)(x) << (32 - (n))) | ((uint32_t)(x) >> (n))) + +#define BSG2_0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define BSG2_1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SSG2_0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ (uint32_t)((x) >> 3)) +#define SSG2_1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ (uint32_t)((x) >> 10)) + +/* see inner.h */ +const uint32_t br_sha224_IV[8] = { + 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 +}; + +/* see inner.h */ +const uint32_t br_sha256_IV[8] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +static const uint32_t K[64] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 +}; + +/* see inner.h */ +void +br_sha2small_round(const unsigned char *buf, uint32_t *val) +{ + +#define SHA2_STEP(A, B, C, D, E, F, G, H, j) do { \ + uint32_t T1, T2; \ + T1 = H + BSG2_1(E) + CH(E, F, G) + K[j] + w[j]; \ + T2 = BSG2_0(A) + MAJ(A, B, C); \ + D += T1; \ + H = T1 + T2; \ + } while (0) + + int i; + uint32_t a, b, c, d, e, f, g, h; + uint32_t w[64]; + + br_range_dec32be(w, 16, buf); + for (i = 16; i < 64; i ++) { + w[i] = SSG2_1(w[i - 2]) + w[i - 7] + + SSG2_0(w[i - 15]) + w[i - 16]; + } + a = val[0]; + b = val[1]; + c = val[2]; + d = val[3]; + e = val[4]; + f = val[5]; + g = val[6]; + h = val[7]; + for (i = 0; i < 64; i += 8) { + SHA2_STEP(a, b, c, d, e, f, g, h, i + 0); + SHA2_STEP(h, a, b, c, d, e, f, g, i + 1); + SHA2_STEP(g, h, a, b, c, d, e, f, i + 2); + SHA2_STEP(f, g, h, a, b, c, d, e, i + 3); + SHA2_STEP(e, f, g, h, a, b, c, d, i + 4); + SHA2_STEP(d, e, f, g, h, a, b, c, i + 5); + SHA2_STEP(c, d, e, f, g, h, a, b, i + 6); + SHA2_STEP(b, c, d, e, f, g, h, a, i + 7); + } + val[0] += a; + val[1] += b; + val[2] += c; + val[3] += d; + val[4] += e; + val[5] += f; + val[6] += g; + val[7] += h; + +#if 0 +/* obsolete */ +#define SHA2_MEXP1(pc) do { \ + W[pc] = br_dec32be(buf + ((pc) << 2)); \ + } while (0) + +#define SHA2_MEXP2(pc) do { \ + W[(pc) & 0x0F] = SSG2_1(W[((pc) - 2) & 0x0F]) \ + + W[((pc) - 7) & 0x0F] \ + + SSG2_0(W[((pc) - 15) & 0x0F]) + W[(pc) & 0x0F]; \ + } while (0) + +#define SHA2_STEPn(n, a, b, c, d, e, f, g, h, pc) do { \ + uint32_t t1, t2; \ + SHA2_MEXP ## n(pc); \ + t1 = h + BSG2_1(e) + CH(e, f, g) \ + + K[pcount + (pc)] + W[(pc) & 0x0F]; \ + t2 = BSG2_0(a) + MAJ(a, b, c); \ + d += t1; \ + h = t1 + t2; \ + } while (0) + +#define SHA2_STEP1(a, b, c, d, e, f, g, h, pc) \ + SHA2_STEPn(1, a, b, c, d, e, f, g, h, pc) +#define SHA2_STEP2(a, b, c, d, e, f, g, h, pc) \ + SHA2_STEPn(2, a, b, c, d, e, f, g, h, pc) + + uint32_t A, B, C, D, E, F, G, H; + uint32_t W[16]; + unsigned pcount; + + A = val[0]; + B = val[1]; + C = val[2]; + D = val[3]; + E = val[4]; + F = val[5]; + G = val[6]; + H = val[7]; + pcount = 0; + SHA2_STEP1(A, B, C, D, E, F, G, H, 0); + SHA2_STEP1(H, A, B, C, D, E, F, G, 1); + SHA2_STEP1(G, H, A, B, C, D, E, F, 2); + SHA2_STEP1(F, G, H, A, B, C, D, E, 3); + SHA2_STEP1(E, F, G, H, A, B, C, D, 4); + SHA2_STEP1(D, E, F, G, H, A, B, C, 5); + SHA2_STEP1(C, D, E, F, G, H, A, B, 6); + SHA2_STEP1(B, C, D, E, F, G, H, A, 7); + SHA2_STEP1(A, B, C, D, E, F, G, H, 8); + SHA2_STEP1(H, A, B, C, D, E, F, G, 9); + SHA2_STEP1(G, H, A, B, C, D, E, F, 10); + SHA2_STEP1(F, G, H, A, B, C, D, E, 11); + SHA2_STEP1(E, F, G, H, A, B, C, D, 12); + SHA2_STEP1(D, E, F, G, H, A, B, C, 13); + SHA2_STEP1(C, D, E, F, G, H, A, B, 14); + SHA2_STEP1(B, C, D, E, F, G, H, A, 15); + for (pcount = 16; pcount < 64; pcount += 16) { + SHA2_STEP2(A, B, C, D, E, F, G, H, 0); + SHA2_STEP2(H, A, B, C, D, E, F, G, 1); + SHA2_STEP2(G, H, A, B, C, D, E, F, 2); + SHA2_STEP2(F, G, H, A, B, C, D, E, 3); + SHA2_STEP2(E, F, G, H, A, B, C, D, 4); + SHA2_STEP2(D, E, F, G, H, A, B, C, 5); + SHA2_STEP2(C, D, E, F, G, H, A, B, 6); + SHA2_STEP2(B, C, D, E, F, G, H, A, 7); + SHA2_STEP2(A, B, C, D, E, F, G, H, 8); + SHA2_STEP2(H, A, B, C, D, E, F, G, 9); + SHA2_STEP2(G, H, A, B, C, D, E, F, 10); + SHA2_STEP2(F, G, H, A, B, C, D, E, 11); + SHA2_STEP2(E, F, G, H, A, B, C, D, 12); + SHA2_STEP2(D, E, F, G, H, A, B, C, 13); + SHA2_STEP2(C, D, E, F, G, H, A, B, 14); + SHA2_STEP2(B, C, D, E, F, G, H, A, 15); + } + val[0] += A; + val[1] += B; + val[2] += C; + val[3] += D; + val[4] += E; + val[5] += F; + val[6] += G; + val[7] += H; +#endif +} + +static void +sha2small_update(br_sha224_context *cc, const void *data, size_t len) +{ + const unsigned char *buf; + size_t ptr; + + buf = data; + ptr = (size_t)cc->count & 63; + cc->count += (uint64_t)len; + while (len > 0) { + size_t clen; + + clen = 64 - ptr; + if (clen > len) { + clen = len; + } + memcpy(cc->buf + ptr, buf, clen); + ptr += clen; + buf += clen; + len -= clen; + if (ptr == 64) { + br_sha2small_round(cc->buf, cc->val); + ptr = 0; + } + } +} + +static void +sha2small_out(const br_sha224_context *cc, void *dst, int num) +{ + unsigned char buf[64]; + uint32_t val[8]; + size_t ptr; + + ptr = (size_t)cc->count & 63; + memcpy(buf, cc->buf, ptr); + memcpy(val, cc->val, sizeof val); + buf[ptr ++] = 0x80; + if (ptr > 56) { + memset(buf + ptr, 0, 64 - ptr); + br_sha2small_round(buf, val); + memset(buf, 0, 56); + } else { + memset(buf + ptr, 0, 56 - ptr); + } + br_enc64be(buf + 56, cc->count << 3); + br_sha2small_round(buf, val); + br_range_enc32be(dst, val, num); +} + +/* see bearssl.h */ +void +br_sha224_init(br_sha224_context *cc) +{ + cc->vtable = &br_sha224_vtable; + memcpy(cc->val, br_sha224_IV, sizeof cc->val); + cc->count = 0; +} + +/* see bearssl.h */ +void +br_sha224_update(br_sha224_context *cc, const void *data, size_t len) +{ + sha2small_update(cc, data, len); +} + +/* see bearssl.h */ +void +br_sha224_out(const br_sha224_context *cc, void *dst) +{ + sha2small_out(cc, dst, 7); +} + +/* see bearssl.h */ +uint64_t +br_sha224_state(const br_sha224_context *cc, void *dst) +{ + br_range_enc32be(dst, cc->val, 8); + return cc->count; +} + +/* see bearssl.h */ +void +br_sha224_set_state(br_sha224_context *cc, const void *stb, uint64_t count) +{ + br_range_dec32be(cc->val, 8, stb); + cc->count = count; +} + +/* see bearssl.h */ +void +br_sha256_init(br_sha256_context *cc) +{ + cc->vtable = &br_sha256_vtable; + memcpy(cc->val, br_sha256_IV, sizeof cc->val); + cc->count = 0; +} + +/* see bearssl.h */ +void +br_sha256_out(const br_sha256_context *cc, void *dst) +{ + sha2small_out(cc, dst, 8); +} + +/* see bearssl.h */ +const br_hash_class br_sha224_vtable = { + sizeof(br_sha224_context), + BR_HASHDESC_ID(br_sha224_ID) + | BR_HASHDESC_OUT(28) + | BR_HASHDESC_STATE(32) + | BR_HASHDESC_LBLEN(6) + | BR_HASHDESC_MD_PADDING + | BR_HASHDESC_MD_PADDING_BE, + (void (*)(const br_hash_class **))&br_sha224_init, + (void (*)(const br_hash_class **, + const void *, size_t))&br_sha224_update, + (void (*)(const br_hash_class *const *, void *))&br_sha224_out, + (uint64_t (*)(const br_hash_class *const *, void *))&br_sha224_state, + (void (*)(const br_hash_class **, const void *, uint64_t)) + &br_sha224_set_state +}; + +/* see bearssl.h */ +const br_hash_class br_sha256_vtable = { + sizeof(br_sha256_context), + BR_HASHDESC_ID(br_sha256_ID) + | BR_HASHDESC_OUT(32) + | BR_HASHDESC_STATE(32) + | BR_HASHDESC_LBLEN(6) + | BR_HASHDESC_MD_PADDING + | BR_HASHDESC_MD_PADDING_BE, + (void (*)(const br_hash_class **))&br_sha256_init, + (void (*)(const br_hash_class **, + const void *, size_t))&br_sha256_update, + (void (*)(const br_hash_class *const *, void *))&br_sha256_out, + (uint64_t (*)(const br_hash_class *const *, void *))&br_sha256_state, + (void (*)(const br_hash_class **, const void *, uint64_t)) + &br_sha256_set_state +}; diff --git a/src/bearssl/src/int/i15_add.c b/src/bearssl/src/int/i15_add.c new file mode 100644 index 0000000..97e29b8 --- /dev/null +++ b/src/bearssl/src/int/i15_add.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 31) >> 4; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw + bw + cc; + cc = naw >> 15; + a[u] = MUX(ctl, naw & 0x7FFF, aw); + } + return cc; +} diff --git a/src/bearssl/src/int/i15_bitlen.c b/src/bearssl/src/int/i15_bitlen.c new file mode 100644 index 0000000..ad74467 --- /dev/null +++ b/src/bearssl/src/int/i15_bitlen.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_bit_length(uint16_t *x, size_t xlen) +{ + uint32_t tw, twk; + + tw = 0; + twk = 0; + while (xlen -- > 0) { + uint32_t w, c; + + c = EQ(tw, 0); + w = x[xlen]; + tw = MUX(c, w, tw); + twk = MUX(c, (uint32_t)xlen, twk); + } + return (twk << 4) + BIT_LENGTH(tw); +} diff --git a/src/bearssl/src/int/i15_decmod.c b/src/bearssl/src/int/i15_decmod.c new file mode 100644 index 0000000..6076c57 --- /dev/null +++ b/src/bearssl/src/int/i15_decmod.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_decode_mod(uint16_t *x, const void *src, size_t len, const uint16_t *m) +{ + /* + * Two-pass algorithm: in the first pass, we determine whether the + * value fits; in the second pass, we do the actual write. + * + * During the first pass, 'r' contains the comparison result so + * far: + * 0x00000000 value is equal to the modulus + * 0x00000001 value is greater than the modulus + * 0xFFFFFFFF value is lower than the modulus + * + * Since we iterate starting with the least significant bytes (at + * the end of src[]), each new comparison overrides the previous + * except when the comparison yields 0 (equal). + * + * During the second pass, 'r' is either 0xFFFFFFFF (value fits) + * or 0x00000000 (value does not fit). + * + * We must iterate over all bytes of the source, _and_ possibly + * some extra virtual bytes (with value 0) so as to cover the + * complete modulus as well. We also add 4 such extra bytes beyond + * the modulus length because it then guarantees that no accumulated + * partial word remains to be processed. + */ + const unsigned char *buf; + size_t mlen, tlen; + int pass; + uint32_t r; + + buf = src; + mlen = (m[0] + 15) >> 4; + tlen = (mlen << 1); + if (tlen < len) { + tlen = len; + } + tlen += 4; + r = 0; + for (pass = 0; pass < 2; pass ++) { + size_t u, v; + uint32_t acc; + int acc_len; + + v = 1; + acc = 0; + acc_len = 0; + for (u = 0; u < tlen; u ++) { + uint32_t b; + + if (u < len) { + b = buf[len - 1 - u]; + } else { + b = 0; + } + acc |= (b << acc_len); + acc_len += 8; + if (acc_len >= 15) { + uint32_t xw; + + xw = acc & (uint32_t)0x7FFF; + acc_len -= 15; + acc = b >> (8 - acc_len); + if (v <= mlen) { + if (pass) { + x[v] = r & xw; + } else { + uint32_t cc; + + cc = (uint32_t)CMP(xw, m[v]); + r = MUX(EQ(cc, 0), r, cc); + } + } else { + if (!pass) { + r = MUX(EQ(xw, 0), r, 1); + } + } + v ++; + } + } + + /* + * When we reach this point at the end of the first pass: + * r is either 0, 1 or -1; we want to set r to 0 if it + * is equal to 0 or 1, and leave it to -1 otherwise. + * + * When we reach this point at the end of the second pass: + * r is either 0 or -1; we want to leave that value + * untouched. This is a subcase of the previous. + */ + r >>= 1; + r |= (r << 1); + } + + x[0] = m[0]; + return r & (uint32_t)1; +} diff --git a/src/bearssl/src/int/i15_decode.c b/src/bearssl/src/int/i15_decode.c new file mode 100644 index 0000000..fc2c0be --- /dev/null +++ b/src/bearssl/src/int/i15_decode.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_decode(uint16_t *x, const void *src, size_t len) +{ + const unsigned char *buf; + size_t v; + uint32_t acc; + int acc_len; + + buf = src; + v = 1; + acc = 0; + acc_len = 0; + while (len -- > 0) { + uint32_t b; + + b = buf[len]; + acc |= (b << acc_len); + acc_len += 8; + if (acc_len >= 15) { + x[v ++] = acc & 0x7FFF; + acc_len -= 15; + acc >>= 15; + } + } + if (acc_len != 0) { + x[v ++] = acc; + } + x[0] = br_i15_bit_length(x + 1, v - 1); +} diff --git a/src/bearssl/src/int/i15_decred.c b/src/bearssl/src/int/i15_decred.c new file mode 100644 index 0000000..81e7dd1 --- /dev/null +++ b/src/bearssl/src/int/i15_decred.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_decode_reduce(uint16_t *x, + const void *src, size_t len, const uint16_t *m) +{ + uint32_t m_ebitlen, m_rbitlen; + size_t mblen, k; + const unsigned char *buf; + uint32_t acc; + int acc_len; + + /* + * Get the encoded bit length. + */ + m_ebitlen = m[0]; + + /* + * Special case for an invalid (null) modulus. + */ + if (m_ebitlen == 0) { + x[0] = 0; + return; + } + + /* + * Clear the destination. + */ + br_i15_zero(x, m_ebitlen); + + /* + * First decode directly as many bytes as possible. This requires + * computing the actual bit length. + */ + m_rbitlen = m_ebitlen >> 4; + m_rbitlen = (m_ebitlen & 15) + (m_rbitlen << 4) - m_rbitlen; + mblen = (m_rbitlen + 7) >> 3; + k = mblen - 1; + if (k >= len) { + br_i15_decode(x, src, len); + x[0] = m_ebitlen; + return; + } + buf = src; + br_i15_decode(x, buf, k); + x[0] = m_ebitlen; + + /* + * Input remaining bytes, using 15-bit words. + */ + acc = 0; + acc_len = 0; + while (k < len) { + uint32_t v; + + v = buf[k ++]; + acc = (acc << 8) | v; + acc_len += 8; + if (acc_len >= 15) { + br_i15_muladd_small(x, acc >> (acc_len - 15), m); + acc_len -= 15; + acc &= ~((uint32_t)-1 << acc_len); + } + } + + /* + * We may have some bits accumulated. We then perform a shift to + * be able to inject these bits as a full 15-bit word. + */ + if (acc_len != 0) { + acc = (acc | (x[1] << acc_len)) & 0x7FFF; + br_i15_rshift(x, 15 - acc_len); + br_i15_muladd_small(x, acc, m); + } +} diff --git a/src/bearssl/src/int/i15_encode.c b/src/bearssl/src/int/i15_encode.c new file mode 100644 index 0000000..50668f4 --- /dev/null +++ b/src/bearssl/src/int/i15_encode.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_encode(void *dst, size_t len, const uint16_t *x) +{ + unsigned char *buf; + size_t u, xlen; + uint32_t acc; + int acc_len; + + xlen = (x[0] + 15) >> 4; + if (xlen == 0) { + memset(dst, 0, len); + return; + } + u = 1; + acc = 0; + acc_len = 0; + buf = dst; + while (len -- > 0) { + if (acc_len < 8) { + if (u <= xlen) { + acc += (uint32_t)x[u ++] << acc_len; + } + acc_len += 15; + } + buf[len] = (unsigned char)acc; + acc >>= 8; + acc_len -= 8; + } +} diff --git a/src/bearssl/src/int/i15_fmont.c b/src/bearssl/src/int/i15_fmont.c new file mode 100644 index 0000000..3450b72 --- /dev/null +++ b/src/bearssl/src/int/i15_fmont.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i) +{ + size_t len, u, v; + + len = (m[0] + 15) >> 4; + for (u = 0; u < len; u ++) { + uint32_t f, cc; + + f = MUL15(x[1], m0i) & 0x7FFF; + cc = 0; + for (v = 0; v < len; v ++) { + uint32_t z; + + z = (uint32_t)x[v + 1] + MUL15(f, m[v + 1]) + cc; + cc = z >> 15; + if (v != 0) { + x[v] = z & 0x7FFF; + } + } + x[len] = cc; + } + + /* + * We may have to do an extra subtraction, but only if the + * value in x[] is indeed greater than or equal to that of m[], + * which is why we must do two calls (first call computes the + * carry, second call performs the subtraction only if the carry + * is 0). + */ + br_i15_sub(x, m, NOT(br_i15_sub(x, m, 0))); +} diff --git a/src/bearssl/src/int/i15_iszero.c b/src/bearssl/src/int/i15_iszero.c new file mode 100644 index 0000000..d4b6f10 --- /dev/null +++ b/src/bearssl/src/int/i15_iszero.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_iszero(const uint16_t *x) +{ + uint32_t z; + size_t u; + + z = 0; + for (u = (x[0] + 15) >> 4; u > 0; u --) { + z |= x[u]; + } + return ~(z | -z) >> 31; +} diff --git a/src/bearssl/src/int/i15_moddiv.c b/src/bearssl/src/int/i15_moddiv.c new file mode 100644 index 0000000..45af756 --- /dev/null +++ b/src/bearssl/src/int/i15_moddiv.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * In this file, we handle big integers with a custom format, i.e. + * without the usual one-word header. Value is split into 15-bit words, + * each stored in a 16-bit slot (top bit is zero) in little-endian + * order. The length (in words) is provided explicitly. In some cases, + * the value can be negative (using two's complement representation). In + * some cases, the top word is allowed to have a 16th bit. + */ + +/* + * Negate big integer conditionally. The value consists of 'len' words, + * with 15 bits in each word (the top bit of each word should be 0, + * except possibly for the last word). If 'ctl' is 1, the negation is + * computed; otherwise, if 'ctl' is 0, then the value is unchanged. + */ +static void +cond_negate(uint16_t *a, size_t len, uint32_t ctl) +{ + size_t k; + uint32_t cc, xm; + + cc = ctl; + xm = 0x7FFF & -ctl; + for (k = 0; k < len; k ++) { + uint32_t aw; + + aw = a[k]; + aw = (aw ^ xm) + cc; + a[k] = aw & 0x7FFF; + cc = (aw >> 15) & 1; + } +} + +/* + * Finish modular reduction. Rules on input parameters: + * + * if neg = 1, then -m <= a < 0 + * if neg = 0, then 0 <= a < 2*m + * + * If neg = 0, then the top word of a[] may use 16 bits. + * + * Also, modulus m must be odd. + */ +static void +finish_mod(uint16_t *a, size_t len, const uint16_t *m, uint32_t neg) +{ + size_t k; + uint32_t cc, xm, ym; + + /* + * First pass: compare a (assumed nonnegative) with m. + */ + cc = 0; + for (k = 0; k < len; k ++) { + uint32_t aw, mw; + + aw = a[k]; + mw = m[k]; + cc = (aw - mw - cc) >> 31; + } + + /* + * At this point: + * if neg = 1, then we must add m (regardless of cc) + * if neg = 0 and cc = 0, then we must subtract m + * if neg = 0 and cc = 1, then we must do nothing + */ + xm = 0x7FFF & -neg; + ym = -(neg | (1 - cc)); + cc = neg; + for (k = 0; k < len; k ++) { + uint32_t aw, mw; + + aw = a[k]; + mw = (m[k] ^ xm) & ym; + aw = aw - mw - cc; + a[k] = aw & 0x7FFF; + cc = aw >> 31; + } +} + +/* + * Compute: + * a <- (a*pa+b*pb)/(2^15) + * b <- (a*qa+b*qb)/(2^15) + * The division is assumed to be exact (i.e. the low word is dropped). + * If the final a is negative, then it is negated. Similarly for b. + * Returned value is the combination of two bits: + * bit 0: 1 if a had to be negated, 0 otherwise + * bit 1: 1 if b had to be negated, 0 otherwise + * + * Factors pa, pb, qa and qb must be at most 2^15 in absolute value. + * Source integers a and b must be nonnegative; top word is not allowed + * to contain an extra 16th bit. + */ +static uint32_t +co_reduce(uint16_t *a, uint16_t *b, size_t len, + int32_t pa, int32_t pb, int32_t qa, int32_t qb) +{ + size_t k; + int32_t cca, ccb; + uint32_t nega, negb; + + cca = 0; + ccb = 0; + for (k = 0; k < len; k ++) { + uint32_t wa, wb, za, zb; + uint16_t tta, ttb; + + /* + * Since: + * |pa| <= 2^15 + * |pb| <= 2^15 + * 0 <= wa <= 2^15 - 1 + * 0 <= wb <= 2^15 - 1 + * |cca| <= 2^16 - 1 + * Then: + * |za| <= (2^15-1)*(2^16) + (2^16-1) = 2^31 - 1 + * + * Thus, the new value of cca is such that |cca| <= 2^16 - 1. + * The same applies to ccb. + */ + wa = a[k]; + wb = b[k]; + za = wa * (uint32_t)pa + wb * (uint32_t)pb + (uint32_t)cca; + zb = wa * (uint32_t)qa + wb * (uint32_t)qb + (uint32_t)ccb; + if (k > 0) { + a[k - 1] = za & 0x7FFF; + b[k - 1] = zb & 0x7FFF; + } + tta = za >> 15; + ttb = zb >> 15; + cca = *(int16_t *)&tta; + ccb = *(int16_t *)&ttb; + } + a[len - 1] = (uint16_t)cca; + b[len - 1] = (uint16_t)ccb; + nega = (uint32_t)cca >> 31; + negb = (uint32_t)ccb >> 31; + cond_negate(a, len, nega); + cond_negate(b, len, negb); + return nega | (negb << 1); +} + +/* + * Compute: + * a <- (a*pa+b*pb)/(2^15) mod m + * b <- (a*qa+b*qb)/(2^15) mod m + * + * m0i is equal to -1/m[0] mod 2^15. + * + * Factors pa, pb, qa and qb must be at most 2^15 in absolute value. + * Source integers a and b must be nonnegative; top word is not allowed + * to contain an extra 16th bit. + */ +static void +co_reduce_mod(uint16_t *a, uint16_t *b, size_t len, + int32_t pa, int32_t pb, int32_t qa, int32_t qb, + const uint16_t *m, uint16_t m0i) +{ + size_t k; + int32_t cca, ccb, fa, fb; + + cca = 0; + ccb = 0; + fa = ((a[0] * (uint32_t)pa + b[0] * (uint32_t)pb) * m0i) & 0x7FFF; + fb = ((a[0] * (uint32_t)qa + b[0] * (uint32_t)qb) * m0i) & 0x7FFF; + for (k = 0; k < len; k ++) { + uint32_t wa, wb, za, zb; + uint32_t tta, ttb; + + /* + * In this loop, carries 'cca' and 'ccb' always fit on + * 17 bits (in absolute value). + */ + wa = a[k]; + wb = b[k]; + za = wa * (uint32_t)pa + wb * (uint32_t)pb + + m[k] * (uint32_t)fa + (uint32_t)cca; + zb = wa * (uint32_t)qa + wb * (uint32_t)qb + + m[k] * (uint32_t)fb + (uint32_t)ccb; + if (k > 0) { + a[k - 1] = za & 0x7FFF; + b[k - 1] = zb & 0x7FFF; + } + + /* + * The XOR-and-sub construction below does an arithmetic + * right shift in a portable way (technically, right-shifting + * a negative signed value is implementation-defined in C). + */ +#define M ((uint32_t)1 << 16) + tta = za >> 15; + ttb = zb >> 15; + tta = (tta ^ M) - M; + ttb = (ttb ^ M) - M; + cca = *(int32_t *)&tta; + ccb = *(int32_t *)&ttb; +#undef M + } + a[len - 1] = (uint32_t)cca; + b[len - 1] = (uint32_t)ccb; + + /* + * At this point: + * -m <= a < 2*m + * -m <= b < 2*m + * (this is a case of Montgomery reduction) + * The top word of 'a' and 'b' may have a 16-th bit set. + * We may have to add or subtract the modulus. + */ + finish_mod(a, len, m, (uint32_t)cca >> 31); + finish_mod(b, len, m, (uint32_t)ccb >> 31); +} + +/* see inner.h */ +uint32_t +br_i15_moddiv(uint16_t *x, const uint16_t *y, const uint16_t *m, uint16_t m0i, + uint16_t *t) +{ + /* + * Algorithm is an extended binary GCD. We maintain four values + * a, b, u and v, with the following invariants: + * + * a * x = y * u mod m + * b * x = y * v mod m + * + * Starting values are: + * + * a = y + * b = m + * u = x + * v = 0 + * + * The formal definition of the algorithm is a sequence of steps: + * + * - If a is even, then a <- a/2 and u <- u/2 mod m. + * - Otherwise, if b is even, then b <- b/2 and v <- v/2 mod m. + * - Otherwise, if a > b, then a <- (a-b)/2 and u <- (u-v)/2 mod m. + * - Otherwise, b <- (b-a)/2 and v <- (v-u)/2 mod m. + * + * Algorithm stops when a = b. At that point, they both are equal + * to GCD(y,m); the modular division succeeds if that value is 1. + * The result of the modular division is then u (or v: both are + * equal at that point). + * + * Each step makes either a or b shrink by at least one bit; hence, + * if m has bit length k bits, then 2k-2 steps are sufficient. + * + * + * Though complexity is quadratic in the size of m, the bit-by-bit + * processing is not very efficient. We can speed up processing by + * remarking that the decisions are taken based only on observation + * of the top and low bits of a and b. + * + * In the loop below, at each iteration, we use the two top words + * of a and b, and the low words of a and b, to compute reduction + * parameters pa, pb, qa and qb such that the new values for a + * and b are: + * + * a' = (a*pa + b*pb) / (2^15) + * b' = (a*qa + b*qb) / (2^15) + * + * the division being exact. + * + * Since the choices are based on the top words, they may be slightly + * off, requiring an optional correction: if a' < 0, then we replace + * pa with -pa, and pb with -pb. The total length of a and b is + * thus reduced by at least 14 bits at each iteration. + * + * The stopping conditions are still the same, though: when a + * and b become equal, they must be both odd (since m is odd, + * the GCD cannot be even), therefore the next operation is a + * subtraction, and one of the values becomes 0. At that point, + * nothing else happens, i.e. one value is stuck at 0, and the + * other one is the GCD. + */ + size_t len, k; + uint16_t *a, *b, *u, *v; + uint32_t num, r; + + len = (m[0] + 15) >> 4; + a = t; + b = a + len; + u = x + 1; + v = b + len; + memcpy(a, y + 1, len * sizeof *y); + memcpy(b, m + 1, len * sizeof *m); + memset(v, 0, len * sizeof *v); + + /* + * Loop below ensures that a and b are reduced by some bits each, + * for a total of at least 14 bits. + */ + for (num = ((m[0] - (m[0] >> 4)) << 1) + 14; num >= 14; num -= 14) { + size_t j; + uint32_t c0, c1; + uint32_t a0, a1, b0, b1; + uint32_t a_hi, b_hi, a_lo, b_lo; + int32_t pa, pb, qa, qb; + int i; + + /* + * Extract top words of a and b. If j is the highest + * index >= 1 such that a[j] != 0 or b[j] != 0, then we want + * (a[j] << 15) + a[j - 1], and (b[j] << 15) + b[j - 1]. + * If a and b are down to one word each, then we use a[0] + * and b[0]. + */ + c0 = (uint32_t)-1; + c1 = (uint32_t)-1; + a0 = 0; + a1 = 0; + b0 = 0; + b1 = 0; + j = len; + while (j -- > 0) { + uint32_t aw, bw; + + aw = a[j]; + bw = b[j]; + a0 ^= (a0 ^ aw) & c0; + a1 ^= (a1 ^ aw) & c1; + b0 ^= (b0 ^ bw) & c0; + b1 ^= (b1 ^ bw) & c1; + c1 = c0; + c0 &= (((aw | bw) + 0xFFFF) >> 16) - (uint32_t)1; + } + + /* + * If c1 = 0, then we grabbed two words for a and b. + * If c1 != 0 but c0 = 0, then we grabbed one word. It + * is not possible that c1 != 0 and c0 != 0, because that + * would mean that both integers are zero. + */ + a1 |= a0 & c1; + a0 &= ~c1; + b1 |= b0 & c1; + b0 &= ~c1; + a_hi = (a0 << 15) + a1; + b_hi = (b0 << 15) + b1; + a_lo = a[0]; + b_lo = b[0]; + + /* + * Compute reduction factors: + * + * a' = a*pa + b*pb + * b' = a*qa + b*qb + * + * such that a' and b' are both multiple of 2^15, but are + * only marginally larger than a and b. + */ + pa = 1; + pb = 0; + qa = 0; + qb = 1; + for (i = 0; i < 15; i ++) { + /* + * At each iteration: + * + * a <- (a-b)/2 if: a is odd, b is odd, a_hi > b_hi + * b <- (b-a)/2 if: a is odd, b is odd, a_hi <= b_hi + * a <- a/2 if: a is even + * b <- b/2 if: a is odd, b is even + * + * We multiply a_lo and b_lo by 2 at each + * iteration, thus a division by 2 really is a + * non-multiplication by 2. + */ + uint32_t r, oa, ob, cAB, cBA, cA; + + /* + * cAB = 1 if b must be subtracted from a + * cBA = 1 if a must be subtracted from b + * cA = 1 if a is divided by 2, 0 otherwise + * + * Rules: + * + * cAB and cBA cannot be both 1. + * if a is not divided by 2, b is. + */ + r = GT(a_hi, b_hi); + oa = (a_lo >> i) & 1; + ob = (b_lo >> i) & 1; + cAB = oa & ob & r; + cBA = oa & ob & NOT(r); + cA = cAB | NOT(oa); + + /* + * Conditional subtractions. + */ + a_lo -= b_lo & -cAB; + a_hi -= b_hi & -cAB; + pa -= qa & -(int32_t)cAB; + pb -= qb & -(int32_t)cAB; + b_lo -= a_lo & -cBA; + b_hi -= a_hi & -cBA; + qa -= pa & -(int32_t)cBA; + qb -= pb & -(int32_t)cBA; + + /* + * Shifting. + */ + a_lo += a_lo & (cA - 1); + pa += pa & ((int32_t)cA - 1); + pb += pb & ((int32_t)cA - 1); + a_hi ^= (a_hi ^ (a_hi >> 1)) & -cA; + b_lo += b_lo & -cA; + qa += qa & -(int32_t)cA; + qb += qb & -(int32_t)cA; + b_hi ^= (b_hi ^ (b_hi >> 1)) & (cA - 1); + } + + /* + * Replace a and b with new values a' and b'. + */ + r = co_reduce(a, b, len, pa, pb, qa, qb); + pa -= pa * ((r & 1) << 1); + pb -= pb * ((r & 1) << 1); + qa -= qa * (r & 2); + qb -= qb * (r & 2); + co_reduce_mod(u, v, len, pa, pb, qa, qb, m + 1, m0i); + } + + /* + * Now one of the arrays should be 0, and the other contains + * the GCD. If a is 0, then u is 0 as well, and v contains + * the division result. + * Result is correct if and only if GCD is 1. + */ + r = (a[0] | b[0]) ^ 1; + u[0] |= v[0]; + for (k = 1; k < len; k ++) { + r |= a[k] | b[k]; + u[k] |= v[k]; + } + return EQ0(r); +} diff --git a/src/bearssl/src/int/i15_modpow.c b/src/bearssl/src/int/i15_modpow.c new file mode 100644 index 0000000..9bf304e --- /dev/null +++ b/src/bearssl/src/int/i15_modpow.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_modpow(uint16_t *x, + const unsigned char *e, size_t elen, + const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2) +{ + size_t mlen; + unsigned k; + + mlen = ((m[0] + 31) >> 4) * sizeof m[0]; + memcpy(t1, x, mlen); + br_i15_to_monty(t1, m); + br_i15_zero(x, m[0]); + x[1] = 1; + for (k = 0; k < ((unsigned)elen << 3); k ++) { + uint32_t ctl; + + ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1; + br_i15_montymul(t2, x, t1, m, m0i); + CCOPY(ctl, x, t2, mlen); + br_i15_montymul(t2, t1, t1, m, m0i); + memcpy(t1, t2, mlen); + } +} diff --git a/src/bearssl/src/int/i15_modpow2.c b/src/bearssl/src/int/i15_modpow2.c new file mode 100644 index 0000000..4b32118 --- /dev/null +++ b/src/bearssl/src/int/i15_modpow2.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_modpow_opt(uint16_t *x, + const unsigned char *e, size_t elen, + const uint16_t *m, uint16_t m0i, uint16_t *tmp, size_t twlen) +{ + size_t mlen, mwlen; + uint16_t *t1, *t2, *base; + size_t u, v; + uint32_t acc; + int acc_len, win_len; + + /* + * Get modulus size. + */ + mwlen = (m[0] + 31) >> 4; + mlen = mwlen * sizeof m[0]; + mwlen += (mwlen & 1); + t1 = tmp; + t2 = tmp + mwlen; + + /* + * Compute possible window size, with a maximum of 5 bits. + * When the window has size 1 bit, we use a specific code + * that requires only two temporaries. Otherwise, for a + * window of k bits, we need 2^k+1 temporaries. + */ + if (twlen < (mwlen << 1)) { + return 0; + } + for (win_len = 5; win_len > 1; win_len --) { + if ((((uint32_t)1 << win_len) + 1) * mwlen <= twlen) { + break; + } + } + + /* + * Everything is done in Montgomery representation. + */ + br_i15_to_monty(x, m); + + /* + * Compute window contents. If the window has size one bit only, + * then t2 is set to x; otherwise, t2[0] is left untouched, and + * t2[k] is set to x^k (for k >= 1). + */ + if (win_len == 1) { + memcpy(t2, x, mlen); + } else { + memcpy(t2 + mwlen, x, mlen); + base = t2 + mwlen; + for (u = 2; u < ((unsigned)1 << win_len); u ++) { + br_i15_montymul(base + mwlen, base, x, m, m0i); + base += mwlen; + } + } + + /* + * We need to set x to 1, in Montgomery representation. This can + * be done efficiently by setting the high word to 1, then doing + * one word-sized shift. + */ + br_i15_zero(x, m[0]); + x[(m[0] + 15) >> 4] = 1; + br_i15_muladd_small(x, 0, m); + + /* + * We process bits from most to least significant. At each + * loop iteration, we have acc_len bits in acc. + */ + acc = 0; + acc_len = 0; + while (acc_len > 0 || elen > 0) { + int i, k; + uint32_t bits; + + /* + * Get the next bits. + */ + k = win_len; + if (acc_len < win_len) { + if (elen > 0) { + acc = (acc << 8) | *e ++; + elen --; + acc_len += 8; + } else { + k = acc_len; + } + } + bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1); + acc_len -= k; + + /* + * We could get exactly k bits. Compute k squarings. + */ + for (i = 0; i < k; i ++) { + br_i15_montymul(t1, x, x, m, m0i); + memcpy(x, t1, mlen); + } + + /* + * Window lookup: we want to set t2 to the window + * lookup value, assuming the bits are non-zero. If + * the window length is 1 bit only, then t2 is + * already set; otherwise, we do a constant-time lookup. + */ + if (win_len > 1) { + br_i15_zero(t2, m[0]); + base = t2 + mwlen; + for (u = 1; u < ((uint32_t)1 << k); u ++) { + uint32_t mask; + + mask = -EQ(u, bits); + for (v = 1; v < mwlen; v ++) { + t2[v] |= mask & base[v]; + } + base += mwlen; + } + } + + /* + * Multiply with the looked-up value. We keep the + * product only if the exponent bits are not all-zero. + */ + br_i15_montymul(t1, x, t2, m, m0i); + CCOPY(NEQ(bits, 0), x, t1, mlen); + } + + /* + * Convert back from Montgomery representation, and exit. + */ + br_i15_from_monty(x, m, m0i); + return 1; +} diff --git a/src/bearssl/src/int/i15_montmul.c b/src/bearssl/src/int/i15_montmul.c new file mode 100644 index 0000000..e98bc32 --- /dev/null +++ b/src/bearssl/src/int/i15_montmul.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y, + const uint16_t *m, uint16_t m0i) +{ + size_t len, len4, u, v; + uint32_t dh; + + len = (m[0] + 15) >> 4; + len4 = len & ~(size_t)3; + br_i15_zero(d, m[0]); + dh = 0; + for (u = 0; u < len; u ++) { + uint32_t f, xu, r, zh; + + xu = x[u + 1]; + f = MUL15((d[1] + MUL15(x[u + 1], y[1])) & 0x7FFF, m0i) + & 0x7FFF; +#if BR_ARMEL_CORTEXM_GCC + if (len4 != 0) { + uint16_t *limit; + + limit = d + len4; + asm volatile ( +"\n\ + @ carry: r=r2 \n\ + @ multipliers: xu=r3 f=r4 \n\ + @ base registers: d+v=r5 y+v=r6 m+v=r7 \n\ + @ r8 contains 0x7FFF \n\ + @ r9 contains d+len4 \n\ + ldr r0, %[limit] \n\ + ldr r3, %[xu] \n\ + mov r9, r0 \n\ + ldr r4, %[f] \n\ + eor r2, r2 \n\ + ldr r5, %[d] \n\ + sub r1, r2, #1 \n\ + ldr r6, %[y] \n\ + lsr r1, r1, #17 \n\ + ldr r7, %[m] \n\ + mov r8, r1 \n\ +loop%=: \n\ + ldrh r0, [r6, #2] \n\ + ldrh r1, [r7, #2] \n\ + mul r0, r3 \n\ + mul r1, r4 \n\ + add r2, r0, r2 \n\ + ldrh r0, [r5, #2] \n\ + add r2, r1, r2 \n\ + mov r1, r8 \n\ + add r2, r0, r2 \n\ + and r1, r2 \n\ + lsr r2, r2, #15 \n\ + strh r1, [r5, #0] \n\ + \n\ + ldrh r0, [r6, #4] \n\ + ldrh r1, [r7, #4] \n\ + mul r0, r3 \n\ + mul r1, r4 \n\ + add r2, r0, r2 \n\ + ldrh r0, [r5, #4] \n\ + add r2, r1, r2 \n\ + mov r1, r8 \n\ + add r2, r0, r2 \n\ + and r1, r2 \n\ + lsr r2, r2, #15 \n\ + strh r1, [r5, #2] \n\ + \n\ + ldrh r0, [r6, #6] \n\ + ldrh r1, [r7, #6] \n\ + mul r0, r3 \n\ + mul r1, r4 \n\ + add r2, r0, r2 \n\ + ldrh r0, [r5, #6] \n\ + add r2, r1, r2 \n\ + mov r1, r8 \n\ + add r2, r0, r2 \n\ + and r1, r2 \n\ + lsr r2, r2, #15 \n\ + strh r1, [r5, #4] \n\ + \n\ + ldrh r0, [r6, #8] \n\ + ldrh r1, [r7, #8] \n\ + mul r0, r3 \n\ + mul r1, r4 \n\ + add r2, r0, r2 \n\ + ldrh r0, [r5, #8] \n\ + add r2, r1, r2 \n\ + mov r1, r8 \n\ + add r2, r0, r2 \n\ + and r1, r2 \n\ + lsr r2, r2, #15 \n\ + strh r1, [r5, #6] \n\ + \n\ + add r5, r5, #8 \n\ + add r6, r6, #8 \n\ + add r7, r7, #8 \n\ + cmp r5, r9 \n\ + bne loop%= \n\ + \n\ + str r2, %[carry] \n\ +" +: [carry] "=m" (r) +: [xu] "m" (xu), [f] "m" (f), [d] "m" (d), [y] "m" (y), + [m] "m" (m), [limit] "m" (limit) +: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + } else { + r = 0; + } + v = len4; +#else + r = 0; + for (v = 0; v < len4; v += 4) { + uint32_t z; + + z = d[v + 1] + MUL15(xu, y[v + 1]) + + MUL15(f, m[v + 1]) + r; + r = z >> 15; + d[v + 0] = z & 0x7FFF; + z = d[v + 2] + MUL15(xu, y[v + 2]) + + MUL15(f, m[v + 2]) + r; + r = z >> 15; + d[v + 1] = z & 0x7FFF; + z = d[v + 3] + MUL15(xu, y[v + 3]) + + MUL15(f, m[v + 3]) + r; + r = z >> 15; + d[v + 2] = z & 0x7FFF; + z = d[v + 4] + MUL15(xu, y[v + 4]) + + MUL15(f, m[v + 4]) + r; + r = z >> 15; + d[v + 3] = z & 0x7FFF; + } +#endif + for (; v < len; v ++) { + uint32_t z; + + z = d[v + 1] + MUL15(xu, y[v + 1]) + + MUL15(f, m[v + 1]) + r; + r = z >> 15; + d[v + 0] = z & 0x7FFF; + } + + zh = dh + r; + d[len] = zh & 0x7FFF; + dh = zh >> 15; + } + + /* + * Restore the bit length (it was overwritten in the loop above). + */ + d[0] = m[0]; + + /* + * d[] may be greater than m[], but it is still lower than twice + * the modulus. + */ + br_i15_sub(d, m, NEQ(dh, 0) | NOT(br_i15_sub(d, m, 0))); +} diff --git a/src/bearssl/src/int/i15_mulacc.c b/src/bearssl/src/int/i15_mulacc.c new file mode 100644 index 0000000..7a073ac --- /dev/null +++ b/src/bearssl/src/int/i15_mulacc.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b) +{ + size_t alen, blen, u; + unsigned dl, dh; + + alen = (a[0] + 15) >> 4; + blen = (b[0] + 15) >> 4; + + /* + * Announced bit length of d[] will be the sum of the announced + * bit lengths of a[] and b[]; but the lengths are encoded. + */ + dl = (a[0] & 15) + (b[0] & 15); + dh = (a[0] >> 4) + (b[0] >> 4); + d[0] = (dh << 4) + dl + (~(uint32_t)(dl - 15) >> 31); + + for (u = 0; u < blen; u ++) { + uint32_t f; + size_t v; + uint32_t cc; + + f = b[1 + u]; + cc = 0; + for (v = 0; v < alen; v ++) { + uint32_t z; + + z = (uint32_t)d[1 + u + v] + MUL15(f, a[1 + v]) + cc; + cc = z >> 15; + d[1 + u + v] = z & 0x7FFF; + } + d[1 + u + alen] = cc; + } +} diff --git a/src/bearssl/src/int/i15_muladd.c b/src/bearssl/src/int/i15_muladd.c new file mode 100644 index 0000000..c4b7216 --- /dev/null +++ b/src/bearssl/src/int/i15_muladd.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Constant-time division. The divisor must not be larger than 16 bits, + * and the quotient must fit on 17 bits. + */ +static uint32_t +divrem16(uint32_t x, uint32_t d, uint32_t *r) +{ + int i; + uint32_t q; + + q = 0; + d <<= 16; + for (i = 16; i >= 0; i --) { + uint32_t ctl; + + ctl = LE(d, x); + q |= ctl << i; + x -= (-ctl) & d; + d >>= 1; + } + if (r != NULL) { + *r = x; + } + return q; +} + +/* see inner.h */ +void +br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m) +{ + /* + * Constant-time: we accept to leak the exact bit length of the + * modulus m. + */ + unsigned m_bitlen, mblr; + size_t u, mlen; + uint32_t hi, a0, a, b, q; + uint32_t cc, tb, over, under; + + /* + * Simple case: the modulus fits on one word. + */ + m_bitlen = m[0]; + if (m_bitlen == 0) { + return; + } + if (m_bitlen <= 15) { + uint32_t rem; + + divrem16(((uint32_t)x[1] << 15) | z, m[1], &rem); + x[1] = rem; + return; + } + mlen = (m_bitlen + 15) >> 4; + mblr = m_bitlen & 15; + + /* + * Principle: we estimate the quotient (x*2^15+z)/m by + * doing a 30/15 division with the high words. + * + * Let: + * w = 2^15 + * a = (w*a0 + a1) * w^N + a2 + * b = b0 * w^N + b2 + * such that: + * 0 <= a0 < w + * 0 <= a1 < w + * 0 <= a2 < w^N + * w/2 <= b0 < w + * 0 <= b2 < w^N + * a < w*b + * I.e. the two top words of a are a0:a1, the top word of b is + * b0, we ensured that b0 is "full" (high bit set), and a is + * such that the quotient q = a/b fits on one word (0 <= q < w). + * + * If a = b*q + r (with 0 <= r < q), then we can estimate q by + * using a division on the top words: + * a0*w + a1 = b0*u + v (with 0 <= v < b0) + * Then the following holds: + * 0 <= u <= w + * u-2 <= q <= u + */ + hi = x[mlen]; + if (mblr == 0) { + a0 = x[mlen]; + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a = (a0 << 15) + x[mlen]; + b = m[mlen]; + } else { + a0 = (x[mlen] << (15 - mblr)) | (x[mlen - 1] >> mblr); + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a = (a0 << 15) | (((x[mlen] << (15 - mblr)) + | (x[mlen - 1] >> mblr)) & 0x7FFF); + b = (m[mlen] << (15 - mblr)) | (m[mlen - 1] >> mblr); + } + q = divrem16(a, b, NULL); + + /* + * We computed an estimate for q, but the real one may be q, + * q-1 or q-2; moreover, the division may have returned a value + * 8000 or even 8001 if the two high words were identical, and + * we want to avoid values beyond 7FFF. We thus adjust q so + * that the "true" multiplier will be q+1, q or q-1, and q is + * in the 0000..7FFF range. + */ + q = MUX(EQ(b, a0), 0x7FFF, q - 1 + ((q - 1) >> 31)); + + /* + * We subtract q*m from x (x has an extra high word of value 'hi'). + * Since q may be off by 1 (in either direction), we may have to + * add or subtract m afterwards. + * + * The 'tb' flag will be true (1) at the end of the loop if the + * result is greater than or equal to the modulus (not counting + * 'hi' or the carry). + */ + cc = 0; + tb = 1; + for (u = 1; u <= mlen; u ++) { + uint32_t mw, zl, xw, nxw; + + mw = m[u]; + zl = MUL15(mw, q) + cc; + cc = zl >> 15; + zl &= 0x7FFF; + xw = x[u]; + nxw = xw - zl; + cc += nxw >> 31; + nxw &= 0x7FFF; + x[u] = nxw; + tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw)); + } + + /* + * If we underestimated q, then either cc < hi (one extra bit + * beyond the top array word), or cc == hi and tb is true (no + * extra bit, but the result is not lower than the modulus). + * + * If we overestimated q, then cc > hi. + */ + over = GT(cc, hi); + under = ~over & (tb | LT(cc, hi)); + br_i15_add(x, m, over); + br_i15_sub(x, m, under); +} diff --git a/src/bearssl/src/int/i15_ninv15.c b/src/bearssl/src/int/i15_ninv15.c new file mode 100644 index 0000000..de3a3ba --- /dev/null +++ b/src/bearssl/src/int/i15_ninv15.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint16_t +br_i15_ninv15(uint16_t x) +{ + uint32_t y; + + y = 2 - x; + y = MUL15(y, 2 - MUL15(x, y)); + y = MUL15(y, 2 - MUL15(x, y)); + y = MUL15(y, 2 - MUL15(x, y)); + return MUX(x & 1, -y, 0) & 0x7FFF; +} diff --git a/src/bearssl/src/int/i15_reduce.c b/src/bearssl/src/int/i15_reduce.c new file mode 100644 index 0000000..0931b10 --- /dev/null +++ b/src/bearssl/src/int/i15_reduce.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m) +{ + uint32_t m_bitlen, a_bitlen; + size_t mlen, alen, u; + + m_bitlen = m[0]; + mlen = (m_bitlen + 15) >> 4; + + x[0] = m_bitlen; + if (m_bitlen == 0) { + return; + } + + /* + * If the source is shorter, then simply copy all words from a[] + * and zero out the upper words. + */ + a_bitlen = a[0]; + alen = (a_bitlen + 15) >> 4; + if (a_bitlen < m_bitlen) { + memcpy(x + 1, a + 1, alen * sizeof *a); + for (u = alen; u < mlen; u ++) { + x[u + 1] = 0; + } + return; + } + + /* + * The source length is at least equal to that of the modulus. + * We must thus copy N-1 words, and input the remaining words + * one by one. + */ + memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a); + x[mlen] = 0; + for (u = 1 + alen - mlen; u > 0; u --) { + br_i15_muladd_small(x, a[u], m); + } +} diff --git a/src/bearssl/src/int/i15_rshift.c b/src/bearssl/src/int/i15_rshift.c new file mode 100644 index 0000000..f9991ab --- /dev/null +++ b/src/bearssl/src/int/i15_rshift.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_rshift(uint16_t *x, int count) +{ + size_t u, len; + unsigned r; + + len = (x[0] + 15) >> 4; + if (len == 0) { + return; + } + r = x[1] >> count; + for (u = 2; u <= len; u ++) { + unsigned w; + + w = x[u]; + x[u - 1] = ((w << (15 - count)) | r) & 0x7FFF; + r = w >> count; + } + x[len] = r; +} diff --git a/src/bearssl/src/int/i15_sub.c b/src/bearssl/src/int/i15_sub.c new file mode 100644 index 0000000..1983c4d --- /dev/null +++ b/src/bearssl/src/int/i15_sub.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 31) >> 4; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw - bw - cc; + cc = naw >> 31; + a[u] = MUX(ctl, naw & 0x7FFF, aw); + } + return cc; +} diff --git a/src/bearssl/src/int/i15_tmont.c b/src/bearssl/src/int/i15_tmont.c new file mode 100644 index 0000000..d5c4b8b --- /dev/null +++ b/src/bearssl/src/int/i15_tmont.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_to_monty(uint16_t *x, const uint16_t *m) +{ + unsigned k; + + for (k = (m[0] + 15) >> 4; k > 0; k --) { + br_i15_muladd_small(x, 0, m); + } +} diff --git a/src/bearssl/src/int/i31_add.c b/src/bearssl/src/int/i31_add.c new file mode 100644 index 0000000..2ca47c6 --- /dev/null +++ b/src/bearssl/src/int/i31_add.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 63) >> 5; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw + bw + cc; + cc = naw >> 31; + a[u] = MUX(ctl, naw & (uint32_t)0x7FFFFFFF, aw); + } + return cc; +} diff --git a/src/bearssl/src/int/i31_bitlen.c b/src/bearssl/src/int/i31_bitlen.c new file mode 100644 index 0000000..3e127c2 --- /dev/null +++ b/src/bearssl/src/int/i31_bitlen.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i31_bit_length(uint32_t *x, size_t xlen) +{ + uint32_t tw, twk; + + tw = 0; + twk = 0; + while (xlen -- > 0) { + uint32_t w, c; + + c = EQ(tw, 0); + w = x[xlen]; + tw = MUX(c, w, tw); + twk = MUX(c, (uint32_t)xlen, twk); + } + return (twk << 5) + BIT_LENGTH(tw); +} diff --git a/src/bearssl/src/int/i31_decmod.c b/src/bearssl/src/int/i31_decmod.c new file mode 100644 index 0000000..3cd7bfe --- /dev/null +++ b/src/bearssl/src/int/i31_decmod.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i31_decode_mod(uint32_t *x, const void *src, size_t len, const uint32_t *m) +{ + /* + * Two-pass algorithm: in the first pass, we determine whether the + * value fits; in the second pass, we do the actual write. + * + * During the first pass, 'r' contains the comparison result so + * far: + * 0x00000000 value is equal to the modulus + * 0x00000001 value is greater than the modulus + * 0xFFFFFFFF value is lower than the modulus + * + * Since we iterate starting with the least significant bytes (at + * the end of src[]), each new comparison overrides the previous + * except when the comparison yields 0 (equal). + * + * During the second pass, 'r' is either 0xFFFFFFFF (value fits) + * or 0x00000000 (value does not fit). + * + * We must iterate over all bytes of the source, _and_ possibly + * some extra virtual bytes (with value 0) so as to cover the + * complete modulus as well. We also add 4 such extra bytes beyond + * the modulus length because it then guarantees that no accumulated + * partial word remains to be processed. + */ + const unsigned char *buf; + size_t mlen, tlen; + int pass; + uint32_t r; + + buf = src; + mlen = (m[0] + 31) >> 5; + tlen = (mlen << 2); + if (tlen < len) { + tlen = len; + } + tlen += 4; + r = 0; + for (pass = 0; pass < 2; pass ++) { + size_t u, v; + uint32_t acc; + int acc_len; + + v = 1; + acc = 0; + acc_len = 0; + for (u = 0; u < tlen; u ++) { + uint32_t b; + + if (u < len) { + b = buf[len - 1 - u]; + } else { + b = 0; + } + acc |= (b << acc_len); + acc_len += 8; + if (acc_len >= 31) { + uint32_t xw; + + xw = acc & (uint32_t)0x7FFFFFFF; + acc_len -= 31; + acc = b >> (8 - acc_len); + if (v <= mlen) { + if (pass) { + x[v] = r & xw; + } else { + uint32_t cc; + + cc = (uint32_t)CMP(xw, m[v]); + r = MUX(EQ(cc, 0), r, cc); + } + } else { + if (!pass) { + r = MUX(EQ(xw, 0), r, 1); + } + } + v ++; + } + } + + /* + * When we reach this point at the end of the first pass: + * r is either 0, 1 or -1; we want to set r to 0 if it + * is equal to 0 or 1, and leave it to -1 otherwise. + * + * When we reach this point at the end of the second pass: + * r is either 0 or -1; we want to leave that value + * untouched. This is a subcase of the previous. + */ + r >>= 1; + r |= (r << 1); + } + + x[0] = m[0]; + return r & (uint32_t)1; +} diff --git a/src/bearssl/src/int/i31_decode.c b/src/bearssl/src/int/i31_decode.c new file mode 100644 index 0000000..8ec6d90 --- /dev/null +++ b/src/bearssl/src/int/i31_decode.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_decode(uint32_t *x, const void *src, size_t len) +{ + const unsigned char *buf; + size_t u, v; + uint32_t acc; + int acc_len; + + buf = src; + u = len; + v = 1; + acc = 0; + acc_len = 0; + while (u -- > 0) { + uint32_t b; + + b = buf[u]; + acc |= (b << acc_len); + acc_len += 8; + if (acc_len >= 31) { + x[v ++] = acc & (uint32_t)0x7FFFFFFF; + acc_len -= 31; + acc = b >> (8 - acc_len); + } + } + if (acc_len != 0) { + x[v ++] = acc; + } + x[0] = br_i31_bit_length(x + 1, v - 1); +} diff --git a/src/bearssl/src/int/i31_decred.c b/src/bearssl/src/int/i31_decred.c new file mode 100644 index 0000000..43db662 --- /dev/null +++ b/src/bearssl/src/int/i31_decred.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_decode_reduce(uint32_t *x, + const void *src, size_t len, const uint32_t *m) +{ + uint32_t m_ebitlen, m_rbitlen; + size_t mblen, k; + const unsigned char *buf; + uint32_t acc; + int acc_len; + + /* + * Get the encoded bit length. + */ + m_ebitlen = m[0]; + + /* + * Special case for an invalid (null) modulus. + */ + if (m_ebitlen == 0) { + x[0] = 0; + return; + } + + /* + * Clear the destination. + */ + br_i31_zero(x, m_ebitlen); + + /* + * First decode directly as many bytes as possible. This requires + * computing the actual bit length. + */ + m_rbitlen = m_ebitlen >> 5; + m_rbitlen = (m_ebitlen & 31) + (m_rbitlen << 5) - m_rbitlen; + mblen = (m_rbitlen + 7) >> 3; + k = mblen - 1; + if (k >= len) { + br_i31_decode(x, src, len); + x[0] = m_ebitlen; + return; + } + buf = src; + br_i31_decode(x, buf, k); + x[0] = m_ebitlen; + + /* + * Input remaining bytes, using 31-bit words. + */ + acc = 0; + acc_len = 0; + while (k < len) { + uint32_t v; + + v = buf[k ++]; + if (acc_len >= 23) { + acc_len -= 23; + acc <<= (8 - acc_len); + acc |= v >> acc_len; + br_i31_muladd_small(x, acc, m); + acc = v & (0xFF >> (8 - acc_len)); + } else { + acc = (acc << 8) | v; + acc_len += 8; + } + } + + /* + * We may have some bits accumulated. We then perform a shift to + * be able to inject these bits as a full 31-bit word. + */ + if (acc_len != 0) { + acc = (acc | (x[1] << acc_len)) & 0x7FFFFFFF; + br_i31_rshift(x, 31 - acc_len); + br_i31_muladd_small(x, acc, m); + } +} diff --git a/src/bearssl/src/int/i31_encode.c b/src/bearssl/src/int/i31_encode.c new file mode 100644 index 0000000..b6b40c4 --- /dev/null +++ b/src/bearssl/src/int/i31_encode.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_encode(void *dst, size_t len, const uint32_t *x) +{ + unsigned char *buf; + size_t k, xlen; + uint32_t acc; + int acc_len; + + xlen = (x[0] + 31) >> 5; + if (xlen == 0) { + memset(dst, 0, len); + return; + } + buf = (unsigned char *)dst + len; + k = 1; + acc = 0; + acc_len = 0; + while (len != 0) { + uint32_t w; + + w = (k <= xlen) ? x[k] : 0; + k ++; + if (acc_len == 0) { + acc = w; + acc_len = 31; + } else { + uint32_t z; + + z = acc | (w << acc_len); + acc_len --; + acc = w >> (31 - acc_len); + if (len >= 4) { + buf -= 4; + len -= 4; + br_enc32be(buf, z); + } else { + switch (len) { + case 3: + buf[-3] = (unsigned char)(z >> 16); + /* fall through */ + case 2: + buf[-2] = (unsigned char)(z >> 8); + /* fall through */ + case 1: + buf[-1] = (unsigned char)z; + break; + } + return; + } + } + } +} diff --git a/src/bearssl/src/int/i31_fmont.c b/src/bearssl/src/int/i31_fmont.c new file mode 100644 index 0000000..c24b417 --- /dev/null +++ b/src/bearssl/src/int/i31_fmont.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i) +{ + size_t len, u, v; + + len = (m[0] + 31) >> 5; + for (u = 0; u < len; u ++) { + uint32_t f; + uint64_t cc; + + f = MUL31_lo(x[1], m0i); + cc = 0; + for (v = 0; v < len; v ++) { + uint64_t z; + + z = (uint64_t)x[v + 1] + MUL31(f, m[v + 1]) + cc; + cc = z >> 31; + if (v != 0) { + x[v] = (uint32_t)z & 0x7FFFFFFF; + } + } + x[len] = (uint32_t)cc; + } + + /* + * We may have to do an extra subtraction, but only if the + * value in x[] is indeed greater than or equal to that of m[], + * which is why we must do two calls (first call computes the + * carry, second call performs the subtraction only if the carry + * is 0). + */ + br_i31_sub(x, m, NOT(br_i31_sub(x, m, 0))); +} diff --git a/src/bearssl/src/int/i31_iszero.c b/src/bearssl/src/int/i31_iszero.c new file mode 100644 index 0000000..8a7ea44 --- /dev/null +++ b/src/bearssl/src/int/i31_iszero.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i31_iszero(const uint32_t *x) +{ + uint32_t z; + size_t u; + + z = 0; + for (u = (x[0] + 31) >> 5; u > 0; u --) { + z |= x[u]; + } + return ~(z | -z) >> 31; +} diff --git a/src/bearssl/src/int/i31_moddiv.c b/src/bearssl/src/int/i31_moddiv.c new file mode 100644 index 0000000..9950591 --- /dev/null +++ b/src/bearssl/src/int/i31_moddiv.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * In this file, we handle big integers with a custom format, i.e. + * without the usual one-word header. Value is split into 31-bit words, + * each stored in a 32-bit slot (top bit is zero) in little-endian + * order. The length (in words) is provided explicitly. In some cases, + * the value can be negative (using two's complement representation). In + * some cases, the top word is allowed to have a 32th bit. + */ + +/* + * Negate big integer conditionally. The value consists of 'len' words, + * with 31 bits in each word (the top bit of each word should be 0, + * except possibly for the last word). If 'ctl' is 1, the negation is + * computed; otherwise, if 'ctl' is 0, then the value is unchanged. + */ +static void +cond_negate(uint32_t *a, size_t len, uint32_t ctl) +{ + size_t k; + uint32_t cc, xm; + + cc = ctl; + xm = -ctl >> 1; + for (k = 0; k < len; k ++) { + uint32_t aw; + + aw = a[k]; + aw = (aw ^ xm) + cc; + a[k] = aw & 0x7FFFFFFF; + cc = aw >> 31; + } +} + +/* + * Finish modular reduction. Rules on input parameters: + * + * if neg = 1, then -m <= a < 0 + * if neg = 0, then 0 <= a < 2*m + * + * If neg = 0, then the top word of a[] may use 32 bits. + * + * Also, modulus m must be odd. + */ +static void +finish_mod(uint32_t *a, size_t len, const uint32_t *m, uint32_t neg) +{ + size_t k; + uint32_t cc, xm, ym; + + /* + * First pass: compare a (assumed nonnegative) with m. + * Note that if the final word uses the top extra bit, then + * subtracting m must yield a value less than 2^31, since we + * assumed that a < 2*m. + */ + cc = 0; + for (k = 0; k < len; k ++) { + uint32_t aw, mw; + + aw = a[k]; + mw = m[k]; + cc = (aw - mw - cc) >> 31; + } + + /* + * At this point: + * if neg = 1, then we must add m (regardless of cc) + * if neg = 0 and cc = 0, then we must subtract m + * if neg = 0 and cc = 1, then we must do nothing + */ + xm = -neg >> 1; + ym = -(neg | (1 - cc)); + cc = neg; + for (k = 0; k < len; k ++) { + uint32_t aw, mw; + + aw = a[k]; + mw = (m[k] ^ xm) & ym; + aw = aw - mw - cc; + a[k] = aw & 0x7FFFFFFF; + cc = aw >> 31; + } +} + +/* + * Compute: + * a <- (a*pa+b*pb)/(2^31) + * b <- (a*qa+b*qb)/(2^31) + * The division is assumed to be exact (i.e. the low word is dropped). + * If the final a is negative, then it is negated. Similarly for b. + * Returned value is the combination of two bits: + * bit 0: 1 if a had to be negated, 0 otherwise + * bit 1: 1 if b had to be negated, 0 otherwise + * + * Factors pa, pb, qa and qb must be at most 2^31 in absolute value. + * Source integers a and b must be nonnegative; top word is not allowed + * to contain an extra 32th bit. + */ +static uint32_t +co_reduce(uint32_t *a, uint32_t *b, size_t len, + int64_t pa, int64_t pb, int64_t qa, int64_t qb) +{ + size_t k; + int64_t cca, ccb; + uint32_t nega, negb; + + cca = 0; + ccb = 0; + for (k = 0; k < len; k ++) { + uint32_t wa, wb; + uint64_t za, zb; + uint64_t tta, ttb; + + /* + * Since: + * |pa| <= 2^31 + * |pb| <= 2^31 + * 0 <= wa <= 2^31 - 1 + * 0 <= wb <= 2^31 - 1 + * |cca| <= 2^32 - 1 + * Then: + * |za| <= (2^31-1)*(2^32) + (2^32-1) = 2^63 - 1 + * + * Thus, the new value of cca is such that |cca| <= 2^32 - 1. + * The same applies to ccb. + */ + wa = a[k]; + wb = b[k]; + za = wa * (uint64_t)pa + wb * (uint64_t)pb + (uint64_t)cca; + zb = wa * (uint64_t)qa + wb * (uint64_t)qb + (uint64_t)ccb; + if (k > 0) { + a[k - 1] = za & 0x7FFFFFFF; + b[k - 1] = zb & 0x7FFFFFFF; + } + + /* + * For the new values of cca and ccb, we need a signed + * right-shift; since, in C, right-shifting a signed + * negative value is implementation-defined, we use a + * custom portable sign extension expression. + */ +#define M ((uint64_t)1 << 32) + tta = za >> 31; + ttb = zb >> 31; + tta = (tta ^ M) - M; + ttb = (ttb ^ M) - M; + cca = *(int64_t *)&tta; + ccb = *(int64_t *)&ttb; +#undef M + } + a[len - 1] = (uint32_t)cca; + b[len - 1] = (uint32_t)ccb; + + nega = (uint32_t)((uint64_t)cca >> 63); + negb = (uint32_t)((uint64_t)ccb >> 63); + cond_negate(a, len, nega); + cond_negate(b, len, negb); + return nega | (negb << 1); +} + +/* + * Compute: + * a <- (a*pa+b*pb)/(2^31) mod m + * b <- (a*qa+b*qb)/(2^31) mod m + * + * m0i is equal to -1/m[0] mod 2^31. + * + * Factors pa, pb, qa and qb must be at most 2^31 in absolute value. + * Source integers a and b must be nonnegative; top word is not allowed + * to contain an extra 32th bit. + */ +static void +co_reduce_mod(uint32_t *a, uint32_t *b, size_t len, + int64_t pa, int64_t pb, int64_t qa, int64_t qb, + const uint32_t *m, uint32_t m0i) +{ + size_t k; + int64_t cca, ccb; + uint32_t fa, fb; + + cca = 0; + ccb = 0; + fa = ((a[0] * (uint32_t)pa + b[0] * (uint32_t)pb) * m0i) & 0x7FFFFFFF; + fb = ((a[0] * (uint32_t)qa + b[0] * (uint32_t)qb) * m0i) & 0x7FFFFFFF; + for (k = 0; k < len; k ++) { + uint32_t wa, wb; + uint64_t za, zb; + uint64_t tta, ttb; + + /* + * In this loop, carries 'cca' and 'ccb' always fit on + * 33 bits (in absolute value). + */ + wa = a[k]; + wb = b[k]; + za = wa * (uint64_t)pa + wb * (uint64_t)pb + + m[k] * (uint64_t)fa + (uint64_t)cca; + zb = wa * (uint64_t)qa + wb * (uint64_t)qb + + m[k] * (uint64_t)fb + (uint64_t)ccb; + if (k > 0) { + a[k - 1] = (uint32_t)za & 0x7FFFFFFF; + b[k - 1] = (uint32_t)zb & 0x7FFFFFFF; + } + +#define M ((uint64_t)1 << 32) + tta = za >> 31; + ttb = zb >> 31; + tta = (tta ^ M) - M; + ttb = (ttb ^ M) - M; + cca = *(int64_t *)&tta; + ccb = *(int64_t *)&ttb; +#undef M + } + a[len - 1] = (uint32_t)cca; + b[len - 1] = (uint32_t)ccb; + + /* + * At this point: + * -m <= a < 2*m + * -m <= b < 2*m + * (this is a case of Montgomery reduction) + * The top word of 'a' and 'b' may have a 32-th bit set. + * We may have to add or subtract the modulus. + */ + finish_mod(a, len, m, (uint32_t)((uint64_t)cca >> 63)); + finish_mod(b, len, m, (uint32_t)((uint64_t)ccb >> 63)); +} + +/* see inner.h */ +uint32_t +br_i31_moddiv(uint32_t *x, const uint32_t *y, const uint32_t *m, uint32_t m0i, + uint32_t *t) +{ + /* + * Algorithm is an extended binary GCD. We maintain four values + * a, b, u and v, with the following invariants: + * + * a * x = y * u mod m + * b * x = y * v mod m + * + * Starting values are: + * + * a = y + * b = m + * u = x + * v = 0 + * + * The formal definition of the algorithm is a sequence of steps: + * + * - If a is even, then a <- a/2 and u <- u/2 mod m. + * - Otherwise, if b is even, then b <- b/2 and v <- v/2 mod m. + * - Otherwise, if a > b, then a <- (a-b)/2 and u <- (u-v)/2 mod m. + * - Otherwise, b <- (b-a)/2 and v <- (v-u)/2 mod m. + * + * Algorithm stops when a = b. At that point, they both are equal + * to GCD(y,m); the modular division succeeds if that value is 1. + * The result of the modular division is then u (or v: both are + * equal at that point). + * + * Each step makes either a or b shrink by at least one bit; hence, + * if m has bit length k bits, then 2k-2 steps are sufficient. + * + * + * Though complexity is quadratic in the size of m, the bit-by-bit + * processing is not very efficient. We can speed up processing by + * remarking that the decisions are taken based only on observation + * of the top and low bits of a and b. + * + * In the loop below, at each iteration, we use the two top words + * of a and b, and the low words of a and b, to compute reduction + * parameters pa, pb, qa and qb such that the new values for a + * and b are: + * + * a' = (a*pa + b*pb) / (2^31) + * b' = (a*qa + b*qb) / (2^31) + * + * the division being exact. + * + * Since the choices are based on the top words, they may be slightly + * off, requiring an optional correction: if a' < 0, then we replace + * pa with -pa, and pb with -pb. The total length of a and b is + * thus reduced by at least 30 bits at each iteration. + * + * The stopping conditions are still the same, though: when a + * and b become equal, they must be both odd (since m is odd, + * the GCD cannot be even), therefore the next operation is a + * subtraction, and one of the values becomes 0. At that point, + * nothing else happens, i.e. one value is stuck at 0, and the + * other one is the GCD. + */ + size_t len, k; + uint32_t *a, *b, *u, *v; + uint32_t num, r; + + len = (m[0] + 31) >> 5; + a = t; + b = a + len; + u = x + 1; + v = b + len; + memcpy(a, y + 1, len * sizeof *y); + memcpy(b, m + 1, len * sizeof *m); + memset(v, 0, len * sizeof *v); + + /* + * Loop below ensures that a and b are reduced by some bits each, + * for a total of at least 30 bits. + */ + for (num = ((m[0] - (m[0] >> 5)) << 1) + 30; num >= 30; num -= 30) { + size_t j; + uint32_t c0, c1; + uint32_t a0, a1, b0, b1; + uint64_t a_hi, b_hi; + uint32_t a_lo, b_lo; + int64_t pa, pb, qa, qb; + int i; + + /* + * Extract top words of a and b. If j is the highest + * index >= 1 such that a[j] != 0 or b[j] != 0, then we want + * (a[j] << 31) + a[j - 1], and (b[j] << 31) + b[j - 1]. + * If a and b are down to one word each, then we use a[0] + * and b[0]. + */ + c0 = (uint32_t)-1; + c1 = (uint32_t)-1; + a0 = 0; + a1 = 0; + b0 = 0; + b1 = 0; + j = len; + while (j -- > 0) { + uint32_t aw, bw; + + aw = a[j]; + bw = b[j]; + a0 ^= (a0 ^ aw) & c0; + a1 ^= (a1 ^ aw) & c1; + b0 ^= (b0 ^ bw) & c0; + b1 ^= (b1 ^ bw) & c1; + c1 = c0; + c0 &= (((aw | bw) + 0x7FFFFFFF) >> 31) - (uint32_t)1; + } + + /* + * If c1 = 0, then we grabbed two words for a and b. + * If c1 != 0 but c0 = 0, then we grabbed one word. It + * is not possible that c1 != 0 and c0 != 0, because that + * would mean that both integers are zero. + */ + a1 |= a0 & c1; + a0 &= ~c1; + b1 |= b0 & c1; + b0 &= ~c1; + a_hi = ((uint64_t)a0 << 31) + a1; + b_hi = ((uint64_t)b0 << 31) + b1; + a_lo = a[0]; + b_lo = b[0]; + + /* + * Compute reduction factors: + * + * a' = a*pa + b*pb + * b' = a*qa + b*qb + * + * such that a' and b' are both multiple of 2^31, but are + * only marginally larger than a and b. + */ + pa = 1; + pb = 0; + qa = 0; + qb = 1; + for (i = 0; i < 31; i ++) { + /* + * At each iteration: + * + * a <- (a-b)/2 if: a is odd, b is odd, a_hi > b_hi + * b <- (b-a)/2 if: a is odd, b is odd, a_hi <= b_hi + * a <- a/2 if: a is even + * b <- b/2 if: a is odd, b is even + * + * We multiply a_lo and b_lo by 2 at each + * iteration, thus a division by 2 really is a + * non-multiplication by 2. + */ + uint32_t r, oa, ob, cAB, cBA, cA; + uint64_t rz; + + /* + * r = GT(a_hi, b_hi) + * But the GT() function works on uint32_t operands, + * so we inline a 64-bit version here. + */ + rz = b_hi - a_hi; + r = (uint32_t)((rz ^ ((a_hi ^ b_hi) + & (a_hi ^ rz))) >> 63); + + /* + * cAB = 1 if b must be subtracted from a + * cBA = 1 if a must be subtracted from b + * cA = 1 if a is divided by 2, 0 otherwise + * + * Rules: + * + * cAB and cBA cannot be both 1. + * if a is not divided by 2, b is. + */ + oa = (a_lo >> i) & 1; + ob = (b_lo >> i) & 1; + cAB = oa & ob & r; + cBA = oa & ob & NOT(r); + cA = cAB | NOT(oa); + + /* + * Conditional subtractions. + */ + a_lo -= b_lo & -cAB; + a_hi -= b_hi & -(uint64_t)cAB; + pa -= qa & -(int64_t)cAB; + pb -= qb & -(int64_t)cAB; + b_lo -= a_lo & -cBA; + b_hi -= a_hi & -(uint64_t)cBA; + qa -= pa & -(int64_t)cBA; + qb -= pb & -(int64_t)cBA; + + /* + * Shifting. + */ + a_lo += a_lo & (cA - 1); + pa += pa & ((int64_t)cA - 1); + pb += pb & ((int64_t)cA - 1); + a_hi ^= (a_hi ^ (a_hi >> 1)) & -(uint64_t)cA; + b_lo += b_lo & -cA; + qa += qa & -(int64_t)cA; + qb += qb & -(int64_t)cA; + b_hi ^= (b_hi ^ (b_hi >> 1)) & ((uint64_t)cA - 1); + } + + /* + * Replace a and b with new values a' and b'. + */ + r = co_reduce(a, b, len, pa, pb, qa, qb); + pa -= pa * ((r & 1) << 1); + pb -= pb * ((r & 1) << 1); + qa -= qa * (r & 2); + qb -= qb * (r & 2); + co_reduce_mod(u, v, len, pa, pb, qa, qb, m + 1, m0i); + } + + /* + * Now one of the arrays should be 0, and the other contains + * the GCD. If a is 0, then u is 0 as well, and v contains + * the division result. + * Result is correct if and only if GCD is 1. + */ + r = (a[0] | b[0]) ^ 1; + u[0] |= v[0]; + for (k = 1; k < len; k ++) { + r |= a[k] | b[k]; + u[k] |= v[k]; + } + return EQ0(r); +} diff --git a/src/bearssl/src/int/i31_modpow.c b/src/bearssl/src/int/i31_modpow.c new file mode 100644 index 0000000..4ef3f5d --- /dev/null +++ b/src/bearssl/src/int/i31_modpow.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_modpow(uint32_t *x, + const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2) +{ + size_t mlen; + uint32_t k; + + /* + * 'mlen' is the length of m[] expressed in bytes (including + * the "bit length" first field). + */ + mlen = ((m[0] + 63) >> 5) * sizeof m[0]; + + /* + * Throughout the algorithm: + * -- t1[] is in Montgomery representation; it contains x, x^2, + * x^4, x^8... + * -- The result is accumulated, in normal representation, in + * the x[] array. + * -- t2[] is used as destination buffer for each multiplication. + * + * Note that there is no need to call br_i32_from_monty(). + */ + memcpy(t1, x, mlen); + br_i31_to_monty(t1, m); + br_i31_zero(x, m[0]); + x[1] = 1; + for (k = 0; k < ((uint32_t)elen << 3); k ++) { + uint32_t ctl; + + ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1; + br_i31_montymul(t2, x, t1, m, m0i); + CCOPY(ctl, x, t2, mlen); + br_i31_montymul(t2, t1, t1, m, m0i); + memcpy(t1, t2, mlen); + } +} diff --git a/src/bearssl/src/int/i31_modpow2.c b/src/bearssl/src/int/i31_modpow2.c new file mode 100644 index 0000000..0b8f8cf --- /dev/null +++ b/src/bearssl/src/int/i31_modpow2.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i31_modpow_opt(uint32_t *x, + const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen) +{ + size_t mlen, mwlen; + uint32_t *t1, *t2, *base; + size_t u, v; + uint32_t acc; + int acc_len, win_len; + + /* + * Get modulus size. + */ + mwlen = (m[0] + 63) >> 5; + mlen = mwlen * sizeof m[0]; + mwlen += (mwlen & 1); + t1 = tmp; + t2 = tmp + mwlen; + + /* + * Compute possible window size, with a maximum of 5 bits. + * When the window has size 1 bit, we use a specific code + * that requires only two temporaries. Otherwise, for a + * window of k bits, we need 2^k+1 temporaries. + */ + if (twlen < (mwlen << 1)) { + return 0; + } + for (win_len = 5; win_len > 1; win_len --) { + if ((((uint32_t)1 << win_len) + 1) * mwlen <= twlen) { + break; + } + } + + /* + * Everything is done in Montgomery representation. + */ + br_i31_to_monty(x, m); + + /* + * Compute window contents. If the window has size one bit only, + * then t2 is set to x; otherwise, t2[0] is left untouched, and + * t2[k] is set to x^k (for k >= 1). + */ + if (win_len == 1) { + memcpy(t2, x, mlen); + } else { + memcpy(t2 + mwlen, x, mlen); + base = t2 + mwlen; + for (u = 2; u < ((unsigned)1 << win_len); u ++) { + br_i31_montymul(base + mwlen, base, x, m, m0i); + base += mwlen; + } + } + + /* + * We need to set x to 1, in Montgomery representation. This can + * be done efficiently by setting the high word to 1, then doing + * one word-sized shift. + */ + br_i31_zero(x, m[0]); + x[(m[0] + 31) >> 5] = 1; + br_i31_muladd_small(x, 0, m); + + /* + * We process bits from most to least significant. At each + * loop iteration, we have acc_len bits in acc. + */ + acc = 0; + acc_len = 0; + while (acc_len > 0 || elen > 0) { + int i, k; + uint32_t bits; + + /* + * Get the next bits. + */ + k = win_len; + if (acc_len < win_len) { + if (elen > 0) { + acc = (acc << 8) | *e ++; + elen --; + acc_len += 8; + } else { + k = acc_len; + } + } + bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1); + acc_len -= k; + + /* + * We could get exactly k bits. Compute k squarings. + */ + for (i = 0; i < k; i ++) { + br_i31_montymul(t1, x, x, m, m0i); + memcpy(x, t1, mlen); + } + + /* + * Window lookup: we want to set t2 to the window + * lookup value, assuming the bits are non-zero. If + * the window length is 1 bit only, then t2 is + * already set; otherwise, we do a constant-time lookup. + */ + if (win_len > 1) { + br_i31_zero(t2, m[0]); + base = t2 + mwlen; + for (u = 1; u < ((uint32_t)1 << k); u ++) { + uint32_t mask; + + mask = -EQ(u, bits); + for (v = 1; v < mwlen; v ++) { + t2[v] |= mask & base[v]; + } + base += mwlen; + } + } + + /* + * Multiply with the looked-up value. We keep the + * product only if the exponent bits are not all-zero. + */ + br_i31_montymul(t1, x, t2, m, m0i); + CCOPY(NEQ(bits, 0), x, t1, mlen); + } + + /* + * Convert back from Montgomery representation, and exit. + */ + br_i31_from_monty(x, m, m0i); + return 1; +} diff --git a/src/bearssl/src/int/i31_montmul.c b/src/bearssl/src/int/i31_montmul.c new file mode 100644 index 0000000..8066808 --- /dev/null +++ b/src/bearssl/src/int/i31_montmul.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i) +{ + size_t len, len4, u, v; + uint64_t dh; + + len = (m[0] + 31) >> 5; + len4 = len & ~(size_t)3; + br_i31_zero(d, m[0]); + dh = 0; + for (u = 0; u < len; u ++) { + uint32_t f, xu; + uint64_t r, zh; + + xu = x[u + 1]; + f = MUL31_lo((d[1] + MUL31_lo(x[u + 1], y[1])), m0i); + + r = 0; + for (v = 0; v < len4; v += 4) { + uint64_t z; + + z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1]) + + MUL31(f, m[v + 1]) + r; + r = z >> 31; + d[v + 0] = (uint32_t)z & 0x7FFFFFFF; + z = (uint64_t)d[v + 2] + MUL31(xu, y[v + 2]) + + MUL31(f, m[v + 2]) + r; + r = z >> 31; + d[v + 1] = (uint32_t)z & 0x7FFFFFFF; + z = (uint64_t)d[v + 3] + MUL31(xu, y[v + 3]) + + MUL31(f, m[v + 3]) + r; + r = z >> 31; + d[v + 2] = (uint32_t)z & 0x7FFFFFFF; + z = (uint64_t)d[v + 4] + MUL31(xu, y[v + 4]) + + MUL31(f, m[v + 4]) + r; + r = z >> 31; + d[v + 3] = (uint32_t)z & 0x7FFFFFFF; + } + for (; v < len; v ++) { + uint64_t z; + + z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1]) + + MUL31(f, m[v + 1]) + r; + r = z >> 31; + d[v] = (uint32_t)z & 0x7FFFFFFF; + } + + zh = dh + r; + d[len] = (uint32_t)zh & 0x7FFFFFFF; + dh = zh >> 31; + } + + /* + * We must write back the bit length because it was overwritten in + * the loop (not overwriting it would require a test in the loop, + * which would yield bigger and slower code). + */ + d[0] = m[0]; + + /* + * d[] may still be greater than m[] at that point; notably, the + * 'dh' word may be non-zero. + */ + br_i31_sub(d, m, NEQ(dh, 0) | NOT(br_i31_sub(d, m, 0))); +} diff --git a/src/bearssl/src/int/i31_mulacc.c b/src/bearssl/src/int/i31_mulacc.c new file mode 100644 index 0000000..024d095 --- /dev/null +++ b/src/bearssl/src/int/i31_mulacc.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + size_t alen, blen, u; + uint32_t dl, dh; + + alen = (a[0] + 31) >> 5; + blen = (b[0] + 31) >> 5; + + /* + * We want to add the two bit lengths, but these are encoded, + * which requires some extra care. + */ + dl = (a[0] & 31) + (b[0] & 31); + dh = (a[0] >> 5) + (b[0] >> 5); + d[0] = (dh << 5) + dl + (~(uint32_t)(dl - 31) >> 31); + + for (u = 0; u < blen; u ++) { + uint32_t f; + size_t v; + uint64_t cc; + + f = b[1 + u]; + cc = 0; + for (v = 0; v < alen; v ++) { + uint64_t z; + + z = (uint64_t)d[1 + u + v] + MUL31(f, a[1 + v]) + cc; + cc = z >> 31; + d[1 + u + v] = (uint32_t)z & 0x7FFFFFFF; + } + d[1 + u + alen] = (uint32_t)cc; + } +} diff --git a/src/bearssl/src/int/i31_muladd.c b/src/bearssl/src/int/i31_muladd.c new file mode 100644 index 0000000..eecd9e2 --- /dev/null +++ b/src/bearssl/src/int/i31_muladd.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m) +{ + uint32_t m_bitlen; + unsigned mblr; + size_t u, mlen; + uint32_t a0, a1, b0, hi, g, q, tb; + uint32_t under, over; + uint32_t cc; + + /* + * We can test on the modulus bit length since we accept to + * leak that length. + */ + m_bitlen = m[0]; + if (m_bitlen == 0) { + return; + } + if (m_bitlen <= 31) { + uint32_t lo; + + hi = x[1] >> 1; + lo = (x[1] << 31) | z; + x[1] = br_rem(hi, lo, m[1]); + return; + } + mlen = (m_bitlen + 31) >> 5; + mblr = (unsigned)m_bitlen & 31; + + /* + * Principle: we estimate the quotient (x*2^31+z)/m by + * doing a 64/32 division with the high words. + * + * Let: + * w = 2^31 + * a = (w*a0 + a1) * w^N + a2 + * b = b0 * w^N + b2 + * such that: + * 0 <= a0 < w + * 0 <= a1 < w + * 0 <= a2 < w^N + * w/2 <= b0 < w + * 0 <= b2 < w^N + * a < w*b + * I.e. the two top words of a are a0:a1, the top word of b is + * b0, we ensured that b0 is "full" (high bit set), and a is + * such that the quotient q = a/b fits on one word (0 <= q < w). + * + * If a = b*q + r (with 0 <= r < q), we can estimate q by + * doing an Euclidean division on the top words: + * a0*w+a1 = b0*u + v (with 0 <= v < b0) + * Then the following holds: + * 0 <= u <= w + * u-2 <= q <= u + */ + hi = x[mlen]; + if (mblr == 0) { + a0 = x[mlen]; + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a1 = x[mlen]; + b0 = m[mlen]; + } else { + a0 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr)) + & 0x7FFFFFFF; + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a1 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr)) + & 0x7FFFFFFF; + b0 = ((m[mlen] << (31 - mblr)) | (m[mlen - 1] >> mblr)) + & 0x7FFFFFFF; + } + + /* + * We estimate a divisor q. If the quotient returned by br_div() + * is g: + * -- If a0 == b0 then g == 0; we want q = 0x7FFFFFFF. + * -- Otherwise: + * -- if g == 0 then we set q = 0; + * -- otherwise, we set q = g - 1. + * The properties described above then ensure that the true + * quotient is q-1, q or q+1. + * + * Take care that a0, a1 and b0 are 31-bit words, not 32-bit. We + * must adjust the parameters to br_div() accordingly. + */ + g = br_div(a0 >> 1, a1 | (a0 << 31), b0); + q = MUX(EQ(a0, b0), 0x7FFFFFFF, MUX(EQ(g, 0), 0, g - 1)); + + /* + * We subtract q*m from x (with the extra high word of value 'hi'). + * Since q may be off by 1 (in either direction), we may have to + * add or subtract m afterwards. + * + * The 'tb' flag will be true (1) at the end of the loop if the + * result is greater than or equal to the modulus (not counting + * 'hi' or the carry). + */ + cc = 0; + tb = 1; + for (u = 1; u <= mlen; u ++) { + uint32_t mw, zw, xw, nxw; + uint64_t zl; + + mw = m[u]; + zl = MUL31(mw, q) + cc; + cc = (uint32_t)(zl >> 31); + zw = (uint32_t)zl & (uint32_t)0x7FFFFFFF; + xw = x[u]; + nxw = xw - zw; + cc += nxw >> 31; + nxw &= 0x7FFFFFFF; + x[u] = nxw; + tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw)); + } + + /* + * If we underestimated q, then either cc < hi (one extra bit + * beyond the top array word), or cc == hi and tb is true (no + * extra bit, but the result is not lower than the modulus). In + * these cases we must subtract m once. + * + * Otherwise, we may have overestimated, which will show as + * cc > hi (thus a negative result). Correction is adding m once. + */ + over = GT(cc, hi); + under = ~over & (tb | LT(cc, hi)); + br_i31_add(x, m, over); + br_i31_sub(x, m, under); +} diff --git a/src/bearssl/src/int/i31_ninv31.c b/src/bearssl/src/int/i31_ninv31.c new file mode 100644 index 0000000..dd83c96 --- /dev/null +++ b/src/bearssl/src/int/i31_ninv31.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i31_ninv31(uint32_t x) +{ + uint32_t y; + + y = 2 - x; + y *= 2 - y * x; + y *= 2 - y * x; + y *= 2 - y * x; + y *= 2 - y * x; + return MUX(x & 1, -y, 0) & 0x7FFFFFFF; +} diff --git a/src/bearssl/src/int/i31_reduce.c b/src/bearssl/src/int/i31_reduce.c new file mode 100644 index 0000000..5c9523e --- /dev/null +++ b/src/bearssl/src/int/i31_reduce.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m) +{ + uint32_t m_bitlen, a_bitlen; + size_t mlen, alen, u; + + m_bitlen = m[0]; + mlen = (m_bitlen + 31) >> 5; + + x[0] = m_bitlen; + if (m_bitlen == 0) { + return; + } + + /* + * If the source is shorter, then simply copy all words from a[] + * and zero out the upper words. + */ + a_bitlen = a[0]; + alen = (a_bitlen + 31) >> 5; + if (a_bitlen < m_bitlen) { + memcpy(x + 1, a + 1, alen * sizeof *a); + for (u = alen; u < mlen; u ++) { + x[u + 1] = 0; + } + return; + } + + /* + * The source length is at least equal to that of the modulus. + * We must thus copy N-1 words, and input the remaining words + * one by one. + */ + memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a); + x[mlen] = 0; + for (u = 1 + alen - mlen; u > 0; u --) { + br_i31_muladd_small(x, a[u], m); + } +} diff --git a/src/bearssl/src/int/i31_rshift.c b/src/bearssl/src/int/i31_rshift.c new file mode 100644 index 0000000..db6ba0b --- /dev/null +++ b/src/bearssl/src/int/i31_rshift.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_rshift(uint32_t *x, int count) +{ + size_t u, len; + uint32_t r; + + len = (x[0] + 31) >> 5; + if (len == 0) { + return; + } + r = x[1] >> count; + for (u = 2; u <= len; u ++) { + uint32_t w; + + w = x[u]; + x[u - 1] = ((w << (31 - count)) | r) & 0x7FFFFFFF; + r = w >> count; + } + x[len] = r; +} diff --git a/src/bearssl/src/int/i31_sub.c b/src/bearssl/src/int/i31_sub.c new file mode 100644 index 0000000..3910895 --- /dev/null +++ b/src/bearssl/src/int/i31_sub.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 63) >> 5; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw - bw - cc; + cc = naw >> 31; + a[u] = MUX(ctl, naw & 0x7FFFFFFF, aw); + } + return cc; +} diff --git a/src/bearssl/src/int/i31_tmont.c b/src/bearssl/src/int/i31_tmont.c new file mode 100644 index 0000000..4798ff6 --- /dev/null +++ b/src/bearssl/src/int/i31_tmont.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i31_to_monty(uint32_t *x, const uint32_t *m) +{ + uint32_t k; + + for (k = (m[0] + 31) >> 5; k > 0; k --) { + br_i31_muladd_small(x, 0, m); + } +} diff --git a/src/bearssl/src/int/i32_add.c b/src/bearssl/src/int/i32_add.c new file mode 100644 index 0000000..620baff --- /dev/null +++ b/src/bearssl/src/int/i32_add.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 63) >> 5; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw + bw + cc; + + /* + * Carry is 1 if naw < aw. Carry is also 1 if naw == aw + * AND the carry was already 1. + */ + cc = (cc & EQ(naw, aw)) | LT(naw, aw); + a[u] = MUX(ctl, naw, aw); + } + return cc; +} diff --git a/src/bearssl/src/int/i32_bitlen.c b/src/bearssl/src/int/i32_bitlen.c new file mode 100644 index 0000000..40ce9fa --- /dev/null +++ b/src/bearssl/src/int/i32_bitlen.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i32_bit_length(uint32_t *x, size_t xlen) +{ + uint32_t tw, twk; + + tw = 0; + twk = 0; + while (xlen -- > 0) { + uint32_t w, c; + + c = EQ(tw, 0); + w = x[xlen]; + tw = MUX(c, w, tw); + twk = MUX(c, (uint32_t)xlen, twk); + } + return (twk << 5) + BIT_LENGTH(tw); +} diff --git a/src/bearssl/src/int/i32_decmod.c b/src/bearssl/src/int/i32_decmod.c new file mode 100644 index 0000000..a859af1 --- /dev/null +++ b/src/bearssl/src/int/i32_decmod.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i32_decode_mod(uint32_t *x, const void *src, size_t len, const uint32_t *m) +{ + const unsigned char *buf; + uint32_t r; + size_t u, v, mlen; + + buf = src; + + /* + * First pass: determine whether the value fits. The 'r' value + * will contain the comparison result, as 0x00000000 (value is + * equal to the modulus), 0x00000001 (value is greater than the + * modulus), or 0xFFFFFFFF (value is lower than the modulus). + */ + mlen = (m[0] + 7) >> 3; + r = 0; + for (u = (mlen > len) ? mlen : len; u > 0; u --) { + uint32_t mb, xb; + + v = u - 1; + if (v >= mlen) { + mb = 0; + } else { + mb = (m[1 + (v >> 2)] >> ((v & 3) << 3)) & 0xFF; + } + if (v >= len) { + xb = 0; + } else { + xb = buf[len - u]; + } + r = MUX(EQ(r, 0), (uint32_t)CMP(xb, mb), r); + } + + /* + * Only r == 0xFFFFFFFF is acceptable. We want to set r to 0xFF if + * the value fits, 0x00 otherwise. + */ + r >>= 24; + br_i32_zero(x, m[0]); + u = (mlen > len) ? len : mlen; + while (u > 0) { + uint32_t xb; + + xb = buf[len - u] & r; + u --; + x[1 + (u >> 2)] |= xb << ((u & 3) << 3); + } + return r >> 7; +} diff --git a/src/bearssl/src/int/i32_decode.c b/src/bearssl/src/int/i32_decode.c new file mode 100644 index 0000000..f289038 --- /dev/null +++ b/src/bearssl/src/int/i32_decode.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_decode(uint32_t *x, const void *src, size_t len) +{ + const unsigned char *buf; + size_t u, v; + + buf = src; + u = len; + v = 1; + for (;;) { + if (u < 4) { + uint32_t w; + + if (u < 2) { + if (u == 0) { + break; + } else { + w = buf[0]; + } + } else { + if (u == 2) { + w = br_dec16be(buf); + } else { + w = ((uint32_t)buf[0] << 16) + | br_dec16be(buf + 1); + } + } + x[v ++] = w; + break; + } else { + u -= 4; + x[v ++] = br_dec32be(buf + u); + } + } + x[0] = br_i32_bit_length(x + 1, v - 1); +} diff --git a/src/bearssl/src/int/i32_decred.c b/src/bearssl/src/int/i32_decred.c new file mode 100644 index 0000000..dc476db --- /dev/null +++ b/src/bearssl/src/int/i32_decred.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_decode_reduce(uint32_t *x, + const void *src, size_t len, const uint32_t *m) +{ + uint32_t m_bitlen; + size_t mblen, k, q; + const unsigned char *buf; + + m_bitlen = m[0]; + + /* + * Special case for an invalid modulus. + */ + if (m_bitlen == 0) { + x[0] = 0; + return; + } + + /* + * Clear the destination. + */ + br_i32_zero(x, m_bitlen); + + /* + * First decode directly as many bytes as possible without + * reduction, taking care to leave a number of bytes which + * is a multiple of 4. + */ + mblen = (m_bitlen + 7) >> 3; + k = mblen - 1; + + /* + * Up to k bytes can be safely decoded. + */ + if (k >= len) { + br_i32_decode(x, src, len); + x[0] = m_bitlen; + return; + } + + /* + * We want to first inject some bytes with direct decoding, + * then extra bytes by whole 32-bit words. First compute + * the size that should be injected that way. + */ + buf = src; + q = (len - k + 3) & ~(size_t)3; + + /* + * It may happen that this is more than what we already have + * (by at most 3 bytes). Such a case may happen only with + * a very short modulus. In that case, we must process the first + * bytes "manually". + */ + if (q > len) { + int i; + uint32_t w; + + w = 0; + for (i = 0; i < 4; i ++) { + w <<= 8; + if (q <= len) { + w |= buf[len - q]; + } + q --; + } + br_i32_muladd_small(x, w, m); + } else { + br_i32_decode(x, buf, len - q); + x[0] = m_bitlen; + } + + /* + * At that point, we have exactly q bytes to inject, and q is + * a multiple of 4. + */ + for (k = len - q; k < len; k += 4) { + br_i32_muladd_small(x, br_dec32be(buf + k), m); + } +} diff --git a/src/bearssl/src/int/i32_div32.c b/src/bearssl/src/int/i32_div32.c new file mode 100644 index 0000000..d8b8023 --- /dev/null +++ b/src/bearssl/src/int/i32_div32.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r) +{ + /* TODO: optimize this */ + uint32_t q; + uint32_t ch, cf; + int k; + + q = 0; + ch = EQ(hi, d); + hi = MUX(ch, 0, hi); + for (k = 31; k > 0; k --) { + int j; + uint32_t w, ctl, hi2, lo2; + + j = 32 - k; + w = (hi << j) | (lo >> k); + ctl = GE(w, d) | (hi >> k); + hi2 = (w - d) >> j; + lo2 = lo - (d << k); + hi = MUX(ctl, hi2, hi); + lo = MUX(ctl, lo2, lo); + q |= ctl << k; + } + cf = GE(lo, d) | hi; + q |= cf; + *r = MUX(cf, lo - d, lo); + return q; +} diff --git a/src/bearssl/src/int/i32_encode.c b/src/bearssl/src/int/i32_encode.c new file mode 100644 index 0000000..303652f --- /dev/null +++ b/src/bearssl/src/int/i32_encode.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_encode(void *dst, size_t len, const uint32_t *x) +{ + unsigned char *buf; + size_t k; + + buf = dst; + + /* + * Compute the announced size of x in bytes; extra bytes are + * filled with zeros. + */ + k = (x[0] + 7) >> 3; + while (len > k) { + *buf ++ = 0; + len --; + } + + /* + * Now we use k as index within x[]. That index starts at 1; + * we initialize it to the topmost complete word, and process + * any remaining incomplete word. + */ + k = (len + 3) >> 2; + switch (len & 3) { + case 3: + *buf ++ = x[k] >> 16; + /* fall through */ + case 2: + *buf ++ = x[k] >> 8; + /* fall through */ + case 1: + *buf ++ = x[k]; + k --; + } + + /* + * Encode all complete words. + */ + while (k > 0) { + br_enc32be(buf, x[k]); + k --; + buf += 4; + } +} diff --git a/src/bearssl/src/int/i32_fmont.c b/src/bearssl/src/int/i32_fmont.c new file mode 100644 index 0000000..dc1c934 --- /dev/null +++ b/src/bearssl/src/int/i32_fmont.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i) +{ + size_t len, u, v; + + len = (m[0] + 31) >> 5; + for (u = 0; u < len; u ++) { + uint32_t f; + uint64_t cc; + + f = x[1] * m0i; + cc = 0; + for (v = 0; v < len; v ++) { + uint64_t z; + + z = (uint64_t)x[v + 1] + MUL(f, m[v + 1]) + cc; + cc = z >> 32; + if (v != 0) { + x[v] = (uint32_t)z; + } + } + x[len] = (uint32_t)cc; + } + + /* + * We may have to do an extra subtraction, but only if the + * value in x[] is indeed greater than or equal to that of m[], + * which is why we must do two calls (first call computes the + * carry, second call performs the subtraction only if the carry + * is 0). + */ + br_i32_sub(x, m, NOT(br_i32_sub(x, m, 0))); +} diff --git a/src/bearssl/src/int/i32_iszero.c b/src/bearssl/src/int/i32_iszero.c new file mode 100644 index 0000000..659df7f --- /dev/null +++ b/src/bearssl/src/int/i32_iszero.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i32_iszero(const uint32_t *x) +{ + uint32_t z; + size_t u; + + z = 0; + for (u = (x[0] + 31) >> 5; u > 0; u --) { + z |= x[u]; + } + return ~(z | -z) >> 31; +} diff --git a/src/bearssl/src/int/i32_modpow.c b/src/bearssl/src/int/i32_modpow.c new file mode 100644 index 0000000..034aba0 --- /dev/null +++ b/src/bearssl/src/int/i32_modpow.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_modpow(uint32_t *x, + const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2) +{ + size_t mlen; + uint32_t k; + + /* + * 'mlen' is the length of m[] expressed in bytes (including + * the "bit length" first field). + */ + mlen = ((m[0] + 63) >> 5) * sizeof m[0]; + + /* + * Throughout the algorithm: + * -- t1[] is in Montgomery representation; it contains x, x^2, + * x^4, x^8... + * -- The result is accumulated, in normal representation, in + * the x[] array. + * -- t2[] is used as destination buffer for each multiplication. + * + * Note that there is no need to call br_i32_from_monty(). + */ + memcpy(t1, x, mlen); + br_i32_to_monty(t1, m); + br_i32_zero(x, m[0]); + x[1] = 1; + for (k = 0; k < ((uint32_t)elen << 3); k ++) { + uint32_t ctl; + + ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1; + br_i32_montymul(t2, x, t1, m, m0i); + CCOPY(ctl, x, t2, mlen); + br_i32_montymul(t2, t1, t1, m, m0i); + memcpy(t1, t2, mlen); + } +} diff --git a/src/bearssl/src/int/i32_montmul.c b/src/bearssl/src/int/i32_montmul.c new file mode 100644 index 0000000..7edb376 --- /dev/null +++ b/src/bearssl/src/int/i32_montmul.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i) +{ + size_t len, u, v; + uint64_t dh; + + len = (m[0] + 31) >> 5; + br_i32_zero(d, m[0]); + dh = 0; + for (u = 0; u < len; u ++) { + uint32_t f, xu; + uint64_t r1, r2, zh; + + xu = x[u + 1]; + f = (d[1] + x[u + 1] * y[1]) * m0i; + r1 = 0; + r2 = 0; + for (v = 0; v < len; v ++) { + uint64_t z; + uint32_t t; + + z = (uint64_t)d[v + 1] + MUL(xu, y[v + 1]) + r1; + r1 = z >> 32; + t = (uint32_t)z; + z = (uint64_t)t + MUL(f, m[v + 1]) + r2; + r2 = z >> 32; + if (v != 0) { + d[v] = (uint32_t)z; + } + } + zh = dh + r1 + r2; + d[len] = (uint32_t)zh; + dh = zh >> 32; + } + + /* + * d[] may still be greater than m[] at that point; notably, the + * 'dh' word may be non-zero. + */ + br_i32_sub(d, m, NEQ(dh, 0) | NOT(br_i32_sub(d, m, 0))); +} diff --git a/src/bearssl/src/int/i32_mulacc.c b/src/bearssl/src/int/i32_mulacc.c new file mode 100644 index 0000000..f62c782 --- /dev/null +++ b/src/bearssl/src/int/i32_mulacc.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b) +{ + size_t alen, blen, u; + + alen = (a[0] + 31) >> 5; + blen = (b[0] + 31) >> 5; + d[0] = a[0] + b[0]; + for (u = 0; u < blen; u ++) { + uint32_t f; + size_t v; + uint64_t cc; + + f = b[1 + u]; + cc = 0; + for (v = 0; v < alen; v ++) { + uint64_t z; + + z = (uint64_t)d[1 + u + v] + MUL(f, a[1 + v]) + cc; + cc = z >> 32; + d[1 + u + v] = (uint32_t)z; + } + d[1 + u + alen] = (uint32_t)cc; + } +} diff --git a/src/bearssl/src/int/i32_muladd.c b/src/bearssl/src/int/i32_muladd.c new file mode 100644 index 0000000..dd526ad --- /dev/null +++ b/src/bearssl/src/int/i32_muladd.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m) +{ + uint32_t m_bitlen; + size_t u, mlen; + uint32_t a0, a1, b0, hi, g, q, tb; + uint32_t chf, clow, under, over; + uint64_t cc; + + /* + * We can test on the modulus bit length since we accept to + * leak that length. + */ + m_bitlen = m[0]; + if (m_bitlen == 0) { + return; + } + if (m_bitlen <= 32) { + x[1] = br_rem(x[1], z, m[1]); + return; + } + mlen = (m_bitlen + 31) >> 5; + + /* + * Principle: we estimate the quotient (x*2^32+z)/m by + * doing a 64/32 division with the high words. + * + * Let: + * w = 2^32 + * a = (w*a0 + a1) * w^N + a2 + * b = b0 * w^N + b2 + * such that: + * 0 <= a0 < w + * 0 <= a1 < w + * 0 <= a2 < w^N + * w/2 <= b0 < w + * 0 <= b2 < w^N + * a < w*b + * I.e. the two top words of a are a0:a1, the top word of b is + * b0, we ensured that b0 is "full" (high bit set), and a is + * such that the quotient q = a/b fits on one word (0 <= q < w). + * + * If a = b*q + r (with 0 <= r < q), we can estimate q by + * doing an Euclidean division on the top words: + * a0*w+a1 = b0*u + v (with 0 <= v < w) + * Then the following holds: + * 0 <= u <= w + * u-2 <= q <= u + */ + a0 = br_i32_word(x, m_bitlen - 32); + hi = x[mlen]; + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a1 = br_i32_word(x, m_bitlen - 32); + b0 = br_i32_word(m, m_bitlen - 32); + + /* + * We estimate a divisor q. If the quotient returned by br_div() + * is g: + * -- If a0 == b0 then g == 0; we want q = 0xFFFFFFFF. + * -- Otherwise: + * -- if g == 0 then we set q = 0; + * -- otherwise, we set q = g - 1. + * The properties described above then ensure that the true + * quotient is q-1, q or q+1. + */ + g = br_div(a0, a1, b0); + q = MUX(EQ(a0, b0), 0xFFFFFFFF, MUX(EQ(g, 0), 0, g - 1)); + + /* + * We subtract q*m from x (with the extra high word of value 'hi'). + * Since q may be off by 1 (in either direction), we may have to + * add or subtract m afterwards. + * + * The 'tb' flag will be true (1) at the end of the loop if the + * result is greater than or equal to the modulus (not counting + * 'hi' or the carry). + */ + cc = 0; + tb = 1; + for (u = 1; u <= mlen; u ++) { + uint32_t mw, zw, xw, nxw; + uint64_t zl; + + mw = m[u]; + zl = MUL(mw, q) + cc; + cc = (uint32_t)(zl >> 32); + zw = (uint32_t)zl; + xw = x[u]; + nxw = xw - zw; + cc += (uint64_t)GT(nxw, xw); + x[u] = nxw; + tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw)); + } + + /* + * If we underestimated q, then either cc < hi (one extra bit + * beyond the top array word), or cc == hi and tb is true (no + * extra bit, but the result is not lower than the modulus). In + * these cases we must subtract m once. + * + * Otherwise, we may have overestimated, which will show as + * cc > hi (thus a negative result). Correction is adding m once. + */ + chf = (uint32_t)(cc >> 32); + clow = (uint32_t)cc; + over = chf | GT(clow, hi); + under = ~over & (tb | (~chf & LT(clow, hi))); + br_i32_add(x, m, over); + br_i32_sub(x, m, under); +} diff --git a/src/bearssl/src/int/i32_ninv32.c b/src/bearssl/src/int/i32_ninv32.c new file mode 100644 index 0000000..6564434 --- /dev/null +++ b/src/bearssl/src/int/i32_ninv32.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i32_ninv32(uint32_t x) +{ + uint32_t y; + + y = 2 - x; + y *= 2 - y * x; + y *= 2 - y * x; + y *= 2 - y * x; + y *= 2 - y * x; + return MUX(x & 1, -y, 0); +} diff --git a/src/bearssl/src/int/i32_reduce.c b/src/bearssl/src/int/i32_reduce.c new file mode 100644 index 0000000..90fff09 --- /dev/null +++ b/src/bearssl/src/int/i32_reduce.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m) +{ + uint32_t m_bitlen, a_bitlen; + size_t mlen, alen, u; + + m_bitlen = m[0]; + mlen = (m_bitlen + 31) >> 5; + + x[0] = m_bitlen; + if (m_bitlen == 0) { + return; + } + + /* + * If the source is shorter, then simply copy all words from a[] + * and zero out the upper words. + */ + a_bitlen = a[0]; + alen = (a_bitlen + 31) >> 5; + if (a_bitlen < m_bitlen) { + memcpy(x + 1, a + 1, alen * sizeof *a); + for (u = alen; u < mlen; u ++) { + x[u + 1] = 0; + } + return; + } + + /* + * The source length is at least equal to that of the modulus. + * We must thus copy N-1 words, and input the remaining words + * one by one. + */ + memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a); + x[mlen] = 0; + for (u = 1 + alen - mlen; u > 0; u --) { + br_i32_muladd_small(x, a[u], m); + } +} diff --git a/src/bearssl/src/int/i32_sub.c b/src/bearssl/src/int/i32_sub.c new file mode 100644 index 0000000..9c50023 --- /dev/null +++ b/src/bearssl/src/int/i32_sub.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 63) >> 5; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw - bw - cc; + + /* + * Carry is 1 if naw > aw. Carry is 1 also if naw == aw + * AND the carry was already 1. + */ + cc = (cc & EQ(naw, aw)) | GT(naw, aw); + a[u] = MUX(ctl, naw, aw); + } + return cc; +} diff --git a/src/bearssl/src/int/i32_tmont.c b/src/bearssl/src/int/i32_tmont.c new file mode 100644 index 0000000..058cd88 --- /dev/null +++ b/src/bearssl/src/int/i32_tmont.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i32_to_monty(uint32_t *x, const uint32_t *m) +{ + uint32_t k; + + for (k = (m[0] + 31) >> 5; k > 0; k --) { + br_i32_muladd_small(x, 0, m); + } +} diff --git a/src/bearssl/src/int/i62_modpow2.c b/src/bearssl/src/int/i62_modpow2.c new file mode 100644 index 0000000..2db537f --- /dev/null +++ b/src/bearssl/src/int/i62_modpow2.c @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +#if BR_INT128 + +/* + * Compute x*y+v1+v2. Operands are 64-bit, and result is 128-bit, with + * high word in "hi" and low word in "lo". + */ +#define FMA1(hi, lo, x, y, v1, v2) do { \ + unsigned __int128 fmaz; \ + fmaz = (unsigned __int128)(x) * (unsigned __int128)(y) \ + + (unsigned __int128)(v1) + (unsigned __int128)(v2); \ + (hi) = (uint64_t)(fmaz >> 64); \ + (lo) = (uint64_t)fmaz; \ + } while (0) + +/* + * Compute x1*y1+x2*y2+v1+v2. Operands are 64-bit, and result is 128-bit, + * with high word in "hi" and low word in "lo". + * + * Callers should ensure that the two inner products, and the v1 and v2 + * operands, are multiple of 4 (this is not used by this specific definition + * but may help other implementations). + */ +#define FMA2(hi, lo, x1, y1, x2, y2, v1, v2) do { \ + unsigned __int128 fmaz; \ + fmaz = (unsigned __int128)(x1) * (unsigned __int128)(y1) \ + + (unsigned __int128)(x2) * (unsigned __int128)(y2) \ + + (unsigned __int128)(v1) + (unsigned __int128)(v2); \ + (hi) = (uint64_t)(fmaz >> 64); \ + (lo) = (uint64_t)fmaz; \ + } while (0) + +#elif BR_UMUL128 + +#include + +#define FMA1(hi, lo, x, y, v1, v2) do { \ + uint64_t fmahi, fmalo; \ + unsigned char fmacc; \ + fmalo = _umul128((x), (y), &fmahi); \ + fmacc = _addcarry_u64(0, fmalo, (v1), &fmalo); \ + _addcarry_u64(fmacc, fmahi, 0, &fmahi); \ + fmacc = _addcarry_u64(0, fmalo, (v2), &(lo)); \ + _addcarry_u64(fmacc, fmahi, 0, &(hi)); \ + } while (0) + +/* + * Normally we should use _addcarry_u64() for FMA2 too, but it makes + * Visual Studio crash. Instead we use this version, which leverages + * the fact that the vx operands, and the products, are multiple of 4. + * This is unfortunately slower. + */ +#define FMA2(hi, lo, x1, y1, x2, y2, v1, v2) do { \ + uint64_t fma1hi, fma1lo; \ + uint64_t fma2hi, fma2lo; \ + uint64_t fmatt; \ + fma1lo = _umul128((x1), (y1), &fma1hi); \ + fma2lo = _umul128((x2), (y2), &fma2hi); \ + fmatt = (fma1lo >> 2) + (fma2lo >> 2) \ + + ((v1) >> 2) + ((v2) >> 2); \ + (lo) = fmatt << 2; \ + (hi) = fma1hi + fma2hi + (fmatt >> 62); \ + } while (0) + +/* + * The FMA2 macro definition we would prefer to use, but it triggers + * an internal compiler error in Visual Studio 2015. + * +#define FMA2(hi, lo, x1, y1, x2, y2, v1, v2) do { \ + uint64_t fma1hi, fma1lo; \ + uint64_t fma2hi, fma2lo; \ + unsigned char fmacc; \ + fma1lo = _umul128((x1), (y1), &fma1hi); \ + fma2lo = _umul128((x2), (y2), &fma2hi); \ + fmacc = _addcarry_u64(0, fma1lo, (v1), &fma1lo); \ + _addcarry_u64(fmacc, fma1hi, 0, &fma1hi); \ + fmacc = _addcarry_u64(0, fma2lo, (v2), &fma2lo); \ + _addcarry_u64(fmacc, fma2hi, 0, &fma2hi); \ + fmacc = _addcarry_u64(0, fma1lo, fma2lo, &(lo)); \ + _addcarry_u64(fmacc, fma1hi, fma2hi, &(hi)); \ + } while (0) + */ + +#endif + +#define MASK62 ((uint64_t)0x3FFFFFFFFFFFFFFF) +#define MUL62_lo(x, y) (((uint64_t)(x) * (uint64_t)(y)) & MASK62) + +/* + * Subtract b from a, and return the final carry. If 'ctl32' is 0, then + * a[] is kept unmodified, but the final carry is still computed and + * returned. + */ +static uint32_t +i62_sub(uint64_t *a, const uint64_t *b, size_t num, uint32_t ctl32) +{ + uint64_t cc, mask; + size_t u; + + cc = 0; + ctl32 = -ctl32; + mask = (uint64_t)ctl32 | ((uint64_t)ctl32 << 32); + for (u = 0; u < num; u ++) { + uint64_t aw, bw, dw; + + aw = a[u]; + bw = b[u]; + dw = aw - bw - cc; + cc = dw >> 63; + dw &= MASK62; + a[u] = aw ^ (mask & (dw ^ aw)); + } + return (uint32_t)cc; +} + +/* + * Montgomery multiplication, over arrays of 62-bit values. The + * destination array (d) must be distinct from the other operands + * (x, y and m). All arrays are in little-endian format (least + * significant word comes first) over 'num' words. + */ +static void +montymul(uint64_t *d, const uint64_t *x, const uint64_t *y, + const uint64_t *m, size_t num, uint64_t m0i) +{ + uint64_t dh; + size_t u, num4; + + num4 = 1 + ((num - 1) & ~(size_t)3); + memset(d, 0, num * sizeof *d); + dh = 0; + for (u = 0; u < num; u ++) { + size_t v; + uint64_t f, xu; + uint64_t r, zh; + uint64_t hi, lo; + + xu = x[u] << 2; + f = MUL62_lo(d[0] + MUL62_lo(x[u], y[0]), m0i) << 2; + + FMA2(hi, lo, xu, y[0], f, m[0], d[0] << 2, 0); + r = hi; + + for (v = 1; v < num4; v += 4) { + FMA2(hi, lo, xu, y[v + 0], + f, m[v + 0], d[v + 0] << 2, r << 2); + r = hi + (r >> 62); + d[v - 1] = lo >> 2; + FMA2(hi, lo, xu, y[v + 1], + f, m[v + 1], d[v + 1] << 2, r << 2); + r = hi + (r >> 62); + d[v + 0] = lo >> 2; + FMA2(hi, lo, xu, y[v + 2], + f, m[v + 2], d[v + 2] << 2, r << 2); + r = hi + (r >> 62); + d[v + 1] = lo >> 2; + FMA2(hi, lo, xu, y[v + 3], + f, m[v + 3], d[v + 3] << 2, r << 2); + r = hi + (r >> 62); + d[v + 2] = lo >> 2; + } + for (; v < num; v ++) { + FMA2(hi, lo, xu, y[v], f, m[v], d[v] << 2, r << 2); + r = hi + (r >> 62); + d[v - 1] = lo >> 2; + } + + zh = dh + r; + d[num - 1] = zh & MASK62; + dh = zh >> 62; + } + i62_sub(d, m, num, (uint32_t)dh | NOT(i62_sub(d, m, num, 0))); +} + +/* + * Conversion back from Montgomery representation. + */ +static void +frommonty(uint64_t *x, const uint64_t *m, size_t num, uint64_t m0i) +{ + size_t u, v; + + for (u = 0; u < num; u ++) { + uint64_t f, cc; + + f = MUL62_lo(x[0], m0i) << 2; + cc = 0; + for (v = 0; v < num; v ++) { + uint64_t hi, lo; + + FMA1(hi, lo, f, m[v], x[v] << 2, cc); + cc = hi << 2; + if (v != 0) { + x[v - 1] = lo >> 2; + } + } + x[num - 1] = cc >> 2; + } + i62_sub(x, m, num, NOT(i62_sub(x, m, num, 0))); +} + +/* see inner.h */ +uint32_t +br_i62_modpow_opt(uint32_t *x31, const unsigned char *e, size_t elen, + const uint32_t *m31, uint32_t m0i31, uint64_t *tmp, size_t twlen) +{ + size_t u, mw31num, mw62num; + uint64_t *x, *m, *t1, *t2; + uint64_t m0i; + uint32_t acc; + int win_len, acc_len; + + /* + * Get modulus size, in words. + */ + mw31num = (m31[0] + 31) >> 5; + mw62num = (mw31num + 1) >> 1; + + /* + * In order to apply this function, we must have enough room to + * copy the operand and modulus into the temporary array, along + * with at least two temporaries. If there is not enough room, + * switch to br_i31_modpow(). We also use br_i31_modpow() if the + * modulus length is not at least four words (94 bits or more). + */ + if (mw31num < 4 || (mw62num << 2) > twlen) { + /* + * We assume here that we can split an aligned uint64_t + * into two properly aligned uint32_t. Since both types + * are supposed to have an exact width with no padding, + * then this property must hold. + */ + size_t txlen; + + txlen = mw31num + 1; + if (twlen < txlen) { + return 0; + } + br_i31_modpow(x31, e, elen, m31, m0i31, + (uint32_t *)tmp, (uint32_t *)tmp + txlen); + return 1; + } + + /* + * Convert x to Montgomery representation: this means that + * we replace x with x*2^z mod m, where z is the smallest multiple + * of the word size such that 2^z >= m. We want to reuse the 31-bit + * functions here (for constant-time operation), but we need z + * for a 62-bit word size. + */ + for (u = 0; u < mw62num; u ++) { + br_i31_muladd_small(x31, 0, m31); + br_i31_muladd_small(x31, 0, m31); + } + + /* + * Assemble operands into arrays of 62-bit words. Note that + * all the arrays of 62-bit words that we will handle here + * are without any leading size word. + * + * We also adjust tmp and twlen to account for the words used + * for these extra arrays. + */ + m = tmp; + x = tmp + mw62num; + tmp += (mw62num << 1); + twlen -= (mw62num << 1); + for (u = 0; u < mw31num; u += 2) { + size_t v; + + v = u >> 1; + if ((u + 1) == mw31num) { + m[v] = (uint64_t)m31[u + 1]; + x[v] = (uint64_t)x31[u + 1]; + } else { + m[v] = (uint64_t)m31[u + 1] + + ((uint64_t)m31[u + 2] << 31); + x[v] = (uint64_t)x31[u + 1] + + ((uint64_t)x31[u + 2] << 31); + } + } + + /* + * Compute window size. We support windows up to 5 bits; for a + * window of size k bits, we need 2^k+1 temporaries (for k = 1, + * we use special code that uses only 2 temporaries). + */ + for (win_len = 5; win_len > 1; win_len --) { + if ((((uint32_t)1 << win_len) + 1) * mw62num <= twlen) { + break; + } + } + + t1 = tmp; + t2 = tmp + mw62num; + + /* + * Compute m0i, which is equal to -(1/m0) mod 2^62. We were + * provided with m0i31, which already fulfills this property + * modulo 2^31; the single expression below is then sufficient. + */ + m0i = (uint64_t)m0i31; + m0i = MUL62_lo(m0i, (uint64_t)2 + MUL62_lo(m0i, m[0])); + + /* + * Compute window contents. If the window has size one bit only, + * then t2 is set to x; otherwise, t2[0] is left untouched, and + * t2[k] is set to x^k (for k >= 1). + */ + if (win_len == 1) { + memcpy(t2, x, mw62num * sizeof *x); + } else { + uint64_t *base; + + memcpy(t2 + mw62num, x, mw62num * sizeof *x); + base = t2 + mw62num; + for (u = 2; u < ((unsigned)1 << win_len); u ++) { + montymul(base + mw62num, base, x, m, mw62num, m0i); + base += mw62num; + } + } + + /* + * Set x to 1, in Montgomery representation. We again use the + * 31-bit code. + */ + br_i31_zero(x31, m31[0]); + x31[(m31[0] + 31) >> 5] = 1; + br_i31_muladd_small(x31, 0, m31); + if (mw31num & 1) { + br_i31_muladd_small(x31, 0, m31); + } + for (u = 0; u < mw31num; u += 2) { + size_t v; + + v = u >> 1; + if ((u + 1) == mw31num) { + x[v] = (uint64_t)x31[u + 1]; + } else { + x[v] = (uint64_t)x31[u + 1] + + ((uint64_t)x31[u + 2] << 31); + } + } + + /* + * We process bits from most to least significant. At each + * loop iteration, we have acc_len bits in acc. + */ + acc = 0; + acc_len = 0; + while (acc_len > 0 || elen > 0) { + int i, k; + uint32_t bits; + uint64_t mask1, mask2; + + /* + * Get the next bits. + */ + k = win_len; + if (acc_len < win_len) { + if (elen > 0) { + acc = (acc << 8) | *e ++; + elen --; + acc_len += 8; + } else { + k = acc_len; + } + } + bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1); + acc_len -= k; + + /* + * We could get exactly k bits. Compute k squarings. + */ + for (i = 0; i < k; i ++) { + montymul(t1, x, x, m, mw62num, m0i); + memcpy(x, t1, mw62num * sizeof *x); + } + + /* + * Window lookup: we want to set t2 to the window + * lookup value, assuming the bits are non-zero. If + * the window length is 1 bit only, then t2 is + * already set; otherwise, we do a constant-time lookup. + */ + if (win_len > 1) { + uint64_t *base; + + memset(t2, 0, mw62num * sizeof *t2); + base = t2 + mw62num; + for (u = 1; u < ((uint32_t)1 << k); u ++) { + uint64_t mask; + size_t v; + + mask = -(uint64_t)EQ(u, bits); + for (v = 0; v < mw62num; v ++) { + t2[v] |= mask & base[v]; + } + base += mw62num; + } + } + + /* + * Multiply with the looked-up value. We keep the product + * only if the exponent bits are not all-zero. + */ + montymul(t1, x, t2, m, mw62num, m0i); + mask1 = -(uint64_t)EQ(bits, 0); + mask2 = ~mask1; + for (u = 0; u < mw62num; u ++) { + x[u] = (mask1 & x[u]) | (mask2 & t1[u]); + } + } + + /* + * Convert back from Montgomery representation. + */ + frommonty(x, m, mw62num, m0i); + + /* + * Convert result into 31-bit words. + */ + for (u = 0; u < mw31num; u += 2) { + uint64_t zw; + + zw = x[u >> 1]; + x31[u + 1] = (uint32_t)zw & 0x7FFFFFFF; + if ((u + 1) < mw31num) { + x31[u + 2] = (uint32_t)(zw >> 31); + } + } + return 1; +} + +#else + +/* see inner.h */ +uint32_t +br_i62_modpow_opt(uint32_t *x31, const unsigned char *e, size_t elen, + const uint32_t *m31, uint32_t m0i31, uint64_t *tmp, size_t twlen) +{ + size_t mwlen; + + mwlen = (m31[0] + 63) >> 5; + if (twlen < mwlen) { + return 0; + } + return br_i31_modpow_opt(x31, e, elen, m31, m0i31, + (uint32_t *)tmp, twlen << 1); +} + +#endif + +/* see inner.h */ +uint32_t +br_i62_modpow_opt_as_i31(uint32_t *x31, const unsigned char *e, size_t elen, + const uint32_t *m31, uint32_t m0i31, uint32_t *tmp, size_t twlen) +{ + /* + * As documented, this function expects the 'tmp' argument to be + * 64-bit aligned. This is OK since this function is internal (it + * is not part of BearSSL's public API). + */ + return br_i62_modpow_opt(x31, e, elen, m31, m0i31, + (uint64_t *)tmp, twlen >> 1); +} diff --git a/src/bearssl/src/kdf/hkdf.c b/src/bearssl/src/kdf/hkdf.c new file mode 100644 index 0000000..6a36851 --- /dev/null +++ b/src/bearssl/src/kdf/hkdf.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +const unsigned char br_hkdf_no_salt = 0; + +/* see bearssl_kdf.h */ +void +br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable, + const void *salt, size_t salt_len) +{ + br_hmac_key_context kc; + unsigned char tmp[64]; + + if (salt == BR_HKDF_NO_SALT) { + salt = tmp; + salt_len = br_digest_size(digest_vtable); + memset(tmp, 0, salt_len); + } + br_hmac_key_init(&kc, digest_vtable, salt, salt_len); + br_hmac_init(&hc->u.hmac_ctx, &kc, 0); + hc->dig_len = br_hmac_size(&hc->u.hmac_ctx); +} + +/* see bearssl_kdf.h */ +void +br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len) +{ + br_hmac_update(&hc->u.hmac_ctx, ikm, ikm_len); +} + +/* see bearssl_kdf.h */ +void +br_hkdf_flip(br_hkdf_context *hc) +{ + unsigned char tmp[64]; + + br_hmac_out(&hc->u.hmac_ctx, tmp); + br_hmac_key_init(&hc->u.prk_ctx, + br_hmac_get_digest(&hc->u.hmac_ctx), tmp, hc->dig_len); + hc->ptr = hc->dig_len; + hc->chunk_num = 0; +} + +/* see bearssl_kdf.h */ +size_t +br_hkdf_produce(br_hkdf_context *hc, + const void *info, size_t info_len, void *out, size_t out_len) +{ + size_t tlen; + + tlen = 0; + while (out_len > 0) { + size_t clen; + + if (hc->ptr == hc->dig_len) { + br_hmac_context hmac_ctx; + unsigned char x; + + hc->chunk_num ++; + if (hc->chunk_num == 256) { + return tlen; + } + x = hc->chunk_num; + br_hmac_init(&hmac_ctx, &hc->u.prk_ctx, 0); + if (x != 1) { + br_hmac_update(&hmac_ctx, hc->buf, hc->dig_len); + } + br_hmac_update(&hmac_ctx, info, info_len); + br_hmac_update(&hmac_ctx, &x, 1); + br_hmac_out(&hmac_ctx, hc->buf); + hc->ptr = 0; + } + clen = hc->dig_len - hc->ptr; + if (clen > out_len) { + clen = out_len; + } + memcpy(out, hc->buf + hc->ptr, clen); + out = (unsigned char *)out + clen; + out_len -= clen; + hc->ptr += clen; + tlen += clen; + } + return tlen; +} diff --git a/src/bearssl/src/mac/hmac.c b/src/bearssl/src/mac/hmac.c new file mode 100644 index 0000000..b438798 --- /dev/null +++ b/src/bearssl/src/mac/hmac.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static inline size_t +block_size(const br_hash_class *dig) +{ + unsigned ls; + + ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF) + & BR_HASHDESC_LBLEN_MASK; + return (size_t)1 << ls; +} + +static void +process_key(const br_hash_class **hc, void *ks, + const void *key, size_t key_len, unsigned bb) +{ + unsigned char tmp[256]; + size_t blen, u; + + blen = block_size(*hc); + memcpy(tmp, key, key_len); + for (u = 0; u < key_len; u ++) { + tmp[u] ^= (unsigned char)bb; + } + memset(tmp + key_len, bb, blen - key_len); + (*hc)->init(hc); + (*hc)->update(hc, tmp, blen); + (*hc)->state(hc, ks); +} + +/* see bearssl.h */ +void +br_hmac_key_init(br_hmac_key_context *kc, + const br_hash_class *dig, const void *key, size_t key_len) +{ + br_hash_compat_context hc; + unsigned char kbuf[64]; + + kc->dig_vtable = dig; + hc.vtable = dig; + if (key_len > block_size(dig)) { + dig->init(&hc.vtable); + dig->update(&hc.vtable, key, key_len); + dig->out(&hc.vtable, kbuf); + key = kbuf; + key_len = br_digest_size(dig); + } + process_key(&hc.vtable, kc->ksi, key, key_len, 0x36); + process_key(&hc.vtable, kc->kso, key, key_len, 0x5C); +} + +/* see bearssl.h */ +void +br_hmac_init(br_hmac_context *ctx, + const br_hmac_key_context *kc, size_t out_len) +{ + const br_hash_class *dig; + size_t blen, hlen; + + dig = kc->dig_vtable; + blen = block_size(dig); + dig->init(&ctx->dig.vtable); + dig->set_state(&ctx->dig.vtable, kc->ksi, (uint64_t)blen); + memcpy(ctx->kso, kc->kso, sizeof kc->kso); + hlen = br_digest_size(dig); + if (out_len > 0 && out_len < hlen) { + hlen = out_len; + } + ctx->out_len = hlen; +} + +/* see bearssl.h */ +void +br_hmac_update(br_hmac_context *ctx, const void *data, size_t len) +{ + ctx->dig.vtable->update(&ctx->dig.vtable, data, len); +} + +/* see bearssl.h */ +size_t +br_hmac_out(const br_hmac_context *ctx, void *out) +{ + const br_hash_class *dig; + br_hash_compat_context hc; + unsigned char tmp[64]; + size_t blen, hlen; + + dig = ctx->dig.vtable; + dig->out(&ctx->dig.vtable, tmp); + blen = block_size(dig); + dig->init(&hc.vtable); + dig->set_state(&hc.vtable, ctx->kso, (uint64_t)blen); + hlen = br_digest_size(dig); + dig->update(&hc.vtable, tmp, hlen); + dig->out(&hc.vtable, tmp); + memcpy(out, tmp, ctx->out_len); + return ctx->out_len; +} diff --git a/src/bearssl/src/mac/hmac_ct.c b/src/bearssl/src/mac/hmac_ct.c new file mode 100644 index 0000000..e1c1d80 --- /dev/null +++ b/src/bearssl/src/mac/hmac_ct.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static inline size_t +hash_size(const br_hash_class *dig) +{ + return (unsigned)(dig->desc >> BR_HASHDESC_OUT_OFF) + & BR_HASHDESC_OUT_MASK; +} + +static inline size_t +block_size(const br_hash_class *dig) +{ + unsigned ls; + + ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF) + & BR_HASHDESC_LBLEN_MASK; + return (size_t)1 << ls; +} + +/* see bearssl.h */ +size_t +br_hmac_outCT(const br_hmac_context *ctx, + const void *data, size_t len, size_t min_len, size_t max_len, + void *out) +{ + /* + * Method implemented here is inspired from the descriptions on: + * https://www.imperialviolet.org/2013/02/04/luckythirteen.html + * + * Principle: we input bytes one by one. We use a MUX to push + * padding bytes instead of data bytes when appropriate. At each + * block limit, we get the current hash function state: this is + * a potential output, since we handle MD padding ourselves. + * + * be 1 for big-endian, 0 for little-endian + * po minimal MD padding length + * bs block size (always a power of 2) + * hlen hash output size + */ + + const br_hash_class *dig; + br_hash_compat_context hc; + int be; + uint32_t po, bs; + uint32_t kr, km, kl, kz, u; + uint64_t count, ncount, bit_len; + unsigned char tmp1[64], tmp2[64]; + size_t hlen; + + /* + * Copy the current hash context. + */ + hc = ctx->dig; + + /* + * Get function-specific information. + */ + dig = hc.vtable; + be = (dig->desc & BR_HASHDESC_MD_PADDING_BE) != 0; + po = 9; + if (dig->desc & BR_HASHDESC_MD_PADDING_128) { + po += 8; + } + bs = block_size(dig); + hlen = hash_size(dig); + + /* + * Get current input length and compute total bit length. + */ + count = dig->state(&hc.vtable, tmp1); + bit_len = (count + (uint64_t)len) << 3; + + /* + * We can input the blocks that we are sure we will use. + * This offers better performance (no MUX for these blocks) + * and also ensures that the remaining lengths fit on 32 bits. + */ + ncount = (count + (uint64_t)min_len) & ~(uint64_t)(bs - 1); + if (ncount > count) { + size_t zlen; + + zlen = (size_t)(ncount - count); + dig->update(&hc.vtable, data, zlen); + data = (const unsigned char *)data + zlen; + len -= zlen; + max_len -= zlen; + count = ncount; + } + + /* + * At that point: + * -- 'count' contains the number of bytes already processed + * (in total). + * -- We must input 'len' bytes. 'min_len' is unimportant: we + * used it to know how many full blocks we could process + * directly. Now only len and max_len matter. + * + * We compute kr, kl, kz and km. + * kr number of input bytes already in the current block + * km index of the first byte after the end of the last padding + * block, if length is max_len + * kz index of the last byte of the actual last padding block + * kl index of the start of the encoded length + * + * km, kz and kl are counted from the current offset in the + * input data. + */ + kr = (uint32_t)count & (bs - 1); + kz = ((kr + (uint32_t)len + po + bs - 1) & ~(bs - 1)) - 1 - kr; + kl = kz - 7; + km = ((kr + (uint32_t)max_len + po + bs - 1) & ~(bs - 1)) - kr; + + /* + * We must now process km bytes. For index u from 0 to km-1: + * d is from data[] if u < max_len, 0x00 otherwise + * e is an encoded length byte or 0x00, depending on u + * The tests for d and e need not be constant-time, since + * they relate only to u and max_len, not to the actual length. + * + * Actual input length is then: + * d if u < len + * 0x80 if u == len + * 0x00 if u > len and u < kl + * e if u >= kl + * + * Hash state is obtained whenever we reach a full block. This + * is the result we want if and only if u == kz. + */ + memset(tmp2, 0, sizeof tmp2); + for (u = 0; u < km; u ++) { + uint32_t v; + uint32_t d, e, x0, x1; + unsigned char x[1]; + + d = (u < max_len) ? ((const unsigned char *)data)[u] : 0x00; + v = (kr + u) & (bs - 1); + if (v >= (bs - 8)) { + unsigned j; + + j = (v - (bs - 8)) << 3; + if (be) { + e = (uint32_t)(bit_len >> (56 - j)); + } else { + e = (uint32_t)(bit_len >> j); + } + e &= 0xFF; + } else { + e = 0x00; + } + x0 = MUX(EQ(u, (uint32_t)len), 0x80, d); + x1 = MUX(LT(u, kl), 0x00, e); + x[0] = MUX(LE(u, (uint32_t)len), x0, x1); + dig->update(&hc.vtable, x, 1); + if (v == (bs - 1)) { + dig->state(&hc.vtable, tmp1); + CCOPY(EQ(u, kz), tmp2, tmp1, hlen); + } + } + + /* + * Inner hash output is in tmp2[]; we finish processing. + */ + dig->init(&hc.vtable); + dig->set_state(&hc.vtable, ctx->kso, (uint64_t)bs); + dig->update(&hc.vtable, tmp2, hlen); + dig->out(&hc.vtable, tmp2); + memcpy(out, tmp2, ctx->out_len); + return ctx->out_len; +} diff --git a/src/bearssl/src/rand/aesctr_drbg.c b/src/bearssl/src/rand/aesctr_drbg.c new file mode 100644 index 0000000..8dbd501 --- /dev/null +++ b/src/bearssl/src/rand/aesctr_drbg.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rand.h */ +void +br_aesctr_drbg_init(br_aesctr_drbg_context *ctx, + const br_block_ctr_class *aesctr, + const void *seed, size_t len) +{ + unsigned char tmp[16]; + + ctx->vtable = &br_aesctr_drbg_vtable; + memset(tmp, 0, sizeof tmp); + aesctr->init(&ctx->sk.vtable, tmp, 16); + ctx->cc = 0; + br_aesctr_drbg_update(ctx, seed, len); +} + +/* see bearssl_rand.h */ +void +br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, void *out, size_t len) +{ + unsigned char *buf; + unsigned char iv[12]; + + buf = out; + memset(iv, 0, sizeof iv); + while (len > 0) { + size_t clen; + + /* + * We generate data by blocks of at most 65280 bytes. This + * allows for unambiguously testing the counter overflow + * condition; also, it should work on 16-bit architectures + * (where 'size_t' is 16 bits only). + */ + clen = len; + if (clen > 65280) { + clen = 65280; + } + + /* + * We make sure that the counter won't exceed the configured + * limit. + */ + if ((uint32_t)(ctx->cc + ((clen + 15) >> 4)) > 32768) { + clen = (32768 - ctx->cc) << 4; + if (clen > len) { + clen = len; + } + } + + /* + * Run CTR. + */ + memset(buf, 0, clen); + ctx->cc = ctx->sk.vtable->run(&ctx->sk.vtable, + iv, ctx->cc, buf, clen); + buf += clen; + len -= clen; + + /* + * Every 32768 blocks, we force a state update. + */ + if (ctx->cc >= 32768) { + br_aesctr_drbg_update(ctx, NULL, 0); + } + } +} + +/* see bearssl_rand.h */ +void +br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, const void *seed, size_t len) +{ + /* + * We use a Hirose construction on AES-256 to make a hash function. + * Function definition: + * - running state consists in two 16-byte blocks G and H + * - initial values of G and H are conventional + * - there is a fixed block-sized constant C + * - for next data block m: + * set AES key to H||m + * G' = E(G) xor G + * H' = E(G xor C) xor G xor C + * G <- G', H <- H' + * - once all blocks have been processed, output is H||G + * + * Constants: + * G_init = B6 B6 ... B6 + * H_init = A5 A5 ... A5 + * C = 01 00 ... 00 + * + * With this hash function h(), we compute the new state as + * follows: + * - produce a state-dependent value s as encryption of an + * all-one block with AES and the current key + * - compute the new key as the first 128 bits of h(s||seed) + * + * Original Hirose article: + * https://www.iacr.org/archive/fse2006/40470213/40470213.pdf + */ + + unsigned char s[16], iv[12]; + unsigned char G[16], H[16]; + int first; + + /* + * Use an all-one IV to get a fresh output block that depends on the + * current seed. + */ + memset(iv, 0xFF, sizeof iv); + memset(s, 0, 16); + ctx->sk.vtable->run(&ctx->sk.vtable, iv, 0xFFFFFFFF, s, 16); + + /* + * Set G[] and H[] to conventional start values. + */ + memset(G, 0xB6, sizeof G); + memset(H, 0x5A, sizeof H); + + /* + * Process the concatenation of the current state and the seed + * with the custom hash function. + */ + first = 1; + for (;;) { + unsigned char tmp[32]; + unsigned char newG[16]; + + /* + * Assemble new key H||m into tmp[]. + */ + memcpy(tmp, H, 16); + if (first) { + memcpy(tmp + 16, s, 16); + first = 0; + } else { + size_t clen; + + if (len == 0) { + break; + } + clen = len < 16 ? len : 16; + memcpy(tmp + 16, seed, clen); + memset(tmp + 16 + clen, 0, 16 - clen); + seed = (const unsigned char *)seed + clen; + len -= clen; + } + ctx->sk.vtable->init(&ctx->sk.vtable, tmp, 32); + + /* + * Compute new G and H values. + */ + memcpy(iv, G, 12); + memcpy(newG, G, 16); + ctx->sk.vtable->run(&ctx->sk.vtable, iv, + br_dec32be(G + 12), newG, 16); + iv[0] ^= 0x01; + memcpy(H, G, 16); + H[0] ^= 0x01; + ctx->sk.vtable->run(&ctx->sk.vtable, iv, + br_dec32be(G + 12), H, 16); + memcpy(G, newG, 16); + } + + /* + * Output hash value is H||G. We truncate it to its first 128 bits, + * i.e. H; that's our new AES key. + */ + ctx->sk.vtable->init(&ctx->sk.vtable, H, 16); + ctx->cc = 0; +} + +/* see bearssl_rand.h */ +const br_prng_class br_aesctr_drbg_vtable = { + sizeof(br_aesctr_drbg_context), + (void (*)(const br_prng_class **, const void *, const void *, size_t)) + &br_aesctr_drbg_init, + (void (*)(const br_prng_class **, void *, size_t)) + &br_aesctr_drbg_generate, + (void (*)(const br_prng_class **, const void *, size_t)) + &br_aesctr_drbg_update +}; diff --git a/src/bearssl/src/rand/hmac_drbg.c b/src/bearssl/src/rand/hmac_drbg.c new file mode 100644 index 0000000..d746756 --- /dev/null +++ b/src/bearssl/src/rand/hmac_drbg.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl.h */ +void +br_hmac_drbg_init(br_hmac_drbg_context *ctx, + const br_hash_class *digest_class, const void *seed, size_t len) +{ + size_t hlen; + + ctx->vtable = &br_hmac_drbg_vtable; + hlen = br_digest_size(digest_class); + memset(ctx->K, 0x00, hlen); + memset(ctx->V, 0x01, hlen); + ctx->digest_class = digest_class; + br_hmac_drbg_update(ctx, seed, len); +} + +/* see bearssl.h */ +void +br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len) +{ + const br_hash_class *dig; + br_hmac_key_context kc; + br_hmac_context hc; + size_t hlen; + unsigned char *buf; + unsigned char x; + + dig = ctx->digest_class; + hlen = br_digest_size(dig); + br_hmac_key_init(&kc, dig, ctx->K, hlen); + buf = out; + while (len > 0) { + size_t clen; + + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, ctx->V, hlen); + br_hmac_out(&hc, ctx->V); + clen = hlen; + if (clen > len) { + clen = len; + } + memcpy(buf, ctx->V, clen); + buf += clen; + len -= clen; + } + + /* + * To prepare the state for the next request, we should call + * br_hmac_drbg_update() with an empty additional seed. However, + * we already have an initialized HMAC context with the right + * initial key, and we don't want to push another one on the + * stack, so we inline that update() call here. + */ + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, ctx->V, hlen); + x = 0x00; + br_hmac_update(&hc, &x, 1); + br_hmac_out(&hc, ctx->K); + br_hmac_key_init(&kc, dig, ctx->K, hlen); + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, ctx->V, hlen); + br_hmac_out(&hc, ctx->V); +} + +/* see bearssl.h */ +void +br_hmac_drbg_update(br_hmac_drbg_context *ctx, const void *seed, size_t len) +{ + const br_hash_class *dig; + br_hmac_key_context kc; + br_hmac_context hc; + size_t hlen; + unsigned char x; + + dig = ctx->digest_class; + hlen = br_digest_size(dig); + + /* + * 1. K = HMAC(K, V || 0x00 || seed) + */ + br_hmac_key_init(&kc, dig, ctx->K, hlen); + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, ctx->V, hlen); + x = 0x00; + br_hmac_update(&hc, &x, 1); + br_hmac_update(&hc, seed, len); + br_hmac_out(&hc, ctx->K); + br_hmac_key_init(&kc, dig, ctx->K, hlen); + + /* + * 2. V = HMAC(K, V) + */ + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, ctx->V, hlen); + br_hmac_out(&hc, ctx->V); + + /* + * 3. If the additional seed is empty, then stop here. + */ + if (len == 0) { + return; + } + + /* + * 4. K = HMAC(K, V || 0x01 || seed) + */ + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, ctx->V, hlen); + x = 0x01; + br_hmac_update(&hc, &x, 1); + br_hmac_update(&hc, seed, len); + br_hmac_out(&hc, ctx->K); + br_hmac_key_init(&kc, dig, ctx->K, hlen); + + /* + * 5. V = HMAC(K, V) + */ + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, ctx->V, hlen); + br_hmac_out(&hc, ctx->V); +} + +/* see bearssl.h */ +const br_prng_class br_hmac_drbg_vtable = { + sizeof(br_hmac_drbg_context), + (void (*)(const br_prng_class **, const void *, const void *, size_t)) + &br_hmac_drbg_init, + (void (*)(const br_prng_class **, void *, size_t)) + &br_hmac_drbg_generate, + (void (*)(const br_prng_class **, const void *, size_t)) + &br_hmac_drbg_update +}; diff --git a/src/bearssl/src/rand/sysrng.c b/src/bearssl/src/rand/sysrng.c new file mode 100644 index 0000000..bec06be --- /dev/null +++ b/src/bearssl/src/rand/sysrng.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +#if BR_USE_URANDOM +#include +#include +#include +#include +#endif + +#if BR_USE_WIN32_RAND +#include +#include +#pragma comment(lib, "advapi32") +#endif + +#if BR_RDRAND +BR_TARGETS_X86_UP +BR_TARGET("rdrnd") +static int +seeder_rdrand(const br_prng_class **ctx) +{ + unsigned char tmp[32]; + size_t u; + + for (u = 0; u < sizeof tmp; u += sizeof(uint32_t)) { + int j; + uint32_t x; + + /* + * We use the 32-bit intrinsic so that code is compatible + * with both 32-bit and 64-bit architectures. + * + * Intel recommends trying at least 10 times in case of + * failure. + */ + for (j = 0; j < 10; j ++) { + if (_rdrand32_step(&x)) { + goto next_word; + } + } + return 0; + next_word: + br_enc32le(tmp + u, x); + } + (*ctx)->update(ctx, tmp, sizeof tmp); + return 1; +} +BR_TARGETS_X86_DOWN + +static int +rdrand_supported(void) +{ + /* + * The RDRND support is bit 30 of ECX, as returned by CPUID. + */ + return br_cpuid(0, 0, 0x40000000, 0); +} + +#endif + +#if BR_USE_URANDOM +static int +seeder_urandom(const br_prng_class **ctx) +{ + int f; + + f = open("/dev/urandom", O_RDONLY); + if (f >= 0) { + unsigned char tmp[32]; + size_t u; + + for (u = 0; u < sizeof tmp;) { + ssize_t len; + + len = read(f, tmp + u, (sizeof tmp) - u); + if (len < 0) { + if (errno == EINTR) { + continue; + } + break; + } + u += (size_t)len; + } + close(f); + if (u == sizeof tmp) { + (*ctx)->update(ctx, tmp, sizeof tmp); + return 1; + } + } + return 0; +} +#endif + +#if BR_USE_WIN32_RAND +static int +seeder_win32(const br_prng_class **ctx) +{ + HCRYPTPROV hp; + + if (CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + BYTE buf[32]; + BOOL r; + + r = CryptGenRandom(hp, sizeof buf, buf); + CryptReleaseContext(hp, 0); + if (r) { + (*ctx)->update(ctx, buf, sizeof buf); + return 1; + } + } + return 0; +} +#endif + +/* see bearssl_rand.h */ +br_prng_seeder +br_prng_seeder_system(const char **name) +{ +#if BR_RDRAND + if (rdrand_supported()) { + if (name != NULL) { + *name = "rdrand"; + } + return &seeder_rdrand; + } +#endif +#if BR_USE_URANDOM + if (name != NULL) { + *name = "urandom"; + } + return &seeder_urandom; +#elif BR_USE_WIN32_RAND + if (name != NULL) { + *name = "win32"; + } + return &seeder_win32; +#endif + if (name != NULL) { + *name = "none"; + } + return 0; +} diff --git a/src/bearssl/src/rsa/rsa_default_keygen.c b/src/bearssl/src/rsa/rsa_default_keygen.c new file mode 100644 index 0000000..f2e83c8 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_keygen.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_keygen +br_rsa_keygen_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_keygen; +#elif BR_LOMUL + return &br_rsa_i15_keygen; +#else + return &br_rsa_i31_keygen; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_modulus.c b/src/bearssl/src/rsa/rsa_default_modulus.c new file mode 100644 index 0000000..57d4be5 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_modulus.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_compute_modulus +br_rsa_compute_modulus_get_default(void) +{ +#if BR_LOMUL + return &br_rsa_i15_compute_modulus; +#else + return &br_rsa_i31_compute_modulus; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_oaep_decrypt.c b/src/bearssl/src/rsa/rsa_default_oaep_decrypt.c new file mode 100644 index 0000000..7345d64 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_oaep_decrypt.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_oaep_decrypt +br_rsa_oaep_decrypt_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_oaep_decrypt; +#elif BR_LOMUL + return &br_rsa_i15_oaep_decrypt; +#else + return &br_rsa_i31_oaep_decrypt; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_oaep_encrypt.c b/src/bearssl/src/rsa/rsa_default_oaep_encrypt.c new file mode 100644 index 0000000..ae33fcc --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_oaep_encrypt.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_oaep_encrypt +br_rsa_oaep_encrypt_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_oaep_encrypt; +#elif BR_LOMUL + return &br_rsa_i15_oaep_encrypt; +#else + return &br_rsa_i31_oaep_encrypt; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_pkcs1_sign.c b/src/bearssl/src/rsa/rsa_default_pkcs1_sign.c new file mode 100644 index 0000000..e926704 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_pkcs1_sign.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_pkcs1_sign +br_rsa_pkcs1_sign_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_pkcs1_sign; +#elif BR_LOMUL + return &br_rsa_i15_pkcs1_sign; +#else + return &br_rsa_i31_pkcs1_sign; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c b/src/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c new file mode 100644 index 0000000..b3dbeb7 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_pkcs1_vrfy +br_rsa_pkcs1_vrfy_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_pkcs1_vrfy; +#elif BR_LOMUL + return &br_rsa_i15_pkcs1_vrfy; +#else + return &br_rsa_i31_pkcs1_vrfy; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_priv.c b/src/bearssl/src/rsa/rsa_default_priv.c new file mode 100644 index 0000000..bb0b2c0 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_priv.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_private +br_rsa_private_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_private; +#elif BR_LOMUL + return &br_rsa_i15_private; +#else + return &br_rsa_i31_private; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_privexp.c b/src/bearssl/src/rsa/rsa_default_privexp.c new file mode 100644 index 0000000..cda4555 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_privexp.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_compute_privexp +br_rsa_compute_privexp_get_default(void) +{ +#if BR_LOMUL + return &br_rsa_i15_compute_privexp; +#else + return &br_rsa_i31_compute_privexp; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_pub.c b/src/bearssl/src/rsa/rsa_default_pub.c new file mode 100644 index 0000000..a1f03ef --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_pub.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_public +br_rsa_public_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_public; +#elif BR_LOMUL + return &br_rsa_i15_public; +#else + return &br_rsa_i31_public; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_pubexp.c b/src/bearssl/src/rsa/rsa_default_pubexp.c new file mode 100644 index 0000000..47bc000 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_pubexp.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_compute_pubexp +br_rsa_compute_pubexp_get_default(void) +{ +#if BR_LOMUL + return &br_rsa_i15_compute_pubexp; +#else + return &br_rsa_i31_compute_pubexp; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_i15_keygen.c b/src/bearssl/src/rsa/rsa_i15_keygen.c new file mode 100644 index 0000000..1c011fe --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_keygen.c @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Make a random integer of the provided size. The size is encoded. + * The header word is untouched. + */ +static void +mkrand(const br_prng_class **rng, uint16_t *x, uint32_t esize) +{ + size_t u, len; + unsigned m; + + len = (esize + 15) >> 4; + (*rng)->generate(rng, x + 1, len * sizeof(uint16_t)); + for (u = 1; u < len; u ++) { + x[u] &= 0x7FFF; + } + m = esize & 15; + if (m == 0) { + x[len] &= 0x7FFF; + } else { + x[len] &= 0x7FFF >> (15 - m); + } +} + +/* + * This is the big-endian unsigned representation of the product of + * all small primes from 13 to 1481. + */ +static const unsigned char SMALL_PRIMES[] = { + 0x2E, 0xAB, 0x92, 0xD1, 0x8B, 0x12, 0x47, 0x31, 0x54, 0x0A, + 0x99, 0x5D, 0x25, 0x5E, 0xE2, 0x14, 0x96, 0x29, 0x1E, 0xB7, + 0x78, 0x70, 0xCC, 0x1F, 0xA5, 0xAB, 0x8D, 0x72, 0x11, 0x37, + 0xFB, 0xD8, 0x1E, 0x3F, 0x5B, 0x34, 0x30, 0x17, 0x8B, 0xE5, + 0x26, 0x28, 0x23, 0xA1, 0x8A, 0xA4, 0x29, 0xEA, 0xFD, 0x9E, + 0x39, 0x60, 0x8A, 0xF3, 0xB5, 0xA6, 0xEB, 0x3F, 0x02, 0xB6, + 0x16, 0xC3, 0x96, 0x9D, 0x38, 0xB0, 0x7D, 0x82, 0x87, 0x0C, + 0xF7, 0xBE, 0x24, 0xE5, 0x5F, 0x41, 0x04, 0x79, 0x76, 0x40, + 0xE7, 0x00, 0x22, 0x7E, 0xB5, 0x85, 0x7F, 0x8D, 0x01, 0x50, + 0xE9, 0xD3, 0x29, 0x42, 0x08, 0xB3, 0x51, 0x40, 0x7B, 0xD7, + 0x8D, 0xCC, 0x10, 0x01, 0x64, 0x59, 0x28, 0xB6, 0x53, 0xF3, + 0x50, 0x4E, 0xB1, 0xF2, 0x58, 0xCD, 0x6E, 0xF5, 0x56, 0x3E, + 0x66, 0x2F, 0xD7, 0x07, 0x7F, 0x52, 0x4C, 0x13, 0x24, 0xDC, + 0x8E, 0x8D, 0xCC, 0xED, 0x77, 0xC4, 0x21, 0xD2, 0xFD, 0x08, + 0xEA, 0xD7, 0xC0, 0x5C, 0x13, 0x82, 0x81, 0x31, 0x2F, 0x2B, + 0x08, 0xE4, 0x80, 0x04, 0x7A, 0x0C, 0x8A, 0x3C, 0xDC, 0x22, + 0xE4, 0x5A, 0x7A, 0xB0, 0x12, 0x5E, 0x4A, 0x76, 0x94, 0x77, + 0xC2, 0x0E, 0x92, 0xBA, 0x8A, 0xA0, 0x1F, 0x14, 0x51, 0x1E, + 0x66, 0x6C, 0x38, 0x03, 0x6C, 0xC7, 0x4A, 0x4B, 0x70, 0x80, + 0xAF, 0xCA, 0x84, 0x51, 0xD8, 0xD2, 0x26, 0x49, 0xF5, 0xA8, + 0x5E, 0x35, 0x4B, 0xAC, 0xCE, 0x29, 0x92, 0x33, 0xB7, 0xA2, + 0x69, 0x7D, 0x0C, 0xE0, 0x9C, 0xDB, 0x04, 0xD6, 0xB4, 0xBC, + 0x39, 0xD7, 0x7F, 0x9E, 0x9D, 0x78, 0x38, 0x7F, 0x51, 0x54, + 0x50, 0x8B, 0x9E, 0x9C, 0x03, 0x6C, 0xF5, 0x9D, 0x2C, 0x74, + 0x57, 0xF0, 0x27, 0x2A, 0xC3, 0x47, 0xCA, 0xB9, 0xD7, 0x5C, + 0xFF, 0xC2, 0xAC, 0x65, 0x4E, 0xBD +}; + +/* + * We need temporary values for at least 7 integers of the same size + * as a factor (including header word); more space helps with performance + * (in modular exponentiations), but we much prefer to remain under + * 2 kilobytes in total, to save stack space. The macro TEMPS below + * exceeds 1024 (which is a count in 16-bit words) when BR_MAX_RSA_SIZE + * is greater than 4350 (default value is 4096, so the 2-kB limit is + * maintained unless BR_MAX_RSA_SIZE was modified). + */ +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#define TEMPS MAX(1024, 7 * ((((BR_MAX_RSA_SIZE + 1) >> 1) + 29) / 15)) + +/* + * Perform trial division on a candidate prime. This computes + * y = SMALL_PRIMES mod x, then tries to compute y/y mod x. The + * br_i15_moddiv() function will report an error if y is not invertible + * modulo x. Returned value is 1 on success (none of the small primes + * divides x), 0 on error (a non-trivial GCD is obtained). + * + * This function assumes that x is odd. + */ +static uint32_t +trial_divisions(const uint16_t *x, uint16_t *t) +{ + uint16_t *y; + uint16_t x0i; + + y = t; + t += 1 + ((x[0] + 15) >> 4); + x0i = br_i15_ninv15(x[1]); + br_i15_decode_reduce(y, SMALL_PRIMES, sizeof SMALL_PRIMES, x); + return br_i15_moddiv(y, y, x, x0i, t); +} + +/* + * Perform n rounds of Miller-Rabin on the candidate prime x. This + * function assumes that x = 3 mod 4. + * + * Returned value is 1 on success (all rounds completed successfully), + * 0 otherwise. + */ +static uint32_t +miller_rabin(const br_prng_class **rng, const uint16_t *x, int n, + uint16_t *t, size_t tlen) +{ + /* + * Since x = 3 mod 4, the Miller-Rabin test is simple: + * - get a random base a (such that 1 < a < x-1) + * - compute z = a^((x-1)/2) mod x + * - if z != 1 and z != x-1, the number x is composite + * + * We generate bases 'a' randomly with a size which is + * one bit less than x, which ensures that a < x-1. It + * is not useful to verify that a > 1 because the probability + * that we get a value a equal to 0 or 1 is much smaller + * than the probability of our Miller-Rabin tests not to + * detect a composite, which is already quite smaller than the + * probability of the hardware misbehaving and return a + * composite integer because of some glitch (e.g. bad RAM + * or ill-timed cosmic ray). + */ + unsigned char *xm1d2; + size_t xlen, xm1d2_len, xm1d2_len_u16, u; + uint32_t asize; + unsigned cc; + uint16_t x0i; + + /* + * Compute (x-1)/2 (encoded). + */ + xm1d2 = (unsigned char *)t; + xm1d2_len = ((x[0] - (x[0] >> 4)) + 7) >> 3; + br_i15_encode(xm1d2, xm1d2_len, x); + cc = 0; + for (u = 0; u < xm1d2_len; u ++) { + unsigned w; + + w = xm1d2[u]; + xm1d2[u] = (unsigned char)((w >> 1) | cc); + cc = w << 7; + } + + /* + * We used some words of the provided buffer for (x-1)/2. + */ + xm1d2_len_u16 = (xm1d2_len + 1) >> 1; + t += xm1d2_len_u16; + tlen -= xm1d2_len_u16; + + xlen = (x[0] + 15) >> 4; + asize = x[0] - 1 - EQ0(x[0] & 15); + x0i = br_i15_ninv15(x[1]); + while (n -- > 0) { + uint16_t *a; + uint32_t eq1, eqm1; + + /* + * Generate a random base. We don't need the base to be + * really uniform modulo x, so we just get a random + * number which is one bit shorter than x. + */ + a = t; + a[0] = x[0]; + a[xlen] = 0; + mkrand(rng, a, asize); + + /* + * Compute a^((x-1)/2) mod x. We assume here that the + * function will not fail (the temporary array is large + * enough). + */ + br_i15_modpow_opt(a, xm1d2, xm1d2_len, + x, x0i, t + 1 + xlen, tlen - 1 - xlen); + + /* + * We must obtain either 1 or x-1. Note that x is odd, + * hence x-1 differs from x only in its low word (no + * carry). + */ + eq1 = a[1] ^ 1; + eqm1 = a[1] ^ (x[1] - 1); + for (u = 2; u <= xlen; u ++) { + eq1 |= a[u]; + eqm1 |= a[u] ^ x[u]; + } + + if ((EQ0(eq1) | EQ0(eqm1)) == 0) { + return 0; + } + } + return 1; +} + +/* + * Create a random prime of the provided size. 'size' is the _encoded_ + * bit length. The two top bits and the two bottom bits are set to 1. + */ +static void +mkprime(const br_prng_class **rng, uint16_t *x, uint32_t esize, + uint32_t pubexp, uint16_t *t, size_t tlen) +{ + size_t len; + + x[0] = esize; + len = (esize + 15) >> 4; + for (;;) { + size_t u; + uint32_t m3, m5, m7, m11; + int rounds; + + /* + * Generate random bits. We force the two top bits and the + * two bottom bits to 1. + */ + mkrand(rng, x, esize); + if ((esize & 15) == 0) { + x[len] |= 0x6000; + } else if ((esize & 15) == 1) { + x[len] |= 0x0001; + x[len - 1] |= 0x4000; + } else { + x[len] |= 0x0003 << ((esize & 15) - 2); + } + x[1] |= 0x0003; + + /* + * Trial division with low primes (3, 5, 7 and 11). We + * use the following properties: + * + * 2^2 = 1 mod 3 + * 2^4 = 1 mod 5 + * 2^3 = 1 mod 7 + * 2^10 = 1 mod 11 + */ + m3 = 0; + m5 = 0; + m7 = 0; + m11 = 0; + for (u = 0; u < len; u ++) { + uint32_t w; + + w = x[1 + u]; + m3 += w << (u & 1); + m3 = (m3 & 0xFF) + (m3 >> 8); + m5 += w << ((4 - u) & 3); + m5 = (m5 & 0xFF) + (m5 >> 8); + m7 += w; + m7 = (m7 & 0x1FF) + (m7 >> 9); + m11 += w << (5 & -(u & 1)); + m11 = (m11 & 0x3FF) + (m11 >> 10); + } + + /* + * Maximum values of m* at this point: + * m3: 511 + * m5: 2310 + * m7: 510 + * m11: 2047 + * We use the same properties to make further reductions. + */ + + m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 46 */ + m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 16 */ + m3 = ((m3 * 43) >> 5) & 3; + + m5 = (m5 & 0xFF) + (m5 >> 8); /* max: 263 */ + m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 30 */ + m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 15 */ + m5 -= 10 & -GT(m5, 9); + m5 -= 5 & -GT(m5, 4); + + m7 = (m7 & 0x3F) + (m7 >> 6); /* max: 69 */ + m7 = (m7 & 7) + (m7 >> 3); /* max: 14 */ + m7 = ((m7 * 147) >> 7) & 7; + + /* + * 2^5 = 32 = -1 mod 11. + */ + m11 = (m11 & 0x1F) + 66 - (m11 >> 5); /* max: 97 */ + m11 -= 88 & -GT(m11, 87); + m11 -= 44 & -GT(m11, 43); + m11 -= 22 & -GT(m11, 21); + m11 -= 11 & -GT(m11, 10); + + /* + * If any of these modulo is 0, then the candidate is + * not prime. Also, if pubexp is 3, 5, 7 or 11, and the + * corresponding modulus is 1, then the candidate must + * be rejected, because we need e to be invertible + * modulo p-1. We can use simple comparisons here + * because they won't leak information on a candidate + * that we keep, only on one that we reject (and is thus + * not secret). + */ + if (m3 == 0 || m5 == 0 || m7 == 0 || m11 == 0) { + continue; + } + if ((pubexp == 3 && m3 == 1) + || (pubexp == 5 && m5 == 5) + || (pubexp == 7 && m5 == 7) + || (pubexp == 11 && m5 == 11)) + { + continue; + } + + /* + * More trial divisions. + */ + if (!trial_divisions(x, t)) { + continue; + } + + /* + * Miller-Rabin algorithm. Since we selected a random + * integer, not a maliciously crafted integer, we can use + * relatively few rounds to lower the risk of a false + * positive (i.e. declaring prime a non-prime) under + * 2^(-80). It is not useful to lower the probability much + * below that, since that would be substantially below + * the probability of the hardware misbehaving. Sufficient + * numbers of rounds are extracted from the Handbook of + * Applied Cryptography, note 4.49 (page 149). + * + * Since we work on the encoded size (esize), we need to + * compare with encoded thresholds. + */ + if (esize < 320) { + rounds = 12; + } else if (esize < 480) { + rounds = 9; + } else if (esize < 693) { + rounds = 6; + } else if (esize < 906) { + rounds = 4; + } else if (esize < 1386) { + rounds = 3; + } else { + rounds = 2; + } + + if (miller_rabin(rng, x, rounds, t, tlen)) { + return; + } + } +} + +/* + * Let p be a prime (p > 2^33, p = 3 mod 4). Let m = (p-1)/2, provided + * as parameter (with announced bit length equal to that of p). This + * function computes d = 1/e mod p-1 (for an odd integer e). Returned + * value is 1 on success, 0 on error (an error is reported if e is not + * invertible modulo p-1). + * + * The temporary buffer (t) must have room for at least 4 integers of + * the size of p. + */ +static uint32_t +invert_pubexp(uint16_t *d, const uint16_t *m, uint32_t e, uint16_t *t) +{ + uint16_t *f; + uint32_t r; + + f = t; + t += 1 + ((m[0] + 15) >> 4); + + /* + * Compute d = 1/e mod m. Since p = 3 mod 4, m is odd. + */ + br_i15_zero(d, m[0]); + d[1] = 1; + br_i15_zero(f, m[0]); + f[1] = e & 0x7FFF; + f[2] = (e >> 15) & 0x7FFF; + f[3] = e >> 30; + r = br_i15_moddiv(d, f, m, br_i15_ninv15(m[1]), t); + + /* + * We really want d = 1/e mod p-1, with p = 2m. By the CRT, + * the result is either the d we got, or d + m. + * + * Let's write e*d = 1 + k*m, for some integer k. Integers e + * and m are odd. If d is odd, then e*d is odd, which implies + * that k must be even; in that case, e*d = 1 + (k/2)*2m, and + * thus d is already fine. Conversely, if d is even, then k + * is odd, and we must add m to d in order to get the correct + * result. + */ + br_i15_add(d, m, (uint32_t)(1 - (d[1] & 1))); + + return r; +} + +/* + * Swap two buffers in RAM. They must be disjoint. + */ +static void +bufswap(void *b1, void *b2, size_t len) +{ + size_t u; + unsigned char *buf1, *buf2; + + buf1 = b1; + buf2 = b2; + for (u = 0; u < len; u ++) { + unsigned w; + + w = buf1[u]; + buf1[u] = buf2[u]; + buf2[u] = w; + } +} + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_keygen(const br_prng_class **rng, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp) +{ + uint32_t esize_p, esize_q; + size_t plen, qlen, tlen; + uint16_t *p, *q, *t; + uint16_t tmp[TEMPS]; + uint32_t r; + + if (size < BR_MIN_RSA_SIZE || size > BR_MAX_RSA_SIZE) { + return 0; + } + if (pubexp == 0) { + pubexp = 3; + } else if (pubexp == 1 || (pubexp & 1) == 0) { + return 0; + } + + esize_p = (size + 1) >> 1; + esize_q = size - esize_p; + sk->n_bitlen = size; + sk->p = kbuf_priv; + sk->plen = (esize_p + 7) >> 3; + sk->q = sk->p + sk->plen; + sk->qlen = (esize_q + 7) >> 3; + sk->dp = sk->q + sk->qlen; + sk->dplen = sk->plen; + sk->dq = sk->dp + sk->dplen; + sk->dqlen = sk->qlen; + sk->iq = sk->dq + sk->dqlen; + sk->iqlen = sk->plen; + + if (pk != NULL) { + pk->n = kbuf_pub; + pk->nlen = (size + 7) >> 3; + pk->e = pk->n + pk->nlen; + pk->elen = 4; + br_enc32be(pk->e, pubexp); + while (*pk->e == 0) { + pk->e ++; + pk->elen --; + } + } + + /* + * We now switch to encoded sizes. + * + * floor((x * 17477) / (2^18)) is equal to floor(x/15) for all + * integers x from 0 to 23833. + */ + esize_p += MUL15(esize_p, 17477) >> 18; + esize_q += MUL15(esize_q, 17477) >> 18; + plen = (esize_p + 15) >> 4; + qlen = (esize_q + 15) >> 4; + p = tmp; + q = p + 1 + plen; + t = q + 1 + qlen; + tlen = ((sizeof tmp) / sizeof(uint16_t)) - (2 + plen + qlen); + + /* + * When looking for primes p and q, we temporarily divide + * candidates by 2, in order to compute the inverse of the + * public exponent. + */ + + for (;;) { + mkprime(rng, p, esize_p, pubexp, t, tlen); + br_i15_rshift(p, 1); + if (invert_pubexp(t, p, pubexp, t + 1 + plen)) { + br_i15_add(p, p, 1); + p[1] |= 1; + br_i15_encode(sk->p, sk->plen, p); + br_i15_encode(sk->dp, sk->dplen, t); + break; + } + } + + for (;;) { + mkprime(rng, q, esize_q, pubexp, t, tlen); + br_i15_rshift(q, 1); + if (invert_pubexp(t, q, pubexp, t + 1 + qlen)) { + br_i15_add(q, q, 1); + q[1] |= 1; + br_i15_encode(sk->q, sk->qlen, q); + br_i15_encode(sk->dq, sk->dqlen, t); + break; + } + } + + /* + * If p and q have the same size, then it is possible that q > p + * (when the target modulus size is odd, we generate p with a + * greater bit length than q). If q > p, we want to swap p and q + * (and also dp and dq) for two reasons: + * - The final step below (inversion of q modulo p) is easier if + * p > q. + * - While BearSSL's RSA code is perfectly happy with RSA keys such + * that p < q, some other implementations have restrictions and + * require p > q. + * + * Note that we can do a simple non-constant-time swap here, + * because the only information we leak here is that we insist on + * returning p and q such that p > q, which is not a secret. + */ + if (esize_p == esize_q && br_i15_sub(p, q, 0) == 1) { + bufswap(p, q, (1 + plen) * sizeof *p); + bufswap(sk->p, sk->q, sk->plen); + bufswap(sk->dp, sk->dq, sk->dplen); + } + + /* + * We have produced p, q, dp and dq. We can now compute iq = 1/d mod p. + * + * We ensured that p >= q, so this is just a matter of updating the + * header word for q (and possibly adding an extra word). + * + * Theoretically, the call below may fail, in case we were + * extraordinarily unlucky, and p = q. Another failure case is if + * Miller-Rabin failed us _twice_, and p and q are non-prime and + * have a factor is common. We report the error mostly because it + * is cheap and we can, but in practice this never happens (or, at + * least, it happens way less often than hardware glitches). + */ + q[0] = p[0]; + if (plen > qlen) { + q[plen] = 0; + t ++; + tlen --; + } + br_i15_zero(t, p[0]); + t[1] = 1; + r = br_i15_moddiv(t, q, p, br_i15_ninv15(p[1]), t + 1 + plen); + br_i15_encode(sk->iq, sk->iqlen, t); + + /* + * Compute the public modulus too, if required. + */ + if (pk != NULL) { + br_i15_zero(t, p[0]); + br_i15_mulacc(t, p, q); + br_i15_encode(pk->n, pk->nlen, t); + } + + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i15_modulus.c b/src/bearssl/src/rsa/rsa_i15_modulus.c new file mode 100644 index 0000000..d61c794 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_modulus.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +size_t +br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk) +{ + uint16_t tmp[2 * ((BR_MAX_RSA_SIZE + 14) / 15) + 5]; + uint16_t *t, *p, *q; + const unsigned char *pbuf, *qbuf; + size_t nlen, plen, qlen, tlen; + + /* + * Compute actual byte and lengths for p and q. + */ + pbuf = sk->p; + plen = sk->plen; + while (plen > 0 && *pbuf == 0) { + pbuf ++; + plen --; + } + qbuf = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *qbuf == 0) { + qbuf ++; + qlen --; + } + + t = tmp; + tlen = (sizeof tmp) / (sizeof tmp[0]); + + /* + * Decode p. + */ + if ((15 * tlen) < (plen << 3) + 15) { + return 0; + } + br_i15_decode(t, pbuf, plen); + p = t; + plen = (p[0] + 31) >> 4; + t += plen; + tlen -= plen; + + /* + * Decode q. + */ + if ((15 * tlen) < (qlen << 3) + 15) { + return 0; + } + br_i15_decode(t, qbuf, qlen); + q = t; + qlen = (q[0] + 31) >> 4; + t += qlen; + tlen -= qlen; + + /* + * Computation can proceed only if we have enough room for the + * modulus. + */ + if (tlen < (plen + qlen + 1)) { + return 0; + } + + /* + * Private key already contains the modulus bit length, from which + * we can infer the output length. Even if n is NULL, we still had + * to decode p and q to make sure that the product can be computed. + */ + nlen = (sk->n_bitlen + 7) >> 3; + if (n != NULL) { + br_i15_zero(t, p[0]); + br_i15_mulacc(t, p, q); + br_i15_encode(n, nlen, t); + } + return nlen; +} diff --git a/src/bearssl/src/rsa/rsa_i15_oaep_decrypt.c b/src/bearssl/src/rsa/rsa_i15_oaep_decrypt.c new file mode 100644 index 0000000..927eecd --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_oaep_decrypt.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_oaep_decrypt(const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len) +{ + uint32_t r; + + if (*len != ((sk->n_bitlen + 7) >> 3)) { + return 0; + } + r = br_rsa_i15_private(data, sk); + r &= br_rsa_oaep_unpad(dig, label, label_len, data, len); + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i15_oaep_encrypt.c b/src/bearssl/src/rsa/rsa_i15_oaep_encrypt.c new file mode 100644 index 0000000..b9a6cfa --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_oaep_encrypt.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +size_t +br_rsa_i15_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len) +{ + size_t dlen; + + dlen = br_rsa_oaep_pad(rnd, dig, label, label_len, + pk, dst, dst_max_len, src, src_len); + if (dlen == 0) { + return 0; + } + return dlen & -(size_t)br_rsa_i15_public(dst, dlen, pk); +} diff --git a/src/bearssl/src/rsa/rsa_i15_pkcs1_sign.c b/src/bearssl/src/rsa/rsa_i15_pkcs1_sign.c new file mode 100644 index 0000000..f519423 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_pkcs1_sign.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) { + return 0; + } + return br_rsa_i15_private(x, sk); +} diff --git a/src/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c b/src/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c new file mode 100644 index 0000000..2c35184 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i15_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out); +} diff --git a/src/bearssl/src/rsa/rsa_i15_priv.c b/src/bearssl/src/rsa/rsa_i15_priv.c new file mode 100644 index 0000000..177cc3a --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_priv.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define U (2 + ((BR_MAX_RSA_FACTOR + 14) / 15)) +#define TLEN (8 * U) + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_private(unsigned char *x, const br_rsa_private_key *sk) +{ + const unsigned char *p, *q; + size_t plen, qlen; + size_t fwlen; + uint16_t p0i, q0i; + size_t xlen, u; + uint16_t tmp[1 + TLEN]; + long z; + uint16_t *mp, *mq, *s1, *s2, *t1, *t2, *t3; + uint32_t r; + + /* + * Compute the actual lengths of p and q, in bytes. + * These lengths are not considered secret (we cannot really hide + * them anyway in constant-time code). + */ + p = sk->p; + plen = sk->plen; + while (plen > 0 && *p == 0) { + p ++; + plen --; + } + q = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *q == 0) { + q ++; + qlen --; + } + + /* + * Compute the maximum factor length, in words. + */ + z = (long)(plen > qlen ? plen : qlen) << 3; + fwlen = 1; + while (z > 0) { + z -= 15; + fwlen ++; + } + /* + * Round up the word length to an even number. + */ + fwlen += (fwlen & 1); + + /* + * We need to fit at least 6 values in the stack buffer. + */ + if (6 * fwlen > TLEN) { + return 0; + } + + /* + * Compute signature length (in bytes). + */ + xlen = (sk->n_bitlen + 7) >> 3; + + /* + * Ensure 32-bit alignment for value words. + */ + mq = tmp; + if (((uintptr_t)mq & 2) == 0) { + mq ++; + } + + /* + * Decode q. + */ + br_i15_decode(mq, q, qlen); + + /* + * Decode p. + */ + t1 = mq + fwlen; + br_i15_decode(t1, p, plen); + + /* + * Compute the modulus (product of the two factors), to compare + * it with the source value. We use br_i15_mulacc(), since it's + * already used later on. + */ + t2 = mq + 2 * fwlen; + br_i15_zero(t2, mq[0]); + br_i15_mulacc(t2, mq, t1); + + /* + * We encode the modulus into bytes, to perform the comparison + * with bytes. We know that the product length, in bytes, is + * exactly xlen. + * The comparison actually computes the carry when subtracting + * the modulus from the source value; that carry must be 1 for + * a value in the correct range. We keep it in r, which is our + * accumulator for the error code. + */ + t3 = mq + 4 * fwlen; + br_i15_encode(t3, xlen, t2); + u = xlen; + r = 0; + while (u > 0) { + uint32_t wn, wx; + + u --; + wn = ((unsigned char *)t3)[u]; + wx = x[u]; + r = ((wx - (wn + r)) >> 8) & 1; + } + + /* + * Move the decoded p to another temporary buffer. + */ + mp = mq + 2 * fwlen; + memmove(mp, t1, fwlen * sizeof *t1); + + /* + * Compute s2 = x^dq mod q. + */ + q0i = br_i15_ninv15(mq[1]); + s2 = mq + fwlen; + br_i15_decode_reduce(s2, x, xlen, mq); + r &= br_i15_modpow_opt(s2, sk->dq, sk->dqlen, mq, q0i, + mq + 3 * fwlen, TLEN - 3 * fwlen); + + /* + * Compute s1 = x^dq mod q. + */ + p0i = br_i15_ninv15(mp[1]); + s1 = mq + 3 * fwlen; + br_i15_decode_reduce(s1, x, xlen, mp); + r &= br_i15_modpow_opt(s1, sk->dp, sk->dplen, mp, p0i, + mq + 4 * fwlen, TLEN - 4 * fwlen); + + /* + * Compute: + * h = (s1 - s2)*(1/q) mod p + * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is + * unclear about whether p may be lower than q (some existing, + * widely deployed implementations of RSA don't tolerate p < q), + * but we want to support that occurrence, so we need to use the + * reduction function. + * + * Since we use br_i15_decode_reduce() for iq (purportedly, the + * inverse of q modulo p), we also tolerate improperly large + * values for this parameter. + */ + t1 = mq + 4 * fwlen; + t2 = mq + 5 * fwlen; + br_i15_reduce(t2, s2, mp); + br_i15_add(s1, mp, br_i15_sub(s1, t2, 1)); + br_i15_to_monty(s1, mp); + br_i15_decode_reduce(t1, sk->iq, sk->iqlen, mp); + br_i15_montymul(t2, s1, t1, mp, p0i); + + /* + * h is now in t2. We compute the final result: + * s = s2 + q*h + * All these operations are non-modular. + * + * We need mq, s2 and t2. We use the t3 buffer as destination. + * The buffers mp, s1 and t1 are no longer needed, so we can + * reuse them for t3. Moreover, the first step of the computation + * is to copy s2 into t3, after which s2 is not needed. Right + * now, mq is in slot 0, s2 is in slot 1, and t2 in slot 5. + * Therefore, we have ample room for t3 by simply using s2. + */ + t3 = s2; + br_i15_mulacc(t3, mq, t2); + + /* + * Encode the result. Since we already checked the value of xlen, + * we can just use it right away. + */ + br_i15_encode(x, xlen, t3); + + /* + * The only error conditions remaining at that point are invalid + * values for p and q (even integers). + */ + return p0i & q0i & r; +} diff --git a/src/bearssl/src/rsa/rsa_i15_privexp.c b/src/bearssl/src/rsa/rsa_i15_privexp.c new file mode 100644 index 0000000..57d6918 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_privexp.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +size_t +br_rsa_i15_compute_privexp(void *d, + const br_rsa_private_key *sk, uint32_t e) +{ + /* + * We want to invert e modulo phi = (p-1)(q-1). This first + * requires computing phi, which is easy since we have the factors + * p and q in the private key structure. + * + * Since p = 3 mod 4 and q = 3 mod 4, phi/4 is an odd integer. + * We could invert e modulo phi/4 then patch the result to + * modulo phi, but this would involve assembling three modulus-wide + * values (phi/4, 1 and e) and calling moddiv, that requires + * three more temporaries, for a total of six big integers, or + * slightly more than 3 kB of stack space for RSA-4096. This + * exceeds our stack requirements. + * + * Instead, we first use one step of the extended GCD: + * + * - We compute phi = k*e + r (Euclidean division of phi by e). + * If public exponent e is correct, then r != 0 (e must be + * invertible modulo phi). We also have k != 0 since we + * enforce non-ridiculously-small factors. + * + * - We find small u, v such that u*e - v*r = 1 (using a + * binary GCD; we can arrange for u < r and v < e, i.e. all + * values fit on 32 bits). + * + * - Solution is: d = u + v*k + * This last computation is exact: since u < r and v < e, + * the above implies d < r + e*((phi-r)/e) = phi + */ + + uint16_t tmp[4 * ((BR_MAX_RSA_FACTOR + 14) / 15) + 12]; + uint16_t *p, *q, *k, *m, *z, *phi; + const unsigned char *pbuf, *qbuf; + size_t plen, qlen, u, len, dlen; + uint32_t r, a, b, u0, v0, u1, v1, he, hr; + int i; + + /* + * Check that e is correct. + */ + if (e < 3 || (e & 1) == 0) { + return 0; + } + + /* + * Check lengths of p and q, and that they are both odd. + */ + pbuf = sk->p; + plen = sk->plen; + while (plen > 0 && *pbuf == 0) { + pbuf ++; + plen --; + } + if (plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8) + || (pbuf[plen - 1] & 1) != 1) + { + return 0; + } + qbuf = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *qbuf == 0) { + qbuf ++; + qlen --; + } + if (qlen < 5 || qlen > (BR_MAX_RSA_FACTOR / 8) + || (qbuf[qlen - 1] & 1) != 1) + { + return 0; + } + + /* + * Output length is that of the modulus. + */ + dlen = (sk->n_bitlen + 7) >> 3; + if (d == NULL) { + return dlen; + } + + p = tmp; + br_i15_decode(p, pbuf, plen); + plen = (p[0] + 15) >> 4; + q = p + 1 + plen; + br_i15_decode(q, qbuf, qlen); + qlen = (q[0] + 15) >> 4; + + /* + * Compute phi = (p-1)*(q-1), then move it over p-1 and q-1 (that + * we do not need anymore). The mulacc function sets the announced + * bit length of t to be the sum of the announced bit lengths of + * p-1 and q-1, which is usually exact but may overshoot by one 1 + * bit in some cases; we readjust it to its true length. + */ + p[1] --; + q[1] --; + phi = q + 1 + qlen; + br_i15_zero(phi, p[0]); + br_i15_mulacc(phi, p, q); + len = (phi[0] + 15) >> 4; + memmove(tmp, phi, (1 + len) * sizeof *phi); + phi = tmp; + phi[0] = br_i15_bit_length(phi + 1, len); + len = (phi[0] + 15) >> 4; + + /* + * Divide phi by public exponent e. The final remainder r must be + * non-zero (otherwise, the key is invalid). The quotient is k, + * which we write over phi, since we don't need phi after that. + */ + r = 0; + for (u = len; u >= 1; u --) { + /* + * Upon entry, r < e, and phi[u] < 2^15; hence, + * hi:lo < e*2^15. Thus, the produced word k[u] + * must be lower than 2^15, and the new remainder r + * is lower than e. + */ + uint32_t hi, lo; + + hi = r >> 17; + lo = (r << 15) + phi[u]; + phi[u] = br_divrem(hi, lo, e, &r); + } + if (r == 0) { + return 0; + } + k = phi; + + /* + * Compute u and v such that u*e - v*r = GCD(e,r). We use + * a binary GCD algorithm, with 6 extra integers a, b, + * u0, u1, v0 and v1. Initial values are: + * a = e u0 = 1 v0 = 0 + * b = r u1 = r v1 = e-1 + * The following invariants are maintained: + * a = u0*e - v0*r + * b = u1*e - v1*r + * 0 < a <= e + * 0 < b <= r + * 0 <= u0 <= r + * 0 <= v0 <= e + * 0 <= u1 <= r + * 0 <= v1 <= e + * + * At each iteration, we reduce either a or b by one bit, and + * adjust u0, u1, v0 and v1 to maintain the invariants: + * - if a is even, then a <- a/2 + * - otherwise, if b is even, then b <- b/2 + * - otherwise, if a > b, then a <- (a-b)/2 + * - otherwise, if b > a, then b <- (b-a)/2 + * Algorithm stops when a = b. At that point, the common value + * is the GCD of e and r; it must be 1 (otherwise, the private + * key or public exponent is not valid). The (u0,v0) or (u1,v1) + * pairs are the solution we are looking for. + * + * Since either a or b is reduced by at least 1 bit at each + * iteration, 62 iterations are enough to reach the end + * condition. + * + * To maintain the invariants, we must compute the same operations + * on the u* and v* values that we do on a and b: + * - When a is divided by 2, u0 and v0 must be divided by 2. + * - When b is divided by 2, u1 and v1 must be divided by 2. + * - When b is subtracted from a, u1 and v1 are subtracted from + * u0 and v0, respectively. + * - When a is subtracted from b, u0 and v0 are subtracted from + * u1 and v1, respectively. + * + * However, we want to keep the u* and v* values in their proper + * ranges. The following remarks apply: + * + * - When a is divided by 2, then a is even. Therefore: + * + * * If r is odd, then u0 and v0 must have the same parity; + * if they are both odd, then adding r to u0 and e to v0 + * makes them both even, and the division by 2 brings them + * back to the proper range. + * + * * If r is even, then u0 must be even; if v0 is odd, then + * adding r to u0 and e to v0 makes them both even, and the + * division by 2 brings them back to the proper range. + * + * Thus, all we need to do is to look at the parity of v0, + * and add (r,e) to (u0,v0) when v0 is odd. In order to avoid + * a 32-bit overflow, we can add ((r+1)/2,(e/2)+1) after the + * division (r+1 does not overflow since r < e; and (e/2)+1 + * is equal to (e+1)/2 since e is odd). + * + * - When we subtract b from a, three cases may occur: + * + * * u1 <= u0 and v1 <= v0: just do the subtractions + * + * * u1 > u0 and v1 > v0: compute: + * (u0, v0) <- (u0 + r - u1, v0 + e - v1) + * + * * u1 <= u0 and v1 > v0: compute: + * (u0, v0) <- (u0 + r - u1, v0 + e - v1) + * + * The fourth case (u1 > u0 and v1 <= v0) is not possible + * because it would contradict "b < a" (which is the reason + * why we subtract b from a). + * + * The tricky case is the third one: from the equations, it + * seems that u0 may go out of range. However, the invariants + * and ranges of other values imply that, in that case, the + * new u0 does not actually exceed the range. + * + * We can thus handle the subtraction by adding (r,e) based + * solely on the comparison between v0 and v1. + */ + a = e; + b = r; + u0 = 1; + v0 = 0; + u1 = r; + v1 = e - 1; + hr = (r + 1) >> 1; + he = (e >> 1) + 1; + for (i = 0; i < 62; i ++) { + uint32_t oa, ob, agtb, bgta; + uint32_t sab, sba, da, db; + uint32_t ctl; + + oa = a & 1; /* 1 if a is odd */ + ob = b & 1; /* 1 if b is odd */ + agtb = GT(a, b); /* 1 if a > b */ + bgta = GT(b, a); /* 1 if b > a */ + + sab = oa & ob & agtb; /* 1 if a <- a-b */ + sba = oa & ob & bgta; /* 1 if b <- b-a */ + + /* a <- a-b, u0 <- u0-u1, v0 <- v0-v1 */ + ctl = GT(v1, v0); + a -= b & -sab; + u0 -= (u1 - (r & -ctl)) & -sab; + v0 -= (v1 - (e & -ctl)) & -sab; + + /* b <- b-a, u1 <- u1-u0 mod r, v1 <- v1-v0 mod e */ + ctl = GT(v0, v1); + b -= a & -sba; + u1 -= (u0 - (r & -ctl)) & -sba; + v1 -= (v0 - (e & -ctl)) & -sba; + + da = NOT(oa) | sab; /* 1 if a <- a/2 */ + db = (oa & NOT(ob)) | sba; /* 1 if b <- b/2 */ + + /* a <- a/2, u0 <- u0/2, v0 <- v0/2 */ + ctl = v0 & 1; + a ^= (a ^ (a >> 1)) & -da; + u0 ^= (u0 ^ ((u0 >> 1) + (hr & -ctl))) & -da; + v0 ^= (v0 ^ ((v0 >> 1) + (he & -ctl))) & -da; + + /* b <- b/2, u1 <- u1/2 mod r, v1 <- v1/2 mod e */ + ctl = v1 & 1; + b ^= (b ^ (b >> 1)) & -db; + u1 ^= (u1 ^ ((u1 >> 1) + (hr & -ctl))) & -db; + v1 ^= (v1 ^ ((v1 >> 1) + (he & -ctl))) & -db; + } + + /* + * Check that the GCD is indeed 1. If not, then the key is invalid + * (and there's no harm in leaking that piece of information). + */ + if (a != 1) { + return 0; + } + + /* + * Now we have u0*e - v0*r = 1. Let's compute the result as: + * d = u0 + v0*k + * We still have k in the tmp[] array, and its announced bit + * length is that of phi. + */ + m = k + 1 + len; + m[0] = (2 << 4) + 2; /* bit length is 32 bits, encoded */ + m[1] = v0 & 0x7FFF; + m[2] = (v0 >> 15) & 0x7FFF; + m[3] = v0 >> 30; + z = m + 4; + br_i15_zero(z, k[0]); + z[1] = u0 & 0x7FFF; + z[2] = (u0 >> 15) & 0x7FFF; + z[3] = u0 >> 30; + br_i15_mulacc(z, k, m); + + /* + * Encode the result. + */ + br_i15_encode(d, dlen, z); + return dlen; +} diff --git a/src/bearssl/src/rsa/rsa_i15_pub.c b/src/bearssl/src/rsa/rsa_i15_pub.c new file mode 100644 index 0000000..9eab5e8 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_pub.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * As a strict minimum, we need four buffers that can hold a + * modular integer. + */ +#define TLEN (4 * (2 + ((BR_MAX_RSA_SIZE + 14) / 15))) + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk) +{ + const unsigned char *n; + size_t nlen; + uint16_t tmp[1 + TLEN]; + uint16_t *m, *a, *t; + size_t fwlen; + long z; + uint16_t m0i; + uint32_t r; + + /* + * Get the actual length of the modulus, and see if it fits within + * our stack buffer. We also check that the length of x[] is valid. + */ + n = pk->n; + nlen = pk->nlen; + while (nlen > 0 && *n == 0) { + n ++; + nlen --; + } + if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) { + return 0; + } + z = (long)nlen << 3; + fwlen = 1; + while (z > 0) { + z -= 15; + fwlen ++; + } + /* + * Round up length to an even number. + */ + fwlen += (fwlen & 1); + + /* + * The modulus gets decoded into m[]. + * The value to exponentiate goes into a[]. + * The temporaries for modular exponentiations are in t[]. + * + * We want the first value word of each integer to be aligned + * on a 32-bit boundary. + */ + m = tmp; + if (((uintptr_t)m & 2) == 0) { + m ++; + } + a = m + fwlen; + t = m + 2 * fwlen; + + /* + * Decode the modulus. + */ + br_i15_decode(m, n, nlen); + m0i = br_i15_ninv15(m[1]); + + /* + * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be + * an odd integer. + */ + r = m0i & 1; + + /* + * Decode x[] into a[]; we also check that its value is proper. + */ + r &= br_i15_decode_mod(a, x, xlen, m); + + /* + * Compute the modular exponentiation. + */ + br_i15_modpow_opt(a, pk->e, pk->elen, m, m0i, t, TLEN - 2 * fwlen); + + /* + * Encode the result. + */ + br_i15_encode(x, xlen, a); + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i15_pubexp.c b/src/bearssl/src/rsa/rsa_i15_pubexp.c new file mode 100644 index 0000000..803bff7 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_pubexp.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Recompute public exponent, based on factor p and reduced private + * exponent dp. + */ +static uint32_t +get_pubexp(const unsigned char *pbuf, size_t plen, + const unsigned char *dpbuf, size_t dplen) +{ + /* + * dp is the inverse of e modulo p-1. If p = 3 mod 4, then + * p-1 = 2*((p-1)/2). Taken modulo 2, e is odd and has inverse 1; + * thus, dp must be odd. + * + * We compute the inverse of dp modulo (p-1)/2. This requires + * first reducing dp modulo (p-1)/2 (this can be done with a + * conditional subtract, no need to use the generic modular + * reduction function); then, we use moddiv. + */ + + uint16_t tmp[6 * ((BR_MAX_RSA_FACTOR + 29) / 15)]; + uint16_t *p, *dp, *x; + size_t len; + uint32_t e; + + /* + * Compute actual factor length (in bytes) and check that it fits + * under our size constraints. + */ + while (plen > 0 && *pbuf == 0) { + pbuf ++; + plen --; + } + if (plen == 0 || plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8)) { + return 0; + } + + /* + * Compute actual reduced exponent length (in bytes) and check that + * it is not longer than p. + */ + while (dplen > 0 && *dpbuf == 0) { + dpbuf ++; + dplen --; + } + if (dplen > plen || dplen == 0 + || (dplen == plen && dpbuf[0] > pbuf[0])) + { + return 0; + } + + /* + * Verify that p = 3 mod 4 and that dp is odd. + */ + if ((pbuf[plen - 1] & 3) != 3 || (dpbuf[dplen - 1] & 1) != 1) { + return 0; + } + + /* + * Decode p and compute (p-1)/2. + */ + p = tmp; + br_i15_decode(p, pbuf, plen); + len = (p[0] + 31) >> 4; + br_i15_rshift(p, 1); + + /* + * Decode dp and make sure its announced bit length matches that of + * p (we already know that the size of dp, in bits, does not exceed + * the size of p, so we just have to copy the header word). + */ + dp = p + len; + memset(dp, 0, len * sizeof *dp); + br_i15_decode(dp, dpbuf, dplen); + dp[0] = p[0]; + + /* + * Subtract (p-1)/2 from dp if necessary. + */ + br_i15_sub(dp, p, NOT(br_i15_sub(dp, p, 0))); + + /* + * If another subtraction is needed, then this means that the + * value was invalid. We don't care to leak information about + * invalid keys. + */ + if (br_i15_sub(dp, p, 0) == 0) { + return 0; + } + + /* + * Invert dp modulo (p-1)/2. If the inversion fails, then the + * key value was invalid. + */ + x = dp + len; + br_i15_zero(x, p[0]); + x[1] = 1; + if (br_i15_moddiv(x, dp, p, br_i15_ninv15(p[1]), x + len) == 0) { + return 0; + } + + /* + * We now have an inverse. We must set it to zero (error) if its + * length is greater than 32 bits and/or if it is an even integer. + * Take care that the bit_length function returns an encoded + * bit length. + */ + e = (uint32_t)x[1] | ((uint32_t)x[2] << 15) | ((uint32_t)x[3] << 30); + e &= -LT(br_i15_bit_length(x + 1, len - 1), 35); + e &= -(e & 1); + return e; +} + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_compute_pubexp(const br_rsa_private_key *sk) +{ + /* + * Get the public exponent from both p and q. This is the right + * exponent if we get twice the same value. + */ + uint32_t ep, eq; + + ep = get_pubexp(sk->p, sk->plen, sk->dp, sk->dplen); + eq = get_pubexp(sk->q, sk->qlen, sk->dq, sk->dqlen); + return ep & -EQ(ep, eq); +} diff --git a/src/bearssl/src/rsa/rsa_i31_keygen.c b/src/bearssl/src/rsa/rsa_i31_keygen.c new file mode 100644 index 0000000..77708f8 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_keygen.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_keygen(const br_prng_class **rng, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp) +{ + return br_rsa_i31_keygen_inner(rng, + sk, kbuf_priv, pk, kbuf_pub, size, pubexp, + &br_i31_modpow_opt); +} diff --git a/src/bearssl/src/rsa/rsa_i31_keygen_inner.c b/src/bearssl/src/rsa/rsa_i31_keygen_inner.c new file mode 100644 index 0000000..9ec881b --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_keygen_inner.c @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Make a random integer of the provided size. The size is encoded. + * The header word is untouched. + */ +static void +mkrand(const br_prng_class **rng, uint32_t *x, uint32_t esize) +{ + size_t u, len; + unsigned m; + + len = (esize + 31) >> 5; + (*rng)->generate(rng, x + 1, len * sizeof(uint32_t)); + for (u = 1; u < len; u ++) { + x[u] &= 0x7FFFFFFF; + } + m = esize & 31; + if (m == 0) { + x[len] &= 0x7FFFFFFF; + } else { + x[len] &= 0x7FFFFFFF >> (31 - m); + } +} + +/* + * This is the big-endian unsigned representation of the product of + * all small primes from 13 to 1481. + */ +static const unsigned char SMALL_PRIMES[] = { + 0x2E, 0xAB, 0x92, 0xD1, 0x8B, 0x12, 0x47, 0x31, 0x54, 0x0A, + 0x99, 0x5D, 0x25, 0x5E, 0xE2, 0x14, 0x96, 0x29, 0x1E, 0xB7, + 0x78, 0x70, 0xCC, 0x1F, 0xA5, 0xAB, 0x8D, 0x72, 0x11, 0x37, + 0xFB, 0xD8, 0x1E, 0x3F, 0x5B, 0x34, 0x30, 0x17, 0x8B, 0xE5, + 0x26, 0x28, 0x23, 0xA1, 0x8A, 0xA4, 0x29, 0xEA, 0xFD, 0x9E, + 0x39, 0x60, 0x8A, 0xF3, 0xB5, 0xA6, 0xEB, 0x3F, 0x02, 0xB6, + 0x16, 0xC3, 0x96, 0x9D, 0x38, 0xB0, 0x7D, 0x82, 0x87, 0x0C, + 0xF7, 0xBE, 0x24, 0xE5, 0x5F, 0x41, 0x04, 0x79, 0x76, 0x40, + 0xE7, 0x00, 0x22, 0x7E, 0xB5, 0x85, 0x7F, 0x8D, 0x01, 0x50, + 0xE9, 0xD3, 0x29, 0x42, 0x08, 0xB3, 0x51, 0x40, 0x7B, 0xD7, + 0x8D, 0xCC, 0x10, 0x01, 0x64, 0x59, 0x28, 0xB6, 0x53, 0xF3, + 0x50, 0x4E, 0xB1, 0xF2, 0x58, 0xCD, 0x6E, 0xF5, 0x56, 0x3E, + 0x66, 0x2F, 0xD7, 0x07, 0x7F, 0x52, 0x4C, 0x13, 0x24, 0xDC, + 0x8E, 0x8D, 0xCC, 0xED, 0x77, 0xC4, 0x21, 0xD2, 0xFD, 0x08, + 0xEA, 0xD7, 0xC0, 0x5C, 0x13, 0x82, 0x81, 0x31, 0x2F, 0x2B, + 0x08, 0xE4, 0x80, 0x04, 0x7A, 0x0C, 0x8A, 0x3C, 0xDC, 0x22, + 0xE4, 0x5A, 0x7A, 0xB0, 0x12, 0x5E, 0x4A, 0x76, 0x94, 0x77, + 0xC2, 0x0E, 0x92, 0xBA, 0x8A, 0xA0, 0x1F, 0x14, 0x51, 0x1E, + 0x66, 0x6C, 0x38, 0x03, 0x6C, 0xC7, 0x4A, 0x4B, 0x70, 0x80, + 0xAF, 0xCA, 0x84, 0x51, 0xD8, 0xD2, 0x26, 0x49, 0xF5, 0xA8, + 0x5E, 0x35, 0x4B, 0xAC, 0xCE, 0x29, 0x92, 0x33, 0xB7, 0xA2, + 0x69, 0x7D, 0x0C, 0xE0, 0x9C, 0xDB, 0x04, 0xD6, 0xB4, 0xBC, + 0x39, 0xD7, 0x7F, 0x9E, 0x9D, 0x78, 0x38, 0x7F, 0x51, 0x54, + 0x50, 0x8B, 0x9E, 0x9C, 0x03, 0x6C, 0xF5, 0x9D, 0x2C, 0x74, + 0x57, 0xF0, 0x27, 0x2A, 0xC3, 0x47, 0xCA, 0xB9, 0xD7, 0x5C, + 0xFF, 0xC2, 0xAC, 0x65, 0x4E, 0xBD +}; + +/* + * We need temporary values for at least 7 integers of the same size + * as a factor (including header word); more space helps with performance + * (in modular exponentiations), but we much prefer to remain under + * 2 kilobytes in total, to save stack space. The macro TEMPS below + * exceeds 512 (which is a count in 32-bit words) when BR_MAX_RSA_SIZE + * is greater than 4464 (default value is 4096, so the 2-kB limit is + * maintained unless BR_MAX_RSA_SIZE was modified). + */ +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ROUND2(x) ((((x) + 1) >> 1) << 1) + +#define TEMPS MAX(512, ROUND2(7 * ((((BR_MAX_RSA_SIZE + 1) >> 1) + 61) / 31))) + +/* + * Perform trial division on a candidate prime. This computes + * y = SMALL_PRIMES mod x, then tries to compute y/y mod x. The + * br_i31_moddiv() function will report an error if y is not invertible + * modulo x. Returned value is 1 on success (none of the small primes + * divides x), 0 on error (a non-trivial GCD is obtained). + * + * This function assumes that x is odd. + */ +static uint32_t +trial_divisions(const uint32_t *x, uint32_t *t) +{ + uint32_t *y; + uint32_t x0i; + + y = t; + t += 1 + ((x[0] + 31) >> 5); + x0i = br_i31_ninv31(x[1]); + br_i31_decode_reduce(y, SMALL_PRIMES, sizeof SMALL_PRIMES, x); + return br_i31_moddiv(y, y, x, x0i, t); +} + +/* + * Perform n rounds of Miller-Rabin on the candidate prime x. This + * function assumes that x = 3 mod 4. + * + * Returned value is 1 on success (all rounds completed successfully), + * 0 otherwise. + */ +static uint32_t +miller_rabin(const br_prng_class **rng, const uint32_t *x, int n, + uint32_t *t, size_t tlen, br_i31_modpow_opt_type mp31) +{ + /* + * Since x = 3 mod 4, the Miller-Rabin test is simple: + * - get a random base a (such that 1 < a < x-1) + * - compute z = a^((x-1)/2) mod x + * - if z != 1 and z != x-1, the number x is composite + * + * We generate bases 'a' randomly with a size which is + * one bit less than x, which ensures that a < x-1. It + * is not useful to verify that a > 1 because the probability + * that we get a value a equal to 0 or 1 is much smaller + * than the probability of our Miller-Rabin tests not to + * detect a composite, which is already quite smaller than the + * probability of the hardware misbehaving and return a + * composite integer because of some glitch (e.g. bad RAM + * or ill-timed cosmic ray). + */ + unsigned char *xm1d2; + size_t xlen, xm1d2_len, xm1d2_len_u32, u; + uint32_t asize; + unsigned cc; + uint32_t x0i; + + /* + * Compute (x-1)/2 (encoded). + */ + xm1d2 = (unsigned char *)t; + xm1d2_len = ((x[0] - (x[0] >> 5)) + 7) >> 3; + br_i31_encode(xm1d2, xm1d2_len, x); + cc = 0; + for (u = 0; u < xm1d2_len; u ++) { + unsigned w; + + w = xm1d2[u]; + xm1d2[u] = (unsigned char)((w >> 1) | cc); + cc = w << 7; + } + + /* + * We used some words of the provided buffer for (x-1)/2. + */ + xm1d2_len_u32 = (xm1d2_len + 3) >> 2; + t += xm1d2_len_u32; + tlen -= xm1d2_len_u32; + + xlen = (x[0] + 31) >> 5; + asize = x[0] - 1 - EQ0(x[0] & 31); + x0i = br_i31_ninv31(x[1]); + while (n -- > 0) { + uint32_t *a, *t2; + uint32_t eq1, eqm1; + size_t t2len; + + /* + * Generate a random base. We don't need the base to be + * really uniform modulo x, so we just get a random + * number which is one bit shorter than x. + */ + a = t; + a[0] = x[0]; + a[xlen] = 0; + mkrand(rng, a, asize); + + /* + * Compute a^((x-1)/2) mod x. We assume here that the + * function will not fail (the temporary array is large + * enough). + */ + t2 = t + 1 + xlen; + t2len = tlen - 1 - xlen; + if ((t2len & 1) != 0) { + /* + * Since the source array is 64-bit aligned and + * has an even number of elements (TEMPS), we + * can use the parity of the remaining length to + * detect and adjust alignment. + */ + t2 ++; + t2len --; + } + mp31(a, xm1d2, xm1d2_len, x, x0i, t2, t2len); + + /* + * We must obtain either 1 or x-1. Note that x is odd, + * hence x-1 differs from x only in its low word (no + * carry). + */ + eq1 = a[1] ^ 1; + eqm1 = a[1] ^ (x[1] - 1); + for (u = 2; u <= xlen; u ++) { + eq1 |= a[u]; + eqm1 |= a[u] ^ x[u]; + } + + if ((EQ0(eq1) | EQ0(eqm1)) == 0) { + return 0; + } + } + return 1; +} + +/* + * Create a random prime of the provided size. 'size' is the _encoded_ + * bit length. The two top bits and the two bottom bits are set to 1. + */ +static void +mkprime(const br_prng_class **rng, uint32_t *x, uint32_t esize, + uint32_t pubexp, uint32_t *t, size_t tlen, br_i31_modpow_opt_type mp31) +{ + size_t len; + + x[0] = esize; + len = (esize + 31) >> 5; + for (;;) { + size_t u; + uint32_t m3, m5, m7, m11; + int rounds, s7, s11; + + /* + * Generate random bits. We force the two top bits and the + * two bottom bits to 1. + */ + mkrand(rng, x, esize); + if ((esize & 31) == 0) { + x[len] |= 0x60000000; + } else if ((esize & 31) == 1) { + x[len] |= 0x00000001; + x[len - 1] |= 0x40000000; + } else { + x[len] |= 0x00000003 << ((esize & 31) - 2); + } + x[1] |= 0x00000003; + + /* + * Trial division with low primes (3, 5, 7 and 11). We + * use the following properties: + * + * 2^2 = 1 mod 3 + * 2^4 = 1 mod 5 + * 2^3 = 1 mod 7 + * 2^10 = 1 mod 11 + */ + m3 = 0; + m5 = 0; + m7 = 0; + m11 = 0; + s7 = 0; + s11 = 0; + for (u = 0; u < len; u ++) { + uint32_t w, w3, w5, w7, w11; + + w = x[1 + u]; + w3 = (w & 0xFFFF) + (w >> 16); /* max: 98302 */ + w5 = (w & 0xFFFF) + (w >> 16); /* max: 98302 */ + w7 = (w & 0x7FFF) + (w >> 15); /* max: 98302 */ + w11 = (w & 0xFFFFF) + (w >> 20); /* max: 1050622 */ + + m3 += w3 << (u & 1); + m3 = (m3 & 0xFF) + (m3 >> 8); /* max: 1025 */ + + m5 += w5 << ((4 - u) & 3); + m5 = (m5 & 0xFFF) + (m5 >> 12); /* max: 4479 */ + + m7 += w7 << s7; + m7 = (m7 & 0x1FF) + (m7 >> 9); /* max: 1280 */ + if (++ s7 == 3) { + s7 = 0; + } + + m11 += w11 << s11; + if (++ s11 == 10) { + s11 = 0; + } + m11 = (m11 & 0x3FF) + (m11 >> 10); /* max: 526847 */ + } + + m3 = (m3 & 0x3F) + (m3 >> 6); /* max: 78 */ + m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 18 */ + m3 = ((m3 * 43) >> 5) & 3; + + m5 = (m5 & 0xFF) + (m5 >> 8); /* max: 271 */ + m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 31 */ + m5 -= 20 & -GT(m5, 19); + m5 -= 10 & -GT(m5, 9); + m5 -= 5 & -GT(m5, 4); + + m7 = (m7 & 0x3F) + (m7 >> 6); /* max: 82 */ + m7 = (m7 & 0x07) + (m7 >> 3); /* max: 16 */ + m7 = ((m7 * 147) >> 7) & 7; + + /* + * 2^5 = 32 = -1 mod 11. + */ + m11 = (m11 & 0x3FF) + (m11 >> 10); /* max: 1536 */ + m11 = (m11 & 0x3FF) + (m11 >> 10); /* max: 1023 */ + m11 = (m11 & 0x1F) + 33 - (m11 >> 5); /* max: 64 */ + m11 -= 44 & -GT(m11, 43); + m11 -= 22 & -GT(m11, 21); + m11 -= 11 & -GT(m11, 10); + + /* + * If any of these modulo is 0, then the candidate is + * not prime. Also, if pubexp is 3, 5, 7 or 11, and the + * corresponding modulus is 1, then the candidate must + * be rejected, because we need e to be invertible + * modulo p-1. We can use simple comparisons here + * because they won't leak information on a candidate + * that we keep, only on one that we reject (and is thus + * not secret). + */ + if (m3 == 0 || m5 == 0 || m7 == 0 || m11 == 0) { + continue; + } + if ((pubexp == 3 && m3 == 1) + || (pubexp == 5 && m5 == 5) + || (pubexp == 7 && m5 == 7) + || (pubexp == 11 && m5 == 11)) + { + continue; + } + + /* + * More trial divisions. + */ + if (!trial_divisions(x, t)) { + continue; + } + + /* + * Miller-Rabin algorithm. Since we selected a random + * integer, not a maliciously crafted integer, we can use + * relatively few rounds to lower the risk of a false + * positive (i.e. declaring prime a non-prime) under + * 2^(-80). It is not useful to lower the probability much + * below that, since that would be substantially below + * the probability of the hardware misbehaving. Sufficient + * numbers of rounds are extracted from the Handbook of + * Applied Cryptography, note 4.49 (page 149). + * + * Since we work on the encoded size (esize), we need to + * compare with encoded thresholds. + */ + if (esize < 309) { + rounds = 12; + } else if (esize < 464) { + rounds = 9; + } else if (esize < 670) { + rounds = 6; + } else if (esize < 877) { + rounds = 4; + } else if (esize < 1341) { + rounds = 3; + } else { + rounds = 2; + } + + if (miller_rabin(rng, x, rounds, t, tlen, mp31)) { + return; + } + } +} + +/* + * Let p be a prime (p > 2^33, p = 3 mod 4). Let m = (p-1)/2, provided + * as parameter (with announced bit length equal to that of p). This + * function computes d = 1/e mod p-1 (for an odd integer e). Returned + * value is 1 on success, 0 on error (an error is reported if e is not + * invertible modulo p-1). + * + * The temporary buffer (t) must have room for at least 4 integers of + * the size of p. + */ +static uint32_t +invert_pubexp(uint32_t *d, const uint32_t *m, uint32_t e, uint32_t *t) +{ + uint32_t *f; + uint32_t r; + + f = t; + t += 1 + ((m[0] + 31) >> 5); + + /* + * Compute d = 1/e mod m. Since p = 3 mod 4, m is odd. + */ + br_i31_zero(d, m[0]); + d[1] = 1; + br_i31_zero(f, m[0]); + f[1] = e & 0x7FFFFFFF; + f[2] = e >> 31; + r = br_i31_moddiv(d, f, m, br_i31_ninv31(m[1]), t); + + /* + * We really want d = 1/e mod p-1, with p = 2m. By the CRT, + * the result is either the d we got, or d + m. + * + * Let's write e*d = 1 + k*m, for some integer k. Integers e + * and m are odd. If d is odd, then e*d is odd, which implies + * that k must be even; in that case, e*d = 1 + (k/2)*2m, and + * thus d is already fine. Conversely, if d is even, then k + * is odd, and we must add m to d in order to get the correct + * result. + */ + br_i31_add(d, m, (uint32_t)(1 - (d[1] & 1))); + + return r; +} + +/* + * Swap two buffers in RAM. They must be disjoint. + */ +static void +bufswap(void *b1, void *b2, size_t len) +{ + size_t u; + unsigned char *buf1, *buf2; + + buf1 = b1; + buf2 = b2; + for (u = 0; u < len; u ++) { + unsigned w; + + w = buf1[u]; + buf1[u] = buf2[u]; + buf2[u] = w; + } +} + +/* see inner.h */ +uint32_t +br_rsa_i31_keygen_inner(const br_prng_class **rng, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp, br_i31_modpow_opt_type mp31) +{ + uint32_t esize_p, esize_q; + size_t plen, qlen, tlen; + uint32_t *p, *q, *t; + union { + uint32_t t32[TEMPS]; + uint64_t t64[TEMPS >> 1]; /* for 64-bit alignment */ + } tmp; + uint32_t r; + + if (size < BR_MIN_RSA_SIZE || size > BR_MAX_RSA_SIZE) { + return 0; + } + if (pubexp == 0) { + pubexp = 3; + } else if (pubexp == 1 || (pubexp & 1) == 0) { + return 0; + } + + esize_p = (size + 1) >> 1; + esize_q = size - esize_p; + sk->n_bitlen = size; + sk->p = kbuf_priv; + sk->plen = (esize_p + 7) >> 3; + sk->q = sk->p + sk->plen; + sk->qlen = (esize_q + 7) >> 3; + sk->dp = sk->q + sk->qlen; + sk->dplen = sk->plen; + sk->dq = sk->dp + sk->dplen; + sk->dqlen = sk->qlen; + sk->iq = sk->dq + sk->dqlen; + sk->iqlen = sk->plen; + + if (pk != NULL) { + pk->n = kbuf_pub; + pk->nlen = (size + 7) >> 3; + pk->e = pk->n + pk->nlen; + pk->elen = 4; + br_enc32be(pk->e, pubexp); + while (*pk->e == 0) { + pk->e ++; + pk->elen --; + } + } + + /* + * We now switch to encoded sizes. + * + * floor((x * 16913) / (2^19)) is equal to floor(x/31) for all + * integers x from 0 to 34966; the intermediate product fits on + * 30 bits, thus we can use MUL31(). + */ + esize_p += MUL31(esize_p, 16913) >> 19; + esize_q += MUL31(esize_q, 16913) >> 19; + plen = (esize_p + 31) >> 5; + qlen = (esize_q + 31) >> 5; + p = tmp.t32; + q = p + 1 + plen; + t = q + 1 + qlen; + tlen = ((sizeof tmp.t32) / sizeof(uint32_t)) - (2 + plen + qlen); + + /* + * When looking for primes p and q, we temporarily divide + * candidates by 2, in order to compute the inverse of the + * public exponent. + */ + + for (;;) { + mkprime(rng, p, esize_p, pubexp, t, tlen, mp31); + br_i31_rshift(p, 1); + if (invert_pubexp(t, p, pubexp, t + 1 + plen)) { + br_i31_add(p, p, 1); + p[1] |= 1; + br_i31_encode(sk->p, sk->plen, p); + br_i31_encode(sk->dp, sk->dplen, t); + break; + } + } + + for (;;) { + mkprime(rng, q, esize_q, pubexp, t, tlen, mp31); + br_i31_rshift(q, 1); + if (invert_pubexp(t, q, pubexp, t + 1 + qlen)) { + br_i31_add(q, q, 1); + q[1] |= 1; + br_i31_encode(sk->q, sk->qlen, q); + br_i31_encode(sk->dq, sk->dqlen, t); + break; + } + } + + /* + * If p and q have the same size, then it is possible that q > p + * (when the target modulus size is odd, we generate p with a + * greater bit length than q). If q > p, we want to swap p and q + * (and also dp and dq) for two reasons: + * - The final step below (inversion of q modulo p) is easier if + * p > q. + * - While BearSSL's RSA code is perfectly happy with RSA keys such + * that p < q, some other implementations have restrictions and + * require p > q. + * + * Note that we can do a simple non-constant-time swap here, + * because the only information we leak here is that we insist on + * returning p and q such that p > q, which is not a secret. + */ + if (esize_p == esize_q && br_i31_sub(p, q, 0) == 1) { + bufswap(p, q, (1 + plen) * sizeof *p); + bufswap(sk->p, sk->q, sk->plen); + bufswap(sk->dp, sk->dq, sk->dplen); + } + + /* + * We have produced p, q, dp and dq. We can now compute iq = 1/d mod p. + * + * We ensured that p >= q, so this is just a matter of updating the + * header word for q (and possibly adding an extra word). + * + * Theoretically, the call below may fail, in case we were + * extraordinarily unlucky, and p = q. Another failure case is if + * Miller-Rabin failed us _twice_, and p and q are non-prime and + * have a factor is common. We report the error mostly because it + * is cheap and we can, but in practice this never happens (or, at + * least, it happens way less often than hardware glitches). + */ + q[0] = p[0]; + if (plen > qlen) { + q[plen] = 0; + t ++; + tlen --; + } + br_i31_zero(t, p[0]); + t[1] = 1; + r = br_i31_moddiv(t, q, p, br_i31_ninv31(p[1]), t + 1 + plen); + br_i31_encode(sk->iq, sk->iqlen, t); + + /* + * Compute the public modulus too, if required. + */ + if (pk != NULL) { + br_i31_zero(t, p[0]); + br_i31_mulacc(t, p, q); + br_i31_encode(pk->n, pk->nlen, t); + } + + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i31_modulus.c b/src/bearssl/src/rsa/rsa_i31_modulus.c new file mode 100644 index 0000000..c469cf3 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_modulus.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +size_t +br_rsa_i31_compute_modulus(void *n, const br_rsa_private_key *sk) +{ + uint32_t tmp[2 * ((BR_MAX_RSA_SIZE + 30) / 31) + 5]; + uint32_t *t, *p, *q; + const unsigned char *pbuf, *qbuf; + size_t nlen, plen, qlen, tlen; + + /* + * Compute actual byte and lengths for p and q. + */ + pbuf = sk->p; + plen = sk->plen; + while (plen > 0 && *pbuf == 0) { + pbuf ++; + plen --; + } + qbuf = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *qbuf == 0) { + qbuf ++; + qlen --; + } + + t = tmp; + tlen = (sizeof tmp) / (sizeof tmp[0]); + + /* + * Decode p. + */ + if ((31 * tlen) < (plen << 3) + 31) { + return 0; + } + br_i31_decode(t, pbuf, plen); + p = t; + plen = (p[0] + 63) >> 5; + t += plen; + tlen -= plen; + + /* + * Decode q. + */ + if ((31 * tlen) < (qlen << 3) + 31) { + return 0; + } + br_i31_decode(t, qbuf, qlen); + q = t; + qlen = (q[0] + 63) >> 5; + t += qlen; + tlen -= qlen; + + /* + * Computation can proceed only if we have enough room for the + * modulus. + */ + if (tlen < (plen + qlen + 1)) { + return 0; + } + + /* + * Private key already contains the modulus bit length, from which + * we can infer the output length. Even if n is NULL, we still had + * to decode p and q to make sure that the product can be computed. + */ + nlen = (sk->n_bitlen + 7) >> 3; + if (n != NULL) { + br_i31_zero(t, p[0]); + br_i31_mulacc(t, p, q); + br_i31_encode(n, nlen, t); + } + return nlen; +} diff --git a/src/bearssl/src/rsa/rsa_i31_oaep_decrypt.c b/src/bearssl/src/rsa/rsa_i31_oaep_decrypt.c new file mode 100644 index 0000000..06fdd93 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_oaep_decrypt.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_oaep_decrypt(const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len) +{ + uint32_t r; + + if (*len != ((sk->n_bitlen + 7) >> 3)) { + return 0; + } + r = br_rsa_i31_private(data, sk); + r &= br_rsa_oaep_unpad(dig, label, label_len, data, len); + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i31_oaep_encrypt.c b/src/bearssl/src/rsa/rsa_i31_oaep_encrypt.c new file mode 100644 index 0000000..367008c --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_oaep_encrypt.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +size_t +br_rsa_i31_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len) +{ + size_t dlen; + + dlen = br_rsa_oaep_pad(rnd, dig, label, label_len, + pk, dst, dst_max_len, src, src_len); + if (dlen == 0) { + return 0; + } + return dlen & -(size_t)br_rsa_i31_public(dst, dlen, pk); +} diff --git a/src/bearssl/src/rsa/rsa_i31_pkcs1_sign.c b/src/bearssl/src/rsa/rsa_i31_pkcs1_sign.c new file mode 100644 index 0000000..784d3c2 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_pkcs1_sign.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) { + return 0; + } + return br_rsa_i31_private(x, sk); +} diff --git a/src/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c b/src/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c new file mode 100644 index 0000000..e79a002 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i31_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out); +} diff --git a/src/bearssl/src/rsa/rsa_i31_priv.c b/src/bearssl/src/rsa/rsa_i31_priv.c new file mode 100644 index 0000000..b1e1244 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_priv.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define U (2 + ((BR_MAX_RSA_FACTOR + 30) / 31)) +#define TLEN (8 * U) + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_private(unsigned char *x, const br_rsa_private_key *sk) +{ + const unsigned char *p, *q; + size_t plen, qlen; + size_t fwlen; + uint32_t p0i, q0i; + size_t xlen, u; + uint32_t tmp[1 + TLEN]; + long z; + uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3; + uint32_t r; + + /* + * Compute the actual lengths of p and q, in bytes. + * These lengths are not considered secret (we cannot really hide + * them anyway in constant-time code). + */ + p = sk->p; + plen = sk->plen; + while (plen > 0 && *p == 0) { + p ++; + plen --; + } + q = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *q == 0) { + q ++; + qlen --; + } + + /* + * Compute the maximum factor length, in words. + */ + z = (long)(plen > qlen ? plen : qlen) << 3; + fwlen = 1; + while (z > 0) { + z -= 31; + fwlen ++; + } + + /* + * Round up the word length to an even number. + */ + fwlen += (fwlen & 1); + + /* + * We need to fit at least 6 values in the stack buffer. + */ + if (6 * fwlen > TLEN) { + return 0; + } + + /* + * Compute modulus length (in bytes). + */ + xlen = (sk->n_bitlen + 7) >> 3; + + /* + * Decode q. + */ + mq = tmp; + br_i31_decode(mq, q, qlen); + + /* + * Decode p. + */ + t1 = mq + fwlen; + br_i31_decode(t1, p, plen); + + /* + * Compute the modulus (product of the two factors), to compare + * it with the source value. We use br_i31_mulacc(), since it's + * already used later on. + */ + t2 = mq + 2 * fwlen; + br_i31_zero(t2, mq[0]); + br_i31_mulacc(t2, mq, t1); + + /* + * We encode the modulus into bytes, to perform the comparison + * with bytes. We know that the product length, in bytes, is + * exactly xlen. + * The comparison actually computes the carry when subtracting + * the modulus from the source value; that carry must be 1 for + * a value in the correct range. We keep it in r, which is our + * accumulator for the error code. + */ + t3 = mq + 4 * fwlen; + br_i31_encode(t3, xlen, t2); + u = xlen; + r = 0; + while (u > 0) { + uint32_t wn, wx; + + u --; + wn = ((unsigned char *)t3)[u]; + wx = x[u]; + r = ((wx - (wn + r)) >> 8) & 1; + } + + /* + * Move the decoded p to another temporary buffer. + */ + mp = mq + 2 * fwlen; + memmove(mp, t1, fwlen * sizeof *t1); + + /* + * Compute s2 = x^dq mod q. + */ + q0i = br_i31_ninv31(mq[1]); + s2 = mq + fwlen; + br_i31_decode_reduce(s2, x, xlen, mq); + r &= br_i31_modpow_opt(s2, sk->dq, sk->dqlen, mq, q0i, + mq + 3 * fwlen, TLEN - 3 * fwlen); + + /* + * Compute s1 = x^dp mod p. + */ + p0i = br_i31_ninv31(mp[1]); + s1 = mq + 3 * fwlen; + br_i31_decode_reduce(s1, x, xlen, mp); + r &= br_i31_modpow_opt(s1, sk->dp, sk->dplen, mp, p0i, + mq + 4 * fwlen, TLEN - 4 * fwlen); + + /* + * Compute: + * h = (s1 - s2)*(1/q) mod p + * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is + * unclear about whether p may be lower than q (some existing, + * widely deployed implementations of RSA don't tolerate p < q), + * but we want to support that occurrence, so we need to use the + * reduction function. + * + * Since we use br_i31_decode_reduce() for iq (purportedly, the + * inverse of q modulo p), we also tolerate improperly large + * values for this parameter. + */ + t1 = mq + 4 * fwlen; + t2 = mq + 5 * fwlen; + br_i31_reduce(t2, s2, mp); + br_i31_add(s1, mp, br_i31_sub(s1, t2, 1)); + br_i31_to_monty(s1, mp); + br_i31_decode_reduce(t1, sk->iq, sk->iqlen, mp); + br_i31_montymul(t2, s1, t1, mp, p0i); + + /* + * h is now in t2. We compute the final result: + * s = s2 + q*h + * All these operations are non-modular. + * + * We need mq, s2 and t2. We use the t3 buffer as destination. + * The buffers mp, s1 and t1 are no longer needed, so we can + * reuse them for t3. Moreover, the first step of the computation + * is to copy s2 into t3, after which s2 is not needed. Right + * now, mq is in slot 0, s2 is in slot 1, and t2 is in slot 5. + * Therefore, we have ample room for t3 by simply using s2. + */ + t3 = s2; + br_i31_mulacc(t3, mq, t2); + + /* + * Encode the result. Since we already checked the value of xlen, + * we can just use it right away. + */ + br_i31_encode(x, xlen, t3); + + /* + * The only error conditions remaining at that point are invalid + * values for p and q (even integers). + */ + return p0i & q0i & r; +} diff --git a/src/bearssl/src/rsa/rsa_i31_privexp.c b/src/bearssl/src/rsa/rsa_i31_privexp.c new file mode 100644 index 0000000..eee62a0 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_privexp.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +size_t +br_rsa_i31_compute_privexp(void *d, + const br_rsa_private_key *sk, uint32_t e) +{ + /* + * We want to invert e modulo phi = (p-1)(q-1). This first + * requires computing phi, which is easy since we have the factors + * p and q in the private key structure. + * + * Since p = 3 mod 4 and q = 3 mod 4, phi/4 is an odd integer. + * We could invert e modulo phi/4 then patch the result to + * modulo phi, but this would involve assembling three modulus-wide + * values (phi/4, 1 and e) and calling moddiv, that requires + * three more temporaries, for a total of six big integers, or + * slightly more than 3 kB of stack space for RSA-4096. This + * exceeds our stack requirements. + * + * Instead, we first use one step of the extended GCD: + * + * - We compute phi = k*e + r (Euclidean division of phi by e). + * If public exponent e is correct, then r != 0 (e must be + * invertible modulo phi). We also have k != 0 since we + * enforce non-ridiculously-small factors. + * + * - We find small u, v such that u*e - v*r = 1 (using a + * binary GCD; we can arrange for u < r and v < e, i.e. all + * values fit on 32 bits). + * + * - Solution is: d = u + v*k + * This last computation is exact: since u < r and v < e, + * the above implies d < r + e*((phi-r)/e) = phi + */ + + uint32_t tmp[4 * ((BR_MAX_RSA_FACTOR + 30) / 31) + 12]; + uint32_t *p, *q, *k, *m, *z, *phi; + const unsigned char *pbuf, *qbuf; + size_t plen, qlen, u, len, dlen; + uint32_t r, a, b, u0, v0, u1, v1, he, hr; + int i; + + /* + * Check that e is correct. + */ + if (e < 3 || (e & 1) == 0) { + return 0; + } + + /* + * Check lengths of p and q, and that they are both odd. + */ + pbuf = sk->p; + plen = sk->plen; + while (plen > 0 && *pbuf == 0) { + pbuf ++; + plen --; + } + if (plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8) + || (pbuf[plen - 1] & 1) != 1) + { + return 0; + } + qbuf = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *qbuf == 0) { + qbuf ++; + qlen --; + } + if (qlen < 5 || qlen > (BR_MAX_RSA_FACTOR / 8) + || (qbuf[qlen - 1] & 1) != 1) + { + return 0; + } + + /* + * Output length is that of the modulus. + */ + dlen = (sk->n_bitlen + 7) >> 3; + if (d == NULL) { + return dlen; + } + + p = tmp; + br_i31_decode(p, pbuf, plen); + plen = (p[0] + 31) >> 5; + q = p + 1 + plen; + br_i31_decode(q, qbuf, qlen); + qlen = (q[0] + 31) >> 5; + + /* + * Compute phi = (p-1)*(q-1), then move it over p-1 and q-1 (that + * we do not need anymore). The mulacc function sets the announced + * bit length of t to be the sum of the announced bit lengths of + * p-1 and q-1, which is usually exact but may overshoot by one 1 + * bit in some cases; we readjust it to its true length. + */ + p[1] --; + q[1] --; + phi = q + 1 + qlen; + br_i31_zero(phi, p[0]); + br_i31_mulacc(phi, p, q); + len = (phi[0] + 31) >> 5; + memmove(tmp, phi, (1 + len) * sizeof *phi); + phi = tmp; + phi[0] = br_i31_bit_length(phi + 1, len); + len = (phi[0] + 31) >> 5; + + /* + * Divide phi by public exponent e. The final remainder r must be + * non-zero (otherwise, the key is invalid). The quotient is k, + * which we write over phi, since we don't need phi after that. + */ + r = 0; + for (u = len; u >= 1; u --) { + /* + * Upon entry, r < e, and phi[u] < 2^31; hence, + * hi:lo < e*2^31. Thus, the produced word k[u] + * must be lower than 2^31, and the new remainder r + * is lower than e. + */ + uint32_t hi, lo; + + hi = r >> 1; + lo = (r << 31) + phi[u]; + phi[u] = br_divrem(hi, lo, e, &r); + } + if (r == 0) { + return 0; + } + k = phi; + + /* + * Compute u and v such that u*e - v*r = GCD(e,r). We use + * a binary GCD algorithm, with 6 extra integers a, b, + * u0, u1, v0 and v1. Initial values are: + * a = e u0 = 1 v0 = 0 + * b = r u1 = r v1 = e-1 + * The following invariants are maintained: + * a = u0*e - v0*r + * b = u1*e - v1*r + * 0 < a <= e + * 0 < b <= r + * 0 <= u0 <= r + * 0 <= v0 <= e + * 0 <= u1 <= r + * 0 <= v1 <= e + * + * At each iteration, we reduce either a or b by one bit, and + * adjust u0, u1, v0 and v1 to maintain the invariants: + * - if a is even, then a <- a/2 + * - otherwise, if b is even, then b <- b/2 + * - otherwise, if a > b, then a <- (a-b)/2 + * - otherwise, if b > a, then b <- (b-a)/2 + * Algorithm stops when a = b. At that point, the common value + * is the GCD of e and r; it must be 1 (otherwise, the private + * key or public exponent is not valid). The (u0,v0) or (u1,v1) + * pairs are the solution we are looking for. + * + * Since either a or b is reduced by at least 1 bit at each + * iteration, 62 iterations are enough to reach the end + * condition. + * + * To maintain the invariants, we must compute the same operations + * on the u* and v* values that we do on a and b: + * - When a is divided by 2, u0 and v0 must be divided by 2. + * - When b is divided by 2, u1 and v1 must be divided by 2. + * - When b is subtracted from a, u1 and v1 are subtracted from + * u0 and v0, respectively. + * - When a is subtracted from b, u0 and v0 are subtracted from + * u1 and v1, respectively. + * + * However, we want to keep the u* and v* values in their proper + * ranges. The following remarks apply: + * + * - When a is divided by 2, then a is even. Therefore: + * + * * If r is odd, then u0 and v0 must have the same parity; + * if they are both odd, then adding r to u0 and e to v0 + * makes them both even, and the division by 2 brings them + * back to the proper range. + * + * * If r is even, then u0 must be even; if v0 is odd, then + * adding r to u0 and e to v0 makes them both even, and the + * division by 2 brings them back to the proper range. + * + * Thus, all we need to do is to look at the parity of v0, + * and add (r,e) to (u0,v0) when v0 is odd. In order to avoid + * a 32-bit overflow, we can add ((r+1)/2,(e/2)+1) after the + * division (r+1 does not overflow since r < e; and (e/2)+1 + * is equal to (e+1)/2 since e is odd). + * + * - When we subtract b from a, three cases may occur: + * + * * u1 <= u0 and v1 <= v0: just do the subtractions + * + * * u1 > u0 and v1 > v0: compute: + * (u0, v0) <- (u0 + r - u1, v0 + e - v1) + * + * * u1 <= u0 and v1 > v0: compute: + * (u0, v0) <- (u0 + r - u1, v0 + e - v1) + * + * The fourth case (u1 > u0 and v1 <= v0) is not possible + * because it would contradict "b < a" (which is the reason + * why we subtract b from a). + * + * The tricky case is the third one: from the equations, it + * seems that u0 may go out of range. However, the invariants + * and ranges of other values imply that, in that case, the + * new u0 does not actually exceed the range. + * + * We can thus handle the subtraction by adding (r,e) based + * solely on the comparison between v0 and v1. + */ + a = e; + b = r; + u0 = 1; + v0 = 0; + u1 = r; + v1 = e - 1; + hr = (r + 1) >> 1; + he = (e >> 1) + 1; + for (i = 0; i < 62; i ++) { + uint32_t oa, ob, agtb, bgta; + uint32_t sab, sba, da, db; + uint32_t ctl; + + oa = a & 1; /* 1 if a is odd */ + ob = b & 1; /* 1 if b is odd */ + agtb = GT(a, b); /* 1 if a > b */ + bgta = GT(b, a); /* 1 if b > a */ + + sab = oa & ob & agtb; /* 1 if a <- a-b */ + sba = oa & ob & bgta; /* 1 if b <- b-a */ + + /* a <- a-b, u0 <- u0-u1, v0 <- v0-v1 */ + ctl = GT(v1, v0); + a -= b & -sab; + u0 -= (u1 - (r & -ctl)) & -sab; + v0 -= (v1 - (e & -ctl)) & -sab; + + /* b <- b-a, u1 <- u1-u0 mod r, v1 <- v1-v0 mod e */ + ctl = GT(v0, v1); + b -= a & -sba; + u1 -= (u0 - (r & -ctl)) & -sba; + v1 -= (v0 - (e & -ctl)) & -sba; + + da = NOT(oa) | sab; /* 1 if a <- a/2 */ + db = (oa & NOT(ob)) | sba; /* 1 if b <- b/2 */ + + /* a <- a/2, u0 <- u0/2, v0 <- v0/2 */ + ctl = v0 & 1; + a ^= (a ^ (a >> 1)) & -da; + u0 ^= (u0 ^ ((u0 >> 1) + (hr & -ctl))) & -da; + v0 ^= (v0 ^ ((v0 >> 1) + (he & -ctl))) & -da; + + /* b <- b/2, u1 <- u1/2 mod r, v1 <- v1/2 mod e */ + ctl = v1 & 1; + b ^= (b ^ (b >> 1)) & -db; + u1 ^= (u1 ^ ((u1 >> 1) + (hr & -ctl))) & -db; + v1 ^= (v1 ^ ((v1 >> 1) + (he & -ctl))) & -db; + } + + /* + * Check that the GCD is indeed 1. If not, then the key is invalid + * (and there's no harm in leaking that piece of information). + */ + if (a != 1) { + return 0; + } + + /* + * Now we have u0*e - v0*r = 1. Let's compute the result as: + * d = u0 + v0*k + * We still have k in the tmp[] array, and its announced bit + * length is that of phi. + */ + m = k + 1 + len; + m[0] = (1 << 5) + 1; /* bit length is 32 bits, encoded */ + m[1] = v0 & 0x7FFFFFFF; + m[2] = v0 >> 31; + z = m + 3; + br_i31_zero(z, k[0]); + z[1] = u0 & 0x7FFFFFFF; + z[2] = u0 >> 31; + br_i31_mulacc(z, k, m); + + /* + * Encode the result. + */ + br_i31_encode(d, dlen, z); + return dlen; +} diff --git a/src/bearssl/src/rsa/rsa_i31_pub.c b/src/bearssl/src/rsa/rsa_i31_pub.c new file mode 100644 index 0000000..d5f3fe2 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_pub.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * As a strict minimum, we need four buffers that can hold a + * modular integer. + */ +#define TLEN (4 * (2 + ((BR_MAX_RSA_SIZE + 30) / 31))) + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk) +{ + const unsigned char *n; + size_t nlen; + uint32_t tmp[1 + TLEN]; + uint32_t *m, *a, *t; + size_t fwlen; + long z; + uint32_t m0i, r; + + /* + * Get the actual length of the modulus, and see if it fits within + * our stack buffer. We also check that the length of x[] is valid. + */ + n = pk->n; + nlen = pk->nlen; + while (nlen > 0 && *n == 0) { + n ++; + nlen --; + } + if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) { + return 0; + } + z = (long)nlen << 3; + fwlen = 1; + while (z > 0) { + z -= 31; + fwlen ++; + } + /* + * Round up length to an even number. + */ + fwlen += (fwlen & 1); + + /* + * The modulus gets decoded into m[]. + * The value to exponentiate goes into a[]. + * The temporaries for modular exponentiation are in t[]. + */ + m = tmp; + a = m + fwlen; + t = m + 2 * fwlen; + + /* + * Decode the modulus. + */ + br_i31_decode(m, n, nlen); + m0i = br_i31_ninv31(m[1]); + + /* + * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be + * an odd integer. + */ + r = m0i & 1; + + /* + * Decode x[] into a[]; we also check that its value is proper. + */ + r &= br_i31_decode_mod(a, x, xlen, m); + + /* + * Compute the modular exponentiation. + */ + br_i31_modpow_opt(a, pk->e, pk->elen, m, m0i, t, TLEN - 2 * fwlen); + + /* + * Encode the result. + */ + br_i31_encode(x, xlen, a); + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i31_pubexp.c b/src/bearssl/src/rsa/rsa_i31_pubexp.c new file mode 100644 index 0000000..f26537d --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_pubexp.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Recompute public exponent, based on factor p and reduced private + * exponent dp. + */ +static uint32_t +get_pubexp(const unsigned char *pbuf, size_t plen, + const unsigned char *dpbuf, size_t dplen) +{ + /* + * dp is the inverse of e modulo p-1. If p = 3 mod 4, then + * p-1 = 2*((p-1)/2). Taken modulo 2, e is odd and has inverse 1; + * thus, dp must be odd. + * + * We compute the inverse of dp modulo (p-1)/2. This requires + * first reducing dp modulo (p-1)/2 (this can be done with a + * conditional subtract, no need to use the generic modular + * reduction function); then, we use moddiv. + */ + + uint32_t tmp[6 * ((BR_MAX_RSA_FACTOR + 61) / 31)]; + uint32_t *p, *dp, *x; + size_t len; + uint32_t e; + + /* + * Compute actual factor length (in bytes) and check that it fits + * under our size constraints. + */ + while (plen > 0 && *pbuf == 0) { + pbuf ++; + plen --; + } + if (plen == 0 || plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8)) { + return 0; + } + + /* + * Compute actual reduced exponent length (in bytes) and check that + * it is not longer than p. + */ + while (dplen > 0 && *dpbuf == 0) { + dpbuf ++; + dplen --; + } + if (dplen > plen || dplen == 0 + || (dplen == plen && dpbuf[0] > pbuf[0])) + { + return 0; + } + + /* + * Verify that p = 3 mod 4 and that dp is odd. + */ + if ((pbuf[plen - 1] & 3) != 3 || (dpbuf[dplen - 1] & 1) != 1) { + return 0; + } + + /* + * Decode p and compute (p-1)/2. + */ + p = tmp; + br_i31_decode(p, pbuf, plen); + len = (p[0] + 63) >> 5; + br_i31_rshift(p, 1); + + /* + * Decode dp and make sure its announced bit length matches that of + * p (we already know that the size of dp, in bits, does not exceed + * the size of p, so we just have to copy the header word). + */ + dp = p + len; + memset(dp, 0, len * sizeof *dp); + br_i31_decode(dp, dpbuf, dplen); + dp[0] = p[0]; + + /* + * Subtract (p-1)/2 from dp if necessary. + */ + br_i31_sub(dp, p, NOT(br_i31_sub(dp, p, 0))); + + /* + * If another subtraction is needed, then this means that the + * value was invalid. We don't care to leak information about + * invalid keys. + */ + if (br_i31_sub(dp, p, 0) == 0) { + return 0; + } + + /* + * Invert dp modulo (p-1)/2. If the inversion fails, then the + * key value was invalid. + */ + x = dp + len; + br_i31_zero(x, p[0]); + x[1] = 1; + if (br_i31_moddiv(x, dp, p, br_i31_ninv31(p[1]), x + len) == 0) { + return 0; + } + + /* + * We now have an inverse. We must set it to zero (error) if its + * length is greater than 32 bits and/or if it is an even integer. + * Take care that the bit_length function returns an encoded + * bit length. + */ + e = (uint32_t)x[1] | ((uint32_t)x[2] << 31); + e &= -LT(br_i31_bit_length(x + 1, len - 1), 34); + e &= -(e & 1); + return e; +} + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_compute_pubexp(const br_rsa_private_key *sk) +{ + /* + * Get the public exponent from both p and q. This is the right + * exponent if we get twice the same value. + */ + uint32_t ep, eq; + + ep = get_pubexp(sk->p, sk->plen, sk->dp, sk->dplen); + eq = get_pubexp(sk->q, sk->qlen, sk->dq, sk->dqlen); + return ep & -EQ(ep, eq); +} diff --git a/src/bearssl/src/rsa/rsa_i32_oaep_decrypt.c b/src/bearssl/src/rsa/rsa_i32_oaep_decrypt.c new file mode 100644 index 0000000..ecfd92b --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_oaep_decrypt.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i32_oaep_decrypt(const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len) +{ + uint32_t r; + + if (*len != ((sk->n_bitlen + 7) >> 3)) { + return 0; + } + r = br_rsa_i32_private(data, sk); + r &= br_rsa_oaep_unpad(dig, label, label_len, data, len); + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i32_oaep_encrypt.c b/src/bearssl/src/rsa/rsa_i32_oaep_encrypt.c new file mode 100644 index 0000000..dc17f3f --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_oaep_encrypt.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +size_t +br_rsa_i32_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len) +{ + size_t dlen; + + dlen = br_rsa_oaep_pad(rnd, dig, label, label_len, + pk, dst, dst_max_len, src, src_len); + if (dlen == 0) { + return 0; + } + return dlen & -(size_t)br_rsa_i32_public(dst, dlen, pk); +} diff --git a/src/bearssl/src/rsa/rsa_i32_pkcs1_sign.c b/src/bearssl/src/rsa/rsa_i32_pkcs1_sign.c new file mode 100644 index 0000000..44b6e6d --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_pkcs1_sign.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) { + return 0; + } + return br_rsa_i32_private(x, sk); +} diff --git a/src/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c b/src/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c new file mode 100644 index 0000000..6ee7a19 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i32_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out); +} diff --git a/src/bearssl/src/rsa/rsa_i32_priv.c b/src/bearssl/src/rsa/rsa_i32_priv.c new file mode 100644 index 0000000..05c22ec --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_priv.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define U (1 + (BR_MAX_RSA_FACTOR >> 5)) + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i32_private(unsigned char *x, const br_rsa_private_key *sk) +{ + const unsigned char *p, *q; + size_t plen, qlen; + uint32_t tmp[6 * U]; + uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3; + uint32_t p0i, q0i; + size_t xlen, u; + uint32_t r; + + /* + * All our temporary buffers are from the tmp[] array. + * + * The mp, mq, s1, s2, t1 and t2 buffers are large enough to + * contain a RSA factor. The t3 buffer can contain a complete + * RSA modulus. t3 shares its storage space with s2, s1 and t1, + * in that order (this is important, see below). + */ + mq = tmp; + mp = tmp + U; + t2 = tmp + 2 * U; + s2 = tmp + 3 * U; + s1 = tmp + 4 * U; + t1 = tmp + 5 * U; + t3 = s2; + + /* + * Compute the actual lengths (in bytes) of p and q, and check + * that they fit within our stack buffers. + */ + p = sk->p; + plen = sk->plen; + while (plen > 0 && *p == 0) { + p ++; + plen --; + } + q = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *q == 0) { + q ++; + qlen --; + } + if (plen > (BR_MAX_RSA_FACTOR >> 3) + || qlen > (BR_MAX_RSA_FACTOR >> 3)) + { + return 0; + } + + /* + * Decode p and q. + */ + br_i32_decode(mp, p, plen); + br_i32_decode(mq, q, qlen); + + /* + * Recompute modulus, to compare with the source value. + */ + br_i32_zero(t2, mp[0]); + br_i32_mulacc(t2, mp, mq); + xlen = (sk->n_bitlen + 7) >> 3; + br_i32_encode(t2 + 2 * U, xlen, t2); + u = xlen; + r = 0; + while (u > 0) { + uint32_t wn, wx; + + u --; + wn = ((unsigned char *)(t2 + 2 * U))[u]; + wx = x[u]; + r = ((wx - (wn + r)) >> 8) & 1; + } + + /* + * Compute s1 = x^dp mod p. + */ + p0i = br_i32_ninv32(mp[1]); + br_i32_decode_reduce(s1, x, xlen, mp); + br_i32_modpow(s1, sk->dp, sk->dplen, mp, p0i, t1, t2); + + /* + * Compute s2 = x^dq mod q. + */ + q0i = br_i32_ninv32(mq[1]); + br_i32_decode_reduce(s2, x, xlen, mq); + br_i32_modpow(s2, sk->dq, sk->dqlen, mq, q0i, t1, t2); + + /* + * Compute: + * h = (s1 - s2)*(1/q) mod p + * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is + * unclear about whether p may be lower than q (some existing, + * widely deployed implementations of RSA don't tolerate p < q), + * but we want to support that occurrence, so we need to use the + * reduction function. + * + * Since we use br_i32_decode_reduce() for iq (purportedly, the + * inverse of q modulo p), we also tolerate improperly large + * values for this parameter. + */ + br_i32_reduce(t2, s2, mp); + br_i32_add(s1, mp, br_i32_sub(s1, t2, 1)); + br_i32_to_monty(s1, mp); + br_i32_decode_reduce(t1, sk->iq, sk->iqlen, mp); + br_i32_montymul(t2, s1, t1, mp, p0i); + + /* + * h is now in t2. We compute the final result: + * s = s2 + q*h + * All these operations are non-modular. + * + * We need mq, s2 and t2. We use the t3 buffer as destination. + * The buffers mp, s1 and t1 are no longer needed. Moreover, + * the first step is to copy s2 into the destination buffer t3. + * We thus arranged for t3 to actually share space with s2, and + * to be followed by the space formerly used by s1 and t1. + */ + br_i32_mulacc(t3, mq, t2); + + /* + * Encode the result. Since we already checked the value of xlen, + * we can just use it right away. + */ + br_i32_encode(x, xlen, t3); + + /* + * The only error conditions remaining at that point are invalid + * values for p and q (even integers). + */ + return p0i & q0i & r; +} diff --git a/src/bearssl/src/rsa/rsa_i32_pub.c b/src/bearssl/src/rsa/rsa_i32_pub.c new file mode 100644 index 0000000..6e8d8e3 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_pub.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i32_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk) +{ + const unsigned char *n; + size_t nlen; + uint32_t m[1 + (BR_MAX_RSA_SIZE >> 5)]; + uint32_t a[1 + (BR_MAX_RSA_SIZE >> 5)]; + uint32_t t1[1 + (BR_MAX_RSA_SIZE >> 5)]; + uint32_t t2[1 + (BR_MAX_RSA_SIZE >> 5)]; + uint32_t m0i, r; + + /* + * Get the actual length of the modulus, and see if it fits within + * our stack buffer. We also check that the length of x[] is valid. + */ + n = pk->n; + nlen = pk->nlen; + while (nlen > 0 && *n == 0) { + n ++; + nlen --; + } + if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) { + return 0; + } + br_i32_decode(m, n, nlen); + m0i = br_i32_ninv32(m[1]); + + /* + * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be + * an odd integer. + */ + r = m0i & 1; + + /* + * Decode x[] into a[]; we also check that its value is proper. + */ + r &= br_i32_decode_mod(a, x, xlen, m); + + /* + * Compute the modular exponentiation. + */ + br_i32_modpow(a, pk->e, pk->elen, m, m0i, t1, t2); + + /* + * Encode the result. + */ + br_i32_encode(x, xlen, a); + return r; +} diff --git a/src/bearssl/src/rsa/rsa_i62_keygen.c b/src/bearssl/src/rsa/rsa_i62_keygen.c new file mode 100644 index 0000000..8f55c37 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_keygen.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_keygen(const br_prng_class **rng, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp) +{ + return br_rsa_i31_keygen_inner(rng, + sk, kbuf_priv, pk, kbuf_pub, size, pubexp, + &br_i62_modpow_opt_as_i31); +} + +/* see bearssl_rsa.h */ +br_rsa_keygen +br_rsa_i62_keygen_get() +{ + return &br_rsa_i62_keygen; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_keygen +br_rsa_i62_keygen_get() +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_i62_oaep_decrypt.c b/src/bearssl/src/rsa/rsa_i62_oaep_decrypt.c new file mode 100644 index 0000000..38470dd --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_oaep_decrypt.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_oaep_decrypt(const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len) +{ + uint32_t r; + + if (*len != ((sk->n_bitlen + 7) >> 3)) { + return 0; + } + r = br_rsa_i62_private(data, sk); + r &= br_rsa_oaep_unpad(dig, label, label_len, data, len); + return r; +} + +/* see bearssl_rsa.h */ +br_rsa_oaep_decrypt +br_rsa_i62_oaep_decrypt_get(void) +{ + return &br_rsa_i62_oaep_decrypt; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_oaep_decrypt +br_rsa_i62_oaep_decrypt_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_i62_oaep_encrypt.c b/src/bearssl/src/rsa/rsa_i62_oaep_encrypt.c new file mode 100644 index 0000000..cf41ecb --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_oaep_encrypt.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* see bearssl_rsa.h */ +size_t +br_rsa_i62_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len) +{ + size_t dlen; + + dlen = br_rsa_oaep_pad(rnd, dig, label, label_len, + pk, dst, dst_max_len, src, src_len); + if (dlen == 0) { + return 0; + } + return dlen & -(size_t)br_rsa_i62_public(dst, dlen, pk); +} + +/* see bearssl_rsa.h */ +br_rsa_oaep_encrypt +br_rsa_i62_oaep_encrypt_get(void) +{ + return &br_rsa_i62_oaep_encrypt; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_oaep_encrypt +br_rsa_i62_oaep_encrypt_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_i62_pkcs1_sign.c b/src/bearssl/src/rsa/rsa_i62_pkcs1_sign.c new file mode 100644 index 0000000..a20a084 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_pkcs1_sign.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) { + return 0; + } + return br_rsa_i62_private(x, sk); +} + +/* see bearssl_rsa.h */ +br_rsa_pkcs1_sign +br_rsa_i62_pkcs1_sign_get(void) +{ + return &br_rsa_i62_pkcs1_sign; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_pkcs1_sign +br_rsa_i62_pkcs1_sign_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c b/src/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c new file mode 100644 index 0000000..6519161 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i62_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out); +} + +/* see bearssl_rsa.h */ +br_rsa_pkcs1_vrfy +br_rsa_i62_pkcs1_vrfy_get(void) +{ + return &br_rsa_i62_pkcs1_vrfy; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_pkcs1_vrfy +br_rsa_i62_pkcs1_vrfy_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_i62_priv.c b/src/bearssl/src/rsa/rsa_i62_priv.c new file mode 100644 index 0000000..f0da600 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_priv.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +#define U (2 + ((BR_MAX_RSA_FACTOR + 30) / 31)) +#define TLEN (4 * U) /* TLEN is counted in 64-bit words */ + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_private(unsigned char *x, const br_rsa_private_key *sk) +{ + const unsigned char *p, *q; + size_t plen, qlen; + size_t fwlen; + uint32_t p0i, q0i; + size_t xlen, u; + uint64_t tmp[TLEN]; + long z; + uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3; + uint32_t r; + + /* + * Compute the actual lengths of p and q, in bytes. + * These lengths are not considered secret (we cannot really hide + * them anyway in constant-time code). + */ + p = sk->p; + plen = sk->plen; + while (plen > 0 && *p == 0) { + p ++; + plen --; + } + q = sk->q; + qlen = sk->qlen; + while (qlen > 0 && *q == 0) { + q ++; + qlen --; + } + + /* + * Compute the maximum factor length, in words. + */ + z = (long)(plen > qlen ? plen : qlen) << 3; + fwlen = 1; + while (z > 0) { + z -= 31; + fwlen ++; + } + + /* + * Convert size to 62-bit words. + */ + fwlen = (fwlen + 1) >> 1; + + /* + * We need to fit at least 6 values in the stack buffer. + */ + if (6 * fwlen > TLEN) { + return 0; + } + + /* + * Compute signature length (in bytes). + */ + xlen = (sk->n_bitlen + 7) >> 3; + + /* + * Decode q. + */ + mq = (uint32_t *)tmp; + br_i31_decode(mq, q, qlen); + + /* + * Decode p. + */ + t1 = (uint32_t *)(tmp + fwlen); + br_i31_decode(t1, p, plen); + + /* + * Compute the modulus (product of the two factors), to compare + * it with the source value. We use br_i31_mulacc(), since it's + * already used later on. + */ + t2 = (uint32_t *)(tmp + 2 * fwlen); + br_i31_zero(t2, mq[0]); + br_i31_mulacc(t2, mq, t1); + + /* + * We encode the modulus into bytes, to perform the comparison + * with bytes. We know that the product length, in bytes, is + * exactly xlen. + * The comparison actually computes the carry when subtracting + * the modulus from the source value; that carry must be 1 for + * a value in the correct range. We keep it in r, which is our + * accumulator for the error code. + */ + t3 = (uint32_t *)(tmp + 4 * fwlen); + br_i31_encode(t3, xlen, t2); + u = xlen; + r = 0; + while (u > 0) { + uint32_t wn, wx; + + u --; + wn = ((unsigned char *)t3)[u]; + wx = x[u]; + r = ((wx - (wn + r)) >> 8) & 1; + } + + /* + * Move the decoded p to another temporary buffer. + */ + mp = (uint32_t *)(tmp + 2 * fwlen); + memmove(mp, t1, 2 * fwlen * sizeof *t1); + + /* + * Compute s2 = x^dq mod q. + */ + q0i = br_i31_ninv31(mq[1]); + s2 = (uint32_t *)(tmp + fwlen); + br_i31_decode_reduce(s2, x, xlen, mq); + r &= br_i62_modpow_opt(s2, sk->dq, sk->dqlen, mq, q0i, + tmp + 3 * fwlen, TLEN - 3 * fwlen); + + /* + * Compute s1 = x^dp mod p. + */ + p0i = br_i31_ninv31(mp[1]); + s1 = (uint32_t *)(tmp + 3 * fwlen); + br_i31_decode_reduce(s1, x, xlen, mp); + r &= br_i62_modpow_opt(s1, sk->dp, sk->dplen, mp, p0i, + tmp + 4 * fwlen, TLEN - 4 * fwlen); + + /* + * Compute: + * h = (s1 - s2)*(1/q) mod p + * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is + * unclear about whether p may be lower than q (some existing, + * widely deployed implementations of RSA don't tolerate p < q), + * but we want to support that occurrence, so we need to use the + * reduction function. + * + * Since we use br_i31_decode_reduce() for iq (purportedly, the + * inverse of q modulo p), we also tolerate improperly large + * values for this parameter. + */ + t1 = (uint32_t *)(tmp + 4 * fwlen); + t2 = (uint32_t *)(tmp + 5 * fwlen); + br_i31_reduce(t2, s2, mp); + br_i31_add(s1, mp, br_i31_sub(s1, t2, 1)); + br_i31_to_monty(s1, mp); + br_i31_decode_reduce(t1, sk->iq, sk->iqlen, mp); + br_i31_montymul(t2, s1, t1, mp, p0i); + + /* + * h is now in t2. We compute the final result: + * s = s2 + q*h + * All these operations are non-modular. + * + * We need mq, s2 and t2. We use the t3 buffer as destination. + * The buffers mp, s1 and t1 are no longer needed, so we can + * reuse them for t3. Moreover, the first step of the computation + * is to copy s2 into t3, after which s2 is not needed. Right + * now, mq is in slot 0, s2 is in slot 1, and t2 is in slot 5. + * Therefore, we have ample room for t3 by simply using s2. + */ + t3 = s2; + br_i31_mulacc(t3, mq, t2); + + /* + * Encode the result. Since we already checked the value of xlen, + * we can just use it right away. + */ + br_i31_encode(x, xlen, t3); + + /* + * The only error conditions remaining at that point are invalid + * values for p and q (even integers). + */ + return p0i & q0i & r; +} + +/* see bearssl_rsa.h */ +br_rsa_private +br_rsa_i62_private_get(void) +{ + return &br_rsa_i62_private; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_private +br_rsa_i62_private_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_i62_pub.c b/src/bearssl/src/rsa/rsa_i62_pub.c new file mode 100644 index 0000000..70cf61b --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_pub.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* + * As a strict minimum, we need four buffers that can hold a + * modular integer. But TLEN is expressed in 64-bit words. + */ +#define TLEN (2 * (2 + ((BR_MAX_RSA_SIZE + 30) / 31))) + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk) +{ + const unsigned char *n; + size_t nlen; + uint64_t tmp[TLEN]; + uint32_t *m, *a; + size_t fwlen; + long z; + uint32_t m0i, r; + + /* + * Get the actual length of the modulus, and see if it fits within + * our stack buffer. We also check that the length of x[] is valid. + */ + n = pk->n; + nlen = pk->nlen; + while (nlen > 0 && *n == 0) { + n ++; + nlen --; + } + if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) { + return 0; + } + z = (long)nlen << 3; + fwlen = 1; + while (z > 0) { + z -= 31; + fwlen ++; + } + /* + * Convert fwlen to a count in 62-bit words. + */ + fwlen = (fwlen + 1) >> 1; + + /* + * The modulus gets decoded into m[]. + * The value to exponentiate goes into a[]. + */ + m = (uint32_t *)tmp; + a = (uint32_t *)(tmp + fwlen); + + /* + * Decode the modulus. + */ + br_i31_decode(m, n, nlen); + m0i = br_i31_ninv31(m[1]); + + /* + * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be + * an odd integer. + */ + r = m0i & 1; + + /* + * Decode x[] into a[]; we also check that its value is proper. + */ + r &= br_i31_decode_mod(a, x, xlen, m); + + /* + * Compute the modular exponentiation. + */ + br_i62_modpow_opt(a, pk->e, pk->elen, m, m0i, + tmp + 2 * fwlen, TLEN - 2 * fwlen); + + /* + * Encode the result. + */ + br_i31_encode(x, xlen, a); + return r; +} + +/* see bearssl_rsa.h */ +br_rsa_public +br_rsa_i62_public_get(void) +{ + return &br_rsa_i62_public; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_public +br_rsa_i62_public_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_oaep_pad.c b/src/bearssl/src/rsa/rsa_oaep_pad.c new file mode 100644 index 0000000..5327dc2 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_oaep_pad.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Hash some data. This is put as a separate function so that stack + * allocation of the hash function context is done only for the duration + * of the hash. + */ +static void +hash_data(const br_hash_class *dig, void *dst, const void *src, size_t len) +{ + br_hash_compat_context hc; + + hc.vtable = dig; + dig->init(&hc.vtable); + dig->update(&hc.vtable, src, len); + dig->out(&hc.vtable, dst); +} + +/* see inner.h */ +size_t +br_rsa_oaep_pad(const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len) +{ + size_t k, hlen; + unsigned char *buf; + + hlen = br_digest_size(dig); + + /* + * Compute actual modulus length (in bytes). + */ + k = pk->nlen; + while (k > 0 && pk->n[k - 1] == 0) { + k --; + } + + /* + * An error is reported if: + * - the modulus is too short; + * - the source message length is too long; + * - the destination buffer is too short. + */ + if (k < ((hlen << 1) + 2) + || src_len > (k - (hlen << 1) - 2) + || dst_max_len < k) + { + return 0; + } + + /* + * Apply padding. At this point, things cannot fail. + */ + buf = dst; + + /* + * Assemble: DB = lHash || PS || 0x01 || M + * We first place the source message M with memmove(), so that + * overlaps between source and destination buffers are supported. + */ + memmove(buf + k - src_len, src, src_len); + hash_data(dig, buf + 1 + hlen, label, label_len); + memset(buf + 1 + (hlen << 1), 0, k - src_len - (hlen << 1) - 2); + buf[k - src_len - 1] = 0x01; + + /* + * Make the random seed. + */ + (*rnd)->generate(rnd, buf + 1, hlen); + + /* + * Mask DB with the mask generated from the seed. + */ + br_mgf1_xor(buf + 1 + hlen, k - hlen - 1, dig, buf + 1, hlen); + + /* + * Mask the seed with the mask generated from the masked DB. + */ + br_mgf1_xor(buf + 1, hlen, dig, buf + 1 + hlen, k - hlen - 1); + + /* + * Padding result: EM = 0x00 || maskedSeed || maskedDB. + */ + buf[0] = 0x00; + return k; +} diff --git a/src/bearssl/src/rsa/rsa_oaep_unpad.c b/src/bearssl/src/rsa/rsa_oaep_unpad.c new file mode 100644 index 0000000..7c4be6a --- /dev/null +++ b/src/bearssl/src/rsa/rsa_oaep_unpad.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Hash some data and XOR the result into the provided buffer. This is put + * as a separate function so that stack allocation of the hash function + * context is done only for the duration of the hash. + */ +static void +xor_hash_data(const br_hash_class *dig, void *dst, const void *src, size_t len) +{ + br_hash_compat_context hc; + unsigned char tmp[64]; + unsigned char *buf; + size_t u, hlen; + + hc.vtable = dig; + dig->init(&hc.vtable); + dig->update(&hc.vtable, src, len); + dig->out(&hc.vtable, tmp); + buf = dst; + hlen = br_digest_size(dig); + for (u = 0; u < hlen; u ++) { + buf[u] ^= tmp[u]; + } +} + +/* see inner.h */ +uint32_t +br_rsa_oaep_unpad(const br_hash_class *dig, + const void *label, size_t label_len, + void *data, size_t *len) +{ + size_t u, k, hlen; + unsigned char *buf; + uint32_t r, s, zlen; + + hlen = br_digest_size(dig); + k = *len; + buf = data; + + /* + * There must be room for the padding. + */ + if (k < ((hlen << 1) + 2)) { + return 0; + } + + /* + * Unmask the seed, then the DB value. + */ + br_mgf1_xor(buf + 1, hlen, dig, buf + 1 + hlen, k - hlen - 1); + br_mgf1_xor(buf + 1 + hlen, k - hlen - 1, dig, buf + 1, hlen); + + /* + * Hash the label and XOR it with the value in the array; if + * they are equal then these should yield only zeros. + */ + xor_hash_data(dig, buf + 1 + hlen, label, label_len); + + /* + * At that point, if the padding was correct, when we should + * have: 0x00 || seed || 0x00 ... 0x00 0x01 || M + * Padding is valid as long as: + * - There is at least hlen+1 leading bytes of value 0x00. + * - There is at least one non-zero byte. + * - The first (leftmost) non-zero byte has value 0x01. + * + * Ultimately, we may leak the resulting message length, i.e. + * the position of the byte of value 0x01, but we must take care + * to do so only if the number of zero bytes has been verified + * to be at least hlen+1. + * + * The loop below counts the number of bytes of value 0x00, and + * checks that the next byte has value 0x01, in constant-time. + * + * - If the initial byte (before the seed) is not 0x00, then + * r and s are set to 0, and stay there. + * - Value r is 1 until the first non-zero byte is reached + * (after the seed); it switches to 0 at that point. + * - Value s is set to 1 if and only if the data encountered + * at the time of the transition of r from 1 to 0 has value + * exactly 0x01. + * - Value zlen counts the number of leading bytes of value zero + * (after the seed). + */ + r = 1 - ((buf[0] + 0xFF) >> 8); + s = 0; + zlen = 0; + for (u = hlen + 1; u < k; u ++) { + uint32_t w, nz; + + w = buf[u]; + + /* + * nz == 1 only for the first non-zero byte. + */ + nz = r & ((w + 0xFF) >> 8); + s |= nz & EQ(w, 0x01); + r &= NOT(nz); + zlen += r; + } + + /* + * Padding is correct only if s == 1, _and_ zlen >= hlen. + */ + s &= GE(zlen, (uint32_t)hlen); + + /* + * At that point, padding was verified, and we are now allowed + * to make conditional jumps. + */ + if (s) { + size_t plen; + + plen = 2 + hlen + zlen; + k -= plen; + memmove(buf, buf + plen, k); + *len = k; + } + return s; +} diff --git a/src/bearssl/src/rsa/rsa_pkcs1_sig_pad.c b/src/bearssl/src/rsa/rsa_pkcs1_sig_pad.c new file mode 100644 index 0000000..06c3bd7 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_pkcs1_sig_pad.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + uint32_t n_bitlen, unsigned char *x) +{ + size_t u, x3, xlen; + + /* + * Padded hash value has format: + * 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH + * + * with the following rules: + * + * -- Total length is equal to the modulus length (unsigned + * encoding). + * + * -- There must be at least eight bytes of value 0xFF. + * + * -- x4 is equal to the hash length (hash_len). + * + * -- x3 is equal to the encoded OID value length (hash_oid[0]). + * + * -- x2 = x3 + 4. + * + * -- x1 = x2 + x4 + 4 = x3 + x4 + 8. + * + * Note: the "05 00" is optional (signatures with and without + * that sequence exist in practice), but notes in PKCS#1 seem to + * indicate that the presence of that sequence (specifically, + * an ASN.1 NULL value for the hash parameters) may be slightly + * more "standard" than the opposite. + */ + xlen = (n_bitlen + 7) >> 3; + + if (hash_oid == NULL) { + if (xlen < hash_len + 11) { + return 0; + } + x[0] = 0x00; + x[1] = 0x01; + u = xlen - hash_len; + memset(x + 2, 0xFF, u - 3); + x[u - 1] = 0x00; + } else { + x3 = hash_oid[0]; + + /* + * Check that there is enough room for all the elements, + * including at least eight bytes of value 0xFF. + */ + if (xlen < (x3 + hash_len + 21)) { + return 0; + } + x[0] = 0x00; + x[1] = 0x01; + u = xlen - x3 - hash_len - 11; + memset(x + 2, 0xFF, u - 2); + x[u] = 0x00; + x[u + 1] = 0x30; + x[u + 2] = x3 + hash_len + 8; + x[u + 3] = 0x30; + x[u + 4] = x3 + 4; + x[u + 5] = 0x06; + memcpy(x + u + 6, hash_oid, x3 + 1); + u += x3 + 7; + x[u ++] = 0x05; + x[u ++] = 0x00; + x[u ++] = 0x04; + x[u ++] = hash_len; + } + memcpy(x + u, hash, hash_len); + return 1; +} diff --git a/src/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c b/src/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c new file mode 100644 index 0000000..c8ae08f --- /dev/null +++ b/src/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len, + const unsigned char *hash_oid, size_t hash_len, + unsigned char *hash_out) +{ + static const unsigned char pad1[] = { + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + unsigned char pad2[43]; + size_t u, x2, x3, pad_len, zlen; + + if (sig_len < 11) { + return 0; + } + + /* + * Expected format: + * 00 01 FF ... FF 00 30 x1 30 x2 06 x3 OID [ 05 00 ] 04 x4 HASH + * + * with the following rules: + * + * -- Total length is that of the modulus and the signature + * (this was already verified by br_rsa_i31_public()). + * + * -- There are at least eight bytes of value 0xFF. + * + * -- x4 is equal to the hash length (hash_len). + * + * -- x3 is equal to the encoded OID value length (so x3 is the + * first byte of hash_oid[]). + * + * -- If the "05 00" is present, then x2 == x3 + 4; otherwise, + * x2 == x3 + 2. + * + * -- x1 == x2 + x4 + 4. + * + * So the total length after the last "FF" is either x3 + x4 + 11 + * (with the "05 00") or x3 + x4 + 9 (without the "05 00"). + */ + + /* + * Check the "00 01 FF .. FF 00" with at least eight 0xFF bytes. + * The comparison is valid because we made sure that the signature + * is at least 11 bytes long. + */ + if (memcmp(sig, pad1, sizeof pad1) != 0) { + return 0; + } + for (u = sizeof pad1; u < sig_len; u ++) { + if (sig[u] != 0xFF) { + break; + } + } + + /* + * Remaining length is sig_len - u bytes (including the 00 just + * after the last FF). This must be equal to one of the two + * possible values (depending on whether the "05 00" sequence is + * present or not). + */ + if (hash_oid == NULL) { + if (sig_len - u != hash_len + 1 || sig[u] != 0x00) { + return 0; + } + } else { + x3 = hash_oid[0]; + pad_len = x3 + 9; + memset(pad2, 0, pad_len); + zlen = sig_len - u - hash_len; + if (zlen == pad_len) { + x2 = x3 + 2; + } else if (zlen == pad_len + 2) { + x2 = x3 + 4; + pad_len = zlen; + pad2[pad_len - 4] = 0x05; + } else { + return 0; + } + pad2[1] = 0x30; + pad2[2] = x2 + hash_len + 4; + pad2[3] = 0x30; + pad2[4] = x2; + pad2[5] = 0x06; + memcpy(pad2 + 6, hash_oid, x3 + 1); + pad2[pad_len - 2] = 0x04; + pad2[pad_len - 1] = hash_len; + if (memcmp(pad2, sig + u, pad_len) != 0) { + return 0; + } + } + memcpy(hash_out, sig + sig_len - hash_len, hash_len); + return 1; +} diff --git a/src/bearssl/src/rsa/rsa_ssl_decrypt.c b/src/bearssl/src/rsa/rsa_ssl_decrypt.c new file mode 100644 index 0000000..047eb18 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_ssl_decrypt.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_ssl_decrypt(br_rsa_private core, const br_rsa_private_key *sk, + unsigned char *data, size_t len) +{ + uint32_t x; + size_t u; + + /* + * A first check on length. Since this test works only on the + * buffer length, it needs not (and cannot) be constant-time. + */ + if (len < 59 || len != (sk->n_bitlen + 7) >> 3) { + return 0; + } + x = core(data, sk); + + x &= EQ(data[0], 0x00); + x &= EQ(data[1], 0x02); + for (u = 2; u < (len - 49); u ++) { + x &= NEQ(data[u], 0); + } + x &= EQ(data[len - 49], 0x00); + memmove(data, data + len - 48, 48); + return x; +} diff --git a/src/bearssl/src/settings.c b/src/bearssl/src/settings.c new file mode 100644 index 0000000..309271c --- /dev/null +++ b/src/bearssl/src/settings.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const br_config_option config[] = { + { "BR_64", +#if BR_64 + 1 +#else + 0 +#endif + }, + { "BR_AES_X86NI", +#if BR_AES_X86NI + 1 +#else + 0 +#endif + }, + { "BR_amd64", +#if BR_amd64 + 1 +#else + 0 +#endif + }, + { "BR_ARMEL_CORTEXM_GCC", +#if BR_ARMEL_CORTEXM_GCC + 1 +#else + 0 +#endif + }, + { "BR_BE_UNALIGNED", +#if BR_BE_UNALIGNED + 1 +#else + 0 +#endif + }, + { "BR_CLANG", +#if BR_CLANG + 1 +#else + 0 +#endif + }, + { "BR_CLANG_3_7", +#if BR_CLANG_3_7 + 1 +#else + 0 +#endif + }, + { "BR_CLANG_3_8", +#if BR_CLANG_3_8 + 1 +#else + 0 +#endif + }, + { "BR_CT_MUL15", +#if BR_CT_MUL15 + 1 +#else + 0 +#endif + }, + { "BR_CT_MUL31", +#if BR_CT_MUL31 + 1 +#else + 0 +#endif + }, + { "BR_GCC", +#if BR_GCC + 1 +#else + 0 +#endif + }, + { "BR_GCC_4_4", +#if BR_GCC_4_4 + 1 +#else + 0 +#endif + }, + { "BR_GCC_4_5", +#if BR_GCC_4_5 + 1 +#else + 0 +#endif + }, + { "BR_GCC_4_6", +#if BR_GCC_4_6 + 1 +#else + 0 +#endif + }, + { "BR_GCC_4_7", +#if BR_GCC_4_7 + 1 +#else + 0 +#endif + }, + { "BR_GCC_4_8", +#if BR_GCC_4_8 + 1 +#else + 0 +#endif + }, + { "BR_GCC_4_9", +#if BR_GCC_4_9 + 1 +#else + 0 +#endif + }, + { "BR_GCC_5_0", +#if BR_GCC_5_0 + 1 +#else + 0 +#endif + }, + { "BR_i386", +#if BR_i386 + 1 +#else + 0 +#endif + }, + { "BR_INT128", +#if BR_INT128 + 1 +#else + 0 +#endif + }, + { "BR_LE_UNALIGNED", +#if BR_LE_UNALIGNED + 1 +#else + 0 +#endif + }, + { "BR_LOMUL", +#if BR_LOMUL + 1 +#else + 0 +#endif + }, + { "BR_MAX_EC_SIZE", BR_MAX_EC_SIZE }, + { "BR_MAX_RSA_SIZE", BR_MAX_RSA_SIZE }, + { "BR_MAX_RSA_FACTOR", BR_MAX_RSA_FACTOR }, + { "BR_MSC", +#if BR_MSC + 1 +#else + 0 +#endif + }, + { "BR_MSC_2005", +#if BR_MSC_2005 + 1 +#else + 0 +#endif + }, + { "BR_MSC_2008", +#if BR_MSC_2008 + 1 +#else + 0 +#endif + }, + { "BR_MSC_2010", +#if BR_MSC_2010 + 1 +#else + 0 +#endif + }, + { "BR_MSC_2012", +#if BR_MSC_2012 + 1 +#else + 0 +#endif + }, + { "BR_MSC_2013", +#if BR_MSC_2013 + 1 +#else + 0 +#endif + }, + { "BR_MSC_2015", +#if BR_MSC_2015 + 1 +#else + 0 +#endif + }, + { "BR_POWER8", +#if BR_POWER8 + 1 +#else + 0 +#endif + }, + { "BR_RDRAND", +#if BR_RDRAND + 1 +#else + 0 +#endif + }, + { "BR_SLOW_MUL", +#if BR_SLOW_MUL + 1 +#else + 0 +#endif + }, + { "BR_SLOW_MUL15", +#if BR_SLOW_MUL15 + 1 +#else + 0 +#endif + }, + { "BR_SSE2", +#if BR_SSE2 + 1 +#else + 0 +#endif + }, + { "BR_UMUL128", +#if BR_UMUL128 + 1 +#else + 0 +#endif + }, + { "BR_USE_UNIX_TIME", +#if BR_USE_UNIX_TIME + 1 +#else + 0 +#endif + }, + { "BR_USE_WIN32_RAND", +#if BR_USE_WIN32_RAND + 1 +#else + 0 +#endif + }, + { "BR_USE_WIN32_TIME", +#if BR_USE_WIN32_TIME + 1 +#else + 0 +#endif + }, + + { NULL, 0 } +}; + +/* see bearssl.h */ +const br_config_option * +br_get_config(void) +{ + return config; +} diff --git a/src/bearssl/src/ssl/prf.c b/src/bearssl/src/ssl/prf.c new file mode 100644 index 0000000..f04a5fb --- /dev/null +++ b/src/bearssl/src/ssl/prf.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_tls_phash(void *dst, size_t len, + const br_hash_class *dig, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed) +{ + unsigned char *buf; + unsigned char tmp[64], a[64]; + br_hmac_key_context kc; + br_hmac_context hc; + size_t label_len, hlen, u; + + if (len == 0) { + return; + } + buf = dst; + for (label_len = 0; label[label_len]; label_len ++); + hlen = br_digest_size(dig); + br_hmac_key_init(&kc, dig, secret, secret_len); + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, label, label_len); + for (u = 0; u < seed_num; u ++) { + br_hmac_update(&hc, seed[u].data, seed[u].len); + } + br_hmac_out(&hc, a); + for (;;) { + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, a, hlen); + br_hmac_update(&hc, label, label_len); + for (u = 0; u < seed_num; u ++) { + br_hmac_update(&hc, seed[u].data, seed[u].len); + } + br_hmac_out(&hc, tmp); + for (u = 0; u < hlen && u < len; u ++) { + buf[u] ^= tmp[u]; + } + buf += u; + len -= u; + if (len == 0) { + return; + } + br_hmac_init(&hc, &kc, 0); + br_hmac_update(&hc, a, hlen); + br_hmac_out(&hc, a); + } +} diff --git a/src/bearssl/src/ssl/prf_md5sha1.c b/src/bearssl/src/ssl/prf_md5sha1.c new file mode 100644 index 0000000..3212833 --- /dev/null +++ b/src/bearssl/src/ssl/prf_md5sha1.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl.h */ +void +br_tls10_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed) +{ + const unsigned char *s1; + size_t slen; + + s1 = secret; + slen = (secret_len + 1) >> 1; + memset(dst, 0, len); + br_tls_phash(dst, len, &br_md5_vtable, + s1, slen, label, seed_num, seed); + br_tls_phash(dst, len, &br_sha1_vtable, + s1 + secret_len - slen, slen, label, seed_num, seed); +} diff --git a/src/bearssl/src/ssl/prf_sha256.c b/src/bearssl/src/ssl/prf_sha256.c new file mode 100644 index 0000000..76041de --- /dev/null +++ b/src/bearssl/src/ssl/prf_sha256.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl.h */ +void +br_tls12_sha256_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed) +{ + memset(dst, 0, len); + br_tls_phash(dst, len, &br_sha256_vtable, + secret, secret_len, label, seed_num, seed); +} diff --git a/src/bearssl/src/ssl/prf_sha384.c b/src/bearssl/src/ssl/prf_sha384.c new file mode 100644 index 0000000..c20c4e6 --- /dev/null +++ b/src/bearssl/src/ssl/prf_sha384.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl.h */ +void +br_tls12_sha384_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed) +{ + memset(dst, 0, len); + br_tls_phash(dst, len, &br_sha384_vtable, + secret, secret_len, label, seed_num, seed); +} diff --git a/src/bearssl/src/ssl/ssl_ccert_single_ec.c b/src/bearssl/src/ssl/ssl_ccert_single_ec.c new file mode 100644 index 0000000..93ebcde --- /dev/null +++ b/src/bearssl/src/ssl/ssl_ccert_single_ec.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static void +cc_none0(const br_ssl_client_certificate_class **pctx) +{ + (void)pctx; +} + +static void +cc_none1(const br_ssl_client_certificate_class **pctx, size_t len) +{ + (void)pctx; + (void)len; +} + +static void +cc_none2(const br_ssl_client_certificate_class **pctx, + const unsigned char *data, size_t len) +{ + (void)pctx; + (void)data; + (void)len; +} + +static void +cc_choose(const br_ssl_client_certificate_class **pctx, + const br_ssl_client_context *cc, uint32_t auth_types, + br_ssl_client_certificate *choices) +{ + br_ssl_client_certificate_ec_context *zc; + int x; + int scurve; + + zc = (br_ssl_client_certificate_ec_context *)pctx; + scurve = br_ssl_client_get_server_curve(cc); + + if ((zc->allowed_usages & BR_KEYTYPE_KEYX) != 0 + && scurve == zc->sk->curve) + { + int x; + + x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17; + if (((auth_types >> x) & 1) != 0) { + choices->auth_type = BR_AUTH_ECDH; + choices->hash_id = -1; + choices->chain = zc->chain; + choices->chain_len = zc->chain_len; + } + } + + /* + * For ECDSA authentication, we must choose an appropriate + * hash function. + */ + x = br_ssl_choose_hash((unsigned)(auth_types >> 8)); + if (x == 0 || (zc->allowed_usages & BR_KEYTYPE_SIGN) == 0) { + memset(choices, 0, sizeof *choices); + return; + } + choices->auth_type = BR_AUTH_ECDSA; + choices->hash_id = x; + choices->chain = zc->chain; + choices->chain_len = zc->chain_len; +} + +static uint32_t +cc_do_keyx(const br_ssl_client_certificate_class **pctx, + unsigned char *data, size_t *len) +{ + br_ssl_client_certificate_ec_context *zc; + uint32_t r; + size_t xoff, xlen; + + zc = (br_ssl_client_certificate_ec_context *)pctx; + r = zc->iec->mul(data, *len, zc->sk->x, zc->sk->xlen, zc->sk->curve); + xoff = zc->iec->xoff(zc->sk->curve, &xlen); + memmove(data, data + xoff, xlen); + *len = xlen; + return r; +} + +static size_t +cc_do_sign(const br_ssl_client_certificate_class **pctx, + int hash_id, size_t hv_len, unsigned char *data, size_t len) +{ + br_ssl_client_certificate_ec_context *zc; + unsigned char hv[64]; + const br_hash_class *hc; + + zc = (br_ssl_client_certificate_ec_context *)pctx; + memcpy(hv, data, hv_len); + hc = br_multihash_getimpl(zc->mhash, hash_id); + if (hc == NULL) { + return 0; + } + if (len < 139) { + return 0; + } + return zc->iecdsa(zc->iec, hc, hv, zc->sk, data); +} + +static const br_ssl_client_certificate_class ccert_vtable = { + sizeof(br_ssl_client_certificate_ec_context), + cc_none0, /* start_name_list */ + cc_none1, /* start_name */ + cc_none2, /* append_name */ + cc_none0, /* end_name */ + cc_none0, /* end_name_list */ + cc_choose, + cc_do_keyx, + cc_do_sign +}; + +/* see bearssl_ssl.h */ +void +br_ssl_client_set_single_ec(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk, unsigned allowed_usages, + unsigned cert_issuer_key_type, + const br_ec_impl *iec, br_ecdsa_sign iecdsa) +{ + cc->client_auth.single_ec.vtable = &ccert_vtable; + cc->client_auth.single_ec.chain = chain; + cc->client_auth.single_ec.chain_len = chain_len; + cc->client_auth.single_ec.sk = sk; + cc->client_auth.single_ec.allowed_usages = allowed_usages; + cc->client_auth.single_ec.issuer_key_type = cert_issuer_key_type; + cc->client_auth.single_ec.mhash = &cc->eng.mhash; + cc->client_auth.single_ec.iec = iec; + cc->client_auth.single_ec.iecdsa = iecdsa; + cc->client_auth_vtable = &cc->client_auth.single_ec.vtable; +} diff --git a/src/bearssl/src/ssl/ssl_ccert_single_rsa.c b/src/bearssl/src/ssl/ssl_ccert_single_rsa.c new file mode 100644 index 0000000..690df20 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_ccert_single_rsa.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static void +cc_none0(const br_ssl_client_certificate_class **pctx) +{ + (void)pctx; +} + +static void +cc_none1(const br_ssl_client_certificate_class **pctx, size_t len) +{ + (void)pctx; + (void)len; +} + +static void +cc_none2(const br_ssl_client_certificate_class **pctx, + const unsigned char *data, size_t len) +{ + (void)pctx; + (void)data; + (void)len; +} + +static void +cc_choose(const br_ssl_client_certificate_class **pctx, + const br_ssl_client_context *cc, uint32_t auth_types, + br_ssl_client_certificate *choices) +{ + br_ssl_client_certificate_rsa_context *zc; + int x; + + (void)cc; + zc = (br_ssl_client_certificate_rsa_context *)pctx; + x = br_ssl_choose_hash((unsigned)auth_types); + if (x == 0 && (auth_types & 1) == 0) { + memset(choices, 0, sizeof *choices); + } + choices->auth_type = BR_AUTH_RSA; + choices->hash_id = x; + choices->chain = zc->chain; + choices->chain_len = zc->chain_len; +} + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char HASH_OID_SHA1[] = { + 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char HASH_OID_SHA224[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char HASH_OID_SHA256[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char HASH_OID_SHA384[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char HASH_OID_SHA512[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const unsigned char *HASH_OID[] = { + HASH_OID_SHA1, + HASH_OID_SHA224, + HASH_OID_SHA256, + HASH_OID_SHA384, + HASH_OID_SHA512 +}; + +static size_t +cc_do_sign(const br_ssl_client_certificate_class **pctx, + int hash_id, size_t hv_len, unsigned char *data, size_t len) +{ + br_ssl_client_certificate_rsa_context *zc; + unsigned char hv[64]; + const unsigned char *hash_oid; + size_t sig_len; + + zc = (br_ssl_client_certificate_rsa_context *)pctx; + memcpy(hv, data, hv_len); + if (hash_id == 0) { + hash_oid = NULL; + } else if (hash_id >= 2 && hash_id <= 6) { + hash_oid = HASH_OID[hash_id - 2]; + } else { + return 0; + } + sig_len = (zc->sk->n_bitlen + 7) >> 3; + if (len < sig_len) { + return 0; + } + return zc->irsasign(hash_oid, hv, hv_len, zc->sk, data) ? sig_len : 0; +} + +static const br_ssl_client_certificate_class ccert_vtable = { + sizeof(br_ssl_client_certificate_rsa_context), + cc_none0, /* start_name_list */ + cc_none1, /* start_name */ + cc_none2, /* append_name */ + cc_none0, /* end_name */ + cc_none0, /* end_name_list */ + cc_choose, + 0, + cc_do_sign +}; + +/* see bearssl_ssl.h */ +void +br_ssl_client_set_single_rsa(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign) +{ + cc->client_auth.single_rsa.vtable = &ccert_vtable; + cc->client_auth.single_rsa.chain = chain; + cc->client_auth.single_rsa.chain_len = chain_len; + cc->client_auth.single_rsa.sk = sk; + cc->client_auth.single_rsa.irsasign = irsasign; + cc->client_auth_vtable = &cc->client_auth.single_rsa.vtable; +} diff --git a/src/bearssl/src/ssl/ssl_client.c b/src/bearssl/src/ssl/ssl_client.c new file mode 100644 index 0000000..28c404b --- /dev/null +++ b/src/bearssl/src/ssl/ssl_client.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_client_zero(br_ssl_client_context *cc) +{ + /* + * For really standard C, we should explicitly set to NULL all + * pointers, and 0 all other fields. However, on all our target + * architectures, a direct memset() will work, be faster, and + * use a lot less code. + */ + memset(cc, 0, sizeof *cc); +} + +/* see bearssl_ssl.h */ +int +br_ssl_client_reset(br_ssl_client_context *cc, + const char *server_name, int resume_session) +{ + size_t n; + + br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0); + cc->eng.version_out = cc->eng.version_min; + if (!resume_session) { + br_ssl_client_forget_session(cc); + } + if (!br_ssl_engine_init_rand(&cc->eng)) { + return 0; + } + + /* + * We always set back the "reneg" flag to 0 because we use it + * to distinguish between first handshake and renegotiation. + * Note that "renegotiation" and "session resumption" are two + * different things. + */ + cc->eng.reneg = 0; + + if (server_name == NULL) { + cc->eng.server_name[0] = 0; + } else { + n = strlen(server_name) + 1; + if (n > sizeof cc->eng.server_name) { + br_ssl_engine_fail(&cc->eng, BR_ERR_BAD_PARAM); + return 0; + } + memcpy(cc->eng.server_name, server_name, n); + } + + br_ssl_engine_hs_reset(&cc->eng, + br_ssl_hs_client_init_main, br_ssl_hs_client_run); + return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK; +} diff --git a/src/bearssl/src/ssl/ssl_client_default_rsapub.c b/src/bearssl/src/ssl/ssl_client_default_rsapub.c new file mode 100644 index 0000000..2cdaab8 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_client_default_rsapub.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_client_set_default_rsapub(br_ssl_client_context *cc) +{ + br_ssl_client_set_rsapub(cc, br_rsa_public_get_default()); +} diff --git a/src/bearssl/src/ssl/ssl_client_full.c b/src/bearssl/src/ssl/ssl_client_full.c new file mode 100644 index 0000000..9814349 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_client_full.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_client_init_full(br_ssl_client_context *cc, + br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) +{ + /* + * The "full" profile supports all implemented cipher suites. + * + * Rationale for suite order, from most important to least + * important rule: + * + * -- Don't use 3DES if AES or ChaCha20 is available. + * -- Try to have Forward Secrecy (ECDHE suite) if possible. + * -- When not using Forward Secrecy, ECDH key exchange is + * better than RSA key exchange (slightly more expensive on the + * client, but much cheaper on the server, and it implies smaller + * messages). + * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller code). + * -- GCM is better than CCM and CBC. CCM is better than CBC. + * -- CCM is preferable over CCM_8 (with CCM_8, forgeries may succeed + * with probability 2^(-64)). + * -- AES-128 is preferred over AES-256 (AES-128 is already + * strong enough, and AES-256 is 40% more expensive). + */ + static const uint16_t suites[] = { + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_RSA_WITH_AES_128_CCM, + BR_TLS_RSA_WITH_AES_256_CCM, + BR_TLS_RSA_WITH_AES_128_CCM_8, + BR_TLS_RSA_WITH_AES_256_CCM_8, + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA + }; + + /* + * All hash functions are activated. + * Note: the X.509 validation engine will nonetheless refuse to + * validate signatures that use MD5 as hash function. + */ + static const br_hash_class *hashes[] = { + &br_md5_vtable, + &br_sha1_vtable, + &br_sha224_vtable, + &br_sha256_vtable, + &br_sha384_vtable, + &br_sha512_vtable + }; + + int id; + + /* + * Reset client context and set supported versions from TLS-1.0 + * to TLS-1.2 (inclusive). + */ + br_ssl_client_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); + + /* + * X.509 engine uses SHA-256 to hash certificate DN (for + * comparisons). + */ + br_x509_minimal_init(xc, &br_sha256_vtable, + trust_anchors, trust_anchors_num); + + /* + * Set suites and asymmetric crypto implementations. We use the + * "i31" code for RSA (it is somewhat faster than the "i32" + * implementation). + * TODO: change that when better implementations are made available. + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + br_ssl_client_set_default_rsapub(cc); + br_ssl_engine_set_default_rsavrfy(&cc->eng); + br_ssl_engine_set_default_ecdsa(&cc->eng); + br_x509_minimal_set_rsa(xc, br_ssl_engine_get_rsavrfy(&cc->eng)); + br_x509_minimal_set_ecdsa(xc, + br_ssl_engine_get_ec(&cc->eng), + br_ssl_engine_get_ecdsa(&cc->eng)); + + /* + * Set supported hash functions, for the SSL engine and for the + * X.509 engine. + */ + for (id = br_md5_ID; id <= br_sha512_ID; id ++) { + const br_hash_class *hc; + + hc = hashes[id - 1]; + br_ssl_engine_set_hash(&cc->eng, id, hc); + br_x509_minimal_set_hash(xc, id, hc); + } + + /* + * Link the X.509 engine in the SSL engine. + */ + br_ssl_engine_set_x509(&cc->eng, &xc->vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + + /* + * Symmetric encryption. We use the "default" implementations + * (fastest among constant-time implementations). + */ + br_ssl_engine_set_default_aes_cbc(&cc->eng); + br_ssl_engine_set_default_aes_ccm(&cc->eng); + br_ssl_engine_set_default_aes_gcm(&cc->eng); + br_ssl_engine_set_default_des_cbc(&cc->eng); + br_ssl_engine_set_default_chapol(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_engine.c b/src/bearssl/src/ssl/ssl_engine.c new file mode 100644 index 0000000..f4ffe18 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine.c @@ -0,0 +1,1569 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if 0 +/* obsolete */ + +/* + * If BR_USE_URANDOM is not defined, then try to autodetect its presence + * through compiler macros. + */ +#ifndef BR_USE_URANDOM + +/* + * Macro values documented on: + * https://sourceforge.net/p/predef/wiki/OperatingSystems/ + * + * Only the most common systems have been included here for now. This + * should be enriched later on. + */ +#if defined _AIX \ + || defined __ANDROID__ \ + || defined __FreeBSD__ \ + || defined __NetBSD__ \ + || defined __OpenBSD__ \ + || defined __DragonFly__ \ + || defined __linux__ \ + || (defined __sun && (defined __SVR4 || defined __svr4__)) \ + || (defined __APPLE__ && defined __MACH__) +#define BR_USE_URANDOM 1 +#endif + +#endif + +/* + * If BR_USE_WIN32_RAND is not defined, perform autodetection here. + */ +#ifndef BR_USE_WIN32_RAND + +#if defined _WIN32 || defined _WIN64 +#define BR_USE_WIN32_RAND 1 +#endif + +#endif + +#if BR_USE_URANDOM +#include +#include +#include +#include +#endif + +#if BR_USE_WIN32_RAND +#include +#include +#pragma comment(lib, "advapi32") +#endif + +#endif + +/* ==================================================================== */ +/* + * This part of the file does the low-level record management. + */ + +/* + * IMPLEMENTATION NOTES + * ==================== + * + * In this file, we designate by "input" (and the "i" letter) the "recv" + * operations: incoming records from the peer, from which payload data + * is obtained, and must be extracted by the application (or the SSL + * handshake engine). Similarly, "output" (and the "o" letter) is for + * "send": payload data injected by the application (and SSL handshake + * engine), to be wrapped into records, that are then conveyed to the + * peer over the transport medium. + * + * The input and output buffers may be distinct or shared. When + * shared, input and output cannot occur concurrently; the caller + * must make sure that it never needs to output data while input + * data has been received. In practice, a shared buffer prevents + * pipelining of HTTP requests, or similar protocols; however, a + * shared buffer saves RAM. + * + * The input buffer is pointed to by 'ibuf' and has size 'ibuf_len'; + * the output buffer is pointed to by 'obuf' and has size 'obuf_len'. + * From the size of these buffers is derived the maximum fragment + * length, which will be honoured upon sending records; regardless of + * that length, incoming records will be processed as long as they + * fit in the input buffer, and their length still complies with the + * protocol specification (maximum plaintext payload length is 16384 + * bytes). + * + * Three registers are used to manage buffering in ibuf, called ixa, + * ixb and ixc. Similarly, three registers are used to manage buffering + * in obuf, called oxa, oxb and oxc. + * + * + * At any time, the engine is in one of the following modes: + * -- Failed mode: an error occurs, no I/O can happen. + * -- Input mode: the engine can either receive record bytes from the + * transport layer, or it has some buffered payload bytes to yield. + * -- Output mode: the engine can either receive payload bytes, or it + * has some record bytes to send to the transport layer. + * -- Input/Output mode: both input and output modes are active. When + * the buffer is shared, this can happen only when the buffer is empty + * (no buffered payload bytes or record bytes in either direction). + * + * + * Failed mode: + * ------------ + * + * I/O failed for some reason (invalid received data, not enough room + * for the next record...). No I/O may ever occur again for this context, + * until an explicit reset is performed. This mode, and the error code, + * are also used for protocol errors, especially handshake errors. + * + * + * Input mode: + * ----------- + * + * ixa index within ibuf[] for the currently read data + * ixb maximum index within ibuf[] for the currently read data + * ixc number of bytes not yet received for the current record + * + * -- When ixa == ixb, there is no available data for readers. When + * ixa != ixb, there is available data and it starts at offset ixa. + * + * -- When waiting for the next record header, ixa and ixb are equal + * and contain a value ranging from 0 to 4; ixc is equal to 5-ixa. + * + * -- When the header has been received, record data is obtained. The + * ixc field records how many bytes are still needed to reach the + * end of the current record. + * + * ** If encryption is active, then ixa and ixb are kept equal, and + * point to the end of the currently received record bytes. When + * ixc reaches 0, decryption/MAC is applied, and ixa and ixb are + * adjusted. + * + * ** If encryption is not active, then ixa and ixb are distinct + * and data can be read right away. Additional record data is + * obtained only when ixa == ixb. + * + * Note: in input mode and no encryption, records larger than the buffer + * size are allowed. When encryption is active, the complete record must + * fit within the buffer, since it cannot be decrypted/MACed until it + * has been completely received. + * + * -- When receiving the next record header, 'version_in' contains the + * expected input version (0 if not expecting a specific version); on + * mismatch, the mode switches to 'failed'. + * + * -- When the header has been received, 'version_in' contains the received + * version. It is up to the caller to check and adjust the 'version_in' field + * to implement the required semantics. + * + * -- The 'record_type_in' field is updated with the incoming record type + * when the next record header has been received. + * + * + * Output mode: + * ------------ + * + * oxa index within obuf[] for the currently accumulated data + * oxb maximum index within obuf[] for record data + * oxc pointer for start of record data, and for record sending + * + * -- When oxa != oxb, more data can be accumulated into the current + * record; when oxa == oxb, a closed record is being sent. + * + * -- When accumulating data, oxc points to the start of the data. + * + * -- During record sending, oxa (and oxb) point to the next record byte + * to send, and oxc indicates the end of the current record. + * + * Note: sent records must fit within the buffer, since the header is + * adjusted only when the complete record has been assembled. + * + * -- The 'version_out' and 'record_type_out' fields are used to build the + * record header when the mode is switched to 'sending'. + * + * + * Modes: + * ------ + * + * The state register iomode contains one of the following values: + * + * BR_IO_FAILED I/O failed + * BR_IO_IN input mode + * BR_IO_OUT output mode + * BR_IO_INOUT input/output mode + * + * Whether encryption is active on incoming records is indicated by the + * incrypt flag. For outgoing records, there is no such flag; "encryption" + * is always considered active, but initially uses functions that do not + * encrypt anything. The 'incrypt' flag is needed because when there is + * no active encryption, records larger than the I/O buffer are accepted. + * + * Note: we do not support no-encryption modes (MAC only). + * + * TODO: implement GCM support + * + * + * Misc: + * ----- + * + * 'max_frag_len' is the maximum plaintext size for an outgoing record. + * By default, it is set to the maximum value that fits in the provided + * buffers, in the following list: 512, 1024, 2048, 4096, 16384. The + * caller may change it if needed, but the new value MUST still fit in + * the buffers, and it MUST be one of the list above for compatibility + * with the Maximum Fragment Length extension. + * + * For incoming records, only the total buffer length and current + * encryption mode impact the maximum length for incoming records. The + * 'max_frag_len' value is still adjusted so that records up to that + * length can be both received and sent. + * + * + * Offsets and lengths: + * -------------------- + * + * When sending fragments with TLS-1.1+, the maximum overhead is: + * 5 bytes for the record header + * 16 bytes for the explicit IV + * 48 bytes for the MAC (HMAC/SHA-384) + * 16 bytes for the padding (AES) + * so a total of 85 extra bytes. Note that we support block cipher sizes + * up to 16 bytes (AES) and HMAC output sizes up to 48 bytes (SHA-384). + * + * With TLS-1.0 and CBC mode, we apply a 1/n-1 split, for a maximum + * overhead of: + * 5 bytes for the first record header + * 32 bytes for the first record payload (AES-CBC + HMAC/SHA-1) + * 5 bytes for the second record header + * 20 bytes for the MAC (HMAC/SHA-1) + * 16 bytes for the padding (AES) + * -1 byte to account for the payload byte in the first record + * so a total of 77 extra bytes at most, less than the 85 bytes above. + * Note that with TLS-1.0, the MAC is HMAC with either MD5 or SHA-1, but + * no other hash function. + * + * The implementation does not try to send larger records when the current + * encryption mode has less overhead. + * + * Maximum input record overhead is: + * 5 bytes for the record header + * 16 bytes for the explicit IV (TLS-1.1+) + * 48 bytes for the MAC (HMAC/SHA-384) + * 256 bytes for the padding + * so a total of 325 extra bytes. + * + * When receiving the next record header, it is written into the buffer + * bytes 0 to 4 (inclusive). Record data is always written into buf[] + * starting at offset 5. When encryption is active, the plaintext data + * may start at a larger offset (e.g. because of an explicit IV). + */ + +#define MAX_OUT_OVERHEAD 85 +#define MAX_IN_OVERHEAD 325 + +/* see inner.h */ +void +br_ssl_engine_fail(br_ssl_engine_context *rc, int err) +{ + if (rc->iomode != BR_IO_FAILED) { + rc->iomode = BR_IO_FAILED; + rc->err = err; + } +} + +/* + * Adjust registers for a new incoming record. + */ +static void +make_ready_in(br_ssl_engine_context *rc) +{ + rc->ixa = rc->ixb = 0; + rc->ixc = 5; + if (rc->iomode == BR_IO_IN) { + rc->iomode = BR_IO_INOUT; + } +} + +/* + * Adjust registers for a new outgoing record. + */ +static void +make_ready_out(br_ssl_engine_context *rc) +{ + size_t a, b; + + a = 5; + b = rc->obuf_len - a; + rc->out.vtable->max_plaintext(&rc->out.vtable, &a, &b); + if ((b - a) > rc->max_frag_len) { + b = a + rc->max_frag_len; + } + rc->oxa = a; + rc->oxb = b; + rc->oxc = a; + if (rc->iomode == BR_IO_OUT) { + rc->iomode = BR_IO_INOUT; + } +} + +/* see inner.h */ +void +br_ssl_engine_new_max_frag_len(br_ssl_engine_context *rc, unsigned max_frag_len) +{ + size_t nxb; + + rc->max_frag_len = max_frag_len; + nxb = rc->oxc + max_frag_len; + if (rc->oxa < rc->oxb && rc->oxb > nxb && rc->oxa < nxb) { + rc->oxb = nxb; + } +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_buffer(br_ssl_engine_context *rc, + void *buf, size_t buf_len, int bidi) +{ + if (buf == NULL) { + br_ssl_engine_set_buffers_bidi(rc, NULL, 0, NULL, 0); + } else { + /* + * In bidirectional mode, we want to maximise input + * buffer size, since we support arbitrary fragmentation + * when sending, but the peer will not necessarily + * comply to any low fragment length (in particular if + * we are the server, because the maximum fragment + * length extension is under client control). + * + * We keep a minimum size of 512 bytes for the plaintext + * of our outgoing records. + * + * br_ssl_engine_set_buffers_bidi() will compute the maximum + * fragment length for outgoing records by using the minimum + * of allocated spaces for both input and output records, + * rounded down to a standard length. + */ + if (bidi) { + size_t w; + + if (buf_len < (512 + MAX_IN_OVERHEAD + + 512 + MAX_OUT_OVERHEAD)) + { + rc->iomode = BR_IO_FAILED; + rc->err = BR_ERR_BAD_PARAM; + return; + } else if (buf_len < (16384 + MAX_IN_OVERHEAD + + 512 + MAX_OUT_OVERHEAD)) + { + w = 512 + MAX_OUT_OVERHEAD; + } else { + w = buf_len - (16384 + MAX_IN_OVERHEAD); + } + br_ssl_engine_set_buffers_bidi(rc, + buf, buf_len - w, + (unsigned char *)buf + w, w); + } else { + br_ssl_engine_set_buffers_bidi(rc, + buf, buf_len, NULL, 0); + } + } +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *rc, + void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len) +{ + rc->iomode = BR_IO_INOUT; + rc->incrypt = 0; + rc->err = BR_ERR_OK; + rc->version_in = 0; + rc->record_type_in = 0; + rc->version_out = 0; + rc->record_type_out = 0; + if (ibuf == NULL) { + if (rc->ibuf == NULL) { + br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM); + } + } else { + unsigned u; + + rc->ibuf = ibuf; + rc->ibuf_len = ibuf_len; + if (obuf == NULL) { + obuf = ibuf; + obuf_len = ibuf_len; + } + rc->obuf = obuf; + rc->obuf_len = obuf_len; + + /* + * Compute the maximum fragment length, that fits for + * both incoming and outgoing records. This length will + * be used in fragment length negotiation, so we must + * honour it both ways. Regardless, larger incoming + * records will be accepted, as long as they fit in the + * actual buffer size. + */ + for (u = 14; u >= 9; u --) { + size_t flen; + + flen = (size_t)1 << u; + if (obuf_len >= flen + MAX_OUT_OVERHEAD + && ibuf_len >= flen + MAX_IN_OVERHEAD) + { + break; + } + } + if (u == 8) { + br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM); + return; + } else if (u == 13) { + u = 12; + } + rc->max_frag_len = (size_t)1 << u; + rc->log_max_frag_len = u; + rc->peer_log_max_frag_len = 0; + } + rc->out.vtable = &br_sslrec_out_clear_vtable; + make_ready_in(rc); + make_ready_out(rc); +} + +/* + * Clear buffers in both directions. + */ +static void +engine_clearbuf(br_ssl_engine_context *rc) +{ + make_ready_in(rc); + make_ready_out(rc); +} + +/* + * Make sure the internal PRNG is initialised (but not necessarily + * seeded properly yet). + */ +static int +rng_init(br_ssl_engine_context *cc) +{ + const br_hash_class *h; + + if (cc->rng_init_done != 0) { + return 1; + } + + /* + * If using TLS-1.2, then SHA-256 or SHA-384 must be present (or + * both); we prefer SHA-256 which is faster for 32-bit systems. + * + * If using TLS-1.0 or 1.1 then SHA-1 must be present. + * + * Though HMAC_DRBG/SHA-1 is, as far as we know, as safe as + * these things can be, we still prefer the SHA-2 functions over + * SHA-1, if only for public relations (known theoretical + * weaknesses of SHA-1 with regards to collisions are mostly + * irrelevant here, but they still make people nervous). + */ + h = br_multihash_getimpl(&cc->mhash, br_sha256_ID); + if (!h) { + h = br_multihash_getimpl(&cc->mhash, br_sha384_ID); + if (!h) { + h = br_multihash_getimpl(&cc->mhash, + br_sha1_ID); + if (!h) { + br_ssl_engine_fail(cc, BR_ERR_BAD_STATE); + return 0; + } + } + } + br_hmac_drbg_init(&cc->rng, h, NULL, 0); + cc->rng_init_done = 1; + return 1; +} + +/* see inner.h */ +int +br_ssl_engine_init_rand(br_ssl_engine_context *cc) +{ + if (!rng_init(cc)) { + return 0; + } + + /* + * We always try OS/hardware seeding once. If it works, then + * we assume proper seeding. If not, then external entropy must + * have been injected; otherwise, we report an error. + */ + if (!cc->rng_os_rand_done) { + br_prng_seeder sd; + + sd = br_prng_seeder_system(NULL); + if (sd != 0 && sd(&cc->rng.vtable)) { + cc->rng_init_done = 2; + } + cc->rng_os_rand_done = 1; + } + if (cc->rng_init_done < 2) { + br_ssl_engine_fail(cc, BR_ERR_NO_RANDOM); + return 0; + } + return 1; +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_inject_entropy(br_ssl_engine_context *cc, + const void *data, size_t len) +{ + /* + * Externally provided entropy is assumed to be "good enough" + * (we cannot really test its quality) so if the RNG structure + * could be initialised at all, then we marked the RNG as + * "properly seeded". + */ + if (!rng_init(cc)) { + return; + } + br_hmac_drbg_update(&cc->rng, data, len); + cc->rng_init_done = 2; +} + +/* + * We define a few internal functions that implement the low-level engine + * API for I/O; the external API (br_ssl_engine_sendapp_buf() and similar + * functions) is built upon these function, with special processing for + * records which are not of type "application data". + * + * recvrec_buf, recvrec_ack receives bytes from transport medium + * sendrec_buf, sendrec_ack send bytes to transport medium + * recvpld_buf, recvpld_ack receives payload data from engine + * sendpld_buf, sendpld_ack send payload data to engine + */ + +static unsigned char * +recvrec_buf(const br_ssl_engine_context *rc, size_t *len) +{ + if (rc->shutdown_recv) { + *len = 0; + return NULL; + } + + /* + * Bytes from the transport can be injected only if the mode is + * compatible (in or in/out), and ixa == ixb; ixc then contains + * the number of bytes that are still expected (but it may + * exceed our buffer size). + * + * We cannot get "stuck" here (buffer is full, but still more + * data is expected) because oversized records are detected when + * their header is processed. + */ + switch (rc->iomode) { + case BR_IO_IN: + case BR_IO_INOUT: + if (rc->ixa == rc->ixb) { + size_t z; + + z = rc->ixc; + if (z > rc->ibuf_len - rc->ixa) { + z = rc->ibuf_len - rc->ixa; + } + *len = z; + return rc->ibuf + rc->ixa; + } + break; + } + *len = 0; + return NULL; +} + +static void +recvrec_ack(br_ssl_engine_context *rc, size_t len) +{ + unsigned char *pbuf; + size_t pbuf_len; + + /* + * Adjust state if necessary (for a shared input/output buffer): + * we got some incoming bytes, so we cannot (temporarily) handle + * outgoing data. + */ + if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) { + rc->iomode = BR_IO_IN; + } + + /* + * Adjust data pointers. + */ + rc->ixb = (rc->ixa += len); + rc->ixc -= len; + + /* + * If we are receiving a header and did not fully obtained it + * yet, then just wait for the next bytes. + */ + if (rc->ixa < 5) { + return; + } + + /* + * If we just obtained a full header, process it. + */ + if (rc->ixa == 5) { + unsigned version; + unsigned rlen; + + /* + * Get record type and version. We support only versions + * 3.x (if the version major number does not match, then + * we suppose that the record format is too alien for us + * to process it). + * + * Note: right now, we reject clients that try to send + * a ClientHello in a format compatible with SSL-2.0. It + * is unclear whether this will ever be supported; and + * if we want to support it, then this might be done in + * in the server-specific code, not here. + */ + rc->record_type_in = rc->ibuf[0]; + version = br_dec16be(rc->ibuf + 1); + if ((version >> 8) != 3) { + br_ssl_engine_fail(rc, BR_ERR_UNSUPPORTED_VERSION); + return; + } + + /* + * We ensure that successive records have the same + * version. The handshake code must check and adjust the + * variables when necessary to accommodate the protocol + * negotiation details. + */ + if (rc->version_in != 0 && rc->version_in != version) { + br_ssl_engine_fail(rc, BR_ERR_BAD_VERSION); + return; + } + rc->version_in = version; + + /* + * Decode record length. We must check that the length + * is valid (relatively to the current encryption mode) + * and also (if encryption is active) that the record + * will fit in our buffer. + * + * When no encryption is active, we can process records + * by chunks, and thus accept any record up to the + * maximum allowed plaintext length (16384 bytes). + */ + rlen = br_dec16be(rc->ibuf + 3); + if (rc->incrypt) { + if (!rc->in.vtable->check_length( + &rc->in.vtable, rlen)) + { + br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH); + return; + } + if (rlen > (rc->ibuf_len - 5)) { + br_ssl_engine_fail(rc, BR_ERR_TOO_LARGE); + return; + } + } else { + if (rlen > 16384) { + br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH); + return; + } + } + + /* + * If the record is completely empty then we must switch + * to a new record. Note that, in that case, we + * completely ignore the record type, which is fitting + * since we received no actual data of that type. + * + * A completely empty record is technically allowed as + * long as encryption/MAC is not active, i.e. before + * completion of the first handshake. It it still weird; + * it might conceptually be useful as a heartbeat or + * keep-alive mechanism while some lengthy operation is + * going on, e.g. interaction with a human user. + */ + if (rlen == 0) { + make_ready_in(rc); + } else { + rc->ixa = rc->ixb = 5; + rc->ixc = rlen; + } + return; + } + + /* + * If there is no active encryption, then the data can be read + * right away. Note that we do not receive bytes from the + * transport medium when we still have payload bytes to be + * acknowledged. + */ + if (!rc->incrypt) { + rc->ixa = 5; + return; + } + + /* + * Since encryption is active, we must wait for a full record + * before processing it. + */ + if (rc->ixc != 0) { + return; + } + + /* + * We got the full record. Decrypt it. + */ + pbuf_len = rc->ixa - 5; + pbuf = rc->in.vtable->decrypt(&rc->in.vtable, + rc->record_type_in, rc->version_in, rc->ibuf + 5, &pbuf_len); + if (pbuf == 0) { + br_ssl_engine_fail(rc, BR_ERR_BAD_MAC); + return; + } + rc->ixa = (size_t)(pbuf - rc->ibuf); + rc->ixb = rc->ixa + pbuf_len; + + /* + * Decryption may have yielded an empty record, in which case + * we get back to "ready" state immediately. + */ + if (rc->ixa == rc->ixb) { + make_ready_in(rc); + } +} + +/* see inner.h */ +int +br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc) +{ + switch (rc->iomode) { + case BR_IO_IN: + case BR_IO_INOUT: + return rc->ixc == 0 || rc->ixa < 5; + default: + return 1; + } +} + +static unsigned char * +recvpld_buf(const br_ssl_engine_context *rc, size_t *len) +{ + /* + * There is payload data to be read only if the mode is + * compatible, and ixa != ixb. + */ + switch (rc->iomode) { + case BR_IO_IN: + case BR_IO_INOUT: + *len = rc->ixb - rc->ixa; + return (*len == 0) ? NULL : (rc->ibuf + rc->ixa); + default: + *len = 0; + return NULL; + } +} + +static void +recvpld_ack(br_ssl_engine_context *rc, size_t len) +{ + rc->ixa += len; + + /* + * If we read all the available data, then we either expect + * the remainder of the current record (if the current record + * was not finished; this may happen when encryption is not + * active), or go to "ready" state. + */ + if (rc->ixa == rc->ixb) { + if (rc->ixc == 0) { + make_ready_in(rc); + } else { + rc->ixa = rc->ixb = 5; + } + } +} + +static unsigned char * +sendpld_buf(const br_ssl_engine_context *rc, size_t *len) +{ + /* + * Payload data can be injected only if the current mode is + * compatible, and oxa != oxb. + */ + switch (rc->iomode) { + case BR_IO_OUT: + case BR_IO_INOUT: + *len = rc->oxb - rc->oxa; + return (*len == 0) ? NULL : (rc->obuf + rc->oxa); + default: + *len = 0; + return NULL; + } +} + +/* + * If some payload bytes have been accumulated, then wrap them into + * an outgoing record. Otherwise, this function does nothing, unless + * 'force' is non-zero, in which case an empty record is assembled. + * + * The caller must take care not to invoke this function if the engine + * is not currently ready to receive payload bytes to send. + */ +static void +sendpld_flush(br_ssl_engine_context *rc, int force) +{ + size_t xlen; + unsigned char *buf; + + if (rc->oxa == rc->oxb) { + return; + } + xlen = rc->oxa - rc->oxc; + if (xlen == 0 && !force) { + return; + } + buf = rc->out.vtable->encrypt(&rc->out.vtable, + rc->record_type_out, rc->version_out, + rc->obuf + rc->oxc, &xlen); + rc->oxb = rc->oxa = (size_t)(buf - rc->obuf); + rc->oxc = rc->oxa + xlen; +} + +static void +sendpld_ack(br_ssl_engine_context *rc, size_t len) +{ + /* + * If using a shared buffer, then we may have to modify the + * current mode. + */ + if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) { + rc->iomode = BR_IO_OUT; + } + rc->oxa += len; + if (rc->oxa >= rc->oxb) { + /* + * Set oxb to one more than oxa so that sendpld_flush() + * does not mistakingly believe that a record is + * already prepared and being sent. + */ + rc->oxb = rc->oxa + 1; + sendpld_flush(rc, 0); + } +} + +static unsigned char * +sendrec_buf(const br_ssl_engine_context *rc, size_t *len) +{ + /* + * When still gathering payload bytes, oxc points to the start + * of the record data, so oxc <= oxa. However, when a full + * record has been completed, oxc points to the end of the record, + * so oxc > oxa. + */ + switch (rc->iomode) { + case BR_IO_OUT: + case BR_IO_INOUT: + if (rc->oxc > rc->oxa) { + *len = rc->oxc - rc->oxa; + return rc->obuf + rc->oxa; + } + break; + } + *len = 0; + return NULL; +} + +static void +sendrec_ack(br_ssl_engine_context *rc, size_t len) +{ + rc->oxb = (rc->oxa += len); + if (rc->oxa == rc->oxc) { + make_ready_out(rc); + } +} + +/* + * Test whether there is some buffered outgoing record that still must + * sent. + */ +static inline int +has_rec_tosend(const br_ssl_engine_context *rc) +{ + return rc->oxa == rc->oxb && rc->oxa != rc->oxc; +} + +/* + * The "no encryption" mode has no overhead. It limits the payload size + * to the maximum size allowed by the standard (16384 bytes); the caller + * is responsible for possibly enforcing a smaller fragment length. + */ +static void +clear_max_plaintext(const br_sslrec_out_clear_context *cc, + size_t *start, size_t *end) +{ + size_t len; + + (void)cc; + len = *end - *start; + if (len > 16384) { + *end = *start + 16384; + } +} + +/* + * In "no encryption" mode, encryption is trivial (a no-operation) so + * we just have to encode the header. + */ +static unsigned char * +clear_encrypt(br_sslrec_out_clear_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + unsigned char *buf; + + (void)cc; + buf = (unsigned char *)data - 5; + buf[0] = record_type; + br_enc16be(buf + 1, version); + br_enc16be(buf + 3, *data_len); + *data_len += 5; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_out_class br_sslrec_out_clear_vtable = { + sizeof(br_sslrec_out_clear_context), + (void (*)(const br_sslrec_out_class *const *, size_t *, size_t *)) + &clear_max_plaintext, + (unsigned char *(*)(const br_sslrec_out_class **, + int, unsigned, void *, size_t *)) + &clear_encrypt +}; + +/* ==================================================================== */ +/* + * In this part of the file, we handle the various record types, and + * communications with the handshake processor. + */ + +/* + * IMPLEMENTATION NOTES + * ==================== + * + * The handshake processor is written in T0 and runs as a coroutine. + * It receives the contents of all records except application data, and + * is responsible for producing the contents of all records except + * application data. + * + * A state flag is maintained, which specifies whether application data + * is acceptable or not. When it is set: + * + * -- Application data can be injected as payload data (provided that + * the output buffer is ready for that). + * + * -- Incoming application data records are accepted, and yield data + * that the caller may retrieve. + * + * When the flag is cleared, application data is not accepted from the + * application, and incoming application data records trigger an error. + * + * + * Records of type handshake, alert or change-cipher-spec are handled + * by the handshake processor. The handshake processor is written in T0 + * and runs as a coroutine; it gets invoked whenever one of the following + * situations is reached: + * + * -- An incoming record has type handshake, alert or change-cipher-spec, + * and yields data that can be read (zero-length records are thus + * ignored). + * + * -- An outgoing record has just finished being sent, and the "application + * data" flag is cleared. + * + * -- The caller wishes to perform a close (call to br_ssl_engine_close()). + * + * -- The caller wishes to perform a renegotiation (call to + * br_ssl_engine_renegotiate()). + * + * Whenever the handshake processor is entered, access to the payload + * buffers is provided, along with some information about explicit + * closures or renegotiations. + */ + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_suites(br_ssl_engine_context *cc, + const uint16_t *suites, size_t suites_num) +{ + if ((suites_num * sizeof *suites) > sizeof cc->suites_buf) { + br_ssl_engine_fail(cc, BR_ERR_BAD_PARAM); + return; + } + memcpy(cc->suites_buf, suites, suites_num * sizeof *suites); + cc->suites_num = suites_num; +} + +/* + * Give control to handshake processor. 'action' is 1 for a close, + * 2 for a renegotiation, or 0 for a jump due to I/O completion. + */ +static void +jump_handshake(br_ssl_engine_context *cc, int action) +{ + /* + * We use a loop because the handshake processor actions may + * allow for more actions; namely, if the processor reads all + * input data, then it may allow for output data to be produced, + * in case of a shared in/out buffer. + */ + for (;;) { + size_t hlen_in, hlen_out; + + /* + * Get input buffer. We do not want to provide + * application data to the handshake processor (we could + * get called with an explicit close or renegotiation + * while there is application data ready to be read). + */ + cc->hbuf_in = recvpld_buf(cc, &hlen_in); + if (cc->hbuf_in != NULL + && cc->record_type_in == BR_SSL_APPLICATION_DATA) + { + hlen_in = 0; + } + + /* + * Get output buffer. The handshake processor never + * leaves an unfinished outgoing record, so if there is + * buffered output, then it MUST be some application + * data, so the processor cannot write to it. + */ + cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &hlen_out); + if (cc->hbuf_out != NULL && br_ssl_engine_has_pld_to_send(cc)) { + hlen_out = 0; + } + + /* + * Note: hlen_in and hlen_out can be both non-zero only if + * the input and output buffers are disjoint. Thus, we can + * offer both buffers to the handshake code. + */ + + cc->hlen_in = hlen_in; + cc->hlen_out = hlen_out; + cc->action = action; + cc->hsrun(&cc->cpu); + if (br_ssl_engine_closed(cc)) { + return; + } + if (cc->hbuf_out != cc->saved_hbuf_out) { + sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out); + } + if (hlen_in != cc->hlen_in) { + recvpld_ack(cc, hlen_in - cc->hlen_in); + if (cc->hlen_in == 0) { + /* + * We read all data bytes, which may have + * released the output buffer in case it + * is shared with the input buffer, and + * the handshake code might be waiting for + * that. + */ + action = 0; + continue; + } + } + break; + } +} + +/* see inner.h */ +void +br_ssl_engine_flush_record(br_ssl_engine_context *cc) +{ + if (cc->hbuf_out != cc->saved_hbuf_out) { + sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out); + } + if (br_ssl_engine_has_pld_to_send(cc)) { + sendpld_flush(cc, 0); + } + cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &cc->hlen_out); +} + +/* see bearssl_ssl.h */ +unsigned char * +br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len) +{ + if (!(cc->application_data & 1)) { + *len = 0; + return NULL; + } + return sendpld_buf(cc, len); +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len) +{ + sendpld_ack(cc, len); +} + +/* see bearssl_ssl.h */ +unsigned char * +br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len) +{ + if (!(cc->application_data & 1) + || cc->record_type_in != BR_SSL_APPLICATION_DATA) + { + *len = 0; + return NULL; + } + return recvpld_buf(cc, len); +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len) +{ + recvpld_ack(cc, len); +} + +/* see bearssl_ssl.h */ +unsigned char * +br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len) +{ + return sendrec_buf(cc, len); +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len) +{ + sendrec_ack(cc, len); + if (len != 0 && !has_rec_tosend(cc) + && (cc->record_type_out != BR_SSL_APPLICATION_DATA + || (cc->application_data & 1) == 0)) + { + jump_handshake(cc, 0); + } +} + +/* see bearssl_ssl.h */ +unsigned char * +br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len) +{ + return recvrec_buf(cc, len); +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len) +{ + unsigned char *buf; + + recvrec_ack(cc, len); + if (br_ssl_engine_closed(cc)) { + return; + } + + /* + * We just received some bytes from the peer. This may have + * yielded some payload bytes, in which case we must process + * them according to the record type. + */ + buf = recvpld_buf(cc, &len); + if (buf != NULL) { + switch (cc->record_type_in) { + case BR_SSL_CHANGE_CIPHER_SPEC: + case BR_SSL_ALERT: + case BR_SSL_HANDSHAKE: + jump_handshake(cc, 0); + break; + case BR_SSL_APPLICATION_DATA: + if (cc->application_data == 1) { + break; + } + + /* + * If we are currently closing, and waiting for + * a close_notify from the peer, then incoming + * application data should be discarded. + */ + if (cc->application_data == 2) { + recvpld_ack(cc, len); + break; + } + + /* Fall through */ + default: + br_ssl_engine_fail(cc, BR_ERR_UNEXPECTED); + break; + } + } +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_close(br_ssl_engine_context *cc) +{ + if (!br_ssl_engine_closed(cc)) { + jump_handshake(cc, 1); + } +} + +/* see bearssl_ssl.h */ +int +br_ssl_engine_renegotiate(br_ssl_engine_context *cc) +{ + size_t len; + + if (br_ssl_engine_closed(cc) || cc->reneg == 1 + || (cc->flags & BR_OPT_NO_RENEGOTIATION) != 0 + || br_ssl_engine_recvapp_buf(cc, &len) != NULL) + { + return 0; + } + jump_handshake(cc, 2); + return 1; +} + +/* see bearssl.h */ +unsigned +br_ssl_engine_current_state(const br_ssl_engine_context *cc) +{ + unsigned s; + size_t len; + + if (br_ssl_engine_closed(cc)) { + return BR_SSL_CLOSED; + } + + s = 0; + if (br_ssl_engine_sendrec_buf(cc, &len) != NULL) { + s |= BR_SSL_SENDREC; + } + if (br_ssl_engine_recvrec_buf(cc, &len) != NULL) { + s |= BR_SSL_RECVREC; + } + if (br_ssl_engine_sendapp_buf(cc, &len) != NULL) { + s |= BR_SSL_SENDAPP; + } + if (br_ssl_engine_recvapp_buf(cc, &len) != NULL) { + s |= BR_SSL_RECVAPP; + } + return s; +} + +/* see bearssl_ssl.h */ +void +br_ssl_engine_flush(br_ssl_engine_context *cc, int force) +{ + if (!br_ssl_engine_closed(cc) && (cc->application_data & 1) != 0) { + sendpld_flush(cc, force); + } +} + +/* see inner.h */ +void +br_ssl_engine_hs_reset(br_ssl_engine_context *cc, + void (*hsinit)(void *), void (*hsrun)(void *)) +{ + engine_clearbuf(cc); + cc->cpu.dp = cc->dp_stack; + cc->cpu.rp = cc->rp_stack; + hsinit(&cc->cpu); + cc->hsrun = hsrun; + cc->shutdown_recv = 0; + cc->application_data = 0; + cc->alert = 0; + jump_handshake(cc, 0); +} + +/* see inner.h */ +br_tls_prf_impl +br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id) +{ + if (cc->session.version >= BR_TLS12) { + if (prf_id == br_sha384_ID) { + return cc->prf_sha384; + } else { + return cc->prf_sha256; + } + } else { + return cc->prf10; + } +} + +/* see inner.h */ +void +br_ssl_engine_compute_master(br_ssl_engine_context *cc, + int prf_id, const void *pms, size_t pms_len) +{ + br_tls_prf_impl iprf; + br_tls_prf_seed_chunk seed[2] = { + { cc->client_random, sizeof cc->client_random }, + { cc->server_random, sizeof cc->server_random } + }; + + iprf = br_ssl_engine_get_PRF(cc, prf_id); + iprf(cc->session.master_secret, sizeof cc->session.master_secret, + pms, pms_len, "master secret", 2, seed); +} + +/* + * Compute key block. + */ +static void +compute_key_block(br_ssl_engine_context *cc, int prf_id, + size_t half_len, unsigned char *kb) +{ + br_tls_prf_impl iprf; + br_tls_prf_seed_chunk seed[2] = { + { cc->server_random, sizeof cc->server_random }, + { cc->client_random, sizeof cc->client_random } + }; + + iprf = br_ssl_engine_get_PRF(cc, prf_id); + iprf(kb, half_len << 1, + cc->session.master_secret, sizeof cc->session.master_secret, + "key expansion", 2, seed); +} + +/* see inner.h */ +void +br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc, + int is_client, int prf_id, int mac_id, + const br_block_cbcdec_class *bc_impl, size_t cipher_key_len) +{ + unsigned char kb[192]; + unsigned char *cipher_key, *mac_key, *iv; + const br_hash_class *imh; + size_t mac_key_len, mac_out_len, iv_len; + + imh = br_ssl_engine_get_hash(cc, mac_id); + mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + mac_key_len = mac_out_len; + + /* + * TLS 1.1+ uses per-record explicit IV, so no IV to generate here. + */ + if (cc->session.version >= BR_TLS11) { + iv_len = 0; + } else { + iv_len = bc_impl->block_size; + } + compute_key_block(cc, prf_id, + mac_key_len + cipher_key_len + iv_len, kb); + if (is_client) { + mac_key = &kb[mac_key_len]; + cipher_key = &kb[(mac_key_len << 1) + cipher_key_len]; + iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len]; + } else { + mac_key = &kb[0]; + cipher_key = &kb[mac_key_len << 1]; + iv = &kb[(mac_key_len + cipher_key_len) << 1]; + } + if (iv_len == 0) { + iv = NULL; + } + cc->icbc_in->init(&cc->in.cbc.vtable, + bc_impl, cipher_key, cipher_key_len, + imh, mac_key, mac_key_len, mac_out_len, iv); + cc->incrypt = 1; +} + +/* see inner.h */ +void +br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc, + int is_client, int prf_id, int mac_id, + const br_block_cbcenc_class *bc_impl, size_t cipher_key_len) +{ + unsigned char kb[192]; + unsigned char *cipher_key, *mac_key, *iv; + const br_hash_class *imh; + size_t mac_key_len, mac_out_len, iv_len; + + imh = br_ssl_engine_get_hash(cc, mac_id); + mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + mac_key_len = mac_out_len; + + /* + * TLS 1.1+ uses per-record explicit IV, so no IV to generate here. + */ + if (cc->session.version >= BR_TLS11) { + iv_len = 0; + } else { + iv_len = bc_impl->block_size; + } + compute_key_block(cc, prf_id, + mac_key_len + cipher_key_len + iv_len, kb); + if (is_client) { + mac_key = &kb[0]; + cipher_key = &kb[mac_key_len << 1]; + iv = &kb[(mac_key_len + cipher_key_len) << 1]; + } else { + mac_key = &kb[mac_key_len]; + cipher_key = &kb[(mac_key_len << 1) + cipher_key_len]; + iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len]; + } + if (iv_len == 0) { + iv = NULL; + } + cc->icbc_out->init(&cc->out.cbc.vtable, + bc_impl, cipher_key, cipher_key_len, + imh, mac_key, mac_key_len, mac_out_len, iv); +} + +/* see inner.h */ +void +br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctr_class *bc_impl, size_t cipher_key_len) +{ + unsigned char kb[72]; + unsigned char *cipher_key, *iv; + + compute_key_block(cc, prf_id, cipher_key_len + 4, kb); + if (is_client) { + cipher_key = &kb[cipher_key_len]; + iv = &kb[(cipher_key_len << 1) + 4]; + } else { + cipher_key = &kb[0]; + iv = &kb[cipher_key_len << 1]; + } + cc->igcm_in->init(&cc->in.gcm.vtable.in, + bc_impl, cipher_key, cipher_key_len, cc->ighash, iv); + cc->incrypt = 1; +} + +/* see inner.h */ +void +br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctr_class *bc_impl, size_t cipher_key_len) +{ + unsigned char kb[72]; + unsigned char *cipher_key, *iv; + + compute_key_block(cc, prf_id, cipher_key_len + 4, kb); + if (is_client) { + cipher_key = &kb[0]; + iv = &kb[cipher_key_len << 1]; + } else { + cipher_key = &kb[cipher_key_len]; + iv = &kb[(cipher_key_len << 1) + 4]; + } + cc->igcm_out->init(&cc->out.gcm.vtable.out, + bc_impl, cipher_key, cipher_key_len, cc->ighash, iv); +} + +/* see inner.h */ +void +br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc, + int is_client, int prf_id) +{ + unsigned char kb[88]; + unsigned char *cipher_key, *iv; + + compute_key_block(cc, prf_id, 44, kb); + if (is_client) { + cipher_key = &kb[32]; + iv = &kb[76]; + } else { + cipher_key = &kb[0]; + iv = &kb[64]; + } + cc->ichapol_in->init(&cc->in.chapol.vtable.in, + cc->ichacha, cc->ipoly, cipher_key, iv); + cc->incrypt = 1; +} + +/* see inner.h */ +void +br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc, + int is_client, int prf_id) +{ + unsigned char kb[88]; + unsigned char *cipher_key, *iv; + + compute_key_block(cc, prf_id, 44, kb); + if (is_client) { + cipher_key = &kb[0]; + iv = &kb[64]; + } else { + cipher_key = &kb[32]; + iv = &kb[76]; + } + cc->ichapol_out->init(&cc->out.chapol.vtable.out, + cc->ichacha, cc->ipoly, cipher_key, iv); +} + +/* see inner.h */ +void +br_ssl_engine_switch_ccm_in(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctrcbc_class *bc_impl, + size_t cipher_key_len, size_t tag_len) +{ + unsigned char kb[72]; + unsigned char *cipher_key, *iv; + + compute_key_block(cc, prf_id, cipher_key_len + 4, kb); + if (is_client) { + cipher_key = &kb[cipher_key_len]; + iv = &kb[(cipher_key_len << 1) + 4]; + } else { + cipher_key = &kb[0]; + iv = &kb[cipher_key_len << 1]; + } + cc->iccm_in->init(&cc->in.ccm.vtable.in, + bc_impl, cipher_key, cipher_key_len, iv, tag_len); + cc->incrypt = 1; +} + +/* see inner.h */ +void +br_ssl_engine_switch_ccm_out(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctrcbc_class *bc_impl, + size_t cipher_key_len, size_t tag_len) +{ + unsigned char kb[72]; + unsigned char *cipher_key, *iv; + + compute_key_block(cc, prf_id, cipher_key_len + 4, kb); + if (is_client) { + cipher_key = &kb[0]; + iv = &kb[cipher_key_len << 1]; + } else { + cipher_key = &kb[cipher_key_len]; + iv = &kb[(cipher_key_len << 1) + 4]; + } + cc->iccm_out->init(&cc->out.ccm.vtable.out, + bc_impl, cipher_key, cipher_key_len, iv, tag_len); +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_aescbc.c b/src/bearssl/src/ssl/ssl_engine_default_aescbc.c new file mode 100644 index 0000000..8c5cdb5 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_aescbc.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_aes_cbc(br_ssl_engine_context *cc) +{ +#if BR_AES_X86NI || BR_POWER8 + const br_block_cbcenc_class *ienc; + const br_block_cbcdec_class *idec; +#endif + + br_ssl_engine_set_cbc(cc, + &br_sslrec_in_cbc_vtable, + &br_sslrec_out_cbc_vtable); +#if BR_AES_X86NI + ienc = br_aes_x86ni_cbcenc_get_vtable(); + idec = br_aes_x86ni_cbcdec_get_vtable(); + if (ienc != NULL && idec != NULL) { + br_ssl_engine_set_aes_cbc(cc, ienc, idec); + return; + } +#endif +#if BR_POWER8 + ienc = br_aes_pwr8_cbcenc_get_vtable(); + idec = br_aes_pwr8_cbcdec_get_vtable(); + if (ienc != NULL && idec != NULL) { + br_ssl_engine_set_aes_cbc(cc, ienc, idec); + return; + } +#endif +#if BR_64 + br_ssl_engine_set_aes_cbc(cc, + &br_aes_ct64_cbcenc_vtable, + &br_aes_ct64_cbcdec_vtable); +#else + br_ssl_engine_set_aes_cbc(cc, + &br_aes_ct_cbcenc_vtable, + &br_aes_ct_cbcdec_vtable); +#endif +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_aesccm.c b/src/bearssl/src/ssl/ssl_engine_default_aesccm.c new file mode 100644 index 0000000..15c0a78 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_aesccm.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_aes_ccm(br_ssl_engine_context *cc) +{ +#if BR_AES_X86NI || BR_POWER8 + const br_block_ctrcbc_class *ictrcbc; +#endif + + br_ssl_engine_set_ccm(cc, + &br_sslrec_in_ccm_vtable, + &br_sslrec_out_ccm_vtable); +#if BR_AES_X86NI + ictrcbc = br_aes_x86ni_ctrcbc_get_vtable(); + if (ictrcbc != NULL) { + br_ssl_engine_set_aes_ctrcbc(cc, ictrcbc); + } else { +#if BR_64 + br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable); +#else + br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable); +#endif + } +#elif BR_POWER8 + ictrcbc = br_aes_pwr8_ctrcbc_get_vtable(); + if (ictrcbc != NULL) { + br_ssl_engine_set_aes_ctrcbc(cc, ictrcbc); + } else { +#if BR_64 + br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable); +#else + br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable); +#endif + } +#else +#if BR_64 + br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable); +#else + br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable); +#endif +#endif +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_aesgcm.c b/src/bearssl/src/ssl/ssl_engine_default_aesgcm.c new file mode 100644 index 0000000..c44a707 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_aesgcm.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_aes_gcm(br_ssl_engine_context *cc) +{ +#if BR_AES_X86NI || BR_POWER8 + const br_block_ctr_class *ictr; + br_ghash ighash; +#endif + + br_ssl_engine_set_gcm(cc, + &br_sslrec_in_gcm_vtable, + &br_sslrec_out_gcm_vtable); +#if BR_AES_X86NI + ictr = br_aes_x86ni_ctr_get_vtable(); + if (ictr != NULL) { + br_ssl_engine_set_aes_ctr(cc, ictr); + } else { +#if BR_64 + br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable); +#else + br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable); +#endif + } +#elif BR_POWER8 + ictr = br_aes_pwr8_ctr_get_vtable(); + if (ictr != NULL) { + br_ssl_engine_set_aes_ctr(cc, ictr); + } else { +#if BR_64 + br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable); +#else + br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable); +#endif + } +#else +#if BR_64 + br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable); +#else + br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable); +#endif +#endif +#if BR_AES_X86NI + ighash = br_ghash_pclmul_get(); + if (ighash != 0) { + br_ssl_engine_set_ghash(cc, ighash); + return; + } +#endif +#if BR_POWER8 + ighash = br_ghash_pwr8_get(); + if (ighash != 0) { + br_ssl_engine_set_ghash(cc, ighash); + return; + } +#endif +#if BR_LOMUL + br_ssl_engine_set_ghash(cc, &br_ghash_ctmul32); +#elif BR_64 + br_ssl_engine_set_ghash(cc, &br_ghash_ctmul64); +#else + br_ssl_engine_set_ghash(cc, &br_ghash_ctmul); +#endif +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_chapol.c b/src/bearssl/src/ssl/ssl_engine_default_chapol.c new file mode 100644 index 0000000..47a0c98 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_chapol.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_chapol(br_ssl_engine_context *cc) +{ +#if BR_INT128 || BR_UMUL128 + br_poly1305_run bp; +#endif +#if BR_SSE2 + br_chacha20_run bc; +#endif + + br_ssl_engine_set_chapol(cc, + &br_sslrec_in_chapol_vtable, + &br_sslrec_out_chapol_vtable); +#if BR_SSE2 + bc = br_chacha20_sse2_get(); + if (bc) { + br_ssl_engine_set_chacha20(cc, bc); + } else { +#endif + br_ssl_engine_set_chacha20(cc, &br_chacha20_ct_run); +#if BR_SSE2 + } +#endif +#if BR_INT128 || BR_UMUL128 + bp = br_poly1305_ctmulq_get(); + if (bp) { + br_ssl_engine_set_poly1305(cc, bp); + } else { +#endif +#if BR_LOMUL + br_ssl_engine_set_poly1305(cc, &br_poly1305_ctmul32_run); +#else + br_ssl_engine_set_poly1305(cc, &br_poly1305_ctmul_run); +#endif +#if BR_INT128 || BR_UMUL128 + } +#endif +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_descbc.c b/src/bearssl/src/ssl/ssl_engine_default_descbc.c new file mode 100644 index 0000000..0253cb2 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_descbc.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_des_cbc(br_ssl_engine_context *cc) +{ + br_ssl_engine_set_cbc(cc, + &br_sslrec_in_cbc_vtable, + &br_sslrec_out_cbc_vtable); + br_ssl_engine_set_des_cbc(cc, + &br_des_ct_cbcenc_vtable, + &br_des_ct_cbcdec_vtable); +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_ec.c b/src/bearssl/src/ssl/ssl_engine_default_ec.c new file mode 100644 index 0000000..0213ae6 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_ec.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_ec(br_ssl_engine_context *cc) +{ +#if BR_LOMUL + br_ssl_engine_set_ec(cc, &br_ec_all_m15); +#else + br_ssl_engine_set_ec(cc, &br_ec_all_m31); +#endif +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_ecdsa.c b/src/bearssl/src/ssl/ssl_engine_default_ecdsa.c new file mode 100644 index 0000000..1304002 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_ecdsa.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_ecdsa(br_ssl_engine_context *cc) +{ +#if BR_LOMUL + br_ssl_engine_set_ec(cc, &br_ec_all_m15); + br_ssl_engine_set_ecdsa(cc, &br_ecdsa_i15_vrfy_asn1); +#else + br_ssl_engine_set_ec(cc, &br_ec_all_m31); + br_ssl_engine_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1); +#endif +} diff --git a/src/bearssl/src/ssl/ssl_engine_default_rsavrfy.c b/src/bearssl/src/ssl/ssl_engine_default_rsavrfy.c new file mode 100644 index 0000000..ad0628a --- /dev/null +++ b/src/bearssl/src/ssl/ssl_engine_default_rsavrfy.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_engine_set_default_rsavrfy(br_ssl_engine_context *cc) +{ + br_ssl_engine_set_rsavrfy(cc, br_rsa_pkcs1_vrfy_get_default()); +} diff --git a/src/bearssl/src/ssl/ssl_hashes.c b/src/bearssl/src/ssl/ssl_hashes.c new file mode 100644 index 0000000..e10a980 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_hashes.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +int +br_ssl_choose_hash(unsigned bf) +{ + static const unsigned char pref[] = { + br_sha256_ID, br_sha384_ID, br_sha512_ID, + br_sha224_ID, br_sha1_ID + }; + size_t u; + + for (u = 0; u < sizeof pref; u ++) { + int x; + + x = pref[u]; + if ((bf >> x) & 1) { + return x; + } + } + return 0; +} diff --git a/src/bearssl/src/ssl/ssl_hs_client.c b/src/bearssl/src/ssl/ssl_hs_client.c new file mode 100644 index 0000000..de36165 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_hs_client.c @@ -0,0 +1,1915 @@ +/* Automatically generated code; do not modify directly. */ + +#include +#include + +typedef struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; +} t0_context; + +static uint32_t +t0_parse7E_unsigned(const unsigned char **p) +{ + uint32_t x; + + x = 0; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + return x; + } + } +} + +static int32_t +t0_parse7E_signed(const unsigned char **p) +{ + int neg; + uint32_t x; + + neg = ((**p) >> 6) & 1; + x = (uint32_t)-neg; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + if (neg) { + return -(int32_t)~x - 1; + } else { + return (int32_t)x; + } + } + } +} + +#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80) +#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F) +#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8) +#define T0_INT1(x) T0_FBYTE(x, 0) +#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) + +/* static const unsigned char t0_datablock[]; */ + + +void br_ssl_hs_client_init_main(void *t0ctx); + +void br_ssl_hs_client_run(void *t0ctx); + + + +#include +#include + +#include "inner.h" + +/* + * This macro evaluates to a pointer to the current engine context. + */ +#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu))) + + + + + +/* + * This macro evaluates to a pointer to the client context, under that + * specific name. It must be noted that since the engine context is the + * first field of the br_ssl_client_context structure ('eng'), then + * pointers values of both types are interchangeable, modulo an + * appropriate cast. This also means that "addresses" computed as offsets + * within the structure work for both kinds of context. + */ +#define CTX ((br_ssl_client_context *)ENG) + +/* + * Generate the pre-master secret for RSA key exchange, and encrypt it + * with the server's public key. Returned value is either the encrypted + * data length (in bytes), or -x on error, with 'x' being an error code. + * + * This code assumes that the public key has been already verified (it + * was properly obtained by the X.509 engine, and it has the right type, + * i.e. it is of type RSA and suitable for encryption). + */ +static int +make_pms_rsa(br_ssl_client_context *ctx, int prf_id) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + const unsigned char *n; + unsigned char *pms; + size_t nlen, u; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + + /* + * Compute actual RSA key length, in case there are leading zeros. + */ + n = pk->key.rsa.n; + nlen = pk->key.rsa.nlen; + while (nlen > 0 && *n == 0) { + n ++; + nlen --; + } + + /* + * We need at least 59 bytes (48 bytes for pre-master secret, and + * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509 + * minimal engine normally blocks RSA keys shorter than 128 bytes, + * so this is mostly for public keys provided explicitly by the + * caller. + */ + if (nlen < 59) { + return -BR_ERR_X509_WEAK_PUBLIC_KEY; + } + if (nlen > sizeof ctx->eng.pad) { + return -BR_ERR_LIMIT_EXCEEDED; + } + + /* + * Make PMS. + */ + pms = ctx->eng.pad + nlen - 48; + br_enc16be(pms, ctx->eng.version_max); + br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46); + br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48); + + /* + * Apply PKCS#1 type 2 padding. + */ + ctx->eng.pad[0] = 0x00; + ctx->eng.pad[1] = 0x02; + ctx->eng.pad[nlen - 49] = 0x00; + br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51); + for (u = 2; u < nlen - 49; u ++) { + while (ctx->eng.pad[u] == 0) { + br_hmac_drbg_generate(&ctx->eng.rng, + &ctx->eng.pad[u], 1); + } + } + + /* + * Compute RSA encryption. + */ + if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) { + return -BR_ERR_LIMIT_EXCEEDED; + } + return (int)nlen; +} + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char *HASH_OID[] = { + BR_HASH_OID_SHA1, + BR_HASH_OID_SHA224, + BR_HASH_OID_SHA256, + BR_HASH_OID_SHA384, + BR_HASH_OID_SHA512 +}; + +/* + * Check the RSA signature on the ServerKeyExchange message. + * + * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only) + * use_rsa non-zero for RSA signature, zero for ECDSA + * sig_len signature length (in bytes); signature value is in the pad + * + * Returned value is 0 on success, or an error code. + */ +static int +verify_SKE_sig(br_ssl_client_context *ctx, + int hash, int use_rsa, size_t sig_len) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + br_multihash_context mhc; + unsigned char hv[64], head[4]; + size_t hv_len; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + br_multihash_zero(&mhc); + br_multihash_copyimpl(&mhc, &ctx->eng.mhash); + br_multihash_init(&mhc); + br_multihash_update(&mhc, + ctx->eng.client_random, sizeof ctx->eng.client_random); + br_multihash_update(&mhc, + ctx->eng.server_random, sizeof ctx->eng.server_random); + head[0] = 3; + head[1] = 0; + head[2] = ctx->eng.ecdhe_curve; + head[3] = ctx->eng.ecdhe_point_len; + br_multihash_update(&mhc, head, sizeof head); + br_multihash_update(&mhc, + ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len); + if (hash) { + hv_len = br_multihash_out(&mhc, hash, hv); + if (hv_len == 0) { + return BR_ERR_INVALID_ALGORITHM; + } + } else { + if (!br_multihash_out(&mhc, br_md5_ID, hv) + || !br_multihash_out(&mhc, br_sha1_ID, hv + 16)) + { + return BR_ERR_INVALID_ALGORITHM; + } + hv_len = 36; + } + if (use_rsa) { + unsigned char tmp[64]; + const unsigned char *hash_oid; + + if (hash) { + hash_oid = HASH_OID[hash - 2]; + } else { + hash_oid = NULL; + } + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, + hash_oid, hv_len, &pk->key.rsa, tmp) + || memcmp(tmp, hv, hv_len) != 0) + { + return BR_ERR_BAD_SIGNATURE; + } + } else { + if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec, + ctx->eng.pad, sig_len)) + { + return BR_ERR_BAD_SIGNATURE; + } + } + return 0; +} + +/* + * Perform client-side ECDH (or ECDHE). The point that should be sent to + * the server is written in the pad; returned value is either the point + * length (in bytes), or -x on error, with 'x' being an error code. + * + * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe' + * is non-zero, or from the X.509 engine context if 'ecdhe' is zero + * (for static ECDH). + */ +static int +make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) +{ + int curve; + unsigned char key[66], point[133]; + const unsigned char *order, *point_src; + size_t glen, olen, point_len, xoff, xlen; + unsigned char mask; + + if (ecdhe) { + curve = ctx->eng.ecdhe_curve; + point_src = ctx->eng.ecdhe_point; + point_len = ctx->eng.ecdhe_point_len; + } else { + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + curve = pk->key.ec.curve; + point_src = pk->key.ec.q; + point_len = pk->key.ec.qlen; + } + if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) { + return -BR_ERR_INVALID_ALGORITHM; + } + + /* + * We need to generate our key, as a non-zero random value which + * is lower than the curve order, in a "large enough" range. We + * force top bit to 0 and bottom bit to 1, which guarantees that + * the value is in the proper range. + */ + order = ctx->eng.iec->order(curve, &olen); + mask = 0xFF; + while (mask >= order[0]) { + mask >>= 1; + } + br_hmac_drbg_generate(&ctx->eng.rng, key, olen); + key[0] &= mask; + key[olen - 1] |= 0x01; + + /* + * Compute the common ECDH point, whose X coordinate is the + * pre-master secret. + */ + ctx->eng.iec->generator(curve, &glen); + if (glen != point_len) { + return -BR_ERR_INVALID_ALGORITHM; + } + + memcpy(point, point_src, glen); + if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) { + return -BR_ERR_INVALID_ALGORITHM; + } + + /* + * The pre-master secret is the X coordinate. + */ + xoff = ctx->eng.iec->xoff(curve, &xlen); + br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen); + + ctx->eng.iec->mulgen(point, key, olen, curve); + memcpy(ctx->eng.pad, point, glen); + return (int)glen; +} + +/* + * Perform full static ECDH. This occurs only in the context of client + * authentication with certificates: the server uses an EC public key, + * the cipher suite is of type ECDH (not ECDHE), the server requested a + * client certificate and accepts static ECDH, the client has a + * certificate with an EC public key in the same curve, and accepts + * static ECDH as well. + * + * Returned value is 0 on success, -1 on error. + */ +static int +make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id) +{ + unsigned char point[133]; + size_t point_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + point_len = pk->key.ec.qlen; + if (point_len > sizeof point) { + return -1; + } + memcpy(point, pk->key.ec.q, point_len); + if (!(*ctx->client_auth_vtable)->do_keyx( + ctx->client_auth_vtable, point, &point_len)) + { + return -1; + } + br_ssl_engine_compute_master(&ctx->eng, + prf_id, point, point_len); + return 0; +} + +/* + * Compute the client-side signature. This is invoked only when a + * signature-based client authentication was selected. The computed + * signature is in the pad; its length (in bytes) is returned. On + * error, 0 is returned. + */ +static size_t +make_client_sign(br_ssl_client_context *ctx) +{ + size_t hv_len; + + /* + * Compute hash of handshake messages so far. This "cannot" fail + * because the list of supported hash functions provided to the + * client certificate handler was trimmed to include only the + * hash functions that the multi-hasher supports. + */ + if (ctx->hash_id) { + hv_len = br_multihash_out(&ctx->eng.mhash, + ctx->hash_id, ctx->eng.pad); + } else { + br_multihash_out(&ctx->eng.mhash, + br_md5_ID, ctx->eng.pad); + br_multihash_out(&ctx->eng.mhash, + br_sha1_ID, ctx->eng.pad + 16); + hv_len = 36; + } + return (*ctx->client_auth_vtable)->do_sign( + ctx->client_auth_vtable, ctx->hash_id, hv_len, + ctx->eng.pad, sizeof ctx->eng.pad); +} + + + +static const unsigned char t0_datablock[] = { + 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02, + 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03, + 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41, + 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21, + 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31, + 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11, + 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22, + 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11, + 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32, + 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43, + 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14, + 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xC0, 0x9C, 0x06, + 0x04, 0xC0, 0x9D, 0x07, 0x04, 0xC0, 0xA0, 0x08, 0x04, 0xC0, 0xA1, 0x09, + 0x04, 0xC0, 0xAC, 0x26, 0x04, 0xC0, 0xAD, 0x27, 0x04, 0xC0, 0xAE, 0x28, + 0x04, 0xC0, 0xAF, 0x29, 0x04, 0xCC, 0xA8, 0x15, 0x04, 0xCC, 0xA9, 0x25, + 0x04, 0x00, 0x00 +}; + +static const unsigned char t0_codeblock[] = { + 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01, + 0x00, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x01, 0x08, + 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00, + 0x01, 0x02, 0x09, 0x00, 0x00, 0x25, 0x25, 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_CIPHER_SUITE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_COMPRESSION), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_FINISHED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_FRAGLEN), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_HANDSHAKE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_HELLO_DONE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_PARAM), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_SECRENEG), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_SNI), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_VERSION), + 0x00, 0x00, 0x01, T0_INT1(BR_ERR_EXTRA_EXTENSION), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_INVALID_ALGORITHM), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK), + 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_RESUME_MISMATCH), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_UNSUPPORTED_VERSION), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_WRONG_KEY_USAGE), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_client_context, auth_type)), 0x00, 0x00, + 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, client_random)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_curve)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, flags)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_client_context, hash_id)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_client_context, hashes)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_client_context, min_clienthello_len)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, protocol_names_num)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, record_type_in)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, selected_protocol)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00, + 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00, 0x00, + 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)), + 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)), + 0x00, 0x00, 0x09, 0x26, 0x58, 0x06, 0x02, 0x68, 0x28, 0x00, 0x00, 0x06, + 0x08, 0x2C, 0x0E, 0x05, 0x02, 0x71, 0x28, 0x04, 0x01, 0x3C, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x01, 0x03, 0x00, 0x99, 0x26, 0x5E, 0x44, 0x9D, 0x26, + 0x05, 0x04, 0x60, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x06, 0x02, 0x9D, + 0x00, 0x5E, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x68, 0x28, 0x00, 0x00, 0x26, + 0x89, 0x44, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x44, 0x79, 0x2C, 0xAB, 0x1C, + 0x84, 0x01, 0x0C, 0x31, 0x00, 0x00, 0x26, 0x1F, 0x01, 0x08, 0x0B, 0x44, + 0x5C, 0x1F, 0x08, 0x00, 0x01, 0x03, 0x00, 0x77, 0x2E, 0x02, 0x00, 0x36, + 0x17, 0x01, 0x01, 0x0B, 0x77, 0x3E, 0x29, 0x1A, 0x36, 0x06, 0x07, 0x02, + 0x00, 0xCF, 0x03, 0x00, 0x04, 0x75, 0x01, 0x00, 0xC5, 0x02, 0x00, 0x26, + 0x1A, 0x17, 0x06, 0x02, 0x6F, 0x28, 0xCF, 0x04, 0x76, 0x01, 0x01, 0x00, + 0x77, 0x3E, 0x01, 0x16, 0x87, 0x3E, 0x01, 0x00, 0x8A, 0x3C, 0x34, 0xD5, + 0x29, 0xB4, 0x06, 0x09, 0x01, 0x7F, 0xAF, 0x01, 0x7F, 0xD2, 0x04, 0x80, + 0x53, 0xB1, 0x79, 0x2C, 0xA1, 0x01, T0_INT1(BR_KEYTYPE_SIGN), 0x17, + 0x06, 0x01, 0xB5, 0xB8, 0x26, 0x01, 0x0D, 0x0E, 0x06, 0x07, 0x25, 0xB7, + 0xB8, 0x01, 0x7F, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00, 0x01, 0x0E, 0x0E, + 0x05, 0x02, 0x72, 0x28, 0x06, 0x02, 0x67, 0x28, 0x33, 0x06, 0x02, 0x72, + 0x28, 0x02, 0x00, 0x06, 0x1C, 0xD3, 0x80, 0x2E, 0x01, 0x81, 0x7F, 0x0E, + 0x06, 0x0D, 0x25, 0x01, 0x10, 0xDE, 0x01, 0x00, 0xDD, 0x79, 0x2C, 0xAB, + 0x24, 0x04, 0x04, 0xD6, 0x06, 0x01, 0xD4, 0x04, 0x01, 0xD6, 0x01, 0x7F, + 0xD2, 0x01, 0x7F, 0xAF, 0x01, 0x01, 0x77, 0x3E, 0x01, 0x17, 0x87, 0x3E, + 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x00, + 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01, + T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX), 0x04, 0x30, 0x01, 0x01, + 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01, + T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN), 0x04, 0x25, 0x01, 0x02, + 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01, + T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_SIGN), 0x04, 0x1A, 0x01, 0x03, + 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01, + T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x0F, 0x01, 0x04, + 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01, + T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x04, 0x01, 0x00, + 0x44, 0x25, 0x00, 0x00, 0x82, 0x2E, 0x01, 0x0E, 0x0E, 0x06, 0x04, 0x01, + 0x00, 0x04, 0x02, 0x01, 0x05, 0x00, 0x00, 0x40, 0x06, 0x04, 0x01, 0x06, + 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x88, 0x2E, 0x26, 0x06, 0x08, 0x01, + 0x01, 0x09, 0x01, 0x11, 0x07, 0x04, 0x03, 0x25, 0x01, 0x05, 0x00, 0x01, + 0x41, 0x03, 0x00, 0x25, 0x01, 0x00, 0x43, 0x06, 0x03, 0x02, 0x00, 0x08, + 0x42, 0x06, 0x03, 0x02, 0x00, 0x08, 0x26, 0x06, 0x06, 0x01, 0x01, 0x0B, + 0x01, 0x06, 0x08, 0x00, 0x00, 0x8B, 0x3F, 0x26, 0x06, 0x03, 0x01, 0x09, + 0x08, 0x00, 0x01, 0x40, 0x26, 0x06, 0x1E, 0x01, 0x00, 0x03, 0x00, 0x26, + 0x06, 0x0E, 0x26, 0x01, 0x01, 0x17, 0x02, 0x00, 0x08, 0x03, 0x00, 0x01, + 0x01, 0x11, 0x04, 0x6F, 0x25, 0x02, 0x00, 0x01, 0x01, 0x0B, 0x01, 0x06, + 0x08, 0x00, 0x00, 0x7F, 0x2D, 0x44, 0x11, 0x01, 0x01, 0x17, 0x35, 0x00, + 0x00, 0x9F, 0xCE, 0x26, 0x01, 0x07, 0x17, 0x01, 0x00, 0x38, 0x0E, 0x06, + 0x09, 0x25, 0x01, 0x10, 0x17, 0x06, 0x01, 0x9F, 0x04, 0x35, 0x01, 0x01, + 0x38, 0x0E, 0x06, 0x2C, 0x25, 0x25, 0x01, 0x00, 0x77, 0x3E, 0xB3, 0x88, + 0x2E, 0x01, 0x01, 0x0E, 0x01, 0x01, 0xA8, 0x37, 0x06, 0x17, 0x29, 0x1A, + 0x36, 0x06, 0x04, 0xCE, 0x25, 0x04, 0x78, 0x01, 0x80, 0x64, 0xC5, 0x01, + 0x01, 0x77, 0x3E, 0x01, 0x17, 0x87, 0x3E, 0x04, 0x01, 0x9F, 0x04, 0x03, + 0x72, 0x28, 0x25, 0x04, 0xFF, 0x34, 0x01, 0x26, 0x03, 0x00, 0x09, 0x26, + 0x58, 0x06, 0x02, 0x68, 0x28, 0x02, 0x00, 0x00, 0x00, 0x9A, 0x01, 0x0F, + 0x17, 0x00, 0x00, 0x76, 0x2E, 0x01, 0x00, 0x38, 0x0E, 0x06, 0x10, 0x25, + 0x26, 0x01, 0x01, 0x0D, 0x06, 0x03, 0x25, 0x01, 0x02, 0x76, 0x3E, 0x01, + 0x00, 0x04, 0x21, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x14, 0x25, 0x01, 0x00, + 0x76, 0x3E, 0x26, 0x01, 0x80, 0x64, 0x0E, 0x06, 0x05, 0x01, 0x82, 0x00, + 0x08, 0x28, 0x5A, 0x04, 0x07, 0x25, 0x01, 0x82, 0x00, 0x08, 0x28, 0x25, + 0x00, 0x00, 0x01, 0x00, 0x2F, 0x06, 0x05, 0x3A, 0xAC, 0x37, 0x04, 0x78, + 0x26, 0x06, 0x04, 0x01, 0x01, 0x8F, 0x3E, 0x00, 0x01, 0xBF, 0xAA, 0xBF, + 0xAA, 0xC1, 0x84, 0x44, 0x26, 0x03, 0x00, 0xB6, 0x9B, 0x9B, 0x02, 0x00, + 0x4D, 0x26, 0x58, 0x06, 0x0A, 0x01, 0x03, 0xA8, 0x06, 0x02, 0x72, 0x28, + 0x25, 0x04, 0x03, 0x5C, 0x8A, 0x3C, 0x00, 0x00, 0x2F, 0x06, 0x0B, 0x86, + 0x2E, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x72, 0x28, 0x04, 0x11, 0xCE, 0x01, + 0x07, 0x17, 0x26, 0x01, 0x02, 0x0D, 0x06, 0x06, 0x06, 0x02, 0x72, 0x28, + 0x04, 0x70, 0x25, 0xC2, 0x01, 0x01, 0x0D, 0x33, 0x37, 0x06, 0x02, 0x61, + 0x28, 0x26, 0x01, 0x01, 0xC8, 0x36, 0xB2, 0x00, 0x01, 0xB8, 0x01, 0x0B, + 0x0E, 0x05, 0x02, 0x72, 0x28, 0x26, 0x01, 0x03, 0x0E, 0x06, 0x08, 0xC0, + 0x06, 0x02, 0x68, 0x28, 0x44, 0x25, 0x00, 0x44, 0x57, 0xC0, 0xAA, 0x26, + 0x06, 0x23, 0xC0, 0xAA, 0x26, 0x56, 0x26, 0x06, 0x18, 0x26, 0x01, 0x82, + 0x00, 0x0F, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x26, 0x03, 0x00, + 0x84, 0x02, 0x00, 0xB6, 0x02, 0x00, 0x53, 0x04, 0x65, 0x9B, 0x54, 0x04, + 0x5A, 0x9B, 0x9B, 0x55, 0x26, 0x06, 0x02, 0x35, 0x00, 0x25, 0x2B, 0x00, + 0x00, 0x79, 0x2C, 0xA1, 0x01, 0x7F, 0xB0, 0x26, 0x58, 0x06, 0x02, 0x35, + 0x28, 0x26, 0x05, 0x02, 0x72, 0x28, 0x38, 0x17, 0x0D, 0x06, 0x02, 0x74, + 0x28, 0x3B, 0x00, 0x00, 0x9C, 0xB8, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x72, + 0x28, 0x84, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0xB6, 0x9B, 0x84, 0x26, 0x01, + 0x0C, 0x08, 0x01, 0x0C, 0x30, 0x05, 0x02, 0x64, 0x28, 0x00, 0x00, 0xB9, + 0x06, 0x02, 0x72, 0x28, 0x06, 0x02, 0x66, 0x28, 0x00, 0x0A, 0xB8, 0x01, + 0x02, 0x0E, 0x05, 0x02, 0x72, 0x28, 0xBF, 0x03, 0x00, 0x02, 0x00, 0x95, + 0x2C, 0x0A, 0x02, 0x00, 0x94, 0x2C, 0x0F, 0x37, 0x06, 0x02, 0x73, 0x28, + 0x02, 0x00, 0x93, 0x2C, 0x0D, 0x06, 0x02, 0x6B, 0x28, 0x02, 0x00, 0x96, + 0x3C, 0x8C, 0x01, 0x20, 0xB6, 0x01, 0x00, 0x03, 0x01, 0xC1, 0x03, 0x02, + 0x02, 0x02, 0x01, 0x20, 0x0F, 0x06, 0x02, 0x70, 0x28, 0x84, 0x02, 0x02, + 0xB6, 0x02, 0x02, 0x8E, 0x2E, 0x0E, 0x02, 0x02, 0x01, 0x00, 0x0F, 0x17, + 0x06, 0x0B, 0x8D, 0x84, 0x02, 0x02, 0x30, 0x06, 0x04, 0x01, 0x7F, 0x03, + 0x01, 0x8D, 0x84, 0x02, 0x02, 0x31, 0x02, 0x02, 0x8E, 0x3E, 0x02, 0x00, + 0x92, 0x02, 0x01, 0x98, 0xBF, 0x26, 0xC3, 0x58, 0x06, 0x02, 0x62, 0x28, + 0x26, 0xCD, 0x02, 0x00, 0x01, 0x86, 0x03, 0x0A, 0x17, 0x06, 0x02, 0x62, + 0x28, 0x79, 0x02, 0x01, 0x98, 0xC1, 0x06, 0x02, 0x63, 0x28, 0x26, 0x06, + 0x81, 0x47, 0xBF, 0xAA, 0xA6, 0x03, 0x03, 0xA4, 0x03, 0x04, 0xA2, 0x03, + 0x05, 0xA5, 0x03, 0x06, 0xA7, 0x03, 0x07, 0xA3, 0x03, 0x08, 0x27, 0x03, + 0x09, 0x26, 0x06, 0x81, 0x18, 0xBF, 0x01, 0x00, 0x38, 0x0E, 0x06, 0x0F, + 0x25, 0x02, 0x03, 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x03, 0xBE, + 0x04, 0x80, 0x7F, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x02, 0x05, + 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x05, 0xBC, 0x04, 0x80, 0x6A, + 0x01, 0x83, 0xFE, 0x01, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x02, 0x04, 0x05, + 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x04, 0xBD, 0x04, 0x80, 0x53, 0x01, + 0x0D, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x06, 0x05, 0x02, 0x6C, 0x28, + 0x01, 0x00, 0x03, 0x06, 0xBA, 0x04, 0x3F, 0x01, 0x0A, 0x38, 0x0E, 0x06, + 0x0E, 0x25, 0x02, 0x07, 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x07, + 0xBA, 0x04, 0x2B, 0x01, 0x0B, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x08, + 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x08, 0xBA, 0x04, 0x17, 0x01, + 0x10, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x09, 0x05, 0x02, 0x6C, 0x28, + 0x01, 0x00, 0x03, 0x09, 0xAE, 0x04, 0x03, 0x6C, 0x28, 0x25, 0x04, 0xFE, + 0x64, 0x02, 0x04, 0x06, 0x0D, 0x02, 0x04, 0x01, 0x05, 0x0F, 0x06, 0x02, + 0x69, 0x28, 0x01, 0x01, 0x88, 0x3E, 0x9B, 0x04, 0x0C, 0xA4, 0x01, 0x05, + 0x0F, 0x06, 0x02, 0x69, 0x28, 0x01, 0x01, 0x88, 0x3E, 0x9B, 0x02, 0x01, + 0x00, 0x04, 0xB8, 0x01, 0x0C, 0x0E, 0x05, 0x02, 0x72, 0x28, 0xC1, 0x01, + 0x03, 0x0E, 0x05, 0x02, 0x6D, 0x28, 0xBF, 0x26, 0x7C, 0x3E, 0x26, 0x01, + 0x20, 0x10, 0x06, 0x02, 0x6D, 0x28, 0x40, 0x44, 0x11, 0x01, 0x01, 0x17, + 0x05, 0x02, 0x6D, 0x28, 0xC1, 0x26, 0x01, 0x81, 0x05, 0x0F, 0x06, 0x02, + 0x6D, 0x28, 0x26, 0x7E, 0x3E, 0x7D, 0x44, 0xB6, 0x92, 0x2C, 0x01, 0x86, + 0x03, 0x10, 0x03, 0x00, 0x79, 0x2C, 0xCB, 0x03, 0x01, 0x01, 0x02, 0x03, + 0x02, 0x02, 0x00, 0x06, 0x21, 0xC1, 0x26, 0x26, 0x01, 0x02, 0x0A, 0x44, + 0x01, 0x06, 0x0F, 0x37, 0x06, 0x02, 0x6D, 0x28, 0x03, 0x02, 0xC1, 0x02, + 0x01, 0x01, 0x01, 0x0B, 0x01, 0x03, 0x08, 0x0E, 0x05, 0x02, 0x6D, 0x28, + 0x04, 0x08, 0x02, 0x01, 0x06, 0x04, 0x01, 0x00, 0x03, 0x02, 0xBF, 0x26, + 0x03, 0x03, 0x26, 0x01, 0x84, 0x00, 0x0F, 0x06, 0x02, 0x6E, 0x28, 0x84, + 0x44, 0xB6, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x50, 0x26, 0x06, 0x01, + 0x28, 0x25, 0x9B, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, 0x97, + 0x02, 0x01, 0x02, 0x00, 0x39, 0x26, 0x01, 0x00, 0x0E, 0x06, 0x02, 0x60, + 0x00, 0xD0, 0x04, 0x74, 0x02, 0x01, 0x00, 0x03, 0x00, 0xC1, 0xAA, 0x26, + 0x06, 0x80, 0x43, 0xC1, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01, + 0x81, 0x7F, 0x04, 0x2E, 0x01, 0x80, 0x40, 0x38, 0x0E, 0x06, 0x07, 0x25, + 0x01, 0x83, 0xFE, 0x00, 0x04, 0x20, 0x01, 0x80, 0x41, 0x38, 0x0E, 0x06, + 0x07, 0x25, 0x01, 0x84, 0x80, 0x00, 0x04, 0x12, 0x01, 0x80, 0x42, 0x38, + 0x0E, 0x06, 0x07, 0x25, 0x01, 0x88, 0x80, 0x00, 0x04, 0x04, 0x01, 0x00, + 0x44, 0x25, 0x02, 0x00, 0x37, 0x03, 0x00, 0x04, 0xFF, 0x39, 0x9B, 0x79, + 0x2C, 0xC9, 0x05, 0x09, 0x02, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x17, 0x03, + 0x00, 0x92, 0x2C, 0x01, 0x86, 0x03, 0x10, 0x06, 0x3A, 0xBB, 0x26, 0x81, + 0x3D, 0x41, 0x25, 0x26, 0x01, 0x08, 0x0B, 0x37, 0x01, 0x8C, 0x80, 0x00, + 0x37, 0x17, 0x02, 0x00, 0x17, 0x02, 0x00, 0x01, 0x8C, 0x80, 0x00, 0x17, + 0x06, 0x19, 0x26, 0x01, 0x81, 0x7F, 0x17, 0x06, 0x05, 0x01, 0x84, 0x80, + 0x00, 0x37, 0x26, 0x01, 0x83, 0xFE, 0x00, 0x17, 0x06, 0x05, 0x01, 0x88, + 0x80, 0x00, 0x37, 0x03, 0x00, 0x04, 0x09, 0x02, 0x00, 0x01, 0x8C, 0x88, + 0x01, 0x17, 0x03, 0x00, 0x16, 0xBF, 0xAA, 0x26, 0x06, 0x23, 0xBF, 0xAA, + 0x26, 0x15, 0x26, 0x06, 0x18, 0x26, 0x01, 0x82, 0x00, 0x0F, 0x06, 0x05, + 0x01, 0x82, 0x00, 0x04, 0x01, 0x26, 0x03, 0x01, 0x84, 0x02, 0x01, 0xB6, + 0x02, 0x01, 0x12, 0x04, 0x65, 0x9B, 0x13, 0x04, 0x5A, 0x9B, 0x14, 0x9B, + 0x02, 0x00, 0x2A, 0x00, 0x00, 0xB9, 0x26, 0x5A, 0x06, 0x07, 0x25, 0x06, + 0x02, 0x66, 0x28, 0x04, 0x74, 0x00, 0x00, 0xC2, 0x01, 0x03, 0xC0, 0x44, + 0x25, 0x44, 0x00, 0x00, 0xBF, 0xC6, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, + 0xBF, 0xAA, 0x26, 0x06, 0x80, 0x50, 0xC1, 0x03, 0x01, 0xC1, 0x03, 0x02, + 0x02, 0x01, 0x01, 0x08, 0x0E, 0x06, 0x16, 0x02, 0x02, 0x01, 0x0F, 0x0C, + 0x06, 0x0D, 0x01, 0x01, 0x02, 0x02, 0x01, 0x10, 0x08, 0x0B, 0x02, 0x00, + 0x37, 0x03, 0x00, 0x04, 0x2A, 0x02, 0x01, 0x01, 0x02, 0x10, 0x02, 0x01, + 0x01, 0x06, 0x0C, 0x17, 0x02, 0x02, 0x01, 0x01, 0x0E, 0x02, 0x02, 0x01, + 0x03, 0x0E, 0x37, 0x17, 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02, 0x02, + 0x5D, 0x01, 0x02, 0x0B, 0x02, 0x01, 0x08, 0x0B, 0x37, 0x03, 0x00, 0x04, + 0xFF, 0x2C, 0x9B, 0x02, 0x00, 0x00, 0x00, 0xBF, 0x01, 0x01, 0x0E, 0x05, + 0x02, 0x65, 0x28, 0xC1, 0x01, 0x08, 0x08, 0x82, 0x2E, 0x0E, 0x05, 0x02, + 0x65, 0x28, 0x00, 0x00, 0xBF, 0x88, 0x2E, 0x05, 0x15, 0x01, 0x01, 0x0E, + 0x05, 0x02, 0x69, 0x28, 0xC1, 0x01, 0x00, 0x0E, 0x05, 0x02, 0x69, 0x28, + 0x01, 0x02, 0x88, 0x3E, 0x04, 0x1C, 0x01, 0x19, 0x0E, 0x05, 0x02, 0x69, + 0x28, 0xC1, 0x01, 0x18, 0x0E, 0x05, 0x02, 0x69, 0x28, 0x84, 0x01, 0x18, + 0xB6, 0x89, 0x84, 0x01, 0x18, 0x30, 0x05, 0x02, 0x69, 0x28, 0x00, 0x00, + 0xBF, 0x06, 0x02, 0x6A, 0x28, 0x00, 0x00, 0x01, 0x02, 0x97, 0xC2, 0x01, + 0x08, 0x0B, 0xC2, 0x08, 0x00, 0x00, 0x01, 0x03, 0x97, 0xC2, 0x01, 0x08, + 0x0B, 0xC2, 0x08, 0x01, 0x08, 0x0B, 0xC2, 0x08, 0x00, 0x00, 0x01, 0x01, + 0x97, 0xC2, 0x00, 0x00, 0x3A, 0x26, 0x58, 0x05, 0x01, 0x00, 0x25, 0xD0, + 0x04, 0x76, 0x02, 0x03, 0x00, 0x91, 0x2E, 0x03, 0x01, 0x01, 0x00, 0x26, + 0x02, 0x01, 0x0A, 0x06, 0x10, 0x26, 0x01, 0x01, 0x0B, 0x90, 0x08, 0x2C, + 0x02, 0x00, 0x0E, 0x06, 0x01, 0x00, 0x5C, 0x04, 0x6A, 0x25, 0x01, 0x7F, + 0x00, 0x00, 0x01, 0x15, 0x87, 0x3E, 0x44, 0x52, 0x25, 0x52, 0x25, 0x29, + 0x00, 0x00, 0x01, 0x01, 0x44, 0xC4, 0x00, 0x00, 0x44, 0x38, 0x97, 0x44, + 0x26, 0x06, 0x05, 0xC2, 0x25, 0x5D, 0x04, 0x78, 0x25, 0x00, 0x00, 0x26, + 0x01, 0x81, 0xAC, 0x00, 0x0E, 0x06, 0x04, 0x25, 0x01, 0x7F, 0x00, 0x9A, + 0x59, 0x00, 0x02, 0x03, 0x00, 0x79, 0x2C, 0x9A, 0x03, 0x01, 0x02, 0x01, + 0x01, 0x0F, 0x17, 0x02, 0x01, 0x01, 0x04, 0x11, 0x01, 0x0F, 0x17, 0x02, + 0x01, 0x01, 0x08, 0x11, 0x01, 0x0F, 0x17, 0x01, 0x00, 0x38, 0x0E, 0x06, + 0x10, 0x25, 0x01, 0x00, 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, + 0x01, 0x4A, 0x04, 0x81, 0x0D, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x10, 0x25, + 0x01, 0x01, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A, + 0x04, 0x80, 0x77, 0x01, 0x02, 0x38, 0x0E, 0x06, 0x10, 0x25, 0x01, 0x01, + 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A, 0x04, 0x80, + 0x61, 0x01, 0x03, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x25, 0x01, 0x10, 0x02, + 0x00, 0x06, 0x03, 0x47, 0x04, 0x01, 0x48, 0x04, 0x80, 0x4C, 0x01, 0x04, + 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x25, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, + 0x47, 0x04, 0x01, 0x48, 0x04, 0x38, 0x01, 0x05, 0x38, 0x0E, 0x06, 0x0C, + 0x25, 0x25, 0x02, 0x00, 0x06, 0x03, 0x4B, 0x04, 0x01, 0x4C, 0x04, 0x26, + 0x26, 0x01, 0x09, 0x0F, 0x06, 0x02, 0x68, 0x28, 0x44, 0x25, 0x26, 0x01, + 0x01, 0x17, 0x01, 0x04, 0x0B, 0x01, 0x10, 0x08, 0x44, 0x01, 0x08, 0x17, + 0x01, 0x10, 0x44, 0x09, 0x02, 0x00, 0x06, 0x03, 0x45, 0x04, 0x01, 0x46, + 0x00, 0x25, 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x02, 0x0F, 0x00, + 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x26, 0x5B, 0x44, 0x01, 0x03, 0x0A, 0x17, + 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x01, 0x0E, 0x00, 0x00, 0x9A, + 0x01, 0x0C, 0x11, 0x5A, 0x00, 0x00, 0x9A, 0x01, 0x81, 0x70, 0x17, 0x01, + 0x20, 0x0D, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x75, 0x2E, 0x26, 0x06, 0x22, + 0x01, 0x01, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01, 0x00, 0x9E, 0x04, 0x14, + 0x01, 0x02, 0x38, 0x0E, 0x06, 0x0D, 0x25, 0x77, 0x2E, 0x01, 0x01, 0x0E, + 0x06, 0x03, 0x01, 0x10, 0x37, 0x04, 0x01, 0x25, 0x04, 0x01, 0x25, 0x7B, + 0x2E, 0x05, 0x33, 0x2F, 0x06, 0x30, 0x86, 0x2E, 0x01, 0x14, 0x38, 0x0E, + 0x06, 0x06, 0x25, 0x01, 0x02, 0x37, 0x04, 0x22, 0x01, 0x15, 0x38, 0x0E, + 0x06, 0x09, 0x25, 0xAD, 0x06, 0x03, 0x01, 0x7F, 0x9E, 0x04, 0x13, 0x01, + 0x16, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01, 0x01, 0x37, 0x04, 0x07, 0x25, + 0x01, 0x04, 0x37, 0x01, 0x00, 0x25, 0x1A, 0x06, 0x03, 0x01, 0x08, 0x37, + 0x00, 0x00, 0x1B, 0x26, 0x05, 0x13, 0x2F, 0x06, 0x10, 0x86, 0x2E, 0x01, + 0x15, 0x0E, 0x06, 0x08, 0x25, 0xAD, 0x01, 0x00, 0x77, 0x3E, 0x04, 0x01, + 0x20, 0x00, 0x00, 0xCE, 0x01, 0x07, 0x17, 0x01, 0x01, 0x0F, 0x06, 0x02, + 0x72, 0x28, 0x00, 0x01, 0x03, 0x00, 0x29, 0x1A, 0x06, 0x05, 0x02, 0x00, + 0x87, 0x3E, 0x00, 0xCE, 0x25, 0x04, 0x74, 0x00, 0x01, 0x14, 0xD1, 0x01, + 0x01, 0xDE, 0x29, 0x26, 0x01, 0x00, 0xC8, 0x01, 0x16, 0xD1, 0xD7, 0x29, + 0x00, 0x00, 0x01, 0x0B, 0xDE, 0x4E, 0x26, 0x26, 0x01, 0x03, 0x08, 0xDD, + 0xDD, 0x18, 0x26, 0x58, 0x06, 0x02, 0x25, 0x00, 0xDD, 0x1D, 0x26, 0x06, + 0x05, 0x84, 0x44, 0xD8, 0x04, 0x77, 0x25, 0x04, 0x6C, 0x00, 0x21, 0x01, + 0x0F, 0xDE, 0x26, 0x92, 0x2C, 0x01, 0x86, 0x03, 0x10, 0x06, 0x0C, 0x01, + 0x04, 0x08, 0xDD, 0x80, 0x2E, 0xDE, 0x78, 0x2E, 0xDE, 0x04, 0x02, 0x5E, + 0xDD, 0x26, 0xDC, 0x84, 0x44, 0xD8, 0x00, 0x02, 0xA4, 0xA6, 0x08, 0xA2, + 0x08, 0xA5, 0x08, 0xA7, 0x08, 0xA3, 0x08, 0x27, 0x08, 0x03, 0x00, 0x01, + 0x01, 0xDE, 0x01, 0x27, 0x8E, 0x2E, 0x08, 0x91, 0x2E, 0x01, 0x01, 0x0B, + 0x08, 0x02, 0x00, 0x06, 0x04, 0x5E, 0x02, 0x00, 0x08, 0x83, 0x2C, 0x38, + 0x09, 0x26, 0x5B, 0x06, 0x24, 0x02, 0x00, 0x05, 0x04, 0x44, 0x5E, 0x44, + 0x5F, 0x01, 0x04, 0x09, 0x26, 0x58, 0x06, 0x03, 0x25, 0x01, 0x00, 0x26, + 0x01, 0x04, 0x08, 0x02, 0x00, 0x08, 0x03, 0x00, 0x44, 0x01, 0x04, 0x08, + 0x38, 0x08, 0x44, 0x04, 0x03, 0x25, 0x01, 0x7F, 0x03, 0x01, 0xDD, 0x94, + 0x2C, 0xDC, 0x7A, 0x01, 0x04, 0x19, 0x7A, 0x01, 0x04, 0x08, 0x01, 0x1C, + 0x32, 0x7A, 0x01, 0x20, 0xD8, 0x8D, 0x8E, 0x2E, 0xDA, 0x91, 0x2E, 0x26, + 0x01, 0x01, 0x0B, 0xDC, 0x90, 0x44, 0x26, 0x06, 0x0F, 0x5D, 0x38, 0x2C, + 0x26, 0xC7, 0x05, 0x02, 0x62, 0x28, 0xDC, 0x44, 0x5E, 0x44, 0x04, 0x6E, + 0x60, 0x01, 0x01, 0xDE, 0x01, 0x00, 0xDE, 0x02, 0x00, 0x06, 0x81, 0x5A, + 0x02, 0x00, 0xDC, 0xA4, 0x06, 0x0E, 0x01, 0x83, 0xFE, 0x01, 0xDC, 0x89, + 0xA4, 0x01, 0x04, 0x09, 0x26, 0xDC, 0x5D, 0xDA, 0xA6, 0x06, 0x16, 0x01, + 0x00, 0xDC, 0x8B, 0xA6, 0x01, 0x04, 0x09, 0x26, 0xDC, 0x01, 0x02, 0x09, + 0x26, 0xDC, 0x01, 0x00, 0xDE, 0x01, 0x03, 0x09, 0xD9, 0xA2, 0x06, 0x0C, + 0x01, 0x01, 0xDC, 0x01, 0x01, 0xDC, 0x82, 0x2E, 0x01, 0x08, 0x09, 0xDE, + 0xA5, 0x06, 0x19, 0x01, 0x0D, 0xDC, 0xA5, 0x01, 0x04, 0x09, 0x26, 0xDC, + 0x01, 0x02, 0x09, 0xDC, 0x42, 0x06, 0x03, 0x01, 0x03, 0xDB, 0x43, 0x06, + 0x03, 0x01, 0x01, 0xDB, 0xA7, 0x26, 0x06, 0x36, 0x01, 0x0A, 0xDC, 0x01, + 0x04, 0x09, 0x26, 0xDC, 0x5F, 0xDC, 0x40, 0x01, 0x00, 0x26, 0x01, 0x82, + 0x80, 0x80, 0x80, 0x00, 0x17, 0x06, 0x0A, 0x01, 0xFD, 0xFF, 0xFF, 0xFF, + 0x7F, 0x17, 0x01, 0x1D, 0xDC, 0x26, 0x01, 0x20, 0x0A, 0x06, 0x0C, 0xA0, + 0x11, 0x01, 0x01, 0x17, 0x06, 0x02, 0x26, 0xDC, 0x5C, 0x04, 0x6E, 0x60, + 0x04, 0x01, 0x25, 0xA3, 0x06, 0x0A, 0x01, 0x0B, 0xDC, 0x01, 0x02, 0xDC, + 0x01, 0x82, 0x00, 0xDC, 0x27, 0x26, 0x06, 0x1F, 0x01, 0x10, 0xDC, 0x01, + 0x04, 0x09, 0x26, 0xDC, 0x5F, 0xDC, 0x85, 0x2C, 0x01, 0x00, 0xA0, 0x0F, + 0x06, 0x0A, 0x26, 0x1E, 0x26, 0xDE, 0x84, 0x44, 0xD8, 0x5C, 0x04, 0x72, + 0x60, 0x04, 0x01, 0x25, 0x02, 0x01, 0x58, 0x05, 0x11, 0x01, 0x15, 0xDC, + 0x02, 0x01, 0x26, 0xDC, 0x26, 0x06, 0x06, 0x5D, 0x01, 0x00, 0xDE, 0x04, + 0x77, 0x25, 0x00, 0x00, 0x01, 0x10, 0xDE, 0x79, 0x2C, 0x26, 0xCC, 0x06, + 0x0C, 0xAB, 0x23, 0x26, 0x5E, 0xDD, 0x26, 0xDC, 0x84, 0x44, 0xD8, 0x04, + 0x0D, 0x26, 0xCA, 0x44, 0xAB, 0x22, 0x26, 0x5C, 0xDD, 0x26, 0xDE, 0x84, + 0x44, 0xD8, 0x00, 0x00, 0x9C, 0x01, 0x14, 0xDE, 0x01, 0x0C, 0xDD, 0x84, + 0x01, 0x0C, 0xD8, 0x00, 0x00, 0x51, 0x26, 0x01, 0x00, 0x0E, 0x06, 0x02, + 0x60, 0x00, 0xCE, 0x25, 0x04, 0x73, 0x00, 0x26, 0xDC, 0xD8, 0x00, 0x00, + 0x26, 0xDE, 0xD8, 0x00, 0x01, 0x03, 0x00, 0x41, 0x25, 0x26, 0x01, 0x10, + 0x17, 0x06, 0x06, 0x01, 0x04, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x08, + 0x17, 0x06, 0x06, 0x01, 0x03, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x20, + 0x17, 0x06, 0x06, 0x01, 0x05, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x80, + 0x40, 0x17, 0x06, 0x06, 0x01, 0x06, 0xDE, 0x02, 0x00, 0xDE, 0x01, 0x04, + 0x17, 0x06, 0x06, 0x01, 0x02, 0xDE, 0x02, 0x00, 0xDE, 0x00, 0x00, 0x26, + 0x01, 0x08, 0x4F, 0xDE, 0xDE, 0x00, 0x00, 0x26, 0x01, 0x10, 0x4F, 0xDE, + 0xDC, 0x00, 0x00, 0x26, 0x52, 0x06, 0x02, 0x25, 0x00, 0xCE, 0x25, 0x04, + 0x76 +}; + +static const uint16_t t0_caddr[] = { + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 44, + 48, + 52, + 56, + 60, + 64, + 68, + 72, + 76, + 80, + 84, + 88, + 92, + 96, + 100, + 104, + 108, + 112, + 116, + 120, + 124, + 129, + 134, + 139, + 144, + 149, + 154, + 159, + 164, + 169, + 174, + 179, + 184, + 189, + 194, + 199, + 204, + 209, + 214, + 219, + 224, + 229, + 234, + 239, + 244, + 249, + 254, + 259, + 264, + 269, + 274, + 279, + 284, + 289, + 294, + 303, + 316, + 320, + 345, + 351, + 370, + 381, + 422, + 542, + 546, + 611, + 626, + 637, + 655, + 684, + 694, + 730, + 740, + 818, + 832, + 838, + 897, + 916, + 951, + 1000, + 1076, + 1103, + 1134, + 1145, + 1497, + 1644, + 1668, + 1884, + 1898, + 1907, + 1911, + 2006, + 2027, + 2083, + 2090, + 2101, + 2117, + 2123, + 2134, + 2169, + 2181, + 2187, + 2202, + 2218, + 2411, + 2420, + 2433, + 2442, + 2449, + 2459, + 2565, + 2590, + 2603, + 2619, + 2637, + 2669, + 2703, + 3071, + 3107, + 3120, + 3134, + 3139, + 3144, + 3210, + 3218, + 3226 +}; + +#define T0_INTERPRETED 88 + +#define T0_ENTER(ip, rp, slot) do { \ + const unsigned char *t0_newip; \ + uint32_t t0_lnum; \ + t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \ + t0_lnum = t0_parse7E_unsigned(&t0_newip); \ + (rp) += t0_lnum; \ + *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \ + (ip) = t0_newip; \ + } while (0) + +#define T0_DEFENTRY(name, slot) \ +void \ +name(void *ctx) \ +{ \ + t0_context *t0ctx = ctx; \ + t0ctx->ip = &t0_codeblock[0]; \ + T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ +} + +T0_DEFENTRY(br_ssl_hs_client_init_main, 169) + +#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++) + +void +br_ssl_hs_client_run(void *t0ctx) +{ + uint32_t *dp, *rp; + const unsigned char *ip; + +#define T0_LOCAL(x) (*(rp - 2 - (x))) +#define T0_POP() (*-- dp) +#define T0_POPi() (*(int32_t *)(-- dp)) +#define T0_PEEK(x) (*(dp - 1 - (x))) +#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x))) +#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0) +#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0) +#define T0_RPOP() (*-- rp) +#define T0_RPOPi() (*(int32_t *)(-- rp)) +#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0) +#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0) +#define T0_ROLL(x) do { \ + size_t t0len = (size_t)(x); \ + uint32_t t0tmp = *(dp - 1 - t0len); \ + memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_SWAP() do { \ + uint32_t t0tmp = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_ROT() do { \ + uint32_t t0tmp = *(dp - 3); \ + *(dp - 3) = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_NROT() do { \ + uint32_t t0tmp = *(dp - 1); \ + *(dp - 1) = *(dp - 2); \ + *(dp - 2) = *(dp - 3); \ + *(dp - 3) = t0tmp; \ +} while (0) +#define T0_PICK(x) do { \ + uint32_t t0depth = (x); \ + T0_PUSH(T0_PEEK(t0depth)); \ +} while (0) +#define T0_CO() do { \ + goto t0_exit; \ +} while (0) +#define T0_RET() goto t0_next + + dp = ((t0_context *)t0ctx)->dp; + rp = ((t0_context *)t0ctx)->rp; + ip = ((t0_context *)t0ctx)->ip; + goto t0_next; + for (;;) { + uint32_t t0x; + + t0_next: + t0x = T0_NEXT(&ip); + if (t0x < T0_INTERPRETED) { + switch (t0x) { + int32_t t0off; + + case 0: /* ret */ + t0x = T0_RPOP(); + rp -= (t0x >> 16); + t0x &= 0xFFFF; + if (t0x == 0) { + ip = NULL; + goto t0_exit; + } + ip = &t0_codeblock[t0x]; + break; + case 1: /* literal constant */ + T0_PUSHi(t0_parse7E_signed(&ip)); + break; + case 2: /* read local */ + T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip))); + break; + case 3: /* write local */ + T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP(); + break; + case 4: /* jump */ + t0off = t0_parse7E_signed(&ip); + ip += t0off; + break; + case 5: /* jump if */ + t0off = t0_parse7E_signed(&ip); + if (T0_POP()) { + ip += t0off; + } + break; + case 6: /* jump if not */ + t0off = t0_parse7E_signed(&ip); + if (!T0_POP()) { + ip += t0off; + } + break; + case 7: { + /* * */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a * b); + + } + break; + case 8: { + /* + */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a + b); + + } + break; + case 9: { + /* - */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a - b); + + } + break; + case 10: { + /* < */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 11: { + /* << */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x << c); + + } + break; + case 12: { + /* <= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a <= b)); + + } + break; + case 13: { + /* <> */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a != b)); + + } + break; + case 14: { + /* = */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a == b)); + + } + break; + case 15: { + /* > */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a > b)); + + } + break; + case 16: { + /* >= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a >= b)); + + } + break; + case 17: { + /* >> */ + + int c = (int)T0_POPi(); + int32_t x = T0_POPi(); + T0_PUSHi(x >> c); + + } + break; + case 18: { + /* anchor-dn-append-name */ + + size_t len; + + len = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->append_name( + CTX->client_auth_vtable, ENG->pad, len); + } + + } + break; + case 19: { + /* anchor-dn-end-name */ + + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name( + CTX->client_auth_vtable); + } + + } + break; + case 20: { + /* anchor-dn-end-name-list */ + + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name_list( + CTX->client_auth_vtable); + } + + } + break; + case 21: { + /* anchor-dn-start-name */ + + size_t len; + + len = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name( + CTX->client_auth_vtable, len); + } + + } + break; + case 22: { + /* anchor-dn-start-name-list */ + + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name_list( + CTX->client_auth_vtable); + } + + } + break; + case 23: { + /* and */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a & b); + + } + break; + case 24: { + /* begin-cert */ + + if (ENG->chain_len == 0) { + T0_PUSHi(-1); + } else { + ENG->cert_cur = ENG->chain->data; + ENG->cert_len = ENG->chain->data_len; + ENG->chain ++; + ENG->chain_len --; + T0_PUSH(ENG->cert_len); + } + + } + break; + case 25: { + /* bzero */ + + size_t len = (size_t)T0_POP(); + void *addr = (unsigned char *)ENG + (size_t)T0_POP(); + memset(addr, 0, len); + + } + break; + case 26: { + /* can-output? */ + + T0_PUSHi(-(ENG->hlen_out > 0)); + + } + break; + case 27: { + /* co */ + T0_CO(); + } + break; + case 28: { + /* compute-Finished-inner */ + + int prf_id = T0_POP(); + int from_client = T0_POPi(); + unsigned char tmp[48]; + br_tls_prf_seed_chunk seed; + + br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id); + seed.data = tmp; + if (ENG->session.version >= BR_TLS12) { + seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp); + } else { + br_multihash_out(&ENG->mhash, br_md5_ID, tmp); + br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16); + seed.len = 36; + } + prf(ENG->pad, 12, ENG->session.master_secret, + sizeof ENG->session.master_secret, + from_client ? "client finished" : "server finished", + 1, &seed); + + } + break; + case 29: { + /* copy-cert-chunk */ + + size_t clen; + + clen = ENG->cert_len; + if (clen > sizeof ENG->pad) { + clen = sizeof ENG->pad; + } + memcpy(ENG->pad, ENG->cert_cur, clen); + ENG->cert_cur += clen; + ENG->cert_len -= clen; + T0_PUSH(clen); + + } + break; + case 30: { + /* copy-protocol-name */ + + size_t idx = T0_POP(); + size_t len = strlen(ENG->protocol_names[idx]); + memcpy(ENG->pad, ENG->protocol_names[idx], len); + T0_PUSH(len); + + } + break; + case 31: { + /* data-get8 */ + + size_t addr = T0_POP(); + T0_PUSH(t0_datablock[addr]); + + } + break; + case 32: { + /* discard-input */ + + ENG->hlen_in = 0; + + } + break; + case 33: { + /* do-client-sign */ + + size_t sig_len; + + sig_len = make_client_sign(CTX); + if (sig_len == 0) { + br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); + T0_CO(); + } + T0_PUSH(sig_len); + + } + break; + case 34: { + /* do-ecdh */ + + unsigned prf_id = T0_POP(); + unsigned ecdhe = T0_POP(); + int x; + + x = make_pms_ecdh(CTX, ecdhe, prf_id); + if (x < 0) { + br_ssl_engine_fail(ENG, -x); + T0_CO(); + } else { + T0_PUSH(x); + } + + } + break; + case 35: { + /* do-rsa-encrypt */ + + int x; + + x = make_pms_rsa(CTX, T0_POP()); + if (x < 0) { + br_ssl_engine_fail(ENG, -x); + T0_CO(); + } else { + T0_PUSH(x); + } + + } + break; + case 36: { + /* do-static-ecdh */ + + unsigned prf_id = T0_POP(); + + if (make_pms_static_ecdh(CTX, prf_id) < 0) { + br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); + T0_CO(); + } + + } + break; + case 37: { + /* drop */ + (void)T0_POP(); + } + break; + case 38: { + /* dup */ + T0_PUSH(T0_PEEK(0)); + } + break; + case 39: { + /* ext-ALPN-length */ + + size_t u, len; + + if (ENG->protocol_names_num == 0) { + T0_PUSH(0); + T0_RET(); + } + len = 6; + for (u = 0; u < ENG->protocol_names_num; u ++) { + len += 1 + strlen(ENG->protocol_names[u]); + } + T0_PUSH(len); + + } + break; + case 40: { + /* fail */ + + br_ssl_engine_fail(ENG, (int)T0_POPi()); + T0_CO(); + + } + break; + case 41: { + /* flush-record */ + + br_ssl_engine_flush_record(ENG); + + } + break; + case 42: { + /* get-client-chain */ + + uint32_t auth_types; + + auth_types = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + br_ssl_client_certificate ux; + + (*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable, + CTX, auth_types, &ux); + CTX->auth_type = (unsigned char)ux.auth_type; + CTX->hash_id = (unsigned char)ux.hash_id; + ENG->chain = ux.chain; + ENG->chain_len = ux.chain_len; + } else { + CTX->hash_id = 0; + ENG->chain_len = 0; + } + + } + break; + case 43: { + /* get-key-type-usages */ + + const br_x509_class *xc; + const br_x509_pkey *pk; + unsigned usages; + + xc = *(ENG->x509ctx); + pk = xc->get_pkey(ENG->x509ctx, &usages); + if (pk == NULL) { + T0_PUSH(0); + } else { + T0_PUSH(pk->key_type | usages); + } + + } + break; + case 44: { + /* get16 */ + + size_t addr = (size_t)T0_POP(); + T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr)); + + } + break; + case 45: { + /* get32 */ + + size_t addr = (size_t)T0_POP(); + T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr)); + + } + break; + case 46: { + /* get8 */ + + size_t addr = (size_t)T0_POP(); + T0_PUSH(*((unsigned char *)ENG + addr)); + + } + break; + case 47: { + /* has-input? */ + + T0_PUSHi(-(ENG->hlen_in != 0)); + + } + break; + case 48: { + /* memcmp */ + + size_t len = (size_t)T0_POP(); + void *addr2 = (unsigned char *)ENG + (size_t)T0_POP(); + void *addr1 = (unsigned char *)ENG + (size_t)T0_POP(); + int x = memcmp(addr1, addr2, len); + T0_PUSH((uint32_t)-(x == 0)); + + } + break; + case 49: { + /* memcpy */ + + size_t len = (size_t)T0_POP(); + void *src = (unsigned char *)ENG + (size_t)T0_POP(); + void *dst = (unsigned char *)ENG + (size_t)T0_POP(); + memcpy(dst, src, len); + + } + break; + case 50: { + /* mkrand */ + + size_t len = (size_t)T0_POP(); + void *addr = (unsigned char *)ENG + (size_t)T0_POP(); + br_hmac_drbg_generate(&ENG->rng, addr, len); + + } + break; + case 51: { + /* more-incoming-bytes? */ + + T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG)); + + } + break; + case 52: { + /* multihash-init */ + + br_multihash_init(&ENG->mhash); + + } + break; + case 53: { + /* neg */ + + uint32_t a = T0_POP(); + T0_PUSH(-a); + + } + break; + case 54: { + /* not */ + + uint32_t a = T0_POP(); + T0_PUSH(~a); + + } + break; + case 55: { + /* or */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a | b); + + } + break; + case 56: { + /* over */ + T0_PUSH(T0_PEEK(1)); + } + break; + case 57: { + /* read-chunk-native */ + + size_t clen = ENG->hlen_in; + if (clen > 0) { + uint32_t addr, len; + + len = T0_POP(); + addr = T0_POP(); + if ((size_t)len < clen) { + clen = (size_t)len; + } + memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen); + if (ENG->record_type_in == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen); + } + T0_PUSH(addr + (uint32_t)clen); + T0_PUSH(len - (uint32_t)clen); + ENG->hbuf_in += clen; + ENG->hlen_in -= clen; + } + + } + break; + case 58: { + /* read8-native */ + + if (ENG->hlen_in > 0) { + unsigned char x; + + x = *ENG->hbuf_in ++; + if (ENG->record_type_in == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, &x, 1); + } + T0_PUSH(x); + ENG->hlen_in --; + } else { + T0_PUSHi(-1); + } + + } + break; + case 59: { + /* set-server-curve */ + + const br_x509_class *xc; + const br_x509_pkey *pk; + + xc = *(ENG->x509ctx); + pk = xc->get_pkey(ENG->x509ctx, NULL); + CTX->server_curve = + (pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0; + + } + break; + case 60: { + /* set16 */ + + size_t addr = (size_t)T0_POP(); + *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP(); + + } + break; + case 61: { + /* set32 */ + + size_t addr = (size_t)T0_POP(); + *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP(); + + } + break; + case 62: { + /* set8 */ + + size_t addr = (size_t)T0_POP(); + *((unsigned char *)ENG + addr) = (unsigned char)T0_POP(); + + } + break; + case 63: { + /* strlen */ + + void *str = (unsigned char *)ENG + (size_t)T0_POP(); + T0_PUSH((uint32_t)strlen(str)); + + } + break; + case 64: { + /* supported-curves */ + + uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves; + T0_PUSH(x); + + } + break; + case 65: { + /* supported-hash-functions */ + + int i; + unsigned x, num; + + x = 0; + num = 0; + for (i = br_sha1_ID; i <= br_sha512_ID; i ++) { + if (br_multihash_getimpl(&ENG->mhash, i)) { + x |= 1U << i; + num ++; + } + } + T0_PUSH(x); + T0_PUSH(num); + + } + break; + case 66: { + /* supports-ecdsa? */ + + T0_PUSHi(-(ENG->iecdsa != 0)); + + } + break; + case 67: { + /* supports-rsa-sign? */ + + T0_PUSHi(-(ENG->irsavrfy != 0)); + + } + break; + case 68: { + /* swap */ + T0_SWAP(); + } + break; + case 69: { + /* switch-aesccm-in */ + + int is_client, prf_id; + unsigned cipher_key_len, tag_len; + + tag_len = T0_POP(); + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id, + ENG->iaes_ctrcbc, cipher_key_len, tag_len); + + } + break; + case 70: { + /* switch-aesccm-out */ + + int is_client, prf_id; + unsigned cipher_key_len, tag_len; + + tag_len = T0_POP(); + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id, + ENG->iaes_ctrcbc, cipher_key_len, tag_len); + + } + break; + case 71: { + /* switch-aesgcm-in */ + + int is_client, prf_id; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id, + ENG->iaes_ctr, cipher_key_len); + + } + break; + case 72: { + /* switch-aesgcm-out */ + + int is_client, prf_id; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id, + ENG->iaes_ctr, cipher_key_len); + + } + break; + case 73: { + /* switch-cbc-in */ + + int is_client, prf_id, mac_id, aes; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + aes = T0_POP(); + mac_id = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id, + aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len); + + } + break; + case 74: { + /* switch-cbc-out */ + + int is_client, prf_id, mac_id, aes; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + aes = T0_POP(); + mac_id = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id, + aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len); + + } + break; + case 75: { + /* switch-chapol-in */ + + int is_client, prf_id; + + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id); + + } + break; + case 76: { + /* switch-chapol-out */ + + int is_client, prf_id; + + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id); + + } + break; + case 77: { + /* test-protocol-name */ + + size_t len = T0_POP(); + size_t u; + + for (u = 0; u < ENG->protocol_names_num; u ++) { + const char *name; + + name = ENG->protocol_names[u]; + if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) { + T0_PUSH(u); + T0_RET(); + } + } + T0_PUSHi(-1); + + } + break; + case 78: { + /* total-chain-length */ + + size_t u; + uint32_t total; + + total = 0; + for (u = 0; u < ENG->chain_len; u ++) { + total += 3 + (uint32_t)ENG->chain[u].data_len; + } + T0_PUSH(total); + + } + break; + case 79: { + /* u>> */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x >> c); + + } + break; + case 80: { + /* verify-SKE-sig */ + + size_t sig_len = T0_POP(); + int use_rsa = T0_POPi(); + int hash = T0_POPi(); + + T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len)); + + } + break; + case 81: { + /* write-blob-chunk */ + + size_t clen = ENG->hlen_out; + if (clen > 0) { + uint32_t addr, len; + + len = T0_POP(); + addr = T0_POP(); + if ((size_t)len < clen) { + clen = (size_t)len; + } + memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen); + if (ENG->record_type_out == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen); + } + T0_PUSH(addr + (uint32_t)clen); + T0_PUSH(len - (uint32_t)clen); + ENG->hbuf_out += clen; + ENG->hlen_out -= clen; + } + + } + break; + case 82: { + /* write8-native */ + + unsigned char x; + + x = (unsigned char)T0_POP(); + if (ENG->hlen_out > 0) { + if (ENG->record_type_out == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, &x, 1); + } + *ENG->hbuf_out ++ = x; + ENG->hlen_out --; + T0_PUSHi(-1); + } else { + T0_PUSHi(0); + } + + } + break; + case 83: { + /* x509-append */ + + const br_x509_class *xc; + size_t len; + + xc = *(ENG->x509ctx); + len = T0_POP(); + xc->append(ENG->x509ctx, ENG->pad, len); + + } + break; + case 84: { + /* x509-end-cert */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->end_cert(ENG->x509ctx); + + } + break; + case 85: { + /* x509-end-chain */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + T0_PUSH(xc->end_chain(ENG->x509ctx)); + + } + break; + case 86: { + /* x509-start-cert */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->start_cert(ENG->x509ctx, T0_POP()); + + } + break; + case 87: { + /* x509-start-chain */ + + const br_x509_class *xc; + uint32_t bc; + + bc = T0_POP(); + xc = *(ENG->x509ctx); + xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL); + + } + break; + } + + } else { + T0_ENTER(ip, rp, t0x); + } + } +t0_exit: + ((t0_context *)t0ctx)->dp = dp; + ((t0_context *)t0ctx)->rp = rp; + ((t0_context *)t0ctx)->ip = ip; +} diff --git a/src/bearssl/src/ssl/ssl_hs_client.t0 b/src/bearssl/src/ssl/ssl_hs_client.t0 new file mode 100644 index 0000000..23b39e7 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_hs_client.t0 @@ -0,0 +1,1276 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +\ ---------------------------------------------------------------------- +\ Handshake processing code, for the client. +\ The common T0 code (ssl_hs_common.t0) shall be read first. + +preamble { + +/* + * This macro evaluates to a pointer to the client context, under that + * specific name. It must be noted that since the engine context is the + * first field of the br_ssl_client_context structure ('eng'), then + * pointers values of both types are interchangeable, modulo an + * appropriate cast. This also means that "addresses" computed as offsets + * within the structure work for both kinds of context. + */ +#define CTX ((br_ssl_client_context *)ENG) + +/* + * Generate the pre-master secret for RSA key exchange, and encrypt it + * with the server's public key. Returned value is either the encrypted + * data length (in bytes), or -x on error, with 'x' being an error code. + * + * This code assumes that the public key has been already verified (it + * was properly obtained by the X.509 engine, and it has the right type, + * i.e. it is of type RSA and suitable for encryption). + */ +static int +make_pms_rsa(br_ssl_client_context *ctx, int prf_id) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + const unsigned char *n; + unsigned char *pms; + size_t nlen, u; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + + /* + * Compute actual RSA key length, in case there are leading zeros. + */ + n = pk->key.rsa.n; + nlen = pk->key.rsa.nlen; + while (nlen > 0 && *n == 0) { + n ++; + nlen --; + } + + /* + * We need at least 59 bytes (48 bytes for pre-master secret, and + * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509 + * minimal engine normally blocks RSA keys shorter than 128 bytes, + * so this is mostly for public keys provided explicitly by the + * caller. + */ + if (nlen < 59) { + return -BR_ERR_X509_WEAK_PUBLIC_KEY; + } + if (nlen > sizeof ctx->eng.pad) { + return -BR_ERR_LIMIT_EXCEEDED; + } + + /* + * Make PMS. + */ + pms = ctx->eng.pad + nlen - 48; + br_enc16be(pms, ctx->eng.version_max); + br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46); + br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48); + + /* + * Apply PKCS#1 type 2 padding. + */ + ctx->eng.pad[0] = 0x00; + ctx->eng.pad[1] = 0x02; + ctx->eng.pad[nlen - 49] = 0x00; + br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51); + for (u = 2; u < nlen - 49; u ++) { + while (ctx->eng.pad[u] == 0) { + br_hmac_drbg_generate(&ctx->eng.rng, + &ctx->eng.pad[u], 1); + } + } + + /* + * Compute RSA encryption. + */ + if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) { + return -BR_ERR_LIMIT_EXCEEDED; + } + return (int)nlen; +} + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char *HASH_OID[] = { + BR_HASH_OID_SHA1, + BR_HASH_OID_SHA224, + BR_HASH_OID_SHA256, + BR_HASH_OID_SHA384, + BR_HASH_OID_SHA512 +}; + +/* + * Check the RSA signature on the ServerKeyExchange message. + * + * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only) + * use_rsa non-zero for RSA signature, zero for ECDSA + * sig_len signature length (in bytes); signature value is in the pad + * + * Returned value is 0 on success, or an error code. + */ +static int +verify_SKE_sig(br_ssl_client_context *ctx, + int hash, int use_rsa, size_t sig_len) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + br_multihash_context mhc; + unsigned char hv[64], head[4]; + size_t hv_len; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + br_multihash_zero(&mhc); + br_multihash_copyimpl(&mhc, &ctx->eng.mhash); + br_multihash_init(&mhc); + br_multihash_update(&mhc, + ctx->eng.client_random, sizeof ctx->eng.client_random); + br_multihash_update(&mhc, + ctx->eng.server_random, sizeof ctx->eng.server_random); + head[0] = 3; + head[1] = 0; + head[2] = ctx->eng.ecdhe_curve; + head[3] = ctx->eng.ecdhe_point_len; + br_multihash_update(&mhc, head, sizeof head); + br_multihash_update(&mhc, + ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len); + if (hash) { + hv_len = br_multihash_out(&mhc, hash, hv); + if (hv_len == 0) { + return BR_ERR_INVALID_ALGORITHM; + } + } else { + if (!br_multihash_out(&mhc, br_md5_ID, hv) + || !br_multihash_out(&mhc, br_sha1_ID, hv + 16)) + { + return BR_ERR_INVALID_ALGORITHM; + } + hv_len = 36; + } + if (use_rsa) { + unsigned char tmp[64]; + const unsigned char *hash_oid; + + if (hash) { + hash_oid = HASH_OID[hash - 2]; + } else { + hash_oid = NULL; + } + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, + hash_oid, hv_len, &pk->key.rsa, tmp) + || memcmp(tmp, hv, hv_len) != 0) + { + return BR_ERR_BAD_SIGNATURE; + } + } else { + if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec, + ctx->eng.pad, sig_len)) + { + return BR_ERR_BAD_SIGNATURE; + } + } + return 0; +} + +/* + * Perform client-side ECDH (or ECDHE). The point that should be sent to + * the server is written in the pad; returned value is either the point + * length (in bytes), or -x on error, with 'x' being an error code. + * + * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe' + * is non-zero, or from the X.509 engine context if 'ecdhe' is zero + * (for static ECDH). + */ +static int +make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) +{ + int curve; + unsigned char key[66], point[133]; + const unsigned char *order, *point_src; + size_t glen, olen, point_len, xoff, xlen; + unsigned char mask; + + if (ecdhe) { + curve = ctx->eng.ecdhe_curve; + point_src = ctx->eng.ecdhe_point; + point_len = ctx->eng.ecdhe_point_len; + } else { + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + curve = pk->key.ec.curve; + point_src = pk->key.ec.q; + point_len = pk->key.ec.qlen; + } + if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) { + return -BR_ERR_INVALID_ALGORITHM; + } + + /* + * We need to generate our key, as a non-zero random value which + * is lower than the curve order, in a "large enough" range. We + * force top bit to 0 and bottom bit to 1, which guarantees that + * the value is in the proper range. + */ + order = ctx->eng.iec->order(curve, &olen); + mask = 0xFF; + while (mask >= order[0]) { + mask >>= 1; + } + br_hmac_drbg_generate(&ctx->eng.rng, key, olen); + key[0] &= mask; + key[olen - 1] |= 0x01; + + /* + * Compute the common ECDH point, whose X coordinate is the + * pre-master secret. + */ + ctx->eng.iec->generator(curve, &glen); + if (glen != point_len) { + return -BR_ERR_INVALID_ALGORITHM; + } + + memcpy(point, point_src, glen); + if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) { + return -BR_ERR_INVALID_ALGORITHM; + } + + /* + * The pre-master secret is the X coordinate. + */ + xoff = ctx->eng.iec->xoff(curve, &xlen); + br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen); + + ctx->eng.iec->mulgen(point, key, olen, curve); + memcpy(ctx->eng.pad, point, glen); + return (int)glen; +} + +/* + * Perform full static ECDH. This occurs only in the context of client + * authentication with certificates: the server uses an EC public key, + * the cipher suite is of type ECDH (not ECDHE), the server requested a + * client certificate and accepts static ECDH, the client has a + * certificate with an EC public key in the same curve, and accepts + * static ECDH as well. + * + * Returned value is 0 on success, -1 on error. + */ +static int +make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id) +{ + unsigned char point[133]; + size_t point_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + point_len = pk->key.ec.qlen; + if (point_len > sizeof point) { + return -1; + } + memcpy(point, pk->key.ec.q, point_len); + if (!(*ctx->client_auth_vtable)->do_keyx( + ctx->client_auth_vtable, point, &point_len)) + { + return -1; + } + br_ssl_engine_compute_master(&ctx->eng, + prf_id, point, point_len); + return 0; +} + +/* + * Compute the client-side signature. This is invoked only when a + * signature-based client authentication was selected. The computed + * signature is in the pad; its length (in bytes) is returned. On + * error, 0 is returned. + */ +static size_t +make_client_sign(br_ssl_client_context *ctx) +{ + size_t hv_len; + + /* + * Compute hash of handshake messages so far. This "cannot" fail + * because the list of supported hash functions provided to the + * client certificate handler was trimmed to include only the + * hash functions that the multi-hasher supports. + */ + if (ctx->hash_id) { + hv_len = br_multihash_out(&ctx->eng.mhash, + ctx->hash_id, ctx->eng.pad); + } else { + br_multihash_out(&ctx->eng.mhash, + br_md5_ID, ctx->eng.pad); + br_multihash_out(&ctx->eng.mhash, + br_sha1_ID, ctx->eng.pad + 16); + hv_len = 36; + } + return (*ctx->client_auth_vtable)->do_sign( + ctx->client_auth_vtable, ctx->hash_id, hv_len, + ctx->eng.pad, sizeof ctx->eng.pad); +} + +} + +\ ======================================================================= + +: addr-ctx: + next-word { field } + "addr-" field + 0 1 define-word + 0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX + postpone literal postpone ; ; + +addr-ctx: min_clienthello_len +addr-ctx: hashes +addr-ctx: auth_type +addr-ctx: hash_id + +\ Length of the Secure Renegotiation extension. This is 5 for the +\ first handshake, 17 for a renegotiation (if the server supports the +\ extension), or 0 if we know that the server does not support the +\ extension. +: ext-reneg-length ( -- n ) + addr-reneg get8 dup if 1 - 17 * else drop 5 then ; + +\ Length of SNI extension. +: ext-sni-length ( -- len ) + addr-server_name strlen dup if 9 + then ; + +\ Length of Maximum Fragment Length extension. +: ext-frag-length ( -- len ) + addr-log_max_frag_len get8 14 = if 0 else 5 then ; + +\ Length of Signatures extension. +: ext-signatures-length ( -- len ) + supported-hash-functions { num } drop 0 + supports-rsa-sign? if num + then + supports-ecdsa? if num + then + dup if 1 << 6 + then ; + +\ Write supported hash functions ( sign -- ) +: write-hashes + { sign } + supported-hash-functions drop + \ We advertise hash functions in the following preference order: + \ SHA-256 SHA-224 SHA-384 SHA-512 SHA-1 + \ Rationale: + \ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures + \ -- SHA-1 is less than ideally collision-resistant + dup 0x10 and if 4 write8 sign write8 then + dup 0x08 and if 3 write8 sign write8 then + dup 0x20 and if 5 write8 sign write8 then + dup 0x40 and if 6 write8 sign write8 then + 0x04 and if 2 write8 sign write8 then ; + +\ Length of Supported Curves extension. +: ext-supported-curves-length ( -- len ) + supported-curves dup if + 0 { x } + begin dup while + dup 1 and x + >x + 1 >> + repeat + drop x 1 << 6 + + then ; + +\ Length of Supported Point Formats extension. +: ext-point-format-length ( -- len ) + supported-curves if 6 else 0 then ; + +\ Length of ALPN extension. +cc: ext-ALPN-length ( -- len ) { + size_t u, len; + + if (ENG->protocol_names_num == 0) { + T0_PUSH(0); + T0_RET(); + } + len = 6; + for (u = 0; u < ENG->protocol_names_num; u ++) { + len += 1 + strlen(ENG->protocol_names[u]); + } + T0_PUSH(len); +} + +\ Write handshake message: ClientHello +: write-ClientHello ( -- ) + { ; total-ext-length } + + \ Compute length for extensions (without the general two-byte header). + \ This does not take padding extension into account. + ext-reneg-length ext-sni-length + ext-frag-length + + ext-signatures-length + + ext-supported-curves-length + ext-point-format-length + + ext-ALPN-length + + >total-ext-length + + \ ClientHello type + 1 write8 + + \ Compute and write length + 39 addr-session_id_len get8 + addr-suites_num get8 1 << + + total-ext-length if 2+ total-ext-length + then + \ Compute padding (if requested). + addr-min_clienthello_len get16 over - dup 0> if + \ We well add a Pad ClientHello extension, which has its + \ own header (4 bytes) and might be the only extension + \ (2 extra bytes for the extension list header). + total-ext-length ifnot swap 2+ swap 2- then + \ Account for the extension header. + 4 - dup 0< if drop 0 then + \ Adjust total extension length. + dup 4 + total-ext-length + >total-ext-length + \ Adjust ClientHello length. + swap 4 + over + swap + else + drop + -1 + then + { ext-padding-amount } + write24 + + \ Protocol version + addr-version_max get16 write16 + + \ Client random + addr-client_random 4 bzero + addr-client_random 4 + 28 mkrand + addr-client_random 32 write-blob + + \ Session ID + addr-session_id addr-session_id_len get8 write-blob-head8 + + \ Supported cipher suites. We also check here that we indeed + \ support all these suites. + addr-suites_num get8 dup 1 << write16 + addr-suites_buf swap + begin + dup while 1- + over get16 + dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then + write16 + swap 2+ swap + repeat + 2drop + + \ Compression methods (only "null" compression) + 1 write8 0 write8 + + \ Extensions + total-ext-length if + total-ext-length write16 + ext-reneg-length if + 0xFF01 write16 \ extension type (0xFF01) + addr-saved_finished + ext-reneg-length 4 - dup write16 \ extension length + 1- write-blob-head8 \ verify data + then + ext-sni-length if + 0x0000 write16 \ extension type (0) + addr-server_name + ext-sni-length 4 - dup write16 \ extension length + 2 - dup write16 \ ServerNameList length + 0 write8 \ name type: host_name + 3 - write-blob-head16 \ the name itself + then + ext-frag-length if + 0x0001 write16 \ extension type (1) + 0x0001 write16 \ extension length + addr-log_max_frag_len get8 8 - write8 + then + ext-signatures-length if + 0x000D write16 \ extension type (13) + ext-signatures-length 4 - dup write16 \ extension length + 2 - write16 \ list length + supports-ecdsa? if 3 write-hashes then + supports-rsa-sign? if 1 write-hashes then + then + \ TODO: add an API to specify preference order for curves. + \ Right now we send Curve25519 first, then other curves in + \ increasing ID values (hence P-256 in second). + ext-supported-curves-length dup if + 0x000A write16 \ extension type (10) + 4 - dup write16 \ extension length + 2- write16 \ list length + supported-curves 0 + dup 0x20000000 and if + 0xDFFFFFFF and 29 write16 + then + begin dup 32 < while + dup2 >> 1 and if dup write16 then + 1+ + repeat + 2drop + else + drop + then + ext-point-format-length if + 0x000B write16 \ extension type (11) + 0x0002 write16 \ extension length + 0x0100 write16 \ value: 1 format: uncompressed + then + ext-ALPN-length dup if + 0x0010 write16 \ extension type (16) + 4 - dup write16 \ extension length + 2- write16 \ list length + addr-protocol_names_num get16 0 + begin + dup2 > while + dup copy-protocol-name + dup write8 addr-pad swap write-blob + 1+ + repeat + 2drop + else + drop + then + ext-padding-amount 0< ifnot + 0x0015 write16 \ extension value (21) + ext-padding-amount + dup write16 \ extension length + begin dup while + 1- 0 write8 repeat \ value (only zeros) + drop + then + then + ; + +\ ======================================================================= + +\ Parse server SNI extension. If present, then it should be empty. +: read-server-sni ( lim -- lim ) + read16 if ERR_BAD_SNI fail then ; + +\ Parse server Max Fragment Length extension. If present, then it should +\ advertise the same length as the client. Note that whether the server +\ sends it or not changes nothing for us: we won't send any record larger +\ than the advertised value anyway, and we will accept incoming records +\ up to our input buffer length. +: read-server-frag ( lim -- lim ) + read16 1 = ifnot ERR_BAD_FRAGLEN fail then + read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ; + +\ Parse server Secure Renegotiation extension. This is called only if +\ the client sent that extension, so we only have two cases to +\ distinguish: first handshake, and renegotiation; in the latter case, +\ we know that the server supports the extension, otherwise the client +\ would not have sent it. +: read-server-reneg ( lim -- lim ) + read16 + addr-reneg get8 ifnot + \ "reneg" is 0, so this is a first handshake. The server's + \ extension MUST be empty. We also learn that the server + \ supports the extension. + 1 = ifnot ERR_BAD_SECRENEG fail then + read8 0 = ifnot ERR_BAD_SECRENEG fail then + 2 addr-reneg set8 + else + \ "reneg" is non-zero, and we sent an extension, so it must + \ be 2 and this is a renegotiation. We must verify that + \ the extension contents have length exactly 24 bytes and + \ match the saved client and server "Finished". + 25 = ifnot ERR_BAD_SECRENEG fail then + read8 24 = ifnot ERR_BAD_SECRENEG fail then + addr-pad 24 read-blob + addr-saved_finished addr-pad 24 memcmp ifnot + ERR_BAD_SECRENEG fail + then + then ; + +\ Read the ALPN extension from the server. It must contain a single name, +\ and that name must match one of our names. +: read-ALPN-from-server ( lim -- lim ) + \ Extension contents length. + read16 open-elt + \ Length of list of names. + read16 open-elt + \ There should be a single name. + read8 addr-pad swap dup { len } read-blob + close-elt + close-elt + len test-protocol-name dup 0< if + 3 flag? if ERR_UNEXPECTED fail then + drop + else + 1+ addr-selected_protocol set16 + then ; + +\ Save a value in a 16-bit field, or check it in case of session resumption. +: check-resume ( val addr resume -- ) + if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ; + +cc: DEBUG-BLOB ( addr len -- ) { + extern int printf(const char *fmt, ...); + + size_t len = T0_POP(); + unsigned char *buf = (unsigned char *)CTX + T0_POP(); + size_t u; + + printf("BLOB:"); + for (u = 0; u < len; u ++) { + if (u % 16 == 0) { + printf("\n "); + } + printf(" %02x", buf[u]); + } + printf("\n"); +} + +\ Parse incoming ServerHello. Returned value is true (-1) on session +\ resumption. +: read-ServerHello ( -- bool ) + \ Get header, and check message type. + read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then + + \ Get protocol version. + read16 { version } + version addr-version_min get16 < version addr-version_max get16 > or if + ERR_UNSUPPORTED_VERSION fail + then + + \ Enforce chosen version for subsequent records in both directions. + version addr-version_in get16 <> if ERR_BAD_VERSION fail then + version addr-version_out set16 + + \ Server random. + addr-server_random 32 read-blob + + \ The "session resumption" flag. + 0 { resume } + + \ Session ID. + read8 { idlen } + idlen 32 > if ERR_OVERSIZED_ID fail then + addr-pad idlen read-blob + idlen addr-session_id_len get8 = idlen 0 > and if + addr-session_id addr-pad idlen memcmp if + \ Server session ID is non-empty and matches what + \ we sent, so this is a session resumption. + -1 >resume + then + then + addr-session_id addr-pad idlen memcpy + idlen addr-session_id_len set8 + + \ Record version. + version addr-version resume check-resume + + \ Cipher suite. We check that it is part of the list of cipher + \ suites that we advertised. + read16 + dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then + \ Also check that the cipher suite is compatible with the + \ announced version: suites that don't use HMAC/SHA-1 are + \ for TLS-1.2 only, not older versions. + dup use-tls12? version 0x0303 < and if ERR_BAD_CIPHER_SUITE fail then + addr-cipher_suite resume check-resume + + \ Compression method. Should be 0 (no compression). + read8 if ERR_BAD_COMPRESSION fail then + + \ Parse extensions (if any). If there is no extension, then the + \ read limit (on the TOS) should be 0 at that point. + dup if + \ Length of extension list. + \ message size. + read16 open-elt + + \ Enumerate extensions. For each of them, check that we + \ sent an extension of that type, and did not see it + \ yet; and then process it. + ext-sni-length { ok-sni } + ext-reneg-length { ok-reneg } + ext-frag-length { ok-frag } + ext-signatures-length { ok-signatures } + ext-supported-curves-length { ok-curves } + ext-point-format-length { ok-points } + ext-ALPN-length { ok-ALPN } + begin dup while + read16 + case + \ Server Name Indication. The server may + \ send such an extension if it uses the SNI + \ from the client, but that "response + \ extension" is supposed to be empty. + 0x0000 of + ok-sni ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-sni + read-server-sni + endof + + \ Max Frag Length. The contents shall be + \ a single byte whose value matches the one + \ sent by the client. + 0x0001 of + ok-frag ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-frag + read-server-frag + endof + + \ Secure Renegotiation. + 0xFF01 of + ok-reneg ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-reneg + read-server-reneg + endof + + \ Signature Algorithms. + \ Normally, the server should never send this + \ extension (so says RFC 5246 #7.4.1.4.1), + \ but some existing servers do. + 0x000D of + ok-signatures ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-signatures + read-ignore-16 + endof + + \ Supported Curves. + 0x000A of + ok-curves ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-curves + read-ignore-16 + endof + + \ Supported Point Formats. + 0x000B of + ok-points ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-points + read-ignore-16 + endof + + \ ALPN. + 0x0010 of + ok-ALPN ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-ALPN + read-ALPN-from-server + endof + + ERR_EXTRA_EXTENSION fail + endcase + repeat + + \ If we sent a secure renegotiation extension but did not + \ receive a response, then the server does not support + \ secure renegotiation. This is a hard failure if this + \ is a renegotiation. + ok-reneg if + ok-reneg 5 > if ERR_BAD_SECRENEG fail then + 1 addr-reneg set8 + then + close-elt + else + \ No extension received at all, so the server does not + \ support secure renegotiation. This is a hard failure + \ if the server was previously known to support it (i.e. + \ this is a renegotiation). + ext-reneg-length 5 > if ERR_BAD_SECRENEG fail then + 1 addr-reneg set8 + then + close-elt + resume + ; + +cc: set-server-curve ( -- ) { + const br_x509_class *xc; + const br_x509_pkey *pk; + + xc = *(ENG->x509ctx); + pk = xc->get_pkey(ENG->x509ctx, NULL); + CTX->server_curve = + (pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0; +} + +\ Read Certificate message from server. +: read-Certificate-from-server ( -- ) + addr-cipher_suite get16 expected-key-type + -1 read-Certificate + dup 0< if neg fail then + dup ifnot ERR_UNEXPECTED fail then + over and <> if ERR_WRONG_KEY_USAGE fail then + + \ Set server curve (used for static ECDH). + set-server-curve ; + +\ Verify signature on ECDHE point sent by the server. +\ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1) +\ 'use-rsa' is 0 for ECDSA, -1 for for RSA +\ 'sig-len' is the signature length (in bytes) +\ The signature itself is in the pad. +cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) { + size_t sig_len = T0_POP(); + int use_rsa = T0_POPi(); + int hash = T0_POPi(); + + T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len)); +} + +\ Parse ServerKeyExchange +: read-ServerKeyExchange ( -- ) + \ Get header, and check message type. + read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then + + \ We expect a named curve, and we must support it. + read8 3 = ifnot ERR_INVALID_ALGORITHM fail then + read16 dup addr-ecdhe_curve set8 + dup 32 >= if ERR_INVALID_ALGORITHM fail then + supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then + + \ Read the server point. + read8 + dup 133 > if ERR_INVALID_ALGORITHM fail then + dup addr-ecdhe_point_len set8 + addr-ecdhe_point swap read-blob + + \ If using TLS-1.2+, then the hash function and signature algorithm + \ are explicitly provided; the signature algorithm must match what + \ the cipher suite specifies. With TLS-1.0 and 1.1, the signature + \ algorithm is inferred from the cipher suite, and the hash is + \ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA). + addr-version get16 0x0303 >= { tls1.2+ } + addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa } + 2 { hash } + tls1.2+ if + \ Read hash function; accept only the SHA-* identifiers + \ (from SHA-1 to SHA-512, no MD5 here). + read8 + dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then + >hash + read8 + \ Get expected signature algorithm and compare with what + \ the server just sent. Expected value is 1 for RSA, 3 + \ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA, + \ 0 for ECDSA. + use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then + else + \ For MD5+SHA-1, we set 'hash' to 0. + use-rsa if 0 >hash then + then + + \ Read signature into the pad. + read16 dup { sig-len } + + dup 512 > if ERR_LIMIT_EXCEEDED fail then + addr-pad swap read-blob + + \ Verify signature. + hash use-rsa sig-len verify-SKE-sig + dup if fail then drop + + close-elt ; + +\ Client certificate: start processing of anchor names. +cc: anchor-dn-start-name-list ( -- ) { + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name_list( + CTX->client_auth_vtable); + } +} + +\ Client certificate: start a new anchor DN (length is 16-bit). +cc: anchor-dn-start-name ( length -- ) { + size_t len; + + len = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name( + CTX->client_auth_vtable, len); + } +} + +\ Client certificate: push some data for current anchor DN. +cc: anchor-dn-append-name ( length -- ) { + size_t len; + + len = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->append_name( + CTX->client_auth_vtable, ENG->pad, len); + } +} + +\ Client certificate: end current anchor DN. +cc: anchor-dn-end-name ( -- ) { + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name( + CTX->client_auth_vtable); + } +} + +\ Client certificate: end list of anchor DN. +cc: anchor-dn-end-name-list ( -- ) { + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name_list( + CTX->client_auth_vtable); + } +} + +\ Client certificate: obtain the client certificate chain. +cc: get-client-chain ( auth_types -- ) { + uint32_t auth_types; + + auth_types = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + br_ssl_client_certificate ux; + + (*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable, + CTX, auth_types, &ux); + CTX->auth_type = (unsigned char)ux.auth_type; + CTX->hash_id = (unsigned char)ux.hash_id; + ENG->chain = ux.chain; + ENG->chain_len = ux.chain_len; + } else { + CTX->hash_id = 0; + ENG->chain_len = 0; + } +} + +\ Parse CertificateRequest. Header has already been read. +: read-contents-CertificateRequest ( lim -- ) + \ Read supported client authentication types. We keep only + \ RSA, ECDSA, and ECDH. + 0 { auth_types } + read8 open-elt + begin dup while + read8 case + 1 of 0x0000FF endof + 64 of 0x00FF00 endof + 65 of 0x010000 endof + 66 of 0x020000 endof + 0 swap + endcase + auth_types or >auth_types + repeat + close-elt + + \ Full static ECDH is allowed only if the cipher suite is ECDH + \ (not ECDHE). It would be theoretically feasible to use static + \ ECDH on the client side with an ephemeral key pair from the + \ server, but RFC 4492 (section 3) forbids it because ECDHE suites + \ are supposed to provide forward secrecy, and static ECDH would + \ negate that property. + addr-cipher_suite get16 use-ecdh? ifnot + auth_types 0xFFFF and >auth_types + then + + \ Note: if the cipher suite is ECDH, then the X.509 validation + \ engine was invoked with the BR_KEYTYPE_EC | BR_KEYTYPE_KEYX + \ combination, so the server's public key has already been + \ checked to be fit for a key exchange. + + \ With TLS 1.2: + \ - rsa_fixed_ecdh and ecdsa_fixed_ecdh are synoymous. + \ - There is an explicit list of supported sign+hash. + \ With TLS 1.0, + addr-version get16 0x0303 >= if + \ With TLS 1.2: + \ - There is an explicit list of supported sign+hash. + \ - The ECDH flags must be adjusted for RSA/ECDSA + \ support. + read-list-sign-algos dup addr-hashes set32 + + \ Trim down the list depending on what hash functions + \ we support (since the hashing itself is done by the SSL + \ engine, not by the certificate handler). + supported-hash-functions drop dup 8 << or 0x030000 or and + + auth_types and + auth_types 0x030000 and if + dup 0x0000FF and if 0x010000 or then + dup 0x00FF00 and if 0x020000 or then + then + >auth_types + else + \ TLS 1.0 or 1.1. The hash function is fixed for signatures + \ (MD5+SHA-1 for RSA, SHA-1 for ECDSA). + auth_types 0x030401 and >auth_types + then + + \ Parse list of anchor DN. + anchor-dn-start-name-list + read16 open-elt + begin dup while + read16 open-elt + dup anchor-dn-start-name + + \ We read the DN by chunks through the pad, so + \ as to use the existing reading function (read-blob) + \ that also ensures proper hashing. + begin + dup while + dup 256 > if 256 else dup then { len } + addr-pad len read-blob + len anchor-dn-append-name + repeat + close-elt + anchor-dn-end-name + repeat + close-elt + anchor-dn-end-name-list + + \ We should have reached the message end. + close-elt + + \ Obtain the client chain. + auth_types get-client-chain + ; + +\ (obsolete) +\ Write an empty Certificate message. +\ : write-empty-Certificate ( -- ) +\ 11 write8 3 write24 0 write24 ; + +cc: do-rsa-encrypt ( prf_id -- nlen ) { + int x; + + x = make_pms_rsa(CTX, T0_POP()); + if (x < 0) { + br_ssl_engine_fail(ENG, -x); + T0_CO(); + } else { + T0_PUSH(x); + } +} + +cc: do-ecdh ( echde prf_id -- ulen ) { + unsigned prf_id = T0_POP(); + unsigned ecdhe = T0_POP(); + int x; + + x = make_pms_ecdh(CTX, ecdhe, prf_id); + if (x < 0) { + br_ssl_engine_fail(ENG, -x); + T0_CO(); + } else { + T0_PUSH(x); + } +} + +cc: do-static-ecdh ( prf-id -- ) { + unsigned prf_id = T0_POP(); + + if (make_pms_static_ecdh(CTX, prf_id) < 0) { + br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); + T0_CO(); + } +} + +cc: do-client-sign ( -- sig_len ) { + size_t sig_len; + + sig_len = make_client_sign(CTX); + if (sig_len == 0) { + br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); + T0_CO(); + } + T0_PUSH(sig_len); +} + +\ Write ClientKeyExchange. +: write-ClientKeyExchange ( -- ) + 16 write8 + addr-cipher_suite get16 + dup use-rsa-keyx? if + prf-id do-rsa-encrypt + dup 2+ write24 + dup write16 + addr-pad swap write-blob + else + dup use-ecdhe? swap prf-id do-ecdh + dup 1+ write24 + dup write8 + addr-pad swap write-blob + then ; + +\ Write CertificateVerify. This is invoked only if a client certificate +\ was requested and sent, and the authentication is not full static ECDH. +: write-CertificateVerify ( -- ) + do-client-sign + 15 write8 dup + addr-version get16 0x0303 >= if + 4 + write24 + addr-hash_id get8 write8 + addr-auth_type get8 write8 + else + 2+ write24 + then + dup write16 addr-pad swap write-blob ; + +\ ======================================================================= + +\ Perform a handshake. +: do-handshake ( -- ) + 0 addr-application_data set8 + 22 addr-record_type_out set8 + 0 addr-selected_protocol set16 + multihash-init + + write-ClientHello + flush-record + read-ServerHello + + if + \ Session resumption. + -1 read-CCS-Finished + -1 write-CCS-Finished + + else + + \ Not a session resumption. + + \ Read certificate; then check key type and usages against + \ cipher suite. + read-Certificate-from-server + + \ Depending on cipher suite, we may now expect a + \ ServerKeyExchange. + addr-cipher_suite get16 expected-key-type + CX 0 63 { BR_KEYTYPE_SIGN } and if + read-ServerKeyExchange + then + + \ Get next header. + read-handshake-header + + \ If this is a CertificateRequest, parse it, then read + \ next header. + dup 13 = if + drop read-contents-CertificateRequest + read-handshake-header + -1 + else + 0 + then + { seen-CR } + + \ At that point, we should have a ServerHelloDone, + \ whose length must be 0. + 14 = ifnot ERR_UNEXPECTED fail then + if ERR_BAD_HELLO_DONE fail then + + \ There should not be more bytes in the record at that point. + more-incoming-bytes? if ERR_UNEXPECTED fail then + + seen-CR if + \ If the server requested a client certificate, then + \ we must write a Certificate message (it may be + \ empty). + write-Certificate + + \ If using static ECDH, then the ClientKeyExchange + \ is empty, and there is no CertificateVerify. + \ Otherwise, there is a ClientKeyExchange; there + \ will then be a CertificateVerify if a client chain + \ was indeed sent. + addr-hash_id get8 0xFF = if + drop + 16 write8 0 write24 + addr-cipher_suite get16 prf-id do-static-ecdh + else + write-ClientKeyExchange + if write-CertificateVerify then + then + else + write-ClientKeyExchange + then + + -1 write-CCS-Finished + -1 read-CCS-Finished + then + + \ Now we should be invoked only in case of renegotiation. + 1 addr-application_data set8 + 23 addr-record_type_out set8 ; + +\ Read a HelloRequest message. +: read-HelloRequest ( -- ) + \ A HelloRequest has length 0 and type 0. + read-handshake-header-core + if ERR_UNEXPECTED fail then + if ERR_BAD_HANDSHAKE fail then ; + +\ Entry point. +: main ( -- ! ) + \ Perform initial handshake. + do-handshake + + begin + \ Wait for further invocation. At that point, we should + \ get either an explicit call for renegotiation, or + \ an incoming HelloRequest handshake message. + wait-co + dup 0x07 and case + 0x00 of + 0x10 and if + do-handshake + then + endof + 0x01 of + drop + 0 addr-application_data set8 + read-HelloRequest + \ Reject renegotiations if the peer does not + \ support secure renegotiation, or if the + \ "no renegotiation" flag is set. + addr-reneg get8 1 = 1 flag? or if + flush-record + begin can-output? not while + wait-co drop + repeat + 100 send-warning + \ We rejected the renegotiation, + \ but the connection is not dead. + \ We must set back things into + \ working "application data" state. + 1 addr-application_data set8 + 23 addr-record_type_out set8 + else + do-handshake + then + endof + ERR_UNEXPECTED fail + endcase + again + ; diff --git a/src/bearssl/src/ssl/ssl_hs_common.t0 b/src/bearssl/src/ssl/ssl_hs_common.t0 new file mode 100644 index 0000000..4674891 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_hs_common.t0 @@ -0,0 +1,1382 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +\ ---------------------------------------------------------------------- +\ This is the common T0 code for processing handshake messages (code that +\ is used by both client and server). + +preamble { + +#include +#include + +#include "inner.h" + +/* + * This macro evaluates to a pointer to the current engine context. + */ +#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu))) + +} + +\ IMPLEMENTATION NOTES +\ ==================== +\ +\ This code handles all records except application data records. +\ Application data is accepted (incoming records, outgoing payload data) +\ only when the application_data flag is set, which is done at the end +\ of the handshake; and it is cleared whenever a renegotiation or a +\ closure takes place. +\ +\ Incoming alerts are processed on the fly; fatal alerts terminate the +\ context, while warnings are ignored, except for close_notify, which +\ triggers the closure procedure. That procedure never returns (it ends +\ with an 'ERR_OK fail' call). We can thus make this processing right +\ into the read functions. +\ +\ Specific actions from the caller (closure or renegotiation) may happen +\ only when jumping back into the T0 code, i.e. just after a 'co' call. +\ Similarly, incoming record type may change only while the caller has +\ control, so we need to check that type only when returning from a 'co'. +\ +\ The handshake processor needs to defer back to the caller ('co') only +\ in one of the following situations: +\ +\ -- Some handshake data is expected. +\ +\ -- The handshake is finished, and application data may flow. There may +\ be some incoming handshake data (HelloRequest from the server). This +\ is the only situation where a renegotiation call won't be ignored. +\ +\ -- Some change-cipher-spec data is expected. +\ +\ -- An alert record is expected. Other types of incoming records will be +\ skipped. +\ +\ -- Waiting for the currently accumulated record to be sent and the +\ output buffer to become free again for another record. + +\ Placeholder for handling not yet implemented functionalities. +: NYI ( -- ! ) + "NOT YET IMPLEMENTED!" puts cr -1 fail ; + +\ Debug function that prints a string (and a newline) on stderr. +cc: DBG ( addr -- ) { + extern void *stderr; + extern int fprintf(void *, const char *, ...); + fprintf(stderr, "%s\n", &t0_datablock[T0_POPi()]); +} + +\ Debug function that prints a string and an integer value (followed +\ by a newline) on stderr. +cc: DBG2 ( addr x -- ) { + extern void *stderr; + extern int fprintf(void *, const char *, ...); + int32_t x = T0_POPi(); + fprintf(stderr, "%s: %ld (0x%08lX)\n", + &t0_datablock[T0_POPi()], (long)x, (unsigned long)(uint32_t)x); +} + +\ Mark the context as failed with a specific error code. This also +\ returns control to the caller. +cc: fail ( err -- ! ) { + br_ssl_engine_fail(ENG, (int)T0_POPi()); + T0_CO(); +} + +\ Read a byte from the context (address is offset in context). +cc: get8 ( addr -- val ) { + size_t addr = (size_t)T0_POP(); + T0_PUSH(*((unsigned char *)ENG + addr)); +} + +\ Read a 16-bit word from the context (address is offset in context). +cc: get16 ( addr -- val ) { + size_t addr = (size_t)T0_POP(); + T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr)); +} + +\ Read a 32-bit word from the context (address is offset in context). +cc: get32 ( addr -- val ) { + size_t addr = (size_t)T0_POP(); + T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr)); +} + +\ Set a byte in the context (address is offset in context). +cc: set8 ( val addr -- ) { + size_t addr = (size_t)T0_POP(); + *((unsigned char *)ENG + addr) = (unsigned char)T0_POP(); +} + +\ Set a 16-bit word in the context (address is offset in context). +cc: set16 ( val addr -- ) { + size_t addr = (size_t)T0_POP(); + *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP(); +} + +\ Set a 32-bit word in the context (address is offset in context). +cc: set32 ( val addr -- ) { + size_t addr = (size_t)T0_POP(); + *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP(); +} + +\ Define a word that evaluates as an address of a field within the +\ engine context. The field name (C identifier) must follow in the +\ source. For field 'foo', the defined word is 'addr-foo'. +: addr-eng: + next-word { field } + "addr-" field + 0 1 define-word + 0 8191 "offsetof(br_ssl_engine_context, " field + ")" + make-CX + postpone literal postpone ; ; + +addr-eng: max_frag_len +addr-eng: log_max_frag_len +addr-eng: peer_log_max_frag_len +addr-eng: shutdown_recv +addr-eng: record_type_in +addr-eng: record_type_out +addr-eng: version_in +addr-eng: version_out +addr-eng: application_data +addr-eng: version_min +addr-eng: version_max +addr-eng: suites_buf +addr-eng: suites_num +addr-eng: server_name +addr-eng: client_random +addr-eng: server_random +addr-eng: ecdhe_curve +addr-eng: ecdhe_point +addr-eng: ecdhe_point_len +addr-eng: reneg +addr-eng: saved_finished +addr-eng: flags +addr-eng: pad +addr-eng: action +addr-eng: alert +addr-eng: close_received +addr-eng: protocol_names_num +addr-eng: selected_protocol + +\ Similar to 'addr-eng:', for fields in the 'session' substructure. +: addr-session-field: + next-word { field } + "addr-" field + 0 1 define-word + 0 8191 "offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, " field + ")" + make-CX + postpone literal postpone ; ; + +addr-session-field: session_id +addr-session-field: session_id_len +addr-session-field: version +addr-session-field: cipher_suite +addr-session-field: master_secret + +\ Check a server flag by index. +: flag? ( index -- bool ) + addr-flags get32 swap >> 1 and neg ; + +\ Define a word that evaluates to an error constant. This assumes that +\ all relevant error codes are in the 0..63 range. +: err: + next-word { name } + name 0 1 define-word + 0 63 "BR_" name + make-CX postpone literal postpone ; ; + +err: ERR_OK +err: ERR_BAD_PARAM +err: ERR_BAD_STATE +err: ERR_UNSUPPORTED_VERSION +err: ERR_BAD_VERSION +err: ERR_BAD_LENGTH +err: ERR_TOO_LARGE +err: ERR_BAD_MAC +err: ERR_NO_RANDOM +err: ERR_UNKNOWN_TYPE +err: ERR_UNEXPECTED +err: ERR_BAD_CCS +err: ERR_BAD_ALERT +err: ERR_BAD_HANDSHAKE +err: ERR_OVERSIZED_ID +err: ERR_BAD_CIPHER_SUITE +err: ERR_BAD_COMPRESSION +err: ERR_BAD_FRAGLEN +err: ERR_BAD_SECRENEG +err: ERR_EXTRA_EXTENSION +err: ERR_BAD_SNI +err: ERR_BAD_HELLO_DONE +err: ERR_LIMIT_EXCEEDED +err: ERR_BAD_FINISHED +err: ERR_RESUME_MISMATCH +err: ERR_INVALID_ALGORITHM +err: ERR_BAD_SIGNATURE +err: ERR_WRONG_KEY_USAGE +err: ERR_NO_CLIENT_AUTH + +\ Get supported curves (bit mask). +cc: supported-curves ( -- x ) { + uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves; + T0_PUSH(x); +} + +\ Get supported hash functions (bit mask and number). +\ Note: this (on purpose) skips MD5. +cc: supported-hash-functions ( -- x num ) { + int i; + unsigned x, num; + + x = 0; + num = 0; + for (i = br_sha1_ID; i <= br_sha512_ID; i ++) { + if (br_multihash_getimpl(&ENG->mhash, i)) { + x |= 1U << i; + num ++; + } + } + T0_PUSH(x); + T0_PUSH(num); +} + +\ Test support for RSA signatures. +cc: supports-rsa-sign? ( -- bool ) { + T0_PUSHi(-(ENG->irsavrfy != 0)); +} + +\ Test support for ECDSA signatures. +cc: supports-ecdsa? ( -- bool ) { + T0_PUSHi(-(ENG->iecdsa != 0)); +} + +\ (Re)initialise the multihasher. +cc: multihash-init ( -- ) { + br_multihash_init(&ENG->mhash); +} + +\ Flush the current record: if some payload data has been accumulated, +\ close the record and schedule it for sending. If there is no such data, +\ this function does nothing. +cc: flush-record ( -- ) { + br_ssl_engine_flush_record(ENG); +} + +\ Yield control to the caller. +\ When the control is returned to us, react to the new context. Returned +\ value is a bitwise combination of the following: +\ 0x01 handshake data is available +\ 0x02 change-cipher-spec data is available +\ 0x04 some data other than handshake or change-cipher-spec is available +\ 0x08 output buffer is ready for a new outgoing record +\ 0x10 renegotiation is requested and not to be ignored +\ Flags 0x01, 0x02 and 0x04 are mutually exclusive. +: wait-co ( -- state ) + co + 0 + addr-action get8 dup if + case + 1 of 0 do-close endof + 2 of addr-application_data get8 1 = if + 0x10 or + then endof + endcase + else + drop + then + addr-close_received get8 ifnot + has-input? if + addr-record_type_in get8 case + + \ ChangeCipherSpec + 20 of 0x02 or endof + + \ Alert -- if close_notify received, trigger + \ the closure sequence. + 21 of process-alerts if -1 do-close then endof + + \ Handshake + 22 of 0x01 or endof + + \ Not CCS, Alert or Handshake. + drop 0x04 or 0 + endcase + then + then + can-output? if 0x08 or then ; + +\ Send an alert message. This shall be called only when there is room for +\ an outgoing record. +: send-alert ( level alert -- ) + 21 addr-record_type_out set8 + swap write8-native drop write8-native drop + flush-record ; + +\ Send an alert message of level "warning". This shall be called only when +\ there is room for an outgoing record. +: send-warning ( alert -- ) + 1 swap send-alert ; + +\ Fail by sending a fatal alert. +: fail-alert ( alert -- ! ) + { alert } + flush-record + begin can-output? not while wait-co drop repeat + 2 alert send-alert + begin can-output? not while wait-co drop repeat + alert 512 + fail ; + +\ Perform the close operation: +\ -- Prevent new application data from the caller. +\ -- Incoming data is discarded (except alerts). +\ -- Outgoing data is flushed. +\ -- A close_notify alert is sent. +\ -- If 'cnr' is zero, then incoming data is discarded until a close_notify +\ is received. +\ -- At the end, the context is terminated. +\ +\ cnr shall be either 0 or -1. +: do-close ( cnr -- ! ) + \ 'cnr' is set to non-zero when a close_notify is received from + \ the peer. + { cnr } + + \ Get out of application data state. If we were accepting + \ application data (flag is 1), and we still expect a close_notify + \ from the peer (cnr is 0), then we should set the flag to 2. + \ In all other cases, flag should be set to 0. + addr-application_data get8 cnr not and 1 << addr-application_data set8 + + \ Flush existing payload if any. + flush-record + + \ Wait for room to send the close_notify. Since individual records + \ can always hold at least 512 bytes, we know that when there is + \ room, then there is room for a complete close_notify (two bytes). + begin can-output? not while cnr wait-for-close >cnr repeat + + \ Write the close_notify and flush it. + \ 21 addr-record_type_out set8 + \ 1 write8-native 0 write8-native 2drop + \ flush-record + 0 send-warning + + \ Loop until our record has been sent (we know it's gone when + \ writing is again possible) and a close_notify has been received. + cnr + begin + dup can-output? and if ERR_OK fail then + wait-for-close + again ; + +\ Yield control to the engine, with a possible flush. If 'cnr' is 0, +\ then input is analysed: all input is discarded, until a close_notify +\ is received. +: wait-for-close ( cnr -- cnr ) + co + dup ifnot + has-input? if + addr-record_type_in get8 21 = if + drop process-alerts + \ If we received a close_notify then we + \ no longer accept incoming application + \ data records. + 0 addr-application_data set8 + else + discard-input + then + then + then ; + +\ Test whether there is some accumulated payload that still needs to be +\ sent. +cc: payload-to-send? ( -- bool ) { + T0_PUSHi(-br_ssl_engine_has_pld_to_send(ENG)); +} + +\ Test whether there is some available input data. +cc: has-input? ( -- bool ) { + T0_PUSHi(-(ENG->hlen_in != 0)); +} + +\ Test whether some payload bytes may be written. +cc: can-output? ( -- bool ) { + T0_PUSHi(-(ENG->hlen_out > 0)); +} + +\ Discard current input entirely. +cc: discard-input ( -- ) { + ENG->hlen_in = 0; +} + +\ Low-level read for one byte. If there is no available byte right +\ away, then -1 is returned. Otherwise, the byte value is returned. +\ If the current record type is "handshake" then the read byte is also +\ injected in the multi-hasher. +cc: read8-native ( -- x ) { + if (ENG->hlen_in > 0) { + unsigned char x; + + x = *ENG->hbuf_in ++; + if (ENG->record_type_in == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, &x, 1); + } + T0_PUSH(x); + ENG->hlen_in --; + } else { + T0_PUSHi(-1); + } +} + +\ Low-level read for several bytes. On entry, this expects an address +\ (offset in the engine context) and a length; these values designate +\ where the chunk should go. Upon exit, the new address and length +\ are pushed; that output length contains how many bytes could not be +\ read. If there is no available byte for reading, the address and +\ length are unchanged. +\ If the current record type is "handshake" then the read bytes are +\ injected in the multi-hasher. +cc: read-chunk-native ( addr len -- addr len ) { + size_t clen = ENG->hlen_in; + if (clen > 0) { + uint32_t addr, len; + + len = T0_POP(); + addr = T0_POP(); + if ((size_t)len < clen) { + clen = (size_t)len; + } + memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen); + if (ENG->record_type_in == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen); + } + T0_PUSH(addr + (uint32_t)clen); + T0_PUSH(len - (uint32_t)clen); + ENG->hbuf_in += clen; + ENG->hlen_in -= clen; + } +} + +\ Process available alert bytes. If a fatal alert is received, then the +\ context is terminated; otherwise, this returns either true (-1) if a +\ close_notify was received, false (0) otherwise. +: process-alerts ( -- bool ) + 0 + begin has-input? while read8-native process-alert-byte or repeat + dup if 1 addr-shutdown_recv set8 then ; + +\ Process an alert byte. Returned value is non-zero if this is a close_notify, +\ zero otherwise. +: process-alert-byte ( x -- bool ) + addr-alert get8 case + 0 of + \ 'alert' field is 0, so this byte shall be a level. + \ Levels shall be 1 (warning) or 2 (fatal); we convert + \ all other values to "fatal". + dup 1 <> if drop 2 then + addr-alert set8 0 + endof + 1 of + 0 addr-alert set8 + \ close_notify has value 0. + \ no_renegotiation has value 100, and we treat it + \ as a fatal alert. + dup 100 = if 256 + fail then + 0= + endof + \ Fatal alert implies context termination. + drop 256 + fail + endcase ; + +\ In general we only deal with handshake data here. Alerts are processed +\ in specific code right when they are received, and ChangeCipherSpec has +\ its own handling code. So we need to check that the data is "handshake" +\ only when returning from a coroutine call. + +\ Yield control to the engine. Alerts are processed; if incoming data is +\ neither handshake or alert, then an error is triggered. +: wait-for-handshake ( -- ) + wait-co 0x07 and 0x01 > if ERR_UNEXPECTED fail then ; + +\ Flush outgoing data (if any), then wait for the output buffer to be +\ clear; when this is done, set the output record type to the specified +\ value. +: wait-rectype-out ( rectype -- ) + { rectype } + flush-record + begin + can-output? if rectype addr-record_type_out set8 ret then + wait-co drop + again ; + +\ Read one byte of handshake data. Block until that byte is available. +\ This does not check any length. +: read8-nc ( -- x ) + begin + read8-native dup 0< ifnot ret then + drop wait-for-handshake + again ; + +\ Test whether there are some more bytes in the current record. These +\ bytes have not necessarily been received yet (processing of unencrypted +\ records may begin before all bytes are received). +cc: more-incoming-bytes? ( -- bool ) { + T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG)); +} + +\ For reading functions, the TOS is supposed to contain the number of bytes +\ that can still be read (from encapsulating structure header), and it is +\ updated. + +: check-len ( lim len -- lim ) + - dup 0< if ERR_BAD_PARAM fail then ; + +\ Read one byte of handshake data. This pushes an integer in the 0..255 range. +: read8 ( lim -- lim x ) + 1 check-len read8-nc ; + +\ Read a 16-bit value (in the 0..65535 range) +: read16 ( lim -- lim n ) + 2 check-len read8-nc 8 << read8-nc + ; + +\ Read a 24-bit value (in the 0..16777215 range) +: read24 ( lim -- lim n ) + 3 check-len read8-nc 8 << read8-nc + 8 << read8-nc + ; + +\ Read some bytes. The "address" is an offset within the context +\ structure. +: read-blob ( lim addr len -- lim ) + { addr len } + len check-len + addr len + begin + read-chunk-native + dup 0 = if 2drop ret then + wait-for-handshake + again ; + +\ Read some bytes and drop them. +: skip-blob ( lim len -- lim ) + swap over check-len swap + begin dup while read8-nc drop 1- repeat + drop ; + +\ Read a 16-bit length, then skip exactly that many bytes. +: read-ignore-16 ( lim -- lim ) + read16 skip-blob ; + +\ Open a substructure: the inner structure length is checked against, +\ and subtracted, from the output structure current limit. +: open-elt ( lim len -- lim-outer lim-inner ) + dup { len } + - dup 0< if ERR_BAD_PARAM fail then + len ; + +\ Close the current structure. This checks that the limit is 0. +: close-elt ( lim -- ) + if ERR_BAD_PARAM fail then ; + +\ Write one byte of handshake data. +: write8 ( n -- ) + begin + dup write8-native if drop ret then + wait-co drop + again ; + +\ Low-level write for one byte. On exit, it pushes either -1 (byte was +\ written) or 0 (no room in output buffer). +cc: write8-native ( x -- bool ) { + unsigned char x; + + x = (unsigned char)T0_POP(); + if (ENG->hlen_out > 0) { + if (ENG->record_type_out == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, &x, 1); + } + *ENG->hbuf_out ++ = x; + ENG->hlen_out --; + T0_PUSHi(-1); + } else { + T0_PUSHi(0); + } +} + +\ Write a 16-bit value. +: write16 ( n -- ) + dup 8 u>> write8 write8 ; + +\ Write a 24-bit value. +: write24 ( n -- ) + dup 16 u>> write8 write16 ; + +\ Write some bytes. The "address" is an offset within the context +\ structure. +: write-blob ( addr len -- ) + begin + write-blob-chunk + dup 0 = if 2drop ret then + wait-co drop + again ; + +cc: write-blob-chunk ( addr len -- addr len ) { + size_t clen = ENG->hlen_out; + if (clen > 0) { + uint32_t addr, len; + + len = T0_POP(); + addr = T0_POP(); + if ((size_t)len < clen) { + clen = (size_t)len; + } + memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen); + if (ENG->record_type_out == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen); + } + T0_PUSH(addr + (uint32_t)clen); + T0_PUSH(len - (uint32_t)clen); + ENG->hbuf_out += clen; + ENG->hlen_out -= clen; + } +} + +\ Write a blob with the length as header (over one byte) +: write-blob-head8 ( addr len -- ) + dup write8 write-blob ; + +\ Write a blob with the length as header (over two bytes) +: write-blob-head16 ( addr len -- ) + dup write16 write-blob ; + +\ Perform a byte-to-byte comparison between two blobs. Each blob is +\ provided as an "address" (offset in the context structure); the +\ length is common. Returned value is true (-1) if the two blobs are +\ equal, false (0) otherwise. +cc: memcmp ( addr1 addr2 len -- bool ) { + size_t len = (size_t)T0_POP(); + void *addr2 = (unsigned char *)ENG + (size_t)T0_POP(); + void *addr1 = (unsigned char *)ENG + (size_t)T0_POP(); + int x = memcmp(addr1, addr2, len); + T0_PUSH((uint32_t)-(x == 0)); +} + +\ Copy bytes between two areas, whose addresses are provided as +\ offsets in the context structure. +cc: memcpy ( dst src len -- ) { + size_t len = (size_t)T0_POP(); + void *src = (unsigned char *)ENG + (size_t)T0_POP(); + void *dst = (unsigned char *)ENG + (size_t)T0_POP(); + memcpy(dst, src, len); +} + +\ Get string length (zero-terminated). The string address is provided as +\ an offset relative to the context start. Returned length does not include +\ the terminated 0. +cc: strlen ( str -- len ) { + void *str = (unsigned char *)ENG + (size_t)T0_POP(); + T0_PUSH((uint32_t)strlen(str)); +} + +\ Fill a buffer with zeros. The buffer address is an offset in the context. +cc: bzero ( addr len -- ) { + size_t len = (size_t)T0_POP(); + void *addr = (unsigned char *)ENG + (size_t)T0_POP(); + memset(addr, 0, len); +} + +\ Scan the list of supported cipher suites for a given value. If found, +\ then the list index at which it was found is returned; otherwise, -1 +\ is returned. +: scan-suite ( suite -- index ) + { suite } + addr-suites_num get8 { num } + 0 + begin dup num < while + dup 1 << addr-suites_buf + get16 suite = if ret then + 1+ + repeat + drop -1 ; + +\ ======================================================================= + +\ Generate random bytes into buffer (address is offset in context). +cc: mkrand ( addr len -- ) { + size_t len = (size_t)T0_POP(); + void *addr = (unsigned char *)ENG + (size_t)T0_POP(); + br_hmac_drbg_generate(&ENG->rng, addr, len); +} + +\ Read a handshake message header: type and length. These are returned +\ in reverse order (type is TOS, length is below it). +: read-handshake-header-core ( -- lim type ) + read8-nc 3 read24 swap drop swap ; + +\ Read a handshake message header: type and length. If the header is for +\ a HelloRequest message, then it is discarded and a new header is read +\ (repeatedly if necessary). +: read-handshake-header ( -- lim type ) + begin + read-handshake-header-core dup 0= while + drop if ERR_BAD_HANDSHAKE fail then + repeat ; + +\ ======================================================================= + +\ Cipher suite processing. +\ +\ Unfortunately, cipher suite identifiers are attributed mostly arbitrary, +\ so we have to map the cipher suite numbers we support into aggregate +\ words that encode the information we need. Table below is organized +\ as a sequence of pairs of 16-bit words, the first being the cipher suite +\ identifier, the second encoding the algorithm elements. The suites are +\ ordered by increasing cipher suite ID, so that fast lookups may be +\ performed with a binary search (not implemented for the moment, since it +\ does not appear to matter much in practice). +\ +\ Algorithm elements are encoded over 4 bits each, in the following order +\ (most significant to least significant): +\ +\ -- Server key type: +\ 0 RSA (RSA key exchange) +\ 1 ECDHE-RSA (ECDHE key exchange, RSA signature) +\ 2 ECDHE-ECDSA (ECDHE key exchange, ECDSA signature) +\ 3 ECDH-RSA (ECDH key exchange, certificate is RSA-signed) +\ 4 ECDH-ECDSA (ECDH key exchange, certificate is ECDSA-signed) +\ -- Encryption algorithm: +\ 0 3DES/CBC +\ 1 AES-128/CBC +\ 2 AES-256/CBC +\ 3 AES-128/GCM +\ 4 AES-256/GCM +\ 5 ChaCha20/Poly1305 +\ 6 AES-128/CCM +\ 7 AES-256/CCM +\ 8 AES-128/CCM8 +\ 9 AES-256/CCM8 +\ -- MAC algorithm: +\ 0 none (for suites with AEAD encryption) +\ 2 HMAC/SHA-1 +\ 4 HMAC/SHA-256 +\ 5 HMAC/SHA-384 +\ -- PRF for TLS-1.2: +\ 4 with SHA-256 +\ 5 with SHA-384 +\ +\ WARNING: if adding a new cipher suite that does not use SHA-256 for the +\ PRF (with TLS 1.2), be sure to check the suites_sha384[] array defined +\ in ssl/ssl_keyexport.c + +data: cipher-suite-def + +hexb| 000A 0024 | \ TLS_RSA_WITH_3DES_EDE_CBC_SHA +hexb| 002F 0124 | \ TLS_RSA_WITH_AES_128_CBC_SHA +hexb| 0035 0224 | \ TLS_RSA_WITH_AES_256_CBC_SHA +hexb| 003C 0144 | \ TLS_RSA_WITH_AES_128_CBC_SHA256 +hexb| 003D 0244 | \ TLS_RSA_WITH_AES_256_CBC_SHA256 + +hexb| 009C 0304 | \ TLS_RSA_WITH_AES_128_GCM_SHA256 +hexb| 009D 0405 | \ TLS_RSA_WITH_AES_256_GCM_SHA384 + +hexb| C003 4024 | \ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA +hexb| C004 4124 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA +hexb| C005 4224 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA +hexb| C008 2024 | \ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA +hexb| C009 2124 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA +hexb| C00A 2224 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA +hexb| C00D 3024 | \ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA +hexb| C00E 3124 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA +hexb| C00F 3224 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA +hexb| C012 1024 | \ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA +hexb| C013 1124 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA +hexb| C014 1224 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + +hexb| C023 2144 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 +hexb| C024 2255 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 +hexb| C025 4144 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 +hexb| C026 4255 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 +hexb| C027 1144 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 +hexb| C028 1255 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 +hexb| C029 3144 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 +hexb| C02A 3255 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 +hexb| C02B 2304 | \ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 +hexb| C02C 2405 | \ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +hexb| C02D 4304 | \ TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 +hexb| C02E 4405 | \ TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 +hexb| C02F 1304 | \ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +hexb| C030 1405 | \ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +hexb| C031 3304 | \ TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 +hexb| C032 3405 | \ TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + +hexb| C09C 0604 | \ TLS_RSA_WITH_AES_128_CCM +hexb| C09D 0704 | \ TLS_RSA_WITH_AES_256_CCM +hexb| C0A0 0804 | \ TLS_RSA_WITH_AES_128_CCM_8 +hexb| C0A1 0904 | \ TLS_RSA_WITH_AES_256_CCM_8 +hexb| C0AC 2604 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM +hexb| C0AD 2704 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM +hexb| C0AE 2804 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 +hexb| C0AF 2904 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 + +hexb| CCA8 1504 | \ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 +hexb| CCA9 2504 | \ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + +hexb| 0000 | \ List terminator. + +\ Convert cipher suite identifier to element words. This returns 0 if +\ the cipher suite is not known. +: cipher-suite-to-elements ( suite -- elts ) + { id } + cipher-suite-def + begin + dup 2+ swap data-get16 + dup ifnot 2drop 0 ret then + id = if data-get16 ret then + 2+ + again ; + +\ Check that a given cipher suite is supported. Note that this also +\ returns true (-1) for the TLS_FALLBACK_SCSV pseudo-ciphersuite. +: suite-supported? ( suite -- bool ) + dup 0x5600 = if drop -1 ret then + cipher-suite-to-elements 0<> ; + +\ Get expected key type for cipher suite. The key type is one of +\ BR_KEYTYPE_RSA or BR_KEYTYPE_EC, combined with either BR_KEYTYPE_KEYX +\ (RSA encryption or static ECDH) or BR_KEYTYPE_SIGN (RSA or ECDSA +\ signature, for ECDHE cipher suites). +: expected-key-type ( suite -- key-type ) + cipher-suite-to-elements 12 >> + case + 0 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX } endof + 1 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN } endof + 2 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_SIGN } endof + 3 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof + 4 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof + 0 swap + endcase ; + +\ Test whether the cipher suite uses RSA key exchange. +: use-rsa-keyx? ( suite -- bool ) + cipher-suite-to-elements 12 >> 0= ; + +\ Test whether the cipher suite uses ECDHE key exchange, signed with RSA. +: use-rsa-ecdhe? ( suite -- bool ) + cipher-suite-to-elements 12 >> 1 = ; + +\ Test whether the cipher suite uses ECDHE key exchange, signed with ECDSA. +: use-ecdsa-ecdhe? ( suite -- bool ) + cipher-suite-to-elements 12 >> 2 = ; + +\ Test whether the cipher suite uses ECDHE key exchange (with RSA or ECDSA). +: use-ecdhe? ( suite -- bool ) + cipher-suite-to-elements 12 >> dup 0> swap 3 < and ; + +\ Test whether the cipher suite uses ECDH (static) key exchange. +: use-ecdh? ( suite -- bool ) + cipher-suite-to-elements 12 >> 2 > ; + +\ Get identifier for the PRF (TLS 1.2). +: prf-id ( suite -- id ) + cipher-suite-to-elements 15 and ; + +\ Test whether a cipher suite is only for TLS-1.2. Cipher suites that +\ can be used with TLS-1.0 or 1.1 use HMAC/SHA-1. RFC do not formally +\ forbid using a CBC-based TLS-1.2 cipher suite, e.g. based on HMAC/SHA-256, +\ with older protocol versions; however, servers should not do that, since +\ it may confuse clients. Since the server code does not try such games, +\ for consistency, the client should reject it as well (normal servers +\ don't do that, so any attempt is a sign of foul play). +: use-tls12? ( suite -- bool ) + cipher-suite-to-elements 0xF0 and 0x20 <> ; + +\ Switch to negotiated security parameters for input or output. +: switch-encryption ( is-client for-input -- ) + { for-input } + addr-cipher_suite get16 cipher-suite-to-elements { elts } + + \ prf_id + elts 15 and + + \ mac_id + elts 4 >> 15 and + + \ cipher type and key length + elts 8 >> 15 and case + \ 3DES/CBC + 0 of 0 24 + for-input if + switch-cbc-in + else + switch-cbc-out + then + endof + + \ AES-128/CBC + 1 of 1 16 + for-input if + switch-cbc-in + else + switch-cbc-out + then + endof + + \ AES-256/CBC + 2 of 1 32 + for-input if + switch-cbc-in + else + switch-cbc-out + then + endof + + \ AES-128/GCM + 3 of drop 16 + for-input if + switch-aesgcm-in + else + switch-aesgcm-out + then + endof + + \ AES-256/GCM + 4 of drop 32 + for-input if + switch-aesgcm-in + else + switch-aesgcm-out + then + endof + + \ ChaCha20+Poly1305 + 5 of drop + for-input if + switch-chapol-in + else + switch-chapol-out + then + endof + + \ Now we only have AES/CCM suites (6 to 9). Since the + \ input is between 0 and 15, and we checked values 0 to 5, + \ we only need to reject values larger than 9. + dup 9 > if + ERR_BAD_PARAM fail + then + + \ Stack: is_client prf_id mac_id cipher_id + \ We want to remove the mac_id (it is zero for CCM suites) + \ and replace the cipher_id with the key and tag lengths. + \ The following table applies: + \ id key length tag length + \ 6 16 16 + \ 7 32 16 + \ 8 16 8 + \ 9 32 8 + swap drop + dup 1 and 4 << 16 + swap + 8 and 16 swap - + for-input if + switch-aesccm-in + else + switch-aesccm-out + then + ret + endcase + ; + +cc: switch-cbc-out ( is_client prf_id mac_id aes cipher_key_len -- ) { + int is_client, prf_id, mac_id, aes; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + aes = T0_POP(); + mac_id = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id, + aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len); +} + +cc: switch-cbc-in ( is_client prf_id mac_id aes cipher_key_len -- ) { + int is_client, prf_id, mac_id, aes; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + aes = T0_POP(); + mac_id = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id, + aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len); +} + +cc: switch-aesgcm-out ( is_client prf_id cipher_key_len -- ) { + int is_client, prf_id; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id, + ENG->iaes_ctr, cipher_key_len); +} + +cc: switch-aesgcm-in ( is_client prf_id cipher_key_len -- ) { + int is_client, prf_id; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id, + ENG->iaes_ctr, cipher_key_len); +} + +cc: switch-chapol-out ( is_client prf_id -- ) { + int is_client, prf_id; + + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id); +} + +cc: switch-chapol-in ( is_client prf_id -- ) { + int is_client, prf_id; + + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id); +} + +cc: switch-aesccm-out ( is_client prf_id cipher_key_len tag_len -- ) { + int is_client, prf_id; + unsigned cipher_key_len, tag_len; + + tag_len = T0_POP(); + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id, + ENG->iaes_ctrcbc, cipher_key_len, tag_len); +} + +cc: switch-aesccm-in ( is_client prf_id cipher_key_len tag_len -- ) { + int is_client, prf_id; + unsigned cipher_key_len, tag_len; + + tag_len = T0_POP(); + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id, + ENG->iaes_ctrcbc, cipher_key_len, tag_len); +} + +\ Write Finished message. +: write-Finished ( from_client -- ) + compute-Finished + 20 write8 12 write24 addr-pad 12 write-blob ; + +\ Read Finished message. +: read-Finished ( from_client -- ) + compute-Finished + read-handshake-header 20 <> if ERR_UNEXPECTED fail then + addr-pad 12 + 12 read-blob + close-elt + addr-pad dup 12 + 12 memcmp ifnot ERR_BAD_FINISHED fail then ; + +\ Compute the "Finished" contents (either the value to send, or the +\ expected value). The 12-byte string is written in the pad. The +\ "from_client" value is non-zero for the Finished sent by the client. +\ The computed value is also saved in the relevant buffer for handling +\ secure renegotiation. +: compute-Finished ( from_client -- ) + dup addr-saved_finished swap ifnot 12 + then swap + addr-cipher_suite get16 prf-id compute-Finished-inner + addr-pad 12 memcpy ; + +cc: compute-Finished-inner ( from_client prf_id -- ) { + int prf_id = T0_POP(); + int from_client = T0_POPi(); + unsigned char tmp[48]; + br_tls_prf_seed_chunk seed; + + br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id); + seed.data = tmp; + if (ENG->session.version >= BR_TLS12) { + seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp); + } else { + br_multihash_out(&ENG->mhash, br_md5_ID, tmp); + br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16); + seed.len = 36; + } + prf(ENG->pad, 12, ENG->session.master_secret, + sizeof ENG->session.master_secret, + from_client ? "client finished" : "server finished", + 1, &seed); +} + +\ Receive ChangeCipherSpec and Finished from the peer. +: read-CCS-Finished ( is-client -- ) + has-input? if + addr-record_type_in get8 20 <> if ERR_UNEXPECTED fail then + else + begin + wait-co 0x07 and dup 0x02 <> while + if ERR_UNEXPECTED fail then + repeat + drop + then + read8-nc 1 <> more-incoming-bytes? or if ERR_BAD_CCS fail then + dup 1 switch-encryption + + \ Read and verify Finished from peer. + not read-Finished ; + +\ Send ChangeCipherSpec and Finished to the peer. +: write-CCS-Finished ( is-client -- ) + \ Flush and wait for output buffer to be clear, so that we may + \ write our ChangeCipherSpec. We must switch immediately after + \ triggering the flush. + 20 wait-rectype-out + 1 write8 + flush-record + dup 0 switch-encryption + 22 wait-rectype-out + write-Finished + flush-record ; + +\ Read and parse a list of supported signature algorithms (with hash +\ functions). The resulting bit field is returned. +: read-list-sign-algos ( lim -- lim value ) + 0 { hashes } + read16 open-elt + begin dup while + read8 { hash } read8 { sign } + + \ If hash is 0x08 then this is a "new algorithm" identifier, + \ and we set the corresponding bit if it is in the 0..15 + \ range. Otherwise, we keep the value only if the signature + \ is either 1 (RSA) or 3 (ECDSA), and the hash is one of the + \ SHA-* functions (2 to 6). Note that we reject MD5. + hash 8 = if + sign 15 <= if + 1 sign 16 + << hashes or >hashes + then + else + hash 2 >= hash 6 <= and + sign 1 = sign 3 = or + and if + hashes 1 sign 1- 2 << hash + << or >hashes + then + then + repeat + close-elt + hashes ; + +\ ======================================================================= + +\ Compute total chain length. This includes the individual certificate +\ headers, but not the total chain header. This also sets the cert_cur, +\ cert_len and chain_len context fields. +cc: total-chain-length ( -- len ) { + size_t u; + uint32_t total; + + total = 0; + for (u = 0; u < ENG->chain_len; u ++) { + total += 3 + (uint32_t)ENG->chain[u].data_len; + } + T0_PUSH(total); +} + +\ Get length for current certificate in the chain; if the chain end was +\ reached, then this returns -1. +cc: begin-cert ( -- len ) { + if (ENG->chain_len == 0) { + T0_PUSHi(-1); + } else { + ENG->cert_cur = ENG->chain->data; + ENG->cert_len = ENG->chain->data_len; + ENG->chain ++; + ENG->chain_len --; + T0_PUSH(ENG->cert_len); + } +} + +\ Copy a chunk of certificate data into the pad. Returned value is the +\ chunk length, or 0 if the certificate end is reached. +cc: copy-cert-chunk ( -- len ) { + size_t clen; + + clen = ENG->cert_len; + if (clen > sizeof ENG->pad) { + clen = sizeof ENG->pad; + } + memcpy(ENG->pad, ENG->cert_cur, clen); + ENG->cert_cur += clen; + ENG->cert_len -= clen; + T0_PUSH(clen); +} + +\ Write a Certificate message. Total chain length (excluding the 3-byte +\ header) is returned; it is 0 if the chain is empty. +: write-Certificate ( -- total_chain_len ) + 11 write8 + total-chain-length dup + dup 3 + write24 write24 + begin + begin-cert + dup 0< if drop ret then write24 + begin copy-cert-chunk dup while + addr-pad swap write-blob + repeat + drop + again ; + +cc: x509-start-chain ( by_client -- ) { + const br_x509_class *xc; + uint32_t bc; + + bc = T0_POP(); + xc = *(ENG->x509ctx); + xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL); +} + +cc: x509-start-cert ( length -- ) { + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->start_cert(ENG->x509ctx, T0_POP()); +} + +cc: x509-append ( length -- ) { + const br_x509_class *xc; + size_t len; + + xc = *(ENG->x509ctx); + len = T0_POP(); + xc->append(ENG->x509ctx, ENG->pad, len); +} + +cc: x509-end-cert ( -- ) { + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->end_cert(ENG->x509ctx); +} + +cc: x509-end-chain ( -- err ) { + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + T0_PUSH(xc->end_chain(ENG->x509ctx)); +} + +cc: get-key-type-usages ( -- key-type-usages ) { + const br_x509_class *xc; + const br_x509_pkey *pk; + unsigned usages; + + xc = *(ENG->x509ctx); + pk = xc->get_pkey(ENG->x509ctx, &usages); + if (pk == NULL) { + T0_PUSH(0); + } else { + T0_PUSH(pk->key_type | usages); + } +} + +\ Read a Certificate message. +\ Parameter: non-zero if this is a read by the client of a certificate +\ sent by the server; zero otherwise. +\ Returned value: +\ - Empty: 0 +\ - Valid: combination of key type and allowed key usages. +\ - Invalid: negative (-x for error code x) +: read-Certificate ( by_client -- key-type-usages ) + \ Get header, and check message type. + read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then + + \ If the chain is empty, do some special processing. + dup 3 = if + read24 if ERR_BAD_PARAM fail then + swap drop ret + then + + \ Start processing the chain through the X.509 engine. + swap x509-start-chain + + \ Total chain length is a 24-bit integer. + read24 open-elt + begin + dup while + read24 open-elt + dup x509-start-cert + + \ We read the certificate by chunks through the pad, so + \ as to use the existing reading function (read-blob) + \ that also ensures proper hashing. + begin + dup while + dup 256 > if 256 else dup then { len } + addr-pad len read-blob + len x509-append + repeat + close-elt + x509-end-cert + repeat + + \ We must close the chain AND the handshake message. + close-elt + close-elt + + \ Chain processing is finished; get the error code. + x509-end-chain + dup if neg ret then drop + + \ Return key type and usages. + get-key-type-usages ; + +\ ======================================================================= + +\ Copy a specific protocol name from the list to the pad. The byte +\ length is returned. +cc: copy-protocol-name ( idx -- len ) { + size_t idx = T0_POP(); + size_t len = strlen(ENG->protocol_names[idx]); + memcpy(ENG->pad, ENG->protocol_names[idx], len); + T0_PUSH(len); +} + +\ Compare name in pad with the configured list of protocol names. +\ If a match is found, then the index is returned; otherwise, -1 +\ is returned. +cc: test-protocol-name ( len -- n ) { + size_t len = T0_POP(); + size_t u; + + for (u = 0; u < ENG->protocol_names_num; u ++) { + const char *name; + + name = ENG->protocol_names[u]; + if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) { + T0_PUSH(u); + T0_RET(); + } + } + T0_PUSHi(-1); +} diff --git a/src/bearssl/src/ssl/ssl_hs_server.c b/src/bearssl/src/ssl/ssl_hs_server.c new file mode 100644 index 0000000..5f8cae7 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_hs_server.c @@ -0,0 +1,2009 @@ +/* Automatically generated code; do not modify directly. */ + +#include +#include + +typedef struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; +} t0_context; + +static uint32_t +t0_parse7E_unsigned(const unsigned char **p) +{ + uint32_t x; + + x = 0; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + return x; + } + } +} + +static int32_t +t0_parse7E_signed(const unsigned char **p) +{ + int neg; + uint32_t x; + + neg = ((**p) >> 6) & 1; + x = (uint32_t)-neg; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + if (neg) { + return -(int32_t)~x - 1; + } else { + return (int32_t)x; + } + } + } +} + +#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80) +#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F) +#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8) +#define T0_INT1(x) T0_FBYTE(x, 0) +#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) + +/* static const unsigned char t0_datablock[]; */ + + +void br_ssl_hs_server_init_main(void *t0ctx); + +void br_ssl_hs_server_run(void *t0ctx); + + + +#include +#include + +#include "inner.h" + +/* + * This macro evaluates to a pointer to the current engine context. + */ +#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu))) + + + + + +/* + * This macro evaluates to a pointer to the server context, under that + * specific name. It must be noted that since the engine context is the + * first field of the br_ssl_server_context structure ('eng'), then + * pointers values of both types are interchangeable, modulo an + * appropriate cast. This also means that "addresses" computed as offsets + * within the structure work for both kinds of context. + */ +#define CTX ((br_ssl_server_context *)ENG) + +/* + * Decrypt the pre-master secret (RSA key exchange). + */ +static void +do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id, + unsigned char *epms, size_t len) +{ + uint32_t x; + unsigned char rpms[48]; + + /* + * Decrypt the PMS. + */ + x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len); + + /* + * Set the first two bytes to the maximum supported client + * protocol version. These bytes are used for version rollback + * detection; forceing the two bytes will make the master secret + * wrong if the bytes are not correct. This process is + * recommended by RFC 5246 (section 7.4.7.1). + */ + br_enc16be(epms, ctx->client_max_version); + + /* + * Make a random PMS and copy it above the decrypted value if the + * decryption failed. Note that we use a constant-time conditional + * copy. + */ + br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms); + br_ccopy(x ^ 1, epms, rpms, sizeof rpms); + + /* + * Compute master secret. + */ + br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48); + + /* + * Clear the pre-master secret from RAM: it is normally a buffer + * in the context, hence potentially long-lived. + */ + memset(epms, 0, len); +} + +/* + * Common part for ECDH and ECDHE. + */ +static void +ecdh_common(br_ssl_server_context *ctx, int prf_id, + unsigned char *xcoor, size_t xcoor_len, uint32_t ctl) +{ + unsigned char rpms[80]; + + if (xcoor_len > sizeof rpms) { + xcoor_len = sizeof rpms; + ctl = 0; + } + + /* + * Make a random PMS and copy it above the decrypted value if the + * decryption failed. Note that we use a constant-time conditional + * copy. + */ + br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len); + br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len); + + /* + * Compute master secret. + */ + br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len); + + /* + * Clear the pre-master secret from RAM: it is normally a buffer + * in the context, hence potentially long-lived. + */ + memset(xcoor, 0, xcoor_len); +} + +/* + * Do the ECDH key exchange (not ECDHE). + */ +static void +do_ecdh(br_ssl_server_context *ctx, int prf_id, + unsigned char *cpoint, size_t cpoint_len) +{ + uint32_t x; + + /* + * Finalise the key exchange. + */ + x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, + cpoint, &cpoint_len); + ecdh_common(ctx, prf_id, cpoint, cpoint_len, x); +} + +/* + * Do the full static ECDH key exchange. When this function is called, + * it has already been verified that the cipher suite uses ECDH (not ECDHE), + * and the client's public key (from its certificate) has type EC and is + * apt for key exchange. + */ +static void +do_static_ecdh(br_ssl_server_context *ctx, int prf_id) +{ + unsigned char cpoint[133]; + size_t cpoint_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + cpoint_len = pk->key.ec.qlen; + if (cpoint_len > sizeof cpoint) { + /* + * If the point is larger than our buffer then we need to + * restrict it. Length 2 is not a valid point length, so + * the ECDH will fail. + */ + cpoint_len = 2; + } + memcpy(cpoint, pk->key.ec.q, cpoint_len); + do_ecdh(ctx, prf_id, cpoint, cpoint_len); +} + +static size_t +hash_data(br_ssl_server_context *ctx, + void *dst, int hash_id, const void *src, size_t len) +{ + const br_hash_class *hf; + br_hash_compat_context hc; + + if (hash_id == 0) { + unsigned char tmp[36]; + + hf = br_multihash_getimpl(&ctx->eng.mhash, br_md5_ID); + if (hf == NULL) { + return 0; + } + hf->init(&hc.vtable); + hf->update(&hc.vtable, src, len); + hf->out(&hc.vtable, tmp); + hf = br_multihash_getimpl(&ctx->eng.mhash, br_sha1_ID); + if (hf == NULL) { + return 0; + } + hf->init(&hc.vtable); + hf->update(&hc.vtable, src, len); + hf->out(&hc.vtable, tmp + 16); + memcpy(dst, tmp, 36); + return 36; + } else { + hf = br_multihash_getimpl(&ctx->eng.mhash, hash_id); + if (hf == NULL) { + return 0; + } + hf->init(&hc.vtable); + hf->update(&hc.vtable, src, len); + hf->out(&hc.vtable, dst); + return (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + } +} + +/* + * Do the ECDHE key exchange (part 1: generation of transient key, and + * computing of the point to send to the client). Returned value is the + * signature length (in bytes), or -x on error (with x being an error + * code). The encoded point is written in the ecdhe_point[] context buffer + * (length in ecdhe_point_len). + */ +static int +do_ecdhe_part1(br_ssl_server_context *ctx, int curve) +{ + unsigned algo_id; + unsigned mask; + const unsigned char *order; + size_t olen, glen; + size_t hv_len, sig_len; + + if (!((ctx->eng.iec->supported_curves >> curve) & 1)) { + return -BR_ERR_INVALID_ALGORITHM; + } + ctx->eng.ecdhe_curve = curve; + + /* + * Generate our private key. We need a non-zero random value + * which is lower than the curve order, in a "large enough" + * range. We force the top bit to 0 and bottom bit to 1, which + * does the trick. Note that contrary to what happens in ECDSA, + * this is not a problem if we do not cover the full range of + * possible values. + */ + order = ctx->eng.iec->order(curve, &olen); + mask = 0xFF; + while (mask >= order[0]) { + mask >>= 1; + } + br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen); + ctx->ecdhe_key[0] &= mask; + ctx->ecdhe_key[olen - 1] |= 0x01; + ctx->ecdhe_key_len = olen; + + /* + * Compute our ECDH point. + */ + glen = ctx->eng.iec->mulgen(ctx->eng.ecdhe_point, + ctx->ecdhe_key, olen, curve); + ctx->eng.ecdhe_point_len = glen; + + /* + * Assemble the message to be signed, and possibly hash it. + */ + memcpy(ctx->eng.pad, ctx->eng.client_random, 32); + memcpy(ctx->eng.pad + 32, ctx->eng.server_random, 32); + ctx->eng.pad[64 + 0] = 0x03; + ctx->eng.pad[64 + 1] = 0x00; + ctx->eng.pad[64 + 2] = curve; + ctx->eng.pad[64 + 3] = ctx->eng.ecdhe_point_len; + memcpy(ctx->eng.pad + 64 + 4, + ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len); + hv_len = 64 + 4 + ctx->eng.ecdhe_point_len; + algo_id = ctx->sign_hash_id; + if (algo_id >= (unsigned)0xFF00) { + hv_len = hash_data(ctx, ctx->eng.pad, algo_id & 0xFF, + ctx->eng.pad, hv_len); + if (hv_len == 0) { + return -BR_ERR_INVALID_ALGORITHM; + } + } + + sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable, + algo_id, ctx->eng.pad, hv_len, sizeof ctx->eng.pad); + return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM; +} + +/* + * Do the ECDHE key exchange (part 2: computation of the shared secret + * from the point sent by the client). + */ +static void +do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id, + unsigned char *cpoint, size_t cpoint_len) +{ + int curve; + uint32_t ctl; + size_t xoff, xlen; + + curve = ctx->eng.ecdhe_curve; + + /* + * Finalise the key exchange. + */ + ctl = ctx->eng.iec->mul(cpoint, cpoint_len, + ctx->ecdhe_key, ctx->ecdhe_key_len, curve); + xoff = ctx->eng.iec->xoff(curve, &xlen); + ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl); + + /* + * Clear the ECDHE private key. Forward Secrecy is achieved insofar + * as that key does not get stolen, so we'd better destroy it + * as soon as it ceases to be useful. + */ + memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len); +} + +/* + * Offset for hash value within the pad (when obtaining all hash values, + * in preparation for verification of the CertificateVerify message). + * Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value + * is used to get the total length. + */ +static const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 }; + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char HASH_OID_SHA1[] = { + 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char HASH_OID_SHA224[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char HASH_OID_SHA256[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char HASH_OID_SHA384[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char HASH_OID_SHA512[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const unsigned char *HASH_OID[] = { + HASH_OID_SHA1, + HASH_OID_SHA224, + HASH_OID_SHA256, + HASH_OID_SHA384, + HASH_OID_SHA512 +}; + +/* + * Verify the signature in CertificateVerify. Returned value is 0 on + * success, or a non-zero error code. Lack of implementation of the + * designated signature algorithm is reported as a "bad signature" + * error (because it means that the peer did not honour our advertised + * set of supported signature algorithms). + */ +static int +verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + int id; + + id = ctx->hash_CV_id; + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + if (pk->key_type == BR_KEYTYPE_RSA) { + unsigned char tmp[64]; + const unsigned char *hash_oid; + + if (id == 0) { + hash_oid = NULL; + } else { + hash_oid = HASH_OID[id - 2]; + } + if (ctx->eng.irsavrfy == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, + hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp) + || memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0) + { + return BR_ERR_BAD_SIGNATURE; + } + } else { + if (ctx->eng.iecdsa == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.iecdsa(ctx->eng.iec, + ctx->hash_CV, ctx->hash_CV_len, + &pk->key.ec, ctx->eng.pad, sig_len)) + { + return BR_ERR_BAD_SIGNATURE; + } + } + return 0; +} + + + +static const unsigned char t0_datablock[] = { + 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02, + 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03, + 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41, + 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21, + 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31, + 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11, + 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22, + 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11, + 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32, + 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43, + 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14, + 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xC0, 0x9C, 0x06, + 0x04, 0xC0, 0x9D, 0x07, 0x04, 0xC0, 0xA0, 0x08, 0x04, 0xC0, 0xA1, 0x09, + 0x04, 0xC0, 0xAC, 0x26, 0x04, 0xC0, 0xAD, 0x27, 0x04, 0xC0, 0xAE, 0x28, + 0x04, 0xC0, 0xAF, 0x29, 0x04, 0xCC, 0xA8, 0x15, 0x04, 0xCC, 0xA9, 0x25, + 0x04, 0x00, 0x00 +}; + +static const unsigned char t0_codeblock[] = { + 0x00, 0x01, 0x00, 0x0B, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x01, + 0x00, 0x0F, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x08, + 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00, + 0x01, 0x02, 0x09, 0x00, 0x00, 0x29, 0x29, 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_FINISHED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_FRAGLEN), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_HANDSHAKE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_PARAM), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_SECRENEG), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_SIGNATURE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_VERSION), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_INVALID_ALGORITHM), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_NO_CLIENT_AUTH), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK), + 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_WRONG_KEY_USAGE), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00, + 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_server_context, client_max_version)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, client_random)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_server_context, client_suites)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_server_context, client_suites_num)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_server_context, curves)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)), + 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, flags)), + 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_server_context, hashes)), + 0x00, 0x00, 0x7B, 0x01, + T0_INT2(BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)), + 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00, + 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, peer_log_max_frag_len)), 0x00, + 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, protocol_names_num)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_in)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)), 0x00, + 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, selected_protocol)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00, + 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_server_context, sign_hash_id)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00, + 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)), + 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)), + 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)), + 0x00, 0x00, 0x09, 0x2A, 0x5D, 0x06, 0x02, 0x6A, 0x2B, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x03, 0x00, 0x9B, 0x2A, 0x63, 0x47, 0x9F, 0x2A, 0x05, + 0x04, 0x65, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0F, 0x06, 0x02, 0x9F, 0x00, + 0x63, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x6A, 0x2B, 0x00, 0x00, 0x2A, 0x8B, + 0x47, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x47, 0x78, 0x2E, 0xA8, 0x1C, 0x85, + 0x01, 0x0C, 0x33, 0x00, 0x00, 0x2A, 0x22, 0x01, 0x08, 0x0C, 0x47, 0x61, + 0x22, 0x08, 0x00, 0x01, 0x03, 0x00, 0x77, 0x30, 0x02, 0x00, 0x38, 0x13, + 0x01, 0x01, 0x0C, 0x77, 0x42, 0x2C, 0x19, 0x38, 0x06, 0x07, 0x02, 0x00, + 0xD0, 0x03, 0x00, 0x04, 0x75, 0x01, 0x00, 0xC7, 0x02, 0x00, 0x2A, 0x19, + 0x13, 0x06, 0x02, 0x71, 0x2B, 0xD0, 0x04, 0x76, 0x00, 0x01, 0x00, 0x77, + 0x42, 0x01, 0x16, 0x89, 0x42, 0x01, 0x00, 0x8C, 0x40, 0x36, 0xB1, 0x35, + 0x06, 0x02, 0x73, 0x2B, 0x06, 0x0A, 0xD7, 0x01, 0x00, 0xD3, 0x01, 0x00, + 0xAD, 0x04, 0x80, 0x46, 0xD7, 0xD4, 0x29, 0xD9, 0x50, 0x06, 0x01, 0xD5, + 0xD8, 0x2C, 0x50, 0x06, 0x31, 0x01, 0x00, 0xAE, 0x2A, 0x5D, 0x06, 0x0F, + 0x01, 0x02, 0xA4, 0x05, 0x02, 0x37, 0x2B, 0x29, 0xB2, 0xB0, 0x2A, 0xC9, + 0x29, 0x04, 0x19, 0x2A, 0x5F, 0x06, 0x0B, 0x29, 0x01, 0x02, 0xA4, 0x05, + 0x02, 0x70, 0x2B, 0xB2, 0x04, 0x0A, 0xB4, 0x2A, 0x05, 0x04, 0x29, 0xAB, + 0x04, 0x02, 0xB3, 0xAF, 0x04, 0x01, 0xB2, 0x01, 0x00, 0xAD, 0x01, 0x00, + 0xD3, 0x3E, 0x01, 0x01, 0x77, 0x42, 0x01, 0x17, 0x89, 0x42, 0x00, 0x00, + 0x3A, 0x3A, 0x00, 0x01, 0x03, 0x00, 0x2C, 0x19, 0x38, 0x06, 0x04, 0xCF, + 0x29, 0x04, 0x78, 0x01, 0x02, 0x02, 0x00, 0xC6, 0x19, 0x38, 0x06, 0x04, + 0xCF, 0x29, 0x04, 0x78, 0x02, 0x00, 0x01, 0x84, 0x00, 0x08, 0x2B, 0x00, + 0x00, 0x81, 0x2F, 0x47, 0x12, 0x01, 0x01, 0x13, 0x37, 0x00, 0x00, 0x2A, + 0x05, 0x04, 0x29, 0x01, 0x7F, 0x00, 0x01, 0x00, 0xA2, 0x12, 0x01, 0x01, + 0x13, 0x5F, 0x06, 0x03, 0x61, 0x04, 0x75, 0x47, 0x29, 0x00, 0x00, 0x01, + 0x7F, 0xA1, 0xCF, 0x2A, 0x01, 0x07, 0x13, 0x01, 0x00, 0x3A, 0x0F, 0x06, + 0x0D, 0x29, 0x01, 0x10, 0x13, 0x06, 0x05, 0x01, 0x00, 0x77, 0x42, 0xC5, + 0x04, 0x33, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x2A, 0x29, 0x29, 0x8A, 0x30, + 0x01, 0x01, 0x0F, 0x01, 0x01, 0xA4, 0x39, 0x06, 0x18, 0xC8, 0x2C, 0x19, + 0x38, 0x06, 0x04, 0xCF, 0x29, 0x04, 0x78, 0x01, 0x80, 0x64, 0xC7, 0x01, + 0x01, 0x77, 0x42, 0x01, 0x17, 0x89, 0x42, 0x04, 0x03, 0x01, 0x00, 0xA1, + 0x04, 0x03, 0x73, 0x2B, 0x29, 0x04, 0xFF, 0x32, 0x01, 0x2A, 0x03, 0x00, + 0x09, 0x2A, 0x5D, 0x06, 0x02, 0x6A, 0x2B, 0x02, 0x00, 0x00, 0x00, 0x9C, + 0x01, 0x0F, 0x13, 0x00, 0x00, 0x76, 0x30, 0x01, 0x00, 0x3A, 0x0F, 0x06, + 0x10, 0x29, 0x2A, 0x01, 0x01, 0x0E, 0x06, 0x03, 0x29, 0x01, 0x02, 0x76, + 0x42, 0x01, 0x00, 0x04, 0x21, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x14, 0x29, + 0x01, 0x00, 0x76, 0x42, 0x2A, 0x01, 0x80, 0x64, 0x0F, 0x06, 0x05, 0x01, + 0x82, 0x00, 0x08, 0x2B, 0x5F, 0x04, 0x07, 0x29, 0x01, 0x82, 0x00, 0x08, + 0x2B, 0x29, 0x00, 0x00, 0x01, 0x00, 0x31, 0x06, 0x05, 0x3D, 0xA9, 0x39, + 0x04, 0x78, 0x2A, 0x06, 0x04, 0x01, 0x01, 0x91, 0x42, 0x00, 0x00, 0x01, + 0x1F, 0x13, 0x01, 0x12, 0x0F, 0x05, 0x02, 0x74, 0x2B, 0x78, 0x2E, 0x2A, + 0xCB, 0x05, 0x02, 0x73, 0x2B, 0xA8, 0x28, 0x00, 0x02, 0x87, 0x2E, 0x05, + 0x02, 0xBC, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x01, 0x7E, 0x03, 0x00, 0x2A, + 0x06, 0x17, 0xC2, 0x2A, 0x03, 0x01, 0x85, 0x47, 0xB6, 0x02, 0x01, 0x51, + 0x2A, 0x02, 0x00, 0x53, 0x06, 0x04, 0x03, 0x00, 0x04, 0x01, 0x29, 0x04, + 0x66, 0x9D, 0x9D, 0x02, 0x00, 0x61, 0x8C, 0x40, 0x00, 0x00, 0x31, 0x06, + 0x0B, 0x88, 0x30, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x73, 0x2B, 0x04, 0x11, + 0xCF, 0x01, 0x07, 0x13, 0x2A, 0x01, 0x02, 0x0E, 0x06, 0x06, 0x06, 0x02, + 0x73, 0x2B, 0x04, 0x70, 0x29, 0xC3, 0x01, 0x01, 0x0E, 0x35, 0x39, 0x06, + 0x02, 0x66, 0x2B, 0x2A, 0x01, 0x01, 0xCA, 0x38, 0xB5, 0x00, 0x01, 0xBA, + 0x01, 0x0B, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x2A, 0x01, 0x03, 0x0F, 0x06, + 0x08, 0xC1, 0x06, 0x02, 0x6A, 0x2B, 0x47, 0x29, 0x00, 0x47, 0x5C, 0xC1, + 0xA7, 0x2A, 0x06, 0x23, 0xC1, 0xA7, 0x2A, 0x5B, 0x2A, 0x06, 0x18, 0x2A, + 0x01, 0x82, 0x00, 0x10, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x2A, + 0x03, 0x00, 0x85, 0x02, 0x00, 0xB6, 0x02, 0x00, 0x58, 0x04, 0x65, 0x9D, + 0x59, 0x04, 0x5A, 0x9D, 0x9D, 0x5A, 0x2A, 0x06, 0x02, 0x37, 0x00, 0x29, + 0x2D, 0x00, 0x02, 0x2A, 0x01, 0x20, 0x13, 0x05, 0x02, 0x74, 0x2B, 0x01, + 0x0F, 0x13, 0x03, 0x00, 0xB0, 0x95, 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06, + 0x23, 0xC0, 0x2A, 0x01, 0x81, 0x7F, 0x13, 0x61, 0x01, 0x01, 0x12, 0x02, + 0x00, 0x0F, 0x05, 0x02, 0x6C, 0x2B, 0x01, 0x08, 0x12, 0x2A, 0x01, 0x02, + 0x0B, 0x3A, 0x01, 0x06, 0x10, 0x39, 0x06, 0x02, 0x6E, 0x2B, 0x04, 0x0D, + 0x02, 0x00, 0x01, 0x01, 0x0F, 0x06, 0x04, 0x01, 0x00, 0x04, 0x02, 0x01, + 0x02, 0x20, 0x05, 0x02, 0x6E, 0x2B, 0xC0, 0x2A, 0x03, 0x01, 0x2A, 0x01, + 0x84, 0x00, 0x10, 0x06, 0x02, 0x6F, 0x2B, 0x85, 0x47, 0xB6, 0x02, 0x01, + 0x55, 0x2A, 0x06, 0x01, 0x2B, 0x29, 0x9D, 0x00, 0x00, 0x1D, 0xBA, 0x01, + 0x0F, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x00, 0x0A, 0xBA, 0x01, 0x01, 0x0F, + 0x05, 0x02, 0x73, 0x2B, 0xC0, 0x2A, 0x03, 0x00, 0x79, 0x40, 0x7A, 0x01, + 0x20, 0xB6, 0xC2, 0x2A, 0x01, 0x20, 0x10, 0x06, 0x02, 0x72, 0x2B, 0x2A, + 0x90, 0x42, 0x8F, 0x47, 0xB6, 0x1A, 0x03, 0x01, 0xC0, 0xA7, 0x01, 0x00, + 0x03, 0x02, 0x01, 0x00, 0x03, 0x03, 0x83, 0xA2, 0x17, 0x3A, 0x08, 0x03, + 0x04, 0x03, 0x05, 0x2A, 0x06, 0x80, 0x6D, 0xC0, 0x2A, 0x03, 0x06, 0x02, + 0x01, 0x06, 0x0A, 0x2A, 0x78, 0x2E, 0x0F, 0x06, 0x04, 0x01, 0x7F, 0x03, + 0x03, 0x2A, 0x01, 0x81, 0x7F, 0x0F, 0x06, 0x0A, 0x8A, 0x30, 0x06, 0x02, + 0x6B, 0x2B, 0x01, 0x7F, 0x03, 0x02, 0x2A, 0x01, 0x81, 0xAC, 0x00, 0x0F, + 0x06, 0x11, 0x02, 0x00, 0x98, 0x2E, 0x11, 0x02, 0x00, 0x97, 0x2E, 0x0B, + 0x13, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x00, 0xC4, 0x2A, 0x5D, 0x06, 0x03, + 0x29, 0x04, 0x26, 0x01, 0x00, 0xA4, 0x06, 0x0B, 0x01, 0x02, 0x0C, 0x7B, + 0x08, 0x02, 0x06, 0x47, 0x40, 0x04, 0x16, 0x29, 0x02, 0x05, 0x02, 0x04, + 0x11, 0x06, 0x02, 0x69, 0x2B, 0x02, 0x06, 0x02, 0x05, 0x40, 0x02, 0x05, + 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0xFF, 0x0F, 0x29, 0x01, 0x00, 0x03, + 0x07, 0xC2, 0xA7, 0x2A, 0x06, 0x09, 0xC2, 0x05, 0x04, 0x01, 0x7F, 0x03, + 0x07, 0x04, 0x74, 0x9D, 0x01, 0x00, 0x8D, 0x42, 0x01, 0x88, 0x04, 0x82, + 0x41, 0x01, 0x84, 0x80, 0x80, 0x00, 0x7E, 0x41, 0x2A, 0x06, 0x80, 0x4E, + 0xC0, 0xA7, 0x2A, 0x06, 0x80, 0x47, 0xC0, 0x01, 0x00, 0x3A, 0x0F, 0x06, + 0x04, 0x29, 0xB9, 0x04, 0x39, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x04, 0x29, + 0xB7, 0x04, 0x2F, 0x01, 0x83, 0xFE, 0x01, 0x3A, 0x0F, 0x06, 0x04, 0x29, + 0xB8, 0x04, 0x23, 0x01, 0x0D, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xBE, 0x04, + 0x19, 0x01, 0x0A, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xBF, 0x04, 0x0F, 0x01, + 0x10, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xAC, 0x04, 0x05, 0x29, 0xBC, 0x01, + 0x00, 0x29, 0x04, 0xFF, 0x35, 0x9D, 0x9D, 0x02, 0x01, 0x02, 0x03, 0x13, + 0x03, 0x01, 0x02, 0x00, 0x5D, 0x06, 0x08, 0x79, 0x2E, 0x99, 0x40, 0x01, + 0x80, 0x56, 0xA3, 0x97, 0x2E, 0x2A, 0x02, 0x00, 0x10, 0x06, 0x03, 0x29, + 0x02, 0x00, 0x2A, 0x01, 0x86, 0x00, 0x0B, 0x06, 0x02, 0x6D, 0x2B, 0x02, + 0x00, 0x98, 0x2E, 0x0B, 0x06, 0x04, 0x01, 0x80, 0x46, 0xA3, 0x02, 0x01, + 0x06, 0x10, 0x95, 0x2E, 0x02, 0x00, 0x0D, 0x06, 0x05, 0x29, 0x95, 0x2E, + 0x04, 0x04, 0x01, 0x00, 0x03, 0x01, 0x2A, 0x95, 0x40, 0x2A, 0x96, 0x40, + 0x2A, 0x99, 0x40, 0x01, 0x86, 0x03, 0x11, 0x03, 0x08, 0x02, 0x02, 0x06, + 0x04, 0x01, 0x02, 0x8A, 0x42, 0x8A, 0x30, 0x05, 0x04, 0x01, 0x01, 0x8A, + 0x42, 0x02, 0x07, 0x05, 0x03, 0x01, 0x28, 0xA3, 0x44, 0x29, 0x01, 0x82, + 0x01, 0x07, 0x01, 0xFC, 0x80, 0x00, 0x39, 0x82, 0x2F, 0x13, 0x2A, 0x82, + 0x41, 0x2A, 0x01, 0x81, 0x7F, 0x13, 0x5E, 0x37, 0x47, 0x01, 0x08, 0x12, + 0x5E, 0x01, 0x02, 0x13, 0x39, 0x01, 0x0C, 0x0C, 0x03, 0x09, 0x7E, 0x2F, + 0x43, 0x13, 0x2A, 0x7E, 0x41, 0x05, 0x04, 0x01, 0x00, 0x03, 0x09, 0x02, + 0x01, 0x06, 0x03, 0x01, 0x7F, 0x00, 0x8F, 0x01, 0x20, 0x34, 0x01, 0x20, + 0x90, 0x42, 0x7B, 0x2A, 0x03, 0x05, 0x2A, 0x02, 0x04, 0x0B, 0x06, 0x80, + 0x49, 0x2A, 0x2E, 0x2A, 0x9C, 0x2A, 0x01, 0x0C, 0x12, 0x2A, 0x01, 0x01, + 0x0F, 0x47, 0x01, 0x02, 0x0F, 0x39, 0x06, 0x0A, 0x2A, 0x02, 0x09, 0x13, + 0x05, 0x04, 0x65, 0x01, 0x00, 0x2A, 0x02, 0x08, 0x05, 0x0E, 0x2A, 0x01, + 0x81, 0x70, 0x13, 0x01, 0x20, 0x0E, 0x06, 0x04, 0x65, 0x01, 0x00, 0x2A, + 0x2A, 0x06, 0x10, 0x02, 0x05, 0x63, 0x40, 0x02, 0x05, 0x40, 0x02, 0x05, + 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0x01, 0x65, 0x01, 0x04, 0x08, 0x04, + 0xFF, 0x30, 0x29, 0x02, 0x05, 0x7B, 0x09, 0x01, 0x02, 0x12, 0x2A, 0x05, + 0x03, 0x01, 0x28, 0xA3, 0x7C, 0x42, 0x8C, 0x2E, 0x01, 0x83, 0xFF, 0x7F, + 0x0F, 0x06, 0x0D, 0x01, 0x03, 0xA4, 0x06, 0x04, 0x01, 0x80, 0x78, 0xA3, + 0x01, 0x00, 0x8C, 0x40, 0x18, 0x05, 0x03, 0x01, 0x28, 0xA3, 0x01, 0x00, + 0x00, 0x00, 0xB4, 0xB3, 0x00, 0x04, 0x78, 0x2E, 0xCE, 0x06, 0x16, 0xC0, + 0x2A, 0x01, 0x84, 0x00, 0x10, 0x06, 0x02, 0x6F, 0x2B, 0x2A, 0x03, 0x00, + 0x85, 0x47, 0xB6, 0x02, 0x00, 0x78, 0x2E, 0xA8, 0x27, 0x78, 0x2E, 0x2A, + 0xCC, 0x47, 0xCB, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, 0x02, 0x02, 0x39, + 0x06, 0x14, 0xC2, 0x2A, 0x03, 0x03, 0x85, 0x47, 0xB6, 0x02, 0x03, 0x78, + 0x2E, 0xA8, 0x02, 0x02, 0x06, 0x03, 0x26, 0x04, 0x01, 0x24, 0x9D, 0x00, + 0x00, 0xBA, 0x01, 0x10, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x00, 0x00, 0x9E, + 0xBA, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x73, 0x2B, 0x85, 0x01, 0x0C, 0x08, + 0x01, 0x0C, 0xB6, 0x9D, 0x85, 0x2A, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x32, + 0x05, 0x02, 0x67, 0x2B, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, + 0x9A, 0x02, 0x01, 0x02, 0x00, 0x3C, 0x2A, 0x01, 0x00, 0x0F, 0x06, 0x02, + 0x65, 0x00, 0xD1, 0x04, 0x74, 0x00, 0xC0, 0x01, 0x01, 0x0E, 0x06, 0x02, + 0x68, 0x2B, 0xC2, 0x2A, 0x2A, 0x5F, 0x47, 0x01, 0x05, 0x11, 0x39, 0x06, + 0x02, 0x68, 0x2B, 0x01, 0x08, 0x08, 0x2A, 0x84, 0x30, 0x0B, 0x06, 0x0D, + 0x2A, 0x01, 0x01, 0x47, 0x0C, 0x3F, 0x2A, 0x84, 0x42, 0x86, 0x42, 0x04, + 0x01, 0x29, 0x00, 0x00, 0xC0, 0x8A, 0x30, 0x01, 0x00, 0x3A, 0x0F, 0x06, + 0x13, 0x29, 0x01, 0x01, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0xC2, 0x06, 0x02, + 0x6B, 0x2B, 0x01, 0x02, 0x8A, 0x42, 0x04, 0x28, 0x01, 0x02, 0x3A, 0x0F, + 0x06, 0x1F, 0x29, 0x01, 0x0D, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0xC2, 0x01, + 0x0C, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0x85, 0x01, 0x0C, 0xB6, 0x8B, 0x85, + 0x01, 0x0C, 0x32, 0x05, 0x02, 0x6B, 0x2B, 0x04, 0x03, 0x6B, 0x2B, 0x29, + 0x00, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x2A, 0x06, 0x1D, 0xC2, 0x06, 0x03, + 0xBC, 0x04, 0x15, 0xC0, 0x2A, 0x01, 0x81, 0x7F, 0x0D, 0x06, 0x0C, 0x2A, + 0x8D, 0x08, 0x01, 0x00, 0x47, 0x42, 0x8D, 0x47, 0xB6, 0x04, 0x01, 0xC9, + 0x04, 0x60, 0x9D, 0x9D, 0x00, 0x00, 0xBB, 0x2A, 0x5F, 0x06, 0x07, 0x29, + 0x06, 0x02, 0x69, 0x2B, 0x04, 0x74, 0x00, 0x00, 0xC3, 0x01, 0x03, 0xC1, + 0x47, 0x29, 0x47, 0x00, 0x00, 0xC0, 0xC9, 0x00, 0x03, 0x01, 0x00, 0x03, + 0x00, 0xC0, 0xA7, 0x2A, 0x06, 0x80, 0x50, 0xC2, 0x03, 0x01, 0xC2, 0x03, + 0x02, 0x02, 0x01, 0x01, 0x08, 0x0F, 0x06, 0x16, 0x02, 0x02, 0x01, 0x0F, + 0x0D, 0x06, 0x0D, 0x01, 0x01, 0x02, 0x02, 0x01, 0x10, 0x08, 0x0C, 0x02, + 0x00, 0x39, 0x03, 0x00, 0x04, 0x2A, 0x02, 0x01, 0x01, 0x02, 0x11, 0x02, + 0x01, 0x01, 0x06, 0x0D, 0x13, 0x02, 0x02, 0x01, 0x01, 0x0F, 0x02, 0x02, + 0x01, 0x03, 0x0F, 0x39, 0x13, 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02, + 0x02, 0x62, 0x01, 0x02, 0x0C, 0x02, 0x01, 0x08, 0x0C, 0x39, 0x03, 0x00, + 0x04, 0xFF, 0x2C, 0x9D, 0x02, 0x00, 0x00, 0x00, 0xC0, 0xA7, 0xBD, 0x82, + 0x41, 0x9D, 0x00, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x01, 0x00, 0x7E, 0x41, + 0x2A, 0x06, 0x15, 0xC0, 0x2A, 0x01, 0x20, 0x0B, 0x06, 0x0B, 0x01, 0x01, + 0x47, 0x0C, 0x7E, 0x2F, 0x39, 0x7E, 0x41, 0x04, 0x01, 0x29, 0x04, 0x68, + 0x9D, 0x9D, 0x00, 0x00, 0x01, 0x02, 0x9A, 0xC3, 0x01, 0x08, 0x0C, 0xC3, + 0x08, 0x00, 0x00, 0x01, 0x03, 0x9A, 0xC3, 0x01, 0x08, 0x0C, 0xC3, 0x08, + 0x01, 0x08, 0x0C, 0xC3, 0x08, 0x00, 0x00, 0x01, 0x01, 0x9A, 0xC3, 0x00, + 0x00, 0x3D, 0x2A, 0x5D, 0x05, 0x01, 0x00, 0x29, 0xD1, 0x04, 0x76, 0x02, + 0x03, 0x00, 0x94, 0x30, 0x03, 0x01, 0x01, 0x00, 0x2A, 0x02, 0x01, 0x0B, + 0x06, 0x10, 0x2A, 0x01, 0x01, 0x0C, 0x93, 0x08, 0x2E, 0x02, 0x00, 0x0F, + 0x06, 0x01, 0x00, 0x61, 0x04, 0x6A, 0x29, 0x01, 0x7F, 0x00, 0x00, 0x2C, + 0x19, 0x38, 0x06, 0x04, 0xCF, 0x29, 0x04, 0x78, 0x01, 0x16, 0x89, 0x42, + 0x01, 0x00, 0xE2, 0x01, 0x00, 0xE1, 0x2C, 0x01, 0x17, 0x89, 0x42, 0x00, + 0x00, 0x01, 0x15, 0x89, 0x42, 0x47, 0x57, 0x29, 0x57, 0x29, 0x2C, 0x00, + 0x00, 0x01, 0x01, 0x47, 0xC6, 0x00, 0x00, 0xBB, 0x01, 0x01, 0x0F, 0x05, + 0x02, 0x73, 0x2B, 0x2A, 0xC9, 0x29, 0x00, 0x00, 0x47, 0x3A, 0x9A, 0x47, + 0x2A, 0x06, 0x05, 0xC3, 0x29, 0x62, 0x04, 0x78, 0x29, 0x00, 0x02, 0x03, + 0x00, 0x78, 0x2E, 0x9C, 0x03, 0x01, 0x02, 0x01, 0x01, 0x0F, 0x13, 0x02, + 0x01, 0x01, 0x04, 0x12, 0x01, 0x0F, 0x13, 0x02, 0x01, 0x01, 0x08, 0x12, + 0x01, 0x0F, 0x13, 0x01, 0x00, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x00, + 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x81, + 0x0D, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x01, 0x01, 0x10, + 0x02, 0x00, 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x80, 0x77, 0x01, + 0x02, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x01, 0x01, 0x20, 0x02, 0x00, + 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x80, 0x61, 0x01, 0x03, 0x3A, + 0x0F, 0x06, 0x0F, 0x29, 0x29, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x4A, + 0x04, 0x01, 0x4B, 0x04, 0x80, 0x4C, 0x01, 0x04, 0x3A, 0x0F, 0x06, 0x0E, + 0x29, 0x29, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x4A, 0x04, 0x01, 0x4B, + 0x04, 0x38, 0x01, 0x05, 0x3A, 0x0F, 0x06, 0x0C, 0x29, 0x29, 0x02, 0x00, + 0x06, 0x03, 0x4E, 0x04, 0x01, 0x4F, 0x04, 0x26, 0x2A, 0x01, 0x09, 0x10, + 0x06, 0x02, 0x6A, 0x2B, 0x47, 0x29, 0x2A, 0x01, 0x01, 0x13, 0x01, 0x04, + 0x0C, 0x01, 0x10, 0x08, 0x47, 0x01, 0x08, 0x13, 0x01, 0x10, 0x47, 0x09, + 0x02, 0x00, 0x06, 0x03, 0x48, 0x04, 0x01, 0x49, 0x00, 0x29, 0x00, 0x00, + 0x9C, 0x01, 0x0C, 0x12, 0x01, 0x02, 0x10, 0x00, 0x00, 0x9C, 0x01, 0x0C, + 0x12, 0x2A, 0x60, 0x47, 0x01, 0x03, 0x0B, 0x13, 0x00, 0x00, 0x9C, 0x01, + 0x0C, 0x12, 0x01, 0x01, 0x0F, 0x00, 0x00, 0x9C, 0x01, 0x0C, 0x12, 0x5F, + 0x00, 0x00, 0x1B, 0x01, 0x00, 0x75, 0x30, 0x2A, 0x06, 0x22, 0x01, 0x01, + 0x3A, 0x0F, 0x06, 0x06, 0x29, 0x01, 0x00, 0xA0, 0x04, 0x14, 0x01, 0x02, + 0x3A, 0x0F, 0x06, 0x0D, 0x29, 0x77, 0x30, 0x01, 0x01, 0x0F, 0x06, 0x03, + 0x01, 0x10, 0x39, 0x04, 0x01, 0x29, 0x04, 0x01, 0x29, 0x7D, 0x30, 0x05, + 0x33, 0x31, 0x06, 0x30, 0x88, 0x30, 0x01, 0x14, 0x3A, 0x0F, 0x06, 0x06, + 0x29, 0x01, 0x02, 0x39, 0x04, 0x22, 0x01, 0x15, 0x3A, 0x0F, 0x06, 0x09, + 0x29, 0xAA, 0x06, 0x03, 0x01, 0x7F, 0xA0, 0x04, 0x13, 0x01, 0x16, 0x3A, + 0x0F, 0x06, 0x06, 0x29, 0x01, 0x01, 0x39, 0x04, 0x07, 0x29, 0x01, 0x04, + 0x39, 0x01, 0x00, 0x29, 0x19, 0x06, 0x03, 0x01, 0x08, 0x39, 0x00, 0x00, + 0x1B, 0x2A, 0x05, 0x13, 0x31, 0x06, 0x10, 0x88, 0x30, 0x01, 0x15, 0x0F, + 0x06, 0x08, 0x29, 0xAA, 0x01, 0x00, 0x77, 0x42, 0x04, 0x01, 0x23, 0x00, + 0x00, 0xCF, 0x01, 0x07, 0x13, 0x01, 0x01, 0x10, 0x06, 0x02, 0x73, 0x2B, + 0x00, 0x01, 0x03, 0x00, 0x2C, 0x19, 0x06, 0x05, 0x02, 0x00, 0x89, 0x42, + 0x00, 0xCF, 0x29, 0x04, 0x74, 0x00, 0x01, 0x14, 0xD2, 0x01, 0x01, 0xE2, + 0x2C, 0x2A, 0x01, 0x00, 0xCA, 0x01, 0x16, 0xD2, 0xD6, 0x2C, 0x00, 0x00, + 0x01, 0x0B, 0xE2, 0x52, 0x2A, 0x2A, 0x01, 0x03, 0x08, 0xE1, 0xE1, 0x14, + 0x2A, 0x5D, 0x06, 0x02, 0x29, 0x00, 0xE1, 0x1E, 0x2A, 0x06, 0x05, 0x85, + 0x47, 0xDA, 0x04, 0x77, 0x29, 0x04, 0x6C, 0x00, 0x01, 0x00, 0xDC, 0x95, + 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06, 0x05, 0x63, 0x01, 0x00, 0xDD, 0x08, + 0x50, 0x08, 0x01, 0x03, 0x08, 0x01, 0x0D, 0xE2, 0xE1, 0x01, 0x00, 0xDC, + 0xE2, 0x01, 0x01, 0xDC, 0x29, 0x95, 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06, + 0x08, 0x01, 0x00, 0xDD, 0xE0, 0x01, 0x01, 0xDD, 0x29, 0x50, 0xE0, 0x16, + 0x15, 0x2A, 0x5D, 0x06, 0x02, 0x29, 0x00, 0xE0, 0x1F, 0x2A, 0x06, 0x05, + 0x85, 0x47, 0xDA, 0x04, 0x77, 0x29, 0x04, 0x6C, 0x00, 0x9E, 0x01, 0x14, + 0xE2, 0x01, 0x0C, 0xE1, 0x85, 0x01, 0x0C, 0xDA, 0x00, 0x04, 0x03, 0x00, + 0x01, 0x02, 0xE2, 0x01, 0x80, 0x46, 0x8A, 0x30, 0x01, 0x02, 0x0F, 0x06, + 0x0C, 0x02, 0x00, 0x06, 0x04, 0x01, 0x05, 0x04, 0x02, 0x01, 0x1D, 0x04, + 0x02, 0x01, 0x00, 0x03, 0x01, 0x86, 0x30, 0x06, 0x04, 0x01, 0x05, 0x04, + 0x02, 0x01, 0x00, 0x03, 0x02, 0x8C, 0x2E, 0x2A, 0x06, 0x05, 0x62, 0x21, + 0x01, 0x07, 0x08, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x02, 0x03, + 0x08, 0x2A, 0x06, 0x03, 0x01, 0x02, 0x08, 0x08, 0xE1, 0x95, 0x2E, 0xE0, + 0x8E, 0x01, 0x04, 0x17, 0x8E, 0x01, 0x04, 0x08, 0x01, 0x1C, 0x34, 0x8E, + 0x01, 0x20, 0xDA, 0x01, 0x20, 0xE2, 0x8F, 0x01, 0x20, 0xDA, 0x78, 0x2E, + 0xE0, 0x01, 0x00, 0xE2, 0x02, 0x01, 0x02, 0x02, 0x08, 0x02, 0x03, 0x08, + 0x2A, 0x06, 0x80, 0x40, 0xE0, 0x02, 0x01, 0x2A, 0x06, 0x10, 0x01, 0x83, + 0xFE, 0x01, 0xE0, 0x01, 0x04, 0x09, 0x2A, 0xE0, 0x62, 0x8B, 0x47, 0xDB, + 0x04, 0x01, 0x29, 0x02, 0x02, 0x06, 0x0C, 0x01, 0x01, 0xE0, 0x01, 0x01, + 0xE0, 0x86, 0x30, 0x01, 0x08, 0x09, 0xE2, 0x02, 0x03, 0x2A, 0x06, 0x11, + 0x01, 0x10, 0xE0, 0x01, 0x04, 0x09, 0x2A, 0xE0, 0x64, 0x2A, 0xE0, 0x62, + 0x85, 0x47, 0xDB, 0x04, 0x01, 0x29, 0x04, 0x01, 0x29, 0x00, 0x00, 0x01, + 0x0E, 0xE2, 0x01, 0x00, 0xE1, 0x00, 0x03, 0x78, 0x2E, 0xCC, 0x05, 0x01, + 0x00, 0x7E, 0x2F, 0x2A, 0x01, 0x82, 0x80, 0x80, 0x80, 0x00, 0x13, 0x06, + 0x05, 0x29, 0x01, 0x1D, 0x04, 0x0E, 0x2A, 0x01, 0x83, 0xC0, 0x80, 0x80, + 0x00, 0x13, 0x2A, 0x06, 0x01, 0x47, 0x29, 0xA5, 0x03, 0x00, 0x02, 0x00, + 0x25, 0x2A, 0x5D, 0x06, 0x02, 0x37, 0x2B, 0x03, 0x01, 0x95, 0x2E, 0x01, + 0x86, 0x03, 0x11, 0x03, 0x02, 0x01, 0x0C, 0xE2, 0x02, 0x01, 0x80, 0x30, + 0x08, 0x02, 0x02, 0x01, 0x02, 0x13, 0x08, 0x01, 0x06, 0x08, 0xE1, 0x01, + 0x03, 0xE2, 0x02, 0x00, 0xE0, 0x7F, 0x80, 0x30, 0xDB, 0x02, 0x02, 0x06, + 0x1C, 0x92, 0x2E, 0x2A, 0x01, 0x83, 0xFE, 0x00, 0x0B, 0x06, 0x03, 0xE0, + 0x04, 0x0F, 0x01, 0x81, 0x7F, 0x13, 0xE2, 0x78, 0x2E, 0xCD, 0x01, 0x01, + 0x0C, 0x01, 0x03, 0x08, 0xE2, 0x02, 0x01, 0xE0, 0x85, 0x02, 0x01, 0xDA, + 0x00, 0x00, 0x56, 0x2A, 0x01, 0x00, 0x0F, 0x06, 0x02, 0x65, 0x00, 0xCF, + 0x29, 0x04, 0x73, 0x00, 0x2A, 0xE2, 0xDA, 0x00, 0x00, 0x01, 0x00, 0x78, + 0x2E, 0xCB, 0x06, 0x0C, 0x63, 0x3A, 0x06, 0x08, 0x01, 0x80, 0x41, 0xE2, + 0x01, 0x80, 0x42, 0xE2, 0x46, 0x06, 0x07, 0x61, 0x3A, 0x06, 0x03, 0x01, + 0x01, 0xE2, 0x45, 0x06, 0x08, 0x61, 0x3A, 0x06, 0x04, 0x01, 0x80, 0x40, + 0xE2, 0x47, 0x29, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x46, 0x45, 0x39, + 0x05, 0x14, 0x01, 0x01, 0x01, 0x80, 0x7C, 0xDE, 0x03, 0x00, 0x01, 0x03, + 0x01, 0x80, 0x7C, 0xDE, 0x02, 0x00, 0x08, 0x47, 0x29, 0x00, 0x46, 0x06, + 0x07, 0x01, 0x01, 0x44, 0x29, 0xDE, 0x03, 0x00, 0x45, 0x06, 0x0A, 0x01, + 0x03, 0x44, 0x29, 0xDE, 0x02, 0x00, 0x08, 0x03, 0x00, 0x29, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x04, 0xDF, 0x01, 0x05, 0xDF, 0x01, 0x06, + 0xDF, 0x01, 0x03, 0xDF, 0x01, 0x02, 0xDF, 0x0A, 0x65, 0x00, 0x01, 0x03, + 0x00, 0x3A, 0x01, 0x01, 0x02, 0x00, 0x0C, 0x13, 0x05, 0x01, 0x00, 0x63, + 0x01, 0x03, 0x3B, 0x06, 0x07, 0x02, 0x00, 0xE2, 0x01, 0x02, 0x3B, 0xE2, + 0x00, 0x00, 0x2A, 0x01, 0x08, 0x54, 0xE2, 0xE2, 0x00, 0x00, 0x2A, 0x01, + 0x10, 0x54, 0xE2, 0xE0, 0x00, 0x00, 0x2A, 0x57, 0x06, 0x02, 0x29, 0x00, + 0xCF, 0x29, 0x04, 0x76 +}; + +static const uint16_t t0_caddr[] = { + 0, + 5, + 10, + 15, + 20, + 25, + 30, + 35, + 40, + 44, + 48, + 52, + 56, + 60, + 64, + 68, + 72, + 76, + 80, + 84, + 88, + 92, + 96, + 100, + 104, + 109, + 114, + 119, + 124, + 129, + 134, + 139, + 144, + 149, + 154, + 159, + 164, + 169, + 174, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 280, + 285, + 290, + 299, + 303, + 328, + 334, + 353, + 364, + 405, + 516, + 520, + 553, + 563, + 587, + 669, + 683, + 689, + 748, + 767, + 789, + 838, + 887, + 963, + 1065, + 1076, + 1670, + 1674, + 1741, + 1751, + 1782, + 1806, + 1852, + 1922, + 1962, + 1976, + 1985, + 1989, + 2084, + 2092, + 2128, + 2139, + 2155, + 2161, + 2172, + 2207, + 2233, + 2245, + 2251, + 2264, + 2279, + 2472, + 2481, + 2494, + 2503, + 2510, + 2616, + 2641, + 2654, + 2670, + 2688, + 2720, + 2793, + 2806, + 2987, + 2995, + 3122, + 3136, + 3141, + 3185, + 3242, + 3263, + 3290, + 3298, + 3306 +}; + +#define T0_INTERPRETED 93 + +#define T0_ENTER(ip, rp, slot) do { \ + const unsigned char *t0_newip; \ + uint32_t t0_lnum; \ + t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \ + t0_lnum = t0_parse7E_unsigned(&t0_newip); \ + (rp) += t0_lnum; \ + *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \ + (ip) = t0_newip; \ + } while (0) + +#define T0_DEFENTRY(name, slot) \ +void \ +name(void *ctx) \ +{ \ + t0_context *t0ctx = ctx; \ + t0ctx->ip = &t0_codeblock[0]; \ + T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ +} + +T0_DEFENTRY(br_ssl_hs_server_init_main, 166) + +#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++) + +void +br_ssl_hs_server_run(void *t0ctx) +{ + uint32_t *dp, *rp; + const unsigned char *ip; + +#define T0_LOCAL(x) (*(rp - 2 - (x))) +#define T0_POP() (*-- dp) +#define T0_POPi() (*(int32_t *)(-- dp)) +#define T0_PEEK(x) (*(dp - 1 - (x))) +#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x))) +#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0) +#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0) +#define T0_RPOP() (*-- rp) +#define T0_RPOPi() (*(int32_t *)(-- rp)) +#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0) +#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0) +#define T0_ROLL(x) do { \ + size_t t0len = (size_t)(x); \ + uint32_t t0tmp = *(dp - 1 - t0len); \ + memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_SWAP() do { \ + uint32_t t0tmp = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_ROT() do { \ + uint32_t t0tmp = *(dp - 3); \ + *(dp - 3) = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_NROT() do { \ + uint32_t t0tmp = *(dp - 1); \ + *(dp - 1) = *(dp - 2); \ + *(dp - 2) = *(dp - 3); \ + *(dp - 3) = t0tmp; \ +} while (0) +#define T0_PICK(x) do { \ + uint32_t t0depth = (x); \ + T0_PUSH(T0_PEEK(t0depth)); \ +} while (0) +#define T0_CO() do { \ + goto t0_exit; \ +} while (0) +#define T0_RET() goto t0_next + + dp = ((t0_context *)t0ctx)->dp; + rp = ((t0_context *)t0ctx)->rp; + ip = ((t0_context *)t0ctx)->ip; + goto t0_next; + for (;;) { + uint32_t t0x; + + t0_next: + t0x = T0_NEXT(&ip); + if (t0x < T0_INTERPRETED) { + switch (t0x) { + int32_t t0off; + + case 0: /* ret */ + t0x = T0_RPOP(); + rp -= (t0x >> 16); + t0x &= 0xFFFF; + if (t0x == 0) { + ip = NULL; + goto t0_exit; + } + ip = &t0_codeblock[t0x]; + break; + case 1: /* literal constant */ + T0_PUSHi(t0_parse7E_signed(&ip)); + break; + case 2: /* read local */ + T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip))); + break; + case 3: /* write local */ + T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP(); + break; + case 4: /* jump */ + t0off = t0_parse7E_signed(&ip); + ip += t0off; + break; + case 5: /* jump if */ + t0off = t0_parse7E_signed(&ip); + if (T0_POP()) { + ip += t0off; + } + break; + case 6: /* jump if not */ + t0off = t0_parse7E_signed(&ip); + if (!T0_POP()) { + ip += t0off; + } + break; + case 7: { + /* * */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a * b); + + } + break; + case 8: { + /* + */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a + b); + + } + break; + case 9: { + /* - */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a - b); + + } + break; + case 10: { + /* -rot */ + T0_NROT(); + } + break; + case 11: { + /* < */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 12: { + /* << */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x << c); + + } + break; + case 13: { + /* <= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a <= b)); + + } + break; + case 14: { + /* <> */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a != b)); + + } + break; + case 15: { + /* = */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a == b)); + + } + break; + case 16: { + /* > */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a > b)); + + } + break; + case 17: { + /* >= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a >= b)); + + } + break; + case 18: { + /* >> */ + + int c = (int)T0_POPi(); + int32_t x = T0_POPi(); + T0_PUSHi(x >> c); + + } + break; + case 19: { + /* and */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a & b); + + } + break; + case 20: { + /* begin-cert */ + + if (ENG->chain_len == 0) { + T0_PUSHi(-1); + } else { + ENG->cert_cur = ENG->chain->data; + ENG->cert_len = ENG->chain->data_len; + ENG->chain ++; + ENG->chain_len --; + T0_PUSH(ENG->cert_len); + } + + } + break; + case 21: { + /* begin-ta-name */ + + const br_x500_name *dn; + if (CTX->cur_dn_index >= CTX->num_tas) { + T0_PUSHi(-1); + } else { + if (CTX->ta_names == NULL) { + dn = &CTX->tas[CTX->cur_dn_index].dn; + } else { + dn = &CTX->ta_names[CTX->cur_dn_index]; + } + CTX->cur_dn_index ++; + CTX->cur_dn = dn->data; + CTX->cur_dn_len = dn->len; + T0_PUSH(CTX->cur_dn_len); + } + + } + break; + case 22: { + /* begin-ta-name-list */ + + CTX->cur_dn_index = 0; + + } + break; + case 23: { + /* bzero */ + + size_t len = (size_t)T0_POP(); + void *addr = (unsigned char *)ENG + (size_t)T0_POP(); + memset(addr, 0, len); + + } + break; + case 24: { + /* call-policy-handler */ + + int x; + br_ssl_server_choices choices; + + x = (*CTX->policy_vtable)->choose( + CTX->policy_vtable, CTX, &choices); + ENG->session.cipher_suite = choices.cipher_suite; + CTX->sign_hash_id = choices.algo_id; + ENG->chain = choices.chain; + ENG->chain_len = choices.chain_len; + T0_PUSHi(-(x != 0)); + + } + break; + case 25: { + /* can-output? */ + + T0_PUSHi(-(ENG->hlen_out > 0)); + + } + break; + case 26: { + /* check-resume */ + + if (ENG->session.session_id_len == 32 + && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load( + CTX->cache_vtable, CTX, &ENG->session)) + { + T0_PUSHi(-1); + } else { + T0_PUSH(0); + } + + } + break; + case 27: { + /* co */ + T0_CO(); + } + break; + case 28: { + /* compute-Finished-inner */ + + int prf_id = T0_POP(); + int from_client = T0_POPi(); + unsigned char tmp[48]; + br_tls_prf_seed_chunk seed; + + br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id); + seed.data = tmp; + if (ENG->session.version >= BR_TLS12) { + seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp); + } else { + br_multihash_out(&ENG->mhash, br_md5_ID, tmp); + br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16); + seed.len = 36; + } + prf(ENG->pad, 12, ENG->session.master_secret, + sizeof ENG->session.master_secret, + from_client ? "client finished" : "server finished", + 1, &seed); + + } + break; + case 29: { + /* compute-hash-CV */ + + int i; + + for (i = 1; i <= 6; i ++) { + br_multihash_out(&ENG->mhash, i, + ENG->pad + HASH_PAD_OFF[i - 1]); + } + + } + break; + case 30: { + /* copy-cert-chunk */ + + size_t clen; + + clen = ENG->cert_len; + if (clen > sizeof ENG->pad) { + clen = sizeof ENG->pad; + } + memcpy(ENG->pad, ENG->cert_cur, clen); + ENG->cert_cur += clen; + ENG->cert_len -= clen; + T0_PUSH(clen); + + } + break; + case 31: { + /* copy-dn-chunk */ + + size_t clen; + + clen = CTX->cur_dn_len; + if (clen > sizeof ENG->pad) { + clen = sizeof ENG->pad; + } + memcpy(ENG->pad, CTX->cur_dn, clen); + CTX->cur_dn += clen; + CTX->cur_dn_len -= clen; + T0_PUSH(clen); + + } + break; + case 32: { + /* copy-hash-CV */ + + int id = T0_POP(); + size_t off, len; + + if (id == 0) { + off = 0; + len = 36; + } else { + if (br_multihash_getimpl(&ENG->mhash, id) == 0) { + T0_PUSH(0); + T0_RET(); + } + off = HASH_PAD_OFF[id - 1]; + len = HASH_PAD_OFF[id] - off; + } + memcpy(CTX->hash_CV, ENG->pad + off, len); + CTX->hash_CV_len = len; + CTX->hash_CV_id = id; + T0_PUSHi(-1); + + } + break; + case 33: { + /* copy-protocol-name */ + + size_t idx = T0_POP(); + size_t len = strlen(ENG->protocol_names[idx]); + memcpy(ENG->pad, ENG->protocol_names[idx], len); + T0_PUSH(len); + + } + break; + case 34: { + /* data-get8 */ + + size_t addr = T0_POP(); + T0_PUSH(t0_datablock[addr]); + + } + break; + case 35: { + /* discard-input */ + + ENG->hlen_in = 0; + + } + break; + case 36: { + /* do-ecdh */ + + int prf_id = T0_POPi(); + size_t len = T0_POP(); + do_ecdh(CTX, prf_id, ENG->pad, len); + + } + break; + case 37: { + /* do-ecdhe-part1 */ + + int curve = T0_POPi(); + T0_PUSHi(do_ecdhe_part1(CTX, curve)); + + } + break; + case 38: { + /* do-ecdhe-part2 */ + + int prf_id = T0_POPi(); + size_t len = T0_POP(); + do_ecdhe_part2(CTX, prf_id, ENG->pad, len); + + } + break; + case 39: { + /* do-rsa-decrypt */ + + int prf_id = T0_POPi(); + size_t len = T0_POP(); + do_rsa_decrypt(CTX, prf_id, ENG->pad, len); + + } + break; + case 40: { + /* do-static-ecdh */ + + do_static_ecdh(CTX, T0_POP()); + + } + break; + case 41: { + /* drop */ + (void)T0_POP(); + } + break; + case 42: { + /* dup */ + T0_PUSH(T0_PEEK(0)); + } + break; + case 43: { + /* fail */ + + br_ssl_engine_fail(ENG, (int)T0_POPi()); + T0_CO(); + + } + break; + case 44: { + /* flush-record */ + + br_ssl_engine_flush_record(ENG); + + } + break; + case 45: { + /* get-key-type-usages */ + + const br_x509_class *xc; + const br_x509_pkey *pk; + unsigned usages; + + xc = *(ENG->x509ctx); + pk = xc->get_pkey(ENG->x509ctx, &usages); + if (pk == NULL) { + T0_PUSH(0); + } else { + T0_PUSH(pk->key_type | usages); + } + + } + break; + case 46: { + /* get16 */ + + size_t addr = (size_t)T0_POP(); + T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr)); + + } + break; + case 47: { + /* get32 */ + + size_t addr = (size_t)T0_POP(); + T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr)); + + } + break; + case 48: { + /* get8 */ + + size_t addr = (size_t)T0_POP(); + T0_PUSH(*((unsigned char *)ENG + addr)); + + } + break; + case 49: { + /* has-input? */ + + T0_PUSHi(-(ENG->hlen_in != 0)); + + } + break; + case 50: { + /* memcmp */ + + size_t len = (size_t)T0_POP(); + void *addr2 = (unsigned char *)ENG + (size_t)T0_POP(); + void *addr1 = (unsigned char *)ENG + (size_t)T0_POP(); + int x = memcmp(addr1, addr2, len); + T0_PUSH((uint32_t)-(x == 0)); + + } + break; + case 51: { + /* memcpy */ + + size_t len = (size_t)T0_POP(); + void *src = (unsigned char *)ENG + (size_t)T0_POP(); + void *dst = (unsigned char *)ENG + (size_t)T0_POP(); + memcpy(dst, src, len); + + } + break; + case 52: { + /* mkrand */ + + size_t len = (size_t)T0_POP(); + void *addr = (unsigned char *)ENG + (size_t)T0_POP(); + br_hmac_drbg_generate(&ENG->rng, addr, len); + + } + break; + case 53: { + /* more-incoming-bytes? */ + + T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG)); + + } + break; + case 54: { + /* multihash-init */ + + br_multihash_init(&ENG->mhash); + + } + break; + case 55: { + /* neg */ + + uint32_t a = T0_POP(); + T0_PUSH(-a); + + } + break; + case 56: { + /* not */ + + uint32_t a = T0_POP(); + T0_PUSH(~a); + + } + break; + case 57: { + /* or */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a | b); + + } + break; + case 58: { + /* over */ + T0_PUSH(T0_PEEK(1)); + } + break; + case 59: { + /* pick */ + T0_PICK(T0_POP()); + } + break; + case 60: { + /* read-chunk-native */ + + size_t clen = ENG->hlen_in; + if (clen > 0) { + uint32_t addr, len; + + len = T0_POP(); + addr = T0_POP(); + if ((size_t)len < clen) { + clen = (size_t)len; + } + memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen); + if (ENG->record_type_in == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen); + } + T0_PUSH(addr + (uint32_t)clen); + T0_PUSH(len - (uint32_t)clen); + ENG->hbuf_in += clen; + ENG->hlen_in -= clen; + } + + } + break; + case 61: { + /* read8-native */ + + if (ENG->hlen_in > 0) { + unsigned char x; + + x = *ENG->hbuf_in ++; + if (ENG->record_type_in == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, &x, 1); + } + T0_PUSH(x); + ENG->hlen_in --; + } else { + T0_PUSHi(-1); + } + + } + break; + case 62: { + /* save-session */ + + if (CTX->cache_vtable != NULL) { + (*CTX->cache_vtable)->save( + CTX->cache_vtable, CTX, &ENG->session); + } + + } + break; + case 63: { + /* set-max-frag-len */ + + size_t max_frag_len = T0_POP(); + + br_ssl_engine_new_max_frag_len(ENG, max_frag_len); + + /* + * We must adjust our own output limit. Since we call this only + * after receiving a ClientHello and before beginning to send + * the ServerHello, the next output record should be empty at + * that point, so we can use max_frag_len as a limit. + */ + if (ENG->hlen_out > max_frag_len) { + ENG->hlen_out = max_frag_len; + } + + } + break; + case 64: { + /* set16 */ + + size_t addr = (size_t)T0_POP(); + *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP(); + + } + break; + case 65: { + /* set32 */ + + size_t addr = (size_t)T0_POP(); + *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP(); + + } + break; + case 66: { + /* set8 */ + + size_t addr = (size_t)T0_POP(); + *((unsigned char *)ENG + addr) = (unsigned char)T0_POP(); + + } + break; + case 67: { + /* supported-curves */ + + uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves; + T0_PUSH(x); + + } + break; + case 68: { + /* supported-hash-functions */ + + int i; + unsigned x, num; + + x = 0; + num = 0; + for (i = br_sha1_ID; i <= br_sha512_ID; i ++) { + if (br_multihash_getimpl(&ENG->mhash, i)) { + x |= 1U << i; + num ++; + } + } + T0_PUSH(x); + T0_PUSH(num); + + } + break; + case 69: { + /* supports-ecdsa? */ + + T0_PUSHi(-(ENG->iecdsa != 0)); + + } + break; + case 70: { + /* supports-rsa-sign? */ + + T0_PUSHi(-(ENG->irsavrfy != 0)); + + } + break; + case 71: { + /* swap */ + T0_SWAP(); + } + break; + case 72: { + /* switch-aesccm-in */ + + int is_client, prf_id; + unsigned cipher_key_len, tag_len; + + tag_len = T0_POP(); + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id, + ENG->iaes_ctrcbc, cipher_key_len, tag_len); + + } + break; + case 73: { + /* switch-aesccm-out */ + + int is_client, prf_id; + unsigned cipher_key_len, tag_len; + + tag_len = T0_POP(); + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id, + ENG->iaes_ctrcbc, cipher_key_len, tag_len); + + } + break; + case 74: { + /* switch-aesgcm-in */ + + int is_client, prf_id; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id, + ENG->iaes_ctr, cipher_key_len); + + } + break; + case 75: { + /* switch-aesgcm-out */ + + int is_client, prf_id; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id, + ENG->iaes_ctr, cipher_key_len); + + } + break; + case 76: { + /* switch-cbc-in */ + + int is_client, prf_id, mac_id, aes; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + aes = T0_POP(); + mac_id = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id, + aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len); + + } + break; + case 77: { + /* switch-cbc-out */ + + int is_client, prf_id, mac_id, aes; + unsigned cipher_key_len; + + cipher_key_len = T0_POP(); + aes = T0_POP(); + mac_id = T0_POP(); + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id, + aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len); + + } + break; + case 78: { + /* switch-chapol-in */ + + int is_client, prf_id; + + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id); + + } + break; + case 79: { + /* switch-chapol-out */ + + int is_client, prf_id; + + prf_id = T0_POP(); + is_client = T0_POP(); + br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id); + + } + break; + case 80: { + /* ta-names-total-length */ + + size_t u, len; + + len = 0; + if (CTX->ta_names != NULL) { + for (u = 0; u < CTX->num_tas; u ++) { + len += CTX->ta_names[u].len + 2; + } + } else if (CTX->tas != NULL) { + for (u = 0; u < CTX->num_tas; u ++) { + len += CTX->tas[u].dn.len + 2; + } + } + T0_PUSH(len); + + } + break; + case 81: { + /* test-protocol-name */ + + size_t len = T0_POP(); + size_t u; + + for (u = 0; u < ENG->protocol_names_num; u ++) { + const char *name; + + name = ENG->protocol_names[u]; + if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) { + T0_PUSH(u); + T0_RET(); + } + } + T0_PUSHi(-1); + + } + break; + case 82: { + /* total-chain-length */ + + size_t u; + uint32_t total; + + total = 0; + for (u = 0; u < ENG->chain_len; u ++) { + total += 3 + (uint32_t)ENG->chain[u].data_len; + } + T0_PUSH(total); + + } + break; + case 83: { + /* u< */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 84: { + /* u>> */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x >> c); + + } + break; + case 85: { + /* verify-CV-sig */ + + int err; + + err = verify_CV_sig(CTX, T0_POP()); + T0_PUSHi(err); + + } + break; + case 86: { + /* write-blob-chunk */ + + size_t clen = ENG->hlen_out; + if (clen > 0) { + uint32_t addr, len; + + len = T0_POP(); + addr = T0_POP(); + if ((size_t)len < clen) { + clen = (size_t)len; + } + memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen); + if (ENG->record_type_out == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen); + } + T0_PUSH(addr + (uint32_t)clen); + T0_PUSH(len - (uint32_t)clen); + ENG->hbuf_out += clen; + ENG->hlen_out -= clen; + } + + } + break; + case 87: { + /* write8-native */ + + unsigned char x; + + x = (unsigned char)T0_POP(); + if (ENG->hlen_out > 0) { + if (ENG->record_type_out == BR_SSL_HANDSHAKE) { + br_multihash_update(&ENG->mhash, &x, 1); + } + *ENG->hbuf_out ++ = x; + ENG->hlen_out --; + T0_PUSHi(-1); + } else { + T0_PUSHi(0); + } + + } + break; + case 88: { + /* x509-append */ + + const br_x509_class *xc; + size_t len; + + xc = *(ENG->x509ctx); + len = T0_POP(); + xc->append(ENG->x509ctx, ENG->pad, len); + + } + break; + case 89: { + /* x509-end-cert */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->end_cert(ENG->x509ctx); + + } + break; + case 90: { + /* x509-end-chain */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + T0_PUSH(xc->end_chain(ENG->x509ctx)); + + } + break; + case 91: { + /* x509-start-cert */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->start_cert(ENG->x509ctx, T0_POP()); + + } + break; + case 92: { + /* x509-start-chain */ + + const br_x509_class *xc; + uint32_t bc; + + bc = T0_POP(); + xc = *(ENG->x509ctx); + xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL); + + } + break; + } + + } else { + T0_ENTER(ip, rp, t0x); + } + } +t0_exit: + ((t0_context *)t0ctx)->dp = dp; + ((t0_context *)t0ctx)->rp = rp; + ((t0_context *)t0ctx)->ip = ip; +} diff --git a/src/bearssl/src/ssl/ssl_hs_server.t0 b/src/bearssl/src/ssl/ssl_hs_server.t0 new file mode 100644 index 0000000..9f6e934 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_hs_server.t0 @@ -0,0 +1,1510 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +\ ---------------------------------------------------------------------- +\ Handshake processing code, for the server. +\ The common T0 code (ssl_hs_common.t0) shall be read first. + +preamble { + +/* + * This macro evaluates to a pointer to the server context, under that + * specific name. It must be noted that since the engine context is the + * first field of the br_ssl_server_context structure ('eng'), then + * pointers values of both types are interchangeable, modulo an + * appropriate cast. This also means that "addresses" computed as offsets + * within the structure work for both kinds of context. + */ +#define CTX ((br_ssl_server_context *)ENG) + +/* + * Decrypt the pre-master secret (RSA key exchange). + */ +static void +do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id, + unsigned char *epms, size_t len) +{ + uint32_t x; + unsigned char rpms[48]; + + /* + * Decrypt the PMS. + */ + x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len); + + /* + * Set the first two bytes to the maximum supported client + * protocol version. These bytes are used for version rollback + * detection; forceing the two bytes will make the master secret + * wrong if the bytes are not correct. This process is + * recommended by RFC 5246 (section 7.4.7.1). + */ + br_enc16be(epms, ctx->client_max_version); + + /* + * Make a random PMS and copy it above the decrypted value if the + * decryption failed. Note that we use a constant-time conditional + * copy. + */ + br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms); + br_ccopy(x ^ 1, epms, rpms, sizeof rpms); + + /* + * Compute master secret. + */ + br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48); + + /* + * Clear the pre-master secret from RAM: it is normally a buffer + * in the context, hence potentially long-lived. + */ + memset(epms, 0, len); +} + +/* + * Common part for ECDH and ECDHE. + */ +static void +ecdh_common(br_ssl_server_context *ctx, int prf_id, + unsigned char *xcoor, size_t xcoor_len, uint32_t ctl) +{ + unsigned char rpms[80]; + + if (xcoor_len > sizeof rpms) { + xcoor_len = sizeof rpms; + ctl = 0; + } + + /* + * Make a random PMS and copy it above the decrypted value if the + * decryption failed. Note that we use a constant-time conditional + * copy. + */ + br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len); + br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len); + + /* + * Compute master secret. + */ + br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len); + + /* + * Clear the pre-master secret from RAM: it is normally a buffer + * in the context, hence potentially long-lived. + */ + memset(xcoor, 0, xcoor_len); +} + +/* + * Do the ECDH key exchange (not ECDHE). + */ +static void +do_ecdh(br_ssl_server_context *ctx, int prf_id, + unsigned char *cpoint, size_t cpoint_len) +{ + uint32_t x; + + /* + * Finalise the key exchange. + */ + x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, + cpoint, &cpoint_len); + ecdh_common(ctx, prf_id, cpoint, cpoint_len, x); +} + +/* + * Do the full static ECDH key exchange. When this function is called, + * it has already been verified that the cipher suite uses ECDH (not ECDHE), + * and the client's public key (from its certificate) has type EC and is + * apt for key exchange. + */ +static void +do_static_ecdh(br_ssl_server_context *ctx, int prf_id) +{ + unsigned char cpoint[133]; + size_t cpoint_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + cpoint_len = pk->key.ec.qlen; + if (cpoint_len > sizeof cpoint) { + /* + * If the point is larger than our buffer then we need to + * restrict it. Length 2 is not a valid point length, so + * the ECDH will fail. + */ + cpoint_len = 2; + } + memcpy(cpoint, pk->key.ec.q, cpoint_len); + do_ecdh(ctx, prf_id, cpoint, cpoint_len); +} + +static size_t +hash_data(br_ssl_server_context *ctx, + void *dst, int hash_id, const void *src, size_t len) +{ + const br_hash_class *hf; + br_hash_compat_context hc; + + if (hash_id == 0) { + unsigned char tmp[36]; + + hf = br_multihash_getimpl(&ctx->eng.mhash, br_md5_ID); + if (hf == NULL) { + return 0; + } + hf->init(&hc.vtable); + hf->update(&hc.vtable, src, len); + hf->out(&hc.vtable, tmp); + hf = br_multihash_getimpl(&ctx->eng.mhash, br_sha1_ID); + if (hf == NULL) { + return 0; + } + hf->init(&hc.vtable); + hf->update(&hc.vtable, src, len); + hf->out(&hc.vtable, tmp + 16); + memcpy(dst, tmp, 36); + return 36; + } else { + hf = br_multihash_getimpl(&ctx->eng.mhash, hash_id); + if (hf == NULL) { + return 0; + } + hf->init(&hc.vtable); + hf->update(&hc.vtable, src, len); + hf->out(&hc.vtable, dst); + return (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + } +} + +/* + * Do the ECDHE key exchange (part 1: generation of transient key, and + * computing of the point to send to the client). Returned value is the + * signature length (in bytes), or -x on error (with x being an error + * code). The encoded point is written in the ecdhe_point[] context buffer + * (length in ecdhe_point_len). + */ +static int +do_ecdhe_part1(br_ssl_server_context *ctx, int curve) +{ + unsigned algo_id; + unsigned mask; + const unsigned char *order; + size_t olen, glen; + size_t hv_len, sig_len; + + if (!((ctx->eng.iec->supported_curves >> curve) & 1)) { + return -BR_ERR_INVALID_ALGORITHM; + } + ctx->eng.ecdhe_curve = curve; + + /* + * Generate our private key. We need a non-zero random value + * which is lower than the curve order, in a "large enough" + * range. We force the top bit to 0 and bottom bit to 1, which + * does the trick. Note that contrary to what happens in ECDSA, + * this is not a problem if we do not cover the full range of + * possible values. + */ + order = ctx->eng.iec->order(curve, &olen); + mask = 0xFF; + while (mask >= order[0]) { + mask >>= 1; + } + br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen); + ctx->ecdhe_key[0] &= mask; + ctx->ecdhe_key[olen - 1] |= 0x01; + ctx->ecdhe_key_len = olen; + + /* + * Compute our ECDH point. + */ + glen = ctx->eng.iec->mulgen(ctx->eng.ecdhe_point, + ctx->ecdhe_key, olen, curve); + ctx->eng.ecdhe_point_len = glen; + + /* + * Assemble the message to be signed, and possibly hash it. + */ + memcpy(ctx->eng.pad, ctx->eng.client_random, 32); + memcpy(ctx->eng.pad + 32, ctx->eng.server_random, 32); + ctx->eng.pad[64 + 0] = 0x03; + ctx->eng.pad[64 + 1] = 0x00; + ctx->eng.pad[64 + 2] = curve; + ctx->eng.pad[64 + 3] = ctx->eng.ecdhe_point_len; + memcpy(ctx->eng.pad + 64 + 4, + ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len); + hv_len = 64 + 4 + ctx->eng.ecdhe_point_len; + algo_id = ctx->sign_hash_id; + if (algo_id >= (unsigned)0xFF00) { + hv_len = hash_data(ctx, ctx->eng.pad, algo_id & 0xFF, + ctx->eng.pad, hv_len); + if (hv_len == 0) { + return -BR_ERR_INVALID_ALGORITHM; + } + } + + sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable, + algo_id, ctx->eng.pad, hv_len, sizeof ctx->eng.pad); + return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM; +} + +/* + * Do the ECDHE key exchange (part 2: computation of the shared secret + * from the point sent by the client). + */ +static void +do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id, + unsigned char *cpoint, size_t cpoint_len) +{ + int curve; + uint32_t ctl; + size_t xoff, xlen; + + curve = ctx->eng.ecdhe_curve; + + /* + * Finalise the key exchange. + */ + ctl = ctx->eng.iec->mul(cpoint, cpoint_len, + ctx->ecdhe_key, ctx->ecdhe_key_len, curve); + xoff = ctx->eng.iec->xoff(curve, &xlen); + ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl); + + /* + * Clear the ECDHE private key. Forward Secrecy is achieved insofar + * as that key does not get stolen, so we'd better destroy it + * as soon as it ceases to be useful. + */ + memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len); +} + +/* + * Offset for hash value within the pad (when obtaining all hash values, + * in preparation for verification of the CertificateVerify message). + * Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value + * is used to get the total length. + */ +static const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 }; + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char HASH_OID_SHA1[] = { + 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char HASH_OID_SHA224[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char HASH_OID_SHA256[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char HASH_OID_SHA384[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char HASH_OID_SHA512[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const unsigned char *HASH_OID[] = { + HASH_OID_SHA1, + HASH_OID_SHA224, + HASH_OID_SHA256, + HASH_OID_SHA384, + HASH_OID_SHA512 +}; + +/* + * Verify the signature in CertificateVerify. Returned value is 0 on + * success, or a non-zero error code. Lack of implementation of the + * designated signature algorithm is reported as a "bad signature" + * error (because it means that the peer did not honour our advertised + * set of supported signature algorithms). + */ +static int +verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + int id; + + id = ctx->hash_CV_id; + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + if (pk->key_type == BR_KEYTYPE_RSA) { + unsigned char tmp[64]; + const unsigned char *hash_oid; + + if (id == 0) { + hash_oid = NULL; + } else { + hash_oid = HASH_OID[id - 2]; + } + if (ctx->eng.irsavrfy == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, + hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp) + || memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0) + { + return BR_ERR_BAD_SIGNATURE; + } + } else { + if (ctx->eng.iecdsa == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.iecdsa(ctx->eng.iec, + ctx->hash_CV, ctx->hash_CV_len, + &pk->key.ec, ctx->eng.pad, sig_len)) + { + return BR_ERR_BAD_SIGNATURE; + } + } + return 0; +} + +} + +\ ======================================================================= + +: addr-ctx: + next-word { field } + "addr-" field + 0 1 define-word + 0 8191 "offsetof(br_ssl_server_context, " field + ")" + make-CX + postpone literal postpone ; ; + +addr-ctx: client_max_version +addr-ctx: client_suites +addr-ctx: client_suites_num +addr-ctx: hashes +addr-ctx: curves +addr-ctx: sign_hash_id + +\ Get address and length of the client_suites[] buffer. Length is expressed +\ in bytes. +: addr-len-client_suites ( -- addr len ) + addr-client_suites + CX 0 1023 { BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated) } ; + +\ Read the client SNI extension. +: read-client-sni ( lim -- lim ) + \ Open extension value. + read16 open-elt + + \ Open ServerNameList. + read16 open-elt + + \ Find if there is a name of type 0 (host_name) with a length + \ that fits in our dedicated buffer. + begin dup while + read8 if + read-ignore-16 + else + read16 + dup 255 <= if + dup addr-server_name + 0 swap set8 + addr-server_name swap read-blob + else + skip-blob + then + then + repeat + + \ Close ServerNameList. + close-elt + + \ Close extension value. + close-elt ; + +\ Set the new maximum fragment length. BEWARE: this shall be called only +\ after reading the ClientHello and before writing the ServerHello. +cc: set-max-frag-len ( len -- ) { + size_t max_frag_len = T0_POP(); + + br_ssl_engine_new_max_frag_len(ENG, max_frag_len); + + /* + * We must adjust our own output limit. Since we call this only + * after receiving a ClientHello and before beginning to send + * the ServerHello, the next output record should be empty at + * that point, so we can use max_frag_len as a limit. + */ + if (ENG->hlen_out > max_frag_len) { + ENG->hlen_out = max_frag_len; + } +} + +\ Read the client Max Frag Length extension. +: read-client-frag ( lim -- lim ) + \ Extension value must have length exactly 1 byte. + read16 1 <> if ERR_BAD_FRAGLEN fail then + read8 + + \ The byte value must be 1, 2, 3 or 4. + dup dup 0= swap 5 >= or if ERR_BAD_FRAGLEN fail then + + \ If our own maximum fragment length is greater, then we reduce + \ our length. + 8 + dup addr-log_max_frag_len get8 < if + dup 1 swap << set-max-frag-len + dup addr-log_max_frag_len set8 + addr-peer_log_max_frag_len set8 + else + drop + then ; + +\ Read the Secure Renegotiation extension from the client. +: read-client-reneg ( lim -- lim ) + \ Get value length. + read16 + + \ The "reneg" value is one of: + \ 0 on first handshake, client support is unknown + \ 1 client does not support secure renegotiation + \ 2 client supports secure renegotiation + addr-reneg get8 case + 0 of + \ First handshake, value length shall be 1. + 1 = ifnot ERR_BAD_SECRENEG fail then + read8 if ERR_BAD_SECRENEG fail then + 2 addr-reneg set8 + endof + 2 of + \ Renegotiation, value shall consist of 13 bytes + \ (header + copy of the saved client "Finished"). + 13 = ifnot ERR_BAD_SECRENEG fail then + read8 12 = ifnot ERR_BAD_SECRENEG fail then + addr-pad 12 read-blob + addr-saved_finished addr-pad 12 memcmp ifnot + ERR_BAD_SECRENEG fail + then + endof + + \ If "reneg" is 1 then the client is not supposed to support + \ the extension, and it sends it nonetheless, which means + \ foul play. + ERR_BAD_SECRENEG fail + endcase ; + +\ Read the Signature Algorithms extension. +: read-signatures ( lim -- lim ) + \ Open extension value. + read16 open-elt + + read-list-sign-algos addr-hashes set32 + + \ Close extension value. + close-elt ; + +\ Read the Supported Curves extension. +: read-supported-curves ( lim -- lim ) + \ Open extension value. + read16 open-elt + + \ Open list of curve identifiers. + read16 open-elt + + \ Get all supported curves. + 0 addr-curves set32 + begin dup while + read16 dup 32 < if + 1 swap << addr-curves get32 or addr-curves set32 + else + drop + then + repeat + close-elt + close-elt ; + +\ Read the ALPN extension from client. +: read-ALPN-from-client ( lim -- lim ) + \ If we do not have configured names, then we just ignore the + \ extension. + addr-protocol_names_num get16 ifnot read-ignore-16 ret then + + \ Open extension value. + read16 open-elt + + \ Open list of protocol names. + read16 open-elt + + \ Get all names and test for their support. We keep the one with + \ the lowest index (because we apply server's preferences, as + \ recommended by RFC 7301, section 3.2. We set the 'found' variable + \ to -2 and use an unsigned comparison, making -2 a huge value. + -2 { found } + begin dup while + read8 dup { len } addr-pad swap read-blob + len test-protocol-name dup found u< if + >found + else + drop + then + repeat + + \ End of extension. + close-elt + close-elt + + \ Write back found name index (or not). If no match was found, + \ then we write -1 (0xFFFF) in the index value, not 0, so that + \ the caller knows that we tried to match, and failed. + found 1+ addr-selected_protocol set16 ; + +\ Call policy handler to get cipher suite, hash function identifier and +\ certificate chain. Returned value is 0 (false) on failure. +cc: call-policy-handler ( -- bool ) { + int x; + br_ssl_server_choices choices; + + x = (*CTX->policy_vtable)->choose( + CTX->policy_vtable, CTX, &choices); + ENG->session.cipher_suite = choices.cipher_suite; + CTX->sign_hash_id = choices.algo_id; + ENG->chain = choices.chain; + ENG->chain_len = choices.chain_len; + T0_PUSHi(-(x != 0)); +} + +\ Check for a remembered session. +cc: check-resume ( -- bool ) { + if (ENG->session.session_id_len == 32 + && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load( + CTX->cache_vtable, CTX, &ENG->session)) + { + T0_PUSHi(-1); + } else { + T0_PUSH(0); + } +} + +\ Save the current session. +cc: save-session ( -- ) { + if (CTX->cache_vtable != NULL) { + (*CTX->cache_vtable)->save( + CTX->cache_vtable, CTX, &ENG->session); + } +} + +\ Read and drop ClientHello. This is used when a client-triggered +\ renegotiation attempt is rejected. +: skip-ClientHello ( -- ) + read-handshake-header-core + 1 = ifnot ERR_UNEXPECTED fail then + dup skip-blob drop ; + +\ Read ClientHello. If the session is resumed, then -1 is returned. +: read-ClientHello ( -- resume ) + \ Get header, and check message type. + read-handshake-header 1 = ifnot ERR_UNEXPECTED fail then + + \ Get maximum protocol version from client. + read16 dup { client-version-max } addr-client_max_version set16 + + \ Client random. + addr-client_random 32 read-blob + + \ Client session ID. + read8 dup 32 > if ERR_OVERSIZED_ID fail then + dup addr-session_id_len set8 + addr-session_id swap read-blob + + \ Lookup session for resumption. We should do that here because + \ we need to verify that the remembered cipher suite is still + \ matched by this ClientHello. + check-resume { resume } + + \ Cipher suites. We read all cipher suites from client, each time + \ matching against our own list. We accumulate suites in the + \ client_suites[] context buffer: we keep suites that are + \ supported by both the client and the server (so the list size + \ cannot exceed that of the server list), and we keep them in + \ either client or server preference order (depending on the + \ relevant flag). + \ + \ We also need to identify the pseudo cipher suite for secure + \ renegotiation here. + read16 open-elt + 0 { reneg-scsv } + 0 { resume-suite } + addr-len-client_suites dup2 bzero + over + { css-off css-max } + begin + dup while + read16 dup { suite } + + \ Check that when resuming a session, the requested + \ suite is still valid. + resume if + dup addr-cipher_suite get16 = if + -1 >resume-suite + then + then + + \ Special handling for TLS_EMPTY_RENEGOTIATION_INFO_SCSV. + \ This fake cipher suite may occur only in the first + \ handshake. + dup 0x00FF = if + addr-reneg get8 if ERR_BAD_SECRENEG fail then + -1 >reneg-scsv + then + + \ Special handling for TLS_FALLBACK_SCSV. If the client + \ maximum version is less than our own maximum version, + \ then this is an undue downgrade. We mark it by setting + \ the client max version to 0x10000. + dup 0x5600 = if + client-version-max addr-version_min get16 >= + client-version-max addr-version_max get16 < and if + -1 >client-version-max + then + then + + \ Test whether the suite is supported by the server. + scan-suite dup 0< if + \ We do not support this cipher suite. Note + \ that this also covers the case of pseudo + \ cipher suites. + drop + else + \ If we use server order, then we place the + \ suite at the computed offset; otherwise, we + \ append it to the list at the current place. + 0 flag? if + 2 << addr-client_suites + suite swap set16 + else + drop + \ We need to test for list length because + \ the client list may have duplicates, + \ that we do not filter. Duplicates are + \ invalid so this is not a problem if we + \ reject such clients. + css-off css-max >= if + ERR_BAD_HANDSHAKE fail + then + suite css-off set16 + css-off 4 + >css-off + then + then + repeat + drop + + \ Compression methods. We need method 0 (no compression). + 0 { ok-compression } + read8 open-elt + begin dup while + read8 ifnot -1 >ok-compression then + repeat + close-elt + + \ Set default values for parameters that may be affected by + \ extensions: + \ -- server name is empty + \ -- client is reputed to know RSA and ECDSA, both with SHA-1 + \ -- the default elliptic curve is P-256 (secp256r1, id = 23) + 0 addr-server_name set8 + 0x0404 addr-hashes set32 + 0x800000 addr-curves set32 + + \ Process extensions, if any. + dup if + read16 open-elt + begin dup while + read16 case + \ Server Name Indication. + 0x0000 of + read-client-sni + endof + \ Max Frag Length. + 0x0001 of + read-client-frag + endof + \ Secure Renegotiation. + 0xFF01 of + read-client-reneg + endof + \ Signature Algorithms. + 0x000D of + read-signatures + endof + \ Supported Curves. + 0x000A of + read-supported-curves + endof + \ Supported Point Formats. + \ We only support "uncompressed", that all + \ implementations are supposed to support, + \ so we can simply ignore that extension. + \ 0x000B of + \ read-ignore-16 + \ endof + + \ ALPN + 0x0010 of + read-ALPN-from-client + endof + + \ Other extensions are ignored. + drop read-ignore-16 0 + endcase + repeat + close-elt + then + + \ Close message. + close-elt + + \ Cancel session resumption if the cipher suite was not found. + resume resume-suite and >resume + + \ Now check the received data. Since the client is expecting an + \ answer, we can send an appropriate fatal alert on any error. + + \ Compute protocol version as the minimum of our maximum version, + \ and the maximum version sent by the client. If that is less than + \ 0x0300 (SSL-3.0), then fail. Otherwise, we may at least send an + \ alert with that version. We still reject versions lower than our + \ configured minimum. + \ As a special case, in case of undue downgrade, we send a specific + \ alert (see RFC 7507). Note that this case may happen only if + \ we would otherwise accept the client's version. + client-version-max 0< if + addr-client_max_version get16 addr-version_out set16 + 86 fail-alert + then + addr-version_max get16 + dup client-version-max > if drop client-version-max then + dup 0x0300 < if ERR_BAD_VERSION fail then + client-version-max addr-version_min get16 < if + 70 fail-alert + then + \ If resuming the session, then enforce the previously negotiated + \ version (if still possible). + resume if + addr-version get16 client-version-max <= if + drop addr-version get16 + else + 0 >resume + then + then + dup addr-version set16 + dup addr-version_in set16 + dup addr-version_out set16 + 0x0303 >= { can-tls12 } + + \ If the client sent TLS_EMPTY_RENEGOTIATION_INFO_SCSV, then + \ we should mark the client as "supporting secure renegotiation". + reneg-scsv if 2 addr-reneg set8 then + + \ If, at that point, the 'reneg' value is still 0, then the client + \ did not send the extension or the SCSV, so we have to assume + \ that secure renegotiation is not supported by that client. + addr-reneg get8 ifnot 1 addr-reneg set8 then + + \ Check compression. + ok-compression ifnot 40 fail-alert then + + \ Filter hash function support by what the server also supports. + \ If no common hash function remains with RSA and/or ECDSA, then + \ the corresponding ECDHE suites are not possible. + supported-hash-functions drop 257 * 0xFFFF0000 or + addr-hashes get32 and dup addr-hashes set32 + \ In 'can-ecdhe', bit 12 is set if ECDHE_RSA is possible, bit 13 is + \ set if ECDHE_ECDSA is possible. + dup 0xFF and 0<> neg + swap 8 >> 0<> 2 and or 12 << { can-ecdhe } + + \ Filter supported curves. If there is no common curve between + \ client and us, then ECDHE suites cannot be used. Note that we + \ may still allow ECDH, depending on the EC key handler. + addr-curves get32 supported-curves and dup addr-curves set32 + ifnot 0 >can-ecdhe then + + \ If resuming a session, then the next steps are not necessary; + \ we won't invoke the policy handler. + resume if -1 ret then + + \ We are not resuming, so a new session ID should be generated. + \ We don't check that the new ID is distinct from the one sent + \ by the client because probability of such an event is 2^(-256), + \ i.e. much (much) lower than that of an undetected transmission + \ error or hardware miscomputation, and with similar consequences + \ (handshake simply fails). + addr-session_id 32 mkrand + 32 addr-session_id_len set8 + + \ Translate common cipher suites, then squeeze out holes: there + \ may be holes because of the way we fill the list when the + \ server preference order is enforced, and also in case some + \ suites are filtered out. In particular: + \ -- ECDHE suites are removed if there is no common hash function + \ (for the relevant signature algorithm) or no common curve. + \ -- TLS-1.2-only suites are removed if the negotiated version is + \ TLS-1.1 or lower. + addr-client_suites dup >css-off + begin dup css-max < while + dup get16 dup cipher-suite-to-elements + dup 12 >> dup 1 = swap 2 = or if + dup can-ecdhe and ifnot + 2drop 0 dup + then + then + can-tls12 ifnot + \ Suites compatible with TLS-1.0 and TLS-1.1 are + \ exactly the ones that use HMAC/SHA-1. + dup 0xF0 and 0x20 <> if + 2drop 0 dup + then + then + dup if + css-off 2+ set16 css-off set16 + css-off 4 + >css-off + else + 2drop + then + 4 + + repeat + drop + css-off addr-client_suites - 2 >> + dup ifnot + \ No common cipher suite: handshake failure. + 40 fail-alert + then + addr-client_suites_num set8 + + \ Check ALPN. + addr-selected_protocol get16 0xFFFF = if + 3 flag? if 120 fail-alert then + 0 addr-selected_protocol set16 + then + + \ Call policy handler to obtain the cipher suite and other + \ parameters. + call-policy-handler ifnot 40 fail-alert then + + \ We are not resuming a session. + 0 ; + +\ Write ServerHello. +: write-ServerHello ( initial -- ) + { initial } + \ Compute ServerHello length. + 2 write8 70 + + \ Compute length of Secure Renegotiation extension. + addr-reneg get8 2 = if + initial if 5 else 29 then + else + 0 + then + { ext-reneg-len } + + \ Compute length of Max Fragment Length extension. + addr-peer_log_max_frag_len get8 if 5 else 0 then + { ext-max-frag-len } + + \ Compute length of ALPN extension. This also copy the + \ selected protocol name into the pad. + addr-selected_protocol get16 dup if 1- copy-protocol-name 7 + then + { ext-ALPN-len } + + \ Adjust ServerHello length to account for the extensions. + ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if 2 + then + + write24 + + \ Protocol version + addr-version get16 write16 + + \ Server random + addr-server_random 4 bzero + addr-server_random 4 + 28 mkrand + addr-server_random 32 write-blob + + \ Session ID + \ TODO: if we have no session cache at all, we might send here + \ an empty session ID. This would save a bit of network + \ bandwidth. + 32 write8 + addr-session_id 32 write-blob + + \ Cipher suite + addr-cipher_suite get16 write16 + + \ Compression method + 0 write8 + + \ Extensions + ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if + write16 + ext-reneg-len dup if + 0xFF01 write16 + 4 - dup write16 + 1- addr-saved_finished swap write-blob-head8 + else + drop + then + ext-max-frag-len if + 0x0001 write16 + 1 write16 addr-peer_log_max_frag_len get8 8 - write8 + then + ext-ALPN-len dup if + \ Note: the selected protocol name was previously + \ copied into the pad. + 0x0010 write16 + 4 - dup write16 + 2- dup write16 + 1- addr-pad swap write-blob-head8 + else + drop + then + else + drop + then ; + +\ Do the first part of ECDHE. Returned value is the computed signature +\ length, or a negative error code on error. +cc: do-ecdhe-part1 ( curve -- len ) { + int curve = T0_POPi(); + T0_PUSHi(do_ecdhe_part1(CTX, curve)); +} + +\ Get index of first bit set to 1 (in low to high order). +: lowest-1 ( bits -- n ) + dup ifnot drop -1 ret then + 0 begin dup2 >> 1 and 0= while 1+ repeat + swap drop ; + +\ Write the Server Key Exchange message (if applicable). +: write-ServerKeyExchange ( -- ) + addr-cipher_suite get16 use-ecdhe? ifnot ret then + + \ We must select an appropriate curve among the curves that + \ are supported both by us and the peer. Right now, we apply + \ a fixed preference order: Curve25519, P-256, P-384, P-521, + \ then the common curve with the lowest ID. + \ (TODO: add some option to make that behaviour configurable.) + \ + \ This loop always terminates because previous processing made + \ sure that ECDHE suites are not selectable if there is no common + \ curve. + addr-curves get32 + dup 0x20000000 and if + drop 29 + else + dup 0x38000000 and dup if swap then + drop lowest-1 + then + { curve-id } + + \ Compute the signed curve point to send. + curve-id do-ecdhe-part1 dup 0< if neg fail then { sig-len } + + \ If using TLS-1.2+, then the hash function and signature + \ algorithm are explicitly encoded in the message. + addr-version get16 0x0303 >= { tls1.2+ } + + 12 write8 + sig-len addr-ecdhe_point_len get8 + tls1.2+ 2 and + 6 + write24 + + \ Curve parameters: named curve with 16-bit ID. + 3 write8 curve-id write16 + + \ Public point. + addr-ecdhe_point addr-ecdhe_point_len get8 write-blob-head8 + + \ If TLS-1.2+, write hash and signature identifiers. + tls1.2+ if + \ sign_hash_id contains either a hash identifier, + \ or the complete 16-bit value to write. + addr-sign_hash_id get16 + dup 0xFF00 < if + write16 + else + 0xFF and write8 + \ 'use-rsa-ecdhe?' returns -1 for RSA, 0 for + \ ECDSA. The byte on the wire shall be 1 for RSA, + \ 3 for ECDSA. + addr-cipher_suite get16 use-rsa-ecdhe? 1 << 3 + write8 + then + then + + \ Signature. + sig-len write16 + addr-pad sig-len write-blob ; + +\ Get length of the list of anchor names to send to the client. The length +\ includes the per-name 2-byte header, but _not_ the 2-byte header for +\ the list itself. If no client certificate is requested, then this +\ returns 0. +cc: ta-names-total-length ( -- len ) { + size_t u, len; + + len = 0; + if (CTX->ta_names != NULL) { + for (u = 0; u < CTX->num_tas; u ++) { + len += CTX->ta_names[u].len + 2; + } + } else if (CTX->tas != NULL) { + for (u = 0; u < CTX->num_tas; u ++) { + len += CTX->tas[u].dn.len + 2; + } + } + T0_PUSH(len); +} + +\ Compute length and optionally write the contents of the list of +\ supported client authentication methods. +: write-list-auth ( do_write -- len ) + 0 + addr-cipher_suite get16 use-ecdh? if + 2+ over if 65 write8 66 write8 then + then + supports-rsa-sign? if 1+ over if 1 write8 then then + supports-ecdsa? if 1+ over if 64 write8 then then + swap drop ; + +: write-signhash-inner2 ( dow algo hashes len id -- dow algo hashes len ) + { id } + over 1 id << and ifnot ret then + 2+ + 3 pick if id write8 2 pick write8 then ; + +: write-signhash-inner1 ( dow algo hashes -- dow len ) + 0 + 4 write-signhash-inner2 + 5 write-signhash-inner2 + 6 write-signhash-inner2 + 3 write-signhash-inner2 + 2 write-signhash-inner2 + -rot 2drop ; + +\ Compute length and optionally write the contents of the list of +\ supported sign+hash algorithms. +: write-list-signhash ( do_write -- len ) + 0 { len } + \ If supporting neither RSA nor ECDSA in the engine, then we + \ will do only static ECDH, and thus we claim support for + \ everything (for the X.509 validator). + supports-rsa-sign? supports-ecdsa? or ifnot + 1 0x7C write-signhash-inner1 >len + 3 0x7C write-signhash-inner1 len + + swap drop ret + then + supports-rsa-sign? if + 1 supported-hash-functions drop + write-signhash-inner1 >len + then + supports-ecdsa? if + 3 supported-hash-functions drop + write-signhash-inner1 len + >len + then + drop len ; + +\ Initialise index for sending the list of anchor DN. +cc: begin-ta-name-list ( -- ) { + CTX->cur_dn_index = 0; +} + +\ Switch to next DN in the list. Returned value is the DN length, or -1 +\ if the end of the list was reached. +cc: begin-ta-name ( -- len ) { + const br_x500_name *dn; + if (CTX->cur_dn_index >= CTX->num_tas) { + T0_PUSHi(-1); + } else { + if (CTX->ta_names == NULL) { + dn = &CTX->tas[CTX->cur_dn_index].dn; + } else { + dn = &CTX->ta_names[CTX->cur_dn_index]; + } + CTX->cur_dn_index ++; + CTX->cur_dn = dn->data; + CTX->cur_dn_len = dn->len; + T0_PUSH(CTX->cur_dn_len); + } +} + +\ Copy a chunk of the current DN into the pad. Returned value is the +\ chunk length; this is 0 when the end of the current DN is reached. +cc: copy-dn-chunk ( -- len ) { + size_t clen; + + clen = CTX->cur_dn_len; + if (clen > sizeof ENG->pad) { + clen = sizeof ENG->pad; + } + memcpy(ENG->pad, CTX->cur_dn, clen); + CTX->cur_dn += clen; + CTX->cur_dn_len -= clen; + T0_PUSH(clen); +} + +\ Write a CertificateRequest message. +: write-CertificateRequest ( -- ) + \ The list of client authentication types includes: + \ rsa_sign (1) + \ ecdsa_sign (64) + \ rsa_fixed_ecdh (65) + \ ecdsa_fixed_ecdh (66) + \ rsa_sign and ecdsa_sign require, respectively, RSA and ECDSA + \ support. Static ECDH requires that the cipher suite is ECDH. + \ When we ask for static ECDH, we always send both rsa_fixed_ecdh + \ and ecdsa_fixed_ecdh because what matters there is what the + \ X.509 engine may support, and we do not control that. + \ + \ With TLS 1.2, we must also send a list of supported signature + \ and hash algorithms. That list is supposed to qualify both + \ the engine itself, and the X.509 validator, which are separate + \ in BearSSL. There again, we use the engine capabilities in that + \ list, and resort to a generic all-support list if only + \ static ECDH is accepted. + \ + \ (In practice, client implementations tend to have at most one + \ or two certificates, and send the chain regardless of what + \ algorithms are used in it.) + + 0 write-list-auth + addr-version get16 0x0303 >= if + 2+ 0 write-list-signhash + + then + ta-names-total-length + 3 + + + \ Message header + 13 write8 write24 + + \ List of authentication methods + 0 write-list-auth write8 1 write-list-auth drop + + \ For TLS 1.2+, list of sign+hash + addr-version get16 0x0303 >= if + 0 write-list-signhash write16 1 write-list-signhash drop + then + + \ Trust anchor names + ta-names-total-length write16 + begin-ta-name-list + begin + begin-ta-name + dup 0< if drop ret then write16 + begin copy-dn-chunk dup while + addr-pad swap write-blob + repeat + drop + again ; + +\ Write the Server Hello Done message. +: write-ServerHelloDone ( -- ) + 14 write8 0 write24 ; + +\ Perform RSA decryption of the client-sent pre-master secret. The value +\ is in the pad, and its length is provided as parameter. +cc: do-rsa-decrypt ( len prf_id -- ) { + int prf_id = T0_POPi(); + size_t len = T0_POP(); + do_rsa_decrypt(CTX, prf_id, ENG->pad, len); +} + +\ Perform ECDH (not ECDHE). The point from the client is in the pad, and +\ its length is provided as parameter. +cc: do-ecdh ( len prf_id -- ) { + int prf_id = T0_POPi(); + size_t len = T0_POP(); + do_ecdh(CTX, prf_id, ENG->pad, len); +} + +\ Do the second part of ECDHE. +cc: do-ecdhe-part2 ( len prf_id -- ) { + int prf_id = T0_POPi(); + size_t len = T0_POP(); + do_ecdhe_part2(CTX, prf_id, ENG->pad, len); +} + +\ Perform static ECDH. The point from the client is the public key +\ extracted from its certificate. +cc: do-static-ecdh ( prf_id -- ) { + do_static_ecdh(CTX, T0_POP()); +} + +\ Read a ClientKeyExchange header. +: read-ClientKeyExchange-header ( -- len ) + read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then ; + +\ Read the Client Key Exchange contents (non-empty case). +: read-ClientKeyExchange-contents ( lim -- ) + \ What we should get depends on the cipher suite. + addr-cipher_suite get16 use-rsa-keyx? if + \ RSA key exchange: we expect a RSA-encrypted value. + read16 + dup 512 > if ERR_LIMIT_EXCEEDED fail then + dup { enc-rsa-len } + addr-pad swap read-blob + enc-rsa-len addr-cipher_suite get16 prf-id do-rsa-decrypt + then + addr-cipher_suite get16 dup use-ecdhe? swap use-ecdh? { ecdhe ecdh } + ecdh ecdhe or if + \ ECDH or ECDHE key exchange: we expect an EC point. + read8 dup { ec-point-len } + addr-pad swap read-blob + ec-point-len addr-cipher_suite get16 prf-id + ecdhe if do-ecdhe-part2 else do-ecdh then + then + close-elt ; + +\ Read the Client Key Exchange (normal case). +: read-ClientKeyExchange ( -- ) + read-ClientKeyExchange-header + read-ClientKeyExchange-contents ; + +\ Obtain all possible hash values for handshake messages so far. This +\ is done because we need the hash value for the CertificateVerify +\ _before_ knowing which hash function will actually be used, as this +\ information is obtained from decoding the message header itself. +\ All hash values are stored in the pad (208 bytes in total). +cc: compute-hash-CV ( -- ) { + int i; + + for (i = 1; i <= 6; i ++) { + br_multihash_out(&ENG->mhash, i, + ENG->pad + HASH_PAD_OFF[i - 1]); + } +} + +\ Copy the proper hash value from the pad into the dedicated buffer. +\ Returned value is true (-1) on success, false (0) on error (error +\ being an unimplemented hash function). The id has already been verified +\ to be either 0 (for MD5+SHA-1) or one of the SHA-* functions. +cc: copy-hash-CV ( hash_id -- bool ) { + int id = T0_POP(); + size_t off, len; + + if (id == 0) { + off = 0; + len = 36; + } else { + if (br_multihash_getimpl(&ENG->mhash, id) == 0) { + T0_PUSH(0); + T0_RET(); + } + off = HASH_PAD_OFF[id - 1]; + len = HASH_PAD_OFF[id] - off; + } + memcpy(CTX->hash_CV, ENG->pad + off, len); + CTX->hash_CV_len = len; + CTX->hash_CV_id = id; + T0_PUSHi(-1); +} + +\ Verify signature in CertificateVerify. Output is 0 on success, or a +\ non-zero error code. +cc: verify-CV-sig ( sig-len -- err ) { + int err; + + err = verify_CV_sig(CTX, T0_POP()); + T0_PUSHi(err); +} + +\ Process static ECDH. +: process-static-ECDH ( ktu -- ) + \ Static ECDH is allowed only if the cipher suite uses ECDH, and + \ the client's public key has type EC and allows key exchange. + \ BR_KEYTYPE_KEYX is 0x10, and BR_KEYTYPE_EC is 2. + 0x1F and 0x12 = ifnot ERR_WRONG_KEY_USAGE fail then + addr-cipher_suite get16 + dup use-ecdh? ifnot ERR_UNEXPECTED fail then + prf-id + do-static-ecdh ; + +\ Read CertificateVerify header. +: read-CertificateVerify-header ( -- lim ) + compute-hash-CV + read-handshake-header 15 = ifnot ERR_UNEXPECTED fail then ; + +\ Read CertificateVerify. The client key type + usage is expected on the +\ stack. +: read-CertificateVerify ( ktu -- ) + \ Check that the key allows for signatures. + dup 0x20 and ifnot ERR_WRONG_KEY_USAGE fail then + 0x0F and { key-type } + + \ Get header. + read-CertificateVerify-header + + \ With TLS 1.2+, there is an explicit hash + signature indication, + \ which must be compatible with the key type. + addr-version get16 0x0303 >= if + \ Get hash function, then signature algorithm. The + \ signature algorithm is 1 (RSA) or 3 (ECDSA) while our + \ symbolic constants for key types are 1 (RSA) or 2 (EC). + read16 + dup 0xFF and 1+ 1 >> key-type = ifnot + ERR_BAD_SIGNATURE fail + then + 8 >> + + \ We support only SHA-1, SHA-224, SHA-256, SHA-384 + \ and SHA-512. We explicitly reject MD5. + dup 2 < over 6 > or if ERR_INVALID_ALGORITHM fail then + else + \ With TLS 1.0 and 1.1, hash is MD5+SHA-1 (0) for RSA, + \ SHA-1 (2) for ECDSA. + key-type 0x01 = if 0 else 2 then + then + copy-hash-CV ifnot ERR_INVALID_ALGORITHM fail then + + \ Read signature. + read16 dup { sig-len } + dup 512 > if ERR_LIMIT_EXCEEDED fail then + addr-pad swap read-blob + sig-len verify-CV-sig + dup if fail then drop + + close-elt ; + +\ Send a HelloRequest. +: send-HelloRequest ( -- ) + flush-record + begin can-output? not while wait-co drop repeat + 22 addr-record_type_out set8 + 0 write8 0 write24 flush-record + 23 addr-record_type_out set8 ; + +\ Make a handshake. +: do-handshake ( initial -- ) + 0 addr-application_data set8 + 22 addr-record_type_out set8 + 0 addr-selected_protocol set16 + multihash-init + read-ClientHello + more-incoming-bytes? if ERR_UNEXPECTED fail then + if + \ Session resumption + write-ServerHello + 0 write-CCS-Finished + 0 read-CCS-Finished + else + \ Not a session resumption + write-ServerHello + write-Certificate drop + write-ServerKeyExchange + ta-names-total-length if + write-CertificateRequest + then + write-ServerHelloDone + flush-record + + \ If we sent a CertificateRequest then we expect a + \ Certificate message. + ta-names-total-length if + \ Read client certificate. + 0 read-Certificate + + choice + dup 0< uf + \ Client certificate validation failed. + 2 flag? ifnot neg fail then + drop + read-ClientKeyExchange + read-CertificateVerify-header + dup skip-blob drop + enduf + dup 0= uf + \ Client sent no certificate at all. + drop + 2 flag? ifnot + ERR_NO_CLIENT_AUTH fail + then + read-ClientKeyExchange + enduf + + \ Client certificate was validated. + read-ClientKeyExchange-header + dup ifnot + \ Empty ClientKeyExchange. + drop + process-static-ECDH + else + read-ClientKeyExchange-contents + read-CertificateVerify + then + endchoice + else + \ No client certificate request, we just expect + \ a non-empty ClientKeyExchange. + read-ClientKeyExchange + then + 0 read-CCS-Finished + 0 write-CCS-Finished + save-session + then + 1 addr-application_data set8 + 23 addr-record_type_out set8 ; + +\ Entry point. +: main ( -- ! ) + \ Perform initial handshake. + -1 do-handshake + + begin + \ Wait for further invocation. At that point, we should + \ get either an explicit call for renegotiation, or + \ an incoming ClientHello handshake message. + wait-co + dup 0x07 and case + 0x00 of + 0x10 and if + \ The best we can do is ask for a + \ renegotiation, then wait for it + \ to happen. + 0 addr-application_data set8 + send-HelloRequest + then + endof + 0x01 of + \ Reject renegotiations if the peer does not + \ support secure renegotiation, or if the + \ "no renegotiation" flag is set. + drop + addr-reneg get8 1 = 1 flag? or if + skip-ClientHello + flush-record + begin can-output? not while + wait-co drop + repeat + 100 send-warning + \ Put back connection in "application + \ data" state: it's not dead yet. + 1 addr-application_data set8 + 23 addr-record_type_out set8 + else + 0 do-handshake + then + endof + ERR_UNEXPECTED fail + endcase + again + ; diff --git a/src/bearssl/src/ssl/ssl_io.c b/src/bearssl/src/ssl/ssl_io.c new file mode 100644 index 0000000..1952615 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_io.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_sslio_init(br_sslio_context *ctx, + br_ssl_engine_context *engine, + int (*low_read)(void *read_context, + unsigned char *data, size_t len), + void *read_context, + int (*low_write)(void *write_context, + const unsigned char *data, size_t len), + void *write_context) +{ + ctx->engine = engine; + ctx->low_read = low_read; + ctx->read_context = read_context; + ctx->low_write = low_write; + ctx->write_context = write_context; +} + +/* + * Run the engine, until the specified target state is achieved, or + * an error occurs. The target state is SENDAPP, RECVAPP, or the + * combination of both (the combination matches either). When a match is + * achieved, this function returns 0. On error, it returns -1. + */ +static int +run_until(br_sslio_context *ctx, unsigned target) +{ + for (;;) { + unsigned state; + + state = br_ssl_engine_current_state(ctx->engine); + if (state & BR_SSL_CLOSED) { + return -1; + } + + /* + * If there is some record data to send, do it. This takes + * precedence over everything else. + */ + if (state & BR_SSL_SENDREC) { + unsigned char *buf; + size_t len; + int wlen; + + buf = br_ssl_engine_sendrec_buf(ctx->engine, &len); + wlen = ctx->low_write(ctx->write_context, buf, len); + if (wlen < 0) { + /* + * If we received a close_notify and we + * still send something, then we have our + * own response close_notify to send, and + * the peer is allowed by RFC 5246 not to + * wait for it. + */ + if (!ctx->engine->shutdown_recv) { + br_ssl_engine_fail( + ctx->engine, BR_ERR_IO); + } + return -1; + } + if (wlen > 0) { + br_ssl_engine_sendrec_ack(ctx->engine, wlen); + } + continue; + } + + /* + * If we reached our target, then we are finished. + */ + if (state & target) { + return 0; + } + + /* + * If some application data must be read, and we did not + * exit, then this means that we are trying to write data, + * and that's not possible until the application data is + * read. This may happen if using a shared in/out buffer, + * and the underlying protocol is not strictly half-duplex. + * This is unrecoverable here, so we report an error. + */ + if (state & BR_SSL_RECVAPP) { + return -1; + } + + /* + * If we reached that point, then either we are trying + * to read data and there is some, or the engine is stuck + * until a new record is obtained. + */ + if (state & BR_SSL_RECVREC) { + unsigned char *buf; + size_t len; + int rlen; + + buf = br_ssl_engine_recvrec_buf(ctx->engine, &len); + rlen = ctx->low_read(ctx->read_context, buf, len); + if (rlen < 0) { + br_ssl_engine_fail(ctx->engine, BR_ERR_IO); + return -1; + } + if (rlen > 0) { + br_ssl_engine_recvrec_ack(ctx->engine, rlen); + } + continue; + } + + /* + * We can reach that point if the target RECVAPP, and + * the state contains SENDAPP only. This may happen with + * a shared in/out buffer. In that case, we must flush + * the buffered data to "make room" for a new incoming + * record. + */ + br_ssl_engine_flush(ctx->engine, 0); + } +} + +/* see bearssl_ssl.h */ +int +br_sslio_read(br_sslio_context *ctx, void *dst, size_t len) +{ + unsigned char *buf; + size_t alen; + + if (len == 0) { + return 0; + } + if (run_until(ctx, BR_SSL_RECVAPP) < 0) { + return -1; + } + buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen); + if (alen > len) { + alen = len; + } + memcpy(dst, buf, alen); + br_ssl_engine_recvapp_ack(ctx->engine, alen); + return (int)alen; +} + +/* see bearssl_ssl.h */ +int +br_sslio_read_all(br_sslio_context *ctx, void *dst, size_t len) +{ + unsigned char *buf; + + buf = dst; + while (len > 0) { + int rlen; + + rlen = br_sslio_read(ctx, buf, len); + if (rlen < 0) { + return -1; + } + buf += rlen; + len -= (size_t)rlen; + } + return 0; +} + +/* see bearssl_ssl.h */ +int +br_sslio_write(br_sslio_context *ctx, const void *src, size_t len) +{ + unsigned char *buf; + size_t alen; + + if (len == 0) { + return 0; + } + if (run_until(ctx, BR_SSL_SENDAPP) < 0) { + return -1; + } + buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen); + if (alen > len) { + alen = len; + } + memcpy(buf, src, alen); + br_ssl_engine_sendapp_ack(ctx->engine, alen); + return (int)alen; +} + +/* see bearssl_ssl.h */ +int +br_sslio_write_all(br_sslio_context *ctx, const void *src, size_t len) +{ + const unsigned char *buf; + + buf = src; + while (len > 0) { + int wlen; + + wlen = br_sslio_write(ctx, buf, len); + if (wlen < 0) { + return -1; + } + buf += wlen; + len -= (size_t)wlen; + } + return 0; +} + +/* see bearssl_ssl.h */ +int +br_sslio_flush(br_sslio_context *ctx) +{ + /* + * We trigger a flush. We know the data is gone when there is + * no longer any record data to send, and we can either read + * or write application data. The call to run_until() does the + * job because it ensures that any assembled record data is + * first sent down the wire before considering anything else. + */ + br_ssl_engine_flush(ctx->engine, 0); + return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP); +} + +/* see bearssl_ssl.h */ +int +br_sslio_close(br_sslio_context *ctx) +{ + br_ssl_engine_close(ctx->engine); + while (br_ssl_engine_current_state(ctx->engine) != BR_SSL_CLOSED) { + /* + * Discard any incoming application data. + */ + size_t len; + + run_until(ctx, BR_SSL_RECVAPP); + if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) { + br_ssl_engine_recvapp_ack(ctx->engine, len); + } + } + return br_ssl_engine_last_error(ctx->engine) == BR_ERR_OK; +} diff --git a/src/bearssl/src/ssl/ssl_keyexport.c b/src/bearssl/src/ssl/ssl_keyexport.c new file mode 100644 index 0000000..58e6dc3 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_keyexport.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Supported cipher suites that use SHA-384 for the PRF when selected + * for TLS 1.2. All other cipher suites are deemed to use SHA-256. + */ +static const uint16_t suites_sha384[] = { + BR_TLS_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 +}; + +/* see bearssl_ssl.h */ +int +br_ssl_key_export(br_ssl_engine_context *cc, + void *dst, size_t len, const char *label, + const void *context, size_t context_len) +{ + br_tls_prf_seed_chunk chunks[4]; + br_tls_prf_impl iprf; + size_t num_chunks, u; + unsigned char tmp[2]; + int prf_id; + + if (cc->application_data != 1) { + return 0; + } + chunks[0].data = cc->client_random; + chunks[0].len = sizeof cc->client_random; + chunks[1].data = cc->server_random; + chunks[1].len = sizeof cc->server_random; + if (context != NULL) { + br_enc16be(tmp, (unsigned)context_len); + chunks[2].data = tmp; + chunks[2].len = 2; + chunks[3].data = context; + chunks[3].len = context_len; + num_chunks = 4; + } else { + num_chunks = 2; + } + prf_id = BR_SSLPRF_SHA256; + for (u = 0; u < (sizeof suites_sha384) / sizeof(uint16_t); u ++) { + if (suites_sha384[u] == cc->session.cipher_suite) { + prf_id = BR_SSLPRF_SHA384; + } + } + iprf = br_ssl_engine_get_PRF(cc, prf_id); + iprf(dst, len, + cc->session.master_secret, sizeof cc->session.master_secret, + label, num_chunks, chunks); + return 1; +} diff --git a/src/bearssl/src/ssl/ssl_lru.c b/src/bearssl/src/ssl/ssl_lru.c new file mode 100644 index 0000000..4c71011 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_lru.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Each entry consists in a fixed number of bytes. Entries are concatenated + * in the store block. "Addresses" are really offsets in the block, + * expressed over 32 bits (so the cache may have size at most 4 GB, which + * "ought to be enough for everyone"). The "null address" is 0xFFFFFFFF. + * Note that since the storage block alignment is in no way guaranteed, we + * perform only accesses that can handle unaligned data. + * + * Two concurrent data structures are maintained: + * + * -- Entries are organised in a doubly-linked list; saved entries are added + * at the head, and loaded entries are moved to the head. Eviction uses + * the list tail (this is the LRU algorithm). + * + * -- Entries are indexed with a binary tree: all left descendants of a + * node have a lower session ID (in lexicographic order), while all + * right descendants have a higher session ID. The tree is heuristically + * balanced. + * + * Entry format: + * + * session ID 32 bytes + * master secret 48 bytes + * protocol version 2 bytes (big endian) + * cipher suite 2 bytes (big endian) + * list prev 4 bytes (big endian) + * list next 4 bytes (big endian) + * tree left child 4 bytes (big endian) + * tree right child 4 bytes (big endian) + * + * If an entry has a protocol version set to 0, then it is "disabled": + * it was a session pushed to the cache at some point, but it has + * been explicitly removed. + * + * We need to keep the tree balanced because an attacker could make + * handshakes, selecting some specific sessions (by reusing them) to + * try to make us make an imbalanced tree that makes lookups expensive + * (a denial-of-service attack that would persist as long as the cache + * remains, i.e. even after the attacker made all his connections). + * To do that, we replace the session ID (or the start of the session ID) + * with a HMAC value computed over the replaced part; the hash function + * implementation and the key are obtained from the server context upon + * first save() call. + * + * Theoretically, an attacker could use the exact timing of the lookup + * to infer the current tree topology, and try to revive entries to make + * it as unbalanced as possible. However, since the session ID are + * chosen randomly by the server, and the attacker cannot see the + * indexing values and must thus rely on blind selection, it should be + * exponentially difficult for the attacker to maintain a large + * imbalance. + */ +#define SESSION_ID_LEN 32 +#define MASTER_SECRET_LEN 48 + +#define SESSION_ID_OFF 0 +#define MASTER_SECRET_OFF 32 +#define VERSION_OFF 80 +#define CIPHER_SUITE_OFF 82 +#define LIST_PREV_OFF 84 +#define LIST_NEXT_OFF 88 +#define TREE_LEFT_OFF 92 +#define TREE_RIGHT_OFF 96 + +#define LRU_ENTRY_LEN 100 + +#define ADDR_NULL ((uint32_t)-1) + +#define GETSET(name, off) \ +static inline uint32_t get_ ## name(br_ssl_session_cache_lru *cc, uint32_t x) \ +{ \ + return br_dec32be(cc->store + x + (off)); \ +} \ +static inline void set_ ## name(br_ssl_session_cache_lru *cc, \ + uint32_t x, uint32_t val) \ +{ \ + br_enc32be(cc->store + x + (off), val); \ +} + +GETSET(prev, LIST_PREV_OFF) +GETSET(next, LIST_NEXT_OFF) +GETSET(left, TREE_LEFT_OFF) +GETSET(right, TREE_RIGHT_OFF) + +/* + * Transform the session ID by replacing the first N bytes with a HMAC + * value computed over these bytes, using the random key K (the HMAC + * value is truncated if needed). HMAC will use the same hash function + * as the DRBG in the SSL server context, so with SHA-256, SHA-384, + * or SHA-1, depending on what is available. + * + * The risk of collision is considered too small to be a concern; and + * the impact of a collision is low (the handshake won't succeed). This + * risk is much lower than any transmission error, which would lead to + * the same consequences. + * + * Source and destination arrays msut be disjoint. + */ +static void +mask_id(br_ssl_session_cache_lru *cc, + const unsigned char *src, unsigned char *dst) +{ + br_hmac_key_context hkc; + br_hmac_context hc; + + memcpy(dst, src, SESSION_ID_LEN); + br_hmac_key_init(&hkc, cc->hash, cc->index_key, sizeof cc->index_key); + br_hmac_init(&hc, &hkc, SESSION_ID_LEN); + br_hmac_update(&hc, src, SESSION_ID_LEN); + br_hmac_out(&hc, dst); +} + +/* + * Find a node by ID. Returned value is the node address, or ADDR_NULL if + * the node is not found. + * + * If addr_link is not NULL, then '*addr_link' is set to the address of the + * last followed link. If the found node is the root, or if the tree is + * empty, then '*addr_link' is set to ADDR_NULL. + */ +static uint32_t +find_node(br_ssl_session_cache_lru *cc, const unsigned char *id, + uint32_t *addr_link) +{ + uint32_t x, y; + + x = cc->root; + y = ADDR_NULL; + while (x != ADDR_NULL) { + int r; + + r = memcmp(id, cc->store + x + SESSION_ID_OFF, SESSION_ID_LEN); + if (r < 0) { + y = x + TREE_LEFT_OFF; + x = get_left(cc, x); + } else if (r == 0) { + if (addr_link != NULL) { + *addr_link = y; + } + return x; + } else { + y = x + TREE_RIGHT_OFF; + x = get_right(cc, x); + } + } + if (addr_link != NULL) { + *addr_link = y; + } + return ADDR_NULL; +} + +/* + * For node x, find its replacement upon removal. + * + * -- If node x has no child, then this returns ADDR_NULL. + * -- Otherwise, if node x has a left child, then the replacement is the + * rightmost left-descendent. + * -- Otherwise, the replacement is the leftmost right-descendent. + * + * If a node is returned, then '*al' is set to the address of the field + * that points to that node. Otherwise (node x has no child), '*al' is + * set to ADDR_NULL. + * + * Note that the replacement node, when found, is always a descendent + * of node 'x', so it cannot be the tree root. Thus, '*al' can be set + * to ADDR_NULL only when no node is found and ADDR_NULL is returned. + */ +static uint32_t +find_replacement_node(br_ssl_session_cache_lru *cc, uint32_t x, uint32_t *al) +{ + uint32_t y1, y2; + + y1 = get_left(cc, x); + if (y1 != ADDR_NULL) { + y2 = x + TREE_LEFT_OFF; + for (;;) { + uint32_t z; + + z = get_right(cc, y1); + if (z == ADDR_NULL) { + *al = y2; + return y1; + } + y2 = y1 + TREE_RIGHT_OFF; + y1 = z; + } + } + y1 = get_right(cc, x); + if (y1 != ADDR_NULL) { + y2 = x + TREE_RIGHT_OFF; + for (;;) { + uint32_t z; + + z = get_left(cc, y1); + if (z == ADDR_NULL) { + *al = y2; + return y1; + } + y2 = y1 + TREE_LEFT_OFF; + y1 = z; + } + } + *al = ADDR_NULL; + return ADDR_NULL; +} + +/* + * Set the link at address 'alx' to point to node 'x'. If 'alx' is + * ADDR_NULL, then this sets the tree root to 'x'. + */ +static inline void +set_link(br_ssl_session_cache_lru *cc, uint32_t alx, uint32_t x) +{ + if (alx == ADDR_NULL) { + cc->root = x; + } else { + br_enc32be(cc->store + alx, x); + } +} + +/* + * Remove node 'x' from the tree. This function shall not be called if + * node 'x' is not part of the tree. + */ +static void +remove_node(br_ssl_session_cache_lru *cc, uint32_t x) +{ + uint32_t alx, y, aly; + + /* + * Removal algorithm: + * ------------------ + * + * - If we remove the root, then the tree becomes empty. + * + * - If the removed node has no child, then we can simply remove + * it, with nothing else to do. + * + * - Otherwise, the removed node must be replaced by either its + * rightmost left-descendent, or its leftmost right-descendent. + * The replacement node itself must be removed from its current + * place. By definition, that replacement node has either no + * child, or at most a single child that will replace it in the + * tree. + */ + + /* + * Find node back and its ancestor link. If the node was the + * root, then alx is set to ADDR_NULL. + */ + find_node(cc, cc->store + x + SESSION_ID_OFF, &alx); + + /* + * Find replacement node 'y', and 'aly' is set to the address of + * the link to that replacement node. If the removed node has no + * child, then both 'y' and 'aly' are set to ADDR_NULL. + */ + y = find_replacement_node(cc, x, &aly); + + if (y != ADDR_NULL) { + uint32_t z; + + /* + * The unlinked replacement node may have one child (but + * not two) that takes its place. + */ + z = get_left(cc, y); + if (z == ADDR_NULL) { + z = get_right(cc, y); + } + set_link(cc, aly, z); + + /* + * Link the replacement node in its new place, overwriting + * the current link to the node 'x' (which removes 'x'). + */ + set_link(cc, alx, y); + + /* + * The replacement node adopts the left and right children + * of the removed node. Note that this also works even if + * the replacement node was a direct descendent of the + * removed node, since we unlinked it previously. + */ + set_left(cc, y, get_left(cc, x)); + set_right(cc, y, get_right(cc, x)); + } else { + /* + * No replacement, we simply unlink the node 'x'. + */ + set_link(cc, alx, ADDR_NULL); + } +} + +static void +lru_save(const br_ssl_session_cache_class **ctx, + br_ssl_server_context *server_ctx, + const br_ssl_session_parameters *params) +{ + br_ssl_session_cache_lru *cc; + unsigned char id[SESSION_ID_LEN]; + uint32_t x, alx; + + cc = (br_ssl_session_cache_lru *)ctx; + + /* + * If the buffer is too small, we don't record anything. This + * test avoids problems in subsequent code. + */ + if (cc->store_len < LRU_ENTRY_LEN) { + return; + } + + /* + * Upon the first save in a session cache instance, we obtain + * a random key for our indexing. + */ + if (!cc->init_done) { + br_hmac_drbg_generate(&server_ctx->eng.rng, + cc->index_key, sizeof cc->index_key); + cc->hash = br_hmac_drbg_get_hash(&server_ctx->eng.rng); + cc->init_done = 1; + } + mask_id(cc, params->session_id, id); + + /* + * Look for the node in the tree. If the same ID is already used, + * then reject it. This is a collision event, which should be + * exceedingly rare. + * Note: we do NOT record the emplacement here, because the + * removal of an entry may change the tree topology. + */ + if (find_node(cc, id, NULL) != ADDR_NULL) { + return; + } + + /* + * Find some room for the new parameters. If the cache is not + * full yet, add it to the end of the area and bump the pointer up. + * Otherwise, evict the list tail entry. Note that we already + * filtered out the case of a ridiculously small buffer that + * cannot hold any entry at all; thus, if there is no room for an + * extra entry, then the cache cannot be empty. + */ + if (cc->store_ptr > (cc->store_len - LRU_ENTRY_LEN)) { + /* + * Evict tail. If the buffer has room for a single entry, + * then this may also be the head. + */ + x = cc->tail; + cc->tail = get_prev(cc, x); + if (cc->tail == ADDR_NULL) { + cc->head = ADDR_NULL; + } else { + set_next(cc, cc->tail, ADDR_NULL); + } + + /* + * Remove the node from the tree. + */ + remove_node(cc, x); + } else { + /* + * Allocate room for new node. + */ + x = cc->store_ptr; + cc->store_ptr += LRU_ENTRY_LEN; + } + + /* + * Find the emplacement for the new node, and link it. + */ + find_node(cc, id, &alx); + set_link(cc, alx, x); + set_left(cc, x, ADDR_NULL); + set_right(cc, x, ADDR_NULL); + + /* + * New entry becomes new list head. It may also become the list + * tail if the cache was empty at that point. + */ + if (cc->head == ADDR_NULL) { + cc->tail = x; + } else { + set_prev(cc, cc->head, x); + } + set_prev(cc, x, ADDR_NULL); + set_next(cc, x, cc->head); + cc->head = x; + + /* + * Fill data in the entry. + */ + memcpy(cc->store + x + SESSION_ID_OFF, id, SESSION_ID_LEN); + memcpy(cc->store + x + MASTER_SECRET_OFF, + params->master_secret, MASTER_SECRET_LEN); + br_enc16be(cc->store + x + VERSION_OFF, params->version); + br_enc16be(cc->store + x + CIPHER_SUITE_OFF, params->cipher_suite); +} + +static int +lru_load(const br_ssl_session_cache_class **ctx, + br_ssl_server_context *server_ctx, + br_ssl_session_parameters *params) +{ + br_ssl_session_cache_lru *cc; + unsigned char id[SESSION_ID_LEN]; + uint32_t x; + + (void)server_ctx; + cc = (br_ssl_session_cache_lru *)ctx; + if (!cc->init_done) { + return 0; + } + mask_id(cc, params->session_id, id); + x = find_node(cc, id, NULL); + if (x != ADDR_NULL) { + unsigned version; + + version = br_dec16be(cc->store + x + VERSION_OFF); + if (version == 0) { + /* + * Entry is disabled, we pretend we did not find it. + * Notably, we don't move it to the front of the + * LRU list. + */ + return 0; + } + params->version = version; + params->cipher_suite = br_dec16be( + cc->store + x + CIPHER_SUITE_OFF); + memcpy(params->master_secret, + cc->store + x + MASTER_SECRET_OFF, + MASTER_SECRET_LEN); + if (x != cc->head) { + /* + * Found node is not at list head, so move + * it to the head. + */ + uint32_t p, n; + + p = get_prev(cc, x); + n = get_next(cc, x); + set_next(cc, p, n); + if (n == ADDR_NULL) { + cc->tail = p; + } else { + set_prev(cc, n, p); + } + set_prev(cc, cc->head, x); + set_next(cc, x, cc->head); + set_prev(cc, x, ADDR_NULL); + cc->head = x; + } + return 1; + } + return 0; +} + +static const br_ssl_session_cache_class lru_class = { + sizeof(br_ssl_session_cache_lru), + &lru_save, + &lru_load +}; + +/* see inner.h */ +void +br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc, + unsigned char *store, size_t store_len) +{ + cc->vtable = &lru_class; + cc->store = store; + cc->store_len = store_len; + cc->store_ptr = 0; + cc->init_done = 0; + cc->head = ADDR_NULL; + cc->tail = ADDR_NULL; + cc->root = ADDR_NULL; +} + +/* see bearssl_ssl.h */ +void br_ssl_session_cache_lru_forget( + br_ssl_session_cache_lru *cc, const unsigned char *id) +{ + unsigned char mid[SESSION_ID_LEN]; + uint32_t addr; + + /* + * If the cache is not initialised yet, then it is empty, and + * there is nothing to forget. + */ + if (!cc->init_done) { + return; + } + + /* + * Look for the node in the tree. If found, the entry is marked + * as "disabled"; it will be reused in due course, as it ages + * through the list. + * + * We do not go through the complex moves of actually releasing + * the entry right away because explicitly forgetting sessions + * should be a rare event, meant mostly for testing purposes, + * so this is not worth the extra code size. + */ + mask_id(cc, id, mid); + addr = find_node(cc, mid, NULL); + if (addr != ADDR_NULL) { + br_enc16be(cc->store + addr + VERSION_OFF, 0); + } +} diff --git a/src/bearssl/src/ssl/ssl_rec_cbc.c b/src/bearssl/src/ssl/ssl_rec_cbc.c new file mode 100644 index 0000000..c080604 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_rec_cbc.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static void +in_cbc_init(br_sslrec_in_cbc_context *cc, + const br_block_cbcdec_class *bc_impl, + const void *bc_key, size_t bc_key_len, + const br_hash_class *dig_impl, + const void *mac_key, size_t mac_key_len, size_t mac_out_len, + const void *iv) +{ + cc->vtable = &br_sslrec_in_cbc_vtable; + cc->seq = 0; + bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len); + br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len); + cc->mac_len = mac_out_len; + if (iv == NULL) { + memset(cc->iv, 0, sizeof cc->iv); + cc->explicit_IV = 1; + } else { + memcpy(cc->iv, iv, bc_impl->block_size); + cc->explicit_IV = 0; + } +} + +static int +cbc_check_length(const br_sslrec_in_cbc_context *cc, size_t rlen) +{ + /* + * Plaintext size: at most 16384 bytes + * Padding: at most 256 bytes + * MAC: mac_len extra bytes + * TLS 1.1+: each record has an explicit IV + * + * Minimum length includes at least one byte of padding, and the + * MAC. + * + * Total length must be a multiple of the block size. + */ + size_t blen; + size_t min_len, max_len; + + blen = cc->bc.vtable->block_size; + min_len = (blen + cc->mac_len) & ~(blen - 1); + max_len = (16384 + 256 + cc->mac_len) & ~(blen - 1); + if (cc->explicit_IV) { + min_len += blen; + max_len += blen; + } + return min_len <= rlen && rlen <= max_len; +} + +/* + * Rotate array buf[] of length 'len' to the left (towards low indices) + * by 'num' bytes if ctl is 1; otherwise, leave it unchanged. This is + * constant-time. 'num' MUST be lower than 'len'. 'len' MUST be lower + * than or equal to 64. + */ +static void +cond_rotate(uint32_t ctl, unsigned char *buf, size_t len, size_t num) +{ + unsigned char tmp[64]; + size_t u, v; + + for (u = 0, v = num; u < len; u ++) { + tmp[u] = MUX(ctl, buf[v], buf[u]); + if (++ v == len) { + v = 0; + } + } + memcpy(buf, tmp, len); +} + +static unsigned char * +cbc_decrypt(br_sslrec_in_cbc_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + /* + * We represent all lengths on 32-bit integers, because: + * -- SSL record lengths always fit in 32 bits; + * -- our constant-time primitives operate on 32-bit integers. + */ + unsigned char *buf; + uint32_t u, v, len, blen, min_len, max_len; + uint32_t good, pad_len, rot_count, len_withmac, len_nomac; + unsigned char tmp1[64], tmp2[64]; + int i; + br_hmac_context hc; + + buf = data; + len = *data_len; + blen = cc->bc.vtable->block_size; + + /* + * Decrypt data, and skip the explicit IV (if applicable). Note + * that the total length is supposed to have been verified by + * the caller. If there is an explicit IV, then we actually + * "decrypt" it using the implicit IV (from previous record), + * which is useless but harmless. + */ + cc->bc.vtable->run(&cc->bc.vtable, cc->iv, data, len); + if (cc->explicit_IV) { + buf += blen; + len -= blen; + } + + /* + * Compute minimum and maximum length of plaintext + MAC. These + * lengths can be inferred from the outside: they are not secret. + */ + min_len = (cc->mac_len + 256 < len) ? len - 256 : cc->mac_len; + max_len = len - 1; + + /* + * Use the last decrypted byte to compute the actual payload + * length. Take care not to underflow (we use unsigned types). + */ + pad_len = buf[max_len]; + good = LE(pad_len, (uint32_t)(max_len - min_len)); + len = MUX(good, (uint32_t)(max_len - pad_len), min_len); + + /* + * Check padding contents: all padding bytes must be equal to + * the value of pad_len. + */ + for (u = min_len; u < max_len; u ++) { + good &= LT(u, len) | EQ(buf[u], pad_len); + } + + /* + * Extract the MAC value. This is done in one pass, but results + * in a "rotated" MAC value depending on where it actually + * occurs. The 'rot_count' value is set to the offset of the + * first MAC byte within tmp1[]. + * + * min_len and max_len are also adjusted to the minimum and + * maximum lengths of the plaintext alone (without the MAC). + */ + len_withmac = (uint32_t)len; + len_nomac = len_withmac - cc->mac_len; + min_len -= cc->mac_len; + rot_count = 0; + memset(tmp1, 0, cc->mac_len); + v = 0; + for (u = min_len; u < max_len; u ++) { + tmp1[v] |= MUX(GE(u, len_nomac) & LT(u, len_withmac), + buf[u], 0x00); + rot_count = MUX(EQ(u, len_nomac), v, rot_count); + if (++ v == cc->mac_len) { + v = 0; + } + } + max_len -= cc->mac_len; + + /* + * Rotate back the MAC value. The loop below does the constant-time + * rotation in time n*log n for a MAC output of length n. We assume + * that the MAC output length is no more than 64 bytes, so the + * rotation count fits on 6 bits. + */ + for (i = 5; i >= 0; i --) { + uint32_t rc; + + rc = (uint32_t)1 << i; + cond_rotate(rot_count >> i, tmp1, cc->mac_len, rc); + rot_count &= ~rc; + } + + /* + * Recompute the HMAC value. The input is the concatenation of + * the sequence number (8 bytes), the record header (5 bytes), + * and the payload. + * + * At that point, min_len is the minimum plaintext length, but + * max_len still includes the MAC length. + */ + br_enc64be(tmp2, cc->seq ++); + tmp2[8] = (unsigned char)record_type; + br_enc16be(tmp2 + 9, version); + br_enc16be(tmp2 + 11, len_nomac); + br_hmac_init(&hc, &cc->mac, cc->mac_len); + br_hmac_update(&hc, tmp2, 13); + br_hmac_outCT(&hc, buf, len_nomac, min_len, max_len, tmp2); + + /* + * Compare the extracted and recomputed MAC values. + */ + for (u = 0; u < cc->mac_len; u ++) { + good &= EQ0(tmp1[u] ^ tmp2[u]); + } + + /* + * Check that the plaintext length is valid. The previous + * check was on the encrypted length, but the padding may have + * turned shorter than expected. + * + * Once this final test is done, the critical "constant-time" + * section ends and we can make conditional jumps again. + */ + good &= LE(len_nomac, 16384); + + if (!good) { + return 0; + } + *data_len = len_nomac; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable = { + { + sizeof(br_sslrec_in_cbc_context), + (int (*)(const br_sslrec_in_class *const *, size_t)) + &cbc_check_length, + (unsigned char *(*)(const br_sslrec_in_class **, + int, unsigned, void *, size_t *)) + &cbc_decrypt + }, + (void (*)(const br_sslrec_in_cbc_class **, + const br_block_cbcdec_class *, const void *, size_t, + const br_hash_class *, const void *, size_t, size_t, + const void *)) + &in_cbc_init +}; + +/* + * For CBC output: + * + * -- With TLS 1.1+, there is an explicit IV. Generation method uses + * HMAC, computed over the current sequence number, and the current MAC + * key. The resulting value is truncated to the size of a block, and + * added at the head of the plaintext; it will get encrypted along with + * the data. This custom generation mechanism is "safe" under the + * assumption that HMAC behaves like a random oracle; since the MAC for + * a record is computed over the concatenation of the sequence number, + * the record header and the plaintext, the HMAC-for-IV will not collide + * with the normal HMAC. + * + * -- With TLS 1.0, for application data, we want to enforce a 1/n-1 + * split, as a countermeasure against chosen-plaintext attacks. We thus + * need to leave some room in the buffer for that extra record. + */ + +static void +out_cbc_init(br_sslrec_out_cbc_context *cc, + const br_block_cbcenc_class *bc_impl, + const void *bc_key, size_t bc_key_len, + const br_hash_class *dig_impl, + const void *mac_key, size_t mac_key_len, size_t mac_out_len, + const void *iv) +{ + cc->vtable = &br_sslrec_out_cbc_vtable; + cc->seq = 0; + bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len); + br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len); + cc->mac_len = mac_out_len; + if (iv == NULL) { + memset(cc->iv, 0, sizeof cc->iv); + cc->explicit_IV = 1; + } else { + memcpy(cc->iv, iv, bc_impl->block_size); + cc->explicit_IV = 0; + } +} + +static void +cbc_max_plaintext(const br_sslrec_out_cbc_context *cc, + size_t *start, size_t *end) +{ + size_t blen, len; + + blen = cc->bc.vtable->block_size; + if (cc->explicit_IV) { + *start += blen; + } else { + *start += 4 + ((cc->mac_len + blen + 1) & ~(blen - 1)); + } + len = (*end - *start) & ~(blen - 1); + len -= 1 + cc->mac_len; + if (len > 16384) { + len = 16384; + } + *end = *start + len; +} + +static unsigned char * +cbc_encrypt(br_sslrec_out_cbc_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + unsigned char *buf, *rbuf; + size_t len, blen, plen; + unsigned char tmp[13]; + br_hmac_context hc; + + buf = data; + len = *data_len; + blen = cc->bc.vtable->block_size; + + /* + * If using TLS 1.0, with more than one byte of plaintext, and + * the record is application data, then we need to compute + * a "split". We do not perform the split on other record types + * because it turned out that some existing, deployed + * implementations of SSL/TLS do not tolerate the splitting of + * some message types (in particular the Finished message). + * + * If using TLS 1.1+, then there is an explicit IV. We produce + * that IV by adding an extra initial plaintext block, whose + * value is computed with HMAC over the record sequence number. + */ + if (cc->explicit_IV) { + /* + * We use here the fact that all the HMAC variants we + * support can produce at least 16 bytes, while all the + * block ciphers we support have blocks of no more than + * 16 bytes. Thus, we can always truncate the HMAC output + * down to the block size. + */ + br_enc64be(tmp, cc->seq); + br_hmac_init(&hc, &cc->mac, blen); + br_hmac_update(&hc, tmp, 8); + br_hmac_out(&hc, buf - blen); + rbuf = buf - blen - 5; + } else { + if (len > 1 && record_type == BR_SSL_APPLICATION_DATA) { + /* + * To do the split, we use a recursive invocation; + * since we only give one byte to the inner call, + * the recursion stops there. + * + * We need to compute the exact size of the extra + * record, so that the two resulting records end up + * being sequential in RAM. + * + * We use here the fact that cbc_max_plaintext() + * adjusted the start offset to leave room for the + * initial fragment. + */ + size_t xlen; + + rbuf = buf - 4 + - ((cc->mac_len + blen + 1) & ~(blen - 1)); + rbuf[0] = buf[0]; + xlen = 1; + rbuf = cbc_encrypt(cc, record_type, + version, rbuf, &xlen); + buf ++; + len --; + } else { + rbuf = buf - 5; + } + } + + /* + * Compute MAC. + */ + br_enc64be(tmp, cc->seq ++); + tmp[8] = record_type; + br_enc16be(tmp + 9, version); + br_enc16be(tmp + 11, len); + br_hmac_init(&hc, &cc->mac, cc->mac_len); + br_hmac_update(&hc, tmp, 13); + br_hmac_update(&hc, buf, len); + br_hmac_out(&hc, buf + len); + len += cc->mac_len; + + /* + * Add padding. + */ + plen = blen - (len & (blen - 1)); + memset(buf + len, (unsigned)plen - 1, plen); + len += plen; + + /* + * If an explicit IV is used, the corresponding extra block was + * already put in place earlier; we just have to account for it + * here. + */ + if (cc->explicit_IV) { + buf -= blen; + len += blen; + } + + /* + * Encrypt the whole thing. If there is an explicit IV, we also + * encrypt it, which is fine (encryption of a uniformly random + * block is still a uniformly random block). + */ + cc->bc.vtable->run(&cc->bc.vtable, cc->iv, buf, len); + + /* + * Add the header and return. + */ + buf[-5] = record_type; + br_enc16be(buf - 4, version); + br_enc16be(buf - 2, len); + *data_len = (size_t)((buf + len) - rbuf); + return rbuf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable = { + { + sizeof(br_sslrec_out_cbc_context), + (void (*)(const br_sslrec_out_class *const *, + size_t *, size_t *)) + &cbc_max_plaintext, + (unsigned char *(*)(const br_sslrec_out_class **, + int, unsigned, void *, size_t *)) + &cbc_encrypt + }, + (void (*)(const br_sslrec_out_cbc_class **, + const br_block_cbcenc_class *, const void *, size_t, + const br_hash_class *, const void *, size_t, size_t, + const void *)) + &out_cbc_init +}; diff --git a/src/bearssl/src/ssl/ssl_rec_ccm.c b/src/bearssl/src/ssl/ssl_rec_ccm.c new file mode 100644 index 0000000..92c3295 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_rec_ccm.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * CCM initialisation. This does everything except setting the vtable, + * which depends on whether this is a context for encrypting or for + * decrypting. + */ +static void +gen_ccm_init(br_sslrec_ccm_context *cc, + const br_block_ctrcbc_class *bc_impl, + const void *key, size_t key_len, + const void *iv, size_t tag_len) +{ + cc->seq = 0; + bc_impl->init(&cc->bc.vtable, key, key_len); + memcpy(cc->iv, iv, sizeof cc->iv); + cc->tag_len = tag_len; +} + +static void +in_ccm_init(br_sslrec_ccm_context *cc, + const br_block_ctrcbc_class *bc_impl, + const void *key, size_t key_len, + const void *iv, size_t tag_len) +{ + cc->vtable.in = &br_sslrec_in_ccm_vtable; + gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len); +} + +static int +ccm_check_length(const br_sslrec_ccm_context *cc, size_t rlen) +{ + /* + * CCM overhead is 8 bytes for nonce_explicit, and the tag + * (normally 8 or 16 bytes, depending on cipher suite). + */ + size_t over; + + over = 8 + cc->tag_len; + return rlen >= over && rlen <= (16384 + over); +} + +static unsigned char * +ccm_decrypt(br_sslrec_ccm_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + br_ccm_context zc; + unsigned char *buf; + unsigned char nonce[12], header[13]; + size_t len; + + buf = (unsigned char *)data + 8; + len = *data_len - (8 + cc->tag_len); + + /* + * Make nonce (implicit + explicit parts). + */ + memcpy(nonce, cc->iv, sizeof cc->iv); + memcpy(nonce + 4, data, 8); + + /* + * Assemble synthetic header for the AAD. + */ + br_enc64be(header, cc->seq ++); + header[8] = (unsigned char)record_type; + br_enc16be(header + 9, version); + br_enc16be(header + 11, len); + + /* + * Perform CCM decryption. + */ + br_ccm_init(&zc, &cc->bc.vtable); + br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len); + br_ccm_aad_inject(&zc, header, sizeof header); + br_ccm_flip(&zc); + br_ccm_run(&zc, 0, buf, len); + if (!br_ccm_check_tag(&zc, buf + len)) { + return NULL; + } + *data_len = len; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable = { + { + sizeof(br_sslrec_ccm_context), + (int (*)(const br_sslrec_in_class *const *, size_t)) + &ccm_check_length, + (unsigned char *(*)(const br_sslrec_in_class **, + int, unsigned, void *, size_t *)) + &ccm_decrypt + }, + (void (*)(const br_sslrec_in_ccm_class **, + const br_block_ctrcbc_class *, const void *, size_t, + const void *, size_t)) + &in_ccm_init +}; + +static void +out_ccm_init(br_sslrec_ccm_context *cc, + const br_block_ctrcbc_class *bc_impl, + const void *key, size_t key_len, + const void *iv, size_t tag_len) +{ + cc->vtable.out = &br_sslrec_out_ccm_vtable; + gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len); +} + +static void +ccm_max_plaintext(const br_sslrec_ccm_context *cc, + size_t *start, size_t *end) +{ + size_t len; + + *start += 8; + len = *end - *start - cc->tag_len; + if (len > 16384) { + len = 16384; + } + *end = *start + len; +} + +static unsigned char * +ccm_encrypt(br_sslrec_ccm_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + br_ccm_context zc; + unsigned char *buf; + unsigned char nonce[12], header[13]; + size_t len; + + buf = (unsigned char *)data; + len = *data_len; + + /* + * Make nonce; the explicit part is an encoding of the sequence + * number. + */ + memcpy(nonce, cc->iv, sizeof cc->iv); + br_enc64be(nonce + 4, cc->seq); + + /* + * Assemble synthetic header for the AAD. + */ + br_enc64be(header, cc->seq ++); + header[8] = (unsigned char)record_type; + br_enc16be(header + 9, version); + br_enc16be(header + 11, len); + + /* + * Perform CCM encryption. + */ + br_ccm_init(&zc, &cc->bc.vtable); + br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len); + br_ccm_aad_inject(&zc, header, sizeof header); + br_ccm_flip(&zc); + br_ccm_run(&zc, 1, buf, len); + br_ccm_get_tag(&zc, buf + len); + + /* + * Assemble header and adjust pointer/length. + */ + len += 8 + cc->tag_len; + buf -= 13; + memcpy(buf + 5, nonce + 4, 8); + buf[0] = (unsigned char)record_type; + br_enc16be(buf + 1, version); + br_enc16be(buf + 3, len); + *data_len = len + 5; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable = { + { + sizeof(br_sslrec_ccm_context), + (void (*)(const br_sslrec_out_class *const *, + size_t *, size_t *)) + &ccm_max_plaintext, + (unsigned char *(*)(const br_sslrec_out_class **, + int, unsigned, void *, size_t *)) + &ccm_encrypt + }, + (void (*)(const br_sslrec_out_ccm_class **, + const br_block_ctrcbc_class *, const void *, size_t, + const void *, size_t)) + &out_ccm_init +}; diff --git a/src/bearssl/src/ssl/ssl_rec_chapol.c b/src/bearssl/src/ssl/ssl_rec_chapol.c new file mode 100644 index 0000000..73b3c78 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_rec_chapol.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static void +gen_chapol_init(br_sslrec_chapol_context *cc, + br_chacha20_run ichacha, br_poly1305_run ipoly, + const void *key, const void *iv) +{ + cc->seq = 0; + cc->ichacha = ichacha; + cc->ipoly = ipoly; + memcpy(cc->key, key, sizeof cc->key); + memcpy(cc->iv, iv, sizeof cc->iv); +} + +static void +gen_chapol_process(br_sslrec_chapol_context *cc, + int record_type, unsigned version, void *data, size_t len, + void *tag, int encrypt) +{ + unsigned char header[13]; + unsigned char nonce[12]; + uint64_t seq; + size_t u; + + seq = cc->seq ++; + br_enc64be(header, seq); + header[8] = (unsigned char)record_type; + br_enc16be(header + 9, version); + br_enc16be(header + 11, len); + memcpy(nonce, cc->iv, 12); + for (u = 0; u < 8; u ++) { + nonce[11 - u] ^= (unsigned char)seq; + seq >>= 8; + } + cc->ipoly(cc->key, nonce, data, len, header, sizeof header, + tag, cc->ichacha, encrypt); +} + +static void +in_chapol_init(br_sslrec_chapol_context *cc, + br_chacha20_run ichacha, br_poly1305_run ipoly, + const void *key, const void *iv) +{ + cc->vtable.in = &br_sslrec_in_chapol_vtable; + gen_chapol_init(cc, ichacha, ipoly, key, iv); +} + +static int +chapol_check_length(const br_sslrec_chapol_context *cc, size_t rlen) +{ + /* + * Overhead is just the authentication tag (16 bytes). + */ + (void)cc; + return rlen >= 16 && rlen <= (16384 + 16); +} + +static unsigned char * +chapol_decrypt(br_sslrec_chapol_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + unsigned char *buf; + size_t u, len; + unsigned char tag[16]; + unsigned bad; + + buf = data; + len = *data_len - 16; + gen_chapol_process(cc, record_type, version, buf, len, tag, 0); + bad = 0; + for (u = 0; u < 16; u ++) { + bad |= tag[u] ^ buf[len + u]; + } + if (bad) { + return NULL; + } + *data_len = len; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_in_chapol_class br_sslrec_in_chapol_vtable = { + { + sizeof(br_sslrec_chapol_context), + (int (*)(const br_sslrec_in_class *const *, size_t)) + &chapol_check_length, + (unsigned char *(*)(const br_sslrec_in_class **, + int, unsigned, void *, size_t *)) + &chapol_decrypt + }, + (void (*)(const br_sslrec_in_chapol_class **, + br_chacha20_run, br_poly1305_run, + const void *, const void *)) + &in_chapol_init +}; + +static void +out_chapol_init(br_sslrec_chapol_context *cc, + br_chacha20_run ichacha, br_poly1305_run ipoly, + const void *key, const void *iv) +{ + cc->vtable.out = &br_sslrec_out_chapol_vtable; + gen_chapol_init(cc, ichacha, ipoly, key, iv); +} + +static void +chapol_max_plaintext(const br_sslrec_chapol_context *cc, + size_t *start, size_t *end) +{ + size_t len; + + (void)cc; + len = *end - *start - 16; + if (len > 16384) { + len = 16384; + } + *end = *start + len; +} + +static unsigned char * +chapol_encrypt(br_sslrec_chapol_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + unsigned char *buf; + size_t len; + + buf = data; + len = *data_len; + gen_chapol_process(cc, record_type, version, buf, len, buf + len, 1); + buf -= 5; + buf[0] = (unsigned char)record_type; + br_enc16be(buf + 1, version); + br_enc16be(buf + 3, len + 16); + *data_len = len + 21; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_out_chapol_class br_sslrec_out_chapol_vtable = { + { + sizeof(br_sslrec_chapol_context), + (void (*)(const br_sslrec_out_class *const *, + size_t *, size_t *)) + &chapol_max_plaintext, + (unsigned char *(*)(const br_sslrec_out_class **, + int, unsigned, void *, size_t *)) + &chapol_encrypt + }, + (void (*)(const br_sslrec_out_chapol_class **, + br_chacha20_run, br_poly1305_run, + const void *, const void *)) + &out_chapol_init +}; diff --git a/src/bearssl/src/ssl/ssl_rec_gcm.c b/src/bearssl/src/ssl/ssl_rec_gcm.c new file mode 100644 index 0000000..70df277 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_rec_gcm.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * GCM initialisation. This does everything except setting the vtable, + * which depends on whether this is a context for encrypting or for + * decrypting. + */ +static void +gen_gcm_init(br_sslrec_gcm_context *cc, + const br_block_ctr_class *bc_impl, + const void *key, size_t key_len, + br_ghash gh_impl, + const void *iv) +{ + unsigned char tmp[12]; + + cc->seq = 0; + bc_impl->init(&cc->bc.vtable, key, key_len); + cc->gh = gh_impl; + memcpy(cc->iv, iv, sizeof cc->iv); + memset(cc->h, 0, sizeof cc->h); + memset(tmp, 0, sizeof tmp); + bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h); +} + +static void +in_gcm_init(br_sslrec_gcm_context *cc, + const br_block_ctr_class *bc_impl, + const void *key, size_t key_len, + br_ghash gh_impl, + const void *iv) +{ + cc->vtable.in = &br_sslrec_in_gcm_vtable; + gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv); +} + +static int +gcm_check_length(const br_sslrec_gcm_context *cc, size_t rlen) +{ + /* + * GCM adds a fixed overhead: + * 8 bytes for the nonce_explicit (before the ciphertext) + * 16 bytes for the authentication tag (after the ciphertext) + */ + (void)cc; + return rlen >= 24 && rlen <= (16384 + 24); +} + +/* + * Compute the authentication tag. The value written in 'tag' must still + * be CTR-encrypted. + */ +static void +do_tag(br_sslrec_gcm_context *cc, + int record_type, unsigned version, + void *data, size_t len, void *tag) +{ + unsigned char header[13]; + unsigned char footer[16]; + + /* + * Compute authentication tag. Three elements must be injected in + * sequence, each possibly 0-padded to reach a length multiple + * of the block size: the 13-byte header (sequence number, record + * type, protocol version, record length), the cipher text, and + * the word containing the encodings of the bit lengths of the two + * other elements. + */ + br_enc64be(header, cc->seq ++); + header[8] = (unsigned char)record_type; + br_enc16be(header + 9, version); + br_enc16be(header + 11, len); + br_enc64be(footer, (uint64_t)(sizeof header) << 3); + br_enc64be(footer + 8, (uint64_t)len << 3); + memset(tag, 0, 16); + cc->gh(tag, cc->h, header, sizeof header); + cc->gh(tag, cc->h, data, len); + cc->gh(tag, cc->h, footer, sizeof footer); +} + +/* + * Do CTR encryption. This also does CTR encryption of a single block at + * address 'xortag' with the counter value appropriate for the final + * processing of the authentication tag. + */ +static void +do_ctr(br_sslrec_gcm_context *cc, const void *nonce, void *data, size_t len, + void *xortag) +{ + unsigned char iv[12]; + + memcpy(iv, cc->iv, 4); + memcpy(iv + 4, nonce, 8); + cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len); + cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16); +} + +static unsigned char * +gcm_decrypt(br_sslrec_gcm_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + unsigned char *buf; + size_t len, u; + uint32_t bad; + unsigned char tag[16]; + + buf = (unsigned char *)data + 8; + len = *data_len - 24; + do_tag(cc, record_type, version, buf, len, tag); + do_ctr(cc, data, buf, len, tag); + + /* + * Compare the computed tag with the value from the record. It + * is possibly useless to do a constant-time comparison here, + * but it does not hurt. + */ + bad = 0; + for (u = 0; u < 16; u ++) { + bad |= tag[u] ^ buf[len + u]; + } + if (bad) { + return NULL; + } + *data_len = len; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable = { + { + sizeof(br_sslrec_gcm_context), + (int (*)(const br_sslrec_in_class *const *, size_t)) + &gcm_check_length, + (unsigned char *(*)(const br_sslrec_in_class **, + int, unsigned, void *, size_t *)) + &gcm_decrypt + }, + (void (*)(const br_sslrec_in_gcm_class **, + const br_block_ctr_class *, const void *, size_t, + br_ghash, const void *)) + &in_gcm_init +}; + +static void +out_gcm_init(br_sslrec_gcm_context *cc, + const br_block_ctr_class *bc_impl, + const void *key, size_t key_len, + br_ghash gh_impl, + const void *iv) +{ + cc->vtable.out = &br_sslrec_out_gcm_vtable; + gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv); +} + +static void +gcm_max_plaintext(const br_sslrec_gcm_context *cc, + size_t *start, size_t *end) +{ + size_t len; + + (void)cc; + *start += 8; + len = *end - *start - 16; + if (len > 16384) { + len = 16384; + } + *end = *start + len; +} + +static unsigned char * +gcm_encrypt(br_sslrec_gcm_context *cc, + int record_type, unsigned version, void *data, size_t *data_len) +{ + unsigned char *buf; + size_t u, len; + unsigned char tmp[16]; + + buf = (unsigned char *)data; + len = *data_len; + memset(tmp, 0, sizeof tmp); + br_enc64be(buf - 8, cc->seq); + do_ctr(cc, buf - 8, buf, len, tmp); + do_tag(cc, record_type, version, buf, len, buf + len); + for (u = 0; u < 16; u ++) { + buf[len + u] ^= tmp[u]; + } + len += 24; + buf -= 13; + buf[0] = (unsigned char)record_type; + br_enc16be(buf + 1, version); + br_enc16be(buf + 3, len); + *data_len = len + 5; + return buf; +} + +/* see bearssl_ssl.h */ +const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable = { + { + sizeof(br_sslrec_gcm_context), + (void (*)(const br_sslrec_out_class *const *, + size_t *, size_t *)) + &gcm_max_plaintext, + (unsigned char *(*)(const br_sslrec_out_class **, + int, unsigned, void *, size_t *)) + &gcm_encrypt + }, + (void (*)(const br_sslrec_out_gcm_class **, + const br_block_ctr_class *, const void *, size_t, + br_ghash, const void *)) + &out_gcm_init +}; diff --git a/src/bearssl/src/ssl/ssl_scert_single_ec.c b/src/bearssl/src/ssl/ssl_scert_single_ec.c new file mode 100644 index 0000000..ce8d753 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_scert_single_ec.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static int +se_choose(const br_ssl_server_policy_class **pctx, + const br_ssl_server_context *cc, + br_ssl_server_choices *choices) +{ + br_ssl_server_policy_ec_context *pc; + const br_suite_translated *st; + size_t u, st_num; + unsigned hash_id; + + pc = (br_ssl_server_policy_ec_context *)pctx; + st = br_ssl_server_get_client_suites(cc, &st_num); + hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc) >> 8); + if (cc->eng.session.version < BR_TLS12) { + hash_id = br_sha1_ID; + } + choices->chain = pc->chain; + choices->chain_len = pc->chain_len; + for (u = 0; u < st_num; u ++) { + unsigned tt; + + tt = st[u][1]; + switch (tt >> 12) { + case BR_SSLKEYX_ECDH_RSA: + if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0 + && pc->cert_issuer_key_type == BR_KEYTYPE_RSA) + { + choices->cipher_suite = st[u][0]; + return 1; + } + break; + case BR_SSLKEYX_ECDH_ECDSA: + if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0 + && pc->cert_issuer_key_type == BR_KEYTYPE_EC) + { + choices->cipher_suite = st[u][0]; + return 1; + } + break; + case BR_SSLKEYX_ECDHE_ECDSA: + if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0 + && hash_id != 0) + { + choices->cipher_suite = st[u][0]; + choices->algo_id = hash_id + 0xFF00; + return 1; + } + break; + } + } + return 0; +} + +static uint32_t +se_do_keyx(const br_ssl_server_policy_class **pctx, + unsigned char *data, size_t *len) +{ + br_ssl_server_policy_ec_context *pc; + uint32_t r; + size_t xoff, xlen; + + pc = (br_ssl_server_policy_ec_context *)pctx; + r = pc->iec->mul(data, *len, pc->sk->x, pc->sk->xlen, pc->sk->curve); + xoff = pc->iec->xoff(pc->sk->curve, &xlen); + memmove(data, data + xoff, xlen); + *len = xlen; + return r; +} + +static size_t +se_do_sign(const br_ssl_server_policy_class **pctx, + unsigned algo_id, unsigned char *data, size_t hv_len, size_t len) +{ + br_ssl_server_policy_ec_context *pc; + unsigned char hv[64]; + const br_hash_class *hc; + + algo_id &= 0xFF; + pc = (br_ssl_server_policy_ec_context *)pctx; + hc = br_multihash_getimpl(pc->mhash, algo_id); + if (hc == NULL) { + return 0; + } + memcpy(hv, data, hv_len); + if (len < 139) { + return 0; + } + return pc->iecdsa(pc->iec, hc, hv, pc->sk, data); +} + +static const br_ssl_server_policy_class se_policy_vtable = { + sizeof(br_ssl_server_policy_ec_context), + se_choose, + se_do_keyx, + se_do_sign +}; + +/* see bearssl_ssl.h */ +void +br_ssl_server_set_single_ec(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk, unsigned allowed_usages, + unsigned cert_issuer_key_type, + const br_ec_impl *iec, br_ecdsa_sign iecdsa) +{ + cc->chain_handler.single_ec.vtable = &se_policy_vtable; + cc->chain_handler.single_ec.chain = chain; + cc->chain_handler.single_ec.chain_len = chain_len; + cc->chain_handler.single_ec.sk = sk; + cc->chain_handler.single_ec.allowed_usages = allowed_usages; + cc->chain_handler.single_ec.cert_issuer_key_type = cert_issuer_key_type; + cc->chain_handler.single_ec.mhash = &cc->eng.mhash; + cc->chain_handler.single_ec.iec = iec; + cc->chain_handler.single_ec.iecdsa = iecdsa; + cc->policy_vtable = &cc->chain_handler.single_ec.vtable; +} diff --git a/src/bearssl/src/ssl/ssl_scert_single_rsa.c b/src/bearssl/src/ssl/ssl_scert_single_rsa.c new file mode 100644 index 0000000..b2c7767 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_scert_single_rsa.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static int +sr_choose(const br_ssl_server_policy_class **pctx, + const br_ssl_server_context *cc, + br_ssl_server_choices *choices) +{ + br_ssl_server_policy_rsa_context *pc; + const br_suite_translated *st; + size_t u, st_num; + unsigned hash_id; + int fh; + + pc = (br_ssl_server_policy_rsa_context *)pctx; + st = br_ssl_server_get_client_suites(cc, &st_num); + if (cc->eng.session.version < BR_TLS12) { + hash_id = 0; + fh = 1; + } else { + hash_id = br_ssl_choose_hash( + br_ssl_server_get_client_hashes(cc)); + fh = (hash_id != 0); + } + choices->chain = pc->chain; + choices->chain_len = pc->chain_len; + for (u = 0; u < st_num; u ++) { + unsigned tt; + + tt = st[u][1]; + switch (tt >> 12) { + case BR_SSLKEYX_RSA: + if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0) { + choices->cipher_suite = st[u][0]; + return 1; + } + break; + case BR_SSLKEYX_ECDHE_RSA: + if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0 && fh) { + choices->cipher_suite = st[u][0]; + choices->algo_id = hash_id + 0xFF00; + return 1; + } + break; + } + } + return 0; +} + +static uint32_t +sr_do_keyx(const br_ssl_server_policy_class **pctx, + unsigned char *data, size_t *len) +{ + br_ssl_server_policy_rsa_context *pc; + + pc = (br_ssl_server_policy_rsa_context *)pctx; + return br_rsa_ssl_decrypt(pc->irsacore, pc->sk, data, *len); +} + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char HASH_OID_SHA1[] = { + 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char HASH_OID_SHA224[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char HASH_OID_SHA256[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char HASH_OID_SHA384[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char HASH_OID_SHA512[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const unsigned char *HASH_OID[] = { + HASH_OID_SHA1, + HASH_OID_SHA224, + HASH_OID_SHA256, + HASH_OID_SHA384, + HASH_OID_SHA512 +}; + +static size_t +sr_do_sign(const br_ssl_server_policy_class **pctx, + unsigned algo_id, unsigned char *data, size_t hv_len, size_t len) +{ + br_ssl_server_policy_rsa_context *pc; + unsigned char hv[64]; + size_t sig_len; + const unsigned char *hash_oid; + + pc = (br_ssl_server_policy_rsa_context *)pctx; + memcpy(hv, data, hv_len); + algo_id &= 0xFF; + if (algo_id == 0) { + hash_oid = NULL; + } else if (algo_id >= 2 && algo_id <= 6) { + hash_oid = HASH_OID[algo_id - 2]; + } else { + return 0; + } + sig_len = (pc->sk->n_bitlen + 7) >> 3; + if (len < sig_len) { + return 0; + } + return pc->irsasign(hash_oid, hv, hv_len, pc->sk, data) ? sig_len : 0; +} + +static const br_ssl_server_policy_class sr_policy_vtable = { + sizeof(br_ssl_server_policy_rsa_context), + sr_choose, + sr_do_keyx, + sr_do_sign +}; + +/* see bearssl_ssl.h */ +void +br_ssl_server_set_single_rsa(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk, unsigned allowed_usages, + br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign) +{ + cc->chain_handler.single_rsa.vtable = &sr_policy_vtable; + cc->chain_handler.single_rsa.chain = chain; + cc->chain_handler.single_rsa.chain_len = chain_len; + cc->chain_handler.single_rsa.sk = sk; + cc->chain_handler.single_rsa.allowed_usages = allowed_usages; + cc->chain_handler.single_rsa.irsacore = irsacore; + cc->chain_handler.single_rsa.irsasign = irsasign; + cc->policy_vtable = &cc->chain_handler.single_rsa.vtable; +} diff --git a/src/bearssl/src/ssl/ssl_server.c b/src/bearssl/src/ssl/ssl_server.c new file mode 100644 index 0000000..5578b63 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_zero(br_ssl_server_context *cc) +{ + /* + * For really standard C, we should explicitly set to NULL all + * pointers, and 0 all other fields. However, on all our target + * architectures, a direct memset() will work, be faster, and + * use a lot less code. + */ + memset(cc, 0, sizeof *cc); +} + +/* see bearssl_ssl.h */ +int +br_ssl_server_reset(br_ssl_server_context *cc) +{ + br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0); + if (!br_ssl_engine_init_rand(&cc->eng)) { + return 0; + } + cc->eng.reneg = 0; + br_ssl_engine_hs_reset(&cc->eng, + br_ssl_hs_server_init_main, br_ssl_hs_server_run); + return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK; +} diff --git a/src/bearssl/src/ssl/ssl_server_full_ec.c b/src/bearssl/src/ssl/ssl_server_full_ec.c new file mode 100644 index 0000000..bccc093 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_full_ec.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_full_ec(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + unsigned cert_issuer_key_type, const br_ec_private_key *sk) +{ + /* + * The "full" profile supports all implemented cipher suites. + * + * Rationale for suite order, from most important to least + * important rule: + * + * -- Don't use 3DES if AES is available. + * -- Try to have Forward Secrecy (ECDHE suite) if possible. + * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller). + * -- GCM is better than CCM and CBC. CCM is better than CBC. + * -- CCM is better than CCM_8. + * -- AES-128 is preferred over AES-256 (AES-128 is already + * strong enough, and AES-256 is 40% more expensive). + * + * Note that for ECDH suites, the list will be automatically + * filtered based on the issuing CA key type. + */ + static const uint16_t suites[] = { + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + }; + + /* + * All hash functions are activated. + * Note: the X.509 validation engine will nonetheless refuse to + * validate signatures that use MD5 as hash function. + */ + static const br_hash_class *hashes[] = { + &br_md5_vtable, + &br_sha1_vtable, + &br_sha224_vtable, + &br_sha256_vtable, + &br_sha384_vtable, + &br_sha512_vtable + }; + + int id; + + /* + * Reset server context and set supported versions from TLS-1.0 + * to TLS-1.2 (inclusive). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); + + /* + * Set suites and elliptic curve implementation (for ECDHE). + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + br_ssl_engine_set_default_ec(&cc->eng); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_ec(cc, chain, chain_len, sk, + BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, + cert_issuer_key_type, + br_ssl_engine_get_ec(&cc->eng), +#if BR_LOMUL + br_ecdsa_i15_sign_asn1 +#else + br_ecdsa_i31_sign_asn1 +#endif + ); + + /* + * Set supported hash functions. + */ + for (id = br_md5_ID; id <= br_sha512_ID; id ++) { + const br_hash_class *hc; + + hc = hashes[id - 1]; + br_ssl_engine_set_hash(&cc->eng, id, hc); + } + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_aes_cbc(&cc->eng); + br_ssl_engine_set_default_aes_ccm(&cc->eng); + br_ssl_engine_set_default_aes_gcm(&cc->eng); + br_ssl_engine_set_default_des_cbc(&cc->eng); + br_ssl_engine_set_default_chapol(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_full_rsa.c b/src/bearssl/src/ssl/ssl_server_full_rsa.c new file mode 100644 index 0000000..d67c076 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_full_rsa.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_full_rsa(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk) +{ + /* + * The "full" profile supports all implemented cipher suites. + * + * Rationale for suite order, from most important to least + * important rule: + * + * -- Don't use 3DES if AES is available. + * -- Try to have Forward Secrecy (ECDHE suite) if possible. + * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller). + * -- GCM is better than CBC. + * -- AES-128 is preferred over AES-256 (AES-128 is already + * strong enough, and AES-256 is 40% more expensive). + */ + static const uint16_t suites[] = { + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_RSA_WITH_AES_128_CCM, + BR_TLS_RSA_WITH_AES_256_CCM, + BR_TLS_RSA_WITH_AES_128_CCM_8, + BR_TLS_RSA_WITH_AES_256_CCM_8, + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA + }; + + /* + * All hash functions are activated. + * Note: the X.509 validation engine will nonetheless refuse to + * validate signatures that use MD5 as hash function. + */ + static const br_hash_class *hashes[] = { + &br_md5_vtable, + &br_sha1_vtable, + &br_sha224_vtable, + &br_sha256_vtable, + &br_sha384_vtable, + &br_sha512_vtable + }; + + int id; + + /* + * Reset server context and set supported versions from TLS-1.0 + * to TLS-1.2 (inclusive). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); + + /* + * Set suites and elliptic curve implementation (for ECDHE). + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + br_ssl_engine_set_default_ec(&cc->eng); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_rsa(cc, chain, chain_len, sk, + BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, + br_rsa_private_get_default(), + br_rsa_pkcs1_sign_get_default()); + + /* + * Set supported hash functions. + */ + for (id = br_md5_ID; id <= br_sha512_ID; id ++) { + const br_hash_class *hc; + + hc = hashes[id - 1]; + br_ssl_engine_set_hash(&cc->eng, id, hc); + } + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_aes_cbc(&cc->eng); + br_ssl_engine_set_default_aes_ccm(&cc->eng); + br_ssl_engine_set_default_aes_gcm(&cc->eng); + br_ssl_engine_set_default_des_cbc(&cc->eng); + br_ssl_engine_set_default_chapol(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_mine2c.c b/src/bearssl/src/ssl/ssl_server_mine2c.c new file mode 100644 index 0000000..bf61b56 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_mine2c.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_mine2c(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk) +{ + static const uint16_t suites[] = { + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + }; + + /* + * Reset server context and set supported versions to TLS-1.2 (only). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set suites and elliptic curve implementation (for ECDHE). + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_rsa(cc, chain, chain_len, sk, + BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign); + + /* + * Set supported hash functions. + */ + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_chapol(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_mine2g.c b/src/bearssl/src/ssl/ssl_server_mine2g.c new file mode 100644 index 0000000..80fa5b1 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_mine2g.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_mine2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk) +{ + static const uint16_t suites[] = { + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + }; + + /* + * Reset server context and set supported versions to TLS-1.2 (only). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set suites and elliptic curve implementation (for ECDHE). + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_rsa(cc, chain, chain_len, sk, + BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign); + + /* + * Set supported hash functions. + */ + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_aes_gcm(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_minf2c.c b/src/bearssl/src/ssl/ssl_server_minf2c.c new file mode 100644 index 0000000..3f44236 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_minf2c.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_minf2c(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk) +{ + static const uint16_t suites[] = { + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + }; + + /* + * Reset server context and set supported versions to TLS-1.2 (only). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set suites and elliptic curve implementation (for ECDHE). + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_ec(cc, chain, chain_len, sk, + BR_KEYTYPE_SIGN, 0, &br_ec_all_m15, br_ecdsa_i31_sign_asn1); + + /* + * Set supported hash functions. + */ + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_chapol(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_minf2g.c b/src/bearssl/src/ssl/ssl_server_minf2g.c new file mode 100644 index 0000000..8613de1 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_minf2g.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_minf2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk) +{ + static const uint16_t suites[] = { + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + }; + + /* + * Reset server context and set supported versions to TLS-1.2 (only). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set suites and elliptic curve implementation (for ECDHE). + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_ec(cc, chain, chain_len, sk, + BR_KEYTYPE_SIGN, 0, &br_ec_all_m15, br_ecdsa_i31_sign_asn1); + + /* + * Set supported hash functions. + */ + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_aes_gcm(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_minr2g.c b/src/bearssl/src/ssl/ssl_server_minr2g.c new file mode 100644 index 0000000..83c238b --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_minr2g.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_minr2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk) +{ + static const uint16_t suites[] = { + BR_TLS_RSA_WITH_AES_128_GCM_SHA256 + }; + + /* + * Reset server context and set supported versions to TLS-1.2 (only). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set suites. + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_rsa(cc, chain, chain_len, sk, + BR_KEYTYPE_KEYX, br_rsa_i31_private, 0); + + /* + * Set supported hash functions. + */ + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_aes_gcm(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_minu2g.c b/src/bearssl/src/ssl/ssl_server_minu2g.c new file mode 100644 index 0000000..6721384 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_minu2g.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_minu2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk) +{ + static const uint16_t suites[] = { + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + }; + + /* + * Reset server context and set supported versions to TLS-1.2 (only). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set suites. + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_ec(cc, chain, chain_len, sk, + BR_KEYTYPE_KEYX, BR_KEYTYPE_RSA, &br_ec_all_m15, 0); + + /* + * Set supported hash functions. + */ + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_aes_gcm(&cc->eng); +} diff --git a/src/bearssl/src/ssl/ssl_server_minv2g.c b/src/bearssl/src/ssl/ssl_server_minv2g.c new file mode 100644 index 0000000..194e654 --- /dev/null +++ b/src/bearssl/src/ssl/ssl_server_minv2g.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_ssl.h */ +void +br_ssl_server_init_minv2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk) +{ + static const uint16_t suites[] = { + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + }; + + /* + * Reset server context and set supported versions to TLS-1.2 (only). + */ + br_ssl_server_zero(cc); + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set suites. + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + + /* + * Set the "server policy": handler for the certificate chain + * and private key operations. + */ + br_ssl_server_set_single_ec(cc, chain, chain_len, sk, + BR_KEYTYPE_KEYX, BR_KEYTYPE_EC, &br_ec_all_m15, 0); + + /* + * Set supported hash functions. + */ + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + + /* + * Set the PRF implementations. + */ + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + + /* + * Symmetric encryption. + */ + br_ssl_engine_set_default_aes_gcm(&cc->eng); +} diff --git a/src/bearssl/src/symcipher/aes_big_cbcdec.c b/src/bearssl/src/symcipher/aes_big_cbcdec.c new file mode 100644 index 0000000..d969a3b --- /dev/null +++ b/src/bearssl/src/symcipher/aes_big_cbcdec.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_big_cbcdec_vtable; + ctx->num_rounds = br_aes_big_keysched_inv(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + + ivbuf = iv; + buf = data; + while (len > 0) { + unsigned char tmp[16]; + int i; + + memcpy(tmp, buf, 16); + br_aes_big_decrypt(ctx->num_rounds, ctx->skey, buf); + for (i = 0; i < 16; i ++) { + buf[i] ^= ivbuf[i]; + } + memcpy(ivbuf, tmp, 16); + buf += 16; + len -= 16; + } +} + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_aes_big_cbcdec_vtable = { + sizeof(br_aes_big_cbcdec_keys), + 16, + 4, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_aes_big_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_aes_big_cbcdec_run +}; diff --git a/src/bearssl/src/symcipher/aes_big_cbcenc.c b/src/bearssl/src/symcipher/aes_big_cbcenc.c new file mode 100644 index 0000000..265e53b --- /dev/null +++ b/src/bearssl/src/symcipher/aes_big_cbcenc.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_big_cbcenc_vtable; + ctx->num_rounds = br_aes_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + + ivbuf = iv; + buf = data; + while (len > 0) { + int i; + + for (i = 0; i < 16; i ++) { + buf[i] ^= ivbuf[i]; + } + br_aes_big_encrypt(ctx->num_rounds, ctx->skey, buf); + memcpy(ivbuf, buf, 16); + buf += 16; + len -= 16; + } +} + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_aes_big_cbcenc_vtable = { + sizeof(br_aes_big_cbcenc_keys), + 16, + 4, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_aes_big_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_aes_big_cbcenc_run +}; diff --git a/src/bearssl/src/symcipher/aes_big_ctr.c b/src/bearssl/src/symcipher/aes_big_ctr.c new file mode 100644 index 0000000..18fbb84 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_big_ctr.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_big_ctr_vtable; + ctx->num_rounds = br_aes_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +uint32_t +br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + + buf = data; + while (len > 0) { + unsigned char tmp[16]; + + memcpy(tmp, iv, 12); + br_enc32be(tmp + 12, cc ++); + br_aes_big_encrypt(ctx->num_rounds, ctx->skey, tmp); + if (len <= 16) { + xorbuf(buf, tmp, len); + break; + } + xorbuf(buf, tmp, 16); + buf += 16; + len -= 16; + } + return cc; +} + +/* see bearssl_block.h */ +const br_block_ctr_class br_aes_big_ctr_vtable = { + sizeof(br_aes_big_ctr_keys), + 16, + 4, + (void (*)(const br_block_ctr_class **, const void *, size_t)) + &br_aes_big_ctr_init, + (uint32_t (*)(const br_block_ctr_class *const *, + const void *, uint32_t, void *, size_t)) + &br_aes_big_ctr_run +}; diff --git a/src/bearssl/src/symcipher/aes_big_ctrcbc.c b/src/bearssl/src/symcipher/aes_big_ctrcbc.c new file mode 100644 index 0000000..d45ca76 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_big_ctrcbc.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_big_ctrcbc_vtable; + ctx->num_rounds = br_aes_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +void +br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len) +{ + unsigned char *buf, *bctr; + uint32_t cc0, cc1, cc2, cc3; + + buf = data; + bctr = ctr; + cc3 = br_dec32be(bctr + 0); + cc2 = br_dec32be(bctr + 4); + cc1 = br_dec32be(bctr + 8); + cc0 = br_dec32be(bctr + 12); + while (len > 0) { + unsigned char tmp[16]; + uint32_t carry; + + br_enc32be(tmp + 0, cc3); + br_enc32be(tmp + 4, cc2); + br_enc32be(tmp + 8, cc1); + br_enc32be(tmp + 12, cc0); + br_aes_big_encrypt(ctx->num_rounds, ctx->skey, tmp); + xorbuf(buf, tmp, 16); + buf += 16; + len -= 16; + cc0 ++; + carry = (~(cc0 | -cc0)) >> 31; + cc1 += carry; + carry &= (~(cc1 | -cc1)) >> 31; + cc2 += carry; + carry &= (~(cc2 | -cc2)) >> 31; + cc3 += carry; + } + br_enc32be(bctr + 0, cc3); + br_enc32be(bctr + 4, cc2); + br_enc32be(bctr + 8, cc1); + br_enc32be(bctr + 12, cc0); +} + +/* see bearssl_block.h */ +void +br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len) +{ + const unsigned char *buf; + + buf = data; + while (len > 0) { + xorbuf(cbcmac, buf, 16); + br_aes_big_encrypt(ctx->num_rounds, ctx->skey, cbcmac); + buf += 16; + len -= 16; + } +} + +/* see bearssl_block.h */ +void +br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + br_aes_big_ctrcbc_ctr(ctx, ctr, data, len); + br_aes_big_ctrcbc_mac(ctx, cbcmac, data, len); +} + +/* see bearssl_block.h */ +void +br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + br_aes_big_ctrcbc_mac(ctx, cbcmac, data, len); + br_aes_big_ctrcbc_ctr(ctx, ctr, data, len); +} + +/* see bearssl_block.h */ +const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable = { + sizeof(br_aes_big_ctrcbc_keys), + 16, + 4, + (void (*)(const br_block_ctrcbc_class **, const void *, size_t)) + &br_aes_big_ctrcbc_init, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_big_ctrcbc_encrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_big_ctrcbc_decrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, size_t)) + &br_aes_big_ctrcbc_ctr, + (void (*)(const br_block_ctrcbc_class *const *, + void *, const void *, size_t)) + &br_aes_big_ctrcbc_mac +}; diff --git a/src/bearssl/src/symcipher/aes_big_dec.c b/src/bearssl/src/symcipher/aes_big_dec.c new file mode 100644 index 0000000..a5d0e3c --- /dev/null +++ b/src/bearssl/src/symcipher/aes_big_dec.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Inverse S-box (used in key schedule for decryption). + */ +static const unsigned char iS[] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D +}; + +static const uint32_t iSsm0[] = { + 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, + 0xACFA58AB, 0x4BE30393, 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, + 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, 0xDEB15A49, 0x25BA1B67, + 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, + 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, + 0x49E06929, 0x8EC9C844, 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, + 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, 0x63DF4A18, 0xE51A3182, + 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, + 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, + 0xE31F8F57, 0x6655AB2A, 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, + 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, 0x8ACF1C2B, 0xA779B492, + 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, + 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, + 0x5E719F06, 0xBD6E1051, 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, + 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, 0x1998FB24, 0xD6BDE997, + 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, + 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, + 0x1E1170AC, 0x6C5A724E, 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, + 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, 0x0C0A67B1, 0x9357E70F, + 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, + 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, + 0x2DB6A8B9, 0x141EA9C8, 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, + 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, 0x8B432976, 0xCB23C6DC, + 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, + 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, + 0x0D8652EC, 0x77C1E3D0, 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, + 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, 0x87494EC7, 0xD938D1C1, + 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, + 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, + 0x2E39F75E, 0x82C3AFF5, 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, + 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, 0xCD267809, 0x6E5918F4, + 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, + 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, + 0xC6A59430, 0x35A266C0, 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, + 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, 0x764DD68D, 0x43EFB04D, + 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, + 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, + 0xE9105633, 0x6DD64713, 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, + 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, 0x9CD2DF59, 0x55F2733F, + 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, + 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, + 0x283C498B, 0xFF0D9541, 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, + 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742 +}; + +static unsigned +mul2(unsigned x) +{ + x <<= 1; + return x ^ ((unsigned)(-(int)(x >> 8)) & 0x11B); +} + +static unsigned +mul9(unsigned x) +{ + return x ^ mul2(mul2(mul2(x))); +} + +static unsigned +mulb(unsigned x) +{ + unsigned x2; + + x2 = mul2(x); + return x ^ x2 ^ mul2(mul2(x2)); +} + +static unsigned +muld(unsigned x) +{ + unsigned x4; + + x4 = mul2(mul2(x)); + return x ^ x4 ^ mul2(x4); +} + +static unsigned +mule(unsigned x) +{ + unsigned x2, x4; + + x2 = mul2(x); + x4 = mul2(x2); + return x2 ^ x4 ^ mul2(x4); +} + +/* see inner.h */ +unsigned +br_aes_big_keysched_inv(uint32_t *skey, const void *key, size_t key_len) +{ + unsigned num_rounds; + int i, m; + + /* + * Sub-keys for decryption are distinct from encryption sub-keys + * in that InvMixColumns() is already applied for the inner + * rounds. + */ + num_rounds = br_aes_keysched(skey, key, key_len); + m = (int)(num_rounds << 2); + for (i = 4; i < m; i ++) { + uint32_t p; + unsigned p0, p1, p2, p3; + uint32_t q0, q1, q2, q3; + + p = skey[i]; + p0 = p >> 24; + p1 = (p >> 16) & 0xFF; + p2 = (p >> 8) & 0xFF; + p3 = p & 0xFF; + q0 = mule(p0) ^ mulb(p1) ^ muld(p2) ^ mul9(p3); + q1 = mul9(p0) ^ mule(p1) ^ mulb(p2) ^ muld(p3); + q2 = muld(p0) ^ mul9(p1) ^ mule(p2) ^ mulb(p3); + q3 = mulb(p0) ^ muld(p1) ^ mul9(p2) ^ mule(p3); + skey[i] = (q0 << 24) | (q1 << 16) | (q2 << 8) | q3; + } + return num_rounds; +} + +static inline uint32_t +rotr(uint32_t x, int n) +{ + return (x << (32 - n)) | (x >> n); +} + +#define iSboxExt0(x) (iSsm0[x]) +#define iSboxExt1(x) (rotr(iSsm0[x], 8)) +#define iSboxExt2(x) (rotr(iSsm0[x], 16)) +#define iSboxExt3(x) (rotr(iSsm0[x], 24)) + +/* see bearssl.h */ +void +br_aes_big_decrypt(unsigned num_rounds, const uint32_t *skey, void *data) +{ + unsigned char *buf; + uint32_t s0, s1, s2, s3; + uint32_t t0, t1, t2, t3; + unsigned u; + + buf = data; + s0 = br_dec32be(buf); + s1 = br_dec32be(buf + 4); + s2 = br_dec32be(buf + 8); + s3 = br_dec32be(buf + 12); + s0 ^= skey[(num_rounds << 2) + 0]; + s1 ^= skey[(num_rounds << 2) + 1]; + s2 ^= skey[(num_rounds << 2) + 2]; + s3 ^= skey[(num_rounds << 2) + 3]; + for (u = num_rounds - 1; u > 0; u --) { + uint32_t v0 = iSboxExt0(s0 >> 24) + ^ iSboxExt1((s3 >> 16) & 0xFF) + ^ iSboxExt2((s2 >> 8) & 0xFF) + ^ iSboxExt3(s1 & 0xFF); + uint32_t v1 = iSboxExt0(s1 >> 24) + ^ iSboxExt1((s0 >> 16) & 0xFF) + ^ iSboxExt2((s3 >> 8) & 0xFF) + ^ iSboxExt3(s2 & 0xFF); + uint32_t v2 = iSboxExt0(s2 >> 24) + ^ iSboxExt1((s1 >> 16) & 0xFF) + ^ iSboxExt2((s0 >> 8) & 0xFF) + ^ iSboxExt3(s3 & 0xFF); + uint32_t v3 = iSboxExt0(s3 >> 24) + ^ iSboxExt1((s2 >> 16) & 0xFF) + ^ iSboxExt2((s1 >> 8) & 0xFF) + ^ iSboxExt3(s0 & 0xFF); + s0 = v0; + s1 = v1; + s2 = v2; + s3 = v3; + s0 ^= skey[u << 2]; + s1 ^= skey[(u << 2) + 1]; + s2 ^= skey[(u << 2) + 2]; + s3 ^= skey[(u << 2) + 3]; + } + t0 = ((uint32_t)iS[s0 >> 24] << 24) + | ((uint32_t)iS[(s3 >> 16) & 0xFF] << 16) + | ((uint32_t)iS[(s2 >> 8) & 0xFF] << 8) + | (uint32_t)iS[s1 & 0xFF]; + t1 = ((uint32_t)iS[s1 >> 24] << 24) + | ((uint32_t)iS[(s0 >> 16) & 0xFF] << 16) + | ((uint32_t)iS[(s3 >> 8) & 0xFF] << 8) + | (uint32_t)iS[s2 & 0xFF]; + t2 = ((uint32_t)iS[s2 >> 24] << 24) + | ((uint32_t)iS[(s1 >> 16) & 0xFF] << 16) + | ((uint32_t)iS[(s0 >> 8) & 0xFF] << 8) + | (uint32_t)iS[s3 & 0xFF]; + t3 = ((uint32_t)iS[s3 >> 24] << 24) + | ((uint32_t)iS[(s2 >> 16) & 0xFF] << 16) + | ((uint32_t)iS[(s1 >> 8) & 0xFF] << 8) + | (uint32_t)iS[s0 & 0xFF]; + s0 = t0 ^ skey[0]; + s1 = t1 ^ skey[1]; + s2 = t2 ^ skey[2]; + s3 = t3 ^ skey[3]; + br_enc32be(buf, s0); + br_enc32be(buf + 4, s1); + br_enc32be(buf + 8, s2); + br_enc32be(buf + 12, s3); +} diff --git a/src/bearssl/src/symcipher/aes_big_enc.c b/src/bearssl/src/symcipher/aes_big_enc.c new file mode 100644 index 0000000..bbabb9a --- /dev/null +++ b/src/bearssl/src/symcipher/aes_big_enc.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define S br_aes_S + +static const uint32_t Ssm0[] = { + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, + 0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, + 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 0x8FCACA45, 0x1F82829D, + 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, + 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, + 0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, + 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 0x6834345C, 0x51A5A5F4, + 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, + 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, + 0x0A05050F, 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, + 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, 0x1D83839E, + 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, + 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, + 0x5E2F2F71, 0x13848497, 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, + 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46, + 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, + 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, + 0x66333355, 0x11858594, 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, + 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE, + 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, + 0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, + 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 0x93C4C457, 0x55A7A7F2, + 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, + 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, + 0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, + 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 0xDBE0E03B, 0x64323256, + 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, + 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, + 0xD3E4E437, 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, + 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, 0xAC5656FA, + 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, + 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, + 0x73B4B4C7, 0x97C6C651, 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, + 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42, + 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, + 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, + 0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, + 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22, + 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, + 0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, + 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A +}; + +static inline uint32_t +rotr(uint32_t x, int n) +{ + return (x << (32 - n)) | (x >> n); +} + +#define SboxExt0(x) (Ssm0[x]) +#define SboxExt1(x) (rotr(Ssm0[x], 8)) +#define SboxExt2(x) (rotr(Ssm0[x], 16)) +#define SboxExt3(x) (rotr(Ssm0[x], 24)) + + +/* see bearssl.h */ +void +br_aes_big_encrypt(unsigned num_rounds, const uint32_t *skey, void *data) +{ + unsigned char *buf; + uint32_t s0, s1, s2, s3; + uint32_t t0, t1, t2, t3; + unsigned u; + + buf = data; + s0 = br_dec32be(buf); + s1 = br_dec32be(buf + 4); + s2 = br_dec32be(buf + 8); + s3 = br_dec32be(buf + 12); + s0 ^= skey[0]; + s1 ^= skey[1]; + s2 ^= skey[2]; + s3 ^= skey[3]; + for (u = 1; u < num_rounds; u ++) { + uint32_t v0, v1, v2, v3; + + v0 = SboxExt0(s0 >> 24) + ^ SboxExt1((s1 >> 16) & 0xFF) + ^ SboxExt2((s2 >> 8) & 0xFF) + ^ SboxExt3(s3 & 0xFF); + v1 = SboxExt0(s1 >> 24) + ^ SboxExt1((s2 >> 16) & 0xFF) + ^ SboxExt2((s3 >> 8) & 0xFF) + ^ SboxExt3(s0 & 0xFF); + v2 = SboxExt0(s2 >> 24) + ^ SboxExt1((s3 >> 16) & 0xFF) + ^ SboxExt2((s0 >> 8) & 0xFF) + ^ SboxExt3(s1 & 0xFF); + v3 = SboxExt0(s3 >> 24) + ^ SboxExt1((s0 >> 16) & 0xFF) + ^ SboxExt2((s1 >> 8) & 0xFF) + ^ SboxExt3(s2 & 0xFF); + s0 = v0; + s1 = v1; + s2 = v2; + s3 = v3; + s0 ^= skey[u << 2]; + s1 ^= skey[(u << 2) + 1]; + s2 ^= skey[(u << 2) + 2]; + s3 ^= skey[(u << 2) + 3]; + } + t0 = ((uint32_t)S[s0 >> 24] << 24) + | ((uint32_t)S[(s1 >> 16) & 0xFF] << 16) + | ((uint32_t)S[(s2 >> 8) & 0xFF] << 8) + | (uint32_t)S[s3 & 0xFF]; + t1 = ((uint32_t)S[s1 >> 24] << 24) + | ((uint32_t)S[(s2 >> 16) & 0xFF] << 16) + | ((uint32_t)S[(s3 >> 8) & 0xFF] << 8) + | (uint32_t)S[s0 & 0xFF]; + t2 = ((uint32_t)S[s2 >> 24] << 24) + | ((uint32_t)S[(s3 >> 16) & 0xFF] << 16) + | ((uint32_t)S[(s0 >> 8) & 0xFF] << 8) + | (uint32_t)S[s1 & 0xFF]; + t3 = ((uint32_t)S[s3 >> 24] << 24) + | ((uint32_t)S[(s0 >> 16) & 0xFF] << 16) + | ((uint32_t)S[(s1 >> 8) & 0xFF] << 8) + | (uint32_t)S[s2 & 0xFF]; + s0 = t0 ^ skey[num_rounds << 2]; + s1 = t1 ^ skey[(num_rounds << 2) + 1]; + s2 = t2 ^ skey[(num_rounds << 2) + 2]; + s3 = t3 ^ skey[(num_rounds << 2) + 3]; + br_enc32be(buf, s0); + br_enc32be(buf + 4, s1); + br_enc32be(buf + 8, s2); + br_enc32be(buf + 12, s3); +} diff --git a/src/bearssl/src/symcipher/aes_common.c b/src/bearssl/src/symcipher/aes_common.c new file mode 100644 index 0000000..72c64fb --- /dev/null +++ b/src/bearssl/src/symcipher/aes_common.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const uint32_t Rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, + 0x40000000, 0x80000000, 0x1B000000, 0x36000000 +}; + +#define S br_aes_S + +/* see inner.h */ +const unsigned char br_aes_S[] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, + 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, + 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, + 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, + 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, + 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, + 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, + 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, + 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, + 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, + 0xB0, 0x54, 0xBB, 0x16 +}; + +static uint32_t +SubWord(uint32_t x) +{ + return ((uint32_t)S[x >> 24] << 24) + | ((uint32_t)S[(x >> 16) & 0xFF] << 16) + | ((uint32_t)S[(x >> 8) & 0xFF] << 8) + | (uint32_t)S[x & 0xFF]; +} + +/* see inner.h */ +unsigned +br_aes_keysched(uint32_t *skey, const void *key, size_t key_len) +{ + unsigned num_rounds; + int i, j, k, nk, nkf; + + switch (key_len) { + case 16: + num_rounds = 10; + break; + case 24: + num_rounds = 12; + break; + case 32: + num_rounds = 14; + break; + default: + /* abort(); */ + return 0; + } + nk = (int)(key_len >> 2); + nkf = (int)((num_rounds + 1) << 2); + for (i = 0; i < nk; i ++) { + skey[i] = br_dec32be((const unsigned char *)key + (i << 2)); + } + for (i = nk, j = 0, k = 0; i < nkf; i ++) { + uint32_t tmp; + + tmp = skey[i - 1]; + if (j == 0) { + tmp = (tmp << 8) | (tmp >> 24); + tmp = SubWord(tmp) ^ Rcon[k]; + } else if (nk > 6 && j == 4) { + tmp = SubWord(tmp); + } + skey[i] = skey[i - nk] ^ tmp; + if (++ j == nk) { + j = 0; + k ++; + } + } + return num_rounds; +} diff --git a/src/bearssl/src/symcipher/aes_ct.c b/src/bearssl/src/symcipher/aes_ct.c new file mode 100644 index 0000000..66776d9 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_aes_ct_bitslice_Sbox(uint32_t *q) +{ + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +/* see inner.h */ +void +br_aes_ct_ortho(uint32_t *q) +{ +#define SWAPN(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)cl) | ((b & (uint32_t)cl) << (s)); \ + (y) = ((a & (uint32_t)ch) >> (s)) | (b & (uint32_t)ch); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + +static const unsigned char Rcon[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 +}; + +static uint32_t +sub_word(uint32_t x) +{ + uint32_t q[8]; + int i; + + for (i = 0; i < 8; i ++) { + q[i] = x; + } + br_aes_ct_ortho(q); + br_aes_ct_bitslice_Sbox(q); + br_aes_ct_ortho(q); + return q[0]; +} + +/* see inner.h */ +unsigned +br_aes_ct_keysched(uint32_t *comp_skey, const void *key, size_t key_len) +{ + unsigned num_rounds; + int i, j, k, nk, nkf; + uint32_t tmp; + uint32_t skey[120]; + + switch (key_len) { + case 16: + num_rounds = 10; + break; + case 24: + num_rounds = 12; + break; + case 32: + num_rounds = 14; + break; + default: + /* abort(); */ + return 0; + } + nk = (int)(key_len >> 2); + nkf = (int)((num_rounds + 1) << 2); + tmp = 0; + for (i = 0; i < nk; i ++) { + tmp = br_dec32le((const unsigned char *)key + (i << 2)); + skey[(i << 1) + 0] = tmp; + skey[(i << 1) + 1] = tmp; + } + for (i = nk, j = 0, k = 0; i < nkf; i ++) { + if (j == 0) { + tmp = (tmp << 24) | (tmp >> 8); + tmp = sub_word(tmp) ^ Rcon[k]; + } else if (nk > 6 && j == 4) { + tmp = sub_word(tmp); + } + tmp ^= skey[(i - nk) << 1]; + skey[(i << 1) + 0] = tmp; + skey[(i << 1) + 1] = tmp; + if (++ j == nk) { + j = 0; + k ++; + } + } + for (i = 0; i < nkf; i += 4) { + br_aes_ct_ortho(skey + (i << 1)); + } + for (i = 0, j = 0; i < nkf; i ++, j += 2) { + comp_skey[i] = (skey[j + 0] & 0x55555555) + | (skey[j + 1] & 0xAAAAAAAA); + } + return num_rounds; +} + +/* see inner.h */ +void +br_aes_ct_skey_expand(uint32_t *skey, + unsigned num_rounds, const uint32_t *comp_skey) +{ + unsigned u, v, n; + + n = (num_rounds + 1) << 2; + for (u = 0, v = 0; u < n; u ++, v += 2) { + uint32_t x, y; + + x = y = comp_skey[u]; + x &= 0x55555555; + skey[v + 0] = x | (x << 1); + y &= 0xAAAAAAAA; + skey[v + 1] = y | (y >> 1); + } +} diff --git a/src/bearssl/src/symcipher/aes_ct64.c b/src/bearssl/src/symcipher/aes_ct64.c new file mode 100644 index 0000000..1523811 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct64.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_aes_ct64_bitslice_Sbox(uint64_t *q) +{ + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +/* see inner.h */ +void +br_aes_ct64_ortho(uint64_t *q) +{ +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)cl) | ((b & (uint64_t)cl) << (s)); \ + (y) = ((a & (uint64_t)ch) >> (s)) | (b & (uint64_t)ch); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + +/* see inner.h */ +void +br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) +{ + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + +/* see inner.h */ +void +br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) +{ + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static const unsigned char Rcon[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 +}; + +static uint32_t +sub_word(uint32_t x) +{ + uint64_t q[8]; + + memset(q, 0, sizeof q); + q[0] = x; + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_Sbox(q); + br_aes_ct64_ortho(q); + return (uint32_t)q[0]; +} + +/* see inner.h */ +unsigned +br_aes_ct64_keysched(uint64_t *comp_skey, const void *key, size_t key_len) +{ + unsigned num_rounds; + int i, j, k, nk, nkf; + uint32_t tmp; + uint32_t skey[60]; + + switch (key_len) { + case 16: + num_rounds = 10; + break; + case 24: + num_rounds = 12; + break; + case 32: + num_rounds = 14; + break; + default: + /* abort(); */ + return 0; + } + nk = (int)(key_len >> 2); + nkf = (int)((num_rounds + 1) << 2); + br_range_dec32le(skey, (key_len >> 2), key); + tmp = skey[(key_len >> 2) - 1]; + for (i = nk, j = 0, k = 0; i < nkf; i ++) { + if (j == 0) { + tmp = (tmp << 24) | (tmp >> 8); + tmp = sub_word(tmp) ^ Rcon[k]; + } else if (nk > 6 && j == 4) { + tmp = sub_word(tmp); + } + tmp ^= skey[i - nk]; + skey[i] = tmp; + if (++ j == nk) { + j = 0; + k ++; + } + } + + for (i = 0, j = 0; i < nkf; i += 4, j += 2) { + uint64_t q[8]; + + br_aes_ct64_interleave_in(&q[0], &q[4], skey + i); + q[1] = q[0]; + q[2] = q[0]; + q[3] = q[0]; + q[5] = q[4]; + q[6] = q[4]; + q[7] = q[4]; + br_aes_ct64_ortho(q); + comp_skey[j + 0] = + (q[0] & (uint64_t)0x1111111111111111) + | (q[1] & (uint64_t)0x2222222222222222) + | (q[2] & (uint64_t)0x4444444444444444) + | (q[3] & (uint64_t)0x8888888888888888); + comp_skey[j + 1] = + (q[4] & (uint64_t)0x1111111111111111) + | (q[5] & (uint64_t)0x2222222222222222) + | (q[6] & (uint64_t)0x4444444444444444) + | (q[7] & (uint64_t)0x8888888888888888); + } + return num_rounds; +} + +/* see inner.h */ +void +br_aes_ct64_skey_expand(uint64_t *skey, + unsigned num_rounds, const uint64_t *comp_skey) +{ + unsigned u, v, n; + + n = (num_rounds + 1) << 1; + for (u = 0, v = 0; u < n; u ++, v += 4) { + uint64_t x0, x1, x2, x3; + + x0 = x1 = x2 = x3 = comp_skey[u]; + x0 &= (uint64_t)0x1111111111111111; + x1 &= (uint64_t)0x2222222222222222; + x2 &= (uint64_t)0x4444444444444444; + x3 &= (uint64_t)0x8888888888888888; + x1 >>= 1; + x2 >>= 2; + x3 >>= 3; + skey[v + 0] = (x0 << 4) - x0; + skey[v + 1] = (x1 << 4) - x1; + skey[v + 2] = (x2 << 4) - x2; + skey[v + 3] = (x3 << 4) - x3; + } +} diff --git a/src/bearssl/src/symcipher/aes_ct64_cbcdec.c b/src/bearssl/src/symcipher/aes_ct64_cbcdec.c new file mode 100644 index 0000000..5a7360b --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct64_cbcdec.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct64_cbcdec_vtable; + ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf; + uint64_t sk_exp[120]; + uint32_t ivw[4]; + + br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + br_range_dec32le(ivw, 4, iv); + buf = data; + while (len > 0) { + uint64_t q[8]; + uint32_t w1[16], w2[16]; + int i; + + if (len >= 64) { + br_range_dec32le(w1, 16, buf); + } else { + br_range_dec32le(w1, len >> 2, buf); + } + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_in( + &q[i], &q[i + 4], w1 + (i << 2)); + } + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_decrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out( + w2 + (i << 2), q[i], q[i + 4]); + } + for (i = 0; i < 4; i ++) { + w2[i] ^= ivw[i]; + } + if (len >= 64) { + for (i = 4; i < 16; i ++) { + w2[i] ^= w1[i - 4]; + } + memcpy(ivw, w1 + 12, sizeof ivw); + br_range_enc32le(buf, w2, 16); + } else { + int j; + + j = (int)(len >> 2); + for (i = 4; i < j; i ++) { + w2[i] ^= w1[i - 4]; + } + memcpy(ivw, w1 + j - 4, sizeof ivw); + br_range_enc32le(buf, w2, j); + break; + } + buf += 64; + len -= 64; + } + br_range_enc32le(iv, ivw, 4); +} + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable = { + sizeof(br_aes_ct64_cbcdec_keys), + 16, + 4, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_aes_ct64_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_aes_ct64_cbcdec_run +}; diff --git a/src/bearssl/src/symcipher/aes_ct64_cbcenc.c b/src/bearssl/src/symcipher/aes_ct64_cbcenc.c new file mode 100644 index 0000000..6cb9dec --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct64_cbcenc.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct64_cbcenc_vtable; + ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf; + uint64_t sk_exp[120]; + uint32_t ivw[4]; + + br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + br_range_dec32le(ivw, 4, iv); + buf = data; + while (len > 0) { + uint32_t w[4]; + uint64_t q[8]; + + w[0] = ivw[0] ^ br_dec32le(buf); + w[1] = ivw[1] ^ br_dec32le(buf + 4); + w[2] = ivw[2] ^ br_dec32le(buf + 8); + w[3] = ivw[3] ^ br_dec32le(buf + 12); + br_aes_ct64_interleave_in(&q[0], &q[4], w); + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + br_aes_ct64_interleave_out(w, q[0], q[4]); + memcpy(ivw, w, sizeof w); + br_enc32le(buf, w[0]); + br_enc32le(buf + 4, w[1]); + br_enc32le(buf + 8, w[2]); + br_enc32le(buf + 12, w[3]); + buf += 16; + len -= 16; + } + br_range_enc32le(iv, ivw, 4); +} + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable = { + sizeof(br_aes_ct64_cbcenc_keys), + 16, + 4, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_aes_ct64_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_aes_ct64_cbcenc_run +}; diff --git a/src/bearssl/src/symcipher/aes_ct64_ctr.c b/src/bearssl/src/symcipher/aes_ct64_ctr.c new file mode 100644 index 0000000..1275873 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct64_ctr.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct64_ctr_vtable; + ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +uint32_t +br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + uint32_t ivw[16]; + uint64_t sk_exp[120]; + + br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + br_range_dec32le(ivw, 3, iv); + memcpy(ivw + 4, ivw, 3 * sizeof(uint32_t)); + memcpy(ivw + 8, ivw, 3 * sizeof(uint32_t)); + memcpy(ivw + 12, ivw, 3 * sizeof(uint32_t)); + buf = data; + while (len > 0) { + uint64_t q[8]; + uint32_t w[16]; + unsigned char tmp[64]; + int i; + + /* + * TODO: see if we can save on the first br_aes_ct64_ortho() + * call, since iv0/iv1/iv2 are constant for the whole run. + */ + memcpy(w, ivw, sizeof ivw); + w[3] = br_swap32(cc); + w[7] = br_swap32(cc + 1); + w[11] = br_swap32(cc + 2); + w[15] = br_swap32(cc + 3); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_in( + &q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out( + w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(tmp, w, 16); + if (len <= 64) { + xorbuf(buf, tmp, len); + cc += (uint32_t)len >> 4; + break; + } + xorbuf(buf, tmp, 64); + buf += 64; + len -= 64; + cc += 4; + } + return cc; +} + +/* see bearssl_block.h */ +const br_block_ctr_class br_aes_ct64_ctr_vtable = { + sizeof(br_aes_ct64_ctr_keys), + 16, + 4, + (void (*)(const br_block_ctr_class **, const void *, size_t)) + &br_aes_ct64_ctr_init, + (uint32_t (*)(const br_block_ctr_class *const *, + const void *, uint32_t, void *, size_t)) + &br_aes_ct64_ctr_run +}; diff --git a/src/bearssl/src/symcipher/aes_ct64_ctrcbc.c b/src/bearssl/src/symcipher/aes_ct64_ctrcbc.c new file mode 100644 index 0000000..21bb8ef --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct64_ctrcbc.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct64_ctrcbc_vtable; + ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +void +br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len) +{ + unsigned char *buf; + unsigned char *ivbuf; + uint32_t iv0, iv1, iv2, iv3; + uint64_t sk_exp[120]; + + br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + /* + * We keep the counter as four 32-bit values, with big-endian + * convention, because that's what is expected for purposes of + * incrementing the counter value. + */ + ivbuf = ctr; + iv0 = br_dec32be(ivbuf + 0); + iv1 = br_dec32be(ivbuf + 4); + iv2 = br_dec32be(ivbuf + 8); + iv3 = br_dec32be(ivbuf + 12); + + buf = data; + while (len > 0) { + uint64_t q[8]; + uint32_t w[16]; + unsigned char tmp[64]; + int i, j; + + /* + * The bitslice implementation expects values in + * little-endian convention, so we have to byteswap them. + */ + j = (len >= 64) ? 16 : (int)(len >> 2); + for (i = 0; i < j; i += 4) { + uint32_t carry; + + w[i + 0] = br_swap32(iv0); + w[i + 1] = br_swap32(iv1); + w[i + 2] = br_swap32(iv2); + w[i + 3] = br_swap32(iv3); + iv3 ++; + carry = ~(iv3 | -iv3) >> 31; + iv2 += carry; + carry &= -(~(iv2 | -iv2) >> 31); + iv1 += carry; + carry &= -(~(iv1 | -iv1) >> 31); + iv0 += carry; + } + memset(w + i, 0, (16 - i) * sizeof(uint32_t)); + + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_in( + &q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out( + w + (i << 2), q[i], q[i + 4]); + } + + br_range_enc32le(tmp, w, 16); + if (len <= 64) { + xorbuf(buf, tmp, len); + break; + } + xorbuf(buf, tmp, 64); + buf += 64; + len -= 64; + } + br_enc32be(ivbuf + 0, iv0); + br_enc32be(ivbuf + 4, iv1); + br_enc32be(ivbuf + 8, iv2); + br_enc32be(ivbuf + 12, iv3); +} + +/* see bearssl_block.h */ +void +br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len) +{ + const unsigned char *buf; + uint32_t cm0, cm1, cm2, cm3; + uint64_t q[8]; + uint64_t sk_exp[120]; + + br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + cm0 = br_dec32le((unsigned char *)cbcmac + 0); + cm1 = br_dec32le((unsigned char *)cbcmac + 4); + cm2 = br_dec32le((unsigned char *)cbcmac + 8); + cm3 = br_dec32le((unsigned char *)cbcmac + 12); + + buf = data; + memset(q, 0, sizeof q); + while (len > 0) { + uint32_t w[4]; + + w[0] = cm0 ^ br_dec32le(buf + 0); + w[1] = cm1 ^ br_dec32le(buf + 4); + w[2] = cm2 ^ br_dec32le(buf + 8); + w[3] = cm3 ^ br_dec32le(buf + 12); + + br_aes_ct64_interleave_in(&q[0], &q[4], w); + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + br_aes_ct64_interleave_out(w, q[0], q[4]); + + cm0 = w[0]; + cm1 = w[1]; + cm2 = w[2]; + cm3 = w[3]; + buf += 16; + len -= 16; + } + + br_enc32le((unsigned char *)cbcmac + 0, cm0); + br_enc32le((unsigned char *)cbcmac + 4, cm1); + br_enc32le((unsigned char *)cbcmac + 8, cm2); + br_enc32le((unsigned char *)cbcmac + 12, cm3); +} + +/* see bearssl_block.h */ +void +br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + /* + * When encrypting, the CBC-MAC processing must be lagging by + * one block, since it operates on the encrypted values, so + * it must wait for that encryption to complete. + */ + + unsigned char *buf; + unsigned char *ivbuf; + uint32_t iv0, iv1, iv2, iv3; + uint32_t cm0, cm1, cm2, cm3; + uint64_t sk_exp[120]; + uint64_t q[8]; + int first_iter; + + br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + /* + * We keep the counter as four 32-bit values, with big-endian + * convention, because that's what is expected for purposes of + * incrementing the counter value. + */ + ivbuf = ctr; + iv0 = br_dec32be(ivbuf + 0); + iv1 = br_dec32be(ivbuf + 4); + iv2 = br_dec32be(ivbuf + 8); + iv3 = br_dec32be(ivbuf + 12); + + /* + * The current CBC-MAC value is kept in little-endian convention. + */ + cm0 = br_dec32le((unsigned char *)cbcmac + 0); + cm1 = br_dec32le((unsigned char *)cbcmac + 4); + cm2 = br_dec32le((unsigned char *)cbcmac + 8); + cm3 = br_dec32le((unsigned char *)cbcmac + 12); + + buf = data; + first_iter = 1; + memset(q, 0, sizeof q); + while (len > 0) { + uint32_t w[8], carry; + + /* + * The bitslice implementation expects values in + * little-endian convention, so we have to byteswap them. + */ + w[0] = br_swap32(iv0); + w[1] = br_swap32(iv1); + w[2] = br_swap32(iv2); + w[3] = br_swap32(iv3); + iv3 ++; + carry = ~(iv3 | -iv3) >> 31; + iv2 += carry; + carry &= -(~(iv2 | -iv2) >> 31); + iv1 += carry; + carry &= -(~(iv1 | -iv1) >> 31); + iv0 += carry; + + /* + * The block for CBC-MAC. + */ + w[4] = cm0; + w[5] = cm1; + w[6] = cm2; + w[7] = cm3; + + br_aes_ct64_interleave_in(&q[0], &q[4], w); + br_aes_ct64_interleave_in(&q[1], &q[5], w + 4); + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + br_aes_ct64_interleave_out(w, q[0], q[4]); + br_aes_ct64_interleave_out(w + 4, q[1], q[5]); + + /* + * We do the XOR with the plaintext in 32-bit registers, + * so that the value are available for CBC-MAC processing + * as well. + */ + w[0] ^= br_dec32le(buf + 0); + w[1] ^= br_dec32le(buf + 4); + w[2] ^= br_dec32le(buf + 8); + w[3] ^= br_dec32le(buf + 12); + br_enc32le(buf + 0, w[0]); + br_enc32le(buf + 4, w[1]); + br_enc32le(buf + 8, w[2]); + br_enc32le(buf + 12, w[3]); + + buf += 16; + len -= 16; + + /* + * We set the cm* values to the block to encrypt in the + * next iteration. + */ + if (first_iter) { + first_iter = 0; + cm0 ^= w[0]; + cm1 ^= w[1]; + cm2 ^= w[2]; + cm3 ^= w[3]; + } else { + cm0 = w[0] ^ w[4]; + cm1 = w[1] ^ w[5]; + cm2 = w[2] ^ w[6]; + cm3 = w[3] ^ w[7]; + } + + /* + * If this was the last iteration, then compute the + * extra block encryption to complete CBC-MAC. + */ + if (len == 0) { + w[0] = cm0; + w[1] = cm1; + w[2] = cm2; + w[3] = cm3; + br_aes_ct64_interleave_in(&q[0], &q[4], w); + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_encrypt( + ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + br_aes_ct64_interleave_out(w, q[0], q[4]); + cm0 = w[0]; + cm1 = w[1]; + cm2 = w[2]; + cm3 = w[3]; + break; + } + } + + br_enc32be(ivbuf + 0, iv0); + br_enc32be(ivbuf + 4, iv1); + br_enc32be(ivbuf + 8, iv2); + br_enc32be(ivbuf + 12, iv3); + br_enc32le((unsigned char *)cbcmac + 0, cm0); + br_enc32le((unsigned char *)cbcmac + 4, cm1); + br_enc32le((unsigned char *)cbcmac + 8, cm2); + br_enc32le((unsigned char *)cbcmac + 12, cm3); +} + +/* see bearssl_block.h */ +void +br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + unsigned char *buf; + unsigned char *ivbuf; + uint32_t iv0, iv1, iv2, iv3; + uint32_t cm0, cm1, cm2, cm3; + uint64_t sk_exp[120]; + uint64_t q[8]; + + br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + /* + * We keep the counter as four 32-bit values, with big-endian + * convention, because that's what is expected for purposes of + * incrementing the counter value. + */ + ivbuf = ctr; + iv0 = br_dec32be(ivbuf + 0); + iv1 = br_dec32be(ivbuf + 4); + iv2 = br_dec32be(ivbuf + 8); + iv3 = br_dec32be(ivbuf + 12); + + /* + * The current CBC-MAC value is kept in little-endian convention. + */ + cm0 = br_dec32le((unsigned char *)cbcmac + 0); + cm1 = br_dec32le((unsigned char *)cbcmac + 4); + cm2 = br_dec32le((unsigned char *)cbcmac + 8); + cm3 = br_dec32le((unsigned char *)cbcmac + 12); + + buf = data; + memset(q, 0, sizeof q); + while (len > 0) { + uint32_t w[8], carry; + unsigned char tmp[16]; + + /* + * The bitslice implementation expects values in + * little-endian convention, so we have to byteswap them. + */ + w[0] = br_swap32(iv0); + w[1] = br_swap32(iv1); + w[2] = br_swap32(iv2); + w[3] = br_swap32(iv3); + iv3 ++; + carry = ~(iv3 | -iv3) >> 31; + iv2 += carry; + carry &= -(~(iv2 | -iv2) >> 31); + iv1 += carry; + carry &= -(~(iv1 | -iv1) >> 31); + iv0 += carry; + + /* + * The block for CBC-MAC. + */ + w[4] = cm0 ^ br_dec32le(buf + 0); + w[5] = cm1 ^ br_dec32le(buf + 4); + w[6] = cm2 ^ br_dec32le(buf + 8); + w[7] = cm3 ^ br_dec32le(buf + 12); + + br_aes_ct64_interleave_in(&q[0], &q[4], w); + br_aes_ct64_interleave_in(&q[1], &q[5], w + 4); + br_aes_ct64_ortho(q); + br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct64_ortho(q); + br_aes_ct64_interleave_out(w, q[0], q[4]); + br_aes_ct64_interleave_out(w + 4, q[1], q[5]); + + br_enc32le(tmp + 0, w[0]); + br_enc32le(tmp + 4, w[1]); + br_enc32le(tmp + 8, w[2]); + br_enc32le(tmp + 12, w[3]); + xorbuf(buf, tmp, 16); + cm0 = w[4]; + cm1 = w[5]; + cm2 = w[6]; + cm3 = w[7]; + buf += 16; + len -= 16; + } + + br_enc32be(ivbuf + 0, iv0); + br_enc32be(ivbuf + 4, iv1); + br_enc32be(ivbuf + 8, iv2); + br_enc32be(ivbuf + 12, iv3); + br_enc32le((unsigned char *)cbcmac + 0, cm0); + br_enc32le((unsigned char *)cbcmac + 4, cm1); + br_enc32le((unsigned char *)cbcmac + 8, cm2); + br_enc32le((unsigned char *)cbcmac + 12, cm3); +} + +/* see bearssl_block.h */ +const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable = { + sizeof(br_aes_ct64_ctrcbc_keys), + 16, + 4, + (void (*)(const br_block_ctrcbc_class **, const void *, size_t)) + &br_aes_ct64_ctrcbc_init, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_ct64_ctrcbc_encrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_ct64_ctrcbc_decrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, size_t)) + &br_aes_ct64_ctrcbc_ctr, + (void (*)(const br_block_ctrcbc_class *const *, + void *, const void *, size_t)) + &br_aes_ct64_ctrcbc_mac +}; diff --git a/src/bearssl/src/symcipher/aes_ct64_dec.c b/src/bearssl/src/symcipher/aes_ct64_dec.c new file mode 100644 index 0000000..ab00e09 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct64_dec.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_aes_ct64_bitslice_invSbox(uint64_t *q) +{ + /* + * See br_aes_ct_bitslice_invSbox(). This is the natural extension + * to 64-bit registers. + */ + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + + q0 = ~q[0]; + q1 = ~q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = ~q[5]; + q6 = ~q[6]; + q7 = q[7]; + q[7] = q1 ^ q4 ^ q6; + q[6] = q0 ^ q3 ^ q5; + q[5] = q7 ^ q2 ^ q4; + q[4] = q6 ^ q1 ^ q3; + q[3] = q5 ^ q0 ^ q2; + q[2] = q4 ^ q7 ^ q1; + q[1] = q3 ^ q6 ^ q0; + q[0] = q2 ^ q5 ^ q7; + + br_aes_ct64_bitslice_Sbox(q); + + q0 = ~q[0]; + q1 = ~q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = ~q[5]; + q6 = ~q[6]; + q7 = q[7]; + q[7] = q1 ^ q4 ^ q6; + q[6] = q0 ^ q3 ^ q5; + q[5] = q7 ^ q2 ^ q4; + q[4] = q6 ^ q1 ^ q3; + q[3] = q5 ^ q0 ^ q2; + q[2] = q4 ^ q7 ^ q1; + q[1] = q3 ^ q6 ^ q0; + q[0] = q2 ^ q5 ^ q7; +} + +static void +add_round_key(uint64_t *q, const uint64_t *sk) +{ + int i; + + for (i = 0; i < 8; i ++) { + q[i] ^= sk[i]; + } +} + +static void +inv_shift_rows(uint64_t *q) +{ + int i; + + for (i = 0; i < 8; i ++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x000000000FFF0000) << 4) + | ((x & (uint64_t)0x00000000F0000000) >> 12) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000F000000000000) << 12) + | ((x & (uint64_t)0xFFF0000000000000) >> 4); + } +} + +static inline uint64_t +rotr32(uint64_t x) +{ + return (x << 32) | (x >> 32); +} + +static void +inv_mix_columns(uint64_t *q) +{ + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr32(q0 ^ q5 ^ q6 ^ r0 ^ r5); + q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6); + q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr32(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7); + q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr32(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7); + q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6); + q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7); + q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr32(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7); + q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr32(q4 ^ q5 ^ q7 ^ r4 ^ r7); +} + +/* see inner.h */ +void +br_aes_ct64_bitslice_decrypt(unsigned num_rounds, + const uint64_t *skey, uint64_t *q) +{ + unsigned u; + + add_round_key(q, skey + (num_rounds << 3)); + for (u = num_rounds - 1; u > 0; u --) { + inv_shift_rows(q); + br_aes_ct64_bitslice_invSbox(q); + add_round_key(q, skey + (u << 3)); + inv_mix_columns(q); + } + inv_shift_rows(q); + br_aes_ct64_bitslice_invSbox(q); + add_round_key(q, skey); +} diff --git a/src/bearssl/src/symcipher/aes_ct64_enc.c b/src/bearssl/src/symcipher/aes_ct64_enc.c new file mode 100644 index 0000000..78631ce --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct64_enc.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static inline void +add_round_key(uint64_t *q, const uint64_t *sk) +{ + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void +shift_rows(uint64_t *q) +{ + int i; + + for (i = 0; i < 8; i ++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t +rotr32(uint64_t x) +{ + return (x << 32) | (x >> 32); +} + +static inline void +mix_columns(uint64_t *q) +{ + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +/* see inner.h */ +void +br_aes_ct64_bitslice_encrypt(unsigned num_rounds, + const uint64_t *skey, uint64_t *q) +{ + unsigned u; + + add_round_key(q, skey); + for (u = 1; u < num_rounds; u ++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, skey + (u << 3)); + } + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + add_round_key(q, skey + (num_rounds << 3)); +} diff --git a/src/bearssl/src/symcipher/aes_ct_cbcdec.c b/src/bearssl/src/symcipher/aes_ct_cbcdec.c new file mode 100644 index 0000000..522645a --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct_cbcdec.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct_cbcdec_vtable; + ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + uint32_t iv0, iv1, iv2, iv3; + uint32_t sk_exp[120]; + + br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + ivbuf = iv; + iv0 = br_dec32le(ivbuf); + iv1 = br_dec32le(ivbuf + 4); + iv2 = br_dec32le(ivbuf + 8); + iv3 = br_dec32le(ivbuf + 12); + buf = data; + while (len > 0) { + uint32_t q[8], sq[8]; + + q[0] = br_dec32le(buf); + q[2] = br_dec32le(buf + 4); + q[4] = br_dec32le(buf + 8); + q[6] = br_dec32le(buf + 12); + if (len >= 32) { + q[1] = br_dec32le(buf + 16); + q[3] = br_dec32le(buf + 20); + q[5] = br_dec32le(buf + 24); + q[7] = br_dec32le(buf + 28); + } else { + q[1] = 0; + q[3] = 0; + q[5] = 0; + q[7] = 0; + } + memcpy(sq, q, sizeof q); + br_aes_ct_ortho(q); + br_aes_ct_bitslice_decrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + br_enc32le(buf, q[0] ^ iv0); + br_enc32le(buf + 4, q[2] ^ iv1); + br_enc32le(buf + 8, q[4] ^ iv2); + br_enc32le(buf + 12, q[6] ^ iv3); + if (len < 32) { + iv0 = sq[0]; + iv1 = sq[2]; + iv2 = sq[4]; + iv3 = sq[6]; + break; + } + br_enc32le(buf + 16, q[1] ^ sq[0]); + br_enc32le(buf + 20, q[3] ^ sq[2]); + br_enc32le(buf + 24, q[5] ^ sq[4]); + br_enc32le(buf + 28, q[7] ^ sq[6]); + iv0 = sq[1]; + iv1 = sq[3]; + iv2 = sq[5]; + iv3 = sq[7]; + buf += 32; + len -= 32; + } + br_enc32le(ivbuf, iv0); + br_enc32le(ivbuf + 4, iv1); + br_enc32le(ivbuf + 8, iv2); + br_enc32le(ivbuf + 12, iv3); +} + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_aes_ct_cbcdec_vtable = { + sizeof(br_aes_ct_cbcdec_keys), + 16, + 4, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_aes_ct_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_aes_ct_cbcdec_run +}; diff --git a/src/bearssl/src/symcipher/aes_ct_cbcenc.c b/src/bearssl/src/symcipher/aes_ct_cbcenc.c new file mode 100644 index 0000000..cb85977 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct_cbcenc.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct_cbcenc_vtable; + ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + uint32_t q[8]; + uint32_t iv0, iv1, iv2, iv3; + uint32_t sk_exp[120]; + + q[1] = 0; + q[3] = 0; + q[5] = 0; + q[7] = 0; + br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + ivbuf = iv; + iv0 = br_dec32le(ivbuf); + iv1 = br_dec32le(ivbuf + 4); + iv2 = br_dec32le(ivbuf + 8); + iv3 = br_dec32le(ivbuf + 12); + buf = data; + while (len > 0) { + q[0] = iv0 ^ br_dec32le(buf); + q[2] = iv1 ^ br_dec32le(buf + 4); + q[4] = iv2 ^ br_dec32le(buf + 8); + q[6] = iv3 ^ br_dec32le(buf + 12); + br_aes_ct_ortho(q); + br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + iv0 = q[0]; + iv1 = q[2]; + iv2 = q[4]; + iv3 = q[6]; + br_enc32le(buf, iv0); + br_enc32le(buf + 4, iv1); + br_enc32le(buf + 8, iv2); + br_enc32le(buf + 12, iv3); + buf += 16; + len -= 16; + } + br_enc32le(ivbuf, iv0); + br_enc32le(ivbuf + 4, iv1); + br_enc32le(ivbuf + 8, iv2); + br_enc32le(ivbuf + 12, iv3); +} + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_aes_ct_cbcenc_vtable = { + sizeof(br_aes_ct_cbcenc_keys), + 16, + 4, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_aes_ct_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_aes_ct_cbcenc_run +}; diff --git a/src/bearssl/src/symcipher/aes_ct_ctr.c b/src/bearssl/src/symcipher/aes_ct_ctr.c new file mode 100644 index 0000000..f407689 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct_ctr.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct_ctr_vtable; + ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +uint32_t +br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + const unsigned char *ivbuf; + uint32_t iv0, iv1, iv2; + uint32_t sk_exp[120]; + + br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + ivbuf = iv; + iv0 = br_dec32le(ivbuf); + iv1 = br_dec32le(ivbuf + 4); + iv2 = br_dec32le(ivbuf + 8); + buf = data; + while (len > 0) { + uint32_t q[8]; + unsigned char tmp[32]; + + /* + * TODO: see if we can save on the first br_aes_ct_ortho() + * call, since iv0/iv1/iv2 are constant for the whole run. + */ + q[0] = q[1] = iv0; + q[2] = q[3] = iv1; + q[4] = q[5] = iv2; + q[6] = br_swap32(cc); + q[7] = br_swap32(cc + 1); + br_aes_ct_ortho(q); + br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + br_enc32le(tmp, q[0]); + br_enc32le(tmp + 4, q[2]); + br_enc32le(tmp + 8, q[4]); + br_enc32le(tmp + 12, q[6]); + br_enc32le(tmp + 16, q[1]); + br_enc32le(tmp + 20, q[3]); + br_enc32le(tmp + 24, q[5]); + br_enc32le(tmp + 28, q[7]); + + if (len <= 32) { + xorbuf(buf, tmp, len); + cc ++; + if (len > 16) { + cc ++; + } + break; + } + xorbuf(buf, tmp, 32); + buf += 32; + len -= 32; + cc += 2; + } + return cc; +} + +/* see bearssl_block.h */ +const br_block_ctr_class br_aes_ct_ctr_vtable = { + sizeof(br_aes_ct_ctr_keys), + 16, + 4, + (void (*)(const br_block_ctr_class **, const void *, size_t)) + &br_aes_ct_ctr_init, + (uint32_t (*)(const br_block_ctr_class *const *, + const void *, uint32_t, void *, size_t)) + &br_aes_ct_ctr_run +}; diff --git a/src/bearssl/src/symcipher/aes_ct_ctrcbc.c b/src/bearssl/src/symcipher/aes_ct_ctrcbc.c new file mode 100644 index 0000000..8ae9fc7 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct_ctrcbc.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_ct_ctrcbc_vtable; + ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +void +br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len) +{ + unsigned char *buf; + unsigned char *ivbuf; + uint32_t iv0, iv1, iv2, iv3; + uint32_t sk_exp[120]; + + br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + /* + * We keep the counter as four 32-bit values, with big-endian + * convention, because that's what is expected for purposes of + * incrementing the counter value. + */ + ivbuf = ctr; + iv0 = br_dec32be(ivbuf + 0); + iv1 = br_dec32be(ivbuf + 4); + iv2 = br_dec32be(ivbuf + 8); + iv3 = br_dec32be(ivbuf + 12); + + buf = data; + while (len > 0) { + uint32_t q[8], carry; + unsigned char tmp[32]; + + /* + * The bitslice implementation expects values in + * little-endian convention, so we have to byteswap them. + */ + q[0] = br_swap32(iv0); + q[2] = br_swap32(iv1); + q[4] = br_swap32(iv2); + q[6] = br_swap32(iv3); + iv3 ++; + carry = ~(iv3 | -iv3) >> 31; + iv2 += carry; + carry &= -(~(iv2 | -iv2) >> 31); + iv1 += carry; + carry &= -(~(iv1 | -iv1) >> 31); + iv0 += carry; + q[1] = br_swap32(iv0); + q[3] = br_swap32(iv1); + q[5] = br_swap32(iv2); + q[7] = br_swap32(iv3); + if (len > 16) { + iv3 ++; + carry = ~(iv3 | -iv3) >> 31; + iv2 += carry; + carry &= -(~(iv2 | -iv2) >> 31); + iv1 += carry; + carry &= -(~(iv1 | -iv1) >> 31); + iv0 += carry; + } + + br_aes_ct_ortho(q); + br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + + br_enc32le(tmp, q[0]); + br_enc32le(tmp + 4, q[2]); + br_enc32le(tmp + 8, q[4]); + br_enc32le(tmp + 12, q[6]); + br_enc32le(tmp + 16, q[1]); + br_enc32le(tmp + 20, q[3]); + br_enc32le(tmp + 24, q[5]); + br_enc32le(tmp + 28, q[7]); + + if (len <= 32) { + xorbuf(buf, tmp, len); + break; + } + xorbuf(buf, tmp, 32); + buf += 32; + len -= 32; + } + br_enc32be(ivbuf + 0, iv0); + br_enc32be(ivbuf + 4, iv1); + br_enc32be(ivbuf + 8, iv2); + br_enc32be(ivbuf + 12, iv3); +} + +/* see bearssl_block.h */ +void +br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len) +{ + const unsigned char *buf; + uint32_t cm0, cm1, cm2, cm3; + uint32_t q[8]; + uint32_t sk_exp[120]; + + br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + buf = data; + cm0 = br_dec32le((unsigned char *)cbcmac + 0); + cm1 = br_dec32le((unsigned char *)cbcmac + 4); + cm2 = br_dec32le((unsigned char *)cbcmac + 8); + cm3 = br_dec32le((unsigned char *)cbcmac + 12); + q[1] = 0; + q[3] = 0; + q[5] = 0; + q[7] = 0; + + while (len > 0) { + q[0] = cm0 ^ br_dec32le(buf + 0); + q[2] = cm1 ^ br_dec32le(buf + 4); + q[4] = cm2 ^ br_dec32le(buf + 8); + q[6] = cm3 ^ br_dec32le(buf + 12); + + br_aes_ct_ortho(q); + br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + + cm0 = q[0]; + cm1 = q[2]; + cm2 = q[4]; + cm3 = q[6]; + buf += 16; + len -= 16; + } + + br_enc32le((unsigned char *)cbcmac + 0, cm0); + br_enc32le((unsigned char *)cbcmac + 4, cm1); + br_enc32le((unsigned char *)cbcmac + 8, cm2); + br_enc32le((unsigned char *)cbcmac + 12, cm3); +} + +/* see bearssl_block.h */ +void +br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + /* + * When encrypting, the CBC-MAC processing must be lagging by + * one block, since it operates on the encrypted values, so + * it must wait for that encryption to complete. + */ + + unsigned char *buf; + unsigned char *ivbuf; + uint32_t iv0, iv1, iv2, iv3; + uint32_t cm0, cm1, cm2, cm3; + uint32_t sk_exp[120]; + int first_iter; + + br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + /* + * We keep the counter as four 32-bit values, with big-endian + * convention, because that's what is expected for purposes of + * incrementing the counter value. + */ + ivbuf = ctr; + iv0 = br_dec32be(ivbuf + 0); + iv1 = br_dec32be(ivbuf + 4); + iv2 = br_dec32be(ivbuf + 8); + iv3 = br_dec32be(ivbuf + 12); + + /* + * The current CBC-MAC value is kept in little-endian convention. + */ + cm0 = br_dec32le((unsigned char *)cbcmac + 0); + cm1 = br_dec32le((unsigned char *)cbcmac + 4); + cm2 = br_dec32le((unsigned char *)cbcmac + 8); + cm3 = br_dec32le((unsigned char *)cbcmac + 12); + + buf = data; + first_iter = 1; + while (len > 0) { + uint32_t q[8], carry; + + /* + * The bitslice implementation expects values in + * little-endian convention, so we have to byteswap them. + */ + q[0] = br_swap32(iv0); + q[2] = br_swap32(iv1); + q[4] = br_swap32(iv2); + q[6] = br_swap32(iv3); + iv3 ++; + carry = ~(iv3 | -iv3) >> 31; + iv2 += carry; + carry &= -(~(iv2 | -iv2) >> 31); + iv1 += carry; + carry &= -(~(iv1 | -iv1) >> 31); + iv0 += carry; + + /* + * The odd values are used for CBC-MAC. + */ + q[1] = cm0; + q[3] = cm1; + q[5] = cm2; + q[7] = cm3; + + br_aes_ct_ortho(q); + br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + + /* + * We do the XOR with the plaintext in 32-bit registers, + * so that the value are available for CBC-MAC processing + * as well. + */ + q[0] ^= br_dec32le(buf + 0); + q[2] ^= br_dec32le(buf + 4); + q[4] ^= br_dec32le(buf + 8); + q[6] ^= br_dec32le(buf + 12); + br_enc32le(buf + 0, q[0]); + br_enc32le(buf + 4, q[2]); + br_enc32le(buf + 8, q[4]); + br_enc32le(buf + 12, q[6]); + + buf += 16; + len -= 16; + + /* + * We set the cm* values to the block to encrypt in the + * next iteration. + */ + if (first_iter) { + first_iter = 0; + cm0 ^= q[0]; + cm1 ^= q[2]; + cm2 ^= q[4]; + cm3 ^= q[6]; + } else { + cm0 = q[0] ^ q[1]; + cm1 = q[2] ^ q[3]; + cm2 = q[4] ^ q[5]; + cm3 = q[6] ^ q[7]; + } + + /* + * If this was the last iteration, then compute the + * extra block encryption to complete CBC-MAC. + */ + if (len == 0) { + q[0] = cm0; + q[2] = cm1; + q[4] = cm2; + q[6] = cm3; + br_aes_ct_ortho(q); + br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + cm0 = q[0]; + cm1 = q[2]; + cm2 = q[4]; + cm3 = q[6]; + break; + } + } + + br_enc32be(ivbuf + 0, iv0); + br_enc32be(ivbuf + 4, iv1); + br_enc32be(ivbuf + 8, iv2); + br_enc32be(ivbuf + 12, iv3); + br_enc32le((unsigned char *)cbcmac + 0, cm0); + br_enc32le((unsigned char *)cbcmac + 4, cm1); + br_enc32le((unsigned char *)cbcmac + 8, cm2); + br_enc32le((unsigned char *)cbcmac + 12, cm3); +} + +/* see bearssl_block.h */ +void +br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + unsigned char *buf; + unsigned char *ivbuf; + uint32_t iv0, iv1, iv2, iv3; + uint32_t cm0, cm1, cm2, cm3; + uint32_t sk_exp[120]; + + br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + + /* + * We keep the counter as four 32-bit values, with big-endian + * convention, because that's what is expected for purposes of + * incrementing the counter value. + */ + ivbuf = ctr; + iv0 = br_dec32be(ivbuf + 0); + iv1 = br_dec32be(ivbuf + 4); + iv2 = br_dec32be(ivbuf + 8); + iv3 = br_dec32be(ivbuf + 12); + + /* + * The current CBC-MAC value is kept in little-endian convention. + */ + cm0 = br_dec32le((unsigned char *)cbcmac + 0); + cm1 = br_dec32le((unsigned char *)cbcmac + 4); + cm2 = br_dec32le((unsigned char *)cbcmac + 8); + cm3 = br_dec32le((unsigned char *)cbcmac + 12); + + buf = data; + while (len > 0) { + uint32_t q[8], carry; + unsigned char tmp[16]; + + /* + * The bitslice implementation expects values in + * little-endian convention, so we have to byteswap them. + */ + q[0] = br_swap32(iv0); + q[2] = br_swap32(iv1); + q[4] = br_swap32(iv2); + q[6] = br_swap32(iv3); + iv3 ++; + carry = ~(iv3 | -iv3) >> 31; + iv2 += carry; + carry &= -(~(iv2 | -iv2) >> 31); + iv1 += carry; + carry &= -(~(iv1 | -iv1) >> 31); + iv0 += carry; + + /* + * The odd values are used for CBC-MAC. + */ + q[1] = cm0 ^ br_dec32le(buf + 0); + q[3] = cm1 ^ br_dec32le(buf + 4); + q[5] = cm2 ^ br_dec32le(buf + 8); + q[7] = cm3 ^ br_dec32le(buf + 12); + + br_aes_ct_ortho(q); + br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q); + br_aes_ct_ortho(q); + + br_enc32le(tmp + 0, q[0]); + br_enc32le(tmp + 4, q[2]); + br_enc32le(tmp + 8, q[4]); + br_enc32le(tmp + 12, q[6]); + xorbuf(buf, tmp, 16); + cm0 = q[1]; + cm1 = q[3]; + cm2 = q[5]; + cm3 = q[7]; + buf += 16; + len -= 16; + } + + br_enc32be(ivbuf + 0, iv0); + br_enc32be(ivbuf + 4, iv1); + br_enc32be(ivbuf + 8, iv2); + br_enc32be(ivbuf + 12, iv3); + br_enc32le((unsigned char *)cbcmac + 0, cm0); + br_enc32le((unsigned char *)cbcmac + 4, cm1); + br_enc32le((unsigned char *)cbcmac + 8, cm2); + br_enc32le((unsigned char *)cbcmac + 12, cm3); +} + +/* see bearssl_block.h */ +const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable = { + sizeof(br_aes_ct_ctrcbc_keys), + 16, + 4, + (void (*)(const br_block_ctrcbc_class **, const void *, size_t)) + &br_aes_ct_ctrcbc_init, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_ct_ctrcbc_encrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_ct_ctrcbc_decrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, size_t)) + &br_aes_ct_ctrcbc_ctr, + (void (*)(const br_block_ctrcbc_class *const *, + void *, const void *, size_t)) + &br_aes_ct_ctrcbc_mac +}; diff --git a/src/bearssl/src/symcipher/aes_ct_dec.c b/src/bearssl/src/symcipher/aes_ct_dec.c new file mode 100644 index 0000000..7f32d2b --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct_dec.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_aes_ct_bitslice_invSbox(uint32_t *q) +{ + /* + * AES S-box is: + * S(x) = A(I(x)) ^ 0x63 + * where I() is inversion in GF(256), and A() is a linear + * transform (0 is formally defined to be its own inverse). + * Since inversion is an involution, the inverse S-box can be + * computed from the S-box as: + * iS(x) = B(S(B(x ^ 0x63)) ^ 0x63) + * where B() is the inverse of A(). Indeed, for any y in GF(256): + * iS(S(y)) = B(A(I(B(A(I(y)) ^ 0x63 ^ 0x63))) ^ 0x63 ^ 0x63) = y + * + * Note: we reuse the implementation of the forward S-box, + * instead of duplicating it here, so that total code size is + * lower. By merging the B() transforms into the S-box circuit + * we could make faster CBC decryption, but CBC decryption is + * already quite faster than CBC encryption because we can + * process two blocks in parallel. + */ + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + + q0 = ~q[0]; + q1 = ~q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = ~q[5]; + q6 = ~q[6]; + q7 = q[7]; + q[7] = q1 ^ q4 ^ q6; + q[6] = q0 ^ q3 ^ q5; + q[5] = q7 ^ q2 ^ q4; + q[4] = q6 ^ q1 ^ q3; + q[3] = q5 ^ q0 ^ q2; + q[2] = q4 ^ q7 ^ q1; + q[1] = q3 ^ q6 ^ q0; + q[0] = q2 ^ q5 ^ q7; + + br_aes_ct_bitslice_Sbox(q); + + q0 = ~q[0]; + q1 = ~q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = ~q[5]; + q6 = ~q[6]; + q7 = q[7]; + q[7] = q1 ^ q4 ^ q6; + q[6] = q0 ^ q3 ^ q5; + q[5] = q7 ^ q2 ^ q4; + q[4] = q6 ^ q1 ^ q3; + q[3] = q5 ^ q0 ^ q2; + q[2] = q4 ^ q7 ^ q1; + q[1] = q3 ^ q6 ^ q0; + q[0] = q2 ^ q5 ^ q7; +} + +static void +add_round_key(uint32_t *q, const uint32_t *sk) +{ + int i; + + for (i = 0; i < 8; i ++) { + q[i] ^= sk[i]; + } +} + +static void +inv_shift_rows(uint32_t *q) +{ + int i; + + for (i = 0; i < 8; i ++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x00003F00) << 2) | ((x & 0x0000C000) >> 6) + | ((x & 0x000F0000) << 4) | ((x & 0x00F00000) >> 4) + | ((x & 0x03000000) << 6) | ((x & 0xFC000000) >> 2); + } +} + +static inline uint32_t +rotr16(uint32_t x) +{ + return (x << 16) | (x >> 16); +} + +static void +inv_mix_columns(uint32_t *q) +{ + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr16(q0 ^ q5 ^ q6 ^ r0 ^ r5); + q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6); + q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr16(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7); + q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr16(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7); + q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6); + q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7); + q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr16(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7); + q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr16(q4 ^ q5 ^ q7 ^ r4 ^ r7); +} + +/* see inner.h */ +void +br_aes_ct_bitslice_decrypt(unsigned num_rounds, + const uint32_t *skey, uint32_t *q) +{ + unsigned u; + + add_round_key(q, skey + (num_rounds << 3)); + for (u = num_rounds - 1; u > 0; u --) { + inv_shift_rows(q); + br_aes_ct_bitslice_invSbox(q); + add_round_key(q, skey + (u << 3)); + inv_mix_columns(q); + } + inv_shift_rows(q); + br_aes_ct_bitslice_invSbox(q); + add_round_key(q, skey); +} diff --git a/src/bearssl/src/symcipher/aes_ct_enc.c b/src/bearssl/src/symcipher/aes_ct_enc.c new file mode 100644 index 0000000..089bf35 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_ct_enc.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static inline void +add_round_key(uint32_t *q, const uint32_t *sk) +{ + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void +shift_rows(uint32_t *q) +{ + int i; + + for (i = 0; i < 8; i ++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t +rotr16(uint32_t x) +{ + return (x << 16) | (x >> 16); +} + +static inline void +mix_columns(uint32_t *q) +{ + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +/* see inner.h */ +void +br_aes_ct_bitslice_encrypt(unsigned num_rounds, + const uint32_t *skey, uint32_t *q) +{ + unsigned u; + + add_round_key(q, skey); + for (u = 1; u < num_rounds; u ++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, skey + (u << 3)); + } + br_aes_ct_bitslice_Sbox(q); + shift_rows(q); + add_round_key(q, skey + (num_rounds << 3)); +} diff --git a/src/bearssl/src/symcipher/aes_pwr8.c b/src/bearssl/src/symcipher/aes_pwr8.c new file mode 100644 index 0000000..b2c63c3 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_pwr8.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_POWER_ASM_MACROS 1 +#include "inner.h" + +/* + * This code contains the AES key schedule implementation using the + * POWER8 opcodes. + */ + +#if BR_POWER8 + +static void +key_schedule_128(unsigned char *sk, const unsigned char *key) +{ + long cc; + + static const uint32_t fmod[] = { 0x11B, 0x11B, 0x11B, 0x11B }; +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc = 0; + + /* + * We use the VSX instructions for loading and storing the + * key/subkeys, since they support unaligned accesses. The rest + * of the computation is VMX only. VMX register 0 is VSX + * register 32. + */ + asm volatile ( + + /* + * v0 = all-zero word + * v1 = constant -8 / +8, copied into four words + * v2 = current subkey + * v3 = Rcon (x4 words) + * v6 = constant 8, copied into four words + * v7 = constant 0x11B, copied into four words + * v8 = constant for byteswapping words + */ + vspltisw(0, 0) +#if BR_POWER8_LE + vspltisw(1, -8) +#else + vspltisw(1, 8) +#endif + lxvw4x(34, 0, %[key]) + vspltisw(3, 1) + vspltisw(6, 8) + lxvw4x(39, 0, %[fmod]) +#if BR_POWER8_LE + lxvw4x(40, 0, %[idx2be]) +#endif + + /* + * First subkey is a copy of the key itself. + */ +#if BR_POWER8_LE + vperm(4, 2, 2, 8) + stxvw4x(36, 0, %[sk]) +#else + stxvw4x(34, 0, %[sk]) +#endif + + /* + * Loop must run 10 times. + */ + li(%[cc], 10) + mtctr(%[cc]) + label(loop) + /* Increment subkey address */ + addi(%[sk], %[sk], 16) + + /* Compute SubWord(RotWord(temp)) xor Rcon (into v4, splat) */ + vrlw(4, 2, 1) + vsbox(4, 4) +#if BR_POWER8_LE + vxor(4, 4, 3) +#else + vsldoi(5, 3, 0, 3) + vxor(4, 4, 5) +#endif + vspltw(4, 4, 3) + + /* XOR words for next subkey */ + vsldoi(5, 0, 2, 12) + vxor(2, 2, 5) + vsldoi(5, 0, 2, 12) + vxor(2, 2, 5) + vsldoi(5, 0, 2, 12) + vxor(2, 2, 5) + vxor(2, 2, 4) + + /* Store next subkey */ +#if BR_POWER8_LE + vperm(4, 2, 2, 8) + stxvw4x(36, 0, %[sk]) +#else + stxvw4x(34, 0, %[sk]) +#endif + + /* Update Rcon */ + vadduwm(3, 3, 3) + vsrw(4, 3, 6) + vsubuwm(4, 0, 4) + vand(4, 4, 7) + vxor(3, 3, 4) + + bdnz(loop) + +: [sk] "+b" (sk), [cc] "+b" (cc) +: [key] "b" (key), [fmod] "b" (fmod) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "ctr", "memory" + ); +} + +static void +key_schedule_192(unsigned char *sk, const unsigned char *key) +{ + long cc; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc = 0; + + /* + * We use the VSX instructions for loading and storing the + * key/subkeys, since they support unaligned accesses. The rest + * of the computation is VMX only. VMX register 0 is VSX + * register 32. + */ + asm volatile ( + + /* + * v0 = all-zero word + * v1 = constant -8 / +8, copied into four words + * v2, v3 = current subkey + * v5 = Rcon (x4 words) (already shifted on big-endian) + * v6 = constant 8, copied into four words + * v8 = constant for byteswapping words + * + * The left two words of v3 are ignored. + */ + vspltisw(0, 0) +#if BR_POWER8_LE + vspltisw(1, -8) +#else + vspltisw(1, 8) +#endif + li(%[cc], 8) + lxvw4x(34, 0, %[key]) + lxvw4x(35, %[cc], %[key]) + vsldoi(3, 3, 0, 8) + vspltisw(5, 1) +#if !BR_POWER8_LE + vsldoi(5, 5, 0, 3) +#endif + vspltisw(6, 8) +#if BR_POWER8_LE + lxvw4x(40, 0, %[idx2be]) +#endif + + /* + * Loop must run 8 times. Each iteration produces 256 + * bits of subkeys, with a 64-bit overlap. + */ + li(%[cc], 8) + mtctr(%[cc]) + li(%[cc], 16) + label(loop) + + /* + * Last 6 words in v2:v3l. Compute next 6 words into + * v3r:v4. + */ + vrlw(10, 3, 1) + vsbox(10, 10) + vxor(10, 10, 5) + vspltw(10, 10, 1) + vsldoi(11, 0, 10, 8) + + vsldoi(12, 0, 2, 12) + vxor(12, 2, 12) + vsldoi(13, 0, 12, 12) + vxor(12, 12, 13) + vsldoi(13, 0, 12, 12) + vxor(12, 12, 13) + + vspltw(13, 12, 3) + vxor(13, 13, 3) + vsldoi(14, 0, 3, 12) + vxor(13, 13, 14) + + vsldoi(4, 12, 13, 8) + vsldoi(14, 0, 3, 8) + vsldoi(3, 14, 12, 8) + + vxor(3, 3, 11) + vxor(4, 4, 10) + + /* + * Update Rcon. Since for a 192-bit key, we use only 8 + * such constants, we will not hit the field modulus, + * so a simple shift (addition) works well. + */ + vadduwm(5, 5, 5) + + /* + * Write out the two left 128-bit words + */ +#if BR_POWER8_LE + vperm(10, 2, 2, 8) + vperm(11, 3, 3, 8) + stxvw4x(42, 0, %[sk]) + stxvw4x(43, %[cc], %[sk]) +#else + stxvw4x(34, 0, %[sk]) + stxvw4x(35, %[cc], %[sk]) +#endif + addi(%[sk], %[sk], 24) + + /* + * Shift words for next iteration. + */ + vsldoi(2, 3, 4, 8) + vsldoi(3, 4, 0, 8) + + bdnz(loop) + + /* + * The loop wrote the first 50 subkey words, but we need + * to produce 52, so we must do one last write. + */ +#if BR_POWER8_LE + vperm(10, 2, 2, 8) + stxvw4x(42, 0, %[sk]) +#else + stxvw4x(34, 0, %[sk]) +#endif + +: [sk] "+b" (sk), [cc] "+b" (cc) +: [key] "b" (key) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "ctr", "memory" + ); +} + +static void +key_schedule_256(unsigned char *sk, const unsigned char *key) +{ + long cc; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc = 0; + + /* + * We use the VSX instructions for loading and storing the + * key/subkeys, since they support unaligned accesses. The rest + * of the computation is VMX only. VMX register 0 is VSX + * register 32. + */ + asm volatile ( + + /* + * v0 = all-zero word + * v1 = constant -8 / +8, copied into four words + * v2, v3 = current subkey + * v6 = Rcon (x4 words) (already shifted on big-endian) + * v7 = constant 8, copied into four words + * v8 = constant for byteswapping words + * + * The left two words of v3 are ignored. + */ + vspltisw(0, 0) +#if BR_POWER8_LE + vspltisw(1, -8) +#else + vspltisw(1, 8) +#endif + li(%[cc], 16) + lxvw4x(34, 0, %[key]) + lxvw4x(35, %[cc], %[key]) + vspltisw(6, 1) +#if !BR_POWER8_LE + vsldoi(6, 6, 0, 3) +#endif + vspltisw(7, 8) +#if BR_POWER8_LE + lxvw4x(40, 0, %[idx2be]) +#endif + + /* + * Loop must run 7 times. Each iteration produces two + * subkeys. + */ + li(%[cc], 7) + mtctr(%[cc]) + li(%[cc], 16) + label(loop) + + /* + * Current words are in v2:v3. Compute next word in v4. + */ + vrlw(10, 3, 1) + vsbox(10, 10) + vxor(10, 10, 6) + vspltw(10, 10, 3) + + vsldoi(4, 0, 2, 12) + vxor(4, 2, 4) + vsldoi(5, 0, 4, 12) + vxor(4, 4, 5) + vsldoi(5, 0, 4, 12) + vxor(4, 4, 5) + vxor(4, 4, 10) + + /* + * Then other word in v5. + */ + vsbox(10, 4) + vspltw(10, 10, 3) + + vsldoi(5, 0, 3, 12) + vxor(5, 3, 5) + vsldoi(11, 0, 5, 12) + vxor(5, 5, 11) + vsldoi(11, 0, 5, 12) + vxor(5, 5, 11) + vxor(5, 5, 10) + + /* + * Update Rcon. Since for a 256-bit key, we use only 7 + * such constants, we will not hit the field modulus, + * so a simple shift (addition) works well. + */ + vadduwm(6, 6, 6) + + /* + * Write out the two left 128-bit words + */ +#if BR_POWER8_LE + vperm(10, 2, 2, 8) + vperm(11, 3, 3, 8) + stxvw4x(42, 0, %[sk]) + stxvw4x(43, %[cc], %[sk]) +#else + stxvw4x(34, 0, %[sk]) + stxvw4x(35, %[cc], %[sk]) +#endif + addi(%[sk], %[sk], 32) + + /* + * Replace v2:v3 with v4:v5. + */ + vxor(2, 0, 4) + vxor(3, 0, 5) + + bdnz(loop) + + /* + * The loop wrote the first 14 subkeys, but we need 15, + * so we must do an extra write. + */ +#if BR_POWER8_LE + vperm(10, 2, 2, 8) + stxvw4x(42, 0, %[sk]) +#else + stxvw4x(34, 0, %[sk]) +#endif + +: [sk] "+b" (sk), [cc] "+b" (cc) +: [key] "b" (key) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "ctr", "memory" + ); +} + +/* see inner.h */ +int +br_aes_pwr8_supported(void) +{ + return 1; +} + +/* see inner.h */ +unsigned +br_aes_pwr8_keysched(unsigned char *sk, const void *key, size_t len) +{ + switch (len) { + case 16: + key_schedule_128(sk, key); + return 10; + case 24: + key_schedule_192(sk, key); + return 12; + default: + key_schedule_256(sk, key); + return 14; + } +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_pwr8_cbcdec.c b/src/bearssl/src/symcipher/aes_pwr8_cbcdec.c new file mode 100644 index 0000000..e535ba6 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_pwr8_cbcdec.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_POWER_ASM_MACROS 1 +#include "inner.h" + +#if BR_POWER8 + +/* see bearssl_block.h */ +void +br_aes_pwr8_cbcdec_init(br_aes_pwr8_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_pwr8_cbcdec_vtable; + ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len); +} + +static void +cbcdec_128(const unsigned char *sk, + const unsigned char *iv, unsigned char *buf, size_t num_blocks) +{ + long cc0, cc1, cc2, cc3; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc0 = 0; + cc1 = 16; + cc2 = 32; + cc3 = 48; + asm volatile ( + + /* + * Load subkeys into v0..v10 + */ + lxvw4x(32, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(33, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(34, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(35, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(36, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(37, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(38, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(39, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(40, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(41, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(42, %[cc0], %[sk]) + li(%[cc0], 0) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * Load IV into v24. + */ + lxvw4x(56, 0, %[iv]) +#if BR_POWER8_LE + vperm(24, 24, 24, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Load next ciphertext words in v16..v19. Also save them + * in v20..v23. + */ + lxvw4x(48, %[cc0], %[buf]) + lxvw4x(49, %[cc1], %[buf]) + lxvw4x(50, %[cc2], %[buf]) + lxvw4x(51, %[cc3], %[buf]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + vand(20, 16, 16) + vand(21, 17, 17) + vand(22, 18, 18) + vand(23, 19, 19) + + /* + * Decrypt the blocks. + */ + vxor(16, 16, 10) + vxor(17, 17, 10) + vxor(18, 18, 10) + vxor(19, 19, 10) + vncipher(16, 16, 9) + vncipher(17, 17, 9) + vncipher(18, 18, 9) + vncipher(19, 19, 9) + vncipher(16, 16, 8) + vncipher(17, 17, 8) + vncipher(18, 18, 8) + vncipher(19, 19, 8) + vncipher(16, 16, 7) + vncipher(17, 17, 7) + vncipher(18, 18, 7) + vncipher(19, 19, 7) + vncipher(16, 16, 6) + vncipher(17, 17, 6) + vncipher(18, 18, 6) + vncipher(19, 19, 6) + vncipher(16, 16, 5) + vncipher(17, 17, 5) + vncipher(18, 18, 5) + vncipher(19, 19, 5) + vncipher(16, 16, 4) + vncipher(17, 17, 4) + vncipher(18, 18, 4) + vncipher(19, 19, 4) + vncipher(16, 16, 3) + vncipher(17, 17, 3) + vncipher(18, 18, 3) + vncipher(19, 19, 3) + vncipher(16, 16, 2) + vncipher(17, 17, 2) + vncipher(18, 18, 2) + vncipher(19, 19, 2) + vncipher(16, 16, 1) + vncipher(17, 17, 1) + vncipher(18, 18, 1) + vncipher(19, 19, 1) + vncipherlast(16, 16, 0) + vncipherlast(17, 17, 0) + vncipherlast(18, 18, 0) + vncipherlast(19, 19, 0) + + /* + * XOR decrypted blocks with IV / previous block. + */ + vxor(16, 16, 24) + vxor(17, 17, 20) + vxor(18, 18, 21) + vxor(19, 19, 22) + + /* + * Store back result (with byteswap) + */ +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + stxvw4x(48, %[cc0], %[buf]) + stxvw4x(49, %[cc1], %[buf]) + stxvw4x(50, %[cc2], %[buf]) + stxvw4x(51, %[cc3], %[buf]) + + /* + * Fourth encrypted block is IV for next run. + */ + vand(24, 23, 23) + + addi(%[buf], %[buf], 64) + + bdnz(loop) + +: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3), + [buf] "+b" (buf) +: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (num_blocks >> 2) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", + "ctr", "memory" + ); +} + +static void +cbcdec_192(const unsigned char *sk, + const unsigned char *iv, unsigned char *buf, size_t num_blocks) +{ + long cc0, cc1, cc2, cc3; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc0 = 0; + cc1 = 16; + cc2 = 32; + cc3 = 48; + asm volatile ( + + /* + * Load subkeys into v0..v12 + */ + lxvw4x(32, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(33, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(34, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(35, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(36, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(37, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(38, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(39, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(40, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(41, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(42, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(43, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(44, %[cc0], %[sk]) + li(%[cc0], 0) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * Load IV into v24. + */ + lxvw4x(56, 0, %[iv]) +#if BR_POWER8_LE + vperm(24, 24, 24, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Load next ciphertext words in v16..v19. Also save them + * in v20..v23. + */ + lxvw4x(48, %[cc0], %[buf]) + lxvw4x(49, %[cc1], %[buf]) + lxvw4x(50, %[cc2], %[buf]) + lxvw4x(51, %[cc3], %[buf]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + vand(20, 16, 16) + vand(21, 17, 17) + vand(22, 18, 18) + vand(23, 19, 19) + + /* + * Decrypt the blocks. + */ + vxor(16, 16, 12) + vxor(17, 17, 12) + vxor(18, 18, 12) + vxor(19, 19, 12) + vncipher(16, 16, 11) + vncipher(17, 17, 11) + vncipher(18, 18, 11) + vncipher(19, 19, 11) + vncipher(16, 16, 10) + vncipher(17, 17, 10) + vncipher(18, 18, 10) + vncipher(19, 19, 10) + vncipher(16, 16, 9) + vncipher(17, 17, 9) + vncipher(18, 18, 9) + vncipher(19, 19, 9) + vncipher(16, 16, 8) + vncipher(17, 17, 8) + vncipher(18, 18, 8) + vncipher(19, 19, 8) + vncipher(16, 16, 7) + vncipher(17, 17, 7) + vncipher(18, 18, 7) + vncipher(19, 19, 7) + vncipher(16, 16, 6) + vncipher(17, 17, 6) + vncipher(18, 18, 6) + vncipher(19, 19, 6) + vncipher(16, 16, 5) + vncipher(17, 17, 5) + vncipher(18, 18, 5) + vncipher(19, 19, 5) + vncipher(16, 16, 4) + vncipher(17, 17, 4) + vncipher(18, 18, 4) + vncipher(19, 19, 4) + vncipher(16, 16, 3) + vncipher(17, 17, 3) + vncipher(18, 18, 3) + vncipher(19, 19, 3) + vncipher(16, 16, 2) + vncipher(17, 17, 2) + vncipher(18, 18, 2) + vncipher(19, 19, 2) + vncipher(16, 16, 1) + vncipher(17, 17, 1) + vncipher(18, 18, 1) + vncipher(19, 19, 1) + vncipherlast(16, 16, 0) + vncipherlast(17, 17, 0) + vncipherlast(18, 18, 0) + vncipherlast(19, 19, 0) + + /* + * XOR decrypted blocks with IV / previous block. + */ + vxor(16, 16, 24) + vxor(17, 17, 20) + vxor(18, 18, 21) + vxor(19, 19, 22) + + /* + * Store back result (with byteswap) + */ +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + stxvw4x(48, %[cc0], %[buf]) + stxvw4x(49, %[cc1], %[buf]) + stxvw4x(50, %[cc2], %[buf]) + stxvw4x(51, %[cc3], %[buf]) + + /* + * Fourth encrypted block is IV for next run. + */ + vand(24, 23, 23) + + addi(%[buf], %[buf], 64) + + bdnz(loop) + +: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3), + [buf] "+b" (buf) +: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (num_blocks >> 2) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", + "ctr", "memory" + ); +} + +static void +cbcdec_256(const unsigned char *sk, + const unsigned char *iv, unsigned char *buf, size_t num_blocks) +{ + long cc0, cc1, cc2, cc3; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc0 = 0; + cc1 = 16; + cc2 = 32; + cc3 = 48; + asm volatile ( + + /* + * Load subkeys into v0..v14 + */ + lxvw4x(32, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(33, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(34, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(35, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(36, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(37, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(38, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(39, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(40, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(41, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(42, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(43, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(44, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(45, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(46, %[cc0], %[sk]) + li(%[cc0], 0) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * Load IV into v24. + */ + lxvw4x(56, 0, %[iv]) +#if BR_POWER8_LE + vperm(24, 24, 24, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Load next ciphertext words in v16..v19. Also save them + * in v20..v23. + */ + lxvw4x(48, %[cc0], %[buf]) + lxvw4x(49, %[cc1], %[buf]) + lxvw4x(50, %[cc2], %[buf]) + lxvw4x(51, %[cc3], %[buf]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + vand(20, 16, 16) + vand(21, 17, 17) + vand(22, 18, 18) + vand(23, 19, 19) + + /* + * Decrypt the blocks. + */ + vxor(16, 16, 14) + vxor(17, 17, 14) + vxor(18, 18, 14) + vxor(19, 19, 14) + vncipher(16, 16, 13) + vncipher(17, 17, 13) + vncipher(18, 18, 13) + vncipher(19, 19, 13) + vncipher(16, 16, 12) + vncipher(17, 17, 12) + vncipher(18, 18, 12) + vncipher(19, 19, 12) + vncipher(16, 16, 11) + vncipher(17, 17, 11) + vncipher(18, 18, 11) + vncipher(19, 19, 11) + vncipher(16, 16, 10) + vncipher(17, 17, 10) + vncipher(18, 18, 10) + vncipher(19, 19, 10) + vncipher(16, 16, 9) + vncipher(17, 17, 9) + vncipher(18, 18, 9) + vncipher(19, 19, 9) + vncipher(16, 16, 8) + vncipher(17, 17, 8) + vncipher(18, 18, 8) + vncipher(19, 19, 8) + vncipher(16, 16, 7) + vncipher(17, 17, 7) + vncipher(18, 18, 7) + vncipher(19, 19, 7) + vncipher(16, 16, 6) + vncipher(17, 17, 6) + vncipher(18, 18, 6) + vncipher(19, 19, 6) + vncipher(16, 16, 5) + vncipher(17, 17, 5) + vncipher(18, 18, 5) + vncipher(19, 19, 5) + vncipher(16, 16, 4) + vncipher(17, 17, 4) + vncipher(18, 18, 4) + vncipher(19, 19, 4) + vncipher(16, 16, 3) + vncipher(17, 17, 3) + vncipher(18, 18, 3) + vncipher(19, 19, 3) + vncipher(16, 16, 2) + vncipher(17, 17, 2) + vncipher(18, 18, 2) + vncipher(19, 19, 2) + vncipher(16, 16, 1) + vncipher(17, 17, 1) + vncipher(18, 18, 1) + vncipher(19, 19, 1) + vncipherlast(16, 16, 0) + vncipherlast(17, 17, 0) + vncipherlast(18, 18, 0) + vncipherlast(19, 19, 0) + + /* + * XOR decrypted blocks with IV / previous block. + */ + vxor(16, 16, 24) + vxor(17, 17, 20) + vxor(18, 18, 21) + vxor(19, 19, 22) + + /* + * Store back result (with byteswap) + */ +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + stxvw4x(48, %[cc0], %[buf]) + stxvw4x(49, %[cc1], %[buf]) + stxvw4x(50, %[cc2], %[buf]) + stxvw4x(51, %[cc3], %[buf]) + + /* + * Fourth encrypted block is IV for next run. + */ + vand(24, 23, 23) + + addi(%[buf], %[buf], 64) + + bdnz(loop) + +: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3), + [buf] "+b" (buf) +: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (num_blocks >> 2) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", + "ctr", "memory" + ); +} + +/* see bearssl_block.h */ +void +br_aes_pwr8_cbcdec_run(const br_aes_pwr8_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char nextiv[16]; + unsigned char *buf; + + if (len == 0) { + return; + } + buf = data; + memcpy(nextiv, buf + len - 16, 16); + if (len >= 64) { + size_t num_blocks; + unsigned char tmp[16]; + + num_blocks = (len >> 4) & ~(size_t)3; + memcpy(tmp, buf + (num_blocks << 4) - 16, 16); + switch (ctx->num_rounds) { + case 10: + cbcdec_128(ctx->skey.skni, iv, buf, num_blocks); + break; + case 12: + cbcdec_192(ctx->skey.skni, iv, buf, num_blocks); + break; + default: + cbcdec_256(ctx->skey.skni, iv, buf, num_blocks); + break; + } + buf += num_blocks << 4; + len &= 63; + memcpy(iv, tmp, 16); + } + if (len > 0) { + unsigned char tmp[64]; + + memcpy(tmp, buf, len); + memset(tmp + len, 0, (sizeof tmp) - len); + switch (ctx->num_rounds) { + case 10: + cbcdec_128(ctx->skey.skni, iv, tmp, 4); + break; + case 12: + cbcdec_192(ctx->skey.skni, iv, tmp, 4); + break; + default: + cbcdec_256(ctx->skey.skni, iv, tmp, 4); + break; + } + memcpy(buf, tmp, len); + } + memcpy(iv, nextiv, 16); +} + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_aes_pwr8_cbcdec_vtable = { + sizeof(br_aes_pwr8_cbcdec_keys), + 16, + 4, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_aes_pwr8_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_aes_pwr8_cbcdec_run +}; + +/* see bearssl_block.h */ +const br_block_cbcdec_class * +br_aes_pwr8_cbcdec_get_vtable(void) +{ + return br_aes_pwr8_supported() ? &br_aes_pwr8_cbcdec_vtable : NULL; +} + +#else + +/* see bearssl_block.h */ +const br_block_cbcdec_class * +br_aes_pwr8_cbcdec_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_pwr8_cbcenc.c b/src/bearssl/src/symcipher/aes_pwr8_cbcenc.c new file mode 100644 index 0000000..00f8eca --- /dev/null +++ b/src/bearssl/src/symcipher/aes_pwr8_cbcenc.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_POWER_ASM_MACROS 1 +#include "inner.h" + +#if BR_POWER8 + +/* see bearssl_block.h */ +void +br_aes_pwr8_cbcenc_init(br_aes_pwr8_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_pwr8_cbcenc_vtable; + ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len); +} + +static void +cbcenc_128(const unsigned char *sk, + const unsigned char *iv, unsigned char *buf, size_t len) +{ + long cc; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc = 0; + asm volatile ( + + /* + * Load subkeys into v0..v10 + */ + lxvw4x(32, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(33, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(34, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(35, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(36, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(37, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(38, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(39, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(40, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(41, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(42, %[cc], %[sk]) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * Load IV into v16. + */ + lxvw4x(48, 0, %[iv]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Load next plaintext word and XOR with current IV. + */ + lxvw4x(49, 0, %[buf]) +#if BR_POWER8_LE + vperm(17, 17, 17, 15) +#endif + vxor(16, 16, 17) + + /* + * Encrypt the block. + */ + vxor(16, 16, 0) + vcipher(16, 16, 1) + vcipher(16, 16, 2) + vcipher(16, 16, 3) + vcipher(16, 16, 4) + vcipher(16, 16, 5) + vcipher(16, 16, 6) + vcipher(16, 16, 7) + vcipher(16, 16, 8) + vcipher(16, 16, 9) + vcipherlast(16, 16, 10) + + /* + * Store back result (with byteswap) + */ +#if BR_POWER8_LE + vperm(17, 16, 16, 15) + stxvw4x(49, 0, %[buf]) +#else + stxvw4x(48, 0, %[buf]) +#endif + addi(%[buf], %[buf], 16) + + bdnz(loop) + +: [cc] "+b" (cc), [buf] "+b" (buf) +: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (len >> 4) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "ctr", "memory" + ); +} + +static void +cbcenc_192(const unsigned char *sk, + const unsigned char *iv, unsigned char *buf, size_t len) +{ + long cc; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc = 0; + asm volatile ( + + /* + * Load subkeys into v0..v12 + */ + lxvw4x(32, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(33, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(34, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(35, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(36, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(37, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(38, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(39, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(40, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(41, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(42, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(43, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(44, %[cc], %[sk]) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * Load IV into v16. + */ + lxvw4x(48, 0, %[iv]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Load next plaintext word and XOR with current IV. + */ + lxvw4x(49, 0, %[buf]) +#if BR_POWER8_LE + vperm(17, 17, 17, 15) +#endif + vxor(16, 16, 17) + + /* + * Encrypt the block. + */ + vxor(16, 16, 0) + vcipher(16, 16, 1) + vcipher(16, 16, 2) + vcipher(16, 16, 3) + vcipher(16, 16, 4) + vcipher(16, 16, 5) + vcipher(16, 16, 6) + vcipher(16, 16, 7) + vcipher(16, 16, 8) + vcipher(16, 16, 9) + vcipher(16, 16, 10) + vcipher(16, 16, 11) + vcipherlast(16, 16, 12) + + /* + * Store back result (with byteswap) + */ +#if BR_POWER8_LE + vperm(17, 16, 16, 15) + stxvw4x(49, 0, %[buf]) +#else + stxvw4x(48, 0, %[buf]) +#endif + addi(%[buf], %[buf], 16) + + bdnz(loop) + +: [cc] "+b" (cc), [buf] "+b" (buf) +: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (len >> 4) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "ctr", "memory" + ); +} + +static void +cbcenc_256(const unsigned char *sk, + const unsigned char *iv, unsigned char *buf, size_t len) +{ + long cc; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + + cc = 0; + asm volatile ( + + /* + * Load subkeys into v0..v14 + */ + lxvw4x(32, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(33, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(34, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(35, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(36, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(37, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(38, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(39, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(40, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(41, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(42, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(43, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(44, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(45, %[cc], %[sk]) + addi(%[cc], %[cc], 16) + lxvw4x(46, %[cc], %[sk]) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * Load IV into v16. + */ + lxvw4x(48, 0, %[iv]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Load next plaintext word and XOR with current IV. + */ + lxvw4x(49, 0, %[buf]) +#if BR_POWER8_LE + vperm(17, 17, 17, 15) +#endif + vxor(16, 16, 17) + + /* + * Encrypt the block. + */ + vxor(16, 16, 0) + vcipher(16, 16, 1) + vcipher(16, 16, 2) + vcipher(16, 16, 3) + vcipher(16, 16, 4) + vcipher(16, 16, 5) + vcipher(16, 16, 6) + vcipher(16, 16, 7) + vcipher(16, 16, 8) + vcipher(16, 16, 9) + vcipher(16, 16, 10) + vcipher(16, 16, 11) + vcipher(16, 16, 12) + vcipher(16, 16, 13) + vcipherlast(16, 16, 14) + + /* + * Store back result (with byteswap) + */ +#if BR_POWER8_LE + vperm(17, 16, 16, 15) + stxvw4x(49, 0, %[buf]) +#else + stxvw4x(48, 0, %[buf]) +#endif + addi(%[buf], %[buf], 16) + + bdnz(loop) + +: [cc] "+b" (cc), [buf] "+b" (buf) +: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (len >> 4) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "ctr", "memory" + ); +} + +/* see bearssl_block.h */ +void +br_aes_pwr8_cbcenc_run(const br_aes_pwr8_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + if (len > 0) { + switch (ctx->num_rounds) { + case 10: + cbcenc_128(ctx->skey.skni, iv, data, len); + break; + case 12: + cbcenc_192(ctx->skey.skni, iv, data, len); + break; + default: + cbcenc_256(ctx->skey.skni, iv, data, len); + break; + } + memcpy(iv, (unsigned char *)data + (len - 16), 16); + } +} + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_aes_pwr8_cbcenc_vtable = { + sizeof(br_aes_pwr8_cbcenc_keys), + 16, + 4, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_aes_pwr8_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_aes_pwr8_cbcenc_run +}; + +/* see bearssl_block.h */ +const br_block_cbcenc_class * +br_aes_pwr8_cbcenc_get_vtable(void) +{ + return br_aes_pwr8_supported() ? &br_aes_pwr8_cbcenc_vtable : NULL; +} + +#else + +/* see bearssl_block.h */ +const br_block_cbcenc_class * +br_aes_pwr8_cbcenc_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_pwr8_ctr.c b/src/bearssl/src/symcipher/aes_pwr8_ctr.c new file mode 100644 index 0000000..f5d20c0 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_pwr8_ctr.c @@ -0,0 +1,717 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_POWER_ASM_MACROS 1 +#include "inner.h" + +#if BR_POWER8 + +/* see bearssl_block.h */ +void +br_aes_pwr8_ctr_init(br_aes_pwr8_ctr_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_pwr8_ctr_vtable; + ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len); +} + +static void +ctr_128(const unsigned char *sk, const unsigned char *ivbuf, + unsigned char *buf, size_t num_blocks) +{ + long cc0, cc1, cc2, cc3; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + static const uint32_t ctrinc[] = { + 0, 0, 0, 4 + }; + + cc0 = 0; + cc1 = 16; + cc2 = 32; + cc3 = 48; + asm volatile ( + + /* + * Load subkeys into v0..v10 + */ + lxvw4x(32, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(33, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(34, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(35, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(36, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(37, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(38, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(39, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(40, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(41, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(42, %[cc0], %[sk]) + li(%[cc0], 0) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * v28 = increment for IV counter. + */ + lxvw4x(60, 0, %[ctrinc]) + + /* + * Load IV into v16..v19 + */ + lxvw4x(48, %[cc0], %[ivbuf]) + lxvw4x(49, %[cc1], %[ivbuf]) + lxvw4x(50, %[cc2], %[ivbuf]) + lxvw4x(51, %[cc3], %[ivbuf]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Compute next IV into v24..v27 + */ + vadduwm(24, 16, 28) + vadduwm(25, 17, 28) + vadduwm(26, 18, 28) + vadduwm(27, 19, 28) + + /* + * Load next data blocks. We do this early on but we + * won't need them until IV encryption is done. + */ + lxvw4x(52, %[cc0], %[buf]) + lxvw4x(53, %[cc1], %[buf]) + lxvw4x(54, %[cc2], %[buf]) + lxvw4x(55, %[cc3], %[buf]) + + /* + * Encrypt the current IV. + */ + vxor(16, 16, 0) + vxor(17, 17, 0) + vxor(18, 18, 0) + vxor(19, 19, 0) + vcipher(16, 16, 1) + vcipher(17, 17, 1) + vcipher(18, 18, 1) + vcipher(19, 19, 1) + vcipher(16, 16, 2) + vcipher(17, 17, 2) + vcipher(18, 18, 2) + vcipher(19, 19, 2) + vcipher(16, 16, 3) + vcipher(17, 17, 3) + vcipher(18, 18, 3) + vcipher(19, 19, 3) + vcipher(16, 16, 4) + vcipher(17, 17, 4) + vcipher(18, 18, 4) + vcipher(19, 19, 4) + vcipher(16, 16, 5) + vcipher(17, 17, 5) + vcipher(18, 18, 5) + vcipher(19, 19, 5) + vcipher(16, 16, 6) + vcipher(17, 17, 6) + vcipher(18, 18, 6) + vcipher(19, 19, 6) + vcipher(16, 16, 7) + vcipher(17, 17, 7) + vcipher(18, 18, 7) + vcipher(19, 19, 7) + vcipher(16, 16, 8) + vcipher(17, 17, 8) + vcipher(18, 18, 8) + vcipher(19, 19, 8) + vcipher(16, 16, 9) + vcipher(17, 17, 9) + vcipher(18, 18, 9) + vcipher(19, 19, 9) + vcipherlast(16, 16, 10) + vcipherlast(17, 17, 10) + vcipherlast(18, 18, 10) + vcipherlast(19, 19, 10) + +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + + /* + * Load next plaintext word and XOR with encrypted IV. + */ + vxor(16, 20, 16) + vxor(17, 21, 17) + vxor(18, 22, 18) + vxor(19, 23, 19) + stxvw4x(48, %[cc0], %[buf]) + stxvw4x(49, %[cc1], %[buf]) + stxvw4x(50, %[cc2], %[buf]) + stxvw4x(51, %[cc3], %[buf]) + + addi(%[buf], %[buf], 64) + + /* + * Update IV. + */ + vand(16, 24, 24) + vand(17, 25, 25) + vand(18, 26, 26) + vand(19, 27, 27) + + bdnz(loop) + +: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3), + [buf] "+b" (buf) +: [sk] "b" (sk), [ivbuf] "b" (ivbuf), [num_blocks] "b" (num_blocks >> 2), + [ctrinc] "b" (ctrinc) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", + "ctr", "memory" + ); +} + +static void +ctr_192(const unsigned char *sk, const unsigned char *ivbuf, + unsigned char *buf, size_t num_blocks) +{ + long cc0, cc1, cc2, cc3; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + static const uint32_t ctrinc[] = { + 0, 0, 0, 4 + }; + + cc0 = 0; + cc1 = 16; + cc2 = 32; + cc3 = 48; + asm volatile ( + + /* + * Load subkeys into v0..v12 + */ + lxvw4x(32, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(33, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(34, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(35, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(36, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(37, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(38, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(39, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(40, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(41, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(42, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(43, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(44, %[cc0], %[sk]) + li(%[cc0], 0) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * v28 = increment for IV counter. + */ + lxvw4x(60, 0, %[ctrinc]) + + /* + * Load IV into v16..v19 + */ + lxvw4x(48, %[cc0], %[ivbuf]) + lxvw4x(49, %[cc1], %[ivbuf]) + lxvw4x(50, %[cc2], %[ivbuf]) + lxvw4x(51, %[cc3], %[ivbuf]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Compute next IV into v24..v27 + */ + vadduwm(24, 16, 28) + vadduwm(25, 17, 28) + vadduwm(26, 18, 28) + vadduwm(27, 19, 28) + + /* + * Load next data blocks. We do this early on but we + * won't need them until IV encryption is done. + */ + lxvw4x(52, %[cc0], %[buf]) + lxvw4x(53, %[cc1], %[buf]) + lxvw4x(54, %[cc2], %[buf]) + lxvw4x(55, %[cc3], %[buf]) + + /* + * Encrypt the current IV. + */ + vxor(16, 16, 0) + vxor(17, 17, 0) + vxor(18, 18, 0) + vxor(19, 19, 0) + vcipher(16, 16, 1) + vcipher(17, 17, 1) + vcipher(18, 18, 1) + vcipher(19, 19, 1) + vcipher(16, 16, 2) + vcipher(17, 17, 2) + vcipher(18, 18, 2) + vcipher(19, 19, 2) + vcipher(16, 16, 3) + vcipher(17, 17, 3) + vcipher(18, 18, 3) + vcipher(19, 19, 3) + vcipher(16, 16, 4) + vcipher(17, 17, 4) + vcipher(18, 18, 4) + vcipher(19, 19, 4) + vcipher(16, 16, 5) + vcipher(17, 17, 5) + vcipher(18, 18, 5) + vcipher(19, 19, 5) + vcipher(16, 16, 6) + vcipher(17, 17, 6) + vcipher(18, 18, 6) + vcipher(19, 19, 6) + vcipher(16, 16, 7) + vcipher(17, 17, 7) + vcipher(18, 18, 7) + vcipher(19, 19, 7) + vcipher(16, 16, 8) + vcipher(17, 17, 8) + vcipher(18, 18, 8) + vcipher(19, 19, 8) + vcipher(16, 16, 9) + vcipher(17, 17, 9) + vcipher(18, 18, 9) + vcipher(19, 19, 9) + vcipher(16, 16, 10) + vcipher(17, 17, 10) + vcipher(18, 18, 10) + vcipher(19, 19, 10) + vcipher(16, 16, 11) + vcipher(17, 17, 11) + vcipher(18, 18, 11) + vcipher(19, 19, 11) + vcipherlast(16, 16, 12) + vcipherlast(17, 17, 12) + vcipherlast(18, 18, 12) + vcipherlast(19, 19, 12) + +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + + /* + * Load next plaintext word and XOR with encrypted IV. + */ + vxor(16, 20, 16) + vxor(17, 21, 17) + vxor(18, 22, 18) + vxor(19, 23, 19) + stxvw4x(48, %[cc0], %[buf]) + stxvw4x(49, %[cc1], %[buf]) + stxvw4x(50, %[cc2], %[buf]) + stxvw4x(51, %[cc3], %[buf]) + + addi(%[buf], %[buf], 64) + + /* + * Update IV. + */ + vand(16, 24, 24) + vand(17, 25, 25) + vand(18, 26, 26) + vand(19, 27, 27) + + bdnz(loop) + +: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3), + [buf] "+b" (buf) +: [sk] "b" (sk), [ivbuf] "b" (ivbuf), [num_blocks] "b" (num_blocks >> 2), + [ctrinc] "b" (ctrinc) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", + "ctr", "memory" + ); +} + +static void +ctr_256(const unsigned char *sk, const unsigned char *ivbuf, + unsigned char *buf, size_t num_blocks) +{ + long cc0, cc1, cc2, cc3; + +#if BR_POWER8_LE + static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C + }; +#endif + static const uint32_t ctrinc[] = { + 0, 0, 0, 4 + }; + + cc0 = 0; + cc1 = 16; + cc2 = 32; + cc3 = 48; + asm volatile ( + + /* + * Load subkeys into v0..v14 + */ + lxvw4x(32, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(33, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(34, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(35, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(36, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(37, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(38, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(39, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(40, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(41, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(42, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(43, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(44, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(45, %[cc0], %[sk]) + addi(%[cc0], %[cc0], 16) + lxvw4x(46, %[cc0], %[sk]) + li(%[cc0], 0) + +#if BR_POWER8_LE + /* + * v15 = constant for byteswapping words + */ + lxvw4x(47, 0, %[idx2be]) +#endif + /* + * v28 = increment for IV counter. + */ + lxvw4x(60, 0, %[ctrinc]) + + /* + * Load IV into v16..v19 + */ + lxvw4x(48, %[cc0], %[ivbuf]) + lxvw4x(49, %[cc1], %[ivbuf]) + lxvw4x(50, %[cc2], %[ivbuf]) + lxvw4x(51, %[cc3], %[ivbuf]) +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + + mtctr(%[num_blocks]) + label(loop) + /* + * Compute next IV into v24..v27 + */ + vadduwm(24, 16, 28) + vadduwm(25, 17, 28) + vadduwm(26, 18, 28) + vadduwm(27, 19, 28) + + /* + * Load next data blocks. We do this early on but we + * won't need them until IV encryption is done. + */ + lxvw4x(52, %[cc0], %[buf]) + lxvw4x(53, %[cc1], %[buf]) + lxvw4x(54, %[cc2], %[buf]) + lxvw4x(55, %[cc3], %[buf]) + + /* + * Encrypt the current IV. + */ + vxor(16, 16, 0) + vxor(17, 17, 0) + vxor(18, 18, 0) + vxor(19, 19, 0) + vcipher(16, 16, 1) + vcipher(17, 17, 1) + vcipher(18, 18, 1) + vcipher(19, 19, 1) + vcipher(16, 16, 2) + vcipher(17, 17, 2) + vcipher(18, 18, 2) + vcipher(19, 19, 2) + vcipher(16, 16, 3) + vcipher(17, 17, 3) + vcipher(18, 18, 3) + vcipher(19, 19, 3) + vcipher(16, 16, 4) + vcipher(17, 17, 4) + vcipher(18, 18, 4) + vcipher(19, 19, 4) + vcipher(16, 16, 5) + vcipher(17, 17, 5) + vcipher(18, 18, 5) + vcipher(19, 19, 5) + vcipher(16, 16, 6) + vcipher(17, 17, 6) + vcipher(18, 18, 6) + vcipher(19, 19, 6) + vcipher(16, 16, 7) + vcipher(17, 17, 7) + vcipher(18, 18, 7) + vcipher(19, 19, 7) + vcipher(16, 16, 8) + vcipher(17, 17, 8) + vcipher(18, 18, 8) + vcipher(19, 19, 8) + vcipher(16, 16, 9) + vcipher(17, 17, 9) + vcipher(18, 18, 9) + vcipher(19, 19, 9) + vcipher(16, 16, 10) + vcipher(17, 17, 10) + vcipher(18, 18, 10) + vcipher(19, 19, 10) + vcipher(16, 16, 11) + vcipher(17, 17, 11) + vcipher(18, 18, 11) + vcipher(19, 19, 11) + vcipher(16, 16, 12) + vcipher(17, 17, 12) + vcipher(18, 18, 12) + vcipher(19, 19, 12) + vcipher(16, 16, 13) + vcipher(17, 17, 13) + vcipher(18, 18, 13) + vcipher(19, 19, 13) + vcipherlast(16, 16, 14) + vcipherlast(17, 17, 14) + vcipherlast(18, 18, 14) + vcipherlast(19, 19, 14) + +#if BR_POWER8_LE + vperm(16, 16, 16, 15) + vperm(17, 17, 17, 15) + vperm(18, 18, 18, 15) + vperm(19, 19, 19, 15) +#endif + + /* + * Load next plaintext word and XOR with encrypted IV. + */ + vxor(16, 20, 16) + vxor(17, 21, 17) + vxor(18, 22, 18) + vxor(19, 23, 19) + stxvw4x(48, %[cc0], %[buf]) + stxvw4x(49, %[cc1], %[buf]) + stxvw4x(50, %[cc2], %[buf]) + stxvw4x(51, %[cc3], %[buf]) + + addi(%[buf], %[buf], 64) + + /* + * Update IV. + */ + vand(16, 24, 24) + vand(17, 25, 25) + vand(18, 26, 26) + vand(19, 27, 27) + + bdnz(loop) + +: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3), + [buf] "+b" (buf) +: [sk] "b" (sk), [ivbuf] "b" (ivbuf), [num_blocks] "b" (num_blocks >> 2), + [ctrinc] "b" (ctrinc) +#if BR_POWER8_LE + , [idx2be] "b" (idx2be) +#endif +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", + "ctr", "memory" + ); +} + +/* see bearssl_block.h */ +uint32_t +br_aes_pwr8_ctr_run(const br_aes_pwr8_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + unsigned char ivbuf[64]; + + buf = data; + memcpy(ivbuf + 0, iv, 12); + memcpy(ivbuf + 16, iv, 12); + memcpy(ivbuf + 32, iv, 12); + memcpy(ivbuf + 48, iv, 12); + if (len >= 64) { + br_enc32be(ivbuf + 12, cc + 0); + br_enc32be(ivbuf + 28, cc + 1); + br_enc32be(ivbuf + 44, cc + 2); + br_enc32be(ivbuf + 60, cc + 3); + switch (ctx->num_rounds) { + case 10: + ctr_128(ctx->skey.skni, ivbuf, buf, + (len >> 4) & ~(size_t)3); + break; + case 12: + ctr_192(ctx->skey.skni, ivbuf, buf, + (len >> 4) & ~(size_t)3); + break; + default: + ctr_256(ctx->skey.skni, ivbuf, buf, + (len >> 4) & ~(size_t)3); + break; + } + cc += (len >> 4) & ~(size_t)3; + buf += len & ~(size_t)63; + len &= 63; + } + if (len > 0) { + unsigned char tmp[64]; + + memcpy(tmp, buf, len); + memset(tmp + len, 0, (sizeof tmp) - len); + br_enc32be(ivbuf + 12, cc + 0); + br_enc32be(ivbuf + 28, cc + 1); + br_enc32be(ivbuf + 44, cc + 2); + br_enc32be(ivbuf + 60, cc + 3); + switch (ctx->num_rounds) { + case 10: + ctr_128(ctx->skey.skni, ivbuf, tmp, 4); + break; + case 12: + ctr_192(ctx->skey.skni, ivbuf, tmp, 4); + break; + default: + ctr_256(ctx->skey.skni, ivbuf, tmp, 4); + break; + } + memcpy(buf, tmp, len); + cc += (len + 15) >> 4; + } + return cc; +} + +/* see bearssl_block.h */ +const br_block_ctr_class br_aes_pwr8_ctr_vtable = { + sizeof(br_aes_pwr8_ctr_keys), + 16, + 4, + (void (*)(const br_block_ctr_class **, const void *, size_t)) + &br_aes_pwr8_ctr_init, + (uint32_t (*)(const br_block_ctr_class *const *, + const void *, uint32_t, void *, size_t)) + &br_aes_pwr8_ctr_run +}; + +/* see bearssl_block.h */ +const br_block_ctr_class * +br_aes_pwr8_ctr_get_vtable(void) +{ + return br_aes_pwr8_supported() ? &br_aes_pwr8_ctr_vtable : NULL; +} + +#else + +/* see bearssl_block.h */ +const br_block_ctr_class * +br_aes_pwr8_ctr_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_pwr8_ctrcbc.c b/src/bearssl/src/symcipher/aes_pwr8_ctrcbc.c new file mode 100644 index 0000000..a67d30b --- /dev/null +++ b/src/bearssl/src/symcipher/aes_pwr8_ctrcbc.c @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_POWER_ASM_MACROS 1 +#include "inner.h" + +#if BR_POWER8 + +/* see bearssl_block.h */ +const br_block_ctrcbc_class * +br_aes_pwr8_ctrcbc_get_vtable(void) +{ + return br_aes_pwr8_supported() ? &br_aes_pwr8_ctrcbc_vtable : NULL; +} + +/* see bearssl_block.h */ +void +br_aes_pwr8_ctrcbc_init(br_aes_pwr8_ctrcbc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_pwr8_ctrcbc_vtable; + ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len); +} + +/* + * Register conventions for CTR + CBC-MAC: + * + * AES subkeys are in registers 0 to 10/12/14 (depending on keys size) + * Register v15 contains the byteswap index register (little-endian only) + * Register v16 contains the CTR counter value + * Register v17 contains the CBC-MAC current value + * Registers v18 to v27 are scratch + * Counter increment uses v28, v29 and v30 + * + * For CTR alone: + * + * AES subkeys are in registers 0 to 10/12/14 (depending on keys size) + * Register v15 contains the byteswap index register (little-endian only) + * Registers v16 to v19 contain the CTR counter values (four blocks) + * Registers v20 to v27 are scratch + * Counter increment uses v28, v29 and v30 + */ + +#define LOAD_SUBKEYS_128 \ + lxvw4x(32, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(33, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(34, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(35, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(36, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(37, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(38, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(39, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(40, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(41, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(42, %[cc], %[sk]) + +#define LOAD_SUBKEYS_192 \ + LOAD_SUBKEYS_128 \ + addi(%[cc], %[cc], 16) \ + lxvw4x(43, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(44, %[cc], %[sk]) + +#define LOAD_SUBKEYS_256 \ + LOAD_SUBKEYS_192 \ + addi(%[cc], %[cc], 16) \ + lxvw4x(45, %[cc], %[sk]) \ + addi(%[cc], %[cc], 16) \ + lxvw4x(46, %[cc], %[sk]) + +#define BLOCK_ENCRYPT_128(x) \ + vxor(x, x, 0) \ + vcipher(x, x, 1) \ + vcipher(x, x, 2) \ + vcipher(x, x, 3) \ + vcipher(x, x, 4) \ + vcipher(x, x, 5) \ + vcipher(x, x, 6) \ + vcipher(x, x, 7) \ + vcipher(x, x, 8) \ + vcipher(x, x, 9) \ + vcipherlast(x, x, 10) + +#define BLOCK_ENCRYPT_192(x) \ + vxor(x, x, 0) \ + vcipher(x, x, 1) \ + vcipher(x, x, 2) \ + vcipher(x, x, 3) \ + vcipher(x, x, 4) \ + vcipher(x, x, 5) \ + vcipher(x, x, 6) \ + vcipher(x, x, 7) \ + vcipher(x, x, 8) \ + vcipher(x, x, 9) \ + vcipher(x, x, 10) \ + vcipher(x, x, 11) \ + vcipherlast(x, x, 12) + +#define BLOCK_ENCRYPT_256(x) \ + vxor(x, x, 0) \ + vcipher(x, x, 1) \ + vcipher(x, x, 2) \ + vcipher(x, x, 3) \ + vcipher(x, x, 4) \ + vcipher(x, x, 5) \ + vcipher(x, x, 6) \ + vcipher(x, x, 7) \ + vcipher(x, x, 8) \ + vcipher(x, x, 9) \ + vcipher(x, x, 10) \ + vcipher(x, x, 11) \ + vcipher(x, x, 12) \ + vcipher(x, x, 13) \ + vcipherlast(x, x, 14) + +#define BLOCK_ENCRYPT_X2_128(x, y) \ + vxor(x, x, 0) \ + vxor(y, y, 0) \ + vcipher(x, x, 1) \ + vcipher(y, y, 1) \ + vcipher(x, x, 2) \ + vcipher(y, y, 2) \ + vcipher(x, x, 3) \ + vcipher(y, y, 3) \ + vcipher(x, x, 4) \ + vcipher(y, y, 4) \ + vcipher(x, x, 5) \ + vcipher(y, y, 5) \ + vcipher(x, x, 6) \ + vcipher(y, y, 6) \ + vcipher(x, x, 7) \ + vcipher(y, y, 7) \ + vcipher(x, x, 8) \ + vcipher(y, y, 8) \ + vcipher(x, x, 9) \ + vcipher(y, y, 9) \ + vcipherlast(x, x, 10) \ + vcipherlast(y, y, 10) + +#define BLOCK_ENCRYPT_X2_192(x, y) \ + vxor(x, x, 0) \ + vxor(y, y, 0) \ + vcipher(x, x, 1) \ + vcipher(y, y, 1) \ + vcipher(x, x, 2) \ + vcipher(y, y, 2) \ + vcipher(x, x, 3) \ + vcipher(y, y, 3) \ + vcipher(x, x, 4) \ + vcipher(y, y, 4) \ + vcipher(x, x, 5) \ + vcipher(y, y, 5) \ + vcipher(x, x, 6) \ + vcipher(y, y, 6) \ + vcipher(x, x, 7) \ + vcipher(y, y, 7) \ + vcipher(x, x, 8) \ + vcipher(y, y, 8) \ + vcipher(x, x, 9) \ + vcipher(y, y, 9) \ + vcipher(x, x, 10) \ + vcipher(y, y, 10) \ + vcipher(x, x, 11) \ + vcipher(y, y, 11) \ + vcipherlast(x, x, 12) \ + vcipherlast(y, y, 12) + +#define BLOCK_ENCRYPT_X2_256(x, y) \ + vxor(x, x, 0) \ + vxor(y, y, 0) \ + vcipher(x, x, 1) \ + vcipher(y, y, 1) \ + vcipher(x, x, 2) \ + vcipher(y, y, 2) \ + vcipher(x, x, 3) \ + vcipher(y, y, 3) \ + vcipher(x, x, 4) \ + vcipher(y, y, 4) \ + vcipher(x, x, 5) \ + vcipher(y, y, 5) \ + vcipher(x, x, 6) \ + vcipher(y, y, 6) \ + vcipher(x, x, 7) \ + vcipher(y, y, 7) \ + vcipher(x, x, 8) \ + vcipher(y, y, 8) \ + vcipher(x, x, 9) \ + vcipher(y, y, 9) \ + vcipher(x, x, 10) \ + vcipher(y, y, 10) \ + vcipher(x, x, 11) \ + vcipher(y, y, 11) \ + vcipher(x, x, 12) \ + vcipher(y, y, 12) \ + vcipher(x, x, 13) \ + vcipher(y, y, 13) \ + vcipherlast(x, x, 14) \ + vcipherlast(y, y, 14) + +#define BLOCK_ENCRYPT_X4_128(x0, x1, x2, x3) \ + vxor(x0, x0, 0) \ + vxor(x1, x1, 0) \ + vxor(x2, x2, 0) \ + vxor(x3, x3, 0) \ + vcipher(x0, x0, 1) \ + vcipher(x1, x1, 1) \ + vcipher(x2, x2, 1) \ + vcipher(x3, x3, 1) \ + vcipher(x0, x0, 2) \ + vcipher(x1, x1, 2) \ + vcipher(x2, x2, 2) \ + vcipher(x3, x3, 2) \ + vcipher(x0, x0, 3) \ + vcipher(x1, x1, 3) \ + vcipher(x2, x2, 3) \ + vcipher(x3, x3, 3) \ + vcipher(x0, x0, 4) \ + vcipher(x1, x1, 4) \ + vcipher(x2, x2, 4) \ + vcipher(x3, x3, 4) \ + vcipher(x0, x0, 5) \ + vcipher(x1, x1, 5) \ + vcipher(x2, x2, 5) \ + vcipher(x3, x3, 5) \ + vcipher(x0, x0, 6) \ + vcipher(x1, x1, 6) \ + vcipher(x2, x2, 6) \ + vcipher(x3, x3, 6) \ + vcipher(x0, x0, 7) \ + vcipher(x1, x1, 7) \ + vcipher(x2, x2, 7) \ + vcipher(x3, x3, 7) \ + vcipher(x0, x0, 8) \ + vcipher(x1, x1, 8) \ + vcipher(x2, x2, 8) \ + vcipher(x3, x3, 8) \ + vcipher(x0, x0, 9) \ + vcipher(x1, x1, 9) \ + vcipher(x2, x2, 9) \ + vcipher(x3, x3, 9) \ + vcipherlast(x0, x0, 10) \ + vcipherlast(x1, x1, 10) \ + vcipherlast(x2, x2, 10) \ + vcipherlast(x3, x3, 10) + +#define BLOCK_ENCRYPT_X4_192(x0, x1, x2, x3) \ + vxor(x0, x0, 0) \ + vxor(x1, x1, 0) \ + vxor(x2, x2, 0) \ + vxor(x3, x3, 0) \ + vcipher(x0, x0, 1) \ + vcipher(x1, x1, 1) \ + vcipher(x2, x2, 1) \ + vcipher(x3, x3, 1) \ + vcipher(x0, x0, 2) \ + vcipher(x1, x1, 2) \ + vcipher(x2, x2, 2) \ + vcipher(x3, x3, 2) \ + vcipher(x0, x0, 3) \ + vcipher(x1, x1, 3) \ + vcipher(x2, x2, 3) \ + vcipher(x3, x3, 3) \ + vcipher(x0, x0, 4) \ + vcipher(x1, x1, 4) \ + vcipher(x2, x2, 4) \ + vcipher(x3, x3, 4) \ + vcipher(x0, x0, 5) \ + vcipher(x1, x1, 5) \ + vcipher(x2, x2, 5) \ + vcipher(x3, x3, 5) \ + vcipher(x0, x0, 6) \ + vcipher(x1, x1, 6) \ + vcipher(x2, x2, 6) \ + vcipher(x3, x3, 6) \ + vcipher(x0, x0, 7) \ + vcipher(x1, x1, 7) \ + vcipher(x2, x2, 7) \ + vcipher(x3, x3, 7) \ + vcipher(x0, x0, 8) \ + vcipher(x1, x1, 8) \ + vcipher(x2, x2, 8) \ + vcipher(x3, x3, 8) \ + vcipher(x0, x0, 9) \ + vcipher(x1, x1, 9) \ + vcipher(x2, x2, 9) \ + vcipher(x3, x3, 9) \ + vcipher(x0, x0, 10) \ + vcipher(x1, x1, 10) \ + vcipher(x2, x2, 10) \ + vcipher(x3, x3, 10) \ + vcipher(x0, x0, 11) \ + vcipher(x1, x1, 11) \ + vcipher(x2, x2, 11) \ + vcipher(x3, x3, 11) \ + vcipherlast(x0, x0, 12) \ + vcipherlast(x1, x1, 12) \ + vcipherlast(x2, x2, 12) \ + vcipherlast(x3, x3, 12) + +#define BLOCK_ENCRYPT_X4_256(x0, x1, x2, x3) \ + vxor(x0, x0, 0) \ + vxor(x1, x1, 0) \ + vxor(x2, x2, 0) \ + vxor(x3, x3, 0) \ + vcipher(x0, x0, 1) \ + vcipher(x1, x1, 1) \ + vcipher(x2, x2, 1) \ + vcipher(x3, x3, 1) \ + vcipher(x0, x0, 2) \ + vcipher(x1, x1, 2) \ + vcipher(x2, x2, 2) \ + vcipher(x3, x3, 2) \ + vcipher(x0, x0, 3) \ + vcipher(x1, x1, 3) \ + vcipher(x2, x2, 3) \ + vcipher(x3, x3, 3) \ + vcipher(x0, x0, 4) \ + vcipher(x1, x1, 4) \ + vcipher(x2, x2, 4) \ + vcipher(x3, x3, 4) \ + vcipher(x0, x0, 5) \ + vcipher(x1, x1, 5) \ + vcipher(x2, x2, 5) \ + vcipher(x3, x3, 5) \ + vcipher(x0, x0, 6) \ + vcipher(x1, x1, 6) \ + vcipher(x2, x2, 6) \ + vcipher(x3, x3, 6) \ + vcipher(x0, x0, 7) \ + vcipher(x1, x1, 7) \ + vcipher(x2, x2, 7) \ + vcipher(x3, x3, 7) \ + vcipher(x0, x0, 8) \ + vcipher(x1, x1, 8) \ + vcipher(x2, x2, 8) \ + vcipher(x3, x3, 8) \ + vcipher(x0, x0, 9) \ + vcipher(x1, x1, 9) \ + vcipher(x2, x2, 9) \ + vcipher(x3, x3, 9) \ + vcipher(x0, x0, 10) \ + vcipher(x1, x1, 10) \ + vcipher(x2, x2, 10) \ + vcipher(x3, x3, 10) \ + vcipher(x0, x0, 11) \ + vcipher(x1, x1, 11) \ + vcipher(x2, x2, 11) \ + vcipher(x3, x3, 11) \ + vcipher(x0, x0, 12) \ + vcipher(x1, x1, 12) \ + vcipher(x2, x2, 12) \ + vcipher(x3, x3, 12) \ + vcipher(x0, x0, 13) \ + vcipher(x1, x1, 13) \ + vcipher(x2, x2, 13) \ + vcipher(x3, x3, 13) \ + vcipherlast(x0, x0, 14) \ + vcipherlast(x1, x1, 14) \ + vcipherlast(x2, x2, 14) \ + vcipherlast(x3, x3, 14) + +#if BR_POWER8_LE +static const uint32_t idx2be[] = { + 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C +}; +#define BYTESWAP_INIT lxvw4x(47, 0, %[idx2be]) +#define BYTESWAP(x) vperm(x, x, x, 15) +#define BYTESWAPX(d, s) vperm(d, s, s, 15) +#define BYTESWAP_REG , [idx2be] "b" (idx2be) +#else +#define BYTESWAP_INIT +#define BYTESWAP(x) +#define BYTESWAPX(d, s) vand(d, s, s) +#define BYTESWAP_REG +#endif + +static const uint32_t ctrinc[] = { + 0, 0, 0, 1 +}; +static const uint32_t ctrinc_x4[] = { + 0, 0, 0, 4 +}; +#define INCR_128_INIT lxvw4x(60, 0, %[ctrinc]) +#define INCR_128_X4_INIT lxvw4x(60, 0, %[ctrinc_x4]) +#define INCR_128(d, s) \ + vaddcuw(29, s, 28) \ + vadduwm(d, s, 28) \ + vsldoi(30, 29, 29, 4) \ + vaddcuw(29, d, 30) \ + vadduwm(d, d, 30) \ + vsldoi(30, 29, 29, 4) \ + vaddcuw(29, d, 30) \ + vadduwm(d, d, 30) \ + vsldoi(30, 29, 29, 4) \ + vadduwm(d, d, 30) + +#define MKCTR(size) \ +static void \ +ctr_ ## size(const unsigned char *sk, \ + unsigned char *ctrbuf, unsigned char *buf, size_t num_blocks_x4) \ +{ \ + long cc, cc0, cc1, cc2, cc3; \ + \ + cc = 0; \ + cc0 = 0; \ + cc1 = 16; \ + cc2 = 32; \ + cc3 = 48; \ + asm volatile ( \ + \ + /* \ + * Load subkeys into v0..v10 \ + */ \ + LOAD_SUBKEYS_ ## size \ + li(%[cc], 0) \ + \ + BYTESWAP_INIT \ + INCR_128_X4_INIT \ + \ + /* \ + * Load current CTR counters into v16 to v19. \ + */ \ + lxvw4x(48, %[cc0], %[ctrbuf]) \ + lxvw4x(49, %[cc1], %[ctrbuf]) \ + lxvw4x(50, %[cc2], %[ctrbuf]) \ + lxvw4x(51, %[cc3], %[ctrbuf]) \ + BYTESWAP(16) \ + BYTESWAP(17) \ + BYTESWAP(18) \ + BYTESWAP(19) \ + \ + mtctr(%[num_blocks_x4]) \ + \ + label(loop) \ + /* \ + * Compute next counter values into v20..v23. \ + */ \ + INCR_128(20, 16) \ + INCR_128(21, 17) \ + INCR_128(22, 18) \ + INCR_128(23, 19) \ + \ + /* \ + * Encrypt counter values and XOR into next data blocks. \ + */ \ + lxvw4x(56, %[cc0], %[buf]) \ + lxvw4x(57, %[cc1], %[buf]) \ + lxvw4x(58, %[cc2], %[buf]) \ + lxvw4x(59, %[cc3], %[buf]) \ + BYTESWAP(24) \ + BYTESWAP(25) \ + BYTESWAP(26) \ + BYTESWAP(27) \ + BLOCK_ENCRYPT_X4_ ## size(16, 17, 18, 19) \ + vxor(16, 16, 24) \ + vxor(17, 17, 25) \ + vxor(18, 18, 26) \ + vxor(19, 19, 27) \ + BYTESWAP(16) \ + BYTESWAP(17) \ + BYTESWAP(18) \ + BYTESWAP(19) \ + stxvw4x(48, %[cc0], %[buf]) \ + stxvw4x(49, %[cc1], %[buf]) \ + stxvw4x(50, %[cc2], %[buf]) \ + stxvw4x(51, %[cc3], %[buf]) \ + \ + /* \ + * Update counters and data pointer. \ + */ \ + vand(16, 20, 20) \ + vand(17, 21, 21) \ + vand(18, 22, 22) \ + vand(19, 23, 23) \ + addi(%[buf], %[buf], 64) \ + \ + bdnz(loop) \ + \ + /* \ + * Write back new counter values. \ + */ \ + BYTESWAP(16) \ + BYTESWAP(17) \ + BYTESWAP(18) \ + BYTESWAP(19) \ + stxvw4x(48, %[cc0], %[ctrbuf]) \ + stxvw4x(49, %[cc1], %[ctrbuf]) \ + stxvw4x(50, %[cc2], %[ctrbuf]) \ + stxvw4x(51, %[cc3], %[ctrbuf]) \ + \ +: [cc] "+b" (cc), [buf] "+b" (buf), \ + [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3) \ +: [sk] "b" (sk), [ctrbuf] "b" (ctrbuf), \ + [num_blocks_x4] "b" (num_blocks_x4), [ctrinc_x4] "b" (ctrinc_x4) \ + BYTESWAP_REG \ +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \ + "v30", "ctr", "memory" \ + ); \ +} + +MKCTR(128) +MKCTR(192) +MKCTR(256) + +#define MKCBCMAC(size) \ +static void \ +cbcmac_ ## size(const unsigned char *sk, \ + unsigned char *cbcmac, const unsigned char *buf, size_t num_blocks) \ +{ \ + long cc; \ + \ + cc = 0; \ + asm volatile ( \ + \ + /* \ + * Load subkeys into v0..v10 \ + */ \ + LOAD_SUBKEYS_ ## size \ + li(%[cc], 0) \ + \ + BYTESWAP_INIT \ + \ + /* \ + * Load current CBC-MAC value into v16. \ + */ \ + lxvw4x(48, %[cc], %[cbcmac]) \ + BYTESWAP(16) \ + \ + mtctr(%[num_blocks]) \ + \ + label(loop) \ + /* \ + * Load next block, XOR into current CBC-MAC value, \ + * and then encrypt it. \ + */ \ + lxvw4x(49, %[cc], %[buf]) \ + BYTESWAP(17) \ + vxor(16, 16, 17) \ + BLOCK_ENCRYPT_ ## size(16) \ + addi(%[buf], %[buf], 16) \ + \ + bdnz(loop) \ + \ + /* \ + * Write back new CBC-MAC value. \ + */ \ + BYTESWAP(16) \ + stxvw4x(48, %[cc], %[cbcmac]) \ + \ +: [cc] "+b" (cc), [buf] "+b" (buf) \ +: [sk] "b" (sk), [cbcmac] "b" (cbcmac), [num_blocks] "b" (num_blocks) \ + BYTESWAP_REG \ +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \ + "v30", "ctr", "memory" \ + ); \ +} + +MKCBCMAC(128) +MKCBCMAC(192) +MKCBCMAC(256) + +#define MKENCRYPT(size) \ +static void \ +ctrcbc_ ## size ## _encrypt(const unsigned char *sk, \ + unsigned char *ctr, unsigned char *cbcmac, unsigned char *buf, \ + size_t num_blocks) \ +{ \ + long cc; \ + \ + cc = 0; \ + asm volatile ( \ + \ + /* \ + * Load subkeys into v0..v10 \ + */ \ + LOAD_SUBKEYS_ ## size \ + li(%[cc], 0) \ + \ + BYTESWAP_INIT \ + INCR_128_INIT \ + \ + /* \ + * Load current CTR counter into v16, and current \ + * CBC-MAC IV into v17. \ + */ \ + lxvw4x(48, %[cc], %[ctr]) \ + lxvw4x(49, %[cc], %[cbcmac]) \ + BYTESWAP(16) \ + BYTESWAP(17) \ + \ + /* \ + * At each iteration, we do two parallel encryption: \ + * - new counter value for encryption of the next block; \ + * - CBC-MAC over the previous encrypted block. \ + * Thus, each plaintext block implies two AES instances, \ + * over two successive iterations. This requires a single \ + * counter encryption before the loop, and a single \ + * CBC-MAC encryption after the loop. \ + */ \ + \ + /* \ + * Encrypt first block (into v20). \ + */ \ + lxvw4x(52, %[cc], %[buf]) \ + BYTESWAP(20) \ + INCR_128(22, 16) \ + BLOCK_ENCRYPT_ ## size(16) \ + vxor(20, 20, 16) \ + BYTESWAPX(21, 20) \ + stxvw4x(53, %[cc], %[buf]) \ + vand(16, 22, 22) \ + addi(%[buf], %[buf], 16) \ + \ + /* \ + * Load loop counter; skip the loop if there is only \ + * one block in total (already handled by the boundary \ + * conditions). \ + */ \ + mtctr(%[num_blocks]) \ + bdz(fastexit) \ + \ + label(loop) \ + /* \ + * Upon loop entry: \ + * v16 counter value for next block \ + * v17 current CBC-MAC value \ + * v20 encrypted previous block \ + */ \ + vxor(17, 17, 20) \ + INCR_128(22, 16) \ + lxvw4x(52, %[cc], %[buf]) \ + BYTESWAP(20) \ + BLOCK_ENCRYPT_X2_ ## size(16, 17) \ + vxor(20, 20, 16) \ + BYTESWAPX(21, 20) \ + stxvw4x(53, %[cc], %[buf]) \ + addi(%[buf], %[buf], 16) \ + vand(16, 22, 22) \ + \ + bdnz(loop) \ + \ + label(fastexit) \ + vxor(17, 17, 20) \ + BLOCK_ENCRYPT_ ## size(17) \ + BYTESWAP(16) \ + BYTESWAP(17) \ + stxvw4x(48, %[cc], %[ctr]) \ + stxvw4x(49, %[cc], %[cbcmac]) \ + \ +: [cc] "+b" (cc), [buf] "+b" (buf) \ +: [sk] "b" (sk), [ctr] "b" (ctr), [cbcmac] "b" (cbcmac), \ + [num_blocks] "b" (num_blocks), [ctrinc] "b" (ctrinc) \ + BYTESWAP_REG \ +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \ + "v30", "ctr", "memory" \ + ); \ +} + +MKENCRYPT(128) +MKENCRYPT(192) +MKENCRYPT(256) + +#define MKDECRYPT(size) \ +static void \ +ctrcbc_ ## size ## _decrypt(const unsigned char *sk, \ + unsigned char *ctr, unsigned char *cbcmac, unsigned char *buf, \ + size_t num_blocks) \ +{ \ + long cc; \ + \ + cc = 0; \ + asm volatile ( \ + \ + /* \ + * Load subkeys into v0..v10 \ + */ \ + LOAD_SUBKEYS_ ## size \ + li(%[cc], 0) \ + \ + BYTESWAP_INIT \ + INCR_128_INIT \ + \ + /* \ + * Load current CTR counter into v16, and current \ + * CBC-MAC IV into v17. \ + */ \ + lxvw4x(48, %[cc], %[ctr]) \ + lxvw4x(49, %[cc], %[cbcmac]) \ + BYTESWAP(16) \ + BYTESWAP(17) \ + \ + /* \ + * At each iteration, we do two parallel encryption: \ + * - new counter value for decryption of the next block; \ + * - CBC-MAC over the next encrypted block. \ + * Each iteration performs the two AES instances related \ + * to the current block; there is thus no need for some \ + * extra pre-loop and post-loop work as in encryption. \ + */ \ + \ + mtctr(%[num_blocks]) \ + \ + label(loop) \ + /* \ + * Upon loop entry: \ + * v16 counter value for next block \ + * v17 current CBC-MAC value \ + */ \ + lxvw4x(52, %[cc], %[buf]) \ + BYTESWAP(20) \ + vxor(17, 17, 20) \ + INCR_128(22, 16) \ + BLOCK_ENCRYPT_X2_ ## size(16, 17) \ + vxor(20, 20, 16) \ + BYTESWAPX(21, 20) \ + stxvw4x(53, %[cc], %[buf]) \ + addi(%[buf], %[buf], 16) \ + vand(16, 22, 22) \ + \ + bdnz(loop) \ + \ + /* \ + * Store back counter and CBC-MAC value. \ + */ \ + BYTESWAP(16) \ + BYTESWAP(17) \ + stxvw4x(48, %[cc], %[ctr]) \ + stxvw4x(49, %[cc], %[cbcmac]) \ + \ +: [cc] "+b" (cc), [buf] "+b" (buf) \ +: [sk] "b" (sk), [ctr] "b" (ctr), [cbcmac] "b" (cbcmac), \ + [num_blocks] "b" (num_blocks), [ctrinc] "b" (ctrinc) \ + BYTESWAP_REG \ +: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \ + "v30", "ctr", "memory" \ + ); \ +} + +MKDECRYPT(128) +MKDECRYPT(192) +MKDECRYPT(256) + +/* see bearssl_block.h */ +void +br_aes_pwr8_ctrcbc_encrypt(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + if (len == 0) { + return; + } + switch (ctx->num_rounds) { + case 10: + ctrcbc_128_encrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4); + break; + case 12: + ctrcbc_192_encrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4); + break; + default: + ctrcbc_256_encrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4); + break; + } +} + +/* see bearssl_block.h */ +void +br_aes_pwr8_ctrcbc_decrypt(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + if (len == 0) { + return; + } + switch (ctx->num_rounds) { + case 10: + ctrcbc_128_decrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4); + break; + case 12: + ctrcbc_192_decrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4); + break; + default: + ctrcbc_256_decrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4); + break; + } +} + +static inline void +incr_ctr(void *dst, const void *src) +{ + uint64_t hi, lo; + + hi = br_dec64be(src); + lo = br_dec64be((const unsigned char *)src + 8); + lo ++; + hi += ((lo | -lo) >> 63) ^ (uint64_t)1; + br_enc64be(dst, hi); + br_enc64be((unsigned char *)dst + 8, lo); +} + +/* see bearssl_block.h */ +void +br_aes_pwr8_ctrcbc_ctr(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len) +{ + unsigned char ctrbuf[64]; + + memcpy(ctrbuf, ctr, 16); + incr_ctr(ctrbuf + 16, ctrbuf); + incr_ctr(ctrbuf + 32, ctrbuf + 16); + incr_ctr(ctrbuf + 48, ctrbuf + 32); + if (len >= 64) { + switch (ctx->num_rounds) { + case 10: + ctr_128(ctx->skey.skni, ctrbuf, data, len >> 6); + break; + case 12: + ctr_192(ctx->skey.skni, ctrbuf, data, len >> 6); + break; + default: + ctr_256(ctx->skey.skni, ctrbuf, data, len >> 6); + break; + } + data = (unsigned char *)data + (len & ~(size_t)63); + len &= 63; + } + if (len > 0) { + unsigned char tmp[64]; + + if (len >= 32) { + if (len >= 48) { + memcpy(ctr, ctrbuf + 48, 16); + } else { + memcpy(ctr, ctrbuf + 32, 16); + } + } else { + if (len >= 16) { + memcpy(ctr, ctrbuf + 16, 16); + } + } + memcpy(tmp, data, len); + memset(tmp + len, 0, (sizeof tmp) - len); + switch (ctx->num_rounds) { + case 10: + ctr_128(ctx->skey.skni, ctrbuf, tmp, 1); + break; + case 12: + ctr_192(ctx->skey.skni, ctrbuf, tmp, 1); + break; + default: + ctr_256(ctx->skey.skni, ctrbuf, tmp, 1); + break; + } + memcpy(data, tmp, len); + } else { + memcpy(ctr, ctrbuf, 16); + } +} + +/* see bearssl_block.h */ +void +br_aes_pwr8_ctrcbc_mac(const br_aes_pwr8_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len) +{ + if (len > 0) { + switch (ctx->num_rounds) { + case 10: + cbcmac_128(ctx->skey.skni, cbcmac, data, len >> 4); + break; + case 12: + cbcmac_192(ctx->skey.skni, cbcmac, data, len >> 4); + break; + default: + cbcmac_256(ctx->skey.skni, cbcmac, data, len >> 4); + break; + } + } +} + +/* see bearssl_block.h */ +const br_block_ctrcbc_class br_aes_pwr8_ctrcbc_vtable = { + sizeof(br_aes_pwr8_ctrcbc_keys), + 16, + 4, + (void (*)(const br_block_ctrcbc_class **, const void *, size_t)) + &br_aes_pwr8_ctrcbc_init, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_pwr8_ctrcbc_encrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_pwr8_ctrcbc_decrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, size_t)) + &br_aes_pwr8_ctrcbc_ctr, + (void (*)(const br_block_ctrcbc_class *const *, + void *, const void *, size_t)) + &br_aes_pwr8_ctrcbc_mac +}; + +#else + +/* see bearssl_block.h */ +const br_block_ctrcbc_class * +br_aes_pwr8_ctrcbc_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_small_cbcdec.c b/src/bearssl/src/symcipher/aes_small_cbcdec.c new file mode 100644 index 0000000..8567244 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_small_cbcdec.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_small_cbcdec_vtable; + ctx->num_rounds = br_aes_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + + ivbuf = iv; + buf = data; + while (len > 0) { + unsigned char tmp[16]; + int i; + + memcpy(tmp, buf, 16); + br_aes_small_decrypt(ctx->num_rounds, ctx->skey, buf); + for (i = 0; i < 16; i ++) { + buf[i] ^= ivbuf[i]; + } + memcpy(ivbuf, tmp, 16); + buf += 16; + len -= 16; + } +} + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_aes_small_cbcdec_vtable = { + sizeof(br_aes_small_cbcdec_keys), + 16, + 4, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_aes_small_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_aes_small_cbcdec_run +}; diff --git a/src/bearssl/src/symcipher/aes_small_cbcenc.c b/src/bearssl/src/symcipher/aes_small_cbcenc.c new file mode 100644 index 0000000..0dc2910 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_small_cbcenc.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_small_cbcenc_vtable; + ctx->num_rounds = br_aes_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + + ivbuf = iv; + buf = data; + while (len > 0) { + int i; + + for (i = 0; i < 16; i ++) { + buf[i] ^= ivbuf[i]; + } + br_aes_small_encrypt(ctx->num_rounds, ctx->skey, buf); + memcpy(ivbuf, buf, 16); + buf += 16; + len -= 16; + } +} + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_aes_small_cbcenc_vtable = { + sizeof(br_aes_small_cbcenc_keys), + 16, + 4, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_aes_small_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_aes_small_cbcenc_run +}; diff --git a/src/bearssl/src/symcipher/aes_small_ctr.c b/src/bearssl/src/symcipher/aes_small_ctr.c new file mode 100644 index 0000000..d5d371c --- /dev/null +++ b/src/bearssl/src/symcipher/aes_small_ctr.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_small_ctr_vtable; + ctx->num_rounds = br_aes_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +uint32_t +br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + + buf = data; + while (len > 0) { + unsigned char tmp[16]; + + memcpy(tmp, iv, 12); + br_enc32be(tmp + 12, cc ++); + br_aes_small_encrypt(ctx->num_rounds, ctx->skey, tmp); + if (len <= 16) { + xorbuf(buf, tmp, len); + break; + } + xorbuf(buf, tmp, 16); + buf += 16; + len -= 16; + } + return cc; +} + +/* see bearssl_block.h */ +const br_block_ctr_class br_aes_small_ctr_vtable = { + sizeof(br_aes_small_ctr_keys), + 16, + 4, + (void (*)(const br_block_ctr_class **, const void *, size_t)) + &br_aes_small_ctr_init, + (uint32_t (*)(const br_block_ctr_class *const *, + const void *, uint32_t, void *, size_t)) + &br_aes_small_ctr_run +}; diff --git a/src/bearssl/src/symcipher/aes_small_ctrcbc.c b/src/bearssl/src/symcipher/aes_small_ctrcbc.c new file mode 100644 index 0000000..2d6ba32 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_small_ctrcbc.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_small_ctrcbc_vtable; + ctx->num_rounds = br_aes_keysched(ctx->skey, key, len); +} + +static void +xorbuf(void *dst, const void *src, size_t len) +{ + unsigned char *d; + const unsigned char *s; + + d = dst; + s = src; + while (len -- > 0) { + *d ++ ^= *s ++; + } +} + +/* see bearssl_block.h */ +void +br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len) +{ + unsigned char *buf, *bctr; + uint32_t cc0, cc1, cc2, cc3; + + buf = data; + bctr = ctr; + cc3 = br_dec32be(bctr + 0); + cc2 = br_dec32be(bctr + 4); + cc1 = br_dec32be(bctr + 8); + cc0 = br_dec32be(bctr + 12); + while (len > 0) { + unsigned char tmp[16]; + uint32_t carry; + + br_enc32be(tmp + 0, cc3); + br_enc32be(tmp + 4, cc2); + br_enc32be(tmp + 8, cc1); + br_enc32be(tmp + 12, cc0); + br_aes_small_encrypt(ctx->num_rounds, ctx->skey, tmp); + xorbuf(buf, tmp, 16); + buf += 16; + len -= 16; + cc0 ++; + carry = (~(cc0 | -cc0)) >> 31; + cc1 += carry; + carry &= (~(cc1 | -cc1)) >> 31; + cc2 += carry; + carry &= (~(cc2 | -cc2)) >> 31; + cc3 += carry; + } + br_enc32be(bctr + 0, cc3); + br_enc32be(bctr + 4, cc2); + br_enc32be(bctr + 8, cc1); + br_enc32be(bctr + 12, cc0); +} + +/* see bearssl_block.h */ +void +br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len) +{ + const unsigned char *buf; + + buf = data; + while (len > 0) { + xorbuf(cbcmac, buf, 16); + br_aes_small_encrypt(ctx->num_rounds, ctx->skey, cbcmac); + buf += 16; + len -= 16; + } +} + +/* see bearssl_block.h */ +void +br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + br_aes_small_ctrcbc_ctr(ctx, ctr, data, len); + br_aes_small_ctrcbc_mac(ctx, cbcmac, data, len); +} + +/* see bearssl_block.h */ +void +br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + br_aes_small_ctrcbc_mac(ctx, cbcmac, data, len); + br_aes_small_ctrcbc_ctr(ctx, ctr, data, len); +} + +/* see bearssl_block.h */ +const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable = { + sizeof(br_aes_small_ctrcbc_keys), + 16, + 4, + (void (*)(const br_block_ctrcbc_class **, const void *, size_t)) + &br_aes_small_ctrcbc_init, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_small_ctrcbc_encrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_small_ctrcbc_decrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, size_t)) + &br_aes_small_ctrcbc_ctr, + (void (*)(const br_block_ctrcbc_class *const *, + void *, const void *, size_t)) + &br_aes_small_ctrcbc_mac +}; diff --git a/src/bearssl/src/symcipher/aes_small_dec.c b/src/bearssl/src/symcipher/aes_small_dec.c new file mode 100644 index 0000000..59dca8e --- /dev/null +++ b/src/bearssl/src/symcipher/aes_small_dec.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Inverse S-box. + */ +static const unsigned char iS[] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D +}; + +static void +add_round_key(unsigned *state, const uint32_t *skeys) +{ + int i; + + for (i = 0; i < 16; i += 4) { + uint32_t k; + + k = *skeys ++; + state[i + 0] ^= (unsigned)(k >> 24); + state[i + 1] ^= (unsigned)(k >> 16) & 0xFF; + state[i + 2] ^= (unsigned)(k >> 8) & 0xFF; + state[i + 3] ^= (unsigned)k & 0xFF; + } +} + +static void +inv_sub_bytes(unsigned *state) +{ + int i; + + for (i = 0; i < 16; i ++) { + state[i] = iS[state[i]]; + } +} + +static void +inv_shift_rows(unsigned *state) +{ + unsigned tmp; + + tmp = state[13]; + state[13] = state[9]; + state[9] = state[5]; + state[5] = state[1]; + state[1] = tmp; + + tmp = state[2]; + state[2] = state[10]; + state[10] = tmp; + tmp = state[6]; + state[6] = state[14]; + state[14] = tmp; + + tmp = state[3]; + state[3] = state[7]; + state[7] = state[11]; + state[11] = state[15]; + state[15] = tmp; +} + +static inline unsigned +gf256red(unsigned x) +{ + unsigned y; + + y = x >> 8; + return (x ^ y ^ (y << 1) ^ (y << 3) ^ (y << 4)) & 0xFF; +} + +static void +inv_mix_columns(unsigned *state) +{ + int i; + + for (i = 0; i < 16; i += 4) { + unsigned s0, s1, s2, s3; + unsigned t0, t1, t2, t3; + + s0 = state[i + 0]; + s1 = state[i + 1]; + s2 = state[i + 2]; + s3 = state[i + 3]; + t0 = (s0 << 1) ^ (s0 << 2) ^ (s0 << 3) + ^ s1 ^ (s1 << 1) ^ (s1 << 3) + ^ s2 ^ (s2 << 2) ^ (s2 << 3) + ^ s3 ^ (s3 << 3); + t1 = s0 ^ (s0 << 3) + ^ (s1 << 1) ^ (s1 << 2) ^ (s1 << 3) + ^ s2 ^ (s2 << 1) ^ (s2 << 3) + ^ s3 ^ (s3 << 2) ^ (s3 << 3); + t2 = s0 ^ (s0 << 2) ^ (s0 << 3) + ^ s1 ^ (s1 << 3) + ^ (s2 << 1) ^ (s2 << 2) ^ (s2 << 3) + ^ s3 ^ (s3 << 1) ^ (s3 << 3); + t3 = s0 ^ (s0 << 1) ^ (s0 << 3) + ^ s1 ^ (s1 << 2) ^ (s1 << 3) + ^ s2 ^ (s2 << 3) + ^ (s3 << 1) ^ (s3 << 2) ^ (s3 << 3); + state[i + 0] = gf256red(t0); + state[i + 1] = gf256red(t1); + state[i + 2] = gf256red(t2); + state[i + 3] = gf256red(t3); + } +} + +/* see inner.h */ +void +br_aes_small_decrypt(unsigned num_rounds, const uint32_t *skey, void *data) +{ + unsigned char *buf; + unsigned state[16]; + unsigned u; + + buf = data; + for (u = 0; u < 16; u ++) { + state[u] = buf[u]; + } + add_round_key(state, skey + (num_rounds << 2)); + for (u = num_rounds - 1; u > 0; u --) { + inv_shift_rows(state); + inv_sub_bytes(state); + add_round_key(state, skey + (u << 2)); + inv_mix_columns(state); + } + inv_shift_rows(state); + inv_sub_bytes(state); + add_round_key(state, skey); + for (u = 0; u < 16; u ++) { + buf[u] = state[u]; + } +} diff --git a/src/bearssl/src/symcipher/aes_small_enc.c b/src/bearssl/src/symcipher/aes_small_enc.c new file mode 100644 index 0000000..29f48a8 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_small_enc.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#define S br_aes_S + +static void +add_round_key(unsigned *state, const uint32_t *skeys) +{ + int i; + + for (i = 0; i < 16; i += 4) { + uint32_t k; + + k = *skeys ++; + state[i + 0] ^= (unsigned)(k >> 24); + state[i + 1] ^= (unsigned)(k >> 16) & 0xFF; + state[i + 2] ^= (unsigned)(k >> 8) & 0xFF; + state[i + 3] ^= (unsigned)k & 0xFF; + } +} + +static void +sub_bytes(unsigned *state) +{ + int i; + + for (i = 0; i < 16; i ++) { + state[i] = S[state[i]]; + } +} + +static void +shift_rows(unsigned *state) +{ + unsigned tmp; + + tmp = state[1]; + state[1] = state[5]; + state[5] = state[9]; + state[9] = state[13]; + state[13] = tmp; + + tmp = state[2]; + state[2] = state[10]; + state[10] = tmp; + tmp = state[6]; + state[6] = state[14]; + state[14] = tmp; + + tmp = state[15]; + state[15] = state[11]; + state[11] = state[7]; + state[7] = state[3]; + state[3] = tmp; +} + +static void +mix_columns(unsigned *state) +{ + int i; + + for (i = 0; i < 16; i += 4) { + unsigned s0, s1, s2, s3; + unsigned t0, t1, t2, t3; + + s0 = state[i + 0]; + s1 = state[i + 1]; + s2 = state[i + 2]; + s3 = state[i + 3]; + t0 = (s0 << 1) ^ s1 ^ (s1 << 1) ^ s2 ^ s3; + t1 = s0 ^ (s1 << 1) ^ s2 ^ (s2 << 1) ^ s3; + t2 = s0 ^ s1 ^ (s2 << 1) ^ s3 ^ (s3 << 1); + t3 = s0 ^ (s0 << 1) ^ s1 ^ s2 ^ (s3 << 1); + state[i + 0] = t0 ^ ((unsigned)(-(int)(t0 >> 8)) & 0x11B); + state[i + 1] = t1 ^ ((unsigned)(-(int)(t1 >> 8)) & 0x11B); + state[i + 2] = t2 ^ ((unsigned)(-(int)(t2 >> 8)) & 0x11B); + state[i + 3] = t3 ^ ((unsigned)(-(int)(t3 >> 8)) & 0x11B); + } +} + +/* see inner.h */ +void +br_aes_small_encrypt(unsigned num_rounds, const uint32_t *skey, void *data) +{ + unsigned char *buf; + unsigned state[16]; + unsigned u; + + buf = data; + for (u = 0; u < 16; u ++) { + state[u] = buf[u]; + } + add_round_key(state, skey); + for (u = 1; u < num_rounds; u ++) { + sub_bytes(state); + shift_rows(state); + mix_columns(state); + add_round_key(state, skey + (u << 2)); + } + sub_bytes(state); + shift_rows(state); + add_round_key(state, skey + (num_rounds << 2)); + for (u = 0; u < 16; u ++) { + buf[u] = state[u]; + } +} diff --git a/src/bearssl/src/symcipher/aes_x86ni.c b/src/bearssl/src/symcipher/aes_x86ni.c new file mode 100644 index 0000000..d5408f1 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_x86ni.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +/* + * This code contains the AES key schedule implementation using the + * AES-NI opcodes. + */ + +#if BR_AES_X86NI + +/* see inner.h */ +int +br_aes_x86ni_supported(void) +{ + /* + * Bit mask for features in ECX: + * 19 SSE4.1 (used for _mm_insert_epi32(), for AES-CTR) + * 25 AES-NI + */ + return br_cpuid(0, 0, 0x02080000, 0); +} + +BR_TARGETS_X86_UP + +BR_TARGET("sse2,aes") +static inline __m128i +expand_step128(__m128i k, __m128i k2) +{ + k = _mm_xor_si128(k, _mm_slli_si128(k, 4)); + k = _mm_xor_si128(k, _mm_slli_si128(k, 4)); + k = _mm_xor_si128(k, _mm_slli_si128(k, 4)); + k2 = _mm_shuffle_epi32(k2, 0xFF); + return _mm_xor_si128(k, k2); +} + +BR_TARGET("sse2,aes") +static inline void +expand_step192(__m128i *t1, __m128i *t2, __m128i *t3) +{ + __m128i t4; + + *t2 = _mm_shuffle_epi32(*t2, 0x55); + t4 = _mm_slli_si128(*t1, 0x4); + *t1 = _mm_xor_si128(*t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + *t1 = _mm_xor_si128(*t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + *t1 = _mm_xor_si128(*t1, t4); + *t1 = _mm_xor_si128(*t1, *t2); + *t2 = _mm_shuffle_epi32(*t1, 0xFF); + t4 = _mm_slli_si128(*t3, 0x4); + *t3 = _mm_xor_si128(*t3, t4); + *t3 = _mm_xor_si128(*t3, *t2); +} + +BR_TARGET("sse2,aes") +static inline void +expand_step256_1(__m128i *t1, __m128i *t2) +{ + __m128i t4; + + *t2 = _mm_shuffle_epi32(*t2, 0xFF); + t4 = _mm_slli_si128(*t1, 0x4); + *t1 = _mm_xor_si128(*t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + *t1 = _mm_xor_si128(*t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + *t1 = _mm_xor_si128(*t1, t4); + *t1 = _mm_xor_si128(*t1, *t2); +} + +BR_TARGET("sse2,aes") +static inline void +expand_step256_2(__m128i *t1, __m128i *t3) +{ + __m128i t2, t4; + + t4 = _mm_aeskeygenassist_si128(*t1, 0x0); + t2 = _mm_shuffle_epi32(t4, 0xAA); + t4 = _mm_slli_si128(*t3, 0x4); + *t3 = _mm_xor_si128(*t3, t4); + t4 = _mm_slli_si128(t4, 0x4); + *t3 = _mm_xor_si128(*t3, t4); + t4 = _mm_slli_si128(t4, 0x4); + *t3 = _mm_xor_si128(*t3, t4); + *t3 = _mm_xor_si128(*t3, t2); +} + +/* + * Perform key schedule for AES, encryption direction. Subkeys are written + * in sk[], and the number of rounds is returned. Key length MUST be 16, + * 24 or 32 bytes. + */ +BR_TARGET("sse2,aes") +static unsigned +x86ni_keysched(__m128i *sk, const void *key, size_t len) +{ + const unsigned char *kb; + +#define KEXP128(k, i, rcon) do { \ + k = expand_step128(k, _mm_aeskeygenassist_si128(k, rcon)); \ + sk[i] = k; \ + } while (0) + +#define KEXP192(i, rcon1, rcon2) do { \ + sk[(i) + 0] = t1; \ + sk[(i) + 1] = t3; \ + t2 = _mm_aeskeygenassist_si128(t3, rcon1); \ + expand_step192(&t1, &t2, &t3); \ + sk[(i) + 1] = _mm_castpd_si128(_mm_shuffle_pd( \ + _mm_castsi128_pd(sk[(i) + 1]), \ + _mm_castsi128_pd(t1), 0)); \ + sk[(i) + 2] = _mm_castpd_si128(_mm_shuffle_pd( \ + _mm_castsi128_pd(t1), \ + _mm_castsi128_pd(t3), 1)); \ + t2 = _mm_aeskeygenassist_si128(t3, rcon2); \ + expand_step192(&t1, &t2, &t3); \ + } while (0) + +#define KEXP256(i, rcon) do { \ + sk[(i) + 0] = t3; \ + t2 = _mm_aeskeygenassist_si128(t3, rcon); \ + expand_step256_1(&t1, &t2); \ + sk[(i) + 1] = t1; \ + expand_step256_2(&t1, &t3); \ + } while (0) + + kb = key; + switch (len) { + __m128i t1, t2, t3; + + case 16: + t1 = _mm_loadu_si128((const void *)kb); + sk[0] = t1; + KEXP128(t1, 1, 0x01); + KEXP128(t1, 2, 0x02); + KEXP128(t1, 3, 0x04); + KEXP128(t1, 4, 0x08); + KEXP128(t1, 5, 0x10); + KEXP128(t1, 6, 0x20); + KEXP128(t1, 7, 0x40); + KEXP128(t1, 8, 0x80); + KEXP128(t1, 9, 0x1B); + KEXP128(t1, 10, 0x36); + return 10; + + case 24: + t1 = _mm_loadu_si128((const void *)kb); + t3 = _mm_loadu_si128((const void *)(kb + 8)); + t3 = _mm_shuffle_epi32(t3, 0x4E); + KEXP192(0, 0x01, 0x02); + KEXP192(3, 0x04, 0x08); + KEXP192(6, 0x10, 0x20); + KEXP192(9, 0x40, 0x80); + sk[12] = t1; + return 12; + + case 32: + t1 = _mm_loadu_si128((const void *)kb); + t3 = _mm_loadu_si128((const void *)(kb + 16)); + sk[0] = t1; + KEXP256( 1, 0x01); + KEXP256( 3, 0x02); + KEXP256( 5, 0x04); + KEXP256( 7, 0x08); + KEXP256( 9, 0x10); + KEXP256(11, 0x20); + sk[13] = t3; + t2 = _mm_aeskeygenassist_si128(t3, 0x40); + expand_step256_1(&t1, &t2); + sk[14] = t1; + return 14; + + default: + return 0; + } + +#undef KEXP128 +#undef KEXP192 +#undef KEXP256 +} + +/* see inner.h */ +BR_TARGET("sse2,aes") +unsigned +br_aes_x86ni_keysched_enc(unsigned char *skni, const void *key, size_t len) +{ + __m128i sk[15]; + unsigned num_rounds; + + num_rounds = x86ni_keysched(sk, key, len); + memcpy(skni, sk, (num_rounds + 1) << 4); + return num_rounds; +} + +/* see inner.h */ +BR_TARGET("sse2,aes") +unsigned +br_aes_x86ni_keysched_dec(unsigned char *skni, const void *key, size_t len) +{ + __m128i sk[15]; + unsigned u, num_rounds; + + num_rounds = x86ni_keysched(sk, key, len); + _mm_storeu_si128((void *)skni, sk[num_rounds]); + for (u = 1; u < num_rounds; u ++) { + _mm_storeu_si128((void *)(skni + (u << 4)), + _mm_aesimc_si128(sk[num_rounds - u])); + } + _mm_storeu_si128((void *)(skni + (num_rounds << 4)), sk[0]); + return num_rounds; +} + +BR_TARGETS_X86_DOWN + +#endif diff --git a/src/bearssl/src/symcipher/aes_x86ni_cbcdec.c b/src/bearssl/src/symcipher/aes_x86ni_cbcdec.c new file mode 100644 index 0000000..862b1b5 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_x86ni_cbcdec.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +#if BR_AES_X86NI + +/* see bearssl_block.h */ +const br_block_cbcdec_class * +br_aes_x86ni_cbcdec_get_vtable(void) +{ + return br_aes_x86ni_supported() ? &br_aes_x86ni_cbcdec_vtable : NULL; +} + +/* see bearssl_block.h */ +void +br_aes_x86ni_cbcdec_init(br_aes_x86ni_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_x86ni_cbcdec_vtable; + ctx->num_rounds = br_aes_x86ni_keysched_dec(ctx->skey.skni, key, len); +} + +BR_TARGETS_X86_UP + +/* see bearssl_block.h */ +BR_TARGET("sse2,aes") +void +br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf; + unsigned num_rounds; + __m128i sk[15], ivx; + unsigned u; + + buf = data; + ivx = _mm_loadu_si128(iv); + num_rounds = ctx->num_rounds; + for (u = 0; u <= num_rounds; u ++) { + sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4))); + } + while (len > 0) { + __m128i x0, x1, x2, x3, e0, e1, e2, e3; + + x0 = _mm_loadu_si128((void *)(buf + 0)); + if (len >= 64) { + x1 = _mm_loadu_si128((void *)(buf + 16)); + x2 = _mm_loadu_si128((void *)(buf + 32)); + x3 = _mm_loadu_si128((void *)(buf + 48)); + } else { + x0 = _mm_loadu_si128((void *)(buf + 0)); + if (len >= 32) { + x1 = _mm_loadu_si128((void *)(buf + 16)); + if (len >= 48) { + x2 = _mm_loadu_si128( + (void *)(buf + 32)); + x3 = x2; + } else { + x2 = x0; + x3 = x1; + } + } else { + x1 = x0; + x2 = x0; + x3 = x0; + } + } + e0 = x0; + e1 = x1; + e2 = x2; + e3 = x3; + x0 = _mm_xor_si128(x0, sk[0]); + x1 = _mm_xor_si128(x1, sk[0]); + x2 = _mm_xor_si128(x2, sk[0]); + x3 = _mm_xor_si128(x3, sk[0]); + x0 = _mm_aesdec_si128(x0, sk[1]); + x1 = _mm_aesdec_si128(x1, sk[1]); + x2 = _mm_aesdec_si128(x2, sk[1]); + x3 = _mm_aesdec_si128(x3, sk[1]); + x0 = _mm_aesdec_si128(x0, sk[2]); + x1 = _mm_aesdec_si128(x1, sk[2]); + x2 = _mm_aesdec_si128(x2, sk[2]); + x3 = _mm_aesdec_si128(x3, sk[2]); + x0 = _mm_aesdec_si128(x0, sk[3]); + x1 = _mm_aesdec_si128(x1, sk[3]); + x2 = _mm_aesdec_si128(x2, sk[3]); + x3 = _mm_aesdec_si128(x3, sk[3]); + x0 = _mm_aesdec_si128(x0, sk[4]); + x1 = _mm_aesdec_si128(x1, sk[4]); + x2 = _mm_aesdec_si128(x2, sk[4]); + x3 = _mm_aesdec_si128(x3, sk[4]); + x0 = _mm_aesdec_si128(x0, sk[5]); + x1 = _mm_aesdec_si128(x1, sk[5]); + x2 = _mm_aesdec_si128(x2, sk[5]); + x3 = _mm_aesdec_si128(x3, sk[5]); + x0 = _mm_aesdec_si128(x0, sk[6]); + x1 = _mm_aesdec_si128(x1, sk[6]); + x2 = _mm_aesdec_si128(x2, sk[6]); + x3 = _mm_aesdec_si128(x3, sk[6]); + x0 = _mm_aesdec_si128(x0, sk[7]); + x1 = _mm_aesdec_si128(x1, sk[7]); + x2 = _mm_aesdec_si128(x2, sk[7]); + x3 = _mm_aesdec_si128(x3, sk[7]); + x0 = _mm_aesdec_si128(x0, sk[8]); + x1 = _mm_aesdec_si128(x1, sk[8]); + x2 = _mm_aesdec_si128(x2, sk[8]); + x3 = _mm_aesdec_si128(x3, sk[8]); + x0 = _mm_aesdec_si128(x0, sk[9]); + x1 = _mm_aesdec_si128(x1, sk[9]); + x2 = _mm_aesdec_si128(x2, sk[9]); + x3 = _mm_aesdec_si128(x3, sk[9]); + if (num_rounds == 10) { + x0 = _mm_aesdeclast_si128(x0, sk[10]); + x1 = _mm_aesdeclast_si128(x1, sk[10]); + x2 = _mm_aesdeclast_si128(x2, sk[10]); + x3 = _mm_aesdeclast_si128(x3, sk[10]); + } else if (num_rounds == 12) { + x0 = _mm_aesdec_si128(x0, sk[10]); + x1 = _mm_aesdec_si128(x1, sk[10]); + x2 = _mm_aesdec_si128(x2, sk[10]); + x3 = _mm_aesdec_si128(x3, sk[10]); + x0 = _mm_aesdec_si128(x0, sk[11]); + x1 = _mm_aesdec_si128(x1, sk[11]); + x2 = _mm_aesdec_si128(x2, sk[11]); + x3 = _mm_aesdec_si128(x3, sk[11]); + x0 = _mm_aesdeclast_si128(x0, sk[12]); + x1 = _mm_aesdeclast_si128(x1, sk[12]); + x2 = _mm_aesdeclast_si128(x2, sk[12]); + x3 = _mm_aesdeclast_si128(x3, sk[12]); + } else { + x0 = _mm_aesdec_si128(x0, sk[10]); + x1 = _mm_aesdec_si128(x1, sk[10]); + x2 = _mm_aesdec_si128(x2, sk[10]); + x3 = _mm_aesdec_si128(x3, sk[10]); + x0 = _mm_aesdec_si128(x0, sk[11]); + x1 = _mm_aesdec_si128(x1, sk[11]); + x2 = _mm_aesdec_si128(x2, sk[11]); + x3 = _mm_aesdec_si128(x3, sk[11]); + x0 = _mm_aesdec_si128(x0, sk[12]); + x1 = _mm_aesdec_si128(x1, sk[12]); + x2 = _mm_aesdec_si128(x2, sk[12]); + x3 = _mm_aesdec_si128(x3, sk[12]); + x0 = _mm_aesdec_si128(x0, sk[13]); + x1 = _mm_aesdec_si128(x1, sk[13]); + x2 = _mm_aesdec_si128(x2, sk[13]); + x3 = _mm_aesdec_si128(x3, sk[13]); + x0 = _mm_aesdeclast_si128(x0, sk[14]); + x1 = _mm_aesdeclast_si128(x1, sk[14]); + x2 = _mm_aesdeclast_si128(x2, sk[14]); + x3 = _mm_aesdeclast_si128(x3, sk[14]); + } + x0 = _mm_xor_si128(x0, ivx); + x1 = _mm_xor_si128(x1, e0); + x2 = _mm_xor_si128(x2, e1); + x3 = _mm_xor_si128(x3, e2); + ivx = e3; + _mm_storeu_si128((void *)(buf + 0), x0); + if (len >= 64) { + _mm_storeu_si128((void *)(buf + 16), x1); + _mm_storeu_si128((void *)(buf + 32), x2); + _mm_storeu_si128((void *)(buf + 48), x3); + buf += 64; + len -= 64; + } else { + if (len >= 32) { + _mm_storeu_si128((void *)(buf + 16), x1); + if (len >= 48) { + _mm_storeu_si128( + (void *)(buf + 32), x2); + } + } + break; + } + } + _mm_storeu_si128(iv, ivx); +} + +BR_TARGETS_X86_DOWN + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_aes_x86ni_cbcdec_vtable = { + sizeof(br_aes_x86ni_cbcdec_keys), + 16, + 4, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_aes_x86ni_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_aes_x86ni_cbcdec_run +}; + +#else + +/* see bearssl_block.h */ +const br_block_cbcdec_class * +br_aes_x86ni_cbcdec_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_x86ni_cbcenc.c b/src/bearssl/src/symcipher/aes_x86ni_cbcenc.c new file mode 100644 index 0000000..85feecd --- /dev/null +++ b/src/bearssl/src/symcipher/aes_x86ni_cbcenc.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +#if BR_AES_X86NI + +/* see bearssl_block.h */ +const br_block_cbcenc_class * +br_aes_x86ni_cbcenc_get_vtable(void) +{ + return br_aes_x86ni_supported() ? &br_aes_x86ni_cbcenc_vtable : NULL; +} + +/* see bearssl_block.h */ +void +br_aes_x86ni_cbcenc_init(br_aes_x86ni_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_x86ni_cbcenc_vtable; + ctx->num_rounds = br_aes_x86ni_keysched_enc(ctx->skey.skni, key, len); +} + +BR_TARGETS_X86_UP + +/* see bearssl_block.h */ +BR_TARGET("sse2,aes") +void +br_aes_x86ni_cbcenc_run(const br_aes_x86ni_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf; + unsigned num_rounds; + __m128i sk[15], ivx; + unsigned u; + + buf = data; + ivx = _mm_loadu_si128(iv); + num_rounds = ctx->num_rounds; + for (u = 0; u <= num_rounds; u ++) { + sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4))); + } + while (len > 0) { + __m128i x; + + x = _mm_xor_si128(_mm_loadu_si128((void *)buf), ivx); + x = _mm_xor_si128(x, sk[0]); + x = _mm_aesenc_si128(x, sk[1]); + x = _mm_aesenc_si128(x, sk[2]); + x = _mm_aesenc_si128(x, sk[3]); + x = _mm_aesenc_si128(x, sk[4]); + x = _mm_aesenc_si128(x, sk[5]); + x = _mm_aesenc_si128(x, sk[6]); + x = _mm_aesenc_si128(x, sk[7]); + x = _mm_aesenc_si128(x, sk[8]); + x = _mm_aesenc_si128(x, sk[9]); + if (num_rounds == 10) { + x = _mm_aesenclast_si128(x, sk[10]); + } else if (num_rounds == 12) { + x = _mm_aesenc_si128(x, sk[10]); + x = _mm_aesenc_si128(x, sk[11]); + x = _mm_aesenclast_si128(x, sk[12]); + } else { + x = _mm_aesenc_si128(x, sk[10]); + x = _mm_aesenc_si128(x, sk[11]); + x = _mm_aesenc_si128(x, sk[12]); + x = _mm_aesenc_si128(x, sk[13]); + x = _mm_aesenclast_si128(x, sk[14]); + } + ivx = x; + _mm_storeu_si128((void *)buf, x); + buf += 16; + len -= 16; + } + _mm_storeu_si128(iv, ivx); +} + +BR_TARGETS_X86_DOWN + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_aes_x86ni_cbcenc_vtable = { + sizeof(br_aes_x86ni_cbcenc_keys), + 16, + 4, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_aes_x86ni_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_aes_x86ni_cbcenc_run +}; + +#else + +/* see bearssl_block.h */ +const br_block_cbcenc_class * +br_aes_x86ni_cbcenc_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_x86ni_ctr.c b/src/bearssl/src/symcipher/aes_x86ni_ctr.c new file mode 100644 index 0000000..1cddd60 --- /dev/null +++ b/src/bearssl/src/symcipher/aes_x86ni_ctr.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +#if BR_AES_X86NI + +/* see bearssl_block.h */ +const br_block_ctr_class * +br_aes_x86ni_ctr_get_vtable(void) +{ + return br_aes_x86ni_supported() ? &br_aes_x86ni_ctr_vtable : NULL; +} + +/* see bearssl_block.h */ +void +br_aes_x86ni_ctr_init(br_aes_x86ni_ctr_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_x86ni_ctr_vtable; + ctx->num_rounds = br_aes_x86ni_keysched_enc(ctx->skey.skni, key, len); +} + +BR_TARGETS_X86_UP + +/* see bearssl_block.h */ +BR_TARGET("sse2,sse4.1,aes") +uint32_t +br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + unsigned char ivbuf[16]; + unsigned num_rounds; + __m128i sk[15]; + __m128i ivx; + unsigned u; + + buf = data; + memcpy(ivbuf, iv, 12); + num_rounds = ctx->num_rounds; + for (u = 0; u <= num_rounds; u ++) { + sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4))); + } + ivx = _mm_loadu_si128((void *)ivbuf); + while (len > 0) { + __m128i x0, x1, x2, x3; + + x0 = _mm_insert_epi32(ivx, br_bswap32(cc + 0), 3); + x1 = _mm_insert_epi32(ivx, br_bswap32(cc + 1), 3); + x2 = _mm_insert_epi32(ivx, br_bswap32(cc + 2), 3); + x3 = _mm_insert_epi32(ivx, br_bswap32(cc + 3), 3); + x0 = _mm_xor_si128(x0, sk[0]); + x1 = _mm_xor_si128(x1, sk[0]); + x2 = _mm_xor_si128(x2, sk[0]); + x3 = _mm_xor_si128(x3, sk[0]); + x0 = _mm_aesenc_si128(x0, sk[1]); + x1 = _mm_aesenc_si128(x1, sk[1]); + x2 = _mm_aesenc_si128(x2, sk[1]); + x3 = _mm_aesenc_si128(x3, sk[1]); + x0 = _mm_aesenc_si128(x0, sk[2]); + x1 = _mm_aesenc_si128(x1, sk[2]); + x2 = _mm_aesenc_si128(x2, sk[2]); + x3 = _mm_aesenc_si128(x3, sk[2]); + x0 = _mm_aesenc_si128(x0, sk[3]); + x1 = _mm_aesenc_si128(x1, sk[3]); + x2 = _mm_aesenc_si128(x2, sk[3]); + x3 = _mm_aesenc_si128(x3, sk[3]); + x0 = _mm_aesenc_si128(x0, sk[4]); + x1 = _mm_aesenc_si128(x1, sk[4]); + x2 = _mm_aesenc_si128(x2, sk[4]); + x3 = _mm_aesenc_si128(x3, sk[4]); + x0 = _mm_aesenc_si128(x0, sk[5]); + x1 = _mm_aesenc_si128(x1, sk[5]); + x2 = _mm_aesenc_si128(x2, sk[5]); + x3 = _mm_aesenc_si128(x3, sk[5]); + x0 = _mm_aesenc_si128(x0, sk[6]); + x1 = _mm_aesenc_si128(x1, sk[6]); + x2 = _mm_aesenc_si128(x2, sk[6]); + x3 = _mm_aesenc_si128(x3, sk[6]); + x0 = _mm_aesenc_si128(x0, sk[7]); + x1 = _mm_aesenc_si128(x1, sk[7]); + x2 = _mm_aesenc_si128(x2, sk[7]); + x3 = _mm_aesenc_si128(x3, sk[7]); + x0 = _mm_aesenc_si128(x0, sk[8]); + x1 = _mm_aesenc_si128(x1, sk[8]); + x2 = _mm_aesenc_si128(x2, sk[8]); + x3 = _mm_aesenc_si128(x3, sk[8]); + x0 = _mm_aesenc_si128(x0, sk[9]); + x1 = _mm_aesenc_si128(x1, sk[9]); + x2 = _mm_aesenc_si128(x2, sk[9]); + x3 = _mm_aesenc_si128(x3, sk[9]); + if (num_rounds == 10) { + x0 = _mm_aesenclast_si128(x0, sk[10]); + x1 = _mm_aesenclast_si128(x1, sk[10]); + x2 = _mm_aesenclast_si128(x2, sk[10]); + x3 = _mm_aesenclast_si128(x3, sk[10]); + } else if (num_rounds == 12) { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x2 = _mm_aesenc_si128(x2, sk[10]); + x3 = _mm_aesenc_si128(x3, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x2 = _mm_aesenc_si128(x2, sk[11]); + x3 = _mm_aesenc_si128(x3, sk[11]); + x0 = _mm_aesenclast_si128(x0, sk[12]); + x1 = _mm_aesenclast_si128(x1, sk[12]); + x2 = _mm_aesenclast_si128(x2, sk[12]); + x3 = _mm_aesenclast_si128(x3, sk[12]); + } else { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x2 = _mm_aesenc_si128(x2, sk[10]); + x3 = _mm_aesenc_si128(x3, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x2 = _mm_aesenc_si128(x2, sk[11]); + x3 = _mm_aesenc_si128(x3, sk[11]); + x0 = _mm_aesenc_si128(x0, sk[12]); + x1 = _mm_aesenc_si128(x1, sk[12]); + x2 = _mm_aesenc_si128(x2, sk[12]); + x3 = _mm_aesenc_si128(x3, sk[12]); + x0 = _mm_aesenc_si128(x0, sk[13]); + x1 = _mm_aesenc_si128(x1, sk[13]); + x2 = _mm_aesenc_si128(x2, sk[13]); + x3 = _mm_aesenc_si128(x3, sk[13]); + x0 = _mm_aesenclast_si128(x0, sk[14]); + x1 = _mm_aesenclast_si128(x1, sk[14]); + x2 = _mm_aesenclast_si128(x2, sk[14]); + x3 = _mm_aesenclast_si128(x3, sk[14]); + } + if (len >= 64) { + x0 = _mm_xor_si128(x0, + _mm_loadu_si128((void *)(buf + 0))); + x1 = _mm_xor_si128(x1, + _mm_loadu_si128((void *)(buf + 16))); + x2 = _mm_xor_si128(x2, + _mm_loadu_si128((void *)(buf + 32))); + x3 = _mm_xor_si128(x3, + _mm_loadu_si128((void *)(buf + 48))); + _mm_storeu_si128((void *)(buf + 0), x0); + _mm_storeu_si128((void *)(buf + 16), x1); + _mm_storeu_si128((void *)(buf + 32), x2); + _mm_storeu_si128((void *)(buf + 48), x3); + buf += 64; + len -= 64; + cc += 4; + } else { + unsigned char tmp[64]; + + _mm_storeu_si128((void *)(tmp + 0), x0); + _mm_storeu_si128((void *)(tmp + 16), x1); + _mm_storeu_si128((void *)(tmp + 32), x2); + _mm_storeu_si128((void *)(tmp + 48), x3); + for (u = 0; u < len; u ++) { + buf[u] ^= tmp[u]; + } + cc += (uint32_t)len >> 4; + break; + } + } + return cc; +} + +BR_TARGETS_X86_DOWN + +/* see bearssl_block.h */ +const br_block_ctr_class br_aes_x86ni_ctr_vtable = { + sizeof(br_aes_x86ni_ctr_keys), + 16, + 4, + (void (*)(const br_block_ctr_class **, const void *, size_t)) + &br_aes_x86ni_ctr_init, + (uint32_t (*)(const br_block_ctr_class *const *, + const void *, uint32_t, void *, size_t)) + &br_aes_x86ni_ctr_run +}; + +#else + +/* see bearssl_block.h */ +const br_block_ctr_class * +br_aes_x86ni_ctr_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/aes_x86ni_ctrcbc.c b/src/bearssl/src/symcipher/aes_x86ni_ctrcbc.c new file mode 100644 index 0000000..f57fead --- /dev/null +++ b/src/bearssl/src/symcipher/aes_x86ni_ctrcbc.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +#if BR_AES_X86NI + +/* see bearssl_block.h */ +const br_block_ctrcbc_class * +br_aes_x86ni_ctrcbc_get_vtable(void) +{ + return br_aes_x86ni_supported() ? &br_aes_x86ni_ctrcbc_vtable : NULL; +} + +/* see bearssl_block.h */ +void +br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_aes_x86ni_ctrcbc_vtable; + ctx->num_rounds = br_aes_x86ni_keysched_enc(ctx->skey.skni, key, len); +} + +BR_TARGETS_X86_UP + +/* see bearssl_block.h */ +BR_TARGET("sse2,sse4.1,aes") +void +br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len) +{ + unsigned char *buf; + unsigned num_rounds; + __m128i sk[15]; + __m128i ivx0, ivx1, ivx2, ivx3; + __m128i erev, zero, one, four, notthree; + unsigned u; + + buf = data; + num_rounds = ctx->num_rounds; + for (u = 0; u <= num_rounds; u ++) { + sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4))); + } + + /* + * Some SSE2 constants. + */ + erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15); + zero = _mm_setzero_si128(); + one = _mm_set_epi64x(0, 1); + four = _mm_set_epi64x(0, 4); + notthree = _mm_sub_epi64(zero, four); + + /* + * Decode the counter in big-endian and pre-increment the other + * three counters. + */ + ivx0 = _mm_shuffle_epi8(_mm_loadu_si128((void *)ctr), erev); + ivx1 = _mm_add_epi64(ivx0, one); + ivx1 = _mm_sub_epi64(ivx1, + _mm_slli_si128(_mm_cmpeq_epi64(ivx1, zero), 8)); + ivx2 = _mm_add_epi64(ivx1, one); + ivx2 = _mm_sub_epi64(ivx2, + _mm_slli_si128(_mm_cmpeq_epi64(ivx2, zero), 8)); + ivx3 = _mm_add_epi64(ivx2, one); + ivx3 = _mm_sub_epi64(ivx3, + _mm_slli_si128(_mm_cmpeq_epi64(ivx3, zero), 8)); + while (len > 0) { + __m128i x0, x1, x2, x3; + + /* + * Load counter values; we need to byteswap them because + * the specification says that they use big-endian. + */ + x0 = _mm_shuffle_epi8(ivx0, erev); + x1 = _mm_shuffle_epi8(ivx1, erev); + x2 = _mm_shuffle_epi8(ivx2, erev); + x3 = _mm_shuffle_epi8(ivx3, erev); + + x0 = _mm_xor_si128(x0, sk[0]); + x1 = _mm_xor_si128(x1, sk[0]); + x2 = _mm_xor_si128(x2, sk[0]); + x3 = _mm_xor_si128(x3, sk[0]); + x0 = _mm_aesenc_si128(x0, sk[1]); + x1 = _mm_aesenc_si128(x1, sk[1]); + x2 = _mm_aesenc_si128(x2, sk[1]); + x3 = _mm_aesenc_si128(x3, sk[1]); + x0 = _mm_aesenc_si128(x0, sk[2]); + x1 = _mm_aesenc_si128(x1, sk[2]); + x2 = _mm_aesenc_si128(x2, sk[2]); + x3 = _mm_aesenc_si128(x3, sk[2]); + x0 = _mm_aesenc_si128(x0, sk[3]); + x1 = _mm_aesenc_si128(x1, sk[3]); + x2 = _mm_aesenc_si128(x2, sk[3]); + x3 = _mm_aesenc_si128(x3, sk[3]); + x0 = _mm_aesenc_si128(x0, sk[4]); + x1 = _mm_aesenc_si128(x1, sk[4]); + x2 = _mm_aesenc_si128(x2, sk[4]); + x3 = _mm_aesenc_si128(x3, sk[4]); + x0 = _mm_aesenc_si128(x0, sk[5]); + x1 = _mm_aesenc_si128(x1, sk[5]); + x2 = _mm_aesenc_si128(x2, sk[5]); + x3 = _mm_aesenc_si128(x3, sk[5]); + x0 = _mm_aesenc_si128(x0, sk[6]); + x1 = _mm_aesenc_si128(x1, sk[6]); + x2 = _mm_aesenc_si128(x2, sk[6]); + x3 = _mm_aesenc_si128(x3, sk[6]); + x0 = _mm_aesenc_si128(x0, sk[7]); + x1 = _mm_aesenc_si128(x1, sk[7]); + x2 = _mm_aesenc_si128(x2, sk[7]); + x3 = _mm_aesenc_si128(x3, sk[7]); + x0 = _mm_aesenc_si128(x0, sk[8]); + x1 = _mm_aesenc_si128(x1, sk[8]); + x2 = _mm_aesenc_si128(x2, sk[8]); + x3 = _mm_aesenc_si128(x3, sk[8]); + x0 = _mm_aesenc_si128(x0, sk[9]); + x1 = _mm_aesenc_si128(x1, sk[9]); + x2 = _mm_aesenc_si128(x2, sk[9]); + x3 = _mm_aesenc_si128(x3, sk[9]); + if (num_rounds == 10) { + x0 = _mm_aesenclast_si128(x0, sk[10]); + x1 = _mm_aesenclast_si128(x1, sk[10]); + x2 = _mm_aesenclast_si128(x2, sk[10]); + x3 = _mm_aesenclast_si128(x3, sk[10]); + } else if (num_rounds == 12) { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x2 = _mm_aesenc_si128(x2, sk[10]); + x3 = _mm_aesenc_si128(x3, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x2 = _mm_aesenc_si128(x2, sk[11]); + x3 = _mm_aesenc_si128(x3, sk[11]); + x0 = _mm_aesenclast_si128(x0, sk[12]); + x1 = _mm_aesenclast_si128(x1, sk[12]); + x2 = _mm_aesenclast_si128(x2, sk[12]); + x3 = _mm_aesenclast_si128(x3, sk[12]); + } else { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x2 = _mm_aesenc_si128(x2, sk[10]); + x3 = _mm_aesenc_si128(x3, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x2 = _mm_aesenc_si128(x2, sk[11]); + x3 = _mm_aesenc_si128(x3, sk[11]); + x0 = _mm_aesenc_si128(x0, sk[12]); + x1 = _mm_aesenc_si128(x1, sk[12]); + x2 = _mm_aesenc_si128(x2, sk[12]); + x3 = _mm_aesenc_si128(x3, sk[12]); + x0 = _mm_aesenc_si128(x0, sk[13]); + x1 = _mm_aesenc_si128(x1, sk[13]); + x2 = _mm_aesenc_si128(x2, sk[13]); + x3 = _mm_aesenc_si128(x3, sk[13]); + x0 = _mm_aesenclast_si128(x0, sk[14]); + x1 = _mm_aesenclast_si128(x1, sk[14]); + x2 = _mm_aesenclast_si128(x2, sk[14]); + x3 = _mm_aesenclast_si128(x3, sk[14]); + } + if (len >= 64) { + x0 = _mm_xor_si128(x0, + _mm_loadu_si128((void *)(buf + 0))); + x1 = _mm_xor_si128(x1, + _mm_loadu_si128((void *)(buf + 16))); + x2 = _mm_xor_si128(x2, + _mm_loadu_si128((void *)(buf + 32))); + x3 = _mm_xor_si128(x3, + _mm_loadu_si128((void *)(buf + 48))); + _mm_storeu_si128((void *)(buf + 0), x0); + _mm_storeu_si128((void *)(buf + 16), x1); + _mm_storeu_si128((void *)(buf + 32), x2); + _mm_storeu_si128((void *)(buf + 48), x3); + buf += 64; + len -= 64; + } else { + unsigned char tmp[64]; + + _mm_storeu_si128((void *)(tmp + 0), x0); + _mm_storeu_si128((void *)(tmp + 16), x1); + _mm_storeu_si128((void *)(tmp + 32), x2); + _mm_storeu_si128((void *)(tmp + 48), x3); + for (u = 0; u < len; u ++) { + buf[u] ^= tmp[u]; + } + switch (len) { + case 16: + ivx0 = ivx1; + break; + case 32: + ivx0 = ivx2; + break; + case 48: + ivx0 = ivx3; + break; + } + break; + } + + /* + * Add 4 to each counter value. For carry propagation + * into the upper 64-bit words, we would need to compare + * the results with 4, but SSE2+ has only _signed_ + * comparisons. Instead, we mask out the low two bits, + * and check whether the remaining bits are zero. + */ + ivx0 = _mm_add_epi64(ivx0, four); + ivx1 = _mm_add_epi64(ivx1, four); + ivx2 = _mm_add_epi64(ivx2, four); + ivx3 = _mm_add_epi64(ivx3, four); + ivx0 = _mm_sub_epi64(ivx0, + _mm_slli_si128(_mm_cmpeq_epi64( + _mm_and_si128(ivx0, notthree), zero), 8)); + ivx1 = _mm_sub_epi64(ivx1, + _mm_slli_si128(_mm_cmpeq_epi64( + _mm_and_si128(ivx1, notthree), zero), 8)); + ivx2 = _mm_sub_epi64(ivx2, + _mm_slli_si128(_mm_cmpeq_epi64( + _mm_and_si128(ivx2, notthree), zero), 8)); + ivx3 = _mm_sub_epi64(ivx3, + _mm_slli_si128(_mm_cmpeq_epi64( + _mm_and_si128(ivx3, notthree), zero), 8)); + } + + /* + * Write back new counter value. The loop took care to put the + * right counter value in ivx0. + */ + _mm_storeu_si128((void *)ctr, _mm_shuffle_epi8(ivx0, erev)); +} + +/* see bearssl_block.h */ +BR_TARGET("sse2,sse4.1,aes") +void +br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len) +{ + const unsigned char *buf; + unsigned num_rounds; + __m128i sk[15], ivx; + unsigned u; + + buf = data; + ivx = _mm_loadu_si128(cbcmac); + num_rounds = ctx->num_rounds; + for (u = 0; u <= num_rounds; u ++) { + sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4))); + } + while (len > 0) { + __m128i x; + + x = _mm_xor_si128(_mm_loadu_si128((void *)buf), ivx); + x = _mm_xor_si128(x, sk[0]); + x = _mm_aesenc_si128(x, sk[1]); + x = _mm_aesenc_si128(x, sk[2]); + x = _mm_aesenc_si128(x, sk[3]); + x = _mm_aesenc_si128(x, sk[4]); + x = _mm_aesenc_si128(x, sk[5]); + x = _mm_aesenc_si128(x, sk[6]); + x = _mm_aesenc_si128(x, sk[7]); + x = _mm_aesenc_si128(x, sk[8]); + x = _mm_aesenc_si128(x, sk[9]); + if (num_rounds == 10) { + x = _mm_aesenclast_si128(x, sk[10]); + } else if (num_rounds == 12) { + x = _mm_aesenc_si128(x, sk[10]); + x = _mm_aesenc_si128(x, sk[11]); + x = _mm_aesenclast_si128(x, sk[12]); + } else { + x = _mm_aesenc_si128(x, sk[10]); + x = _mm_aesenc_si128(x, sk[11]); + x = _mm_aesenc_si128(x, sk[12]); + x = _mm_aesenc_si128(x, sk[13]); + x = _mm_aesenclast_si128(x, sk[14]); + } + ivx = x; + buf += 16; + len -= 16; + } + _mm_storeu_si128(cbcmac, ivx); +} + +/* see bearssl_block.h */ +BR_TARGET("sse2,sse4.1,aes") +void +br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + unsigned char *buf; + unsigned num_rounds; + __m128i sk[15]; + __m128i ivx, cmx; + __m128i erev, zero, one; + unsigned u; + int first_iter; + + num_rounds = ctx->num_rounds; + for (u = 0; u <= num_rounds; u ++) { + sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4))); + } + + /* + * Some SSE2 constants. + */ + erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15); + zero = _mm_setzero_si128(); + one = _mm_set_epi64x(0, 1); + + /* + * Decode the counter in big-endian. + */ + ivx = _mm_shuffle_epi8(_mm_loadu_si128(ctr), erev); + cmx = _mm_loadu_si128(cbcmac); + + buf = data; + first_iter = 1; + while (len > 0) { + __m128i dx, x0, x1; + + /* + * Load initial values: + * dx encrypted block of data + * x0 counter (for CTR encryption) + * x1 input for CBC-MAC + */ + dx = _mm_loadu_si128((void *)buf); + x0 = _mm_shuffle_epi8(ivx, erev); + x1 = cmx; + + x0 = _mm_xor_si128(x0, sk[0]); + x1 = _mm_xor_si128(x1, sk[0]); + x0 = _mm_aesenc_si128(x0, sk[1]); + x1 = _mm_aesenc_si128(x1, sk[1]); + x0 = _mm_aesenc_si128(x0, sk[2]); + x1 = _mm_aesenc_si128(x1, sk[2]); + x0 = _mm_aesenc_si128(x0, sk[3]); + x1 = _mm_aesenc_si128(x1, sk[3]); + x0 = _mm_aesenc_si128(x0, sk[4]); + x1 = _mm_aesenc_si128(x1, sk[4]); + x0 = _mm_aesenc_si128(x0, sk[5]); + x1 = _mm_aesenc_si128(x1, sk[5]); + x0 = _mm_aesenc_si128(x0, sk[6]); + x1 = _mm_aesenc_si128(x1, sk[6]); + x0 = _mm_aesenc_si128(x0, sk[7]); + x1 = _mm_aesenc_si128(x1, sk[7]); + x0 = _mm_aesenc_si128(x0, sk[8]); + x1 = _mm_aesenc_si128(x1, sk[8]); + x0 = _mm_aesenc_si128(x0, sk[9]); + x1 = _mm_aesenc_si128(x1, sk[9]); + if (num_rounds == 10) { + x0 = _mm_aesenclast_si128(x0, sk[10]); + x1 = _mm_aesenclast_si128(x1, sk[10]); + } else if (num_rounds == 12) { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x0 = _mm_aesenclast_si128(x0, sk[12]); + x1 = _mm_aesenclast_si128(x1, sk[12]); + } else { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x0 = _mm_aesenc_si128(x0, sk[12]); + x1 = _mm_aesenc_si128(x1, sk[12]); + x0 = _mm_aesenc_si128(x0, sk[13]); + x1 = _mm_aesenc_si128(x1, sk[13]); + x0 = _mm_aesenclast_si128(x0, sk[14]); + x1 = _mm_aesenclast_si128(x1, sk[14]); + } + + x0 = _mm_xor_si128(x0, dx); + if (first_iter) { + cmx = _mm_xor_si128(cmx, x0); + first_iter = 0; + } else { + cmx = _mm_xor_si128(x1, x0); + } + _mm_storeu_si128((void *)buf, x0); + + buf += 16; + len -= 16; + + /* + * Increment the counter value. + */ + ivx = _mm_add_epi64(ivx, one); + ivx = _mm_sub_epi64(ivx, + _mm_slli_si128(_mm_cmpeq_epi64(ivx, zero), 8)); + + /* + * If this was the last iteration, then compute the + * extra block encryption to complete CBC-MAC. + */ + if (len == 0) { + cmx = _mm_xor_si128(cmx, sk[0]); + cmx = _mm_aesenc_si128(cmx, sk[1]); + cmx = _mm_aesenc_si128(cmx, sk[2]); + cmx = _mm_aesenc_si128(cmx, sk[3]); + cmx = _mm_aesenc_si128(cmx, sk[4]); + cmx = _mm_aesenc_si128(cmx, sk[5]); + cmx = _mm_aesenc_si128(cmx, sk[6]); + cmx = _mm_aesenc_si128(cmx, sk[7]); + cmx = _mm_aesenc_si128(cmx, sk[8]); + cmx = _mm_aesenc_si128(cmx, sk[9]); + if (num_rounds == 10) { + cmx = _mm_aesenclast_si128(cmx, sk[10]); + } else if (num_rounds == 12) { + cmx = _mm_aesenc_si128(cmx, sk[10]); + cmx = _mm_aesenc_si128(cmx, sk[11]); + cmx = _mm_aesenclast_si128(cmx, sk[12]); + } else { + cmx = _mm_aesenc_si128(cmx, sk[10]); + cmx = _mm_aesenc_si128(cmx, sk[11]); + cmx = _mm_aesenc_si128(cmx, sk[12]); + cmx = _mm_aesenc_si128(cmx, sk[13]); + cmx = _mm_aesenclast_si128(cmx, sk[14]); + } + break; + } + } + + /* + * Write back new counter value and CBC-MAC value. + */ + _mm_storeu_si128(ctr, _mm_shuffle_epi8(ivx, erev)); + _mm_storeu_si128(cbcmac, cmx); +} + +/* see bearssl_block.h */ +BR_TARGET("sse2,sse4.1,aes") +void +br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len) +{ + unsigned char *buf; + unsigned num_rounds; + __m128i sk[15]; + __m128i ivx, cmx; + __m128i erev, zero, one; + unsigned u; + + num_rounds = ctx->num_rounds; + for (u = 0; u <= num_rounds; u ++) { + sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4))); + } + + /* + * Some SSE2 constants. + */ + erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15); + zero = _mm_setzero_si128(); + one = _mm_set_epi64x(0, 1); + + /* + * Decode the counter in big-endian. + */ + ivx = _mm_shuffle_epi8(_mm_loadu_si128(ctr), erev); + cmx = _mm_loadu_si128(cbcmac); + + buf = data; + while (len > 0) { + __m128i dx, x0, x1; + + /* + * Load initial values: + * dx encrypted block of data + * x0 counter (for CTR encryption) + * x1 input for CBC-MAC + */ + dx = _mm_loadu_si128((void *)buf); + x0 = _mm_shuffle_epi8(ivx, erev); + x1 = _mm_xor_si128(cmx, dx); + + x0 = _mm_xor_si128(x0, sk[0]); + x1 = _mm_xor_si128(x1, sk[0]); + x0 = _mm_aesenc_si128(x0, sk[1]); + x1 = _mm_aesenc_si128(x1, sk[1]); + x0 = _mm_aesenc_si128(x0, sk[2]); + x1 = _mm_aesenc_si128(x1, sk[2]); + x0 = _mm_aesenc_si128(x0, sk[3]); + x1 = _mm_aesenc_si128(x1, sk[3]); + x0 = _mm_aesenc_si128(x0, sk[4]); + x1 = _mm_aesenc_si128(x1, sk[4]); + x0 = _mm_aesenc_si128(x0, sk[5]); + x1 = _mm_aesenc_si128(x1, sk[5]); + x0 = _mm_aesenc_si128(x0, sk[6]); + x1 = _mm_aesenc_si128(x1, sk[6]); + x0 = _mm_aesenc_si128(x0, sk[7]); + x1 = _mm_aesenc_si128(x1, sk[7]); + x0 = _mm_aesenc_si128(x0, sk[8]); + x1 = _mm_aesenc_si128(x1, sk[8]); + x0 = _mm_aesenc_si128(x0, sk[9]); + x1 = _mm_aesenc_si128(x1, sk[9]); + if (num_rounds == 10) { + x0 = _mm_aesenclast_si128(x0, sk[10]); + x1 = _mm_aesenclast_si128(x1, sk[10]); + } else if (num_rounds == 12) { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x0 = _mm_aesenclast_si128(x0, sk[12]); + x1 = _mm_aesenclast_si128(x1, sk[12]); + } else { + x0 = _mm_aesenc_si128(x0, sk[10]); + x1 = _mm_aesenc_si128(x1, sk[10]); + x0 = _mm_aesenc_si128(x0, sk[11]); + x1 = _mm_aesenc_si128(x1, sk[11]); + x0 = _mm_aesenc_si128(x0, sk[12]); + x1 = _mm_aesenc_si128(x1, sk[12]); + x0 = _mm_aesenc_si128(x0, sk[13]); + x1 = _mm_aesenc_si128(x1, sk[13]); + x0 = _mm_aesenclast_si128(x0, sk[14]); + x1 = _mm_aesenclast_si128(x1, sk[14]); + } + x0 = _mm_xor_si128(x0, dx); + cmx = x1; + _mm_storeu_si128((void *)buf, x0); + + buf += 16; + len -= 16; + + /* + * Increment the counter value. + */ + ivx = _mm_add_epi64(ivx, one); + ivx = _mm_sub_epi64(ivx, + _mm_slli_si128(_mm_cmpeq_epi64(ivx, zero), 8)); + } + + /* + * Write back new counter value and CBC-MAC value. + */ + _mm_storeu_si128(ctr, _mm_shuffle_epi8(ivx, erev)); + _mm_storeu_si128(cbcmac, cmx); +} + +BR_TARGETS_X86_DOWN + +/* see bearssl_block.h */ +const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable = { + sizeof(br_aes_x86ni_ctrcbc_keys), + 16, + 4, + (void (*)(const br_block_ctrcbc_class **, const void *, size_t)) + &br_aes_x86ni_ctrcbc_init, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_x86ni_ctrcbc_encrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, void *, size_t)) + &br_aes_x86ni_ctrcbc_decrypt, + (void (*)(const br_block_ctrcbc_class *const *, + void *, void *, size_t)) + &br_aes_x86ni_ctrcbc_ctr, + (void (*)(const br_block_ctrcbc_class *const *, + void *, const void *, size_t)) + &br_aes_x86ni_ctrcbc_mac +}; + +#else + +/* see bearssl_block.h */ +const br_block_ctrcbc_class * +br_aes_x86ni_ctrcbc_get_vtable(void) +{ + return NULL; +} + +#endif diff --git a/src/bearssl/src/symcipher/chacha20_ct.c b/src/bearssl/src/symcipher/chacha20_ct.c new file mode 100644 index 0000000..9961eb1 --- /dev/null +++ b/src/bearssl/src/symcipher/chacha20_ct.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +uint32_t +br_chacha20_ct_run(const void *key, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + uint32_t kw[8], ivw[3]; + size_t u; + + static const uint32_t CW[] = { + 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 + }; + + buf = data; + for (u = 0; u < 8; u ++) { + kw[u] = br_dec32le((const unsigned char *)key + (u << 2)); + } + for (u = 0; u < 3; u ++) { + ivw[u] = br_dec32le((const unsigned char *)iv + (u << 2)); + } + while (len > 0) { + uint32_t state[16]; + int i; + size_t clen; + unsigned char tmp[64]; + + memcpy(&state[0], CW, sizeof CW); + memcpy(&state[4], kw, sizeof kw); + state[12] = cc; + memcpy(&state[13], ivw, sizeof ivw); + for (i = 0; i < 10; i ++) { + +#define QROUND(a, b, c, d) do { \ + state[a] += state[b]; \ + state[d] ^= state[a]; \ + state[d] = (state[d] << 16) | (state[d] >> 16); \ + state[c] += state[d]; \ + state[b] ^= state[c]; \ + state[b] = (state[b] << 12) | (state[b] >> 20); \ + state[a] += state[b]; \ + state[d] ^= state[a]; \ + state[d] = (state[d] << 8) | (state[d] >> 24); \ + state[c] += state[d]; \ + state[b] ^= state[c]; \ + state[b] = (state[b] << 7) | (state[b] >> 25); \ + } while (0) + + QROUND( 0, 4, 8, 12); + QROUND( 1, 5, 9, 13); + QROUND( 2, 6, 10, 14); + QROUND( 3, 7, 11, 15); + QROUND( 0, 5, 10, 15); + QROUND( 1, 6, 11, 12); + QROUND( 2, 7, 8, 13); + QROUND( 3, 4, 9, 14); + +#undef QROUND + + } + for (u = 0; u < 4; u ++) { + br_enc32le(&tmp[u << 2], state[u] + CW[u]); + } + for (u = 4; u < 12; u ++) { + br_enc32le(&tmp[u << 2], state[u] + kw[u - 4]); + } + br_enc32le(&tmp[48], state[12] + cc); + for (u = 13; u < 16; u ++) { + br_enc32le(&tmp[u << 2], state[u] + ivw[u - 13]); + } + + clen = len < 64 ? len : 64; + for (u = 0; u < clen; u ++) { + buf[u] ^= tmp[u]; + } + buf += clen; + len -= clen; + cc ++; + } + return cc; +} diff --git a/src/bearssl/src/symcipher/chacha20_sse2.c b/src/bearssl/src/symcipher/chacha20_sse2.c new file mode 100644 index 0000000..92b4a4a --- /dev/null +++ b/src/bearssl/src/symcipher/chacha20_sse2.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +#if BR_SSE2 + +/* + * This file contains a ChaCha20 implementation that leverages SSE2 + * opcodes for better performance. + */ + +/* see bearssl_block.h */ +br_chacha20_run +br_chacha20_sse2_get(void) +{ + /* + * If using 64-bit mode, then SSE2 opcodes should be automatically + * available, since they are part of the ABI. + * + * In 32-bit mode, we use CPUID to detect the SSE2 feature. + */ + +#if BR_amd64 + return &br_chacha20_sse2_run; +#else + + /* + * SSE2 support is indicated by bit 26 in EDX. + */ + if (br_cpuid(0, 0, 0, 0x04000000)) { + return &br_chacha20_sse2_run; + } else { + return 0; + } +#endif +} + +BR_TARGETS_X86_UP + +/* see bearssl_block.h */ +BR_TARGET("sse2") +uint32_t +br_chacha20_sse2_run(const void *key, + const void *iv, uint32_t cc, void *data, size_t len) +{ + unsigned char *buf; + uint32_t ivtmp[4]; + __m128i kw0, kw1; + __m128i iw, cw; + __m128i one; + + static const uint32_t CW[] = { + 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 + }; + + buf = data; + kw0 = _mm_loadu_si128(key); + kw1 = _mm_loadu_si128((const void *)((const unsigned char *)key + 16)); + ivtmp[0] = cc; + memcpy(ivtmp + 1, iv, 12); + iw = _mm_loadu_si128((const void *)ivtmp); + cw = _mm_loadu_si128((const void *)CW); + one = _mm_set_epi32(0, 0, 0, 1); + + while (len > 0) { + /* + * sj contains state words 4*j to 4*j+3. + */ + __m128i s0, s1, s2, s3; + int i; + + s0 = cw; + s1 = kw0; + s2 = kw1; + s3 = iw; + for (i = 0; i < 10; i ++) { + /* + * Even round is straightforward application on + * the state words. + */ + s0 = _mm_add_epi32(s0, s1); + s3 = _mm_xor_si128(s3, s0); + s3 = _mm_or_si128( + _mm_slli_epi32(s3, 16), + _mm_srli_epi32(s3, 16)); + + s2 = _mm_add_epi32(s2, s3); + s1 = _mm_xor_si128(s1, s2); + s1 = _mm_or_si128( + _mm_slli_epi32(s1, 12), + _mm_srli_epi32(s1, 20)); + + s0 = _mm_add_epi32(s0, s1); + s3 = _mm_xor_si128(s3, s0); + s3 = _mm_or_si128( + _mm_slli_epi32(s3, 8), + _mm_srli_epi32(s3, 24)); + + s2 = _mm_add_epi32(s2, s3); + s1 = _mm_xor_si128(s1, s2); + s1 = _mm_or_si128( + _mm_slli_epi32(s1, 7), + _mm_srli_epi32(s1, 25)); + + /* + * For the odd round, we must rotate some state + * words so that the computations apply on the + * right combinations of words. + */ + s1 = _mm_shuffle_epi32(s1, 0x39); + s2 = _mm_shuffle_epi32(s2, 0x4E); + s3 = _mm_shuffle_epi32(s3, 0x93); + + s0 = _mm_add_epi32(s0, s1); + s3 = _mm_xor_si128(s3, s0); + s3 = _mm_or_si128( + _mm_slli_epi32(s3, 16), + _mm_srli_epi32(s3, 16)); + + s2 = _mm_add_epi32(s2, s3); + s1 = _mm_xor_si128(s1, s2); + s1 = _mm_or_si128( + _mm_slli_epi32(s1, 12), + _mm_srli_epi32(s1, 20)); + + s0 = _mm_add_epi32(s0, s1); + s3 = _mm_xor_si128(s3, s0); + s3 = _mm_or_si128( + _mm_slli_epi32(s3, 8), + _mm_srli_epi32(s3, 24)); + + s2 = _mm_add_epi32(s2, s3); + s1 = _mm_xor_si128(s1, s2); + s1 = _mm_or_si128( + _mm_slli_epi32(s1, 7), + _mm_srli_epi32(s1, 25)); + + /* + * After the odd round, we rotate back the values + * to undo the rotate at the start of the odd round. + */ + s1 = _mm_shuffle_epi32(s1, 0x93); + s2 = _mm_shuffle_epi32(s2, 0x4E); + s3 = _mm_shuffle_epi32(s3, 0x39); + } + + /* + * Addition with the initial state. + */ + s0 = _mm_add_epi32(s0, cw); + s1 = _mm_add_epi32(s1, kw0); + s2 = _mm_add_epi32(s2, kw1); + s3 = _mm_add_epi32(s3, iw); + + /* + * Increment block counter. + */ + iw = _mm_add_epi32(iw, one); + + /* + * XOR final state with the data. + */ + if (len < 64) { + unsigned char tmp[64]; + size_t u; + + _mm_storeu_si128((void *)(tmp + 0), s0); + _mm_storeu_si128((void *)(tmp + 16), s1); + _mm_storeu_si128((void *)(tmp + 32), s2); + _mm_storeu_si128((void *)(tmp + 48), s3); + for (u = 0; u < len; u ++) { + buf[u] ^= tmp[u]; + } + break; + } else { + __m128i b0, b1, b2, b3; + + b0 = _mm_loadu_si128((const void *)(buf + 0)); + b1 = _mm_loadu_si128((const void *)(buf + 16)); + b2 = _mm_loadu_si128((const void *)(buf + 32)); + b3 = _mm_loadu_si128((const void *)(buf + 48)); + b0 = _mm_xor_si128(b0, s0); + b1 = _mm_xor_si128(b1, s1); + b2 = _mm_xor_si128(b2, s2); + b3 = _mm_xor_si128(b3, s3); + _mm_storeu_si128((void *)(buf + 0), b0); + _mm_storeu_si128((void *)(buf + 16), b1); + _mm_storeu_si128((void *)(buf + 32), b2); + _mm_storeu_si128((void *)(buf + 48), b3); + buf += 64; + len -= 64; + } + } + + /* + * _mm_extract_epi32() requires SSE4.1. We prefer to stick to + * raw SSE2, thus we use _mm_extract_epi16(). + */ + return (uint32_t)_mm_extract_epi16(iw, 0) + | ((uint32_t)_mm_extract_epi16(iw, 1) << 16); +} + +BR_TARGETS_X86_DOWN + +#else + +/* see bearssl_block.h */ +br_chacha20_run +br_chacha20_sse2_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/symcipher/des_ct.c b/src/bearssl/src/symcipher/des_ct.c new file mode 100644 index 0000000..581c0ab --- /dev/null +++ b/src/bearssl/src/symcipher/des_ct.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * During key schedule, we need to apply bit extraction PC-2 then permute + * things into our bitslice representation. PC-2 extracts 48 bits out + * of two 28-bit words (kl and kr), and we store these bits into two + * 32-bit words sk0 and sk1. + * + * -- bit 16+x of sk0 comes from bit QL0[x] of kl + * -- bit x of sk0 comes from bit QR0[x] of kr + * -- bit 16+x of sk1 comes from bit QL1[x] of kl + * -- bit x of sk1 comes from bit QR1[x] of kr + */ + +static const unsigned char QL0[] = { + 17, 4, 27, 23, 13, 22, 7, 18, + 16, 24, 2, 20, 1, 8, 15, 26 +}; + +static const unsigned char QR0[] = { + 25, 19, 9, 1, 5, 11, 23, 8, + 17, 0, 22, 3, 6, 20, 27, 24 +}; + +static const unsigned char QL1[] = { + 28, 28, 14, 11, 28, 28, 25, 0, + 28, 28, 5, 9, 28, 28, 12, 21 +}; + +static const unsigned char QR1[] = { + 28, 28, 15, 4, 28, 28, 26, 16, + 28, 28, 12, 7, 28, 28, 10, 14 +}; + +/* + * 32-bit rotation. The C compiler is supposed to recognize it as a + * rotation and use the local architecture rotation opcode (if available). + */ +static inline uint32_t +rotl(uint32_t x, int n) +{ + return (x << n) | (x >> (32 - n)); +} + +/* + * Compute key schedule for 8 key bytes (produces 32 subkey words). + */ +static void +keysched_unit(uint32_t *skey, const void *key) +{ + int i; + + br_des_keysched_unit(skey, key); + + /* + * Apply PC-2 + bitslicing. + */ + for (i = 0; i < 16; i ++) { + uint32_t kl, kr, sk0, sk1; + int j; + + kl = skey[(i << 1) + 0]; + kr = skey[(i << 1) + 1]; + sk0 = 0; + sk1 = 0; + for (j = 0; j < 16; j ++) { + sk0 <<= 1; + sk1 <<= 1; + sk0 |= ((kl >> QL0[j]) & (uint32_t)1) << 16; + sk0 |= (kr >> QR0[j]) & (uint32_t)1; + sk1 |= ((kl >> QL1[j]) & (uint32_t)1) << 16; + sk1 |= (kr >> QR1[j]) & (uint32_t)1; + } + + skey[(i << 1) + 0] = sk0; + skey[(i << 1) + 1] = sk1; + } + +#if 0 + /* + * Speed-optimized version for PC-2 + bitslicing. + * (Unused. Kept for reference only.) + */ + sk0 = kl & (uint32_t)0x00100000; + sk0 |= (kl & (uint32_t)0x08008000) << 2; + sk0 |= (kl & (uint32_t)0x00400000) << 4; + sk0 |= (kl & (uint32_t)0x00800000) << 5; + sk0 |= (kl & (uint32_t)0x00040000) << 6; + sk0 |= (kl & (uint32_t)0x00010000) << 7; + sk0 |= (kl & (uint32_t)0x00000100) << 10; + sk0 |= (kl & (uint32_t)0x00022000) << 14; + sk0 |= (kl & (uint32_t)0x00000082) << 18; + sk0 |= (kl & (uint32_t)0x00000004) << 19; + sk0 |= (kl & (uint32_t)0x04000000) >> 10; + sk0 |= (kl & (uint32_t)0x00000010) << 26; + sk0 |= (kl & (uint32_t)0x01000000) >> 2; + + sk0 |= kr & (uint32_t)0x00000100; + sk0 |= (kr & (uint32_t)0x00000008) << 1; + sk0 |= (kr & (uint32_t)0x00000200) << 4; + sk0 |= rotl(kr & (uint32_t)0x08000021, 6); + sk0 |= (kr & (uint32_t)0x01000000) >> 24; + sk0 |= (kr & (uint32_t)0x00000002) << 11; + sk0 |= (kr & (uint32_t)0x00100000) >> 18; + sk0 |= (kr & (uint32_t)0x00400000) >> 17; + sk0 |= (kr & (uint32_t)0x00800000) >> 14; + sk0 |= (kr & (uint32_t)0x02020000) >> 10; + sk0 |= (kr & (uint32_t)0x00080000) >> 5; + sk0 |= (kr & (uint32_t)0x00000040) >> 3; + sk0 |= (kr & (uint32_t)0x00000800) >> 1; + + sk1 = kl & (uint32_t)0x02000000; + sk1 |= (kl & (uint32_t)0x00001000) << 5; + sk1 |= (kl & (uint32_t)0x00000200) << 11; + sk1 |= (kl & (uint32_t)0x00004000) << 15; + sk1 |= (kl & (uint32_t)0x00000020) << 16; + sk1 |= (kl & (uint32_t)0x00000800) << 17; + sk1 |= (kl & (uint32_t)0x00000001) << 24; + sk1 |= (kl & (uint32_t)0x00200000) >> 5; + + sk1 |= (kr & (uint32_t)0x00000010) << 8; + sk1 |= (kr & (uint32_t)0x04000000) >> 17; + sk1 |= (kr & (uint32_t)0x00004000) >> 14; + sk1 |= (kr & (uint32_t)0x00000400) >> 9; + sk1 |= (kr & (uint32_t)0x00010000) >> 8; + sk1 |= (kr & (uint32_t)0x00001000) >> 7; + sk1 |= (kr & (uint32_t)0x00000080) >> 3; + sk1 |= (kr & (uint32_t)0x00008000) >> 2; +#endif +} + +/* see inner.h */ +unsigned +br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len) +{ + switch (key_len) { + case 8: + keysched_unit(skey, key); + return 1; + case 16: + keysched_unit(skey, key); + keysched_unit(skey + 32, (const unsigned char *)key + 8); + br_des_rev_skey(skey + 32); + memcpy(skey + 64, skey, 32 * sizeof *skey); + return 3; + default: + keysched_unit(skey, key); + keysched_unit(skey + 32, (const unsigned char *)key + 8); + br_des_rev_skey(skey + 32); + keysched_unit(skey + 64, (const unsigned char *)key + 16); + return 3; + } +} + +/* + * DES confusion function. This function performs expansion E (32 to + * 48 bits), XOR with subkey, S-boxes, and permutation P. + */ +static inline uint32_t +Fconf(uint32_t r0, const uint32_t *sk) +{ + /* + * Each 6->4 S-box is virtually turned into four 6->1 boxes; we + * thus end up with 32 boxes that we call "T-boxes" here. We will + * evaluate them with bitslice code. + * + * Each T-box is a circuit of multiplexers (sort of) and thus + * takes 70 inputs: the 6 actual T-box inputs, and 64 constants + * that describe the T-box output for all combinations of the + * 6 inputs. With this model, all T-boxes are identical (with + * distinct inputs) and thus can be executed in parallel with + * bitslice code. + * + * T-boxes are numbered from 0 to 31, in least-to-most + * significant order. Thus, S-box S1 corresponds to T-boxes 31, + * 30, 29 and 28, in that order. T-box 'n' is computed with the + * bits at rank 'n' in the 32-bit words. + * + * Words x0 to x5 contain the T-box inputs 0 to 5. + */ + uint32_t x0, x1, x2, x3, x4, x5, z0; + uint32_t y0, y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21, y22, y23, y24, y25, y26, y27, y28, y29; + uint32_t y30; + + /* + * Spread input bits over the 6 input words x*. + */ + x1 = r0 & (uint32_t)0x11111111; + x2 = (r0 >> 1) & (uint32_t)0x11111111; + x3 = (r0 >> 2) & (uint32_t)0x11111111; + x4 = (r0 >> 3) & (uint32_t)0x11111111; + x1 = (x1 << 4) - x1; + x2 = (x2 << 4) - x2; + x3 = (x3 << 4) - x3; + x4 = (x4 << 4) - x4; + x0 = (x4 << 4) | (x4 >> 28); + x5 = (x1 >> 4) | (x1 << 28); + + /* + * XOR with the subkey for this round. + */ + x0 ^= sk[0]; + x1 ^= sk[1]; + x2 ^= sk[2]; + x3 ^= sk[3]; + x4 ^= sk[4]; + x5 ^= sk[5]; + + /* + * The T-boxes are done in parallel, since they all use a + * "tree of multiplexer". We use "fake multiplexers": + * + * y = a ^ (x & b) + * + * computes y as either 'a' (if x == 0) or 'a ^ b' (if x == 1). + */ + y0 = (uint32_t)0xEFA72C4D ^ (x0 & (uint32_t)0xEC7AC69C); + y1 = (uint32_t)0xAEAAEDFF ^ (x0 & (uint32_t)0x500FB821); + y2 = (uint32_t)0x37396665 ^ (x0 & (uint32_t)0x40EFA809); + y3 = (uint32_t)0x68D7B833 ^ (x0 & (uint32_t)0xA5EC0B28); + y4 = (uint32_t)0xC9C755BB ^ (x0 & (uint32_t)0x252CF820); + y5 = (uint32_t)0x73FC3606 ^ (x0 & (uint32_t)0x40205801); + y6 = (uint32_t)0xA2A0A918 ^ (x0 & (uint32_t)0xE220F929); + y7 = (uint32_t)0x8222BD90 ^ (x0 & (uint32_t)0x44A3F9E1); + y8 = (uint32_t)0xD6B6AC77 ^ (x0 & (uint32_t)0x794F104A); + y9 = (uint32_t)0x3069300C ^ (x0 & (uint32_t)0x026F320B); + y10 = (uint32_t)0x6CE0D5CC ^ (x0 & (uint32_t)0x7640B01A); + y11 = (uint32_t)0x59A9A22D ^ (x0 & (uint32_t)0x238F1572); + y12 = (uint32_t)0xAC6D0BD4 ^ (x0 & (uint32_t)0x7A63C083); + y13 = (uint32_t)0x21C83200 ^ (x0 & (uint32_t)0x11CCA000); + y14 = (uint32_t)0xA0E62188 ^ (x0 & (uint32_t)0x202F69AA); + /* y15 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */ + y16 = (uint32_t)0xAF7D655A ^ (x0 & (uint32_t)0x51B33BE9); + y17 = (uint32_t)0xF0168AA3 ^ (x0 & (uint32_t)0x3B0FE8AE); + y18 = (uint32_t)0x90AA30C6 ^ (x0 & (uint32_t)0x90BF8816); + y19 = (uint32_t)0x5AB2750A ^ (x0 & (uint32_t)0x09E34F9B); + y20 = (uint32_t)0x5391BE65 ^ (x0 & (uint32_t)0x0103BE88); + y21 = (uint32_t)0x93372BAF ^ (x0 & (uint32_t)0x49AC8E25); + y22 = (uint32_t)0xF288210C ^ (x0 & (uint32_t)0x922C313D); + y23 = (uint32_t)0x920AF5C0 ^ (x0 & (uint32_t)0x70EF31B0); + y24 = (uint32_t)0x63D312C0 ^ (x0 & (uint32_t)0x6A707100); + y25 = (uint32_t)0x537B3006 ^ (x0 & (uint32_t)0xB97C9011); + y26 = (uint32_t)0xA2EFB0A5 ^ (x0 & (uint32_t)0xA320C959); + y27 = (uint32_t)0xBC8F96A5 ^ (x0 & (uint32_t)0x6EA0AB4A); + y28 = (uint32_t)0xFAD176A5 ^ (x0 & (uint32_t)0x6953DDF8); + y29 = (uint32_t)0x665A14A3 ^ (x0 & (uint32_t)0xF74F3E2B); + y30 = (uint32_t)0xF2EFF0CC ^ (x0 & (uint32_t)0xF0306CAD); + /* y31 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */ + + y0 = y0 ^ (x1 & y1); + y1 = y2 ^ (x1 & y3); + y2 = y4 ^ (x1 & y5); + y3 = y6 ^ (x1 & y7); + y4 = y8 ^ (x1 & y9); + y5 = y10 ^ (x1 & y11); + y6 = y12 ^ (x1 & y13); + y7 = y14; /* was: y14 ^ (x1 & y15) */ + y8 = y16 ^ (x1 & y17); + y9 = y18 ^ (x1 & y19); + y10 = y20 ^ (x1 & y21); + y11 = y22 ^ (x1 & y23); + y12 = y24 ^ (x1 & y25); + y13 = y26 ^ (x1 & y27); + y14 = y28 ^ (x1 & y29); + y15 = y30; /* was: y30 ^ (x1 & y31) */ + + y0 = y0 ^ (x2 & y1); + y1 = y2 ^ (x2 & y3); + y2 = y4 ^ (x2 & y5); + y3 = y6 ^ (x2 & y7); + y4 = y8 ^ (x2 & y9); + y5 = y10 ^ (x2 & y11); + y6 = y12 ^ (x2 & y13); + y7 = y14 ^ (x2 & y15); + + y0 = y0 ^ (x3 & y1); + y1 = y2 ^ (x3 & y3); + y2 = y4 ^ (x3 & y5); + y3 = y6 ^ (x3 & y7); + + y0 = y0 ^ (x4 & y1); + y1 = y2 ^ (x4 & y3); + + y0 = y0 ^ (x5 & y1); + + /* + * The P permutation: + * -- Each bit move is converted into a mask + left rotation. + * -- Rotations that use the same movement are coalesced together. + * -- Left and right shifts are used as alternatives to a rotation + * where appropriate (this will help architectures that do not have + * a rotation opcode). + */ + z0 = (y0 & (uint32_t)0x00000004) << 3; + z0 |= (y0 & (uint32_t)0x00004000) << 4; + z0 |= rotl(y0 & 0x12020120, 5); + z0 |= (y0 & (uint32_t)0x00100000) << 6; + z0 |= (y0 & (uint32_t)0x00008000) << 9; + z0 |= (y0 & (uint32_t)0x04000000) >> 22; + z0 |= (y0 & (uint32_t)0x00000001) << 11; + z0 |= rotl(y0 & 0x20000200, 12); + z0 |= (y0 & (uint32_t)0x00200000) >> 19; + z0 |= (y0 & (uint32_t)0x00000040) << 14; + z0 |= (y0 & (uint32_t)0x00010000) << 15; + z0 |= (y0 & (uint32_t)0x00000002) << 16; + z0 |= rotl(y0 & 0x40801800, 17); + z0 |= (y0 & (uint32_t)0x00080000) >> 13; + z0 |= (y0 & (uint32_t)0x00000010) << 21; + z0 |= (y0 & (uint32_t)0x01000000) >> 10; + z0 |= rotl(y0 & 0x88000008, 24); + z0 |= (y0 & (uint32_t)0x00000480) >> 7; + z0 |= (y0 & (uint32_t)0x00442000) >> 6; + return z0; +} + +/* + * Process one block through 16 successive rounds, omitting the swap + * in the final round. + */ +static void +process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *sk_exp) +{ + int i; + uint32_t l, r; + + l = *pl; + r = *pr; + for (i = 0; i < 16; i ++) { + uint32_t t; + + t = l ^ Fconf(r, sk_exp); + l = r; + r = t; + sk_exp += 6; + } + *pl = r; + *pr = l; +} + +/* see inner.h */ +void +br_des_ct_process_block(unsigned num_rounds, + const uint32_t *sk_exp, void *block) +{ + unsigned char *buf; + uint32_t l, r; + + buf = block; + l = br_dec32be(buf); + r = br_dec32be(buf + 4); + br_des_do_IP(&l, &r); + while (num_rounds -- > 0) { + process_block_unit(&l, &r, sk_exp); + sk_exp += 96; + } + br_des_do_invIP(&l, &r); + br_enc32be(buf, l); + br_enc32be(buf + 4, r); +} + +/* see inner.h */ +void +br_des_ct_skey_expand(uint32_t *sk_exp, + unsigned num_rounds, const uint32_t *skey) +{ + num_rounds <<= 4; + while (num_rounds -- > 0) { + uint32_t v, w0, w1, w2, w3; + + v = *skey ++; + w0 = v & 0x11111111; + w1 = (v >> 1) & 0x11111111; + w2 = (v >> 2) & 0x11111111; + w3 = (v >> 3) & 0x11111111; + *sk_exp ++ = (w0 << 4) - w0; + *sk_exp ++ = (w1 << 4) - w1; + *sk_exp ++ = (w2 << 4) - w2; + *sk_exp ++ = (w3 << 4) - w3; + v = *skey ++; + w0 = v & 0x11111111; + w1 = (v >> 1) & 0x11111111; + *sk_exp ++ = (w0 << 4) - w0; + *sk_exp ++ = (w1 << 4) - w1; + } +} diff --git a/src/bearssl/src/symcipher/des_ct_cbcdec.c b/src/bearssl/src/symcipher/des_ct_cbcdec.c new file mode 100644 index 0000000..d208a3d --- /dev/null +++ b/src/bearssl/src/symcipher/des_ct_cbcdec.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_des_ct_cbcdec_vtable; + ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len); + if (len == 8) { + br_des_rev_skey(ctx->skey); + } else { + int i; + + for (i = 0; i < 48; i += 2) { + uint32_t t; + + t = ctx->skey[i]; + ctx->skey[i] = ctx->skey[94 - i]; + ctx->skey[94 - i] = t; + t = ctx->skey[i + 1]; + ctx->skey[i + 1] = ctx->skey[95 - i]; + ctx->skey[95 - i] = t; + } + } +} + +/* see bearssl_block.h */ +void +br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + uint32_t sk_exp[288]; + + br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + ivbuf = iv; + buf = data; + while (len > 0) { + unsigned char tmp[8]; + int i; + + memcpy(tmp, buf, 8); + br_des_ct_process_block(ctx->num_rounds, sk_exp, buf); + for (i = 0; i < 8; i ++) { + buf[i] ^= ivbuf[i]; + } + memcpy(ivbuf, tmp, 8); + buf += 8; + len -= 8; + } +} + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_des_ct_cbcdec_vtable = { + sizeof(br_des_ct_cbcdec_keys), + 8, + 3, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_des_ct_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_des_ct_cbcdec_run +}; diff --git a/src/bearssl/src/symcipher/des_ct_cbcenc.c b/src/bearssl/src/symcipher/des_ct_cbcenc.c new file mode 100644 index 0000000..4b3610e --- /dev/null +++ b/src/bearssl/src/symcipher/des_ct_cbcenc.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_des_ct_cbcenc_vtable; + ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + uint32_t sk_exp[288]; + + br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey); + ivbuf = iv; + buf = data; + while (len > 0) { + int i; + + for (i = 0; i < 8; i ++) { + buf[i] ^= ivbuf[i]; + } + br_des_ct_process_block(ctx->num_rounds, sk_exp, buf); + memcpy(ivbuf, buf, 8); + buf += 8; + len -= 8; + } +} + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_des_ct_cbcenc_vtable = { + sizeof(br_des_ct_cbcenc_keys), + 8, + 3, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_des_ct_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_des_ct_cbcenc_run +}; diff --git a/src/bearssl/src/symcipher/des_support.c b/src/bearssl/src/symcipher/des_support.c new file mode 100644 index 0000000..37f6db3 --- /dev/null +++ b/src/bearssl/src/symcipher/des_support.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_des_do_IP(uint32_t *xl, uint32_t *xr) +{ + /* + * Permutation algorithm is initially from Richard Outerbridge; + * implementation here is adapted from Crypto++ "des.cpp" file + * (which is in public domain). + */ + uint32_t l, r, t; + + l = *xl; + r = *xr; + t = ((l >> 4) ^ r) & (uint32_t)0x0F0F0F0F; + r ^= t; + l ^= t << 4; + t = ((l >> 16) ^ r) & (uint32_t)0x0000FFFF; + r ^= t; + l ^= t << 16; + t = ((r >> 2) ^ l) & (uint32_t)0x33333333; + l ^= t; + r ^= t << 2; + t = ((r >> 8) ^ l) & (uint32_t)0x00FF00FF; + l ^= t; + r ^= t << 8; + t = ((l >> 1) ^ r) & (uint32_t)0x55555555; + r ^= t; + l ^= t << 1; + *xl = l; + *xr = r; +} + +/* see inner.h */ +void +br_des_do_invIP(uint32_t *xl, uint32_t *xr) +{ + /* + * See br_des_do_IP(). + */ + uint32_t l, r, t; + + l = *xl; + r = *xr; + t = ((l >> 1) ^ r) & 0x55555555; + r ^= t; + l ^= t << 1; + t = ((r >> 8) ^ l) & 0x00FF00FF; + l ^= t; + r ^= t << 8; + t = ((r >> 2) ^ l) & 0x33333333; + l ^= t; + r ^= t << 2; + t = ((l >> 16) ^ r) & 0x0000FFFF; + r ^= t; + l ^= t << 16; + t = ((l >> 4) ^ r) & 0x0F0F0F0F; + r ^= t; + l ^= t << 4; + *xl = l; + *xr = r; +} + +/* see inner.h */ +void +br_des_keysched_unit(uint32_t *skey, const void *key) +{ + uint32_t xl, xr, kl, kr; + int i; + + xl = br_dec32be(key); + xr = br_dec32be((const unsigned char *)key + 4); + + /* + * Permutation PC-1 is quite similar to the IP permutation. + * Definition of IP (in FIPS 46-3 notations) is: + * 58 50 42 34 26 18 10 2 + * 60 52 44 36 28 20 12 4 + * 62 54 46 38 30 22 14 6 + * 64 56 48 40 32 24 16 8 + * 57 49 41 33 25 17 9 1 + * 59 51 43 35 27 19 11 3 + * 61 53 45 37 29 21 13 5 + * 63 55 47 39 31 23 15 7 + * + * Definition of PC-1 is: + * 57 49 41 33 25 17 9 1 + * 58 50 42 34 26 18 10 2 + * 59 51 43 35 27 19 11 3 + * 60 52 44 36 + * 63 55 47 39 31 23 15 7 + * 62 54 46 38 30 22 14 6 + * 61 53 45 37 29 21 13 5 + * 28 20 12 4 + */ + br_des_do_IP(&xl, &xr); + kl = ((xr & (uint32_t)0xFF000000) >> 4) + | ((xl & (uint32_t)0xFF000000) >> 12) + | ((xr & (uint32_t)0x00FF0000) >> 12) + | ((xl & (uint32_t)0x00FF0000) >> 20); + kr = ((xr & (uint32_t)0x000000FF) << 20) + | ((xl & (uint32_t)0x0000FF00) << 4) + | ((xr & (uint32_t)0x0000FF00) >> 4) + | ((xl & (uint32_t)0x000F0000) >> 16); + + /* + * For each round, rotate the two 28-bit words kl and kr. + * The extraction of the 48-bit subkey (PC-2) is not done yet. + */ + for (i = 0; i < 16; i ++) { + if ((1 << i) & 0x8103) { + kl = (kl << 1) | (kl >> 27); + kr = (kr << 1) | (kr >> 27); + } else { + kl = (kl << 2) | (kl >> 26); + kr = (kr << 2) | (kr >> 26); + } + kl &= (uint32_t)0x0FFFFFFF; + kr &= (uint32_t)0x0FFFFFFF; + skey[(i << 1) + 0] = kl; + skey[(i << 1) + 1] = kr; + } +} + +/* see inner.h */ +void +br_des_rev_skey(uint32_t *skey) +{ + int i; + + for (i = 0; i < 16; i += 2) { + uint32_t t; + + t = skey[i + 0]; + skey[i + 0] = skey[30 - i]; + skey[30 - i] = t; + t = skey[i + 1]; + skey[i + 1] = skey[31 - i]; + skey[31 - i] = t; + } +} diff --git a/src/bearssl/src/symcipher/des_tab.c b/src/bearssl/src/symcipher/des_tab.c new file mode 100644 index 0000000..3f8e4f9 --- /dev/null +++ b/src/bearssl/src/symcipher/des_tab.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * PC2left[x] tells where bit x goes when applying PC-2. 'x' is a bit + * position in the left rotated key word. Both position are in normal + * order (rightmost bit is 0). + */ +static const unsigned char PC2left[] = { + 16, 3, 7, 24, 20, 11, 24, + 13, 2, 10, 24, 22, 5, 15, + 23, 1, 9, 21, 12, 24, 6, + 4, 14, 18, 8, 17, 0, 19 +}; + +/* + * Similar to PC2left[x], for the right rotated key word. + */ +static const unsigned char PC2right[] = { + 8, 18, 24, 6, 22, 15, 3, + 10, 12, 19, 5, 14, 11, 24, + 4, 23, 16, 9, 24, 20, 2, + 24, 7, 13, 0, 21, 17, 1 +}; + +/* + * S-boxes and PC-1 merged. + */ +static const uint32_t S1[] = { + 0x00808200, 0x00000000, 0x00008000, 0x00808202, + 0x00808002, 0x00008202, 0x00000002, 0x00008000, + 0x00000200, 0x00808200, 0x00808202, 0x00000200, + 0x00800202, 0x00808002, 0x00800000, 0x00000002, + 0x00000202, 0x00800200, 0x00800200, 0x00008200, + 0x00008200, 0x00808000, 0x00808000, 0x00800202, + 0x00008002, 0x00800002, 0x00800002, 0x00008002, + 0x00000000, 0x00000202, 0x00008202, 0x00800000, + 0x00008000, 0x00808202, 0x00000002, 0x00808000, + 0x00808200, 0x00800000, 0x00800000, 0x00000200, + 0x00808002, 0x00008000, 0x00008200, 0x00800002, + 0x00000200, 0x00000002, 0x00800202, 0x00008202, + 0x00808202, 0x00008002, 0x00808000, 0x00800202, + 0x00800002, 0x00000202, 0x00008202, 0x00808200, + 0x00000202, 0x00800200, 0x00800200, 0x00000000, + 0x00008002, 0x00008200, 0x00000000, 0x00808002 +}; + +static const uint32_t S2[] = { + 0x40084010, 0x40004000, 0x00004000, 0x00084010, + 0x00080000, 0x00000010, 0x40080010, 0x40004010, + 0x40000010, 0x40084010, 0x40084000, 0x40000000, + 0x40004000, 0x00080000, 0x00000010, 0x40080010, + 0x00084000, 0x00080010, 0x40004010, 0x00000000, + 0x40000000, 0x00004000, 0x00084010, 0x40080000, + 0x00080010, 0x40000010, 0x00000000, 0x00084000, + 0x00004010, 0x40084000, 0x40080000, 0x00004010, + 0x00000000, 0x00084010, 0x40080010, 0x00080000, + 0x40004010, 0x40080000, 0x40084000, 0x00004000, + 0x40080000, 0x40004000, 0x00000010, 0x40084010, + 0x00084010, 0x00000010, 0x00004000, 0x40000000, + 0x00004010, 0x40084000, 0x00080000, 0x40000010, + 0x00080010, 0x40004010, 0x40000010, 0x00080010, + 0x00084000, 0x00000000, 0x40004000, 0x00004010, + 0x40000000, 0x40080010, 0x40084010, 0x00084000 +}; + +static const uint32_t S3[] = { + 0x00000104, 0x04010100, 0x00000000, 0x04010004, + 0x04000100, 0x00000000, 0x00010104, 0x04000100, + 0x00010004, 0x04000004, 0x04000004, 0x00010000, + 0x04010104, 0x00010004, 0x04010000, 0x00000104, + 0x04000000, 0x00000004, 0x04010100, 0x00000100, + 0x00010100, 0x04010000, 0x04010004, 0x00010104, + 0x04000104, 0x00010100, 0x00010000, 0x04000104, + 0x00000004, 0x04010104, 0x00000100, 0x04000000, + 0x04010100, 0x04000000, 0x00010004, 0x00000104, + 0x00010000, 0x04010100, 0x04000100, 0x00000000, + 0x00000100, 0x00010004, 0x04010104, 0x04000100, + 0x04000004, 0x00000100, 0x00000000, 0x04010004, + 0x04000104, 0x00010000, 0x04000000, 0x04010104, + 0x00000004, 0x00010104, 0x00010100, 0x04000004, + 0x04010000, 0x04000104, 0x00000104, 0x04010000, + 0x00010104, 0x00000004, 0x04010004, 0x00010100 +}; + +static const uint32_t S4[] = { + 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x00401040, 0x80400040, 0x80400000, 0x80001000, + 0x00000000, 0x00401000, 0x00401000, 0x80401040, + 0x80000040, 0x00000000, 0x00400040, 0x80400000, + 0x80000000, 0x00001000, 0x00400000, 0x80401000, + 0x00000040, 0x00400000, 0x80001000, 0x00001040, + 0x80400040, 0x80000000, 0x00001040, 0x00400040, + 0x00001000, 0x00401040, 0x80401040, 0x80000040, + 0x00400040, 0x80400000, 0x00401000, 0x80401040, + 0x80000040, 0x00000000, 0x00000000, 0x00401000, + 0x00001040, 0x00400040, 0x80400040, 0x80000000, + 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x80401040, 0x80000040, 0x80000000, 0x00001000, + 0x80400000, 0x80001000, 0x00401040, 0x80400040, + 0x80001000, 0x00001040, 0x00400000, 0x80401000, + 0x00000040, 0x00400000, 0x00001000, 0x00401040 +}; + +static const uint32_t S5[] = { + 0x00000080, 0x01040080, 0x01040000, 0x21000080, + 0x00040000, 0x00000080, 0x20000000, 0x01040000, + 0x20040080, 0x00040000, 0x01000080, 0x20040080, + 0x21000080, 0x21040000, 0x00040080, 0x20000000, + 0x01000000, 0x20040000, 0x20040000, 0x00000000, + 0x20000080, 0x21040080, 0x21040080, 0x01000080, + 0x21040000, 0x20000080, 0x00000000, 0x21000000, + 0x01040080, 0x01000000, 0x21000000, 0x00040080, + 0x00040000, 0x21000080, 0x00000080, 0x01000000, + 0x20000000, 0x01040000, 0x21000080, 0x20040080, + 0x01000080, 0x20000000, 0x21040000, 0x01040080, + 0x20040080, 0x00000080, 0x01000000, 0x21040000, + 0x21040080, 0x00040080, 0x21000000, 0x21040080, + 0x01040000, 0x00000000, 0x20040000, 0x21000000, + 0x00040080, 0x01000080, 0x20000080, 0x00040000, + 0x00000000, 0x20040000, 0x01040080, 0x20000080 +}; + +static const uint32_t S6[] = { + 0x10000008, 0x10200000, 0x00002000, 0x10202008, + 0x10200000, 0x00000008, 0x10202008, 0x00200000, + 0x10002000, 0x00202008, 0x00200000, 0x10000008, + 0x00200008, 0x10002000, 0x10000000, 0x00002008, + 0x00000000, 0x00200008, 0x10002008, 0x00002000, + 0x00202000, 0x10002008, 0x00000008, 0x10200008, + 0x10200008, 0x00000000, 0x00202008, 0x10202000, + 0x00002008, 0x00202000, 0x10202000, 0x10000000, + 0x10002000, 0x00000008, 0x10200008, 0x00202000, + 0x10202008, 0x00200000, 0x00002008, 0x10000008, + 0x00200000, 0x10002000, 0x10000000, 0x00002008, + 0x10000008, 0x10202008, 0x00202000, 0x10200000, + 0x00202008, 0x10202000, 0x00000000, 0x10200008, + 0x00000008, 0x00002000, 0x10200000, 0x00202008, + 0x00002000, 0x00200008, 0x10002008, 0x00000000, + 0x10202000, 0x10000000, 0x00200008, 0x10002008 +}; + +static const uint32_t S7[] = { + 0x00100000, 0x02100001, 0x02000401, 0x00000000, + 0x00000400, 0x02000401, 0x00100401, 0x02100400, + 0x02100401, 0x00100000, 0x00000000, 0x02000001, + 0x00000001, 0x02000000, 0x02100001, 0x00000401, + 0x02000400, 0x00100401, 0x00100001, 0x02000400, + 0x02000001, 0x02100000, 0x02100400, 0x00100001, + 0x02100000, 0x00000400, 0x00000401, 0x02100401, + 0x00100400, 0x00000001, 0x02000000, 0x00100400, + 0x02000000, 0x00100400, 0x00100000, 0x02000401, + 0x02000401, 0x02100001, 0x02100001, 0x00000001, + 0x00100001, 0x02000000, 0x02000400, 0x00100000, + 0x02100400, 0x00000401, 0x00100401, 0x02100400, + 0x00000401, 0x02000001, 0x02100401, 0x02100000, + 0x00100400, 0x00000000, 0x00000001, 0x02100401, + 0x00000000, 0x00100401, 0x02100000, 0x00000400, + 0x02000001, 0x02000400, 0x00000400, 0x00100001 +}; + +static const uint32_t S8[] = { + 0x08000820, 0x00000800, 0x00020000, 0x08020820, + 0x08000000, 0x08000820, 0x00000020, 0x08000000, + 0x00020020, 0x08020000, 0x08020820, 0x00020800, + 0x08020800, 0x00020820, 0x00000800, 0x00000020, + 0x08020000, 0x08000020, 0x08000800, 0x00000820, + 0x00020800, 0x00020020, 0x08020020, 0x08020800, + 0x00000820, 0x00000000, 0x00000000, 0x08020020, + 0x08000020, 0x08000800, 0x00020820, 0x00020000, + 0x00020820, 0x00020000, 0x08020800, 0x00000800, + 0x00000020, 0x08020020, 0x00000800, 0x00020820, + 0x08000800, 0x00000020, 0x08000020, 0x08020000, + 0x08020020, 0x08000000, 0x00020000, 0x08000820, + 0x00000000, 0x08020820, 0x00020020, 0x08000020, + 0x08020000, 0x08000800, 0x08000820, 0x00000000, + 0x08020820, 0x00020800, 0x00020800, 0x00000820, + 0x00000820, 0x00020020, 0x08000000, 0x08020800 +}; + +static inline uint32_t +Fconf(uint32_t r0, uint32_t skl, uint32_t skr) +{ + uint32_t r1; + + r1 = (r0 << 16) | (r0 >> 16); + return + S1[((r1 >> 11) ^ (skl >> 18)) & 0x3F] + | S2[((r0 >> 23) ^ (skl >> 12)) & 0x3F] + | S3[((r0 >> 19) ^ (skl >> 6)) & 0x3F] + | S4[((r0 >> 15) ^ (skl )) & 0x3F] + | S5[((r0 >> 11) ^ (skr >> 18)) & 0x3F] + | S6[((r0 >> 7) ^ (skr >> 12)) & 0x3F] + | S7[((r0 >> 3) ^ (skr >> 6)) & 0x3F] + | S8[((r1 >> 15) ^ (skr )) & 0x3F]; +} + +static void +process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *skey) +{ + int i; + uint32_t l, r; + + l = *pl; + r = *pr; + for (i = 0; i < 16; i ++) { + uint32_t t; + + t = l ^ Fconf(r, skey[(i << 1) + 0], skey[(i << 1) + 1]); + l = r; + r = t; + } + *pl = r; + *pr = l; +} + +/* see inner.h */ +void +br_des_tab_process_block(unsigned num_rounds, const uint32_t *skey, void *block) +{ + unsigned char *buf; + uint32_t l, r; + + buf = block; + l = br_dec32be(buf); + r = br_dec32be(buf + 4); + br_des_do_IP(&l, &r); + while (num_rounds -- > 0) { + process_block_unit(&l, &r, skey); + skey += 32; + } + br_des_do_invIP(&l, &r); + br_enc32be(buf, l); + br_enc32be(buf + 4, r); +} + +static void +keysched_unit(uint32_t *skey, const void *key) +{ + int i; + + br_des_keysched_unit(skey, key); + + /* + * Apply PC-2 to get the 48-bit subkeys. + */ + for (i = 0; i < 16; i ++) { + uint32_t xl, xr, ul, ur; + int j; + + xl = skey[(i << 1) + 0]; + xr = skey[(i << 1) + 1]; + ul = 0; + ur = 0; + for (j = 0; j < 28; j ++) { + ul |= (xl & 1) << PC2left[j]; + ur |= (xr & 1) << PC2right[j]; + xl >>= 1; + xr >>= 1; + } + skey[(i << 1) + 0] = ul; + skey[(i << 1) + 1] = ur; + } +} + +/* see inner.h */ +unsigned +br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len) +{ + switch (key_len) { + case 8: + keysched_unit(skey, key); + return 1; + case 16: + keysched_unit(skey, key); + keysched_unit(skey + 32, (const unsigned char *)key + 8); + br_des_rev_skey(skey + 32); + memcpy(skey + 64, skey, 32 * sizeof *skey); + return 3; + default: + keysched_unit(skey, key); + keysched_unit(skey + 32, (const unsigned char *)key + 8); + br_des_rev_skey(skey + 32); + keysched_unit(skey + 64, (const unsigned char *)key + 16); + return 3; + } +} diff --git a/src/bearssl/src/symcipher/des_tab_cbcdec.c b/src/bearssl/src/symcipher/des_tab_cbcdec.c new file mode 100644 index 0000000..e7eabe9 --- /dev/null +++ b/src/bearssl/src/symcipher/des_tab_cbcdec.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_des_tab_cbcdec_vtable; + ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len); + if (len == 8) { + br_des_rev_skey(ctx->skey); + } else { + int i; + + for (i = 0; i < 48; i += 2) { + uint32_t t; + + t = ctx->skey[i]; + ctx->skey[i] = ctx->skey[94 - i]; + ctx->skey[94 - i] = t; + t = ctx->skey[i + 1]; + ctx->skey[i + 1] = ctx->skey[95 - i]; + ctx->skey[95 - i] = t; + } + } +} + +/* see bearssl_block.h */ +void +br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + + ivbuf = iv; + buf = data; + while (len > 0) { + unsigned char tmp[8]; + int i; + + memcpy(tmp, buf, 8); + br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf); + for (i = 0; i < 8; i ++) { + buf[i] ^= ivbuf[i]; + } + memcpy(ivbuf, tmp, 8); + buf += 8; + len -= 8; + } +} + +/* see bearssl_block.h */ +const br_block_cbcdec_class br_des_tab_cbcdec_vtable = { + sizeof(br_des_tab_cbcdec_keys), + 8, + 3, + (void (*)(const br_block_cbcdec_class **, const void *, size_t)) + &br_des_tab_cbcdec_init, + (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t)) + &br_des_tab_cbcdec_run +}; diff --git a/src/bearssl/src/symcipher/des_tab_cbcenc.c b/src/bearssl/src/symcipher/des_tab_cbcenc.c new file mode 100644 index 0000000..3a45ba3 --- /dev/null +++ b/src/bearssl/src/symcipher/des_tab_cbcenc.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_block.h */ +void +br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx, + const void *key, size_t len) +{ + ctx->vtable = &br_des_tab_cbcenc_vtable; + ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len); +} + +/* see bearssl_block.h */ +void +br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx, + void *iv, void *data, size_t len) +{ + unsigned char *buf, *ivbuf; + + ivbuf = iv; + buf = data; + while (len > 0) { + int i; + + for (i = 0; i < 8; i ++) { + buf[i] ^= ivbuf[i]; + } + br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf); + memcpy(ivbuf, buf, 8); + buf += 8; + len -= 8; + } +} + +/* see bearssl_block.h */ +const br_block_cbcenc_class br_des_tab_cbcenc_vtable = { + sizeof(br_des_tab_cbcenc_keys), + 8, + 3, + (void (*)(const br_block_cbcenc_class **, const void *, size_t)) + &br_des_tab_cbcenc_init, + (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t)) + &br_des_tab_cbcenc_run +}; diff --git a/src/bearssl/src/symcipher/poly1305_ctmul.c b/src/bearssl/src/symcipher/poly1305_ctmul.c new file mode 100644 index 0000000..150e610 --- /dev/null +++ b/src/bearssl/src/symcipher/poly1305_ctmul.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Perform the inner processing of blocks for Poly1305. The accumulator + * and the r key are provided as arrays of 26-bit words (these words + * are allowed to have an extra bit, i.e. use 27 bits). + * + * On output, all accumulator words fit on 26 bits, except acc[1], which + * may be slightly larger (but by a very small amount only). + */ +static void +poly1305_inner(uint32_t *acc, const uint32_t *r, const void *data, size_t len) +{ + /* + * Implementation notes: we split the 130-bit values into five + * 26-bit words. This gives us some space for carries. + * + * This code is inspired from the public-domain code available + * on: + * https://github.com/floodyberry/poly1305-donna + * + * Since we compute modulo 2^130-5, the "upper words" become + * low words with a factor of 5; that is, x*2^130 = x*5 mod p. + */ + const unsigned char *buf; + uint32_t a0, a1, a2, a3, a4; + uint32_t r0, r1, r2, r3, r4; + uint32_t u1, u2, u3, u4; + + r0 = r[0]; + r1 = r[1]; + r2 = r[2]; + r3 = r[3]; + r4 = r[4]; + + u1 = r1 * 5; + u2 = r2 * 5; + u3 = r3 * 5; + u4 = r4 * 5; + + a0 = acc[0]; + a1 = acc[1]; + a2 = acc[2]; + a3 = acc[3]; + a4 = acc[4]; + + buf = data; + while (len > 0) { + uint64_t w0, w1, w2, w3, w4; + uint64_t c; + unsigned char tmp[16]; + + /* + * If there is a partial block, right-pad it with zeros. + */ + if (len < 16) { + memset(tmp, 0, sizeof tmp); + memcpy(tmp, buf, len); + buf = tmp; + len = 16; + } + + /* + * Decode next block and apply the "high bit"; that value + * is added to the accumulator. + */ + a0 += br_dec32le(buf) & 0x03FFFFFF; + a1 += (br_dec32le(buf + 3) >> 2) & 0x03FFFFFF; + a2 += (br_dec32le(buf + 6) >> 4) & 0x03FFFFFF; + a3 += (br_dec32le(buf + 9) >> 6) & 0x03FFFFFF; + a4 += (br_dec32le(buf + 12) >> 8) | 0x01000000; + + /* + * Compute multiplication. + */ +#define M(x, y) ((uint64_t)(x) * (uint64_t)(y)) + + w0 = M(a0, r0) + M(a1, u4) + M(a2, u3) + M(a3, u2) + M(a4, u1); + w1 = M(a0, r1) + M(a1, r0) + M(a2, u4) + M(a3, u3) + M(a4, u2); + w2 = M(a0, r2) + M(a1, r1) + M(a2, r0) + M(a3, u4) + M(a4, u3); + w3 = M(a0, r3) + M(a1, r2) + M(a2, r1) + M(a3, r0) + M(a4, u4); + w4 = M(a0, r4) + M(a1, r3) + M(a2, r2) + M(a3, r1) + M(a4, r0); + +#undef M + /* + * Perform some (partial) modular reduction. This step is + * enough to keep values in ranges such that there won't + * be carry overflows. Most of the reduction was done in + * the multiplication step (by using the 'u*' values, and + * using the fact that 2^130 = -5 mod p); here we perform + * some carry propagation. + */ + c = w0 >> 26; + a0 = (uint32_t)w0 & 0x3FFFFFF; + w1 += c; + c = w1 >> 26; + a1 = (uint32_t)w1 & 0x3FFFFFF; + w2 += c; + c = w2 >> 26; + a2 = (uint32_t)w2 & 0x3FFFFFF; + w3 += c; + c = w3 >> 26; + a3 = (uint32_t)w3 & 0x3FFFFFF; + w4 += c; + c = w4 >> 26; + a4 = (uint32_t)w4 & 0x3FFFFFF; + a0 += (uint32_t)c * 5; + a1 += a0 >> 26; + a0 &= 0x3FFFFFF; + + buf += 16; + len -= 16; + } + + acc[0] = a0; + acc[1] = a1; + acc[2] = a2; + acc[3] = a3; + acc[4] = a4; +} + +/* see bearssl_block.h */ +void +br_poly1305_ctmul_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt) +{ + unsigned char pkey[32], foot[16]; + uint32_t r[5], acc[5], cc, ctl, hi; + uint64_t w; + int i; + + /* + * Compute the MAC key. The 'r' value is the first 16 bytes of + * pkey[]. + */ + memset(pkey, 0, sizeof pkey); + ichacha(key, iv, 0, pkey, sizeof pkey); + + /* + * If encrypting, ChaCha20 must run first, followed by Poly1305. + * When decrypting, the operations are reversed. + */ + if (encrypt) { + ichacha(key, iv, 1, data, len); + } + + /* + * Run Poly1305. We must process the AAD, then ciphertext, then + * the footer (with the lengths). Note that the AAD and ciphertext + * are meant to be padded with zeros up to the next multiple of 16, + * and the length of the footer is 16 bytes as well. + */ + + /* + * Decode the 'r' value into 26-bit words, with the "clamping" + * operation applied. + */ + r[0] = br_dec32le(pkey) & 0x03FFFFFF; + r[1] = (br_dec32le(pkey + 3) >> 2) & 0x03FFFF03; + r[2] = (br_dec32le(pkey + 6) >> 4) & 0x03FFC0FF; + r[3] = (br_dec32le(pkey + 9) >> 6) & 0x03F03FFF; + r[4] = (br_dec32le(pkey + 12) >> 8) & 0x000FFFFF; + + /* + * Accumulator is 0. + */ + memset(acc, 0, sizeof acc); + + /* + * Process the additional authenticated data, ciphertext, and + * footer in due order. + */ + br_enc64le(foot, (uint64_t)aad_len); + br_enc64le(foot + 8, (uint64_t)len); + poly1305_inner(acc, r, aad, aad_len); + poly1305_inner(acc, r, data, len); + poly1305_inner(acc, r, foot, sizeof foot); + + /* + * Finalise modular reduction. This is done with carry propagation + * and applying the '2^130 = -5 mod p' rule. Note that the output + * of poly1035_inner() is already mostly reduced, since only + * acc[1] may be (very slightly) above 2^26. A single loop back + * to acc[1] will be enough to make the value fit in 130 bits. + */ + cc = 0; + for (i = 1; i <= 6; i ++) { + int j; + + j = (i >= 5) ? i - 5 : i; + acc[j] += cc; + cc = acc[j] >> 26; + acc[j] &= 0x03FFFFFF; + } + + /* + * We may still have a value in the 2^130-5..2^130-1 range, in + * which case we must reduce it again. The code below selects, + * in constant-time, between 'acc' and 'acc-p', + */ + ctl = GT(acc[0], 0x03FFFFFA); + for (i = 1; i < 5; i ++) { + ctl &= EQ(acc[i], 0x03FFFFFF); + } + cc = 5; + for (i = 0; i < 5; i ++) { + uint32_t t; + + t = (acc[i] + cc); + cc = t >> 26; + t &= 0x03FFFFFF; + acc[i] = MUX(ctl, t, acc[i]); + } + + /* + * Convert back the accumulator to 32-bit words, and add the + * 's' value (second half of pkey[]). That addition is done + * modulo 2^128. + */ + w = (uint64_t)acc[0] + ((uint64_t)acc[1] << 26) + br_dec32le(pkey + 16); + br_enc32le((unsigned char *)tag, (uint32_t)w); + w = (w >> 32) + ((uint64_t)acc[2] << 20) + br_dec32le(pkey + 20); + br_enc32le((unsigned char *)tag + 4, (uint32_t)w); + w = (w >> 32) + ((uint64_t)acc[3] << 14) + br_dec32le(pkey + 24); + br_enc32le((unsigned char *)tag + 8, (uint32_t)w); + hi = (uint32_t)(w >> 32) + (acc[4] << 8) + br_dec32le(pkey + 28); + br_enc32le((unsigned char *)tag + 12, hi); + + /* + * If decrypting, then ChaCha20 runs _after_ Poly1305. + */ + if (!encrypt) { + ichacha(key, iv, 1, data, len); + } +} diff --git a/src/bearssl/src/symcipher/poly1305_ctmul32.c b/src/bearssl/src/symcipher/poly1305_ctmul32.c new file mode 100644 index 0000000..15d9635 --- /dev/null +++ b/src/bearssl/src/symcipher/poly1305_ctmul32.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Perform the inner processing of blocks for Poly1305. + */ +static void +poly1305_inner(uint32_t *a, const uint32_t *r, const void *data, size_t len) +{ + /* + * Implementation notes: we split the 130-bit values into ten + * 13-bit words. This gives us some space for carries and allows + * using only 32x32->32 multiplications, which are way faster than + * 32x32->64 multiplications on the ARM Cortex-M0/M0+, and also + * help in making constant-time code on the Cortex-M3. + * + * Since we compute modulo 2^130-5, the "upper words" become + * low words with a factor of 5; that is, x*2^130 = x*5 mod p. + * This has already been integrated in the r[] array, which + * is extended to the 0..18 range. + * + * In each loop iteration, a[] and r[] words are 13-bit each, + * except a[1] which may use 14 bits. + */ + const unsigned char *buf; + + buf = data; + while (len > 0) { + unsigned char tmp[16]; + uint32_t b[10]; + unsigned u, v; + uint32_t z, cc1, cc2; + + /* + * If there is a partial block, right-pad it with zeros. + */ + if (len < 16) { + memset(tmp, 0, sizeof tmp); + memcpy(tmp, buf, len); + buf = tmp; + len = 16; + } + + /* + * Decode next block and apply the "high bit"; that value + * is added to the accumulator. + */ + v = br_dec16le(buf); + a[0] += v & 0x01FFF; + v >>= 13; + v |= buf[2] << 3; + v |= buf[3] << 11; + a[1] += v & 0x01FFF; + v >>= 13; + v |= buf[4] << 6; + a[2] += v & 0x01FFF; + v >>= 13; + v |= buf[5] << 1; + v |= buf[6] << 9; + a[3] += v & 0x01FFF; + v >>= 13; + v |= buf[7] << 4; + v |= buf[8] << 12; + a[4] += v & 0x01FFF; + v >>= 13; + v |= buf[9] << 7; + a[5] += v & 0x01FFF; + v >>= 13; + v |= buf[10] << 2; + v |= buf[11] << 10; + a[6] += v & 0x01FFF; + v >>= 13; + v |= buf[12] << 5; + a[7] += v & 0x01FFF; + v = br_dec16le(buf + 13); + a[8] += v & 0x01FFF; + v >>= 13; + v |= buf[15] << 3; + a[9] += v | 0x00800; + + /* + * At that point, all a[] values fit on 14 bits, while + * all r[] values fit on 13 bits. Thus products fit on + * 27 bits, and we can accumulate up to 31 of them in + * a 32-bit word and still have some room for carries. + */ + + /* + * Now a[] contains words with values up to 14 bits each. + * We perform the multiplication with r[]. + * + * The extended words of r[] may be larger than 13 bits + * (they are 5 times a 13-bit word) so the full summation + * may yield values up to 46 times a 27-bit word, which + * does not fit on a 32-bit word. To avoid that issue, we + * must split the loop below in two, with a carry + * propagation operation in the middle. + */ + cc1 = 0; + for (u = 0; u < 10; u ++) { + uint32_t s; + + s = cc1 + + MUL15(a[0], r[u + 9 - 0]) + + MUL15(a[1], r[u + 9 - 1]) + + MUL15(a[2], r[u + 9 - 2]) + + MUL15(a[3], r[u + 9 - 3]) + + MUL15(a[4], r[u + 9 - 4]); + b[u] = s & 0x1FFF; + cc1 = s >> 13; + } + cc2 = 0; + for (u = 0; u < 10; u ++) { + uint32_t s; + + s = b[u] + cc2 + + MUL15(a[5], r[u + 9 - 5]) + + MUL15(a[6], r[u + 9 - 6]) + + MUL15(a[7], r[u + 9 - 7]) + + MUL15(a[8], r[u + 9 - 8]) + + MUL15(a[9], r[u + 9 - 9]); + b[u] = s & 0x1FFF; + cc2 = s >> 13; + } + memcpy(a, b, sizeof b); + + /* + * The two carries "loop back" with a factor of 5. We + * propagate them into a[0] and a[1]. + */ + z = cc1 + cc2; + z += (z << 2) + a[0]; + a[0] = z & 0x1FFF; + a[1] += z >> 13; + + buf += 16; + len -= 16; + } +} + +/* see bearssl_block.h */ +void +br_poly1305_ctmul32_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt) +{ + unsigned char pkey[32], foot[16]; + uint32_t z, r[19], acc[10], cc, ctl; + int i; + + /* + * Compute the MAC key. The 'r' value is the first 16 bytes of + * pkey[]. + */ + memset(pkey, 0, sizeof pkey); + ichacha(key, iv, 0, pkey, sizeof pkey); + + /* + * If encrypting, ChaCha20 must run first, followed by Poly1305. + * When decrypting, the operations are reversed. + */ + if (encrypt) { + ichacha(key, iv, 1, data, len); + } + + /* + * Run Poly1305. We must process the AAD, then ciphertext, then + * the footer (with the lengths). Note that the AAD and ciphertext + * are meant to be padded with zeros up to the next multiple of 16, + * and the length of the footer is 16 bytes as well. + */ + + /* + * Decode the 'r' value into 13-bit words, with the "clamping" + * operation applied. + */ + z = br_dec32le(pkey) & 0x03FFFFFF; + r[9] = z & 0x1FFF; + r[10] = z >> 13; + z = (br_dec32le(pkey + 3) >> 2) & 0x03FFFF03; + r[11] = z & 0x1FFF; + r[12] = z >> 13; + z = (br_dec32le(pkey + 6) >> 4) & 0x03FFC0FF; + r[13] = z & 0x1FFF; + r[14] = z >> 13; + z = (br_dec32le(pkey + 9) >> 6) & 0x03F03FFF; + r[15] = z & 0x1FFF; + r[16] = z >> 13; + z = (br_dec32le(pkey + 12) >> 8) & 0x000FFFFF; + r[17] = z & 0x1FFF; + r[18] = z >> 13; + + /* + * Extend r[] with the 5x factor pre-applied. + */ + for (i = 0; i < 9; i ++) { + r[i] = MUL15(5, r[i + 10]); + } + + /* + * Accumulator is 0. + */ + memset(acc, 0, sizeof acc); + + /* + * Process the additional authenticated data, ciphertext, and + * footer in due order. + */ + br_enc64le(foot, (uint64_t)aad_len); + br_enc64le(foot + 8, (uint64_t)len); + poly1305_inner(acc, r, aad, aad_len); + poly1305_inner(acc, r, data, len); + poly1305_inner(acc, r, foot, sizeof foot); + + /* + * Finalise modular reduction. This is done with carry propagation + * and applying the '2^130 = -5 mod p' rule. Note that the output + * of poly1035_inner() is already mostly reduced, since only + * acc[1] may be (very slightly) above 2^13. A single loop back + * to acc[1] will be enough to make the value fit in 130 bits. + */ + cc = 0; + for (i = 1; i < 10; i ++) { + z = acc[i] + cc; + acc[i] = z & 0x1FFF; + cc = z >> 13; + } + z = acc[0] + cc + (cc << 2); + acc[0] = z & 0x1FFF; + acc[1] += z >> 13; + + /* + * We may still have a value in the 2^130-5..2^130-1 range, in + * which case we must reduce it again. The code below selects, + * in constant-time, between 'acc' and 'acc-p', + */ + ctl = GT(acc[0], 0x1FFA); + for (i = 1; i < 10; i ++) { + ctl &= EQ(acc[i], 0x1FFF); + } + acc[0] = MUX(ctl, acc[0] - 0x1FFB, acc[0]); + for (i = 1; i < 10; i ++) { + acc[i] &= ~(-ctl); + } + + /* + * Convert back the accumulator to 32-bit words, and add the + * 's' value (second half of pkey[]). That addition is done + * modulo 2^128. + */ + z = acc[0] + (acc[1] << 13) + br_dec16le(pkey + 16); + br_enc16le((unsigned char *)tag, z & 0xFFFF); + z = (z >> 16) + (acc[2] << 10) + br_dec16le(pkey + 18); + br_enc16le((unsigned char *)tag + 2, z & 0xFFFF); + z = (z >> 16) + (acc[3] << 7) + br_dec16le(pkey + 20); + br_enc16le((unsigned char *)tag + 4, z & 0xFFFF); + z = (z >> 16) + (acc[4] << 4) + br_dec16le(pkey + 22); + br_enc16le((unsigned char *)tag + 6, z & 0xFFFF); + z = (z >> 16) + (acc[5] << 1) + (acc[6] << 14) + br_dec16le(pkey + 24); + br_enc16le((unsigned char *)tag + 8, z & 0xFFFF); + z = (z >> 16) + (acc[7] << 11) + br_dec16le(pkey + 26); + br_enc16le((unsigned char *)tag + 10, z & 0xFFFF); + z = (z >> 16) + (acc[8] << 8) + br_dec16le(pkey + 28); + br_enc16le((unsigned char *)tag + 12, z & 0xFFFF); + z = (z >> 16) + (acc[9] << 5) + br_dec16le(pkey + 30); + br_enc16le((unsigned char *)tag + 14, z & 0xFFFF); + + /* + * If decrypting, then ChaCha20 runs _after_ Poly1305. + */ + if (!encrypt) { + ichacha(key, iv, 1, data, len); + } +} diff --git a/src/bearssl/src/symcipher/poly1305_ctmulq.c b/src/bearssl/src/symcipher/poly1305_ctmulq.c new file mode 100644 index 0000000..b00683a --- /dev/null +++ b/src/bearssl/src/symcipher/poly1305_ctmulq.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +#if BR_INT128 + +#define MUL128(hi, lo, x, y) do { \ + unsigned __int128 mul128tmp; \ + mul128tmp = (unsigned __int128)(x) * (unsigned __int128)(y); \ + (hi) = (uint64_t)(mul128tmp >> 64); \ + (lo) = (uint64_t)mul128tmp; \ + } while (0) + +#elif BR_UMUL128 + +#include + +#define MUL128(hi, lo, x, y) do { \ + (lo) = _umul128((x), (y), &(hi)); \ + } while (0) + +#endif + +#define MASK42 ((uint64_t)0x000003FFFFFFFFFF) +#define MASK44 ((uint64_t)0x00000FFFFFFFFFFF) + +/* + * The "accumulator" word is nominally a 130-bit value. We split it into + * words of 44 bits, each held in a 64-bit variable. + * + * If the current accumulator is a = a0 + a1*W + a2*W^2 (where W = 2^44) + * and r = r0 + r1*W + r2*W^2, then: + * + * a*r = (a0*r0) + * + (a0*r1 + a1*r0) * W + * + (a0*r2 + a1*r1 + a2*r0) * W^2 + * + (a1*r2 + a2*r1) * W^3 + * + (a2*r2) * W^4 + * + * We want to reduce that value modulo p = 2^130-5, so W^3 = 20 mod p, + * and W^4 = 20*W mod p. Thus, if we define u1 = 20*r1 and u2 = 20*r2, + * then the equations above become: + * + * b0 = a0*r0 + a1*u2 + a2*u1 + * b1 = a0*r1 + a1*r0 + a2*u2 + * b2 = a0*r2 + a1*r1 + a2*r0 + * + * In order to make u1 fit in 44 bits, we can change these equations + * into: + * + * b0 = a0*r0 + a1*u2 + a2*t1 + * b1 = a0*r1 + a1*r0 + a2*t2 + * b2 = a0*r2 + a1*r1 + a2*r0 + * + * Where t1 is u1 truncated to 44 bits, and t2 is u2 added to the extra + * bits of u1. Note that since r is clamped down to a 124-bit value, the + * values u2 and t2 fit on 44 bits too. + * + * The bx values are larger than 44 bits, so we may split them into a + * lower half (cx, 44 bits) and an upper half (dx). The new values for + * the accumulator are then: + * + * e0 = c0 + 20*d2 + * e1 = c1 + d0 + * e2 = c2 + d1 + * + * The equations allow for some room, i.e. the ax values may be larger + * than 44 bits. Similarly, the ex values will usually be larger than + * the ax. Thus, some sort of carry propagation must be done regularly, + * though not necessarily at each iteration. In particular, we do not + * need to compute the additions (for the bx values) over 128-bit + * quantities; we can stick to 64-bit computations. + * + * + * Since the 128-bit result of a 64x64 multiplication is actually + * represented over two 64-bit registers, it is cheaper to arrange for + * any split that happens between the "high" and "low" halves to be on + * that 64-bit boundary. This is done by left shifting the rx, ux and tx + * by 20 bits (since they all fit on 44 bits each, this shift is + * always possible). + */ + +static void +poly1305_inner_big(uint64_t *acc, uint64_t *r, const void *data, size_t len) +{ + +#define MX(hi, lo, m0, m1, m2) do { \ + uint64_t mxhi, mxlo; \ + MUL128(mxhi, mxlo, a0, m0); \ + (hi) = mxhi; \ + (lo) = mxlo >> 20; \ + MUL128(mxhi, mxlo, a1, m1); \ + (hi) += mxhi; \ + (lo) += mxlo >> 20; \ + MUL128(mxhi, mxlo, a2, m2); \ + (hi) += mxhi; \ + (lo) += mxlo >> 20; \ + } while (0) + + const unsigned char *buf; + uint64_t a0, a1, a2; + uint64_t r0, r1, r2, t1, t2, u2; + + r0 = r[0]; + r1 = r[1]; + r2 = r[2]; + t1 = r[3]; + t2 = r[4]; + u2 = r[5]; + a0 = acc[0]; + a1 = acc[1]; + a2 = acc[2]; + buf = data; + + while (len > 0) { + uint64_t v0, v1, v2; + uint64_t c0, c1, c2, d0, d1, d2; + + v0 = br_dec64le(buf + 0); + v1 = br_dec64le(buf + 8); + v2 = v1 >> 24; + v1 = ((v0 >> 44) | (v1 << 20)) & MASK44; + v0 &= MASK44; + a0 += v0; + a1 += v1; + a2 += v2 + ((uint64_t)1 << 40); + MX(d0, c0, r0, u2, t1); + MX(d1, c1, r1, r0, t2); + MX(d2, c2, r2, r1, r0); + a0 = c0 + 20 * d2; + a1 = c1 + d0; + a2 = c2 + d1; + + v0 = br_dec64le(buf + 16); + v1 = br_dec64le(buf + 24); + v2 = v1 >> 24; + v1 = ((v0 >> 44) | (v1 << 20)) & MASK44; + v0 &= MASK44; + a0 += v0; + a1 += v1; + a2 += v2 + ((uint64_t)1 << 40); + MX(d0, c0, r0, u2, t1); + MX(d1, c1, r1, r0, t2); + MX(d2, c2, r2, r1, r0); + a0 = c0 + 20 * d2; + a1 = c1 + d0; + a2 = c2 + d1; + + v0 = br_dec64le(buf + 32); + v1 = br_dec64le(buf + 40); + v2 = v1 >> 24; + v1 = ((v0 >> 44) | (v1 << 20)) & MASK44; + v0 &= MASK44; + a0 += v0; + a1 += v1; + a2 += v2 + ((uint64_t)1 << 40); + MX(d0, c0, r0, u2, t1); + MX(d1, c1, r1, r0, t2); + MX(d2, c2, r2, r1, r0); + a0 = c0 + 20 * d2; + a1 = c1 + d0; + a2 = c2 + d1; + + v0 = br_dec64le(buf + 48); + v1 = br_dec64le(buf + 56); + v2 = v1 >> 24; + v1 = ((v0 >> 44) | (v1 << 20)) & MASK44; + v0 &= MASK44; + a0 += v0; + a1 += v1; + a2 += v2 + ((uint64_t)1 << 40); + MX(d0, c0, r0, u2, t1); + MX(d1, c1, r1, r0, t2); + MX(d2, c2, r2, r1, r0); + a0 = c0 + 20 * d2; + a1 = c1 + d0; + a2 = c2 + d1; + + a1 += a0 >> 44; + a0 &= MASK44; + a2 += a1 >> 44; + a1 &= MASK44; + a0 += 20 * (a2 >> 44); + a2 &= MASK44; + + buf += 64; + len -= 64; + } + acc[0] = a0; + acc[1] = a1; + acc[2] = a2; + +#undef MX +} + +static void +poly1305_inner_small(uint64_t *acc, uint64_t *r, const void *data, size_t len) +{ + const unsigned char *buf; + uint64_t a0, a1, a2; + uint64_t r0, r1, r2, t1, t2, u2; + + r0 = r[0]; + r1 = r[1]; + r2 = r[2]; + t1 = r[3]; + t2 = r[4]; + u2 = r[5]; + a0 = acc[0]; + a1 = acc[1]; + a2 = acc[2]; + buf = data; + + while (len > 0) { + uint64_t v0, v1, v2; + uint64_t c0, c1, c2, d0, d1, d2; + unsigned char tmp[16]; + + if (len < 16) { + memcpy(tmp, buf, len); + memset(tmp + len, 0, (sizeof tmp) - len); + buf = tmp; + len = 16; + } + v0 = br_dec64le(buf + 0); + v1 = br_dec64le(buf + 8); + + v2 = v1 >> 24; + v1 = ((v0 >> 44) | (v1 << 20)) & MASK44; + v0 &= MASK44; + + a0 += v0; + a1 += v1; + a2 += v2 + ((uint64_t)1 << 40); + +#define MX(hi, lo, m0, m1, m2) do { \ + uint64_t mxhi, mxlo; \ + MUL128(mxhi, mxlo, a0, m0); \ + (hi) = mxhi; \ + (lo) = mxlo >> 20; \ + MUL128(mxhi, mxlo, a1, m1); \ + (hi) += mxhi; \ + (lo) += mxlo >> 20; \ + MUL128(mxhi, mxlo, a2, m2); \ + (hi) += mxhi; \ + (lo) += mxlo >> 20; \ + } while (0) + + MX(d0, c0, r0, u2, t1); + MX(d1, c1, r1, r0, t2); + MX(d2, c2, r2, r1, r0); + +#undef MX + + a0 = c0 + 20 * d2; + a1 = c1 + d0; + a2 = c2 + d1; + + a1 += a0 >> 44; + a0 &= MASK44; + a2 += a1 >> 44; + a1 &= MASK44; + a0 += 20 * (a2 >> 44); + a2 &= MASK44; + + buf += 16; + len -= 16; + } + acc[0] = a0; + acc[1] = a1; + acc[2] = a2; +} + +static inline void +poly1305_inner(uint64_t *acc, uint64_t *r, const void *data, size_t len) +{ + if (len >= 64) { + size_t len2; + + len2 = len & ~(size_t)63; + poly1305_inner_big(acc, r, data, len2); + data = (const unsigned char *)data + len2; + len -= len2; + } + if (len > 0) { + poly1305_inner_small(acc, r, data, len); + } +} + +/* see bearssl_block.h */ +void +br_poly1305_ctmulq_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt) +{ + unsigned char pkey[32], foot[16]; + uint64_t r[6], acc[3], r0, r1; + uint32_t v0, v1, v2, v3, v4; + uint64_t w0, w1, w2, w3; + uint32_t ctl; + + /* + * Compute the MAC key. The 'r' value is the first 16 bytes of + * pkey[]. + */ + memset(pkey, 0, sizeof pkey); + ichacha(key, iv, 0, pkey, sizeof pkey); + + /* + * If encrypting, ChaCha20 must run first, followed by Poly1305. + * When decrypting, the operations are reversed. + */ + if (encrypt) { + ichacha(key, iv, 1, data, len); + } + + /* + * Run Poly1305. We must process the AAD, then ciphertext, then + * the footer (with the lengths). Note that the AAD and ciphertext + * are meant to be padded with zeros up to the next multiple of 16, + * and the length of the footer is 16 bytes as well. + */ + + /* + * Apply the "clamping" on r. + */ + pkey[ 3] &= 0x0F; + pkey[ 4] &= 0xFC; + pkey[ 7] &= 0x0F; + pkey[ 8] &= 0xFC; + pkey[11] &= 0x0F; + pkey[12] &= 0xFC; + pkey[15] &= 0x0F; + + /* + * Decode the 'r' value into 44-bit words, left-shifted by 20 bits. + * Also compute the u1 and u2 values. + */ + r0 = br_dec64le(pkey + 0); + r1 = br_dec64le(pkey + 8); + r[0] = r0 << 20; + r[1] = ((r0 >> 24) | (r1 << 40)) & ~(uint64_t)0xFFFFF; + r[2] = (r1 >> 4) & ~(uint64_t)0xFFFFF; + r1 = 20 * (r[1] >> 20); + r[3] = r1 << 20; + r[5] = 20 * r[2]; + r[4] = (r[5] + (r1 >> 24)) & ~(uint64_t)0xFFFFF; + + /* + * Accumulator is 0. + */ + acc[0] = 0; + acc[1] = 0; + acc[2] = 0; + + /* + * Process the additional authenticated data, ciphertext, and + * footer in due order. + */ + br_enc64le(foot, (uint64_t)aad_len); + br_enc64le(foot + 8, (uint64_t)len); + poly1305_inner(acc, r, aad, aad_len); + poly1305_inner(acc, r, data, len); + poly1305_inner_small(acc, r, foot, sizeof foot); + + /* + * Finalise modular reduction. At that point, the value consists + * in three 44-bit values (the lowest one might be slightly above + * 2^44). Two loops shall be sufficient. + */ + acc[1] += (acc[0] >> 44); + acc[0] &= MASK44; + acc[2] += (acc[1] >> 44); + acc[1] &= MASK44; + acc[0] += 5 * (acc[2] >> 42); + acc[2] &= MASK42; + acc[1] += (acc[0] >> 44); + acc[0] &= MASK44; + acc[2] += (acc[1] >> 44); + acc[1] &= MASK44; + acc[0] += 5 * (acc[2] >> 42); + acc[2] &= MASK42; + + /* + * The value may still fall in the 2^130-5..2^130-1 range, in + * which case we must reduce it again. The code below selects, + * in constant-time, between 'acc' and 'acc-p'. We encode the + * value over four 32-bit integers to finish the operation. + */ + v0 = (uint32_t)acc[0]; + v1 = (uint32_t)(acc[0] >> 32) | ((uint32_t)acc[1] << 12); + v2 = (uint32_t)(acc[1] >> 20) | ((uint32_t)acc[2] << 24); + v3 = (uint32_t)(acc[2] >> 8); + v4 = (uint32_t)(acc[2] >> 40); + + ctl = GT(v0, 0xFFFFFFFA); + ctl &= EQ(v1, 0xFFFFFFFF); + ctl &= EQ(v2, 0xFFFFFFFF); + ctl &= EQ(v3, 0xFFFFFFFF); + ctl &= EQ(v4, 0x00000003); + v0 = MUX(ctl, v0 + 5, v0); + v1 = MUX(ctl, 0, v1); + v2 = MUX(ctl, 0, v2); + v3 = MUX(ctl, 0, v3); + + /* + * Add the "s" value. This is done modulo 2^128. Don't forget + * carry propagation... + */ + w0 = (uint64_t)v0 + (uint64_t)br_dec32le(pkey + 16); + w1 = (uint64_t)v1 + (uint64_t)br_dec32le(pkey + 20) + (w0 >> 32); + w2 = (uint64_t)v2 + (uint64_t)br_dec32le(pkey + 24) + (w1 >> 32); + w3 = (uint64_t)v3 + (uint64_t)br_dec32le(pkey + 28) + (w2 >> 32); + v0 = (uint32_t)w0; + v1 = (uint32_t)w1; + v2 = (uint32_t)w2; + v3 = (uint32_t)w3; + + /* + * Encode the tag. + */ + br_enc32le((unsigned char *)tag + 0, v0); + br_enc32le((unsigned char *)tag + 4, v1); + br_enc32le((unsigned char *)tag + 8, v2); + br_enc32le((unsigned char *)tag + 12, v3); + + /* + * If decrypting, then ChaCha20 runs _after_ Poly1305. + */ + if (!encrypt) { + ichacha(key, iv, 1, data, len); + } +} + +/* see bearssl_block.h */ +br_poly1305_run +br_poly1305_ctmulq_get(void) +{ + return &br_poly1305_ctmulq_run; +} + +#else + +/* see bearssl_block.h */ +br_poly1305_run +br_poly1305_ctmulq_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/symcipher/poly1305_i15.c b/src/bearssl/src/symcipher/poly1305_i15.c new file mode 100644 index 0000000..6f89212 --- /dev/null +++ b/src/bearssl/src/symcipher/poly1305_i15.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * This is a "reference" implementation of Poly1305 that uses the + * generic "i15" code for big integers. It is slow, but it handles all + * big-integer operations with generic code, thereby avoiding most + * tricky situations with carry propagation and modular reduction. + */ + +/* + * Modulus: 2^130-5. + */ +static const uint16_t P1305[] = { + 0x008A, + 0x7FFB, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x03FF +}; + +/* + * -p mod 2^15. + */ +#define P0I 0x4CCD + +/* + * R^2 mod p, for conversion to Montgomery representation (R = 2^135, + * since we use 9 words of 15 bits each, and 15*9 = 135). + */ +static const uint16_t R2[] = { + 0x008A, + 0x6400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +/* + * Perform the inner processing of blocks for Poly1305. The "r" array + * is in Montgomery representation, while the "a" array is not. + */ +static void +poly1305_inner(uint16_t *a, const uint16_t *r, const void *data, size_t len) +{ + const unsigned char *buf; + + buf = data; + while (len > 0) { + unsigned char tmp[16], rev[16]; + uint16_t b[10]; + uint32_t ctl; + int i; + + /* + * If there is a partial block, right-pad it with zeros. + */ + if (len < 16) { + memset(tmp, 0, sizeof tmp); + memcpy(tmp, buf, len); + buf = tmp; + len = 16; + } + + /* + * Decode next block and apply the "high bit". Since + * decoding is little-endian, we must byte-swap the buffer. + */ + for (i = 0; i < 16; i ++) { + rev[i] = buf[15 - i]; + } + br_i15_decode_mod(b, rev, sizeof rev, P1305); + b[9] |= 0x0100; + + /* + * Add the accumulator to the decoded block (modular + * addition). + */ + ctl = br_i15_add(b, a, 1); + ctl |= NOT(br_i15_sub(b, P1305, 0)); + br_i15_sub(b, P1305, ctl); + + /* + * Multiply by r, result is the new accumulator value. + */ + br_i15_montymul(a, b, r, P1305, P0I); + + buf += 16; + len -= 16; + } +} + +/* + * Byteswap a 16-byte value. + */ +static void +byteswap16(unsigned char *buf) +{ + int i; + + for (i = 0; i < 8; i ++) { + unsigned x; + + x = buf[i]; + buf[i] = buf[15 - i]; + buf[15 - i] = x; + } +} + +/* see bearssl_block.h */ +void +br_poly1305_i15_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt) +{ + unsigned char pkey[32], foot[16]; + uint16_t t[10], r[10], acc[10]; + + /* + * Compute the MAC key. The 'r' value is the first 16 bytes of + * pkey[]. + */ + memset(pkey, 0, sizeof pkey); + ichacha(key, iv, 0, pkey, sizeof pkey); + + /* + * If encrypting, ChaCha20 must run first, followed by Poly1305. + * When decrypting, the operations are reversed. + */ + if (encrypt) { + ichacha(key, iv, 1, data, len); + } + + /* + * Run Poly1305. We must process the AAD, then ciphertext, then + * the footer (with the lengths). Note that the AAD and ciphertext + * are meant to be padded with zeros up to the next multiple of 16, + * and the length of the footer is 16 bytes as well. + */ + + /* + * Apply the "clamping" operation on the encoded 'r' value. + */ + pkey[ 3] &= 0x0F; + pkey[ 7] &= 0x0F; + pkey[11] &= 0x0F; + pkey[15] &= 0x0F; + pkey[ 4] &= 0xFC; + pkey[ 8] &= 0xFC; + pkey[12] &= 0xFC; + + /* + * Decode the clamped 'r' value. Decoding should use little-endian + * so we must byteswap the value first. + */ + byteswap16(pkey); + br_i15_decode_mod(t, pkey, 16, P1305); + + /* + * Convert 'r' to Montgomery representation. + */ + br_i15_montymul(r, t, R2, P1305, P0I); + + /* + * Accumulator is 0. + */ + br_i15_zero(acc, 0x8A); + + /* + * Process the additional authenticated data, ciphertext, and + * footer in due order. + */ + br_enc64le(foot, (uint64_t)aad_len); + br_enc64le(foot + 8, (uint64_t)len); + poly1305_inner(acc, r, aad, aad_len); + poly1305_inner(acc, r, data, len); + poly1305_inner(acc, r, foot, sizeof foot); + + /* + * Decode the value 's'. Again, a byteswap is needed. + */ + byteswap16(pkey + 16); + br_i15_decode_mod(t, pkey + 16, 16, P1305); + + /* + * Add the value 's' to the accumulator. That addition is done + * modulo 2^128, so we just ignore the carry. + */ + br_i15_add(acc, t, 1); + + /* + * Encode the result (128 low bits) to the tag. Encoding should + * be little-endian. + */ + br_i15_encode(tag, 16, acc); + byteswap16(tag); + + /* + * If decrypting, then ChaCha20 runs _after_ Poly1305. + */ + if (!encrypt) { + ichacha(key, iv, 1, data, len); + } +} diff --git a/src/bearssl/src/x509/asn1.t0 b/src/bearssl/src/x509/asn1.t0 new file mode 100644 index 0000000..ba59252 --- /dev/null +++ b/src/bearssl/src/x509/asn1.t0 @@ -0,0 +1,757 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +\ ======================================================================= + +\ This file contains code which is common to all engines that do some +\ ASN.1 decoding. It should not be compiled on its own, but only along +\ with another file (e.g. x509_minimal.t0) which uses it. +\ +\ Users must define several things: +\ +\ -- In the preamble, a macro called "CTX" that evaluates to the current +\ context structure. +\ +\ -- In the preamble, a macro called "CONTEXT_NAME" that evaluates to the +\ context structure type. This will be invoked during compilation. +\ +\ -- A word called "read8-low" ( -- x ) that reads the next byte, or -1 +\ if the input buffer is empty. That word is usually written in C. +\ +\ -- A word called "read-blob-inner" ( addr len -- addr len ) that is +\ the multi-byte version of read8-low. +\ +\ -- A word called "skip-remaining-inner" ( lim -- lim ) which reads but +\ drops some input bytes. + +preamble { + +#include "inner.h" + +} + +\ Read next source character, skipping blanks. +: skip-blanks begin char dup 32 > if ret then drop again ; + +: fail-oid + "Invalid OID" puts cr exitvm ; + +\ Read a decimal integer, followed by either a dot or whitespace. +\ Note: this does not check for overflows. +: parse-number ( -- val nextchar ) + char decval + begin + char + dup dup `. = swap 32 <= or if ret then + decval swap 10 * + + again ; + +\ Encode a number in unsigned 7E format. +: encode7E ( val -- ) + 0 encode7E-inner ; + +: encode7E-inner ( val eb -- ) + swap dup 0x7F > if + dup 7 u>> 0x80 encode7E-inner 0x7F and + then + or data-add8 ; + +\ Decode an OID from source, and encode it. First byte is length, +\ followed by encoded ASN.1 DER value. The OID is encoded in the +\ current data block. +: OID + \ Get current data address, and push a 0 for length. + current-data 0 data-add8 + \ Skip blanks and get first digit, which must be 0, 1 or 2. + skip-blanks decval dup 2 > if fail-oid then + 40 * + \ Next character must be a dot. + char `. <> if fail-oid then + \ Second group must be one or two digits. + parse-number { nextchar } + dup 40 >= if fail-oid then + + encode7E + \ While next character is a dot, keep encoding numbers. + begin nextchar `. = while + parse-number >nextchar + encode7E + repeat + \ Write back length in the first byte. + dup current-data swap - 1- swap data-set8 + ; immediate + +\ Define a new data word for an encoded OID. The OID is read from the +\ source. +: OID: + new-data-block next-word define-data-word postpone OID ; + +\ Define a word that evaluates to the address of a field within the +\ context. +: addr: + next-word { field } + "addr-" field + 0 1 define-word + 0 8191 "offsetof(CONTEXT_NAME, " field + ")" + make-CX + postpone literal postpone ; ; + +addr: pad + +\ Define a word that evaluates to an error code through a macro name. +: err: + next-word { name } + name 0 1 define-word + 0 63 "BR_" name + make-CX postpone literal postpone ; ; + +err: ERR_X509_INVALID_VALUE +err: ERR_X509_TRUNCATED +err: ERR_X509_EMPTY_CHAIN +err: ERR_X509_INNER_TRUNC +err: ERR_X509_BAD_TAG_CLASS +err: ERR_X509_BAD_TAG_VALUE +err: ERR_X509_INDEFINITE_LENGTH +err: ERR_X509_EXTRA_ELEMENT +err: ERR_X509_UNEXPECTED +err: ERR_X509_NOT_CONSTRUCTED +err: ERR_X509_NOT_PRIMITIVE +err: ERR_X509_PARTIAL_BYTE +err: ERR_X509_BAD_BOOLEAN +err: ERR_X509_OVERFLOW +err: ERR_X509_BAD_DN +err: ERR_X509_BAD_TIME +err: ERR_X509_UNSUPPORTED +err: ERR_X509_LIMIT_EXCEEDED +err: ERR_X509_WRONG_KEY_TYPE +err: ERR_X509_BAD_SIGNATURE +err: ERR_X509_EXPIRED +err: ERR_X509_DN_MISMATCH +err: ERR_X509_BAD_SERVER_NAME +err: ERR_X509_CRITICAL_EXTENSION +err: ERR_X509_NOT_CA +err: ERR_X509_FORBIDDEN_KEY_USAGE +err: ERR_X509_WEAK_PUBLIC_KEY + +: KEYTYPE_RSA CX 0 15 { BR_KEYTYPE_RSA } ; +: KEYTYPE_EC CX 0 15 { BR_KEYTYPE_EC } ; + +cc: fail ( err -- ! ) { + CTX->err = T0_POPi(); + T0_CO(); +} + +\ Read one byte from the stream. +: read8-nc ( -- x ) + begin + read8-low dup 0 >= if ret then + drop co + again ; + +\ Read one byte, enforcing current read limit. +: read8 ( lim -- lim x ) + dup ifnot ERR_X509_INNER_TRUNC fail then + 1- read8-nc ; + +\ Read a 16-bit value, big-endian encoding. +: read16be ( lim -- lim x ) + read8 8 << swap read8 rot + ; + +\ Read a 16-bit value, little-endian encoding. +: read16le ( lim -- lim x ) + read8 swap read8 8 << rot + ; + +\ Read all bytes from the current element, then close it (i.e. drop the +\ limit). Destination address is an offset within the context. +: read-blob ( lim addr -- ) + swap + begin dup while read-blob-inner dup if co then repeat + 2drop ; + +\ Skip remaining bytes in the current structure, but do not close it +\ (thus, this leaves the value 0 on the stack). +: skip-remaining ( lim -- lim ) + begin dup while skip-remaining-inner dup if co then repeat ; + +: skip-remaining-inner ( lim -- lim ) + 0 over read-blob-inner -rot 2drop ; + +cc: set8 ( val addr -- ) { + uint32_t addr = T0_POP(); + *((unsigned char *)CTX + addr) = (unsigned char)T0_POP(); +} + +cc: set16 ( val addr -- ) { + uint32_t addr = T0_POP(); + *(uint16_t *)(void *)((unsigned char *)CTX + addr) = T0_POP(); +} + +cc: set32 ( val addr -- ) { + uint32_t addr = T0_POP(); + *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP(); +} + +cc: get8 ( addr -- val ) { + uint32_t addr = T0_POP(); + T0_PUSH(*((unsigned char *)CTX + addr)); +} + +cc: get16 ( addr -- val ) { + uint32_t addr = T0_POP(); + T0_PUSH(*(uint16_t *)(void *)((unsigned char *)CTX + addr)); +} + +cc: get32 ( addr -- val ) { + uint32_t addr = T0_POP(); + T0_PUSH(*(uint32_t *)(void *)((unsigned char *)CTX + addr)); +} + +\ Read an ASN.1 tag. This function returns the "constructed" status +\ and the tag value. The constructed status is a boolean (-1 for +\ constructed, 0 for primitive). The tag value is either 0 to 31 for +\ a universal tag, or 32+x for a contextual tag of value x. Tag classes +\ "application" and "private" are rejected. Universal tags beyond 30 +\ are rejected. Contextual tags beyond 30 are rejected. Thus, accepted +\ tags will necessarily fit on exactly one byte. This does not support +\ the whole of ASN.1/BER, but is sufficient for certificate parsing. +: read-tag ( lim -- lim constructed value ) + read8 { fb } + + \ Constructed flag is bit 5. + fb 5 >> 0x01 and neg + + \ Class is in bits 6 and 7. Accepted classes are 00 (universal) + \ and 10 (context). We check that bit 6 is 0, and shift back + \ bit 7 so that we get 0 (universal) or 32 (context). + fb 6 >> dup 0x01 and if ERR_X509_BAD_TAG_CLASS fail then + 4 << + + \ Tag value is in bits 0..4. If the value is 31, then this is + \ an extended tag, encoded over subsequent bytes, and we do + \ not support that. + fb 0x1F and dup 0x1F = if ERR_X509_BAD_TAG_VALUE fail then + + ; + +\ Read a tag, but only if not at the end of the current object. If there +\ is no room for another element (limit is zero), then this will push a +\ synthetic "no tag" value (primitive, with value -1). +: read-tag-or-end ( lim -- lim constructed value ) + dup ifnot 0 -1 ret then + read-tag ; + +\ Compare the read tag with the provided value. If equal, then the +\ element is skipped, and a new tag is read (or end of object). +: iftag-skip ( lim constructed value ref -- lim constructed value ) + over = if + 2drop + read-length-open-elt skip-close-elt + read-tag-or-end + then ; + +\ Read an ASN.1 length. This supports only definite lengths (theoretically, +\ certificates may use an indefinite length for the outer structure, using +\ DER only in the TBS, but this never happens in practice, except in a +\ single example certificate from 15 years ago that also fails to decode +\ properly for other reasons). +: read-length ( lim -- lim length ) + read8 + \ Lengths in 0x00..0x7F get encoded as a single byte. + dup 0x80 < if ret then + + \ If the byte is 0x80 then this is an indefinite length, and we + \ do not support that. + 0x80 - dup ifnot ERR_X509_INDEFINITE_LENGTH fail then + + \ Masking out bit 7, this yields the number of bytes over which + \ the value is encoded. Since the total certificate length must + \ fit over 3 bytes (this is a consequence of SSL/TLS message + \ format), we can reject big lengths and keep the length in a + \ single integer. + { n } 0 + begin n 0 > while n 1- >n + dup 0x7FFFFF > if ERR_X509_INNER_TRUNC fail then + 8 << swap read8 rot + + repeat ; + +\ Open a sub-structure. This subtracts the length from the limit, and +\ pushes the length back as new limit. +: open-elt ( lim length -- lim_outer lim_inner ) + dup2 < if ERR_X509_INNER_TRUNC fail then + dup { len } - len ; + +\ Read a length and open the value as a sub-structure. +: read-length-open-elt ( lim -- lim_outer lim_inner ) + read-length open-elt ; + +\ Close a sub-structure. This verifies that there is no remaining +\ element to read. +: close-elt ( lim -- ) + if ERR_X509_EXTRA_ELEMENT fail then ; + +\ Skip remaining bytes in the current structure, then close it. +: skip-close-elt ( lim -- ) + skip-remaining drop ; + +\ Read a length and then skip the value. +: read-length-skip ( lim -- lim ) + read-length-open-elt skip-close-elt ; + +\ Check that a given tag is constructed and has the expected value. +: check-tag-constructed ( constructed value refvalue -- ) + = ifnot ERR_X509_UNEXPECTED fail then + check-constructed ; + +\ Check that the top value is true; report a "not constructed" +\ error otherwise. +: check-constructed ( constructed -- ) + ifnot ERR_X509_NOT_CONSTRUCTED fail then ; + +\ Check that a given tag is primitive and has the expected value. +: check-tag-primitive ( constructed value refvalue -- ) + = ifnot ERR_X509_UNEXPECTED fail then + check-primitive ; + +\ Check that the top value is true; report a "not primitive" +\ error otherwise. +: check-primitive ( constructed -- ) + if ERR_X509_NOT_PRIMITIVE fail then ; + +\ Check that the tag is for a constructed SEQUENCE. +: check-sequence ( constructed value -- ) + 0x10 check-tag-constructed ; + +\ Read a tag, check that it is for a constructed SEQUENCE, and open +\ it as a sub-element. +: read-sequence-open ( lim -- lim_outer lim_inner ) + read-tag check-sequence read-length-open-elt ; + +\ Read the next element as a BIT STRING with no ignore bits, and open +\ it as a sub-element. +: read-bits-open ( lim -- lim_outer lim_inner ) + read-tag 0x03 check-tag-primitive + read-length-open-elt + read8 if ERR_X509_PARTIAL_BYTE fail then ; + +OID: rsaEncryption 1.2.840.113549.1.1.1 + +OID: sha1WithRSAEncryption 1.2.840.113549.1.1.5 +OID: sha224WithRSAEncryption 1.2.840.113549.1.1.14 +OID: sha256WithRSAEncryption 1.2.840.113549.1.1.11 +OID: sha384WithRSAEncryption 1.2.840.113549.1.1.12 +OID: sha512WithRSAEncryption 1.2.840.113549.1.1.13 + +OID: id-sha1 1.3.14.3.2.26 +OID: id-sha224 2.16.840.1.101.3.4.2.4 +OID: id-sha256 2.16.840.1.101.3.4.2.1 +OID: id-sha384 2.16.840.1.101.3.4.2.2 +OID: id-sha512 2.16.840.1.101.3.4.2.3 + +OID: id-ecPublicKey 1.2.840.10045.2.1 + +OID: ansix9p256r1 1.2.840.10045.3.1.7 +OID: ansix9p384r1 1.3.132.0.34 +OID: ansix9p521r1 1.3.132.0.35 + +OID: ecdsa-with-SHA1 1.2.840.10045.4.1 +OID: ecdsa-with-SHA224 1.2.840.10045.4.3.1 +OID: ecdsa-with-SHA256 1.2.840.10045.4.3.2 +OID: ecdsa-with-SHA384 1.2.840.10045.4.3.3 +OID: ecdsa-with-SHA512 1.2.840.10045.4.3.4 + +OID: id-at-commonName 2.5.4.3 + +\ Read a "small value". This assumes that the tag has just been read +\ and processed, but not the length. The first pad byte is set to the +\ value length; the encoded value itself follows. If the value length +\ exceeds 255 bytes, then a single 0 is written in the pad, and this +\ method returns false (0). Otherwise, it returns true (-1). +\ Either way, the element is fully read. +: read-small-value ( lim -- lim bool ) + read-length-open-elt + dup 255 > if skip-close-elt 0 addr-pad set8 0 ret then + dup addr-pad set8 + addr-pad 1+ read-blob + -1 ; + +\ Read an OID as a "small value" (tag, length and value). A boolean +\ value is returned, which is true (-1) if the OID value fits on the pad, +\ false (0) otherwise. +: read-OID ( lim -- lim bool ) + read-tag 0x06 check-tag-primitive read-small-value ; + +\ Read a UTF-8 code point. On error, return 0. Reading a code point of +\ value 0 is considered to be an error. +: read-UTF8 ( lim -- lim val ) + read8 + choice + dup 0x80 < uf ret enduf + dup 0xC0 < uf drop 0 ret enduf + dup 0xE0 < uf 0x1F and 1 read-UTF8-next 0x80 0x7FF enduf + dup 0xF0 < uf 0x0F and 2 read-UTF8-next 0x800 0xFFFF enduf + dup 0xF8 < uf 0x07 and 3 read-UTF8-next 0x10000 0x10FFFF enduf + drop 0 ret + endchoice + between? ifnot drop 0 then + ; + +\ Read n subsequent bytes to complete the provided first byte. The final +\ value is -1 on error, or the code point numerical value. The final +\ value is duplicated. +: read-UTF8-next ( lim val n -- lim val val ) + begin dup while + -rot + read-UTF8-chunk + rot 1- + repeat + drop dup ; + +\ Read one byte, that should be a trailing UTF-8 byte, and complement the +\ current value. On error, value is set to -1. +: read-UTF8-chunk ( lim val -- lim val ) + swap + \ If we are at the end of the value, report an error but don't fail. + dup ifnot 2drop 0 -1 ret then + read8 rot + dup 0< if swap drop ret then 6 << + swap dup 6 >> 2 <> if 2drop -1 ret then + 0x3F and + ; + +: high-surrogate? ( x -- x bool ) + dup 0xD800 0xDBFF between? ; + +: low-surrogate? ( x -- x bool ) + dup 0xDC00 0xDFFF between? ; + +: assemble-surrogate-pair ( hi lim lo -- lim val ) + low-surrogate? ifnot rot 2drop 0 ret then + rot 10 << + 0x35FDC00 - ; + +\ Read a UTF-16 code point (big-endian). Returned value is 0 on error. +: read-UTF16BE ( lim -- lim val ) + read16be + choice + high-surrogate? uf + swap dup ifnot 2drop 0 0 ret then + read16be assemble-surrogate-pair + enduf + low-surrogate? uf + drop 0 + enduf + endchoice ; + +\ Read a UTF-16 code point (little-endian). Returned value is 0 on error. +: read-UTF16LE ( lim -- lim val ) + read16le + choice + high-surrogate? uf + swap dup ifnot 2drop 0 0 ret then + read16le assemble-surrogate-pair + enduf + low-surrogate? uf + drop 0 + enduf + endchoice ; + +\ Add byte to current pad value. Offset is updated, or set to 0 on error. +: pad-append ( off val -- off ) + over dup 0= swap 256 >= or if 2drop 0 ret then + over addr-pad + set8 1+ ; + +\ Add UTF-8 chunk byte to the pad. The 'nn' parameter is the shift count. +: pad-append-UTF8-chunk ( off val nn -- off ) + >> 0x3F and 0x80 or pad-append ; + +\ Test whether a code point is invalid when encoding. This rejects the +\ 66 noncharacters, and also the surrogate range; this function does NOT +\ check that the value is in the 0..10FFFF range. +: valid-unicode? ( val -- bool ) + dup 0xFDD0 0xFEDF between? if drop 0 ret then + dup 0xD800 0xDFFF between? if drop 0 ret then + 0xFFFF and 0xFFFE < ; + +\ Encode a code point in UTF-8. Offset is in the pad; it is updated, or +\ set to 0 on error. Leading BOM are ignored. +: encode-UTF8 ( val off -- off ) + \ Skip leading BOM (U+FEFF when off is 1). + dup2 1 = swap 0xFEFF = and if swap drop ret then + + swap dup { val } + dup valid-unicode? ifnot 2drop 0 ret then + choice + dup 0x80 < uf pad-append enduf + dup 0x800 < uf + 6 >> 0xC0 or pad-append + val 0 pad-append-UTF8-chunk + enduf + dup 0xFFFF < uf + 12 >> 0xE0 or pad-append + val 6 pad-append-UTF8-chunk + val 0 pad-append-UTF8-chunk + enduf + 18 >> 0xF0 or pad-append + val 12 pad-append-UTF8-chunk + val 6 pad-append-UTF8-chunk + val 0 pad-append-UTF8-chunk + endchoice ; + +\ Read a string value into the pad; this function checks that the source +\ characters are UTF-8 and non-zero. The string length (in bytes) is +\ written in the first pad byte. Returned value is true (-1) on success, +\ false (0) on error. +: read-value-UTF8 ( lim -- lim bool ) + read-length-open-elt + 1 { off } + begin dup while + read-UTF8 dup ifnot drop skip-close-elt 0 ret then + off encode-UTF8 >off + repeat + drop off dup ifnot ret then 1- addr-pad set8 -1 ; + +\ Decode a UTF-16 string into the pad. The string is converted to UTF-8, +\ and the length is written in the first pad byte. A leading BOM is +\ honoured (big-endian is assumed if there is no BOM). A code point of +\ value 0 is an error. Returned value is true (-1) on success, false (0) +\ on error. +: read-value-UTF16 ( lim -- lim bool ) + read-length-open-elt + dup ifnot addr-pad set8 -1 ret then + 1 { off } + read-UTF16BE dup 0xFFFE = if + \ Leading BOM, and indicates little-endian. + drop + begin dup while + read-UTF16LE dup ifnot drop skip-close-elt 0 ret then + off encode-UTF8 >off + repeat + else + dup ifnot drop skip-close-elt 0 ret then + \ Big-endian BOM, or no BOM. + begin + off encode-UTF8 >off + dup while + read-UTF16BE dup ifnot drop skip-close-elt 0 ret then + repeat + then + drop off dup ifnot ret then 1- addr-pad set8 -1 ; + +\ Decode a latin-1 string into the pad. The string is converted to UTF-8, +\ and the length is written in the first pad byte. A source byte of +\ value 0 is an error. Returned value is true (-1) on success, false (0) +\ on error. +: read-value-latin1 ( lim -- lim bool ) + read-length-open-elt + 1 { off } + begin dup while + read8 dup ifnot drop skip-close-elt 0 ret then + off encode-UTF8 >off + repeat + drop off dup ifnot ret then 1- addr-pad set8 -1 ; + +\ Read a value and interpret it as an INTEGER or ENUMERATED value. If +\ the integer value does not fit on an unsigned 32-bit value, an error +\ is reported. This function assumes that the tag has just been read +\ and processed, but not the length. +: read-small-int-value ( lim -- lim x ) + read-length-open-elt + dup ifnot ERR_X509_OVERFLOW fail then + read8 dup 0x80 >= if ERR_X509_OVERFLOW fail then + { x } + begin dup while + read8 x dup 0xFFFFFF >= if ERR_X509_OVERFLOW fail then + 8 << + >x + repeat + drop x ; + +\ Compare the OID in the pad with an OID in the constant data block. +\ Returned value is -1 on equality, 0 otherwise. +cc: eqOID ( addrConst -- bool ) { + const unsigned char *a2 = &t0_datablock[T0_POP()]; + const unsigned char *a1 = &CTX->pad[0]; + size_t len = a1[0]; + int x; + if (len == a2[0]) { + x = -(memcmp(a1 + 1, a2 + 1, len) == 0); + } else { + x = 0; + } + T0_PUSH((uint32_t)x); +} + +\ Compare two blobs in the context. Returned value is -1 on equality, 0 +\ otherwise. +cc: eqblob ( addr1 addr2 len -- bool ) { + size_t len = T0_POP(); + const unsigned char *a2 = (const unsigned char *)CTX + T0_POP(); + const unsigned char *a1 = (const unsigned char *)CTX + T0_POP(); + T0_PUSHi(-(memcmp(a1, a2, len) == 0)); +} + +\ Check that a value is in a given range (inclusive). +: between? ( x min max -- bool ) + { min max } dup min >= swap max <= and ; + +\ Convert the provided byte value into a number in the 0..9 range, +\ assuming that it is an ASCII digit. A non-digit triggers an error +\ (a "bad time" error since this is used in date/time decoding). +: digit-dec ( char -- value ) + `0 - dup 0 9 between? ifnot ERR_X509_BAD_TIME fail then ; + +\ Read two ASCII digits and return the value in the 0..99 range. An +\ error is reported if the characters are not ASCII digits. +: read-dec2 ( lim -- lim x ) + read8 digit-dec 10 * { x } read8 digit-dec x + ; + +\ Read two ASCII digits and check that the value is in the provided +\ range (inclusive). +: read-dec2-range ( lim min max -- lim x ) + { min max } + read-dec2 dup min max between? ifnot ERR_X509_BAD_TIME fail then ; + +\ Maximum days in a month and accumulated day count. Each +\ 16-bit value contains the month day count in its lower 5 bits. The first +\ 12 values are for a normal year, the other 12 for a leap year. +data: month-to-days +hexb| 001F 03FC 077F 0B5E 0F1F 12FE 16BF 1A9F 1E7E 223F 261E 29DF | +hexb| 001F 03FD 079F 0B7E 0F3F 131E 16DF 1ABF 1E9E 225F 263E 29FF | + +\ Read a date (UTCTime or GeneralizedTime). The date value is converted +\ to a day count and a second count. The day count starts at 0 for +\ January 1st, 0 AD (that's they year before 1 AD, also known as 1 BC) +\ in a proleptic Gregorian calendar (i.e. Gregorian rules are assumed to +\ extend indefinitely in the past). The second count is between 0 and +\ 86400 (inclusive, in case of a leap second). +: read-date ( lim -- lim days seconds ) + \ Read tag; must be UTCTime or GeneralizedTime. Year count is + \ 4 digits with GeneralizedTime, 2 digits with UTCTime. + read-tag + dup 0x17 0x18 between? ifnot ERR_X509_BAD_TIME fail then + 0x18 = { y4d } + check-primitive + read-length-open-elt + + \ We compute the days and seconds counts during decoding, in + \ order to minimize the number of needed temporary variables. + { ; days seconds x } + + \ Year is 4-digit with GeneralizedTime. With UTCTime, the year + \ is in the 1950..2049 range, and only the last two digits are + \ present in the encoding. + read-dec2 + y4d if + 100 * >x read-dec2 x + + else + dup 50 < if 100 + then 1900 + + then + >x + x 365 * x 3 + 4 / + x 99 + 100 / - x 399 + 400 / + >days + + \ Month is 1..12. Number of days in a months depend on the + \ month and on the year (year count is in x at that point). + 1 12 read-dec2-range + 1- 1 << + x 4 % 0= x 100 % 0<> x 400 % 0= or and if 24 + then + month-to-days + data-get16 + dup 5 >> days + >days + 0x1F and + + \ Day. At this point, the TOS contains the maximum day count for + \ the current month. + 1 swap read-dec2-range + days + 1- >days + + \ Hour, minute and seconds. Count of seconds is allowed to go to + \ 60 in case of leap seconds (in practice, leap seconds really + \ occur only at the very end of the day, so this computation is + \ exact for a real leap second, and a spurious leap second only + \ implies a one-second shift that we can ignore). + 0 23 read-dec2-range 3600 * >seconds + 0 59 read-dec2-range 60 * seconds + >seconds + 0 60 read-dec2-range seconds + >seconds + + \ At this point, we may have fractional seconds. This should + \ happen only with GeneralizedTime, but we accept it for UTCTime + \ too (and, anyway, we ignore these fractional seconds). + read8 dup `. = if + drop + begin read8 dup `0 `9 between? while drop repeat + then + + \ The time zone should be 'Z', not followed by anything. Other + \ time zone indications are not DER and thus not supposed to + \ appear in certificates. + `Z <> if ERR_X509_BAD_TIME fail then + close-elt + days seconds ; + +\ Read an INTEGER (tag, length and value). The INTEGER is supposed to be +\ positive; its unsigned big-endian encoding is stored in the provided +\ in-context buffer. Returned value is the decoded length. If the integer +\ did not fit, or the value is negative, then an error is reported. +: read-integer ( lim addr len -- lim dlen ) + rot read-tag 0x02 check-tag-primitive -rot + read-integer-next ; + +\ Identical to read-integer, but the tag has already been read and checked. +: read-integer-next ( lim addr len -- lim dlen ) + dup { addr len origlen } + read-length-open-elt + \ Read first byte; sign bit must be 0. + read8 dup 0x80 >= if ERR_X509_OVERFLOW fail then + \ Skip leading bytes of value 0. If there are only bytes of + \ value 0, then return. + begin dup 0 = while + drop dup ifnot drop 0 ret then + read8 + repeat + \ At that point, we have the first non-zero byte on the stack. + begin + len dup ifnot ERR_X509_LIMIT_EXCEEDED fail then 1- >len + addr set8 addr 1+ >addr + dup while read8 + repeat + drop origlen len - ; + +\ Read a BOOLEAN value. This should be called immediately after reading +\ the tag. +: read-boolean ( lim constructed value -- lim bool ) + 0x01 check-tag-primitive + read-length 1 <> if ERR_X509_BAD_BOOLEAN fail then + read8 0<> ; + +\ Identify an elliptic curve: read the OID, then check it against the +\ known curve OID. +: read-curve-ID ( lim -- lim curve ) + read-OID ifnot ERR_X509_UNSUPPORTED fail then + choice + ansix9p256r1 eqOID uf 23 enduf + ansix9p384r1 eqOID uf 24 enduf + ansix9p521r1 eqOID uf 25 enduf + ERR_X509_UNSUPPORTED fail + endchoice ; + +\ A convenient debug word: print the current data stack contents. +cc: DEBUG ( -- ) { + extern int printf(const char *fmt, ...); + uint32_t *p; + + printf("dp_stack[0]; p != dp; p ++) { + printf(" %lu", (unsigned long)*p); + } + printf(" >\n"); +} diff --git a/src/bearssl/src/x509/asn1enc.c b/src/bearssl/src/x509/asn1enc.c new file mode 100644 index 0000000..7a74963 --- /dev/null +++ b/src/bearssl/src/x509/asn1enc.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +br_asn1_uint +br_asn1_uint_prepare(const void *xdata, size_t xlen) +{ + const unsigned char *x; + br_asn1_uint t; + + x = xdata; + while (xlen > 0 && *x == 0) { + x ++; + xlen --; + } + t.data = x; + t.len = xlen; + t.asn1len = xlen; + if (xlen == 0 || x[0] >= 0x80) { + t.asn1len ++; + } + return t; +} + +/* see inner.h */ +size_t +br_asn1_encode_length(void *dest, size_t len) +{ + unsigned char *buf; + size_t z; + int i, j; + + buf = dest; + if (len < 0x80) { + if (buf != NULL) { + *buf = len; + } + return 1; + } + i = 0; + for (z = len; z != 0; z >>= 8) { + i ++; + } + if (buf != NULL) { + *buf ++ = 0x80 + i; + for (j = i - 1; j >= 0; j --) { + *buf ++ = len >> (j << 3); + } + } + return i + 1; +} + +/* see inner.h */ +size_t +br_asn1_encode_uint(void *dest, br_asn1_uint pp) +{ + unsigned char *buf; + size_t lenlen; + + if (dest == NULL) { + return 1 + br_asn1_encode_length(NULL, pp.asn1len) + pp.asn1len; + } + buf = dest; + *buf ++ = 0x02; + lenlen = br_asn1_encode_length(buf, pp.asn1len); + buf += lenlen; + *buf = 0x00; + memcpy(buf + pp.asn1len - pp.len, pp.data, pp.len); + return 1 + lenlen + pp.asn1len; +} diff --git a/src/bearssl/src/x509/encode_ec_pk8der.c b/src/bearssl/src/x509/encode_ec_pk8der.c new file mode 100644 index 0000000..53717ce --- /dev/null +++ b/src/bearssl/src/x509/encode_ec_pk8der.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_x509.h */ +size_t +br_encode_ec_pkcs8_der(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk) +{ + /* + * ASN.1 format: + * + * OneAsymmetricKey ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL, + * ..., + * [[2: publicKey [1] PublicKey OPTIONAL ]], + * ... + * } + * + * We don't include attributes or public key (the public key + * is included in the private key value instead). The + * 'version' field is an INTEGER that we will set to 0 + * (meaning 'v1', compatible with previous versions of PKCS#8). + * The 'privateKeyAlgorithm' structure is an AlgorithmIdentifier + * whose OID should be id-ecPublicKey, with, as parameters, the + * curve OID. The 'privateKey' is an OCTET STRING, whose value + * is the "raw DER" encoding of the key pair. + */ + + /* + * OID id-ecPublicKey (1.2.840.10045.2.1), DER-encoded (with + * the tag). + */ + static const unsigned char OID_ECPUBKEY[] = { + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 + }; + + size_t len_version, len_privateKeyAlgorithm, len_privateKeyValue; + size_t len_privateKey, len_seq; + const unsigned char *oid; + + oid = br_get_curve_OID(sk->curve); + if (oid == NULL) { + return 0; + } + len_version = 3; + len_privateKeyAlgorithm = 2 + sizeof OID_ECPUBKEY + 2 + oid[0]; + len_privateKeyValue = br_encode_ec_raw_der_inner(NULL, sk, pk, 0); + len_privateKey = 1 + len_of_len(len_privateKeyValue) + + len_privateKeyValue; + len_seq = len_version + len_privateKeyAlgorithm + len_privateKey; + + if (dest == NULL) { + return 1 + len_of_len(len_seq) + len_seq; + } else { + unsigned char *buf; + size_t lenlen; + + buf = dest; + *buf ++ = 0x30; /* SEQUENCE tag */ + lenlen = br_asn1_encode_length(buf, len_seq); + buf += lenlen; + + /* version */ + *buf ++ = 0x02; + *buf ++ = 0x01; + *buf ++ = 0x00; + + /* privateKeyAlgorithm */ + *buf ++ = 0x30; + *buf ++ = (sizeof OID_ECPUBKEY) + 2 + oid[0]; + memcpy(buf, OID_ECPUBKEY, sizeof OID_ECPUBKEY); + buf += sizeof OID_ECPUBKEY; + *buf ++ = 0x06; + memcpy(buf, oid, 1 + oid[0]); + buf += 1 + oid[0]; + + /* privateKey */ + *buf ++ = 0x04; + buf += br_asn1_encode_length(buf, len_privateKeyValue); + br_encode_ec_raw_der_inner(buf, sk, pk, 0); + + return 1 + lenlen + len_seq; + } +} diff --git a/src/bearssl/src/x509/encode_ec_rawder.c b/src/bearssl/src/x509/encode_ec_rawder.c new file mode 100644 index 0000000..5985909 --- /dev/null +++ b/src/bearssl/src/x509/encode_ec_rawder.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +const unsigned char * +br_get_curve_OID(int curve) +{ + static const unsigned char OID_secp256r1[] = { + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 + }; + static const unsigned char OID_secp384r1[] = { + 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22 + }; + static const unsigned char OID_secp521r1[] = { + 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23 + }; + + switch (curve) { + case BR_EC_secp256r1: return OID_secp256r1; + case BR_EC_secp384r1: return OID_secp384r1; + case BR_EC_secp521r1: return OID_secp521r1; + default: + return NULL; + } +} + +/* see inner.h */ +size_t +br_encode_ec_raw_der_inner(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk, + int include_curve_oid) +{ + /* + * ASN.1 format: + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + * + * The tages '[0]' and '[1]' are explicit. The 'ECParameters' + * is a CHOICE; in our case, it will always be an OBJECT IDENTIFIER + * that identifies the curve. + * + * The value of the 'privateKey' field is the raw unsigned big-endian + * encoding of the private key (integer modulo the curve subgroup + * order); there is no INTEGER tag, and the leading bit may be 1. + * Also, leading bytes of value 0x00 are _not_ removed. + * + * The 'publicKey' contents are the raw encoded public key point, + * normally uncompressed (leading byte of value 0x04, followed + * by the unsigned big-endian encodings of the X and Y coordinates, + * padded to the full field length if necessary). + */ + + size_t len_version, len_privateKey, len_parameters, len_publicKey; + size_t len_publicKey_bits, len_seq; + const unsigned char *oid; + + if (include_curve_oid) { + oid = br_get_curve_OID(sk->curve); + if (oid == NULL) { + return 0; + } + } else { + oid = NULL; + } + len_version = 3; + len_privateKey = 1 + len_of_len(sk->xlen) + sk->xlen; + if (include_curve_oid) { + len_parameters = 4 + oid[0]; + } else { + len_parameters = 0; + } + if (pk == NULL) { + len_publicKey = 0; + len_publicKey_bits = 0; + } else { + len_publicKey_bits = 2 + len_of_len(pk->qlen) + pk->qlen; + len_publicKey = 1 + len_of_len(len_publicKey_bits) + + len_publicKey_bits; + } + len_seq = len_version + len_privateKey + len_parameters + len_publicKey; + if (dest == NULL) { + return 1 + len_of_len(len_seq) + len_seq; + } else { + unsigned char *buf; + size_t lenlen; + + buf = dest; + *buf ++ = 0x30; /* SEQUENCE tag */ + lenlen = br_asn1_encode_length(buf, len_seq); + buf += lenlen; + + /* version */ + *buf ++ = 0x02; + *buf ++ = 0x01; + *buf ++ = 0x01; + + /* privateKey */ + *buf ++ = 0x04; + buf += br_asn1_encode_length(buf, sk->xlen); + memcpy(buf, sk->x, sk->xlen); + buf += sk->xlen; + + /* parameters */ + if (include_curve_oid) { + *buf ++ = 0xA0; + *buf ++ = oid[0] + 2; + *buf ++ = 0x06; + memcpy(buf, oid, oid[0] + 1); + buf += oid[0] + 1; + } + + /* publicKey */ + if (pk != NULL) { + *buf ++ = 0xA1; + buf += br_asn1_encode_length(buf, len_publicKey_bits); + *buf ++ = 0x03; + buf += br_asn1_encode_length(buf, pk->qlen + 1); + *buf ++ = 0x00; + memcpy(buf, pk->q, pk->qlen); + /* buf += pk->qlen; */ + } + + return 1 + lenlen + len_seq; + } +} + +/* see bearssl_x509.h */ +size_t +br_encode_ec_raw_der(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk) +{ + return br_encode_ec_raw_der_inner(dest, sk, pk, 1); +} diff --git a/src/bearssl/src/x509/encode_rsa_pk8der.c b/src/bearssl/src/x509/encode_rsa_pk8der.c new file mode 100644 index 0000000..c053503 --- /dev/null +++ b/src/bearssl/src/x509/encode_rsa_pk8der.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_x509.h */ +size_t +br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk, + const br_rsa_public_key *pk, const void *d, size_t dlen) +{ + /* + * ASN.1 format: + * + * OneAsymmetricKey ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL, + * ..., + * [[2: publicKey [1] PublicKey OPTIONAL ]], + * ... + * } + * + * We don't include attributes or public key. The 'version' field + * is an INTEGER that we will set to 0 (meaning 'v1', compatible + * with previous versions of PKCS#8). The 'privateKeyAlgorithm' + * structure is an AlgorithmIdentifier whose OID should be + * rsaEncryption, with NULL parameters. The 'privateKey' is an + * OCTET STRING, whose value is the "raw DER" encoding of the + * key pair. + * + * Since the private key value comes last, this function really + * adds a header, which is mostly fixed (only some lengths have + * to be modified. + */ + + /* + * Concatenation of: + * - DER encoding of an INTEGER of value 0 (the 'version' field) + * - DER encoding of a PrivateKeyAlgorithmIdentifier that uses + * the rsaEncryption OID, and NULL parameters + * - An OCTET STRING tag + */ + static const unsigned char PK8_HEAD[] = { + 0x02, 0x01, 0x00, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x04 + }; + + size_t len_raw, len_seq; + + len_raw = br_encode_rsa_raw_der(NULL, sk, pk, d, dlen); + len_seq = (sizeof PK8_HEAD) + len_of_len(len_raw) + len_raw; + if (dest == NULL) { + return 1 + len_of_len(len_seq) + len_seq; + } else { + unsigned char *buf; + size_t lenlen; + + buf = dest; + *buf ++ = 0x30; /* SEQUENCE tag */ + lenlen = br_asn1_encode_length(buf, len_seq); + buf += lenlen; + + /* version, privateKeyAlgorithm, privateKey tag */ + memcpy(buf, PK8_HEAD, sizeof PK8_HEAD); + buf += sizeof PK8_HEAD; + + /* privateKey */ + buf += br_asn1_encode_length(buf, len_raw); + br_encode_rsa_raw_der(buf, sk, pk, d, dlen); + + return 1 + lenlen + len_seq; + } +} diff --git a/src/bearssl/src/x509/encode_rsa_rawder.c b/src/bearssl/src/x509/encode_rsa_rawder.c new file mode 100644 index 0000000..1a8052b --- /dev/null +++ b/src/bearssl/src/x509/encode_rsa_rawder.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_x509.h */ +size_t +br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk, + const br_rsa_public_key *pk, const void *d, size_t dlen) +{ + /* + * ASN.1 format: + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * The 'version' field is an INTEGER of value 0 (meaning: there + * are exactly two prime factors), and 'otherPrimeInfos' will + * be absent (because there are exactly two prime factors). + */ + + br_asn1_uint num[9]; + size_t u, slen; + + /* + * For all INTEGER values, get the pointer and length for the + * data bytes. + */ + num[0] = br_asn1_uint_prepare(NULL, 0); + num[1] = br_asn1_uint_prepare(pk->n, pk->nlen); + num[2] = br_asn1_uint_prepare(pk->e, pk->elen); + num[3] = br_asn1_uint_prepare(d, dlen); + num[4] = br_asn1_uint_prepare(sk->p, sk->plen); + num[5] = br_asn1_uint_prepare(sk->q, sk->qlen); + num[6] = br_asn1_uint_prepare(sk->dp, sk->dplen); + num[7] = br_asn1_uint_prepare(sk->dq, sk->dqlen); + num[8] = br_asn1_uint_prepare(sk->iq, sk->iqlen); + + /* + * Get the length of the SEQUENCE contents. + */ + slen = 0; + for (u = 0; u < 9; u ++) { + uint32_t ilen; + + ilen = num[u].asn1len; + slen += 1 + len_of_len(ilen) + ilen; + } + + if (dest == NULL) { + return 1 + len_of_len(slen) + slen; + } else { + unsigned char *buf; + size_t lenlen; + + buf = dest; + *buf ++ = 0x30; /* SEQUENCE tag */ + lenlen = br_asn1_encode_length(buf, slen); + buf += lenlen; + for (u = 0; u < 9; u ++) { + buf += br_asn1_encode_uint(buf, num[u]); + } + return 1 + lenlen + slen; + } +} diff --git a/src/bearssl/src/x509/skey_decoder.c b/src/bearssl/src/x509/skey_decoder.c new file mode 100644 index 0000000..f4e43e7 --- /dev/null +++ b/src/bearssl/src/x509/skey_decoder.c @@ -0,0 +1,650 @@ +/* Automatically generated code; do not modify directly. */ + +#include +#include + +typedef struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; +} t0_context; + +static uint32_t +t0_parse7E_unsigned(const unsigned char **p) +{ + uint32_t x; + + x = 0; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + return x; + } + } +} + +static int32_t +t0_parse7E_signed(const unsigned char **p) +{ + int neg; + uint32_t x; + + neg = ((**p) >> 6) & 1; + x = (uint32_t)-neg; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + if (neg) { + return -(int32_t)~x - 1; + } else { + return (int32_t)x; + } + } + } +} + +#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80) +#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F) +#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8) +#define T0_INT1(x) T0_FBYTE(x, 0) +#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) + +/* static const unsigned char t0_datablock[]; */ + + +void br_skey_decoder_init_main(void *t0ctx); + +void br_skey_decoder_run(void *t0ctx); + + + +#include "inner.h" + + + + + +#include "inner.h" + +#define CTX ((br_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu))) +#define CONTEXT_NAME br_skey_decoder_context + +/* see bearssl_x509.h */ +void +br_skey_decoder_init(br_skey_decoder_context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + ctx->cpu.dp = &ctx->dp_stack[0]; + ctx->cpu.rp = &ctx->rp_stack[0]; + br_skey_decoder_init_main(&ctx->cpu); + br_skey_decoder_run(&ctx->cpu); +} + +/* see bearssl_x509.h */ +void +br_skey_decoder_push(br_skey_decoder_context *ctx, + const void *data, size_t len) +{ + ctx->hbuf = data; + ctx->hlen = len; + br_skey_decoder_run(&ctx->cpu); +} + + + +static const unsigned char t0_datablock[] = { + 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x07, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x05, 0x2B, + 0x81, 0x04, 0x00, 0x23 +}; + +static const unsigned char t0_codeblock[] = { + 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x13, + 0x13, 0x00, 0x00, 0x01, T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, + 0x01, T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INVALID_VALUE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01, + T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA), + 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_data)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_type)), 0x00, 0x00, + 0x33, 0x48, 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, pad)), + 0x00, 0x00, 0x01, 0x13, 0x00, 0x00, 0x01, 0x1C, 0x00, 0x00, 0x01, 0x22, + 0x00, 0x00, 0x05, 0x02, 0x2C, 0x16, 0x00, 0x00, 0x06, 0x02, 0x2D, 0x16, + 0x00, 0x00, 0x01, 0x10, 0x3D, 0x00, 0x00, 0x0D, 0x05, 0x02, 0x2F, 0x16, + 0x3A, 0x00, 0x00, 0x0D, 0x05, 0x02, 0x2F, 0x16, 0x3B, 0x00, 0x00, 0x06, + 0x02, 0x27, 0x16, 0x00, 0x01, 0x03, 0x00, 0x54, 0x57, 0x01, 0x02, 0x3E, + 0x55, 0x23, 0x06, 0x02, 0x30, 0x16, 0x57, 0x01, 0x04, 0x3E, 0x02, 0x00, + 0x41, 0x3F, 0x00, 0x02, 0x03, 0x00, 0x53, 0x14, 0x14, 0x03, 0x01, 0x48, + 0x0E, 0x06, 0x02, 0x30, 0x16, 0x33, 0x4C, 0x58, 0x01, 0x7F, 0x19, 0x0D, + 0x06, 0x04, 0x13, 0x13, 0x04, 0x29, 0x01, 0x20, 0x19, 0x0D, 0x06, 0x16, + 0x13, 0x3A, 0x53, 0x4D, 0x02, 0x00, 0x06, 0x09, 0x02, 0x00, 0x0C, 0x06, + 0x02, 0x2A, 0x16, 0x04, 0x02, 0x03, 0x00, 0x3F, 0x04, 0x0D, 0x01, 0x21, + 0x19, 0x0D, 0x06, 0x04, 0x13, 0x3A, 0x04, 0x03, 0x30, 0x16, 0x13, 0x5D, + 0x02, 0x00, 0x05, 0x02, 0x30, 0x16, 0x02, 0x00, 0x02, 0x01, 0x1D, 0x00, + 0x02, 0x53, 0x4B, 0x05, 0x02, 0x30, 0x16, 0x5B, 0x15, 0x06, 0x07, 0x5D, + 0x01, 0x7F, 0x03, 0x01, 0x04, 0x16, 0x46, 0x15, 0x06, 0x10, 0x01, 0x00, + 0x03, 0x01, 0x14, 0x06, 0x03, 0x4D, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00, + 0x04, 0x02, 0x30, 0x16, 0x3F, 0x57, 0x01, 0x04, 0x3E, 0x53, 0x02, 0x01, + 0x06, 0x03, 0x43, 0x04, 0x03, 0x02, 0x00, 0x40, 0x3F, 0x5D, 0x02, 0x01, + 0x06, 0x03, 0x32, 0x04, 0x01, 0x31, 0x00, 0x00, 0x54, 0x57, 0x01, 0x02, + 0x3E, 0x55, 0x06, 0x02, 0x30, 0x16, 0x57, 0x01, 0x02, 0x3E, 0x44, 0x3F, + 0x00, 0x07, 0x35, 0x50, 0x14, 0x05, 0x02, 0x2F, 0x16, 0x23, 0x01, 0x03, + 0x0B, 0x33, 0x17, 0x47, 0x07, 0x03, 0x00, 0x4F, 0x4F, 0x35, 0x4E, 0x14, + 0x14, 0x03, 0x01, 0x03, 0x02, 0x51, 0x14, 0x03, 0x03, 0x02, 0x02, 0x07, + 0x14, 0x03, 0x02, 0x51, 0x14, 0x03, 0x04, 0x02, 0x02, 0x07, 0x14, 0x03, + 0x02, 0x51, 0x14, 0x03, 0x05, 0x02, 0x02, 0x07, 0x14, 0x03, 0x02, 0x51, + 0x03, 0x06, 0x02, 0x00, 0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x02, 0x05, + 0x02, 0x06, 0x1E, 0x00, 0x00, 0x19, 0x19, 0x00, 0x00, 0x01, 0x0B, 0x00, + 0x00, 0x01, 0x00, 0x20, 0x14, 0x06, 0x08, 0x01, 0x01, 0x21, 0x20, 0x22, + 0x20, 0x04, 0x75, 0x13, 0x00, 0x00, 0x01, + T0_INT2(3 * BR_X509_BUFSIZE_KEY), 0x00, 0x01, 0x01, 0x87, 0xFF, 0xFF, + 0x7F, 0x54, 0x57, 0x01, 0x02, 0x3E, 0x55, 0x01, 0x01, 0x0E, 0x06, 0x02, + 0x30, 0x16, 0x57, 0x01, 0x02, 0x19, 0x0D, 0x06, 0x06, 0x13, 0x3B, 0x44, + 0x32, 0x04, 0x1C, 0x01, 0x04, 0x19, 0x0D, 0x06, 0x08, 0x13, 0x3B, 0x01, + 0x00, 0x41, 0x31, 0x04, 0x0E, 0x01, 0x10, 0x19, 0x0D, 0x06, 0x05, 0x13, + 0x3A, 0x42, 0x04, 0x03, 0x30, 0x16, 0x13, 0x03, 0x00, 0x3F, 0x02, 0x00, + 0x34, 0x1F, 0x5A, 0x27, 0x16, 0x00, 0x01, 0x45, 0x0A, 0x06, 0x02, 0x29, + 0x16, 0x14, 0x03, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x57, 0x01, 0x06, + 0x3E, 0x56, 0x00, 0x00, 0x20, 0x14, 0x06, 0x07, 0x1A, 0x14, 0x06, 0x01, + 0x12, 0x04, 0x76, 0x24, 0x00, 0x00, 0x4B, 0x05, 0x02, 0x30, 0x16, 0x37, + 0x15, 0x06, 0x04, 0x01, 0x17, 0x04, 0x12, 0x38, 0x15, 0x06, 0x04, 0x01, + 0x18, 0x04, 0x0A, 0x39, 0x15, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x30, + 0x16, 0x00, 0x00, 0x1C, 0x57, 0x01, 0x02, 0x3E, 0x09, 0x50, 0x00, 0x00, + 0x35, 0x4E, 0x13, 0x00, 0x03, 0x14, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, + 0x53, 0x59, 0x14, 0x01, 0x81, 0x00, 0x0F, 0x06, 0x02, 0x2E, 0x16, 0x14, + 0x01, 0x00, 0x0D, 0x06, 0x0B, 0x13, 0x14, 0x05, 0x04, 0x13, 0x01, 0x00, + 0x00, 0x59, 0x04, 0x6F, 0x02, 0x01, 0x14, 0x05, 0x02, 0x2B, 0x16, 0x23, + 0x03, 0x01, 0x02, 0x02, 0x1F, 0x02, 0x02, 0x22, 0x03, 0x02, 0x14, 0x06, + 0x03, 0x59, 0x04, 0x68, 0x13, 0x02, 0x00, 0x02, 0x01, 0x08, 0x00, 0x00, + 0x14, 0x35, 0x1C, 0x08, 0x20, 0x1C, 0x07, 0x20, 0x4E, 0x00, 0x01, 0x59, + 0x14, 0x01, 0x81, 0x00, 0x0A, 0x06, 0x01, 0x00, 0x01, 0x81, 0x00, 0x08, + 0x14, 0x05, 0x02, 0x28, 0x16, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x0E, 0x06, 0x19, 0x02, 0x00, 0x23, 0x03, 0x00, 0x14, 0x01, 0x83, + 0xFF, 0xFF, 0x7F, 0x0E, 0x06, 0x02, 0x29, 0x16, 0x01, 0x08, 0x0B, 0x20, + 0x59, 0x1C, 0x07, 0x04, 0x60, 0x00, 0x00, 0x52, 0x4A, 0x00, 0x00, 0x57, + 0x3C, 0x53, 0x00, 0x01, 0x53, 0x14, 0x05, 0x02, 0x2E, 0x16, 0x59, 0x14, + 0x01, 0x81, 0x00, 0x0F, 0x06, 0x02, 0x2E, 0x16, 0x03, 0x00, 0x14, 0x06, + 0x16, 0x59, 0x02, 0x00, 0x14, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x0F, 0x06, + 0x02, 0x2E, 0x16, 0x01, 0x08, 0x0B, 0x07, 0x03, 0x00, 0x04, 0x67, 0x13, + 0x02, 0x00, 0x00, 0x00, 0x53, 0x14, 0x01, 0x81, 0x7F, 0x0E, 0x06, 0x08, + 0x5C, 0x01, 0x00, 0x36, 0x1F, 0x01, 0x00, 0x00, 0x14, 0x36, 0x1F, 0x36, + 0x22, 0x4C, 0x01, 0x7F, 0x00, 0x01, 0x59, 0x03, 0x00, 0x02, 0x00, 0x01, + 0x05, 0x10, 0x01, 0x01, 0x11, 0x18, 0x02, 0x00, 0x01, 0x06, 0x10, 0x14, + 0x01, 0x01, 0x11, 0x06, 0x02, 0x25, 0x16, 0x01, 0x04, 0x0B, 0x02, 0x00, + 0x01, 0x1F, 0x11, 0x14, 0x01, 0x1F, 0x0D, 0x06, 0x02, 0x26, 0x16, 0x07, + 0x00, 0x00, 0x14, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x57, 0x00, + 0x00, 0x14, 0x05, 0x02, 0x29, 0x16, 0x23, 0x5A, 0x00, 0x00, 0x1B, 0x14, + 0x01, 0x00, 0x0F, 0x06, 0x01, 0x00, 0x13, 0x12, 0x04, 0x74, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x5D, 0x13, 0x00, 0x00, 0x14, 0x06, 0x07, 0x5E, 0x14, + 0x06, 0x01, 0x12, 0x04, 0x76, 0x00, 0x00, 0x01, 0x00, 0x19, 0x1A, 0x09, + 0x24, 0x00 +}; + +static const uint16_t t0_caddr[] = { + 0, + 5, + 10, + 14, + 18, + 22, + 26, + 30, + 34, + 38, + 42, + 46, + 50, + 54, + 58, + 62, + 66, + 70, + 75, + 80, + 84, + 89, + 93, + 97, + 101, + 107, + 113, + 118, + 126, + 134, + 140, + 163, + 244, + 311, + 329, + 404, + 408, + 412, + 429, + 434, + 505, + 519, + 526, + 540, + 573, + 582, + 587, + 654, + 665, + 721, + 725, + 730, + 778, + 804, + 848, + 859, + 868, + 881, + 885, + 889, + 901 +}; + +#define T0_INTERPRETED 34 + +#define T0_ENTER(ip, rp, slot) do { \ + const unsigned char *t0_newip; \ + uint32_t t0_lnum; \ + t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \ + t0_lnum = t0_parse7E_unsigned(&t0_newip); \ + (rp) += t0_lnum; \ + *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \ + (ip) = t0_newip; \ + } while (0) + +#define T0_DEFENTRY(name, slot) \ +void \ +name(void *ctx) \ +{ \ + t0_context *t0ctx = ctx; \ + t0ctx->ip = &t0_codeblock[0]; \ + T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ +} + +T0_DEFENTRY(br_skey_decoder_init_main, 73) + +#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++) + +void +br_skey_decoder_run(void *t0ctx) +{ + uint32_t *dp, *rp; + const unsigned char *ip; + +#define T0_LOCAL(x) (*(rp - 2 - (x))) +#define T0_POP() (*-- dp) +#define T0_POPi() (*(int32_t *)(-- dp)) +#define T0_PEEK(x) (*(dp - 1 - (x))) +#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x))) +#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0) +#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0) +#define T0_RPOP() (*-- rp) +#define T0_RPOPi() (*(int32_t *)(-- rp)) +#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0) +#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0) +#define T0_ROLL(x) do { \ + size_t t0len = (size_t)(x); \ + uint32_t t0tmp = *(dp - 1 - t0len); \ + memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_SWAP() do { \ + uint32_t t0tmp = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_ROT() do { \ + uint32_t t0tmp = *(dp - 3); \ + *(dp - 3) = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_NROT() do { \ + uint32_t t0tmp = *(dp - 1); \ + *(dp - 1) = *(dp - 2); \ + *(dp - 2) = *(dp - 3); \ + *(dp - 3) = t0tmp; \ +} while (0) +#define T0_PICK(x) do { \ + uint32_t t0depth = (x); \ + T0_PUSH(T0_PEEK(t0depth)); \ +} while (0) +#define T0_CO() do { \ + goto t0_exit; \ +} while (0) +#define T0_RET() goto t0_next + + dp = ((t0_context *)t0ctx)->dp; + rp = ((t0_context *)t0ctx)->rp; + ip = ((t0_context *)t0ctx)->ip; + goto t0_next; + for (;;) { + uint32_t t0x; + + t0_next: + t0x = T0_NEXT(&ip); + if (t0x < T0_INTERPRETED) { + switch (t0x) { + int32_t t0off; + + case 0: /* ret */ + t0x = T0_RPOP(); + rp -= (t0x >> 16); + t0x &= 0xFFFF; + if (t0x == 0) { + ip = NULL; + goto t0_exit; + } + ip = &t0_codeblock[t0x]; + break; + case 1: /* literal constant */ + T0_PUSHi(t0_parse7E_signed(&ip)); + break; + case 2: /* read local */ + T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip))); + break; + case 3: /* write local */ + T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP(); + break; + case 4: /* jump */ + t0off = t0_parse7E_signed(&ip); + ip += t0off; + break; + case 5: /* jump if */ + t0off = t0_parse7E_signed(&ip); + if (T0_POP()) { + ip += t0off; + } + break; + case 6: /* jump if not */ + t0off = t0_parse7E_signed(&ip); + if (!T0_POP()) { + ip += t0off; + } + break; + case 7: { + /* + */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a + b); + + } + break; + case 8: { + /* - */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a - b); + + } + break; + case 9: { + /* -rot */ + T0_NROT(); + } + break; + case 10: { + /* < */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 11: { + /* << */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x << c); + + } + break; + case 12: { + /* <> */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a != b)); + + } + break; + case 13: { + /* = */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a == b)); + + } + break; + case 14: { + /* > */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a > b)); + + } + break; + case 15: { + /* >= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a >= b)); + + } + break; + case 16: { + /* >> */ + + int c = (int)T0_POPi(); + int32_t x = T0_POPi(); + T0_PUSHi(x >> c); + + } + break; + case 17: { + /* and */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a & b); + + } + break; + case 18: { + /* co */ + T0_CO(); + } + break; + case 19: { + /* drop */ + (void)T0_POP(); + } + break; + case 20: { + /* dup */ + T0_PUSH(T0_PEEK(0)); + } + break; + case 21: { + /* eqOID */ + + const unsigned char *a2 = &t0_datablock[T0_POP()]; + const unsigned char *a1 = &CTX->pad[0]; + size_t len = a1[0]; + int x; + if (len == a2[0]) { + x = -(memcmp(a1 + 1, a2 + 1, len) == 0); + } else { + x = 0; + } + T0_PUSH((uint32_t)x); + + } + break; + case 22: { + /* fail */ + + CTX->err = T0_POPi(); + T0_CO(); + + } + break; + case 23: { + /* get8 */ + + uint32_t addr = T0_POP(); + T0_PUSH(*((unsigned char *)CTX + addr)); + + } + break; + case 24: { + /* neg */ + + uint32_t a = T0_POP(); + T0_PUSH(-a); + + } + break; + case 25: { + /* over */ + T0_PUSH(T0_PEEK(1)); + } + break; + case 26: { + /* read-blob-inner */ + + uint32_t len = T0_POP(); + uint32_t addr = T0_POP(); + size_t clen = CTX->hlen; + if (clen > len) { + clen = (size_t)len; + } + if (addr != 0) { + memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); + } + CTX->hbuf += clen; + CTX->hlen -= clen; + T0_PUSH(addr + clen); + T0_PUSH(len - clen); + + } + break; + case 27: { + /* read8-low */ + + if (CTX->hlen == 0) { + T0_PUSHi(-1); + } else { + CTX->hlen --; + T0_PUSH(*CTX->hbuf ++); + } + + } + break; + case 28: { + /* rot */ + T0_ROT(); + } + break; + case 29: { + /* set-ec-key */ + + size_t xlen = T0_POP(); + uint32_t curve = T0_POP(); + CTX->key.ec.curve = curve; + CTX->key.ec.x = CTX->key_data; + CTX->key.ec.xlen = xlen; + + } + break; + case 30: { + /* set-rsa-key */ + + size_t iqlen = T0_POP(); + size_t dqlen = T0_POP(); + size_t dplen = T0_POP(); + size_t qlen = T0_POP(); + size_t plen = T0_POP(); + uint32_t n_bitlen = T0_POP(); + size_t off; + + CTX->key.rsa.n_bitlen = n_bitlen; + CTX->key.rsa.p = CTX->key_data; + CTX->key.rsa.plen = plen; + off = plen; + CTX->key.rsa.q = CTX->key_data + off; + CTX->key.rsa.qlen = qlen; + off += qlen; + CTX->key.rsa.dp = CTX->key_data + off; + CTX->key.rsa.dplen = dplen; + off += dplen; + CTX->key.rsa.dq = CTX->key_data + off; + CTX->key.rsa.dqlen = dqlen; + off += dqlen; + CTX->key.rsa.iq = CTX->key_data + off; + CTX->key.rsa.iqlen = iqlen; + + } + break; + case 31: { + /* set8 */ + + uint32_t addr = T0_POP(); + *((unsigned char *)CTX + addr) = (unsigned char)T0_POP(); + + } + break; + case 32: { + /* swap */ + T0_SWAP(); + } + break; + case 33: { + /* u>> */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x >> c); + + } + break; + } + + } else { + T0_ENTER(ip, rp, t0x); + } + } +t0_exit: + ((t0_context *)t0ctx)->dp = dp; + ((t0_context *)t0ctx)->rp = rp; + ((t0_context *)t0ctx)->ip = ip; +} diff --git a/src/bearssl/src/x509/skey_decoder.t0 b/src/bearssl/src/x509/skey_decoder.t0 new file mode 100644 index 0000000..5b59421 --- /dev/null +++ b/src/bearssl/src/x509/skey_decoder.t0 @@ -0,0 +1,373 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +preamble { + +#include "inner.h" + +#define CTX ((br_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu))) +#define CONTEXT_NAME br_skey_decoder_context + +/* see bearssl_x509.h */ +void +br_skey_decoder_init(br_skey_decoder_context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + ctx->cpu.dp = &ctx->dp_stack[0]; + ctx->cpu.rp = &ctx->rp_stack[0]; + br_skey_decoder_init_main(&ctx->cpu); + br_skey_decoder_run(&ctx->cpu); +} + +/* see bearssl_x509.h */ +void +br_skey_decoder_push(br_skey_decoder_context *ctx, + const void *data, size_t len) +{ + ctx->hbuf = data; + ctx->hlen = len; + br_skey_decoder_run(&ctx->cpu); +} + +} + +addr: key_type +addr: key_data + +cc: read8-low ( -- x ) { + if (CTX->hlen == 0) { + T0_PUSHi(-1); + } else { + CTX->hlen --; + T0_PUSH(*CTX->hbuf ++); + } +} + +cc: read-blob-inner ( addr len -- addr len ) { + uint32_t len = T0_POP(); + uint32_t addr = T0_POP(); + size_t clen = CTX->hlen; + if (clen > len) { + clen = (size_t)len; + } + if (addr != 0) { + memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); + } + CTX->hbuf += clen; + CTX->hlen -= clen; + T0_PUSH(addr + clen); + T0_PUSH(len - clen); +} + +\ Get the length of the key_data buffer. +: len-key_data + CX 0 8191 { 3 * BR_X509_BUFSIZE_KEY } ; + +\ Get the address and length for the key_data buffer. +: addr-len-key_data ( -- addr len ) + addr-key_data len-key_data ; + +\ Set the private key (RSA). +cc: set-rsa-key ( n_bitlen plen qlen dplen dqlen iqlen -- ) { + size_t iqlen = T0_POP(); + size_t dqlen = T0_POP(); + size_t dplen = T0_POP(); + size_t qlen = T0_POP(); + size_t plen = T0_POP(); + uint32_t n_bitlen = T0_POP(); + size_t off; + + CTX->key.rsa.n_bitlen = n_bitlen; + CTX->key.rsa.p = CTX->key_data; + CTX->key.rsa.plen = plen; + off = plen; + CTX->key.rsa.q = CTX->key_data + off; + CTX->key.rsa.qlen = qlen; + off += qlen; + CTX->key.rsa.dp = CTX->key_data + off; + CTX->key.rsa.dplen = dplen; + off += dplen; + CTX->key.rsa.dq = CTX->key_data + off; + CTX->key.rsa.dqlen = dqlen; + off += dqlen; + CTX->key.rsa.iq = CTX->key_data + off; + CTX->key.rsa.iqlen = iqlen; +} + +\ Set the private key (EC). +cc: set-ec-key ( curve xlen -- ) { + size_t xlen = T0_POP(); + uint32_t curve = T0_POP(); + CTX->key.ec.curve = curve; + CTX->key.ec.x = CTX->key_data; + CTX->key.ec.xlen = xlen; +} + +\ Get the bit length for an integer (unsigned). +: int-bit-length ( x -- bitlen ) + 0 swap + begin dup while 1 u>> swap 1+ swap repeat + drop ; + +\ Read an INTEGER into the key_data buffer, but then ignore it. +: read-integer-ignore ( lim -- lim ) + addr-len-key_data read-integer drop ; + +\ Read an INTEGER into the key_data buffer, at the provided offset. +\ Returned value is the integer length (in bytes). +: read-integer-off ( lim off -- lim dlen ) + dup addr-len-key_data rot - swap rot + swap read-integer ; + +\ Decode RSA key, starting with the SEQUENCE tag. +: decode-RSA ( lim -- lim ) + read-sequence-open + + \ Version should be 0. + read-tag 0x02 check-tag-primitive read-small-int-value if + ERR_X509_UNSUPPORTED fail + then + + \ Read tag for the modulus; should be INTEGER. Then use the + \ decode-RSA-next function for the remainder of the key. + read-tag 0x02 check-tag-primitive + decode-RSA-next + + \ Close the SEQUENCE. + close-elt ; + +\ Decode RSA key; the version, and the tag for the modulus, have been +\ read. +: decode-RSA-next ( lim -- lim ) + \ Modulus: we read it but we do not keep it; we merely gather + \ the modulus bit length. + addr-len-key_data read-integer-next + dup ifnot ERR_X509_UNEXPECTED fail then + 1- 3 << addr-key_data get8 int-bit-length + { n_bitlen } + + \ Public exponent: read but skip. + read-integer-ignore + + \ Private exponent: read but skip. + read-integer-ignore + + \ First prime factor. + addr-len-key_data read-integer dup dup { off plen } + + \ Second prime factor. + read-integer-off dup { qlen } off + dup >off + + \ First reduced private exponent. + read-integer-off dup { dplen } off + dup >off + + \ Second reduced private exponent. + read-integer-off dup { dqlen } off + dup >off + + \ CRT coefficient. + read-integer-off { iqlen } + + \ Set RSA key. + n_bitlen plen qlen dplen dqlen iqlen set-rsa-key + + \ The caller will close the sequence, thereby validating that there + \ is no extra field. + ; + +\ Decode an EC key, starting with the SEQUENCE tag. +: decode-EC ( lim curve -- lim ) + { curve } + read-sequence-open + + \ Version should be 1. + read-tag 0x02 check-tag-primitive read-small-int-value 1- if + ERR_X509_UNSUPPORTED fail + then + + \ Read tag for the private key; should be OCTET STRING. Then use the + \ decode-EC-next function for the remainder of the key. + read-tag 0x04 check-tag-primitive + curve decode-EC-next + + \ Close the SEQUENCE. + close-elt ; + +\ Decode an EC key; the version, and the tag for the OCTET STRING, have +\ already been read. The curve ID is provided (0 if unknown). +: decode-EC-next ( lim curve -- lim ) + { curve } + + \ Read the private key proper. + read-length-open-elt + dup dup { xlen } len-key_data > if ERR_X509_UNSUPPORTED fail then + addr-key_data read-blob + + \ Next element might be the curve identifier. + read-tag-or-end + case + + \ End of structure. + -1 of drop endof + + \ Curve parameters; we support only named curves. + 0x20 of + check-constructed read-length-open-elt + read-curve-ID + curve if + curve <> if ERR_X509_INVALID_VALUE fail then + else + >curve + then + close-elt + endof + + \ Public key. We ignore it. + 0x21 of check-constructed endof + + ERR_X509_UNSUPPORTED fail + endcase + skip-remaining + + \ The curve must have been defined one way or another. + curve ifnot ERR_X509_UNSUPPORTED fail then + + \ Set the EC key. + curve xlen set-ec-key + + \ The caller will close the sequence. + ; + +\ Decode a PKCS#8 object. The version and the tag for the AlgorithmIdentifier +\ structure have already been read. This function returns the key type. +: decode-PKCS8-next ( lim -- lim keytype ) + \ Decode the AlgorithmIdentifier. + read-length-open-elt + read-OID ifnot ERR_X509_UNSUPPORTED fail then + { ; is-rsa curve } + choice + rsaEncryption eqOID uf + \ RSA private key. We ignore the parameters. + skip-remaining -1 >is-rsa + enduf + id-ecPublicKey eqOID uf + \ EC private key. Parameters, if present, shall + \ identify the curve. + 0 >is-rsa + dup if read-curve-ID else 0 then >curve + enduf + + ERR_X509_UNSUPPORTED fail + endchoice + close-elt + + \ Open private key value and decode it. + read-tag 0x04 check-tag-primitive + read-length-open-elt + is-rsa if + decode-RSA + else + curve decode-EC + then + close-elt + + \ We ignore any extra field, i.e. attributes or public key. + skip-remaining + + \ Return the key type. + is-rsa if KEYTYPE_RSA else KEYTYPE_EC then + ; + +\ Decode a private key. +: main ( -- ! ) + \ RSA private key format is defined in PKCS#1 (RFC 3447): + \ RSAPrivateKey ::= SEQUENCE { + \ version INTEGER, -- 0 or 1 + \ n INTEGER, + \ e INTEGER, + \ d INTEGER, + \ p INTEGER, + \ q INTEGER, + \ dp INTEGER, + \ dq INTEGER, + \ iq INTEGER, + \ other OtherPrimeInfos OPTIONAL + \ } + \ We do not support keys with more than two primes (these have + \ version 1); thus, we expect the version field to be 0, and + \ the 'other' field to be absent. + \ + \ EC private key format is defined in RFC 5915: + \ ECPrivateKey ::= SEQUENCE { + \ version INTEGER, -- always 1 + \ privateKey OCTET STRING, + \ parameters [0] EXPLICIT OBJECT IDENTIFIER OPTIONAL, + \ publicKey [1] EXPLICIT BIT STRING OPTIONAL + \ } + \ The "parameters" might conceptually be a complex curve description + \ structure but we support only named curves. The private key + \ contents are the unsigned big-endian encoding of the key value, + \ which is exactly what we want. + \ + \ PKCS#8 (unencrypted) is: + \ OneAsymmetricKey ::= SEQUENCE { + \ version INTEGER, -- 0 or 1 + \ algorithm AlgorithmIdentifier, + \ privateKey OCTET STRING, + \ attributes [0] IMPLICIT Attributes OPTIONAL, + \ publicKey [1] IMPLICIT BIT STRING OPTIONAL + \ } + \ The 'publicKey' field is an add-on from RFC 5958 and may be + \ present only if the 'version' is v2 (i.e. has value 1). We + \ ignore it anyway. + + \ An arbitrary upper limit on the private key size. + 0xFFFFFF + + \ Open the outer SEQUENCE. + read-sequence-open + + \ All our schemas begin with a small INTEGER which is either 0 or + \ 1. We don't care which it is. + read-tag 0x02 check-tag-primitive read-small-int-value 1 > if + ERR_X509_UNSUPPORTED fail + then + + \ Get next tag: it should be either an INTEGER (RSA private key), + \ an OCTET STRING (EC private key), or a SEQUENCE (for an + \ AlgorithmIdentifier, in a PKCS#8 object). + read-tag + case + 0x02 of check-primitive decode-RSA-next KEYTYPE_RSA endof + 0x04 of check-primitive 0 decode-EC-next KEYTYPE_EC endof + 0x10 of check-constructed decode-PKCS8-next endof + ERR_X509_UNSUPPORTED fail + endcase + { key-type } + + \ Close the SEQUENCE. + close-elt + + \ Set the key type, which marks the decoding as a success. + key-type addr-key_type set8 + + \ Read one byte, then fail: if the read succeeds, then there is + \ some trailing byte. + read8-nc ERR_X509_EXTRA_ELEMENT fail + ; diff --git a/src/bearssl/src/x509/x509_decoder.c b/src/bearssl/src/x509/x509_decoder.c new file mode 100644 index 0000000..8dd970f --- /dev/null +++ b/src/bearssl/src/x509/x509_decoder.c @@ -0,0 +1,773 @@ +/* Automatically generated code; do not modify directly. */ + +#include +#include + +typedef struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; +} t0_context; + +static uint32_t +t0_parse7E_unsigned(const unsigned char **p) +{ + uint32_t x; + + x = 0; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + return x; + } + } +} + +static int32_t +t0_parse7E_signed(const unsigned char **p) +{ + int neg; + uint32_t x; + + neg = ((**p) >> 6) & 1; + x = (uint32_t)-neg; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + if (neg) { + return -(int32_t)~x - 1; + } else { + return (int32_t)x; + } + } + } +} + +#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80) +#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F) +#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8) +#define T0_INT1(x) T0_FBYTE(x, 0) +#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) + +/* static const unsigned char t0_datablock[]; */ + + +void br_x509_decoder_init_main(void *t0ctx); + +void br_x509_decoder_run(void *t0ctx); + + + +#include "inner.h" + + + + + +#include "inner.h" + +#define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu))) +#define CONTEXT_NAME br_x509_decoder_context + +/* see bearssl_x509.h */ +void +br_x509_decoder_init(br_x509_decoder_context *ctx, + void (*append_dn)(void *ctx, const void *buf, size_t len), + void *append_dn_ctx) +{ + memset(ctx, 0, sizeof *ctx); + /* obsolete + ctx->err = 0; + ctx->hbuf = NULL; + ctx->hlen = 0; + */ + ctx->append_dn = append_dn; + ctx->append_dn_ctx = append_dn_ctx; + ctx->cpu.dp = &ctx->dp_stack[0]; + ctx->cpu.rp = &ctx->rp_stack[0]; + br_x509_decoder_init_main(&ctx->cpu); + br_x509_decoder_run(&ctx->cpu); +} + +/* see bearssl_x509.h */ +void +br_x509_decoder_push(br_x509_decoder_context *ctx, + const void *data, size_t len) +{ + ctx->hbuf = data; + ctx->hlen = len; + br_x509_decoder_run(&ctx->cpu); +} + + + +static const unsigned char t0_datablock[] = { + 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x09, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x01, 0x0C, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, + 0x0D, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, + 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, + 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x04, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x08, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x08, 0x2A, 0x86, 0x48, + 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, + 0x03, 0x04, 0x00, 0x1F, 0x03, 0xFC, 0x07, 0x7F, 0x0B, 0x5E, 0x0F, 0x1F, + 0x12, 0xFE, 0x16, 0xBF, 0x1A, 0x9F, 0x1E, 0x7E, 0x22, 0x3F, 0x26, 0x1E, + 0x29, 0xDF, 0x00, 0x1F, 0x03, 0xFD, 0x07, 0x9F, 0x0B, 0x7E, 0x0F, 0x3F, + 0x13, 0x1E, 0x16, 0xDF, 0x1A, 0xBF, 0x1E, 0x9E, 0x22, 0x5F, 0x26, 0x3E, + 0x29, 0xFF, 0x03, 0x55, 0x1D, 0x13 +}; + +static const unsigned char t0_codeblock[] = { + 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x00, 0x00, 0x1A, 0x1A, 0x00, + 0x00, 0x01, T0_INT1(BR_ERR_X509_BAD_BOOLEAN), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TIME), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_PARTIAL_BYTE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01, + T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA), + 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, copy_dn)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, decoded)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, isCA)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_x509_decoder_context, pkey_data)), 0x01, + T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notafter_days)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notafter_seconds)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notbefore_days)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notbefore_seconds)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, signer_hash_id)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, signer_key_type)), 0x00, 0x00, 0x01, + 0x80, 0x45, 0x00, 0x00, 0x01, 0x80, 0x4E, 0x00, 0x00, 0x01, 0x80, 0x54, + 0x00, 0x00, 0x01, 0x81, 0x36, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x1B, + 0x02, 0x01, 0x13, 0x26, 0x02, 0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, + 0x34, 0x1D, 0x00, 0x00, 0x06, 0x02, 0x35, 0x1D, 0x00, 0x00, 0x01, 0x10, + 0x4F, 0x00, 0x00, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x4C, 0x00, 0x00, 0x11, + 0x05, 0x02, 0x38, 0x1D, 0x4D, 0x00, 0x00, 0x06, 0x02, 0x30, 0x1D, 0x00, + 0x00, 0x1B, 0x19, 0x01, 0x08, 0x0E, 0x26, 0x29, 0x19, 0x09, 0x00, 0x00, + 0x01, 0x30, 0x0A, 0x1B, 0x01, 0x00, 0x01, 0x09, 0x4B, 0x05, 0x02, 0x2F, + 0x1D, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x80, 0x5A, 0x00, 0x00, + 0x01, 0x80, 0x62, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x80, + 0x74, 0x00, 0x00, 0x01, 0x80, 0x7D, 0x00, 0x00, 0x01, 0x3D, 0x00, 0x00, + 0x20, 0x11, 0x06, 0x04, 0x2B, 0x6B, 0x7A, 0x71, 0x00, 0x04, 0x01, 0x00, + 0x3D, 0x25, 0x01, 0x00, 0x3C, 0x25, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x6D, + 0x6D, 0x70, 0x1B, 0x01, 0x20, 0x11, 0x06, 0x11, 0x1A, 0x4C, 0x6B, 0x70, + 0x01, 0x02, 0x50, 0x6E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x39, 0x1D, 0x51, + 0x70, 0x01, 0x02, 0x50, 0x6C, 0x6D, 0x7A, 0x6D, 0x7A, 0x6D, 0x65, 0x43, + 0x24, 0x42, 0x24, 0x65, 0x41, 0x24, 0x40, 0x24, 0x51, 0x01, 0x01, 0x3C, + 0x25, 0x6D, 0x7A, 0x01, 0x00, 0x3C, 0x25, 0x6D, 0x6D, 0x60, 0x05, 0x02, + 0x39, 0x1D, 0x74, 0x1C, 0x06, 0x1C, 0x7A, 0x61, 0x6D, 0x3F, 0x68, 0x03, + 0x00, 0x3F, 0x26, 0x02, 0x00, 0x09, 0x26, 0x02, 0x00, 0x0A, 0x68, 0x03, + 0x01, 0x51, 0x51, 0x02, 0x00, 0x02, 0x01, 0x18, 0x04, 0x1E, 0x5A, 0x1C, + 0x06, 0x18, 0x64, 0x03, 0x02, 0x51, 0x61, 0x1B, 0x03, 0x03, 0x1B, 0x3F, + 0x23, 0x0D, 0x06, 0x02, 0x33, 0x1D, 0x62, 0x02, 0x02, 0x02, 0x03, 0x17, + 0x04, 0x02, 0x39, 0x1D, 0x51, 0x01, 0x00, 0x3E, 0x25, 0x71, 0x01, 0x21, + 0x5B, 0x01, 0x22, 0x5B, 0x1B, 0x01, 0x23, 0x11, 0x06, 0x28, 0x1A, 0x4C, + 0x6B, 0x6D, 0x1B, 0x06, 0x1D, 0x6D, 0x60, 0x1A, 0x70, 0x1B, 0x01, 0x01, + 0x11, 0x06, 0x03, 0x63, 0x1A, 0x70, 0x01, 0x04, 0x50, 0x6B, 0x4A, 0x1C, + 0x06, 0x03, 0x5F, 0x04, 0x01, 0x7B, 0x51, 0x51, 0x04, 0x60, 0x51, 0x51, + 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x1A, 0x51, 0x6D, + 0x60, 0x06, 0x80, 0x63, 0x75, 0x1C, 0x06, 0x06, 0x01, 0x02, 0x3B, 0x04, + 0x80, 0x57, 0x76, 0x1C, 0x06, 0x06, 0x01, 0x03, 0x3B, 0x04, 0x80, 0x4D, + 0x77, 0x1C, 0x06, 0x06, 0x01, 0x04, 0x3B, 0x04, 0x80, 0x43, 0x78, 0x1C, + 0x06, 0x05, 0x01, 0x05, 0x3B, 0x04, 0x3A, 0x79, 0x1C, 0x06, 0x05, 0x01, + 0x06, 0x3B, 0x04, 0x31, 0x55, 0x1C, 0x06, 0x05, 0x01, 0x02, 0x3A, 0x04, + 0x28, 0x56, 0x1C, 0x06, 0x05, 0x01, 0x03, 0x3A, 0x04, 0x1F, 0x57, 0x1C, + 0x06, 0x05, 0x01, 0x04, 0x3A, 0x04, 0x16, 0x58, 0x1C, 0x06, 0x05, 0x01, + 0x05, 0x3A, 0x04, 0x0D, 0x59, 0x1C, 0x06, 0x05, 0x01, 0x06, 0x3A, 0x04, + 0x04, 0x01, 0x00, 0x01, 0x00, 0x04, 0x04, 0x01, 0x00, 0x01, 0x00, 0x46, + 0x25, 0x45, 0x25, 0x7A, 0x61, 0x7A, 0x51, 0x1A, 0x01, 0x01, 0x3D, 0x25, + 0x73, 0x30, 0x1D, 0x00, 0x00, 0x01, 0x81, 0x06, 0x00, 0x01, 0x54, 0x0D, + 0x06, 0x02, 0x32, 0x1D, 0x1B, 0x03, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, + 0x6D, 0x71, 0x1B, 0x01, 0x01, 0x11, 0x06, 0x08, 0x63, 0x01, 0x01, 0x15, + 0x3E, 0x25, 0x04, 0x01, 0x2B, 0x7A, 0x00, 0x00, 0x70, 0x01, 0x06, 0x50, + 0x6F, 0x00, 0x00, 0x70, 0x01, 0x03, 0x50, 0x6B, 0x72, 0x06, 0x02, 0x37, + 0x1D, 0x00, 0x00, 0x26, 0x1B, 0x06, 0x07, 0x21, 0x1B, 0x06, 0x01, 0x16, + 0x04, 0x76, 0x2B, 0x00, 0x00, 0x01, 0x01, 0x50, 0x6A, 0x01, 0x01, 0x10, + 0x06, 0x02, 0x2C, 0x1D, 0x72, 0x27, 0x00, 0x00, 0x60, 0x05, 0x02, 0x39, + 0x1D, 0x47, 0x1C, 0x06, 0x04, 0x01, 0x17, 0x04, 0x12, 0x48, 0x1C, 0x06, + 0x04, 0x01, 0x18, 0x04, 0x0A, 0x49, 0x1C, 0x06, 0x04, 0x01, 0x19, 0x04, + 0x02, 0x39, 0x1D, 0x00, 0x04, 0x70, 0x1B, 0x01, 0x17, 0x01, 0x18, 0x4B, + 0x05, 0x02, 0x2F, 0x1D, 0x01, 0x18, 0x11, 0x03, 0x00, 0x4D, 0x6B, 0x66, + 0x02, 0x00, 0x06, 0x0C, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, 0x66, 0x02, + 0x01, 0x09, 0x04, 0x0E, 0x1B, 0x01, 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80, + 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, 0x01, 0x01, 0x82, + 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02, + 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01, + 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01, + 0x01, 0x01, 0x0C, 0x67, 0x2A, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01, 0x04, + 0x07, 0x28, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, 0x27, 0x02, 0x01, 0x01, + 0x83, 0x10, 0x07, 0x28, 0x1F, 0x15, 0x06, 0x03, 0x01, 0x18, 0x09, 0x5D, + 0x09, 0x52, 0x1B, 0x01, 0x05, 0x14, 0x02, 0x03, 0x09, 0x03, 0x03, 0x01, + 0x1F, 0x15, 0x01, 0x01, 0x26, 0x67, 0x02, 0x03, 0x09, 0x2A, 0x03, 0x03, + 0x01, 0x00, 0x01, 0x17, 0x67, 0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, + 0x00, 0x01, 0x3B, 0x67, 0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, + 0x01, 0x00, 0x01, 0x3C, 0x67, 0x02, 0x02, 0x09, 0x03, 0x02, 0x72, 0x1B, + 0x01, 0x2E, 0x11, 0x06, 0x0D, 0x1A, 0x72, 0x1B, 0x01, 0x30, 0x01, 0x39, + 0x4B, 0x06, 0x03, 0x1A, 0x04, 0x74, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, + 0x2F, 0x1D, 0x51, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x72, 0x53, 0x01, + 0x0A, 0x08, 0x03, 0x00, 0x72, 0x53, 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, + 0x00, 0x03, 0x01, 0x66, 0x1B, 0x02, 0x01, 0x02, 0x00, 0x4B, 0x05, 0x02, + 0x2F, 0x1D, 0x00, 0x00, 0x23, 0x70, 0x01, 0x02, 0x50, 0x0B, 0x69, 0x00, + 0x03, 0x1B, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x6B, 0x72, 0x1B, 0x01, + 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x1B, 0x01, 0x00, 0x11, 0x06, + 0x0B, 0x1A, 0x1B, 0x05, 0x04, 0x1A, 0x01, 0x00, 0x00, 0x72, 0x04, 0x6F, + 0x02, 0x01, 0x1B, 0x05, 0x02, 0x33, 0x1D, 0x2A, 0x03, 0x01, 0x02, 0x02, + 0x25, 0x02, 0x02, 0x29, 0x03, 0x02, 0x1B, 0x06, 0x03, 0x72, 0x04, 0x68, + 0x1A, 0x02, 0x00, 0x02, 0x01, 0x0A, 0x00, 0x01, 0x72, 0x1B, 0x01, 0x81, + 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x1B, 0x05, 0x02, + 0x31, 0x1D, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, + 0x19, 0x02, 0x00, 0x2A, 0x03, 0x00, 0x1B, 0x01, 0x83, 0xFF, 0xFF, 0x7F, + 0x12, 0x06, 0x02, 0x32, 0x1D, 0x01, 0x08, 0x0E, 0x26, 0x72, 0x23, 0x09, + 0x04, 0x60, 0x00, 0x00, 0x6A, 0x5E, 0x00, 0x00, 0x6B, 0x7A, 0x00, 0x00, + 0x70, 0x4E, 0x6B, 0x00, 0x01, 0x6B, 0x1B, 0x05, 0x02, 0x36, 0x1D, 0x72, + 0x1B, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x03, 0x00, 0x1B, + 0x06, 0x16, 0x72, 0x02, 0x00, 0x1B, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, + 0x06, 0x02, 0x36, 0x1D, 0x01, 0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x67, + 0x1A, 0x02, 0x00, 0x00, 0x00, 0x6B, 0x1B, 0x01, 0x81, 0x7F, 0x12, 0x06, + 0x08, 0x7A, 0x01, 0x00, 0x44, 0x25, 0x01, 0x00, 0x00, 0x1B, 0x44, 0x25, + 0x44, 0x29, 0x62, 0x01, 0x7F, 0x00, 0x01, 0x72, 0x03, 0x00, 0x02, 0x00, + 0x01, 0x05, 0x14, 0x01, 0x01, 0x15, 0x1E, 0x02, 0x00, 0x01, 0x06, 0x14, + 0x1B, 0x01, 0x01, 0x15, 0x06, 0x02, 0x2D, 0x1D, 0x01, 0x04, 0x0E, 0x02, + 0x00, 0x01, 0x1F, 0x15, 0x1B, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x2E, 0x1D, + 0x09, 0x00, 0x00, 0x1B, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x70, + 0x00, 0x00, 0x1B, 0x05, 0x02, 0x32, 0x1D, 0x2A, 0x73, 0x00, 0x00, 0x22, + 0x1B, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x1A, 0x16, 0x04, 0x74, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, + 0x01, 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, + 0x7B, 0x1A, 0x00, 0x00, 0x1B, 0x06, 0x07, 0x7C, 0x1B, 0x06, 0x01, 0x16, + 0x04, 0x76, 0x00, 0x00, 0x01, 0x00, 0x20, 0x21, 0x0B, 0x2B, 0x00 +}; + +static const uint16_t t0_caddr[] = { + 0, + 5, + 10, + 15, + 20, + 24, + 28, + 32, + 36, + 40, + 44, + 48, + 52, + 56, + 60, + 64, + 68, + 72, + 76, + 80, + 84, + 88, + 93, + 98, + 103, + 111, + 116, + 121, + 126, + 131, + 136, + 141, + 146, + 151, + 156, + 161, + 166, + 181, + 187, + 193, + 198, + 206, + 214, + 220, + 231, + 246, + 250, + 255, + 260, + 265, + 270, + 275, + 279, + 289, + 620, + 625, + 639, + 659, + 666, + 678, + 692, + 707, + 740, + 960, + 974, + 991, + 1000, + 1067, + 1123, + 1127, + 1131, + 1136, + 1184, + 1210, + 1254, + 1265, + 1274, + 1287, + 1291, + 1295, + 1299, + 1303, + 1307, + 1311, + 1315, + 1327 +}; + +#define T0_INTERPRETED 39 + +#define T0_ENTER(ip, rp, slot) do { \ + const unsigned char *t0_newip; \ + uint32_t t0_lnum; \ + t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \ + t0_lnum = t0_parse7E_unsigned(&t0_newip); \ + (rp) += t0_lnum; \ + *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \ + (ip) = t0_newip; \ + } while (0) + +#define T0_DEFENTRY(name, slot) \ +void \ +name(void *ctx) \ +{ \ + t0_context *t0ctx = ctx; \ + t0ctx->ip = &t0_codeblock[0]; \ + T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ +} + +T0_DEFENTRY(br_x509_decoder_init_main, 92) + +#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++) + +void +br_x509_decoder_run(void *t0ctx) +{ + uint32_t *dp, *rp; + const unsigned char *ip; + +#define T0_LOCAL(x) (*(rp - 2 - (x))) +#define T0_POP() (*-- dp) +#define T0_POPi() (*(int32_t *)(-- dp)) +#define T0_PEEK(x) (*(dp - 1 - (x))) +#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x))) +#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0) +#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0) +#define T0_RPOP() (*-- rp) +#define T0_RPOPi() (*(int32_t *)(-- rp)) +#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0) +#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0) +#define T0_ROLL(x) do { \ + size_t t0len = (size_t)(x); \ + uint32_t t0tmp = *(dp - 1 - t0len); \ + memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_SWAP() do { \ + uint32_t t0tmp = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_ROT() do { \ + uint32_t t0tmp = *(dp - 3); \ + *(dp - 3) = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_NROT() do { \ + uint32_t t0tmp = *(dp - 1); \ + *(dp - 1) = *(dp - 2); \ + *(dp - 2) = *(dp - 3); \ + *(dp - 3) = t0tmp; \ +} while (0) +#define T0_PICK(x) do { \ + uint32_t t0depth = (x); \ + T0_PUSH(T0_PEEK(t0depth)); \ +} while (0) +#define T0_CO() do { \ + goto t0_exit; \ +} while (0) +#define T0_RET() goto t0_next + + dp = ((t0_context *)t0ctx)->dp; + rp = ((t0_context *)t0ctx)->rp; + ip = ((t0_context *)t0ctx)->ip; + goto t0_next; + for (;;) { + uint32_t t0x; + + t0_next: + t0x = T0_NEXT(&ip); + if (t0x < T0_INTERPRETED) { + switch (t0x) { + int32_t t0off; + + case 0: /* ret */ + t0x = T0_RPOP(); + rp -= (t0x >> 16); + t0x &= 0xFFFF; + if (t0x == 0) { + ip = NULL; + goto t0_exit; + } + ip = &t0_codeblock[t0x]; + break; + case 1: /* literal constant */ + T0_PUSHi(t0_parse7E_signed(&ip)); + break; + case 2: /* read local */ + T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip))); + break; + case 3: /* write local */ + T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP(); + break; + case 4: /* jump */ + t0off = t0_parse7E_signed(&ip); + ip += t0off; + break; + case 5: /* jump if */ + t0off = t0_parse7E_signed(&ip); + if (T0_POP()) { + ip += t0off; + } + break; + case 6: /* jump if not */ + t0off = t0_parse7E_signed(&ip); + if (!T0_POP()) { + ip += t0off; + } + break; + case 7: { + /* %25 */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSHi(a % b); + + } + break; + case 8: { + /* * */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a * b); + + } + break; + case 9: { + /* + */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a + b); + + } + break; + case 10: { + /* - */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a - b); + + } + break; + case 11: { + /* -rot */ + T0_NROT(); + } + break; + case 12: { + /* / */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSHi(a / b); + + } + break; + case 13: { + /* < */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 14: { + /* << */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x << c); + + } + break; + case 15: { + /* <= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a <= b)); + + } + break; + case 16: { + /* <> */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a != b)); + + } + break; + case 17: { + /* = */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a == b)); + + } + break; + case 18: { + /* > */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a > b)); + + } + break; + case 19: { + /* >= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a >= b)); + + } + break; + case 20: { + /* >> */ + + int c = (int)T0_POPi(); + int32_t x = T0_POPi(); + T0_PUSHi(x >> c); + + } + break; + case 21: { + /* and */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a & b); + + } + break; + case 22: { + /* co */ + T0_CO(); + } + break; + case 23: { + /* copy-ec-pkey */ + + size_t qlen = T0_POP(); + uint32_t curve = T0_POP(); + CTX->pkey.key_type = BR_KEYTYPE_EC; + CTX->pkey.key.ec.curve = curve; + CTX->pkey.key.ec.q = CTX->pkey_data; + CTX->pkey.key.ec.qlen = qlen; + + } + break; + case 24: { + /* copy-rsa-pkey */ + + size_t elen = T0_POP(); + size_t nlen = T0_POP(); + CTX->pkey.key_type = BR_KEYTYPE_RSA; + CTX->pkey.key.rsa.n = CTX->pkey_data; + CTX->pkey.key.rsa.nlen = nlen; + CTX->pkey.key.rsa.e = CTX->pkey_data + nlen; + CTX->pkey.key.rsa.elen = elen; + + } + break; + case 25: { + /* data-get8 */ + + size_t addr = T0_POP(); + T0_PUSH(t0_datablock[addr]); + + } + break; + case 26: { + /* drop */ + (void)T0_POP(); + } + break; + case 27: { + /* dup */ + T0_PUSH(T0_PEEK(0)); + } + break; + case 28: { + /* eqOID */ + + const unsigned char *a2 = &t0_datablock[T0_POP()]; + const unsigned char *a1 = &CTX->pad[0]; + size_t len = a1[0]; + int x; + if (len == a2[0]) { + x = -(memcmp(a1 + 1, a2 + 1, len) == 0); + } else { + x = 0; + } + T0_PUSH((uint32_t)x); + + } + break; + case 29: { + /* fail */ + + CTX->err = T0_POPi(); + T0_CO(); + + } + break; + case 30: { + /* neg */ + + uint32_t a = T0_POP(); + T0_PUSH(-a); + + } + break; + case 31: { + /* or */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a | b); + + } + break; + case 32: { + /* over */ + T0_PUSH(T0_PEEK(1)); + } + break; + case 33: { + /* read-blob-inner */ + + uint32_t len = T0_POP(); + uint32_t addr = T0_POP(); + size_t clen = CTX->hlen; + if (clen > len) { + clen = (size_t)len; + } + if (addr != 0) { + memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); + } + if (CTX->copy_dn && CTX->append_dn) { + CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen); + } + CTX->hbuf += clen; + CTX->hlen -= clen; + T0_PUSH(addr + clen); + T0_PUSH(len - clen); + + } + break; + case 34: { + /* read8-low */ + + if (CTX->hlen == 0) { + T0_PUSHi(-1); + } else { + unsigned char x = *CTX->hbuf ++; + if (CTX->copy_dn && CTX->append_dn) { + CTX->append_dn(CTX->append_dn_ctx, &x, 1); + } + CTX->hlen --; + T0_PUSH(x); + } + + } + break; + case 35: { + /* rot */ + T0_ROT(); + } + break; + case 36: { + /* set32 */ + + uint32_t addr = T0_POP(); + *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP(); + + } + break; + case 37: { + /* set8 */ + + uint32_t addr = T0_POP(); + *((unsigned char *)CTX + addr) = (unsigned char)T0_POP(); + + } + break; + case 38: { + /* swap */ + T0_SWAP(); + } + break; + } + + } else { + T0_ENTER(ip, rp, t0x); + } + } +t0_exit: + ((t0_context *)t0ctx)->dp = dp; + ((t0_context *)t0ctx)->rp = rp; + ((t0_context *)t0ctx)->ip = ip; +} diff --git a/src/bearssl/src/x509/x509_decoder.t0 b/src/bearssl/src/x509/x509_decoder.t0 new file mode 100644 index 0000000..0bf276f --- /dev/null +++ b/src/bearssl/src/x509/x509_decoder.t0 @@ -0,0 +1,321 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +preamble { + +#include "inner.h" + +#define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu))) +#define CONTEXT_NAME br_x509_decoder_context + +/* see bearssl_x509.h */ +void +br_x509_decoder_init(br_x509_decoder_context *ctx, + void (*append_dn)(void *ctx, const void *buf, size_t len), + void *append_dn_ctx) +{ + memset(ctx, 0, sizeof *ctx); + /* obsolete + ctx->err = 0; + ctx->hbuf = NULL; + ctx->hlen = 0; + */ + ctx->append_dn = append_dn; + ctx->append_dn_ctx = append_dn_ctx; + ctx->cpu.dp = &ctx->dp_stack[0]; + ctx->cpu.rp = &ctx->rp_stack[0]; + br_x509_decoder_init_main(&ctx->cpu); + br_x509_decoder_run(&ctx->cpu); +} + +/* see bearssl_x509.h */ +void +br_x509_decoder_push(br_x509_decoder_context *ctx, + const void *data, size_t len) +{ + ctx->hbuf = data; + ctx->hlen = len; + br_x509_decoder_run(&ctx->cpu); +} + +} + +addr: decoded +addr: notbefore_days +addr: notbefore_seconds +addr: notafter_days +addr: notafter_seconds +addr: isCA +addr: copy_dn +addr: signer_key_type +addr: signer_hash_id + +cc: read8-low ( -- x ) { + if (CTX->hlen == 0) { + T0_PUSHi(-1); + } else { + unsigned char x = *CTX->hbuf ++; + if (CTX->copy_dn && CTX->append_dn) { + CTX->append_dn(CTX->append_dn_ctx, &x, 1); + } + CTX->hlen --; + T0_PUSH(x); + } +} + +cc: read-blob-inner ( addr len -- addr len ) { + uint32_t len = T0_POP(); + uint32_t addr = T0_POP(); + size_t clen = CTX->hlen; + if (clen > len) { + clen = (size_t)len; + } + if (addr != 0) { + memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); + } + if (CTX->copy_dn && CTX->append_dn) { + CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen); + } + CTX->hbuf += clen; + CTX->hlen -= clen; + T0_PUSH(addr + clen); + T0_PUSH(len - clen); +} + +\ Get the address and length for the pkey_data buffer. +: addr-len-pkey_data ( -- addr len ) + CX 0 8191 { offsetof(br_x509_decoder_context, pkey_data) } + CX 0 8191 { BR_X509_BUFSIZE_KEY } ; + +\ Copy the public key (RSA) to the permanent buffer. +cc: copy-rsa-pkey ( nlen elen -- ) { + size_t elen = T0_POP(); + size_t nlen = T0_POP(); + CTX->pkey.key_type = BR_KEYTYPE_RSA; + CTX->pkey.key.rsa.n = CTX->pkey_data; + CTX->pkey.key.rsa.nlen = nlen; + CTX->pkey.key.rsa.e = CTX->pkey_data + nlen; + CTX->pkey.key.rsa.elen = elen; +} + +\ Copy the public key (EC) to the permanent buffer. +cc: copy-ec-pkey ( curve qlen -- ) { + size_t qlen = T0_POP(); + uint32_t curve = T0_POP(); + CTX->pkey.key_type = BR_KEYTYPE_EC; + CTX->pkey.key.ec.curve = curve; + CTX->pkey.key.ec.q = CTX->pkey_data; + CTX->pkey.key.ec.qlen = qlen; +} + +\ Extensions with specific processing. +OID: basicConstraints 2.5.29.19 + +\ Process a Basic Constraints extension. We want the "CA" flag only. +: process-basicConstraints ( lim -- lim ) + read-sequence-open + read-tag-or-end dup 0x01 = if + read-boolean 1 and addr-isCA set8 + else + 2drop + then + skip-close-elt + ; + +\ Decode a certificate. +: main ( -- ! ) + + \ Initialise state flags. + 0 addr-decoded set8 + 0 addr-copy_dn set8 + + \ An arbitrary limit for the total certificate size. + 0xFFFFFF + + \ Open the outer SEQUENCE. + read-sequence-open + + \ TBS + read-sequence-open + + \ First element may be an explicit version. We accept only + \ versions 0 to 2 (certificates v1 to v3). + read-tag dup 0x20 = if + drop check-constructed read-length-open-elt + read-tag + 0x02 check-tag-primitive + read-small-int-value + 2 > if ERR_X509_UNSUPPORTED fail then + close-elt + read-tag + then + + \ Serial number. We just check that the tag is correct. + 0x02 check-tag-primitive read-length-skip + + \ Signature algorithm. + read-sequence-open skip-close-elt + + \ Issuer name. + read-sequence-open skip-close-elt + + \ Validity dates. + read-sequence-open + read-date addr-notbefore_seconds set32 addr-notbefore_days set32 + read-date addr-notafter_seconds set32 addr-notafter_days set32 + close-elt + + \ Subject name. + 1 addr-copy_dn set8 + read-sequence-open skip-close-elt + 0 addr-copy_dn set8 + + \ Public Key. + read-sequence-open + \ Algorithm Identifier. Right now we are only interested in the + \ OID, since we only support RSA keys. + \ TODO: support EC keys + read-sequence-open + read-OID ifnot ERR_X509_UNSUPPORTED fail then + choice + \ RSA public key. + rsaEncryption eqOID uf + skip-close-elt + \ Public key itself: the BIT STRING contains bytes + \ (no partial byte) and these bytes encode the + \ actual value. + read-bits-open + \ RSA public key is a SEQUENCE of two + \ INTEGER. We get both INTEGER values into + \ the pkey_data[] buffer, if they fit. + read-sequence-open + addr-len-pkey_data + read-integer { nlen } + addr-len-pkey_data swap nlen + swap nlen - + read-integer { elen } + close-elt + close-elt + nlen elen copy-rsa-pkey + enduf + + \ EC public key. + id-ecPublicKey eqOID uf + \ We support only named curves, for which the + \ "parameters" field in the AlgorithmIdentifier + \ field should be an OID. + read-curve-ID { curve } + close-elt + read-bits-open + dup { qlen } + dup addr-len-pkey_data rot < if + ERR_X509_LIMIT_EXCEEDED fail + then + read-blob + curve qlen copy-ec-pkey + enduf + ERR_X509_UNSUPPORTED fail + endchoice + close-elt + + \ This flag will be set to true if the Basic Constraints extension + \ is encountered. + 0 addr-isCA set8 + + \ Skip issuerUniqueID and subjectUniqueID, and process extensions + \ if present. Extensions are an explicit context tag of value 3 + \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE + \ with an OID, an optional boolean, and a value; the value is + \ an OCTET STRING. + read-tag-or-end + 0x21 iftag-skip + 0x22 iftag-skip + dup 0x23 = if + drop + check-constructed read-length-open-elt + read-sequence-open + begin dup while + read-sequence-open + read-OID drop + read-tag dup 0x01 = if + read-boolean drop + read-tag + then + 0x04 check-tag-primitive read-length-open-elt + choice + \ Extensions with specific processing. + basicConstraints eqOID uf + process-basicConstraints + enduf + skip-remaining + endchoice + close-elt + close-elt + repeat + close-elt + close-elt + else + -1 = ifnot ERR_X509_UNEXPECTED fail then + drop + then + + close-elt + + \ signature algorithm + read-sequence-open + read-OID if + choice + sha1WithRSAEncryption eqOID uf 2 KEYTYPE_RSA enduf + sha224WithRSAEncryption eqOID uf 3 KEYTYPE_RSA enduf + sha256WithRSAEncryption eqOID uf 4 KEYTYPE_RSA enduf + sha384WithRSAEncryption eqOID uf 5 KEYTYPE_RSA enduf + sha512WithRSAEncryption eqOID uf 6 KEYTYPE_RSA enduf + + ecdsa-with-SHA1 eqOID uf 2 KEYTYPE_EC enduf + ecdsa-with-SHA224 eqOID uf 3 KEYTYPE_EC enduf + ecdsa-with-SHA256 eqOID uf 4 KEYTYPE_EC enduf + ecdsa-with-SHA384 eqOID uf 5 KEYTYPE_EC enduf + ecdsa-with-SHA512 eqOID uf 6 KEYTYPE_EC enduf + + 0 0 + endchoice + else + 0 0 + then + addr-signer_key_type set8 + addr-signer_hash_id set8 + skip-close-elt + \ read-sequence-open skip-close-elt + + \ signature value + read-bits-open skip-close-elt + + \ Close the outer SEQUENCE. + close-elt + drop + + \ Mark the decoding as successful. + 1 addr-decoded set8 + + \ Read one byte, then fail: if the read succeeds, then there is + \ some trailing byte. + read8-nc ERR_X509_EXTRA_ELEMENT fail + ; diff --git a/src/bearssl/src/x509/x509_knownkey.c b/src/bearssl/src/x509/x509_knownkey.c new file mode 100644 index 0000000..7674f3f --- /dev/null +++ b/src/bearssl/src/x509/x509_knownkey.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_x509.h */ +void +br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx, + const br_rsa_public_key *pk, unsigned usages) +{ + ctx->vtable = &br_x509_knownkey_vtable; + ctx->pkey.key_type = BR_KEYTYPE_RSA; + ctx->pkey.key.rsa = *pk; + ctx->usages = usages; +} + +/* see bearssl_x509.h */ +void +br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, + const br_ec_public_key *pk, unsigned usages) +{ + ctx->vtable = &br_x509_knownkey_vtable; + ctx->pkey.key_type = BR_KEYTYPE_EC; + ctx->pkey.key.ec = *pk; + ctx->usages = usages; +} + +static void +kk_start_chain(const br_x509_class **ctx, const char *server_name) +{ + (void)ctx; + (void)server_name; +} + +static void +kk_start_cert(const br_x509_class **ctx, uint32_t length) +{ + (void)ctx; + (void)length; +} + +static void +kk_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) +{ + (void)ctx; + (void)buf; + (void)len; +} + +static void +kk_end_cert(const br_x509_class **ctx) +{ + (void)ctx; +} + +static unsigned +kk_end_chain(const br_x509_class **ctx) +{ + (void)ctx; + return 0; +} + +static const br_x509_pkey * +kk_get_pkey(const br_x509_class *const *ctx, unsigned *usages) +{ + const br_x509_knownkey_context *xc; + + xc = (const br_x509_knownkey_context *)ctx; + if (usages != NULL) { + *usages = xc->usages; + } + return &xc->pkey; +} + +/* see bearssl_x509.h */ +const br_x509_class br_x509_knownkey_vtable = { + sizeof(br_x509_knownkey_context), + kk_start_chain, + kk_start_cert, + kk_append, + kk_end_cert, + kk_end_chain, + kk_get_pkey +}; diff --git a/src/bearssl/src/x509/x509_minimal.c b/src/bearssl/src/x509/x509_minimal.c new file mode 100644 index 0000000..3b876ef --- /dev/null +++ b/src/bearssl/src/x509/x509_minimal.c @@ -0,0 +1,1713 @@ +/* Automatically generated code; do not modify directly. */ + +#include +#include + +typedef struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; +} t0_context; + +static uint32_t +t0_parse7E_unsigned(const unsigned char **p) +{ + uint32_t x; + + x = 0; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + return x; + } + } +} + +static int32_t +t0_parse7E_signed(const unsigned char **p) +{ + int neg; + uint32_t x; + + neg = ((**p) >> 6) & 1; + x = (uint32_t)-neg; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + if (neg) { + return -(int32_t)~x - 1; + } else { + return (int32_t)x; + } + } + } +} + +#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80) +#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F) +#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8) +#define T0_INT1(x) T0_FBYTE(x, 0) +#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) + +/* static const unsigned char t0_datablock[]; */ + + +void br_x509_minimal_init_main(void *t0ctx); + +void br_x509_minimal_run(void *t0ctx); + + + +#include "inner.h" + + + + + +#include "inner.h" + +/* + * Implementation Notes + * -------------------- + * + * The C code pushes the data by chunks; all decoding is done in the + * T0 code. The cert_length value is set to the certificate length when + * a new certificate is started; the T0 code picks it up as outer limit, + * and decoding functions use it to ensure that no attempt is made at + * reading past it. The T0 code also checks that once the certificate is + * decoded, there are no trailing bytes. + * + * The T0 code sets cert_length to 0 when the certificate is fully + * decoded. + * + * The C code must still perform two checks: + * + * -- If the certificate length is 0, then the T0 code will not be + * invoked at all. This invalid condition must thus be reported by the + * C code. + * + * -- When reaching the end of certificate, the C code must verify that + * the certificate length has been set to 0, thereby signaling that + * the T0 code properly decoded a certificate. + * + * Processing of a chain works in the following way: + * + * -- The error flag is set to a non-zero value when validation is + * finished. The value is either BR_ERR_X509_OK (validation is + * successful) or another non-zero error code. When a non-zero error + * code is obtained, the remaining bytes in the current certificate and + * the subsequent certificates (if any) are completely ignored. + * + * -- Each certificate is decoded in due course, with the following + * "interesting points": + * + * -- Start of the TBS: the multihash engine is reset and activated. + * + * -- Start of the issuer DN: the secondary hash engine is started, + * to process the encoded issuer DN. + * + * -- End of the issuer DN: the secondary hash engine is stopped. The + * resulting hash value is computed and then copied into the + * next_dn_hash[] buffer. + * + * -- Start of the subject DN: the secondary hash engine is started, + * to process the encoded subject DN. + * + * -- For the EE certificate only: the Common Name, if any, is matched + * against the expected server name. + * + * -- End of the subject DN: the secondary hash engine is stopped. The + * resulting hash value is computed into the pad. It is then processed: + * + * -- If this is the EE certificate, then the hash is ignored + * (except for direct trust processing, see later; the hash is + * simply left in current_dn_hash[]). + * + * -- Otherwise, the hashed subject DN is compared with the saved + * hash value (in saved_dn_hash[]). They must match. + * + * Either way, the next_dn_hash[] value is then copied into the + * saved_dn_hash[] value. Thus, at that point, saved_dn_hash[] + * contains the hash of the issuer DN for the current certificate, + * and current_dn_hash[] contains the hash of the subject DN for the + * current certificate. + * + * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown + * key types are reported at that point. + * + * -- If this is the EE certificate, then the key type is compared + * with the expected key type (initialization parameter). The public + * key data is copied to ee_pkey_data[]. The key and hashed subject + * DN are also compared with the "direct trust" keys; if the key + * and DN are matched, then validation ends with a success. + * + * -- Otherwise, the saved signature (cert_sig[]) is verified + * against the saved TBS hash (tbs_hash[]) and that freshly + * decoded public key. Failure here ends validation with an error. + * + * -- Extensions: extension values are processed in due order. + * + * -- Basic Constraints: for all certificates except EE, must be + * present, indicate a CA, and have a path legnth compatible with + * the chain length so far. + * + * -- Key Usage: for the EE, if present, must allow signatures + * or encryption/key exchange, as required for the cipher suite. + * For non-EE, if present, must have the "certificate sign" bit. + * + * -- Subject Alt Name: for the EE, dNSName names are matched + * against the server name. Ignored for non-EE. + * + * -- Authority Key Identifier, Subject Key Identifier, Issuer + * Alt Name, Subject Directory Attributes, CRL Distribution Points + * Freshest CRL, Authority Info Access and Subject Info Access + * extensions are always ignored: they either contain only + * informative data, or they relate to revocation processing, which + * we explicitly do not support. + * + * -- All other extensions are ignored if non-critical. If a + * critical extension other than the ones above is encountered, + * then a failure is reported. + * + * -- End of the TBS: the multihash engine is stopped. + * + * -- Signature algorithm: the signature algorithm on the + * certificate is decoded. A failure is reported if that algorithm + * is unknown. The hashed TBS corresponding to the signature hash + * function is computed and stored in tbs_hash[] (if not supported, + * then a failure is reported). The hash OID and length are stored + * in cert_sig_hash_oid and cert_sig_hash_len. + * + * -- Signature value: the signature value is copied into the + * cert_sig[] array. + * + * -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is + * looked up in the trust store (CA trust anchors only); for all + * that match, the signature (cert_sig[]) is verified against the + * anchor public key (hashed TBS is in tbs_hash[]). If one of these + * signatures is valid, then validation ends with a success. + * + * -- If the chain end is reached without obtaining a validation success, + * then validation is reported as failed. + */ + +#if BR_USE_UNIX_TIME +#include +#endif + +#if BR_USE_WIN32_TIME +#include +#endif + +/* + * The T0 compiler will produce these prototypes declarations in the + * header. + * +void br_x509_minimal_init_main(void *ctx); +void br_x509_minimal_run(void *ctx); + */ + +/* see bearssl_x509.h */ +void +br_x509_minimal_init(br_x509_minimal_context *ctx, + const br_hash_class *dn_hash_impl, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) +{ + memset(ctx, 0, sizeof *ctx); + ctx->vtable = &br_x509_minimal_vtable; + ctx->dn_hash_impl = dn_hash_impl; + ctx->trust_anchors = trust_anchors; + ctx->trust_anchors_num = trust_anchors_num; +} + +static void +xm_start_chain(const br_x509_class **ctx, const char *server_name) +{ + br_x509_minimal_context *cc; + size_t u; + + cc = (br_x509_minimal_context *)(void *)ctx; + for (u = 0; u < cc->num_name_elts; u ++) { + cc->name_elts[u].status = 0; + cc->name_elts[u].buf[0] = 0; + } + memset(&cc->pkey, 0, sizeof cc->pkey); + cc->num_certs = 0; + cc->err = 0; + cc->cpu.dp = cc->dp_stack; + cc->cpu.rp = cc->rp_stack; + br_x509_minimal_init_main(&cc->cpu); + if (server_name == NULL || *server_name == 0) { + cc->server_name = NULL; + } else { + cc->server_name = server_name; + } +} + +static void +xm_start_cert(const br_x509_class **ctx, uint32_t length) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err != 0) { + return; + } + if (length == 0) { + cc->err = BR_ERR_X509_TRUNCATED; + return; + } + cc->cert_length = length; +} + +static void +xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err != 0) { + return; + } + cc->hbuf = buf; + cc->hlen = len; + br_x509_minimal_run(&cc->cpu); +} + +static void +xm_end_cert(const br_x509_class **ctx) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err == 0 && cc->cert_length != 0) { + cc->err = BR_ERR_X509_TRUNCATED; + } + cc->num_certs ++; +} + +static unsigned +xm_end_chain(const br_x509_class **ctx) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err == 0) { + if (cc->num_certs == 0) { + cc->err = BR_ERR_X509_EMPTY_CHAIN; + } else { + cc->err = BR_ERR_X509_NOT_TRUSTED; + } + } else if (cc->err == BR_ERR_X509_OK) { + return 0; + } + return (unsigned)cc->err; +} + +static const br_x509_pkey * +xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err == BR_ERR_X509_OK + || cc->err == BR_ERR_X509_NOT_TRUSTED) + { + if (usages != NULL) { + *usages = cc->key_usages; + } + return &((br_x509_minimal_context *)(void *)ctx)->pkey; + } else { + return NULL; + } +} + +/* see bearssl_x509.h */ +const br_x509_class br_x509_minimal_vtable = { + sizeof(br_x509_minimal_context), + xm_start_chain, + xm_start_cert, + xm_append, + xm_end_cert, + xm_end_chain, + xm_get_pkey +}; + +#define CTX ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu))) +#define CONTEXT_NAME br_x509_minimal_context + +#define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK) + +/* + * Hash a DN (from a trust anchor) into the provided buffer. This uses the + * DN hash implementation and context structure from the X.509 engine + * context. + */ +static void +hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len, + unsigned char *out) +{ + ctx->dn_hash_impl->init(&ctx->dn_hash.vtable); + ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len); + ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out); +} + +/* + * Compare two big integers for equality. The integers use unsigned big-endian + * encoding; extra leading bytes (of value 0) are allowed. + */ +static int +eqbigint(const unsigned char *b1, size_t len1, + const unsigned char *b2, size_t len2) +{ + while (len1 > 0 && *b1 == 0) { + b1 ++; + len1 --; + } + while (len2 > 0 && *b2 == 0) { + b2 ++; + len2 --; + } + if (len1 != len2) { + return 0; + } + return memcmp(b1, b2, len1) == 0; +} + +/* + * Compare two strings for equality, in a case-insensitive way. This + * function handles casing only for ASCII letters. + */ +static int +eqnocase(const void *s1, const void *s2, size_t len) +{ + const unsigned char *buf1, *buf2; + + buf1 = s1; + buf2 = s2; + while (len -- > 0) { + int x1, x2; + + x1 = *buf1 ++; + x2 = *buf2 ++; + if (x1 >= 'A' && x1 <= 'Z') { + x1 += 'a' - 'A'; + } + if (x2 >= 'A' && x2 <= 'Z') { + x2 += 'a' - 'A'; + } + if (x1 != x2) { + return 0; + } + } + return 1; +} + +static int verify_signature(br_x509_minimal_context *ctx, + const br_x509_pkey *pk); + + + +static const unsigned char t0_datablock[] = { + 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x09, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x01, 0x0C, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, + 0x0D, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x04, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x01, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, + 0x02, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x07, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x05, 0x2B, + 0x81, 0x04, 0x00, 0x23, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01, + 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x08, 0x2A, 0x86, + 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x04, 0x03, 0x03, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04, + 0x03, 0x55, 0x04, 0x03, 0x00, 0x1F, 0x03, 0xFC, 0x07, 0x7F, 0x0B, 0x5E, + 0x0F, 0x1F, 0x12, 0xFE, 0x16, 0xBF, 0x1A, 0x9F, 0x1E, 0x7E, 0x22, 0x3F, + 0x26, 0x1E, 0x29, 0xDF, 0x00, 0x1F, 0x03, 0xFD, 0x07, 0x9F, 0x0B, 0x7E, + 0x0F, 0x3F, 0x13, 0x1E, 0x16, 0xDF, 0x1A, 0xBF, 0x1E, 0x9E, 0x22, 0x5F, + 0x26, 0x3E, 0x29, 0xFF, 0x03, 0x55, 0x1D, 0x13, 0x03, 0x55, 0x1D, 0x0F, + 0x03, 0x55, 0x1D, 0x11, 0x03, 0x55, 0x1D, 0x20, 0x08, 0x2B, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x02, 0x01, 0x03, 0x55, 0x1D, 0x23, 0x03, 0x55, 0x1D, + 0x0E, 0x03, 0x55, 0x1D, 0x12, 0x03, 0x55, 0x1D, 0x09, 0x03, 0x55, 0x1D, + 0x1F, 0x03, 0x55, 0x1D, 0x2E, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0B +}; + +static const unsigned char t0_codeblock[] = { + 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, + 0x00, 0x11, 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A, + 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_BOOLEAN), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_DN), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_SERVER_NAME), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TIME), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_CRITICAL_EXTENSION), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_DN_MISMATCH), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_EXPIRED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_FORBIDDEN_KEY_USAGE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_CA), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_PARTIAL_BYTE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_WEAK_PUBLIC_KEY), 0x00, 0x00, 0x01, + T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA), + 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_length)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_hash_len)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_hash_oid)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_len)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, cert_signer_key_type)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, current_dn_hash)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_usages)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01, + T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, min_rsa_size)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, next_dn_hash)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, num_certs)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0xC9, 0x71, + 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00, 0x00, + 0x01, 0x81, 0x02, 0x00, 0x00, 0x92, 0x05, 0x05, 0x34, 0x42, 0x01, 0x00, + 0x00, 0x34, 0x01, 0x0A, 0x0E, 0x09, 0x01, 0x9A, 0xFF, 0xB8, 0x00, 0x0A, + 0x00, 0x00, 0x01, 0x82, 0x19, 0x00, 0x00, 0x01, 0x82, 0x01, 0x00, 0x00, + 0x01, 0x81, 0x68, 0x00, 0x04, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, + 0x03, 0x02, 0x03, 0x02, 0x01, 0x11, 0x06, 0x07, 0x02, 0x02, 0x02, 0x00, + 0x0D, 0x04, 0x05, 0x02, 0x03, 0x02, 0x01, 0x0D, 0x00, 0x02, 0x03, 0x00, + 0x03, 0x01, 0x25, 0x02, 0x01, 0x13, 0x3B, 0x02, 0x00, 0x0F, 0x15, 0x00, + 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x05, 0x02, 0x52, 0x28, 0x00, 0x00, + 0x06, 0x02, 0x53, 0x28, 0x00, 0x00, 0x01, 0x10, 0x77, 0x00, 0x00, 0x11, + 0x05, 0x02, 0x56, 0x28, 0x74, 0x00, 0x00, 0x11, 0x05, 0x02, 0x56, 0x28, + 0x75, 0x00, 0x00, 0x06, 0x02, 0x4C, 0x28, 0x00, 0x00, 0x01, 0x82, 0x11, + 0x00, 0x00, 0x25, 0x20, 0x01, 0x08, 0x0E, 0x3B, 0x40, 0x20, 0x09, 0x00, + 0x09, 0x03, 0x00, 0x5B, 0x2B, 0xAF, 0x39, 0xAF, 0xB3, 0x25, 0x01, 0x20, + 0x11, 0x06, 0x11, 0x24, 0x74, 0xAD, 0xB3, 0x01, 0x02, 0x78, 0xB0, 0x01, + 0x02, 0x12, 0x06, 0x02, 0x57, 0x28, 0x79, 0xB3, 0x01, 0x02, 0x78, 0xAE, + 0xAF, 0xC2, 0x9C, 0x65, 0x61, 0x21, 0x16, 0xAF, 0xA7, 0x29, 0x69, 0x06, + 0x02, 0x4B, 0x28, 0xA7, 0x29, 0x71, 0x06, 0x02, 0x4B, 0x28, 0x79, 0x02, + 0x00, 0x06, 0x05, 0x9D, 0x03, 0x01, 0x04, 0x09, 0x9C, 0x61, 0x68, 0x21, + 0x27, 0x05, 0x02, 0x4A, 0x28, 0x68, 0x65, 0x21, 0x16, 0xAF, 0xAF, 0x9E, + 0x05, 0x02, 0x57, 0x28, 0xBC, 0x26, 0x06, 0x27, 0xC2, 0xA4, 0xAF, 0x63, + 0xAA, 0x03, 0x03, 0x63, 0x3B, 0x02, 0x03, 0x09, 0x3B, 0x02, 0x03, 0x0A, + 0xAA, 0x03, 0x04, 0x79, 0x64, 0x2A, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, + 0x12, 0x06, 0x02, 0x58, 0x28, 0x79, 0x5A, 0x03, 0x02, 0x04, 0x3A, 0x88, + 0x26, 0x06, 0x34, 0x9E, 0x05, 0x02, 0x57, 0x28, 0x6A, 0x26, 0x06, 0x04, + 0x01, 0x17, 0x04, 0x12, 0x6B, 0x26, 0x06, 0x04, 0x01, 0x18, 0x04, 0x0A, + 0x6C, 0x26, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x57, 0x28, 0x03, 0x05, + 0x79, 0xA4, 0x25, 0x03, 0x06, 0x25, 0x63, 0x34, 0x0D, 0x06, 0x02, 0x50, + 0x28, 0xA5, 0x59, 0x03, 0x02, 0x04, 0x02, 0x57, 0x28, 0x79, 0x02, 0x00, + 0x06, 0x21, 0x02, 0x02, 0x5A, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x03, + 0x02, 0x04, 0x1D, 0x04, 0x10, 0x59, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, + 0x05, 0x02, 0x06, 0x1C, 0x04, 0x03, 0x57, 0x28, 0x24, 0x04, 0x24, 0x02, + 0x02, 0x5A, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x03, 0x02, 0x04, 0x23, + 0x04, 0x10, 0x59, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x05, 0x02, 0x06, + 0x22, 0x04, 0x03, 0x57, 0x28, 0x24, 0x25, 0x06, 0x01, 0x28, 0x24, 0x01, + 0x00, 0x03, 0x07, 0xB4, 0x01, 0x21, 0x8F, 0x01, 0x22, 0x8F, 0x25, 0x01, + 0x23, 0x11, 0x06, 0x81, 0x26, 0x24, 0x74, 0xAD, 0xAF, 0x25, 0x06, 0x81, + 0x1A, 0x01, 0x00, 0x03, 0x08, 0xAF, 0x9E, 0x24, 0xB3, 0x25, 0x01, 0x01, + 0x11, 0x06, 0x04, 0xA6, 0x03, 0x08, 0xB3, 0x01, 0x04, 0x78, 0xAD, 0x70, + 0x26, 0x06, 0x0F, 0x02, 0x00, 0x06, 0x03, 0xC3, 0x04, 0x05, 0x99, 0x01, + 0x7F, 0x03, 0x07, 0x04, 0x80, 0x6C, 0x91, 0x26, 0x06, 0x06, 0x02, 0x00, + 0x9B, 0x04, 0x80, 0x62, 0xC5, 0x26, 0x06, 0x11, 0x02, 0x00, 0x06, 0x09, + 0x01, 0x00, 0x03, 0x01, 0x98, 0x03, 0x01, 0x04, 0x01, 0xC3, 0x04, 0x80, + 0x4D, 0x73, 0x26, 0x06, 0x0A, 0x02, 0x08, 0x06, 0x03, 0x9A, 0x04, 0x01, + 0xC3, 0x04, 0x3F, 0x6F, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x38, 0xC8, 0x26, + 0x06, 0x03, 0xC3, 0x04, 0x31, 0x90, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x2A, + 0xC6, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x23, 0x7A, 0x26, 0x06, 0x03, 0xC3, + 0x04, 0x1C, 0x85, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x15, 0x6E, 0x26, 0x06, + 0x03, 0xC3, 0x04, 0x0E, 0xC7, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x07, 0x02, + 0x08, 0x06, 0x02, 0x49, 0x28, 0xC3, 0x79, 0x79, 0x04, 0xFE, 0x62, 0x79, + 0x79, 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, 0x56, 0x28, 0x24, 0x79, + 0x3A, 0x02, 0x00, 0x06, 0x08, 0x02, 0x01, 0x3C, 0x2F, 0x05, 0x02, 0x45, + 0x28, 0x02, 0x00, 0x06, 0x01, 0x17, 0x02, 0x00, 0x02, 0x07, 0x2F, 0x05, + 0x02, 0x51, 0x28, 0xB3, 0x76, 0xAD, 0x9E, 0x06, 0x80, 0x77, 0xBD, 0x26, + 0x06, 0x07, 0x01, 0x02, 0x5A, 0x8A, 0x04, 0x80, 0x5E, 0xBE, 0x26, 0x06, + 0x07, 0x01, 0x03, 0x5A, 0x8B, 0x04, 0x80, 0x53, 0xBF, 0x26, 0x06, 0x07, + 0x01, 0x04, 0x5A, 0x8C, 0x04, 0x80, 0x48, 0xC0, 0x26, 0x06, 0x06, 0x01, + 0x05, 0x5A, 0x8D, 0x04, 0x3E, 0xC1, 0x26, 0x06, 0x06, 0x01, 0x06, 0x5A, + 0x8E, 0x04, 0x34, 0x7F, 0x26, 0x06, 0x06, 0x01, 0x02, 0x59, 0x8A, 0x04, + 0x2A, 0x80, 0x26, 0x06, 0x06, 0x01, 0x03, 0x59, 0x8B, 0x04, 0x20, 0x81, + 0x26, 0x06, 0x06, 0x01, 0x04, 0x59, 0x8C, 0x04, 0x16, 0x82, 0x26, 0x06, + 0x06, 0x01, 0x05, 0x59, 0x8D, 0x04, 0x0C, 0x83, 0x26, 0x06, 0x06, 0x01, + 0x06, 0x59, 0x8E, 0x04, 0x02, 0x57, 0x28, 0x5E, 0x35, 0x60, 0x37, 0x1B, + 0x25, 0x05, 0x02, 0x57, 0x28, 0x5D, 0x37, 0x04, 0x02, 0x57, 0x28, 0xC2, + 0xA4, 0x25, 0x01, T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02, 0x50, + 0x28, 0x25, 0x5F, 0x35, 0x5C, 0xA5, 0x79, 0x79, 0x01, 0x00, 0x5B, 0x36, + 0x18, 0x00, 0x00, 0x01, 0x30, 0x0A, 0x25, 0x01, 0x00, 0x01, 0x09, 0x72, + 0x05, 0x02, 0x48, 0x28, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x01, 0x81, + 0x08, 0x00, 0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81, 0x19, 0x00, + 0x00, 0x01, 0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00, 0x01, 0x7E, + 0x01, 0x01, 0x11, 0x3B, 0x01, 0x83, 0xFD, 0x7F, 0x11, 0x15, 0x06, 0x03, + 0x3B, 0x24, 0x00, 0x3B, 0x25, 0x03, 0x00, 0x25, 0xCA, 0x05, 0x04, 0x42, + 0x01, 0x00, 0x00, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x04, 0x96, 0x04, + 0x80, 0x49, 0x25, 0x01, 0x90, 0x00, 0x0D, 0x06, 0x0F, 0x01, 0x06, 0x14, + 0x01, 0x81, 0x40, 0x2F, 0x96, 0x02, 0x00, 0x01, 0x00, 0x97, 0x04, 0x33, + 0x25, 0x01, 0x83, 0xFF, 0x7F, 0x0D, 0x06, 0x14, 0x01, 0x0C, 0x14, 0x01, + 0x81, 0x60, 0x2F, 0x96, 0x02, 0x00, 0x01, 0x06, 0x97, 0x02, 0x00, 0x01, + 0x00, 0x97, 0x04, 0x17, 0x01, 0x12, 0x14, 0x01, 0x81, 0x70, 0x2F, 0x96, + 0x02, 0x00, 0x01, 0x0C, 0x97, 0x02, 0x00, 0x01, 0x06, 0x97, 0x02, 0x00, + 0x01, 0x00, 0x97, 0x00, 0x00, 0x01, 0x82, 0x15, 0x00, 0x00, 0x25, 0x01, + 0x83, 0xB0, 0x00, 0x01, 0x83, 0xB7, 0x7F, 0x72, 0x00, 0x00, 0x01, 0x81, + 0x34, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x81, 0x78, 0x00, + 0x00, 0x01, 0x3D, 0x00, 0x00, 0x01, 0x80, 0x43, 0x00, 0x00, 0x01, 0x80, + 0x4D, 0x00, 0x00, 0x01, 0x80, 0x57, 0x00, 0x00, 0x01, 0x80, 0x61, 0x00, + 0x00, 0x30, 0x11, 0x06, 0x04, 0x42, 0xAD, 0xC2, 0xB4, 0x00, 0x00, 0x01, + 0x82, 0x09, 0x00, 0x00, 0x01, 0x81, 0x6C, 0x00, 0x00, 0x25, 0x01, 0x83, + 0xB8, 0x00, 0x01, 0x83, 0xBF, 0x7F, 0x72, 0x00, 0x00, 0x01, 0x30, 0x62, + 0x37, 0x01, 0x7F, 0x7C, 0x19, 0x01, 0x00, 0x7C, 0x19, 0x04, 0x7A, 0x00, + 0x01, 0x81, 0x38, 0x00, 0x01, 0x7E, 0x0D, 0x06, 0x02, 0x4F, 0x28, 0x25, + 0x03, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x30, 0x25, 0x3F, 0x3B, 0x01, + 0x82, 0x00, 0x13, 0x2F, 0x06, 0x04, 0x42, 0x01, 0x00, 0x00, 0x30, 0x67, + 0x09, 0x37, 0x40, 0x00, 0x00, 0x14, 0x01, 0x3F, 0x15, 0x01, 0x81, 0x00, + 0x2F, 0x96, 0x00, 0x02, 0x01, 0x00, 0x03, 0x00, 0xAF, 0x25, 0x06, 0x80, + 0x59, 0xB3, 0x01, 0x20, 0x30, 0x11, 0x06, 0x17, 0x24, 0x74, 0xAD, 0x9E, + 0x24, 0x01, 0x7F, 0x2E, 0x03, 0x01, 0xB3, 0x01, 0x20, 0x77, 0xAD, 0xB2, + 0x02, 0x01, 0x1F, 0x79, 0x79, 0x04, 0x38, 0x01, 0x21, 0x30, 0x11, 0x06, + 0x08, 0x24, 0x75, 0xB6, 0x01, 0x01, 0x1E, 0x04, 0x2A, 0x01, 0x22, 0x30, + 0x11, 0x06, 0x11, 0x24, 0x75, 0xB6, 0x25, 0x06, 0x06, 0x2C, 0x02, 0x00, + 0x2F, 0x03, 0x00, 0x01, 0x02, 0x1E, 0x04, 0x13, 0x01, 0x26, 0x30, 0x11, + 0x06, 0x08, 0x24, 0x75, 0xB6, 0x01, 0x06, 0x1E, 0x04, 0x05, 0x42, 0xAE, + 0x01, 0x00, 0x24, 0x04, 0xFF, 0x23, 0x79, 0x02, 0x00, 0x00, 0x00, 0xAF, + 0xB4, 0x25, 0x01, 0x01, 0x11, 0x06, 0x08, 0xA6, 0x05, 0x02, 0x51, 0x28, + 0xB4, 0x04, 0x02, 0x51, 0x28, 0x25, 0x01, 0x02, 0x11, 0x06, 0x0C, 0x24, + 0x75, 0xB0, 0x66, 0x2B, 0x41, 0x0D, 0x06, 0x02, 0x51, 0x28, 0xB4, 0x01, + 0x7F, 0x10, 0x06, 0x02, 0x56, 0x28, 0x24, 0x79, 0x00, 0x00, 0xAF, 0x25, + 0x06, 0x1A, 0xAF, 0x9E, 0x24, 0x25, 0x06, 0x11, 0xAF, 0x25, 0x06, 0x0C, + 0xAF, 0x9E, 0x24, 0x89, 0x26, 0x05, 0x02, 0x49, 0x28, 0xC2, 0x04, 0x71, + 0x79, 0x79, 0x04, 0x63, 0x79, 0x00, 0x02, 0x03, 0x00, 0xB3, 0x01, 0x03, + 0x78, 0xAD, 0xBA, 0x03, 0x01, 0x02, 0x01, 0x01, 0x07, 0x12, 0x06, 0x02, + 0x56, 0x28, 0x25, 0x01, 0x00, 0x30, 0x11, 0x06, 0x05, 0x24, 0x4D, 0x28, + 0x04, 0x15, 0x01, 0x01, 0x30, 0x11, 0x06, 0x0A, 0x24, 0xBA, 0x02, 0x01, + 0x14, 0x02, 0x01, 0x0E, 0x04, 0x05, 0x24, 0xBA, 0x01, 0x00, 0x24, 0x02, + 0x00, 0x06, 0x19, 0x01, 0x00, 0x30, 0x01, 0x38, 0x15, 0x06, 0x03, 0x01, + 0x10, 0x2F, 0x3B, 0x01, 0x81, 0x40, 0x15, 0x06, 0x03, 0x01, 0x20, 0x2F, + 0x62, 0x37, 0x04, 0x07, 0x01, 0x04, 0x15, 0x05, 0x02, 0x4D, 0x28, 0xC2, + 0x00, 0x00, 0x38, 0xAF, 0xC2, 0x1A, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, + 0x38, 0xAF, 0x25, 0x06, 0x30, 0xB3, 0x01, 0x11, 0x77, 0xAD, 0x25, 0x05, + 0x02, 0x44, 0x28, 0x25, 0x06, 0x20, 0xAF, 0x9E, 0x24, 0x87, 0x26, 0x03, + 0x01, 0x01, 0x00, 0x2E, 0x03, 0x02, 0xB2, 0x25, 0x02, 0x01, 0x15, 0x06, + 0x07, 0x2C, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x00, 0x02, 0x02, 0x1F, 0x79, + 0x04, 0x5D, 0x79, 0x04, 0x4D, 0x79, 0x1A, 0x02, 0x00, 0x00, 0x00, 0xB3, + 0x01, 0x06, 0x78, 0xB1, 0x00, 0x00, 0xB8, 0x86, 0x06, 0x0E, 0x3B, 0x25, + 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x00, 0x00, 0xB8, 0x6D, 0x04, 0x08, + 0x92, 0x06, 0x05, 0x24, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB9, 0x86, + 0x06, 0x0E, 0x3B, 0x25, 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x00, 0x00, + 0xB9, 0x6D, 0x04, 0x08, 0x92, 0x06, 0x05, 0x24, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x00, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x04, 0x00, 0x04, + 0x80, 0x55, 0x25, 0x01, 0x81, 0x40, 0x0D, 0x06, 0x07, 0x24, 0x01, 0x00, + 0x00, 0x04, 0x80, 0x47, 0x25, 0x01, 0x81, 0x60, 0x0D, 0x06, 0x0E, 0x01, + 0x1F, 0x15, 0x01, 0x01, 0xA3, 0x01, 0x81, 0x00, 0x01, 0x8F, 0x7F, 0x04, + 0x32, 0x25, 0x01, 0x81, 0x70, 0x0D, 0x06, 0x0F, 0x01, 0x0F, 0x15, 0x01, + 0x02, 0xA3, 0x01, 0x90, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x04, 0x1C, 0x25, + 0x01, 0x81, 0x78, 0x0D, 0x06, 0x11, 0x01, 0x07, 0x15, 0x01, 0x03, 0xA3, + 0x01, 0x84, 0x80, 0x00, 0x01, 0x80, 0xC3, 0xFF, 0x7F, 0x04, 0x04, 0x24, + 0x01, 0x00, 0x00, 0x72, 0x05, 0x03, 0x24, 0x01, 0x00, 0x00, 0x00, 0x3B, + 0x25, 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x7F, 0x00, 0xBA, 0x34, 0x25, + 0x3D, 0x06, 0x03, 0x3B, 0x24, 0x00, 0x01, 0x06, 0x0E, 0x3B, 0x25, 0x01, + 0x06, 0x14, 0x01, 0x02, 0x10, 0x06, 0x04, 0x42, 0x01, 0x7F, 0x00, 0x01, + 0x3F, 0x15, 0x09, 0x00, 0x00, 0x25, 0x06, 0x06, 0x0B, 0xA2, 0x34, 0x41, + 0x04, 0x77, 0x24, 0x25, 0x00, 0x00, 0xB3, 0x01, 0x03, 0x78, 0xAD, 0xBA, + 0x06, 0x02, 0x55, 0x28, 0x00, 0x00, 0x3B, 0x25, 0x06, 0x07, 0x31, 0x25, + 0x06, 0x01, 0x19, 0x04, 0x76, 0x42, 0x00, 0x00, 0x01, 0x01, 0x78, 0xAC, + 0x01, 0x01, 0x10, 0x06, 0x02, 0x43, 0x28, 0xBA, 0x3E, 0x00, 0x04, 0xB3, + 0x25, 0x01, 0x17, 0x01, 0x18, 0x72, 0x05, 0x02, 0x48, 0x28, 0x01, 0x18, + 0x11, 0x03, 0x00, 0x75, 0xAD, 0xA8, 0x02, 0x00, 0x06, 0x0C, 0x01, 0x80, + 0x64, 0x08, 0x03, 0x01, 0xA8, 0x02, 0x01, 0x09, 0x04, 0x0E, 0x25, 0x01, + 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80, 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, + 0x03, 0x01, 0x02, 0x01, 0x01, 0x82, 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, + 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02, 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, + 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01, 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, + 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01, 0x01, 0x01, 0x0C, 0xA9, 0x41, 0x01, + 0x01, 0x0E, 0x02, 0x01, 0x01, 0x04, 0x07, 0x3F, 0x02, 0x01, 0x01, 0x80, + 0x64, 0x07, 0x3E, 0x02, 0x01, 0x01, 0x83, 0x10, 0x07, 0x3F, 0x2F, 0x15, + 0x06, 0x03, 0x01, 0x18, 0x09, 0x94, 0x09, 0x7B, 0x25, 0x01, 0x05, 0x14, + 0x02, 0x03, 0x09, 0x03, 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x3B, 0xA9, + 0x02, 0x03, 0x09, 0x41, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0xA9, 0x01, + 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0xA9, 0x01, 0x3C, + 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C, 0xA9, 0x02, + 0x02, 0x09, 0x03, 0x02, 0xBA, 0x25, 0x01, 0x2E, 0x11, 0x06, 0x0D, 0x24, + 0xBA, 0x25, 0x01, 0x30, 0x01, 0x39, 0x72, 0x06, 0x03, 0x24, 0x04, 0x74, + 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x48, 0x28, 0x79, 0x02, 0x03, 0x02, + 0x02, 0x00, 0x01, 0xBA, 0x7D, 0x01, 0x0A, 0x08, 0x03, 0x00, 0xBA, 0x7D, + 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0xA8, 0x25, 0x02, + 0x01, 0x02, 0x00, 0x72, 0x05, 0x02, 0x48, 0x28, 0x00, 0x00, 0x34, 0xB3, + 0x01, 0x02, 0x78, 0x0B, 0xAB, 0x00, 0x03, 0x25, 0x03, 0x00, 0x03, 0x01, + 0x03, 0x02, 0xAD, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x54, + 0x28, 0x25, 0x01, 0x00, 0x11, 0x06, 0x0B, 0x24, 0x25, 0x05, 0x04, 0x24, + 0x01, 0x00, 0x00, 0xBA, 0x04, 0x6F, 0x02, 0x01, 0x25, 0x05, 0x02, 0x50, + 0x28, 0x41, 0x03, 0x01, 0x02, 0x02, 0x37, 0x02, 0x02, 0x40, 0x03, 0x02, + 0x25, 0x06, 0x03, 0xBA, 0x04, 0x68, 0x24, 0x02, 0x00, 0x02, 0x01, 0x0A, + 0x00, 0x01, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01, + 0x81, 0x00, 0x0A, 0x25, 0x05, 0x02, 0x4E, 0x28, 0x03, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x19, 0x02, 0x00, 0x41, 0x03, 0x00, + 0x25, 0x01, 0x83, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02, 0x4F, 0x28, 0x01, + 0x08, 0x0E, 0x3B, 0xBA, 0x34, 0x09, 0x04, 0x60, 0x00, 0x00, 0xAC, 0x95, + 0x00, 0x00, 0xAD, 0xC2, 0x00, 0x00, 0xB3, 0x76, 0xAD, 0x00, 0x01, 0xAD, + 0x25, 0x05, 0x02, 0x54, 0x28, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x13, 0x06, + 0x02, 0x54, 0x28, 0x03, 0x00, 0x25, 0x06, 0x16, 0xBA, 0x02, 0x00, 0x25, + 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x54, 0x28, 0x01, 0x08, + 0x0E, 0x09, 0x03, 0x00, 0x04, 0x67, 0x24, 0x02, 0x00, 0x00, 0x00, 0xAD, + 0x25, 0x01, 0x81, 0x7F, 0x12, 0x06, 0x08, 0xC2, 0x01, 0x00, 0x67, 0x37, + 0x01, 0x00, 0x00, 0x25, 0x67, 0x37, 0x67, 0x40, 0xA5, 0x01, 0x7F, 0x00, + 0x00, 0xB3, 0x01, 0x0C, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB6, 0x04, + 0x3E, 0x01, 0x12, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x33, + 0x01, 0x13, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x28, 0x01, + 0x14, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x1D, 0x01, 0x16, + 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x12, 0x01, 0x1E, 0x30, + 0x11, 0x06, 0x05, 0x24, 0x75, 0xB5, 0x04, 0x07, 0x42, 0xAE, 0x01, 0x00, + 0x01, 0x00, 0x24, 0x00, 0x01, 0xBA, 0x03, 0x00, 0x02, 0x00, 0x01, 0x05, + 0x14, 0x01, 0x01, 0x15, 0x2D, 0x02, 0x00, 0x01, 0x06, 0x14, 0x25, 0x01, + 0x01, 0x15, 0x06, 0x02, 0x46, 0x28, 0x01, 0x04, 0x0E, 0x02, 0x00, 0x01, + 0x1F, 0x15, 0x25, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x47, 0x28, 0x09, 0x00, + 0x00, 0x25, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0xB3, 0x00, 0x01, + 0xAD, 0x25, 0x05, 0x05, 0x67, 0x37, 0x01, 0x7F, 0x00, 0x01, 0x01, 0x03, + 0x00, 0x9F, 0x25, 0x01, 0x83, 0xFF, 0x7E, 0x11, 0x06, 0x16, 0x24, 0x25, + 0x06, 0x10, 0xA0, 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02, + 0x00, 0x84, 0x03, 0x00, 0x04, 0x6D, 0x04, 0x1B, 0x25, 0x05, 0x05, 0x24, + 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03, 0x00, 0x25, 0x06, 0x0B, + 0x9F, 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x04, 0x6D, 0x24, + 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67, 0x37, 0x01, 0x7F, 0x00, + 0x01, 0xAD, 0x01, 0x01, 0x03, 0x00, 0x25, 0x06, 0x10, 0xA1, 0x25, 0x05, + 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03, 0x00, 0x04, + 0x6D, 0x24, 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67, 0x37, 0x01, + 0x7F, 0x00, 0x01, 0xAD, 0x01, 0x01, 0x03, 0x00, 0x25, 0x06, 0x10, 0xBA, + 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03, + 0x00, 0x04, 0x6D, 0x24, 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67, + 0x37, 0x01, 0x7F, 0x00, 0x00, 0xBA, 0x01, 0x08, 0x0E, 0x3B, 0xBA, 0x34, + 0x09, 0x00, 0x00, 0xBA, 0x3B, 0xBA, 0x01, 0x08, 0x0E, 0x34, 0x09, 0x00, + 0x00, 0x25, 0x05, 0x02, 0x4F, 0x28, 0x41, 0xBB, 0x00, 0x00, 0x32, 0x25, + 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x24, 0x19, 0x04, 0x74, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x01, + 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0xC3, + 0x24, 0x00, 0x00, 0x25, 0x06, 0x07, 0xC4, 0x25, 0x06, 0x01, 0x19, 0x04, + 0x76, 0x00, 0x00, 0x01, 0x00, 0x30, 0x31, 0x0B, 0x42, 0x00, 0x00, 0x01, + 0x81, 0x70, 0x00, 0x00, 0x01, 0x82, 0x0D, 0x00, 0x00, 0x01, 0x82, 0x22, + 0x00, 0x00, 0x01, 0x82, 0x05, 0x00, 0x00, 0x01, 0x03, 0x33, 0x01, 0x03, + 0x33, 0x00, 0x00, 0x25, 0x01, 0x83, 0xFB, 0x50, 0x01, 0x83, 0xFD, 0x5F, + 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x83, 0xB0, 0x00, + 0x01, 0x83, 0xBF, 0x7F, 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x01, + 0x83, 0xFF, 0x7F, 0x15, 0x01, 0x83, 0xFF, 0x7E, 0x0D, 0x00 +}; + +static const uint16_t t0_caddr[] = { + 0, + 5, + 10, + 15, + 20, + 25, + 29, + 33, + 37, + 41, + 45, + 49, + 53, + 57, + 61, + 65, + 69, + 73, + 77, + 81, + 85, + 89, + 93, + 97, + 101, + 105, + 109, + 113, + 117, + 121, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 165, + 173, + 178, + 183, + 188, + 193, + 198, + 202, + 207, + 212, + 217, + 238, + 243, + 248, + 253, + 282, + 297, + 302, + 308, + 314, + 319, + 327, + 335, + 341, + 346, + 357, + 992, + 1007, + 1011, + 1016, + 1021, + 1026, + 1031, + 1036, + 1150, + 1155, + 1167, + 1172, + 1177, + 1182, + 1186, + 1191, + 1196, + 1201, + 1206, + 1216, + 1221, + 1226, + 1238, + 1253, + 1258, + 1272, + 1294, + 1305, + 1408, + 1455, + 1488, + 1579, + 1585, + 1648, + 1655, + 1683, + 1711, + 1816, + 1858, + 1871, + 1883, + 1897, + 1912, + 2132, + 2146, + 2163, + 2172, + 2239, + 2295, + 2299, + 2303, + 2308, + 2356, + 2382, + 2458, + 2502, + 2513, + 2598, + 2636, + 2674, + 2684, + 2694, + 2703, + 2716, + 2720, + 2724, + 2728, + 2732, + 2736, + 2740, + 2744, + 2756, + 2764, + 2769, + 2774, + 2779, + 2784, + 2792 +}; + +#define T0_INTERPRETED 61 + +#define T0_ENTER(ip, rp, slot) do { \ + const unsigned char *t0_newip; \ + uint32_t t0_lnum; \ + t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \ + t0_lnum = t0_parse7E_unsigned(&t0_newip); \ + (rp) += t0_lnum; \ + *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \ + (ip) = t0_newip; \ + } while (0) + +#define T0_DEFENTRY(name, slot) \ +void \ +name(void *ctx) \ +{ \ + t0_context *t0ctx = ctx; \ + t0ctx->ip = &t0_codeblock[0]; \ + T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ +} + +T0_DEFENTRY(br_x509_minimal_init_main, 147) + +#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++) + +void +br_x509_minimal_run(void *t0ctx) +{ + uint32_t *dp, *rp; + const unsigned char *ip; + +#define T0_LOCAL(x) (*(rp - 2 - (x))) +#define T0_POP() (*-- dp) +#define T0_POPi() (*(int32_t *)(-- dp)) +#define T0_PEEK(x) (*(dp - 1 - (x))) +#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x))) +#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0) +#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0) +#define T0_RPOP() (*-- rp) +#define T0_RPOPi() (*(int32_t *)(-- rp)) +#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0) +#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0) +#define T0_ROLL(x) do { \ + size_t t0len = (size_t)(x); \ + uint32_t t0tmp = *(dp - 1 - t0len); \ + memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_SWAP() do { \ + uint32_t t0tmp = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_ROT() do { \ + uint32_t t0tmp = *(dp - 3); \ + *(dp - 3) = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_NROT() do { \ + uint32_t t0tmp = *(dp - 1); \ + *(dp - 1) = *(dp - 2); \ + *(dp - 2) = *(dp - 3); \ + *(dp - 3) = t0tmp; \ +} while (0) +#define T0_PICK(x) do { \ + uint32_t t0depth = (x); \ + T0_PUSH(T0_PEEK(t0depth)); \ +} while (0) +#define T0_CO() do { \ + goto t0_exit; \ +} while (0) +#define T0_RET() goto t0_next + + dp = ((t0_context *)t0ctx)->dp; + rp = ((t0_context *)t0ctx)->rp; + ip = ((t0_context *)t0ctx)->ip; + goto t0_next; + for (;;) { + uint32_t t0x; + + t0_next: + t0x = T0_NEXT(&ip); + if (t0x < T0_INTERPRETED) { + switch (t0x) { + int32_t t0off; + + case 0: /* ret */ + t0x = T0_RPOP(); + rp -= (t0x >> 16); + t0x &= 0xFFFF; + if (t0x == 0) { + ip = NULL; + goto t0_exit; + } + ip = &t0_codeblock[t0x]; + break; + case 1: /* literal constant */ + T0_PUSHi(t0_parse7E_signed(&ip)); + break; + case 2: /* read local */ + T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip))); + break; + case 3: /* write local */ + T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP(); + break; + case 4: /* jump */ + t0off = t0_parse7E_signed(&ip); + ip += t0off; + break; + case 5: /* jump if */ + t0off = t0_parse7E_signed(&ip); + if (T0_POP()) { + ip += t0off; + } + break; + case 6: /* jump if not */ + t0off = t0_parse7E_signed(&ip); + if (!T0_POP()) { + ip += t0off; + } + break; + case 7: { + /* %25 */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSHi(a % b); + + } + break; + case 8: { + /* * */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a * b); + + } + break; + case 9: { + /* + */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a + b); + + } + break; + case 10: { + /* - */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a - b); + + } + break; + case 11: { + /* -rot */ + T0_NROT(); + } + break; + case 12: { + /* / */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSHi(a / b); + + } + break; + case 13: { + /* < */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 14: { + /* << */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x << c); + + } + break; + case 15: { + /* <= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a <= b)); + + } + break; + case 16: { + /* <> */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a != b)); + + } + break; + case 17: { + /* = */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a == b)); + + } + break; + case 18: { + /* > */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a > b)); + + } + break; + case 19: { + /* >= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a >= b)); + + } + break; + case 20: { + /* >> */ + + int c = (int)T0_POPi(); + int32_t x = T0_POPi(); + T0_PUSHi(x >> c); + + } + break; + case 21: { + /* and */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a & b); + + } + break; + case 22: { + /* blobcopy */ + + size_t len = T0_POP(); + unsigned char *src = (unsigned char *)CTX + T0_POP(); + unsigned char *dst = (unsigned char *)CTX + T0_POP(); + memcpy(dst, src, len); + + } + break; + case 23: { + /* check-direct-trust */ + + size_t u; + + for (u = 0; u < CTX->trust_anchors_num; u ++) { + const br_x509_trust_anchor *ta; + unsigned char hashed_DN[64]; + int kt; + + ta = &CTX->trust_anchors[u]; + if (ta->flags & BR_X509_TA_CA) { + continue; + } + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); + if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) { + continue; + } + kt = CTX->pkey.key_type; + if ((ta->pkey.key_type & 0x0F) != kt) { + continue; + } + switch (kt) { + + case BR_KEYTYPE_RSA: + if (!eqbigint(CTX->pkey.key.rsa.n, + CTX->pkey.key.rsa.nlen, + ta->pkey.key.rsa.n, + ta->pkey.key.rsa.nlen) + || !eqbigint(CTX->pkey.key.rsa.e, + CTX->pkey.key.rsa.elen, + ta->pkey.key.rsa.e, + ta->pkey.key.rsa.elen)) + { + continue; + } + break; + + case BR_KEYTYPE_EC: + if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve + || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen + || memcmp(CTX->pkey.key.ec.q, + ta->pkey.key.ec.q, + ta->pkey.key.ec.qlen) != 0) + { + continue; + } + break; + + default: + continue; + } + + /* + * Direct trust match! + */ + CTX->err = BR_ERR_X509_OK; + T0_CO(); + } + + } + break; + case 24: { + /* check-trust-anchor-CA */ + + size_t u; + + for (u = 0; u < CTX->trust_anchors_num; u ++) { + const br_x509_trust_anchor *ta; + unsigned char hashed_DN[64]; + + ta = &CTX->trust_anchors[u]; + if (!(ta->flags & BR_X509_TA_CA)) { + continue; + } + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); + if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) { + continue; + } + if (verify_signature(CTX, &ta->pkey) == 0) { + CTX->err = BR_ERR_X509_OK; + T0_CO(); + } + } + + } + break; + case 25: { + /* co */ + T0_CO(); + } + break; + case 26: { + /* compute-dn-hash */ + + CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash); + CTX->do_dn_hash = 0; + + } + break; + case 27: { + /* compute-tbs-hash */ + + int id = T0_POPi(); + size_t len; + len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash); + T0_PUSH(len); + + } + break; + case 28: { + /* copy-ee-ec-pkey */ + + size_t qlen = T0_POP(); + uint32_t curve = T0_POP(); + memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen); + CTX->pkey.key_type = BR_KEYTYPE_EC; + CTX->pkey.key.ec.curve = curve; + CTX->pkey.key.ec.q = CTX->ee_pkey_data; + CTX->pkey.key.ec.qlen = qlen; + + } + break; + case 29: { + /* copy-ee-rsa-pkey */ + + size_t elen = T0_POP(); + size_t nlen = T0_POP(); + memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen); + CTX->pkey.key_type = BR_KEYTYPE_RSA; + CTX->pkey.key.rsa.n = CTX->ee_pkey_data; + CTX->pkey.key.rsa.nlen = nlen; + CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen; + CTX->pkey.key.rsa.elen = elen; + + } + break; + case 30: { + /* copy-name-SAN */ + + unsigned tag = T0_POP(); + unsigned ok = T0_POP(); + size_t u, len; + + len = CTX->pad[0]; + for (u = 0; u < CTX->num_name_elts; u ++) { + br_name_element *ne; + + ne = &CTX->name_elts[u]; + if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) { + if (ok && ne->len > len) { + memcpy(ne->buf, CTX->pad + 1, len); + ne->buf[len] = 0; + ne->status = 1; + } else { + ne->status = -1; + } + break; + } + } + + } + break; + case 31: { + /* copy-name-element */ + + size_t len; + int32_t off = T0_POPi(); + int ok = T0_POPi(); + + if (off >= 0) { + br_name_element *ne = &CTX->name_elts[off]; + + if (ok) { + len = CTX->pad[0]; + if (len < ne->len) { + memcpy(ne->buf, CTX->pad + 1, len); + ne->buf[len] = 0; + ne->status = 1; + } else { + ne->status = -1; + } + } else { + ne->status = -1; + } + } + + } + break; + case 32: { + /* data-get8 */ + + size_t addr = T0_POP(); + T0_PUSH(t0_datablock[addr]); + + } + break; + case 33: { + /* dn-hash-length */ + + T0_PUSH(DNHASH_LEN); + + } + break; + case 34: { + /* do-ecdsa-vrfy */ + + size_t qlen = T0_POP(); + int curve = T0_POP(); + br_x509_pkey pk; + + pk.key_type = BR_KEYTYPE_EC; + pk.key.ec.curve = curve; + pk.key.ec.q = CTX->pkey_data; + pk.key.ec.qlen = qlen; + T0_PUSH(verify_signature(CTX, &pk)); + + } + break; + case 35: { + /* do-rsa-vrfy */ + + size_t elen = T0_POP(); + size_t nlen = T0_POP(); + br_x509_pkey pk; + + pk.key_type = BR_KEYTYPE_RSA; + pk.key.rsa.n = CTX->pkey_data; + pk.key.rsa.nlen = nlen; + pk.key.rsa.e = CTX->pkey_data + nlen; + pk.key.rsa.elen = elen; + T0_PUSH(verify_signature(CTX, &pk)); + + } + break; + case 36: { + /* drop */ + (void)T0_POP(); + } + break; + case 37: { + /* dup */ + T0_PUSH(T0_PEEK(0)); + } + break; + case 38: { + /* eqOID */ + + const unsigned char *a2 = &t0_datablock[T0_POP()]; + const unsigned char *a1 = &CTX->pad[0]; + size_t len = a1[0]; + int x; + if (len == a2[0]) { + x = -(memcmp(a1 + 1, a2 + 1, len) == 0); + } else { + x = 0; + } + T0_PUSH((uint32_t)x); + + } + break; + case 39: { + /* eqblob */ + + size_t len = T0_POP(); + const unsigned char *a2 = (const unsigned char *)CTX + T0_POP(); + const unsigned char *a1 = (const unsigned char *)CTX + T0_POP(); + T0_PUSHi(-(memcmp(a1, a2, len) == 0)); + + } + break; + case 40: { + /* fail */ + + CTX->err = T0_POPi(); + T0_CO(); + + } + break; + case 41: { + /* get-system-date */ + + if (CTX->days == 0 && CTX->seconds == 0) { +#if BR_USE_UNIX_TIME + time_t x = time(NULL); + + T0_PUSH((uint32_t)(x / 86400) + 719528); + T0_PUSH((uint32_t)(x % 86400)); +#elif BR_USE_WIN32_TIME + FILETIME ft; + uint64_t x; + + GetSystemTimeAsFileTime(&ft); + x = ((uint64_t)ft.dwHighDateTime << 32) + + (uint64_t)ft.dwLowDateTime; + x = (x / 10000000); + T0_PUSH((uint32_t)(x / 86400) + 584754); + T0_PUSH((uint32_t)(x % 86400)); +#else + CTX->err = BR_ERR_X509_TIME_UNKNOWN; + T0_CO(); +#endif + } else { + T0_PUSH(CTX->days); + T0_PUSH(CTX->seconds); + } + + } + break; + case 42: { + /* get16 */ + + uint32_t addr = T0_POP(); + T0_PUSH(*(uint16_t *)(void *)((unsigned char *)CTX + addr)); + + } + break; + case 43: { + /* get32 */ + + uint32_t addr = T0_POP(); + T0_PUSH(*(uint32_t *)(void *)((unsigned char *)CTX + addr)); + + } + break; + case 44: { + /* match-server-name */ + + size_t n1, n2; + + if (CTX->server_name == NULL) { + T0_PUSH(0); + T0_RET(); + } + n1 = strlen(CTX->server_name); + n2 = CTX->pad[0]; + if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) { + T0_PUSHi(-1); + T0_RET(); + } + if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') { + size_t u; + + u = 0; + while (u < n1 && CTX->server_name[u] != '.') { + u ++; + } + u ++; + n1 -= u; + if ((n2 - 2) == n1 + && eqnocase(&CTX->pad[3], CTX->server_name + u, n1)) + { + T0_PUSHi(-1); + T0_RET(); + } + } + T0_PUSH(0); + + } + break; + case 45: { + /* neg */ + + uint32_t a = T0_POP(); + T0_PUSH(-a); + + } + break; + case 46: { + /* offset-name-element */ + + unsigned san = T0_POP(); + size_t u; + + for (u = 0; u < CTX->num_name_elts; u ++) { + if (CTX->name_elts[u].status == 0) { + const unsigned char *oid; + size_t len, off; + + oid = CTX->name_elts[u].oid; + if (san) { + if (oid[0] != 0 || oid[1] != 0) { + continue; + } + off = 2; + } else { + off = 0; + } + len = oid[off]; + if (len != 0 && len == CTX->pad[0] + && memcmp(oid + off + 1, + CTX->pad + 1, len) == 0) + { + T0_PUSH(u); + T0_RET(); + } + } + } + T0_PUSHi(-1); + + } + break; + case 47: { + /* or */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a | b); + + } + break; + case 48: { + /* over */ + T0_PUSH(T0_PEEK(1)); + } + break; + case 49: { + /* read-blob-inner */ + + uint32_t len = T0_POP(); + uint32_t addr = T0_POP(); + size_t clen = CTX->hlen; + if (clen > len) { + clen = (size_t)len; + } + if (addr != 0) { + memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); + } + if (CTX->do_mhash) { + br_multihash_update(&CTX->mhash, CTX->hbuf, clen); + } + if (CTX->do_dn_hash) { + CTX->dn_hash_impl->update( + &CTX->dn_hash.vtable, CTX->hbuf, clen); + } + CTX->hbuf += clen; + CTX->hlen -= clen; + T0_PUSH(addr + clen); + T0_PUSH(len - clen); + + } + break; + case 50: { + /* read8-low */ + + if (CTX->hlen == 0) { + T0_PUSHi(-1); + } else { + unsigned char x = *CTX->hbuf ++; + if (CTX->do_mhash) { + br_multihash_update(&CTX->mhash, &x, 1); + } + if (CTX->do_dn_hash) { + CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1); + } + CTX->hlen --; + T0_PUSH(x); + } + + } + break; + case 51: { + /* roll */ + T0_ROLL(T0_POP()); + } + break; + case 52: { + /* rot */ + T0_ROT(); + } + break; + case 53: { + /* set16 */ + + uint32_t addr = T0_POP(); + *(uint16_t *)(void *)((unsigned char *)CTX + addr) = T0_POP(); + + } + break; + case 54: { + /* set32 */ + + uint32_t addr = T0_POP(); + *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP(); + + } + break; + case 55: { + /* set8 */ + + uint32_t addr = T0_POP(); + *((unsigned char *)CTX + addr) = (unsigned char)T0_POP(); + + } + break; + case 56: { + /* start-dn-hash */ + + CTX->dn_hash_impl->init(&CTX->dn_hash.vtable); + CTX->do_dn_hash = 1; + + } + break; + case 57: { + /* start-tbs-hash */ + + br_multihash_init(&CTX->mhash); + CTX->do_mhash = 1; + + } + break; + case 58: { + /* stop-tbs-hash */ + + CTX->do_mhash = 0; + + } + break; + case 59: { + /* swap */ + T0_SWAP(); + } + break; + case 60: { + /* zero-server-name */ + + T0_PUSHi(-(CTX->server_name == NULL)); + + } + break; + } + + } else { + T0_ENTER(ip, rp, t0x); + } + } +t0_exit: + ((t0_context *)t0ctx)->dp = dp; + ((t0_context *)t0ctx)->rp = rp; + ((t0_context *)t0ctx)->ip = ip; +} + + + +/* + * Verify the signature on the certificate with the provided public key. + * This function checks the public key type with regards to the expected + * type. Returned value is either 0 on success, or a non-zero error code. + */ +static int +verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk) +{ + int kt; + + kt = ctx->cert_signer_key_type; + if ((pk->key_type & 0x0F) != kt) { + return BR_ERR_X509_WRONG_KEY_TYPE; + } + switch (kt) { + unsigned char tmp[64]; + + case BR_KEYTYPE_RSA: + if (ctx->irsa == 0) { + return BR_ERR_X509_UNSUPPORTED; + } + if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len, + &t0_datablock[ctx->cert_sig_hash_oid], + ctx->cert_sig_hash_len, &pk->key.rsa, tmp)) + { + return BR_ERR_X509_BAD_SIGNATURE; + } + if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) { + return BR_ERR_X509_BAD_SIGNATURE; + } + return 0; + + case BR_KEYTYPE_EC: + if (ctx->iecdsa == 0) { + return BR_ERR_X509_UNSUPPORTED; + } + if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash, + ctx->cert_sig_hash_len, &pk->key.ec, + ctx->cert_sig, ctx->cert_sig_len)) + { + return BR_ERR_X509_BAD_SIGNATURE; + } + return 0; + + default: + return BR_ERR_X509_UNSUPPORTED; + } +} + + diff --git a/src/bearssl/src/x509/x509_minimal.t0 b/src/bearssl/src/x509/x509_minimal.t0 new file mode 100644 index 0000000..1e60016 --- /dev/null +++ b/src/bearssl/src/x509/x509_minimal.t0 @@ -0,0 +1,1508 @@ +\ Copyright (c) 2016 Thomas Pornin +\ +\ Permission is hereby granted, free of charge, to any person obtaining +\ a copy of this software and associated documentation files (the +\ "Software"), to deal in the Software without restriction, including +\ without limitation the rights to use, copy, modify, merge, publish, +\ distribute, sublicense, and/or sell copies of the Software, and to +\ permit persons to whom the Software is furnished to do so, subject to +\ the following conditions: +\ +\ The above copyright notice and this permission notice shall be +\ included in all copies or substantial portions of the Software. +\ +\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +\ SOFTWARE. + +preamble { + +#include "inner.h" + +/* + * Implementation Notes + * -------------------- + * + * The C code pushes the data by chunks; all decoding is done in the + * T0 code. The cert_length value is set to the certificate length when + * a new certificate is started; the T0 code picks it up as outer limit, + * and decoding functions use it to ensure that no attempt is made at + * reading past it. The T0 code also checks that once the certificate is + * decoded, there are no trailing bytes. + * + * The T0 code sets cert_length to 0 when the certificate is fully + * decoded. + * + * The C code must still perform two checks: + * + * -- If the certificate length is 0, then the T0 code will not be + * invoked at all. This invalid condition must thus be reported by the + * C code. + * + * -- When reaching the end of certificate, the C code must verify that + * the certificate length has been set to 0, thereby signaling that + * the T0 code properly decoded a certificate. + * + * Processing of a chain works in the following way: + * + * -- The error flag is set to a non-zero value when validation is + * finished. The value is either BR_ERR_X509_OK (validation is + * successful) or another non-zero error code. When a non-zero error + * code is obtained, the remaining bytes in the current certificate and + * the subsequent certificates (if any) are completely ignored. + * + * -- Each certificate is decoded in due course, with the following + * "interesting points": + * + * -- Start of the TBS: the multihash engine is reset and activated. + * + * -- Start of the issuer DN: the secondary hash engine is started, + * to process the encoded issuer DN. + * + * -- End of the issuer DN: the secondary hash engine is stopped. The + * resulting hash value is computed and then copied into the + * next_dn_hash[] buffer. + * + * -- Start of the subject DN: the secondary hash engine is started, + * to process the encoded subject DN. + * + * -- For the EE certificate only: the Common Name, if any, is matched + * against the expected server name. + * + * -- End of the subject DN: the secondary hash engine is stopped. The + * resulting hash value is computed into the pad. It is then processed: + * + * -- If this is the EE certificate, then the hash is ignored + * (except for direct trust processing, see later; the hash is + * simply left in current_dn_hash[]). + * + * -- Otherwise, the hashed subject DN is compared with the saved + * hash value (in saved_dn_hash[]). They must match. + * + * Either way, the next_dn_hash[] value is then copied into the + * saved_dn_hash[] value. Thus, at that point, saved_dn_hash[] + * contains the hash of the issuer DN for the current certificate, + * and current_dn_hash[] contains the hash of the subject DN for the + * current certificate. + * + * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown + * key types are reported at that point. + * + * -- If this is the EE certificate, then the key type is compared + * with the expected key type (initialization parameter). The public + * key data is copied to ee_pkey_data[]. The key and hashed subject + * DN are also compared with the "direct trust" keys; if the key + * and DN are matched, then validation ends with a success. + * + * -- Otherwise, the saved signature (cert_sig[]) is verified + * against the saved TBS hash (tbs_hash[]) and that freshly + * decoded public key. Failure here ends validation with an error. + * + * -- Extensions: extension values are processed in due order. + * + * -- Basic Constraints: for all certificates except EE, must be + * present, indicate a CA, and have a path legnth compatible with + * the chain length so far. + * + * -- Key Usage: for the EE, if present, must allow signatures + * or encryption/key exchange, as required for the cipher suite. + * For non-EE, if present, must have the "certificate sign" bit. + * + * -- Subject Alt Name: for the EE, dNSName names are matched + * against the server name. Ignored for non-EE. + * + * -- Authority Key Identifier, Subject Key Identifier, Issuer + * Alt Name, Subject Directory Attributes, CRL Distribution Points + * Freshest CRL, Authority Info Access and Subject Info Access + * extensions are always ignored: they either contain only + * informative data, or they relate to revocation processing, which + * we explicitly do not support. + * + * -- All other extensions are ignored if non-critical. If a + * critical extension other than the ones above is encountered, + * then a failure is reported. + * + * -- End of the TBS: the multihash engine is stopped. + * + * -- Signature algorithm: the signature algorithm on the + * certificate is decoded. A failure is reported if that algorithm + * is unknown. The hashed TBS corresponding to the signature hash + * function is computed and stored in tbs_hash[] (if not supported, + * then a failure is reported). The hash OID and length are stored + * in cert_sig_hash_oid and cert_sig_hash_len. + * + * -- Signature value: the signature value is copied into the + * cert_sig[] array. + * + * -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is + * looked up in the trust store (CA trust anchors only); for all + * that match, the signature (cert_sig[]) is verified against the + * anchor public key (hashed TBS is in tbs_hash[]). If one of these + * signatures is valid, then validation ends with a success. + * + * -- If the chain end is reached without obtaining a validation success, + * then validation is reported as failed. + */ + +#if BR_USE_UNIX_TIME +#include +#endif + +#if BR_USE_WIN32_TIME +#include +#endif + +/* + * The T0 compiler will produce these prototypes declarations in the + * header. + * +void br_x509_minimal_init_main(void *ctx); +void br_x509_minimal_run(void *ctx); + */ + +/* see bearssl_x509.h */ +void +br_x509_minimal_init(br_x509_minimal_context *ctx, + const br_hash_class *dn_hash_impl, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) +{ + memset(ctx, 0, sizeof *ctx); + ctx->vtable = &br_x509_minimal_vtable; + ctx->dn_hash_impl = dn_hash_impl; + ctx->trust_anchors = trust_anchors; + ctx->trust_anchors_num = trust_anchors_num; +} + +static void +xm_start_chain(const br_x509_class **ctx, const char *server_name) +{ + br_x509_minimal_context *cc; + size_t u; + + cc = (br_x509_minimal_context *)(void *)ctx; + for (u = 0; u < cc->num_name_elts; u ++) { + cc->name_elts[u].status = 0; + cc->name_elts[u].buf[0] = 0; + } + memset(&cc->pkey, 0, sizeof cc->pkey); + cc->num_certs = 0; + cc->err = 0; + cc->cpu.dp = cc->dp_stack; + cc->cpu.rp = cc->rp_stack; + br_x509_minimal_init_main(&cc->cpu); + if (server_name == NULL || *server_name == 0) { + cc->server_name = NULL; + } else { + cc->server_name = server_name; + } +} + +static void +xm_start_cert(const br_x509_class **ctx, uint32_t length) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err != 0) { + return; + } + if (length == 0) { + cc->err = BR_ERR_X509_TRUNCATED; + return; + } + cc->cert_length = length; +} + +static void +xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err != 0) { + return; + } + cc->hbuf = buf; + cc->hlen = len; + br_x509_minimal_run(&cc->cpu); +} + +static void +xm_end_cert(const br_x509_class **ctx) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err == 0 && cc->cert_length != 0) { + cc->err = BR_ERR_X509_TRUNCATED; + } + cc->num_certs ++; +} + +static unsigned +xm_end_chain(const br_x509_class **ctx) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err == 0) { + if (cc->num_certs == 0) { + cc->err = BR_ERR_X509_EMPTY_CHAIN; + } else { + cc->err = BR_ERR_X509_NOT_TRUSTED; + } + } else if (cc->err == BR_ERR_X509_OK) { + return 0; + } + return (unsigned)cc->err; +} + +static const br_x509_pkey * +xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages) +{ + br_x509_minimal_context *cc; + + cc = (br_x509_minimal_context *)(void *)ctx; + if (cc->err == BR_ERR_X509_OK + || cc->err == BR_ERR_X509_NOT_TRUSTED) + { + if (usages != NULL) { + *usages = cc->key_usages; + } + return &((br_x509_minimal_context *)(void *)ctx)->pkey; + } else { + return NULL; + } +} + +/* see bearssl_x509.h */ +const br_x509_class br_x509_minimal_vtable = { + sizeof(br_x509_minimal_context), + xm_start_chain, + xm_start_cert, + xm_append, + xm_end_cert, + xm_end_chain, + xm_get_pkey +}; + +#define CTX ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu))) +#define CONTEXT_NAME br_x509_minimal_context + +#define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK) + +/* + * Hash a DN (from a trust anchor) into the provided buffer. This uses the + * DN hash implementation and context structure from the X.509 engine + * context. + */ +static void +hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len, + unsigned char *out) +{ + ctx->dn_hash_impl->init(&ctx->dn_hash.vtable); + ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len); + ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out); +} + +/* + * Compare two big integers for equality. The integers use unsigned big-endian + * encoding; extra leading bytes (of value 0) are allowed. + */ +static int +eqbigint(const unsigned char *b1, size_t len1, + const unsigned char *b2, size_t len2) +{ + while (len1 > 0 && *b1 == 0) { + b1 ++; + len1 --; + } + while (len2 > 0 && *b2 == 0) { + b2 ++; + len2 --; + } + if (len1 != len2) { + return 0; + } + return memcmp(b1, b2, len1) == 0; +} + +/* + * Compare two strings for equality, in a case-insensitive way. This + * function handles casing only for ASCII letters. + */ +static int +eqnocase(const void *s1, const void *s2, size_t len) +{ + const unsigned char *buf1, *buf2; + + buf1 = s1; + buf2 = s2; + while (len -- > 0) { + int x1, x2; + + x1 = *buf1 ++; + x2 = *buf2 ++; + if (x1 >= 'A' && x1 <= 'Z') { + x1 += 'a' - 'A'; + } + if (x2 >= 'A' && x2 <= 'Z') { + x2 += 'a' - 'A'; + } + if (x1 != x2) { + return 0; + } + } + return 1; +} + +static int verify_signature(br_x509_minimal_context *ctx, + const br_x509_pkey *pk); + +} + +postamble { + +/* + * Verify the signature on the certificate with the provided public key. + * This function checks the public key type with regards to the expected + * type. Returned value is either 0 on success, or a non-zero error code. + */ +static int +verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk) +{ + int kt; + + kt = ctx->cert_signer_key_type; + if ((pk->key_type & 0x0F) != kt) { + return BR_ERR_X509_WRONG_KEY_TYPE; + } + switch (kt) { + unsigned char tmp[64]; + + case BR_KEYTYPE_RSA: + if (ctx->irsa == 0) { + return BR_ERR_X509_UNSUPPORTED; + } + if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len, + &t0_datablock[ctx->cert_sig_hash_oid], + ctx->cert_sig_hash_len, &pk->key.rsa, tmp)) + { + return BR_ERR_X509_BAD_SIGNATURE; + } + if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) { + return BR_ERR_X509_BAD_SIGNATURE; + } + return 0; + + case BR_KEYTYPE_EC: + if (ctx->iecdsa == 0) { + return BR_ERR_X509_UNSUPPORTED; + } + if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash, + ctx->cert_sig_hash_len, &pk->key.ec, + ctx->cert_sig, ctx->cert_sig_len)) + { + return BR_ERR_X509_BAD_SIGNATURE; + } + return 0; + + default: + return BR_ERR_X509_UNSUPPORTED; + } +} + +} + +cc: read8-low ( -- x ) { + if (CTX->hlen == 0) { + T0_PUSHi(-1); + } else { + unsigned char x = *CTX->hbuf ++; + if (CTX->do_mhash) { + br_multihash_update(&CTX->mhash, &x, 1); + } + if (CTX->do_dn_hash) { + CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1); + } + CTX->hlen --; + T0_PUSH(x); + } +} + +addr: cert_length +addr: num_certs + +cc: read-blob-inner ( addr len -- addr len ) { + uint32_t len = T0_POP(); + uint32_t addr = T0_POP(); + size_t clen = CTX->hlen; + if (clen > len) { + clen = (size_t)len; + } + if (addr != 0) { + memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); + } + if (CTX->do_mhash) { + br_multihash_update(&CTX->mhash, CTX->hbuf, clen); + } + if (CTX->do_dn_hash) { + CTX->dn_hash_impl->update( + &CTX->dn_hash.vtable, CTX->hbuf, clen); + } + CTX->hbuf += clen; + CTX->hlen -= clen; + T0_PUSH(addr + clen); + T0_PUSH(len - clen); +} + +\ Compute the TBS hash, using the provided hash ID. The hash value is +\ written in the tbs_hash[] array, and the hash length is returned. If +\ the requested hash function is not supported, then 0 is returned. +cc: compute-tbs-hash ( id -- hashlen ) { + int id = T0_POPi(); + size_t len; + len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash); + T0_PUSH(len); +} + +\ Push true (-1) if no server name is expected in the EE certificate. +cc: zero-server-name ( -- bool ) { + T0_PUSHi(-(CTX->server_name == NULL)); +} + +addr: key_usages +addr: cert_sig +addr: cert_sig_len +addr: cert_signer_key_type +addr: cert_sig_hash_oid +addr: cert_sig_hash_len +addr: tbs_hash +addr: min_rsa_size + +\ Start TBS hash computation. The hash functions are reinitialised. +cc: start-tbs-hash ( -- ) { + br_multihash_init(&CTX->mhash); + CTX->do_mhash = 1; +} + +\ Stop TBS hash computation. +cc: stop-tbs-hash ( -- ) { + CTX->do_mhash = 0; +} + +\ Start DN hash computation. +cc: start-dn-hash ( -- ) { + CTX->dn_hash_impl->init(&CTX->dn_hash.vtable); + CTX->do_dn_hash = 1; +} + +\ Terminate DN hash computation and write the DN hash into the +\ current_dn_hash buffer. +cc: compute-dn-hash ( -- ) { + CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash); + CTX->do_dn_hash = 0; +} + +\ Get the length of hash values obtained with the DN hasher. +cc: dn-hash-length ( -- len ) { + T0_PUSH(DNHASH_LEN); +} + +\ Copy data between two areas in the context. +cc: blobcopy ( addr-dst addr-src len -- ) { + size_t len = T0_POP(); + unsigned char *src = (unsigned char *)CTX + T0_POP(); + unsigned char *dst = (unsigned char *)CTX + T0_POP(); + memcpy(dst, src, len); +} + +addr: current_dn_hash +addr: next_dn_hash +addr: saved_dn_hash + +\ Read a DN, hashing it into current_dn_hash. The DN contents are not +\ inspected (only the outer tag, for SEQUENCE, is checked). +: read-DN ( lim -- lim ) + start-dn-hash + read-sequence-open skip-close-elt + compute-dn-hash ; + +cc: offset-name-element ( san -- n ) { + unsigned san = T0_POP(); + size_t u; + + for (u = 0; u < CTX->num_name_elts; u ++) { + if (CTX->name_elts[u].status == 0) { + const unsigned char *oid; + size_t len, off; + + oid = CTX->name_elts[u].oid; + if (san) { + if (oid[0] != 0 || oid[1] != 0) { + continue; + } + off = 2; + } else { + off = 0; + } + len = oid[off]; + if (len != 0 && len == CTX->pad[0] + && memcmp(oid + off + 1, + CTX->pad + 1, len) == 0) + { + T0_PUSH(u); + T0_RET(); + } + } + } + T0_PUSHi(-1); +} + +cc: copy-name-element ( bool offbuf -- ) { + size_t len; + int32_t off = T0_POPi(); + int ok = T0_POPi(); + + if (off >= 0) { + br_name_element *ne = &CTX->name_elts[off]; + + if (ok) { + len = CTX->pad[0]; + if (len < ne->len) { + memcpy(ne->buf, CTX->pad + 1, len); + ne->buf[len] = 0; + ne->status = 1; + } else { + ne->status = -1; + } + } else { + ne->status = -1; + } + } +} + +cc: copy-name-SAN ( bool tag -- ) { + unsigned tag = T0_POP(); + unsigned ok = T0_POP(); + size_t u, len; + + len = CTX->pad[0]; + for (u = 0; u < CTX->num_name_elts; u ++) { + br_name_element *ne; + + ne = &CTX->name_elts[u]; + if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) { + if (ok && ne->len > len) { + memcpy(ne->buf, CTX->pad + 1, len); + ne->buf[len] = 0; + ne->status = 1; + } else { + ne->status = -1; + } + break; + } + } +} + +\ Read a value, decoding string types. If the string type is recognised +\ and the value could be converted to UTF-8 into the pad, then true (-1) +\ is returned; in all other cases, false (0) is returned. Either way, the +\ object is consumed. +: read-string ( lim -- lim bool ) + read-tag case + \ UTF8String + 12 of check-primitive read-value-UTF8 endof + \ NumericString + 18 of check-primitive read-value-latin1 endof + \ PrintableString + 19 of check-primitive read-value-latin1 endof + \ TeletexString + 20 of check-primitive read-value-latin1 endof + \ IA5String + 22 of check-primitive read-value-latin1 endof + \ BMPString + 30 of check-primitive read-value-UTF16 endof + 2drop read-length-skip 0 0 + endcase ; + +\ Read a DN for the EE. The normalized DN hash is computed and stored in the +\ current_dn_hash. +\ Name elements are gathered. Also, the Common Name is matched against the +\ intended server name. +\ Returned value is true (-1) if the CN matches the intended server name, +\ false (0) otherwise. +: read-DN-EE ( lim -- lim bool ) + \ Flag will be set to true if there is a CN and it matches the + \ intended server name. + 0 { eename-matches } + + \ Activate DN hashing. + start-dn-hash + + \ Parse the DN structure: it is a SEQUENCE of SET of + \ AttributeTypeAndValue. Each AttributeTypeAndValue is a + \ SEQUENCE { OBJECT IDENTIFIER, ANY }. + read-sequence-open + begin + dup while + + read-tag 0x11 check-tag-constructed read-length-open-elt + dup ifnot ERR_X509_BAD_DN fail then + begin + dup while + + read-sequence-open + + \ Read the OID. If the OID could not be read (too + \ long) then the first pad byte will be 0. + read-OID drop + + \ If it is the Common Name then we'll need to + \ match it against the intended server name (if + \ applicable). + id-at-commonName eqOID { isCN } + + \ Get offset for reception buffer for that element + \ (or -1). + 0 offset-name-element { offbuf } + + \ Try to read the value as a string. + read-string + + \ If the value could be decoded as a string, + \ copy it and/or match it, as appropriate. + dup isCN and if + match-server-name if + -1 >eename-matches + then + then + offbuf copy-name-element + + \ Close the SEQUENCE + close-elt + + repeat + close-elt + repeat + close-elt + + \ Compute DN hash and deactivate DN hashing. + compute-dn-hash + + \ Return the CN match flag. + eename-matches ; + +\ Get the validation date and time from the context or system. +cc: get-system-date ( -- days seconds ) { + if (CTX->days == 0 && CTX->seconds == 0) { +#if BR_USE_UNIX_TIME + time_t x = time(NULL); + + T0_PUSH((uint32_t)(x / 86400) + 719528); + T0_PUSH((uint32_t)(x % 86400)); +#elif BR_USE_WIN32_TIME + FILETIME ft; + uint64_t x; + + GetSystemTimeAsFileTime(&ft); + x = ((uint64_t)ft.dwHighDateTime << 32) + + (uint64_t)ft.dwLowDateTime; + x = (x / 10000000); + T0_PUSH((uint32_t)(x / 86400) + 584754); + T0_PUSH((uint32_t)(x % 86400)); +#else + CTX->err = BR_ERR_X509_TIME_UNKNOWN; + T0_CO(); +#endif + } else { + T0_PUSH(CTX->days); + T0_PUSH(CTX->seconds); + } +} + +\ Compare two dates (days+seconds) together. +: before ( days1 seconds1 days2 seconds2 -- bool ) + { d1 s1 d2 s2 } + d1 d2 = if s1 s2 < else d1 d2 < then ; + +: after ( days1 seconds1 days2 seconds2 -- bool ) + swap2 before ; + +\ Swap the top two elements with the two elements immediately below. +: swap2 ( a b c d -- c d a b ) + 3 roll 3 roll ; + +\ Match the name in the pad with the expected server name. Returned value +\ is true (-1) on match, false (0) otherwise. If there is no expected +\ server name, then 0 is returned. +\ Match conditions: either an exact match (case insensitive), or a +\ wildcard match, if the found name starts with "*.". We only match a +\ starting wildcard, and only against a complete DN name component. +cc: match-server-name ( -- bool ) { + size_t n1, n2; + + if (CTX->server_name == NULL) { + T0_PUSH(0); + T0_RET(); + } + n1 = strlen(CTX->server_name); + n2 = CTX->pad[0]; + if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) { + T0_PUSHi(-1); + T0_RET(); + } + if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') { + size_t u; + + u = 0; + while (u < n1 && CTX->server_name[u] != '.') { + u ++; + } + u ++; + n1 -= u; + if ((n2 - 2) == n1 + && eqnocase(&CTX->pad[3], CTX->server_name + u, n1)) + { + T0_PUSHi(-1); + T0_RET(); + } + } + T0_PUSH(0); +} + +\ Get the address and length for the pkey_data buffer. +: addr-len-pkey_data ( -- addr len ) + CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) } + CX 0 8191 { BR_X509_BUFSIZE_KEY } ; + +\ Copy the EE public key to the permanent buffer (RSA). +cc: copy-ee-rsa-pkey ( nlen elen -- ) { + size_t elen = T0_POP(); + size_t nlen = T0_POP(); + memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen); + CTX->pkey.key_type = BR_KEYTYPE_RSA; + CTX->pkey.key.rsa.n = CTX->ee_pkey_data; + CTX->pkey.key.rsa.nlen = nlen; + CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen; + CTX->pkey.key.rsa.elen = elen; +} + +\ Copy the EE public key to the permanent buffer (EC). +cc: copy-ee-ec-pkey ( curve qlen -- ) { + size_t qlen = T0_POP(); + uint32_t curve = T0_POP(); + memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen); + CTX->pkey.key_type = BR_KEYTYPE_EC; + CTX->pkey.key.ec.curve = curve; + CTX->pkey.key.ec.q = CTX->ee_pkey_data; + CTX->pkey.key.ec.qlen = qlen; +} + +\ Check whether the current certificate (EE) is directly trusted. +cc: check-direct-trust ( -- ) { + size_t u; + + for (u = 0; u < CTX->trust_anchors_num; u ++) { + const br_x509_trust_anchor *ta; + unsigned char hashed_DN[64]; + int kt; + + ta = &CTX->trust_anchors[u]; + if (ta->flags & BR_X509_TA_CA) { + continue; + } + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); + if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) { + continue; + } + kt = CTX->pkey.key_type; + if ((ta->pkey.key_type & 0x0F) != kt) { + continue; + } + switch (kt) { + + case BR_KEYTYPE_RSA: + if (!eqbigint(CTX->pkey.key.rsa.n, + CTX->pkey.key.rsa.nlen, + ta->pkey.key.rsa.n, + ta->pkey.key.rsa.nlen) + || !eqbigint(CTX->pkey.key.rsa.e, + CTX->pkey.key.rsa.elen, + ta->pkey.key.rsa.e, + ta->pkey.key.rsa.elen)) + { + continue; + } + break; + + case BR_KEYTYPE_EC: + if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve + || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen + || memcmp(CTX->pkey.key.ec.q, + ta->pkey.key.ec.q, + ta->pkey.key.ec.qlen) != 0) + { + continue; + } + break; + + default: + continue; + } + + /* + * Direct trust match! + */ + CTX->err = BR_ERR_X509_OK; + T0_CO(); + } +} + +\ Check the signature on the certificate with regards to all trusted CA. +\ We use the issuer hash (in saved_dn_hash[]) as CA identifier. +cc: check-trust-anchor-CA ( -- ) { + size_t u; + + for (u = 0; u < CTX->trust_anchors_num; u ++) { + const br_x509_trust_anchor *ta; + unsigned char hashed_DN[64]; + + ta = &CTX->trust_anchors[u]; + if (!(ta->flags & BR_X509_TA_CA)) { + continue; + } + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); + if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) { + continue; + } + if (verify_signature(CTX, &ta->pkey) == 0) { + CTX->err = BR_ERR_X509_OK; + T0_CO(); + } + } +} + +\ Verify RSA signature. This uses the public key that was just decoded +\ into CTX->pkey_data; the modulus and exponent length are provided as +\ parameters. The resulting hash value is compared with the one in +\ tbs_hash. Returned value is 0 on success, or a non-zero error code. +cc: do-rsa-vrfy ( nlen elen -- err ) { + size_t elen = T0_POP(); + size_t nlen = T0_POP(); + br_x509_pkey pk; + + pk.key_type = BR_KEYTYPE_RSA; + pk.key.rsa.n = CTX->pkey_data; + pk.key.rsa.nlen = nlen; + pk.key.rsa.e = CTX->pkey_data + nlen; + pk.key.rsa.elen = elen; + T0_PUSH(verify_signature(CTX, &pk)); +} + +\ Verify ECDSA signature. This uses the public key that was just decoded +\ into CTX->pkey_dayta; the curve ID and public point length are provided +\ as parameters. The hash value in tbs_hash is used. Returned value is 0 +\ on success, or non-zero error code. +cc: do-ecdsa-vrfy ( curve qlen -- err ) { + size_t qlen = T0_POP(); + int curve = T0_POP(); + br_x509_pkey pk; + + pk.key_type = BR_KEYTYPE_EC; + pk.key.ec.curve = curve; + pk.key.ec.q = CTX->pkey_data; + pk.key.ec.qlen = qlen; + T0_PUSH(verify_signature(CTX, &pk)); +} + +cc: print-bytes ( addr len -- ) { + extern int printf(const char *fmt, ...); + size_t len = T0_POP(); + unsigned char *buf = (unsigned char *)CTX + T0_POP(); + size_t u; + + for (u = 0; u < len; u ++) { + printf("%02X", buf[u]); + } +} + +cc: printOID ( -- ) { + extern int printf(const char *fmt, ...); + size_t u, len; + + len = CTX->pad[0]; + if (len == 0) { + printf("*"); + T0_RET(); + } + printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40); + u = 2; + while (u <= len) { + unsigned long ul; + + ul = 0; + for (;;) { + int x; + + if (u > len) { + printf("BAD"); + T0_RET(); + } + x = CTX->pad[u ++]; + ul = (ul << 7) + (x & 0x7F); + if (!(x & 0x80)) { + break; + } + } + printf(".%lu", ul); + } +} + +\ Extensions with specific processing. +OID: basicConstraints 2.5.29.19 +OID: keyUsage 2.5.29.15 +OID: subjectAltName 2.5.29.17 +OID: certificatePolicies 2.5.29.32 + +\ Policy qualifier "pointer to CPS" +OID: id-qt-cps 1.3.6.1.5.5.7.2.1 + +\ Extensions which are ignored when encountered, even if critical. +OID: authorityKeyIdentifier 2.5.29.35 +OID: subjectKeyIdentifier 2.5.29.14 +OID: issuerAltName 2.5.29.18 +OID: subjectDirectoryAttributes 2.5.29.9 +OID: crlDistributionPoints 2.5.29.31 +OID: freshestCRL 2.5.29.46 +OID: authorityInfoAccess 1.3.6.1.5.5.7.1.1 +OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11 + +\ Process a Basic Constraints extension. This should be called only if +\ the certificate is not the EE. We check that the extension contains +\ the "CA" flag, and that the path length, if specified, is compatible +\ with the current chain length. +: process-basicConstraints ( lim -- lim ) + read-sequence-open + read-tag-or-end + dup 0x01 = if + read-boolean ifnot ERR_X509_NOT_CA fail then + read-tag-or-end + else + ERR_X509_NOT_CA fail + then + dup 0x02 = if + drop check-primitive read-small-int-value + addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then + read-tag-or-end + then + -1 <> if ERR_X509_UNEXPECTED fail then + drop + close-elt + ; + +\ Process a Key Usage extension. +\ For the EE certificate: +\ -- if the key usage contains keyEncipherment (2), dataEncipherment (3) +\ or keyAgreement (4), then the "key exchange" usage is allowed; +\ -- if the key usage contains digitalSignature (0) or nonRepudiation (1), +\ then the "signature" usage is allowed. +\ For CA certificates, the extension must contain keyCertSign (5). +: process-keyUsage ( lim ee -- lim ) + { ee } + + \ Read tag for the BIT STRING and open it. + read-tag 0x03 check-tag-primitive + read-length-open-elt + \ First byte indicates number of ignored bits in the last byte. It + \ must be between 0 and 7. + read8 { ign } + ign 7 > if ERR_X509_UNEXPECTED fail then + \ Depending on length, we have either 0, 1 or more bytes to read. + dup case + 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof + 1 of read8 ign >> ign << endof + drop read8 0 + endcase + + \ Check bits. + ee if + \ EE: get usages. + 0 + over 0x38 and if 0x10 or then + swap 0xC0 and if 0x20 or then + addr-key_usages set8 + else + \ Not EE: keyCertSign must be set. + 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then + then + + \ We don't care about subsequent bytes. + skip-close-elt ; + +\ Process a Certificate Policies extension. +\ +\ Since we don't actually support full policies processing, this function +\ only checks that the extension contents can be safely ignored. Indeed, +\ we don't validate against a specific set of policies (in RFC 5280 +\ terminology, user-initial-policy-set only contains the special value +\ any-policy). Moreover, we don't support policy constraints (if a +\ critical Policy Constraints extension is encountered, the validation +\ will fail). Therefore, we can safely ignore the contents of this +\ extension, except if it is critical AND one of the policy OID has a +\ qualifier which is distinct from id-qt-cps (because id-qt-cps is +\ specially designated by RFC 5280 has having no mandated action). +\ +\ This function is called only if the extension is critical. +: process-certPolicies ( lim -- lim ) + \ Extension value is a SEQUENCE OF PolicyInformation. + read-sequence-open + begin dup while + \ PolicyInformation ::= SEQUENCE { + \ policyIdentifier OBJECT IDENTIFIER, + \ policyQualifiers SEQUENCE OF PolicyQualifierInfo OPTIONAL + \ } + read-sequence-open + read-OID drop + dup if + read-sequence-open + begin dup while + \ PolicyQualifierInfo ::= SEQUENCE { + \ policyQualifierId OBJECT IDENTIFIER, + \ qualifier ANY + \ } + read-sequence-open + read-OID drop id-qt-cps eqOID ifnot + ERR_X509_CRITICAL_EXTENSION fail + then + skip-close-elt + repeat + close-elt + then + close-elt + repeat + close-elt ; + +\ Process a Subject Alt Name extension. Returned value is a boolean set +\ to true if the expected server name was matched against a dNSName in +\ the extension. +: process-SAN ( lim -- lim bool ) + 0 { m } + read-sequence-open + begin dup while + \ Read the tag. If the tag is context-0, then parse an + \ 'otherName'. If the tag is context-2, then parse a + \ dNSName. If the tag is context-1 or context-6, + \ parse + read-tag case + \ OtherName + 0x20 of + \ OtherName ::= SEQUENCE { + \ type-id OBJECT IDENTIFIER, + \ value [0] EXPLICIT ANY + \ } + check-constructed read-length-open-elt + read-OID drop + -1 offset-name-element { offbuf } + read-tag 0x20 check-tag-constructed + read-length-open-elt + read-string offbuf copy-name-element + close-elt + close-elt + endof + \ rfc822Name (IA5String) + 0x21 of + check-primitive + read-value-UTF8 1 copy-name-SAN + endof + \ dNSName (IA5String) + 0x22 of + check-primitive + read-value-UTF8 + dup if match-server-name m or >m then + 2 copy-name-SAN + endof + \ uniformResourceIdentifier (IA5String) + 0x26 of + check-primitive + read-value-UTF8 6 copy-name-SAN + endof + 2drop read-length-skip 0 + endcase + + \ We check only names of type dNSName; they use IA5String, + \ which is basically ASCII. + \ read-tag 0x22 = if + \ check-primitive + \ read-small-value drop + \ match-server-name m or >m + \ else + \ drop read-length-skip + \ then + repeat + close-elt + m ; + +\ Decode a certificate. The "ee" boolean must be true for the EE. +: decode-certificate ( ee -- ) + { ee } + + \ Obtain the total certificate length. + addr-cert_length get32 + + \ Open the outer SEQUENCE. + read-sequence-open + + \ TBS + \ Activate hashing. + start-tbs-hash + read-sequence-open + + \ First element may be an explicit version. We accept only + \ versions 0 to 2 (certificates v1 to v3). + read-tag dup 0x20 = if + drop check-constructed read-length-open-elt + read-tag + 0x02 check-tag-primitive + read-small-int-value + 2 > if ERR_X509_UNSUPPORTED fail then + close-elt + read-tag + then + + \ Serial number. We just check that the tag is correct. + 0x02 check-tag-primitive + read-length-skip + + \ Signature algorithm. This structure is redundant with the one + \ on the outside; we just skip it. + read-sequence-open skip-close-elt + + \ Issuer name: hashed, then copied into next_dn_hash[]. + read-DN + addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy + + \ Validity dates. + read-sequence-open + read-date get-system-date after if ERR_X509_EXPIRED fail then + read-date get-system-date before if ERR_X509_EXPIRED fail then + close-elt + + \ Subject name. + ee if + \ For the EE, we must check whether the Common Name, if + \ any, matches the expected server name. + read-DN-EE { eename } + else + \ For a non-EE certificate, the hashed subject DN must match + \ the saved hashed issuer DN from the previous certificate. + read-DN + addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob + ifnot ERR_X509_DN_MISMATCH fail then + then + \ Move the hashed issuer DN for this certificate into the + \ saved_dn_hash[] array. + addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy + + \ Public Key. + read-sequence-open + \ Algorithm Identifier. Right now we are only interested in the + \ OID, since we only support RSA keys. + read-sequence-open + read-OID ifnot ERR_X509_UNSUPPORTED fail then + { ; pkey-type } + choice + \ RSA public key. + rsaEncryption eqOID uf + skip-close-elt + \ Public key itself: the BIT STRING contains bytes + \ (no partial byte) and these bytes encode the + \ actual value. + read-bits-open + \ RSA public key is a SEQUENCE of two + \ INTEGER. We get both INTEGER values into + \ the pkey_data[] buffer, if they fit. + read-sequence-open + addr-len-pkey_data + read-integer { nlen } + addr-len-pkey_data swap nlen + swap nlen - + read-integer { elen } + close-elt + + \ Check that the public key fits our minimal + \ size requirements. Note that the integer + \ decoder already skipped the leading bytes + \ of value 0, so we are working on the true + \ modulus length here. + addr-min_rsa_size get16 128 + nlen > if + ERR_X509_WEAK_PUBLIC_KEY fail + then + close-elt + KEYTYPE_RSA >pkey-type + enduf + + \ EC public key. + id-ecPublicKey eqOID uf + \ We support only named curves, for which the + \ "parameters" field in the AlgorithmIdentifier + \ field should be an OID. + read-OID ifnot ERR_X509_UNSUPPORTED fail then + choice + ansix9p256r1 eqOID uf 23 enduf + ansix9p384r1 eqOID uf 24 enduf + ansix9p521r1 eqOID uf 25 enduf + ERR_X509_UNSUPPORTED fail + endchoice + { curve } + close-elt + read-bits-open + dup { qlen } + dup addr-len-pkey_data rot < if + ERR_X509_LIMIT_EXCEEDED fail + then + read-blob + KEYTYPE_EC >pkey-type + enduf + + \ Not a recognised public key type. + ERR_X509_UNSUPPORTED fail + endchoice + close-elt + + \ Process public key. + ee if + \ For the EE certificate, copy the key data to the + \ relevant buffer. + pkey-type case + KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof + KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof + ERR_X509_UNSUPPORTED fail + endcase + else + \ Verify signature on previous certificate. We invoke + \ the RSA implementation. + pkey-type case + KEYTYPE_RSA of nlen elen do-rsa-vrfy endof + KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof + ERR_X509_UNSUPPORTED fail + endcase + dup if fail then + drop + then + + \ This flag will be set to true if the Basic Constraints extension + \ is encountered. + 0 { seenBC } + + \ Skip issuerUniqueID and subjectUniqueID, and process extensions + \ if present. Extensions are an explicit context tag of value 3 + \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE + \ with an OID, an optional boolean, and a value; the value is + \ an OCTET STRING. + read-tag-or-end + 0x21 iftag-skip + 0x22 iftag-skip + dup 0x23 = if + drop + check-constructed read-length-open-elt + read-sequence-open + begin dup while + 0 { critical } + read-sequence-open + read-OID drop + read-tag dup 0x01 = if + read-boolean >critical + read-tag + then + 0x04 check-tag-primitive read-length-open-elt + choice + \ Extensions with specific processing. + basicConstraints eqOID uf + ee if + skip-remaining + else + process-basicConstraints + -1 >seenBC + then + enduf + keyUsage eqOID uf + ee process-keyUsage + enduf + subjectAltName eqOID uf + ee if + 0 >eename + process-SAN >eename + else + skip-remaining + then + enduf + + \ We don't implement full processing of + \ policies. The call below mostly checks + \ that the contents of the Certificate + \ Policies extension can be safely ignored. + certificatePolicies eqOID uf + critical if + process-certPolicies + else + skip-remaining + then + enduf + + \ Extensions which are always ignored, + \ even if critical. + authorityKeyIdentifier eqOID uf + skip-remaining + enduf + subjectKeyIdentifier eqOID uf + skip-remaining + enduf + issuerAltName eqOID uf + skip-remaining + enduf + subjectDirectoryAttributes eqOID uf + skip-remaining + enduf + crlDistributionPoints eqOID uf + skip-remaining + enduf + freshestCRL eqOID uf + skip-remaining + enduf + authorityInfoAccess eqOID uf + skip-remaining + enduf + subjectInfoAccess eqOID uf + skip-remaining + enduf + + \ Unrecognized extensions trigger a failure + \ if critical; otherwise, they are just + \ ignored. + critical if + ERR_X509_CRITICAL_EXTENSION fail + then + skip-remaining + endchoice + close-elt + close-elt + repeat + close-elt + close-elt + else + -1 = ifnot ERR_X509_UNEXPECTED fail then + drop + then + + close-elt + \ Terminate hashing. + stop-tbs-hash + + \ For the EE certificate, verify that the intended server name + \ was matched. + ee if + eename zero-server-name or ifnot + ERR_X509_BAD_SERVER_NAME fail + then + then + + \ If this is the EE certificate, then direct trust may apply. + \ Note: we do this at this point, not immediately after decoding + \ the public key, because even in case of direct trust we still + \ want to check the server name with regards to the SAN extension. + \ However, we want to check direct trust before trying to decode + \ the signature algorithm, because it should work even if that + \ algorithm is not supported. + ee if check-direct-trust then + + \ Non-EE certificates MUST have a Basic Constraints extension + \ (that marks them as being CA). + ee seenBC or ifnot ERR_X509_NOT_CA fail then + + \ signature algorithm + read-tag check-sequence read-length-open-elt + \ Read and understand the OID. Right now, we support only + \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1, + \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT + \ support MD5 here. + \ TODO: add support for RSA/PSS + read-OID if + \ Based on the signature OID, we get: + \ -- the signing key type + \ -- the hash function numeric identifier + \ -- the hash function OID + choice + sha1WithRSAEncryption eqOID + uf 2 KEYTYPE_RSA id-sha1 enduf + sha224WithRSAEncryption eqOID + uf 3 KEYTYPE_RSA id-sha224 enduf + sha256WithRSAEncryption eqOID + uf 4 KEYTYPE_RSA id-sha256 enduf + sha384WithRSAEncryption eqOID + uf 5 KEYTYPE_RSA id-sha384 enduf + sha512WithRSAEncryption eqOID + uf 6 KEYTYPE_RSA id-sha512 enduf + + ecdsa-with-SHA1 eqOID + uf 2 KEYTYPE_EC id-sha1 enduf + ecdsa-with-SHA224 eqOID + uf 3 KEYTYPE_EC id-sha224 enduf + ecdsa-with-SHA256 eqOID + uf 4 KEYTYPE_EC id-sha256 enduf + ecdsa-with-SHA384 eqOID + uf 5 KEYTYPE_EC id-sha384 enduf + ecdsa-with-SHA512 eqOID + uf 6 KEYTYPE_EC id-sha512 enduf + ERR_X509_UNSUPPORTED fail + endchoice + addr-cert_sig_hash_oid set16 + addr-cert_signer_key_type set8 + + \ Compute the TBS hash into tbs_hash. + compute-tbs-hash + dup ifnot ERR_X509_UNSUPPORTED fail then + addr-cert_sig_hash_len set8 + else + ERR_X509_UNSUPPORTED fail + then + \ We ignore the parameters, whether they are present or not, + \ because we got all the information from the OID. + skip-close-elt + + \ signature value + read-bits-open + dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if + ERR_X509_LIMIT_EXCEEDED fail + then + dup addr-cert_sig_len set16 + addr-cert_sig read-blob + + \ Close the outer SEQUENCE. + close-elt + + \ Close the advertised total certificate length. This checks that + \ there is no trailing garbage after the certificate. + close-elt + + \ Flag the certificate as fully processed. + 0 addr-cert_length set32 + + \ Check whether the issuer for the current certificate is known + \ as a trusted CA; in which case, verify the signature. + check-trust-anchor-CA ; + +: main + \ Unless restricted by a Key Usage extension, all usages are + \ deemed allowed. + 0x30 addr-key_usages set8 + -1 decode-certificate + co + begin + 0 decode-certificate co + again + ; diff --git a/src/bearssl/src/x509/x509_minimal_full.c b/src/bearssl/src/x509/x509_minimal_full.c new file mode 100644 index 0000000..2b54426 --- /dev/null +++ b/src/bearssl/src/x509/x509_minimal_full.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_x509.h */ +void +br_x509_minimal_init_full(br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) +{ + /* + * All hash functions are activated. + * Note: the X.509 validation engine will nonetheless refuse to + * validate signatures that use MD5 as hash function. + */ + static const br_hash_class *hashes[] = { + &br_md5_vtable, + &br_sha1_vtable, + &br_sha224_vtable, + &br_sha256_vtable, + &br_sha384_vtable, + &br_sha512_vtable + }; + + int id; + + br_x509_minimal_init(xc, &br_sha256_vtable, + trust_anchors, trust_anchors_num); + br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy); + br_x509_minimal_set_ecdsa(xc, + &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); + for (id = br_md5_ID; id <= br_sha512_ID; id ++) { + const br_hash_class *hc; + + hc = hashes[id - 1]; + br_x509_minimal_set_hash(xc, id, hc); + } +} From 0cb8cce5480d884c8f6d1c3feed08ceb98381cd4 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 19 Feb 2019 11:51:33 -0800 Subject: [PATCH 004/205] started writing class for an SSL Client --- SSLClient.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++ src/SSLClient.cpp | 22 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/SSLClient.cpp diff --git a/SSLClient.h b/SSLClient.h index bf50be5..8711efa 100644 --- a/SSLClient.h +++ b/SSLClient.h @@ -31,12 +31,66 @@ * And then call the functions they normally would with EthernetClient using SSLCLient. */ +#include #include "bearssl.h" +#include "Client.h" #ifdef SSLClient_H_ #define SSLClient_H_ +template +class SSLClient : public Client { +public: + /** Ctor + * Creates a new dynamically allocated Client object based on the + * one passed to client + * We copy the client because we aren't sure the Client object + * is going to exists past the inital creation of the SSLClient. + * @param client the (Ethernet)client object + */ + static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); + SSLClient(const C &client): + m_client(client) + { + } + /** Dtor is implicit since unique_ptr handles it fine */ + /** + * The virtual functions defining a Client are below + * Most of them smply pass through + */ + virtual int availableForWrite(void) const { return m_client.availableForWrite(); }; + virtual operator bool() const { return static_cast(m_client); } + virtual bool operator==(const bool value) const { return bool() == value; } + virtual bool operator!=(const bool value) const { return bool() != value; } + virtual bool operator==(const C& rhs) const { return m_client.operator==(rhs); } + virtual bool operator!=(const C& rhs) const { return !this->operator==(rhs); } + virtual uint16_t localPort() const { return m_client.localPort(); } + virtual IPAddress remoteIP() const { return m_client.remoteIP(); } + virtual uint16_t remotePort() const { return m_client.remotePort(); } + virtual void setConnectionTimeout(uint16_t timeout) { m_client.setConnectionTimeout(timeout); } + + /** functions specific to the EthernetClient which I'll have to override */ + uint8_t status() const; + uint8_t getSocketNumber() const; + /** functions dealing with read/write that BearSSL will be injected into */ + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + + +private: + // create a copy of the class + C m_client; +}; #endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp new file mode 100644 index 0000000..42f41bd --- /dev/null +++ b/src/SSLClient.cpp @@ -0,0 +1,22 @@ +/* Copyright 2019 OSU OPEnS Lab + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "SSLClient.h" + From 32fa4ac11d3fb9816a6d6da73987ae61fece6524 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 19 Feb 2019 14:29:50 -0800 Subject: [PATCH 005/205] restruturing according to arduino library guidlines --- .vscode/c_cpp_properties.json | 22 +++++++++++++ .vscode/settings.json | 25 ++++++++++++++ src/Client.h | 45 ++++++++++++++++++++++++++ src/SSLClient.cpp | 3 +- SSLClient.h => src/SSLClient.h | 15 +++++++-- bearssl.h => src/bearssl.h | 0 bearssl_aead.h => src/bearssl_aead.h | 0 bearssl_block.h => src/bearssl_block.h | 0 bearssl_ec.h => src/bearssl_ec.h | 0 bearssl_hash.h => src/bearssl_hash.h | 0 bearssl_hmac.h => src/bearssl_hmac.h | 0 bearssl_kdf.h => src/bearssl_kdf.h | 0 bearssl_pem.h => src/bearssl_pem.h | 0 bearssl_prf.h => src/bearssl_prf.h | 0 bearssl_rand.h => src/bearssl_rand.h | 0 bearssl_rsa.h => src/bearssl_rsa.h | 0 bearssl_ssl.h => src/bearssl_ssl.h | 0 bearssl_x509.h => src/bearssl_x509.h | 0 config.h => src/config.h | 0 inner.h => src/inner.h | 0 20 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 src/Client.h rename SSLClient.h => src/SSLClient.h (86%) rename bearssl.h => src/bearssl.h (100%) rename bearssl_aead.h => src/bearssl_aead.h (100%) rename bearssl_block.h => src/bearssl_block.h (100%) rename bearssl_ec.h => src/bearssl_ec.h (100%) rename bearssl_hash.h => src/bearssl_hash.h (100%) rename bearssl_hmac.h => src/bearssl_hmac.h (100%) rename bearssl_kdf.h => src/bearssl_kdf.h (100%) rename bearssl_pem.h => src/bearssl_pem.h (100%) rename bearssl_prf.h => src/bearssl_prf.h (100%) rename bearssl_rand.h => src/bearssl_rand.h (100%) rename bearssl_rsa.h => src/bearssl_rsa.h (100%) rename bearssl_ssl.h => src/bearssl_ssl.h (100%) rename bearssl_x509.h => src/bearssl_x509.h (100%) rename config.h => src/config.h (100%) rename inner.h => src/inner.h (100%) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..89064ed --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "SAMD", + "includePath": [ + "${workspaceFolder}/**", + "C:/Users/Noah/AppData/Local/Arduino15/packages/adafruit/hardware/samd/1.2.9/cores/arduino/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.17763.0", + "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Tools/MSVC/14.16.27023/bin/Hostx64/x64/cl.exe", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "msvc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f76f1b2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,25 @@ +{ + "files.associations": { + "cmath": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "limits": "cpp", + "memory": "cpp", + "new": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "utility": "cpp", + "xmemory": "cpp", + "xmemory0": "cpp", + "xstddef": "cpp", + "xtr1common": "cpp", + "xutility": "cpp" + } +} \ No newline at end of file diff --git a/src/Client.h b/src/Client.h new file mode 100644 index 0000000..b8e5d93 --- /dev/null +++ b/src/Client.h @@ -0,0 +1,45 @@ +/* + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef client_h +#define client_h +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 42f41bd..85c1e45 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -18,5 +18,4 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "SSLClient.h" - +#include "SSLClient.h" \ No newline at end of file diff --git a/SSLClient.h b/src/SSLClient.h similarity index 86% rename from SSLClient.h rename to src/SSLClient.h index 8711efa..36c6a5f 100644 --- a/SSLClient.h +++ b/src/SSLClient.h @@ -40,7 +40,17 @@ template class SSLClient : public Client { +/** static type checks + * I'm a java developer, so I want to ensure that my inheritance is safe. + * These checks ensure that all the functions we use on class C are + * actually present on class C. It does this by first checking that the + * class inherits from Client, and then that it contains a status() function. + */ +static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); +static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!"); + public: + /** Ctor * Creates a new dynamically allocated Client object based on the * one passed to client @@ -48,7 +58,6 @@ public: * is going to exists past the inital creation of the SSLClient. * @param client the (Ethernet)client object */ - static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); SSLClient(const C &client): m_client(client) { @@ -61,7 +70,7 @@ public: * Most of them smply pass through */ virtual int availableForWrite(void) const { return m_client.availableForWrite(); }; - virtual operator bool() const { return static_cast(m_client); } + virtual operator bool() const { return m_client.bool(); } virtual bool operator==(const bool value) const { return bool() == value; } virtual bool operator!=(const bool value) const { return bool() != value; } virtual bool operator==(const C& rhs) const { return m_client.operator==(rhs); } @@ -87,6 +96,8 @@ public: virtual void stop(); virtual uint8_t connected(); + /** get the client object */ + C& getClient() { return m_client; } private: // create a copy of the class diff --git a/bearssl.h b/src/bearssl.h similarity index 100% rename from bearssl.h rename to src/bearssl.h diff --git a/bearssl_aead.h b/src/bearssl_aead.h similarity index 100% rename from bearssl_aead.h rename to src/bearssl_aead.h diff --git a/bearssl_block.h b/src/bearssl_block.h similarity index 100% rename from bearssl_block.h rename to src/bearssl_block.h diff --git a/bearssl_ec.h b/src/bearssl_ec.h similarity index 100% rename from bearssl_ec.h rename to src/bearssl_ec.h diff --git a/bearssl_hash.h b/src/bearssl_hash.h similarity index 100% rename from bearssl_hash.h rename to src/bearssl_hash.h diff --git a/bearssl_hmac.h b/src/bearssl_hmac.h similarity index 100% rename from bearssl_hmac.h rename to src/bearssl_hmac.h diff --git a/bearssl_kdf.h b/src/bearssl_kdf.h similarity index 100% rename from bearssl_kdf.h rename to src/bearssl_kdf.h diff --git a/bearssl_pem.h b/src/bearssl_pem.h similarity index 100% rename from bearssl_pem.h rename to src/bearssl_pem.h diff --git a/bearssl_prf.h b/src/bearssl_prf.h similarity index 100% rename from bearssl_prf.h rename to src/bearssl_prf.h diff --git a/bearssl_rand.h b/src/bearssl_rand.h similarity index 100% rename from bearssl_rand.h rename to src/bearssl_rand.h diff --git a/bearssl_rsa.h b/src/bearssl_rsa.h similarity index 100% rename from bearssl_rsa.h rename to src/bearssl_rsa.h diff --git a/bearssl_ssl.h b/src/bearssl_ssl.h similarity index 100% rename from bearssl_ssl.h rename to src/bearssl_ssl.h diff --git a/bearssl_x509.h b/src/bearssl_x509.h similarity index 100% rename from bearssl_x509.h rename to src/bearssl_x509.h diff --git a/config.h b/src/config.h similarity index 100% rename from config.h rename to src/config.h diff --git a/inner.h b/src/inner.h similarity index 100% rename from inner.h rename to src/inner.h From 0d424049f08162f195b424fc227af3ed17380684 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 20 Feb 2019 16:58:26 -0800 Subject: [PATCH 006/205] started integrating bearssl, wrote SSL profile that only incorporates safe TLS1.2 ciphers --- src/SSLClient.h | 7 +- src/bearssl/TLS12_only_profile.c | 459 +++++++++++++++++++++++++++++++ src/config.h | 6 +- 3 files changed, 467 insertions(+), 5 deletions(-) create mode 100644 src/bearssl/TLS12_only_profile.c diff --git a/src/SSLClient.h b/src/SSLClient.h index 36c6a5f..8b3e389 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -100,8 +100,13 @@ public: C& getClient() { return m_client; } private: - // create a copy of the class + // create a copy of the client C m_client; + // store the context values required for SSL + br_ssl_client_context m_sslctx; + br_x509_minimal_context m_x509ctx; + unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO]; + br_sslio_context m_ioctx; }; #endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/src/bearssl/TLS12_only_profile.c b/src/bearssl/TLS12_only_profile.c new file mode 100644 index 0000000..b58ee01 --- /dev/null +++ b/src/bearssl/TLS12_only_profile.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "bearssl.h" + +/* + * A "profile" is an initialisation function for a SSL context, that + * configures a list of cipher suites and algorithm implementations. + * While BearSSL comes with a few predefined profiles, you might one + * to define you own, using the example below as guidance. + * + * Each individual initialisation call sets a parameter or an algorithm + * support. Setting a specific algorithm pulls in the implementation of + * that algorithm in the compiled binary, as per static linking + * behaviour. Removing some of this calls will then reduce total code + * footprint, but also mechanically prevents some features to be + * supported (protocol versions and cipher suites). + * + * The two below define profiles for the client and the server contexts, + * respectively. Of course, in a typical size-constrained application, + * you would use one or the other, not both, to avoid pulling in code + * for both. + * + * This profile has been modified to the following criteria + * * support only TLS 1.2 for security + * * Use a minimal size footprint + * * remove RSA_WITH_AES ciphers for above + */ + +void +TLS12_only_profile(br_ssl_client_context *cc + br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) +{ + /* + * The "full" profile supports all implemented cipher suites. + * + * Rationale for suite order, from most important to least + * important rule: + * + * -- Only support TLS 1.2 + * -- Don't support RSA and 3DES as they are weaker protocols + * -- Try to have Forward Secrecy (ECDHE suite) if possible. + * -- When not using Forward Secrecy, ECDH key exchange is + * better than RSA key exchange (slightly more expensive on the + * client, but much cheaper on the server, and it implies smaller + * messages). + * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller code). + * -- GCM is better than CBC. + * -- AES-128 is preferred over AES-256 (AES-128 is already + * strong enough, and AES-256 is 40% more expensive). + */ + static const uint16_t suites[] = { + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + }; + + /* + * Client context must be cleared at some point. This sets + * every value and pointer to 0 or NULL. + */ + br_ssl_client_zero(cc); + + /* + * Define minimum and maximum protocol versions. Supported + * versions are: + * BR_TLS10 TLS 1.0 + * BR_TLS11 TLS 1.1 + * BR_TLS12 TLS 1.2 + */ + br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); + + /* + * Set the PRF implementation(s). + * For TLS 1.0 and 1.1, the "prf10" is needed. + * For TLS 1.2, this depends on the cipher suite: + * -- cipher suites with a name ending in "SHA384" need "prf_sha384"; + * -- all others need "prf_sha256". + * + * Note that a cipher suite like TLS_RSA_WITH_AES_128_CBC_SHA will + * use SHA-1 for the per-record MAC (that's what the final "SHA" + * means), but still SHA-256 for the PRF when selected along with + * the TLS-1.2 protocol version. + */ + // br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + + /* + * Set hash functions for the engine. Required hash functions + * depend on the protocol and cipher suite: + * + * -- TLS 1.0 and 1.1 require both MD5 and SHA-1. + * -- With TLS 1.2, cipher suites with a name ending in "SHA384" + * require SHA-384. + * -- With TLS 1.2, cipher suites with a name ending in "SHA256" + * require SHA-256. + * -- With TLS 1.2, cipher suites with a name ending in "SHA" + * require both SHA-256 and SHA-1. + * + * Moreover, these hash functions are also used to compute + * hashes supporting signatures on the server side (for ECDHE_* + * cipher suites), and on the client side (for client + * certificates, except in the case of full static ECDH). In TLS + * 1.0 and 1.1, SHA-1 (and also MD5) will be used, but with TLS + * 1.2 these hash functions are negotiated between client and + * server; SHA-256 and/or SHA-384 should be sufficient in + * practice. + * + * Note that with current implementations, SHA-224 and SHA-256 + * share the same file, so if you use one, you may have the other + * one with no additional overhead. Similarly, SHA-384 and SHA-512 + * share the same implementation code. + */ + // br_ssl_engine_set_hash(&cc->eng, br_md5_ID, &br_md5_vtable); + // br_ssl_engine_set_hash(&cc->eng, br_sha1_ID, &br_sha1_vtable); + br_ssl_engine_set_hash(&cc->eng, br_sha224_ID, &br_sha224_vtable); + br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); + br_ssl_engine_set_hash(&cc->eng, br_sha384_ID, &br_sha384_vtable); + // br_ssl_engine_set_hash(&cc->eng, br_sha512_ID, &br_sha512_vtable); + + /* + * Set the cipher suites. All specified cipher suite MUST be + * supported, and the relevant algorithms MUST have been + * configured (failure to provide needed implementations may + * trigger unwanted behaviours like segfaults or overflows). + */ + br_ssl_engine_set_suites(&cc->eng, suites, + (sizeof suites) / (sizeof suites[0])); + + /* + * Public-key algorithm implementations. + * + * -- RSA public core ("rsapub") is needed for "RSA" key exchange + * (cipher suites whose name starts with TLS_RSA). + * + * -- RSA signature verification ("rsavrfy") is needed for + * "ECDHE_RSA" cipher suites (not ECDH_RSA). + * + * -- Elliptic curve implementation ("ec") is needed for cipher + * suites that use elliptic curves (both "ECDH" and "ECDHE" + * cipher suites). + * + * -- ECDSA signature verification is needed for "ECDHE_ECDSA" + * cipher suites (but not for ECDHE_RSA, ECDH_ECDSA or ECDH_RSA). + * + * Normally, you use the "default" implementations, obtained + * through relevant function calls. These functions return + * implementations that are deemed "best" for the current + * platform, where "best" means "fastest within constant-time + * implementations". Selecting the default implementation is a + * mixture of compile-time and runtime checks. + * + * Nevertheless, specific implementations may be selected + * explicitly, e.g. to use code which is slower but with a + * smaller footprint. + * + * The RSA code comes in three variants, called "i15", "i31" and + * "i32". The "i31" code is somewhat faster than the "i32" code. + * Usually, "i31" is faster than "i15", except on some specific + * architectures (ARM Cortex M0, M0+, M1 and M3) where the "i15" + * should be preferred (the "i15" code is constant-time, while + * the "i31" is not, and the "i15" code is faster anyway). + * + * ECDSA code also comes in "i15" and "i31" variants. As in the + * case of RSA, the "i31" code is faster, except on the small + * ARM Cortex M, where the "i15" code is faster and safer. + * + * There are no less than 10 elliptic curve implementations: + * + * - ec_c25519_i15, ec_c25519_i31, ec_c25519_m15 and ec_c25519_m31 + * implement Curve25519. + * + * - ec_p256_m15 and ec_p256_m31 implement NIST curve P-256. + * + * - ec_prime_i15 and ec_prime_i31 implement NIST curves P-256, + * P-384 and P-521. + * + * - ec_all_m15 is an aggregate implementation that uses + * ec_c25519_m15, ec_p256_m15 and ec_prime_i15. + * + * - ec_all_m31 is an aggregate implementation that uses + * ec_c25519_m31, ec_p256_m31 and ec_prime_i31. + * + * For a given curve, "m15" is faster than "i15" (but possibly + * with a larger code footprint) and "m31" is faster than "i31" + * (there again with a larger code footprint). For best + * performance, use ec_all_m31, except on the small ARM Cortex M + * where ec_all_m15 should be used. Referencing the other + * implementations directly will result in smaller code, but + * support for fewer curves and possibly lower performance. + */ + // br_ssl_client_set_default_rsapub(cc); + // br_ssl_engine_set_default_rsavrfy(&cc->eng); + // br_ssl_engine_set_default_ecdsa(&cc->eng); + //* Alternate: set implementations explicitly. + // br_ssl_client_set_rsapub(cc, &br_rsa_i31_public); + br_ssl_client_set_rsavrfy(cc, &br_rsa_i15_pkcs1_vrfy); + br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); + br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1); + //*/ + + /* + * Record handler: + * -- Cipher suites in AES_128_CBC, AES_256_CBC and 3DES_EDE_CBC + * need the CBC record handler ("set_cbc"). + * -- Cipher suites in AES_128_GCM and AES_256_GCM need the GCM + * record handler ("set_gcm"). + * -- Cipher suites in CHACHA20_POLY1305 need the ChaCha20+Poly1305 + * record handler ("set_chapol"). + */ + br_ssl_engine_set_cbc(&cc->eng, + &br_sslrec_in_cbc_vtable, + &br_sslrec_out_cbc_vtable); + br_ssl_engine_set_gcm(&cc->eng, + &br_sslrec_in_gcm_vtable, + &br_sslrec_out_gcm_vtable); + // br_ssl_engine_set_chapol(&cc->eng, + // &br_sslrec_in_chapol_vtable, + // &br_sslrec_out_chapol_vtable); + + /* + * Set the ChaCha20 and Poly1305 implementations + * Not included in this file orignally for some reason + */ + br_ssl_engine_set_default_chapol(&cc->eng); + + /* + * Symmetric encryption: + * -- AES_128_CBC and AES_256_CBC require an "aes_cbc" implementation + * (actually two implementations, for encryption and decryption). + * -- 3DES_EDE_CBC requires a "des_cbc" implementation + * (actually two implementations, for encryption and decryption). + * -- AES_128_GCM and AES_256_GCM require an "aes_ctr" imeplementation + * and also a GHASH implementation. + * + * Two 3DES implementations are provided: + * + * des_tab Classical table-based implementation; it is + * not constant-time. + * + * dest_ct Constant-time DES/3DES implementation. It is + * slower than des_tab. + * + * Four AES implementations are provided: + * + * aes_ct Constant-time AES implementation, for 32-bit + * systems. + * + * aes_ct64 Constant-time AES implementation, for 64-bit + * systems. It actually also runs on 32-bit systems, + * but, on such systems, it yields larger code and + * slightly worse performance. On 64-bit systems, + * aes_ct64 is about twice faster than aes_ct for + * CTR processing (GCM encryption and decryption), + * and for CBC (decryption only). + * + * aes_small Smallest implementation provided, but also the + * slowest, and it is not constant-time. Use it + * only if desperate for code size. + * + * aes_big Classical table-based AES implementation. This + * is decently fast and still resonably compact, + * but it is not constant-time. + * + * aes_x86ni Very fast implementation that uses the AES-NI + * opcodes on recent x86 CPU. But it may not be + * compiled in the library if the compiler or + * architecture is not supported; and the CPU + * may also not support the opcodes. Selection + * functions are provided to test for availability + * of the code and the opcodes. + * + * Whether having constant-time implementations is absolutely + * required for security depends on the context (in particular + * whether the target architecture actually has cache memory), + * and while side-channel analysis for non-constant-time AES + * code has been demonstrated in lab conditions, it certainly + * does not apply to all actual usages, and it has never been + * spotted in the wild. It is still considered cautious to use + * constant-time code by default, and to consider the other + * implementations only if duly measured performance issues make + * it mandatory. + */ + br_ssl_engine_set_aes_cbc(&cc->eng, + &br_aes_ct_cbcenc_vtable, + &br_aes_ct_cbcdec_vtable); + br_ssl_engine_set_aes_ctr(&cc->eng, + &br_aes_ct_ctr_vtable); + /* Alternate: aes_ct64 + br_ssl_engine_set_aes_cbc(&cc->eng, + &br_aes_ct64_cbcenc_vtable, + &br_aes_ct64_cbcdec_vtable); + br_ssl_engine_set_aes_ctr(&cc->eng, + &br_aes_ct64_ctr_vtable); + */ + /* Alternate: aes_small + br_ssl_engine_set_aes_cbc(&cc->eng, + &br_aes_small_cbcenc_vtable, + &br_aes_small_cbcdec_vtable); + br_ssl_engine_set_aes_ctr(&cc->eng, + &br_aes_small_ctr_vtable); + */ + /* Alternate: aes_big + br_ssl_engine_set_aes_cbc(&cc->eng, + &br_aes_big_cbcenc_vtable, + &br_aes_big_cbcdec_vtable); + br_ssl_engine_set_aes_ctr(&cc->eng, + &br_aes_big_ctr_vtable); + */ + /* 3DES Disabled + br_ssl_engine_set_des_cbc(&cc->eng, + &br_des_ct_cbcenc_vtable, + &br_des_ct_cbcdec_vtable); + */ + /* Alternate: des_tab + br_ssl_engine_set_des_cbc(&cc->eng, + &br_des_tab_cbcenc_vtable, + &br_des_tab_cbcdec_vtable); + */ + + /* + * GHASH is needed for AES_128_GCM and AES_256_GCM. Three + * implementations are provided: + * + * ctmul Uses 32-bit multiplications with a 64-bit result. + * + * ctmul32 Uses 32-bit multiplications with a 32-bit result. + * + * ctmul64 Uses 64-bit multiplications with a 64-bit result. + * + * On 64-bit platforms, ctmul64 is the smallest and fastest of + * the three. On 32-bit systems, ctmul should be preferred. The + * ctmul32 implementation is meant to be used for the specific + * 32-bit systems that do not have a 32x32->64 multiplier (i.e. + * the ARM Cortex-M0 and Cortex-M0+). + * + * These implementations are all constant-time as long as the + * underlying multiplication opcode is constant-time (which is + * true for all modern systems, but not for older architectures + * such that ARM9 or 80486). + */ + /* + br_ssl_engine_set_ghash(&cc->eng, + &br_ghash_ctmul); */ + //* Alternate: ghash_ctmul32 + br_ssl_engine_set_ghash(&cc->eng, + &br_ghash_ctmul32); + //*/ + /* Alternate: ghash_ctmul64 + br_ssl_engine_set_ghash(&cc->eng, + &br_ghash_ctmul64); + */ + + /* + * For a client, the normal case is to validate the server + * certificate with regards to a set of trust anchors. This + * entails using a br_x509_minimal_context structure, configured + * with the relevant algorithms, as shown below. + * + * Alternatively, the client could "know" the intended server + * public key through an out-of-band mechanism, in which case + * a br_x509_knownkey_context is appropriate, for a much reduced + * code footprint. + * + * We assume here that the following extra parameters have been + * provided: + * + * xc engine context (br_x509_minimal_context *) + * trust_anchors trust anchors (br_x509_trust_anchor *) + * trust_anchors_num number of trust anchors (size_t) + */ + + /* + * The X.509 engine needs a hash function for processing the + * subject and issuer DN of certificates and trust anchors. Any + * supported hash function is appropriate; here we use SHA-256. + * The trust an + */ + br_x509_minimal_init(xc, &br_sha256_vtable, + trust_anchors, trust_anchors_num); + + /* + * Set suites and asymmetric crypto implementations. We use the + * "i31" code for RSA (it is somewhat faster than the "i32" + * implementation). These implementations are used for + * signature verification on certificates, but not for the + * SSL-specific usage of the server's public key. For instance, + * if the server has an EC public key but the rest of the chain + * (intermediate CA, root...) use RSA, then you would need only + * the RSA verification function below. + */ + // br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy); + br_x509_minimal_set_rsa(xc, &br_rsa_i15_pkcs1_vrfy); + // br_x509_minimal_set_ecdsa(xc, + // &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); + br_x509_minimal_set_ecdsa(xc, + &br_ec_all_m15, &br_ecdsa_i15_vrfy_asn1); + + /* + * Set supported hash functions. These are for signatures on + * certificates. There again, you only need the hash functions + * that are actually used in certificates, but if a given + * function was included for the SSL engine, you may as well + * add it here. + * + * Note: the engine explicitly rejects signatures that use MD5. + * Thus, there is no need for MD5 here. + */ + // br_ssl_engine_set_hash(xc, br_sha1_ID, &br_sha1_vtable); + br_ssl_engine_set_hash(xc, br_sha224_ID, &br_sha224_vtable); + br_ssl_engine_set_hash(xc, br_sha256_ID, &br_sha256_vtable); + br_ssl_engine_set_hash(xc, br_sha384_ID, &br_sha384_vtable); + // br_ssl_engine_set_hash(xc, br_sha512_ID, &br_sha512_vtable); + + /* + * Link the X.509 engine in the SSL engine. + */ + br_ssl_engine_set_x509(&cc->eng, &xc->vtable); +} diff --git a/src/config.h b/src/config.h index 8ea4d8a..001b352 100644 --- a/src/config.h +++ b/src/config.h @@ -47,9 +47,8 @@ * substantially more efficient than 32-bit multiplications that yield * 64-bit results. This is typically the case on low-end ARM Cortex M * systems (M0, M0+, M1, and arguably M3 and M4 as well). - * -#define BR_LOMUL 1 */ +#define BR_LOMUL 1 /* * When BR_SLOW_MUL is enabled, multiplications are assumed to be @@ -159,9 +158,8 @@ * This is meant for the low-end cores (Cortex M0, M0+, M1, M3). * Note: if BR_LOMUL is not explicitly enabled or disabled, then * enabling BR_ARMEL_CORTEXM_GCC also enables BR_LOMUL. - * -#define BR_ARMEL_CORTEXM_GCC 1 */ +#define BR_ARMEL_CORTEXM_GCC 1 /* * When BR_AES_X86NI is enabled, the AES implementation using the x86 "NI" From 093d1fac8b83a160502e98402e8d4ebe321edba3 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 21 Feb 2019 11:45:52 -0800 Subject: [PATCH 007/205] made a lot of progress creating the SSLClient, slow but steady --- src/SSLClient.cpp | 65 +++++++++++++++++++++++- src/SSLClient.h | 84 +++++++++++++++++++++++++++----- src/bearssl/TLS12_only_profile.c | 6 +-- src/bearssl/src/ssl/ssl_io.c | 12 ++--- src/bearssl_ssl.h | 32 ++++++++++++ 5 files changed, 178 insertions(+), 21 deletions(-) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 85c1e45..045bfda 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -18,4 +18,67 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "SSLClient.h" \ No newline at end of file +#include "SSLClient.h" + +/** see SSLClient.h */ +SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) { + // initlalize the various bearssl libraries so they're ready to go when we connect + br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + br_ssl_engine_set_buffer(&m_sslctx, m_iobuf, sizeof m_iobuf, 0); + br_sslio_init(&m_ioctx, &m_sslctx.eng, m_readraw, NULL, m_writeraw, NULL); +} + +/* see SSLClient.h */ +virtual int SSLClient::connect(IPAddress ip, uint16_t port) { + // Warning for security + m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible.") + // first we need our hidden client member to negotiate the socket for us, + // since most times socket functionality is implemented in hardeware. + if (!this->m_client.connect(ip, port)) { + m_print("Failed to connect using m_client"); + return 0; + } + // reset the client context, and look for previous sessions + // in this case we also provide NULL host since we only have an IP + br_ssl_client_reset(&sc, NULL, 1); + // initlalize the SSL socket over the network + // normally this would happen in br_sslio_write, but I think it makes + // a little more structural sense to put it here + if (br_run_until(ctx, BR_SSL_SENDAPP) < 0) { + m_print("Failed to initlalize the SSL layer"); + return 0; + } + // all good to go! the SSL socket should be up and running + m_print("SSL Initialized"); + return 1; +} + +/* see SSLClient.h */ +virtual int SSLClient::connect(const char *host, uint16_t port) { + // first we need our hidden client member to negotiate the socket for us, + // since most times socket functionality is implemented in hardeware. + if (!this->m_client.connect(host, port)) { + m_print("Failed to connect using m_client"); + return 0; + } + // reset the client context, and look for previous sessions + br_ssl_client_reset(&sc, host, 1); + // initlalize the SSL socket over the network + // normally this would happen in br_sslio_write, but I think it makes + // a little more structural sense to put it here + if (br_run_until(ctx, BR_SSL_SENDAPP) < 0) { + m_print("Failed to initlalize the SSL layer"); + return 0; + } + // all good to go! the SSL socket should be up and running + m_print("SSL Initialized"); + return 1; +} + +virtual size_t SSLClient::write(const uint8_t *buf, size_t size) { + // check if the socket is still open and such + + // write to the ssl socket using bearssl, and error check + int status = br_sslio_write_all(&m_ioctx, buf, len); + if (status < 0 ) +} \ No newline at end of file diff --git a/src/SSLClient.h b/src/SSLClient.h index 8b3e389..d14135d 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -50,18 +50,22 @@ static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!"); public: - - /** Ctor - * Creates a new dynamically allocated Client object based on the - * one passed to client + /** + * @brief copies the client object and initializes SSL contexts for bearSSL * We copy the client because we aren't sure the Client object * is going to exists past the inital creation of the SSLClient. * @param client the (Ethernet)client object + * @param trust_anchors Trust anchors used in the verification + * of the SSL server certificate, generated using the `brssl` command + * line utility. For more information see the samples or bearssl.org + * @param trust_anchors_num The number of trust anchors stored + * @param debug whether to enable or disable debug logging, must be constexpr */ - SSLClient(const C &client): - m_client(client) - { - } + SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true) + : m_client(client) + , m_trust_anchors(trust_anchors) + , m_trust_anchors_num(trust_anchors_num) + , m_debug(debug); /** Dtor is implicit since unique_ptr handles it fine */ @@ -83,10 +87,50 @@ public: /** functions specific to the EthernetClient which I'll have to override */ uint8_t status() const; uint8_t getSocketNumber() const; + /** functions dealing with read/write that BearSSL will be injected into */ - virtual int connect(IPAddress ip, uint16_t port); - virtual int connect(const char *host, uint16_t port); - virtual size_t write(uint8_t); + /** + * @brief Connect over SSL to a host specified by an ip address + * + * SSLClient::connect(host, port) should be preffered over this function, + * as verifying the domain name is a step in ensuring the certificate is + * legitimate, which is important to the security of the device. Additionally, + * SSL sessions cannot be resumed, which can drastically increase initial + * connect time. + * + * This function initializes EthernetClient by calling EthernetClient::connect + * with the parameters supplied, then once the socket is open initializes + * the appropriete bearssl contexts using the TLS_only_profile. Due to the + * design of the SSL standard, this function will probably take an extended + * period (1-2sec) to negotiate the handshake and finish the connection. + * + * @param ip The ip address to connect to + * @param port the port to connect to + * @returns 1 if success, 0 if failure (as found in EthernetClient) + */ + virtual int connect(IPAddress ip, uint16_t port = 443); + /** + * @brief Connect over SSL using connect(ip, port), but use a DNS lookup to + * get the IP Address first. + * + * This function initializes EthernetClient by calling EthernetClient::connect + * with the parameters supplied, then once the socket is open initializes + * the appropriete bearssl contexts using the TLS_only_profile. + * + * Due to the design of the SSL standard, this function will probably take an + * extended period (1-2sec) to negotiate the handshake and finish the + * connection. Since the hostname is provided, however, BearSSL is able to keep + * a session cache of the clients we have connected to. This should reduce + * connection time greatly. In order to use this feature, you must reuse the + * same SSLClient object to connect to the reused host. Doing this will allow + * BearSSL to automatically match the hostname to a cached session. + * + * @param host The cstring host ("www.google.com") + * @param port the port to connect to + * @returns 1 of success, 0 if failure (as found in EthernetClient) + */ + virtual int connect(const char *host, uint16_t port = 443); + virtual size_t write(uint8_t b) { return write(&b, 1); } virtual size_t write(const uint8_t *buf, size_t size); virtual int available(); virtual int read(); @@ -100,8 +144,26 @@ public: C& getClient() { return m_client; } private: + /** @brief debugging print function, only prints if m_debug is true */ + template + constexpr void m_print(const T str) { + if (m_debug) { + Serial.print("SSLClient: "); + Serial.println(str); + } + } + /** Callback function pointing to m_client.read to be used by the br_sslio API */ + int m_readraw(void *ctx, unsigned char *buf, size_t len); + /** Callback function pointing to m_client.write to be used by the br_sslio API */ + int m_writeraw(void *ctx, unsigned char *buf, size_t len); // create a copy of the client C m_client; + // store pointers to the trust anchors + // should not be computed at runtime + constexpr br_x509_trust_anchor *m_trust_anchors; + constexpr size_t m_trust_anchors_num; + // store whether to enable debug logging + constexpr bool m_debug; // store the context values required for SSL br_ssl_client_context m_sslctx; br_x509_minimal_context m_x509ctx; diff --git a/src/bearssl/TLS12_only_profile.c b/src/bearssl/TLS12_only_profile.c index b58ee01..4400b5a 100644 --- a/src/bearssl/TLS12_only_profile.c +++ b/src/bearssl/TLS12_only_profile.c @@ -49,18 +49,18 @@ */ void -TLS12_only_profile(br_ssl_client_context *cc +br_client_init_TLS12_only(br_ssl_client_context *cc, br_x509_minimal_context *xc, const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) { /* - * The "full" profile supports all implemented cipher suites. + * The TLS1.2 profile supports widely used implemented cipher suites. * * Rationale for suite order, from most important to least * important rule: * * -- Only support TLS 1.2 - * -- Don't support RSA and 3DES as they are weaker protocols + * -- Don't support RSA and 3DES as primary encryption as they are weaker protocols * -- Try to have Forward Secrecy (ECDHE suite) if possible. * -- When not using Forward Secrecy, ECDH key exchange is * better than RSA key exchange (slightly more expensive on the diff --git a/src/bearssl/src/ssl/ssl_io.c b/src/bearssl/src/ssl/ssl_io.c index 1952615..e929228 100644 --- a/src/bearssl/src/ssl/ssl_io.c +++ b/src/bearssl/src/ssl/ssl_io.c @@ -48,8 +48,8 @@ br_sslio_init(br_sslio_context *ctx, * combination of both (the combination matches either). When a match is * achieved, this function returns 0. On error, it returns -1. */ -static int -run_until(br_sslio_context *ctx, unsigned target) +int +br_run_until(br_sslio_context *ctx, unsigned target) { for (;;) { unsigned state; @@ -152,7 +152,7 @@ br_sslio_read(br_sslio_context *ctx, void *dst, size_t len) if (len == 0) { return 0; } - if (run_until(ctx, BR_SSL_RECVAPP) < 0) { + if (br_run_until(ctx, BR_SSL_RECVAPP) < 0) { return -1; } buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen); @@ -194,7 +194,7 @@ br_sslio_write(br_sslio_context *ctx, const void *src, size_t len) if (len == 0) { return 0; } - if (run_until(ctx, BR_SSL_SENDAPP) < 0) { + if (br_run_until(ctx, BR_SSL_SENDAPP) < 0) { return -1; } buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen); @@ -238,7 +238,7 @@ br_sslio_flush(br_sslio_context *ctx) * first sent down the wire before considering anything else. */ br_ssl_engine_flush(ctx->engine, 0); - return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP); + return br_run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP); } /* see bearssl_ssl.h */ @@ -252,7 +252,7 @@ br_sslio_close(br_sslio_context *ctx) */ size_t len; - run_until(ctx, BR_SSL_RECVAPP); + br_run_until(ctx, BR_SSL_RECVAPP); if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) { br_ssl_engine_recvapp_ack(ctx->engine, len); } diff --git a/src/bearssl_ssl.h b/src/bearssl_ssl.h index 8c8c86b..d28405a 100644 --- a/src/bearssl_ssl.h +++ b/src/bearssl_ssl.h @@ -2735,6 +2735,24 @@ void br_ssl_client_init_full(br_ssl_client_context *cc, br_x509_minimal_context *xc, const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); +/** + * \brief SSL client profile: TLS1.2 minus weak ciphers + * + * This function initialises the provided SSL client context with + * most (see brief) supported algorithms and cipher suites. It also initialises + * a companion X.509 validation engine with most supported algorithms, + * and the provided trust anchors; the X.509 engine will be used by + * the client context to validate the server's certificate. + * + * \param cc client context to initialise. + * \param xc X.509 validation context to initialise. + * \param trust_anchors trust anchors to use. + * \param trust_anchors_num number of trust anchors. + */ +void br_client_init_TLS12_only(br_ssl_client_context *cc, + br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + /** * \brief Clear the complete contents of a SSL client context. * @@ -4136,6 +4154,20 @@ int br_sslio_flush(br_sslio_context *cc); */ int br_sslio_close(br_sslio_context *cc); +/* + * Run the engine, until the specified target state is achieved, or + * an error occurs. The target state is SENDAPP, RECVAPP, or the + * combination of both (the combination matches either). When a match is + * achieved, this function returns 0. On error, it returns -1. + * + * Static function made public since we would like to be able to + * initialize the ssl socket in a single function + * + * \return 0 on success, or -1 on error. + */ +int +br_run_until(br_sslio_context *ctx, unsigned target); + /* ===================================================================== */ /* From f4ea538dabf6206984078ffc97b1fbf9a12c0ae2 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 25 Feb 2019 18:18:41 -0800 Subject: [PATCH 008/205] refactored client to use the generic IO API for bearSSL, need to figure out a way to structure write() such that bytes are only written when availible() is called, to allow for multiple calls without significant delay and/or bugs --- src/SSLClient.cpp | 166 +++++++++++++++++++++++++++++++++++++++++++--- src/SSLClient.h | 43 +++++++++--- 2 files changed, 193 insertions(+), 16 deletions(-) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 045bfda..d4c2981 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -24,32 +24,36 @@ SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) { // initlalize the various bearssl libraries so they're ready to go when we connect br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); - br_ssl_engine_set_buffer(&m_sslctx, m_iobuf, sizeof m_iobuf, 0); + // check if the buffer size is half or full duplex + constexpr auto duplex = sizeof iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; + br_ssl_engine_set_buffer(&m_sslctx, m_iobuf, sizeof m_iobuf, duplex); br_sslio_init(&m_ioctx, &m_sslctx.eng, m_readraw, NULL, m_writeraw, NULL); } /* see SSLClient.h */ virtual int SSLClient::connect(IPAddress ip, uint16_t port) { // Warning for security - m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible.") + m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible."); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!this->m_client.connect(ip, port)) { m_print("Failed to connect using m_client"); + setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } // reset the client context, and look for previous sessions - // in this case we also provide NULL host since we only have an IP br_ssl_client_reset(&sc, NULL, 1); // initlalize the SSL socket over the network // normally this would happen in br_sslio_write, but I think it makes // a little more structural sense to put it here - if (br_run_until(ctx, BR_SSL_SENDAPP) < 0) { + if (m_run_until(ctx, BR_SSL_SENDAPP) < 0) { m_print("Failed to initlalize the SSL layer"); + setWriteError(SSL_BR_CONNECT_FAIL); return 0; } // all good to go! the SSL socket should be up and running m_print("SSL Initialized"); + setWriteError(SSL_OK); return 1; } @@ -59,6 +63,7 @@ virtual int SSLClient::connect(const char *host, uint16_t port) { // since most times socket functionality is implemented in hardeware. if (!this->m_client.connect(host, port)) { m_print("Failed to connect using m_client"); + setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } // reset the client context, and look for previous sessions @@ -66,19 +71,164 @@ virtual int SSLClient::connect(const char *host, uint16_t port) { // initlalize the SSL socket over the network // normally this would happen in br_sslio_write, but I think it makes // a little more structural sense to put it here - if (br_run_until(ctx, BR_SSL_SENDAPP) < 0) { + if (m_run_until(BR_SSL_SENDAPP) < 0) { m_print("Failed to initlalize the SSL layer"); + setWriteError(SSL_BR_CONNECT_FAIL); return 0; } // all good to go! the SSL socket should be up and running m_print("SSL Initialized"); + setWriteError(SSL_OK); return 1; } +/** see SSLClient.h TODO: fix */ virtual size_t SSLClient::write(const uint8_t *buf, size_t size) { // check if the socket is still open and such - + if(!m_client.connected()) { + m_print("Client is not connected! Perhaps something has happened?"); + setWriteError(SSL_CLIENT_CONNECT_FAIL); + return 0; + } // write to the ssl socket using bearssl, and error check - int status = br_sslio_write_all(&m_ioctx, buf, len); - if (status < 0 ) + const auto status = br_sslio_write_all(&m_ioctx, buf, size); + if (status != size) { + if (status < 0) { + m_print("Encountered a write error:"); + if (m_client.getWriteError()) { + m_print("m_client write error"); + setWriteError(SSL_CLIENT_WRTIE_ERROR); + } + else { + m_print("bearssl write error: "); + m_print(err = br_ssl_engine_last_error(&m_sslctx.eng)); + setWriteError(SSL_BR_WRITE_ERROR); + } + return 0; + } + m_print("Warn: Wrote less than status! Something might be wrong"); + } + return status; +} + +virtual int SSLClient::available() { + if (!m_client.connected()) { + m_print("Cannot check available of disconnected client!"); + return 0; + } + // run the SSL engine until we are waiting for either user input or a server response + unsigned state = m_update_engine(); + if(state & BR_SSL_RECVAPP) { + // return how many received bytes we have + size_t alen; + br_ssl_engine_recvapp_buf(ctx->engine, &alen); + return (int)alen; + } + else if (state == BR_SSL_CLOSED) m_print("Tried to check available when engine is closed!"); + // flush the buffer if it's stuck in the SENDAPP state + else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(m_sslctx->engine, 0); + else if (state == 0) { + m_print("SSL engine failed: "); + m_print(br_ssl_engine_last_error(&m_sslctx)); + setWriteError(SSL_BR_WRITE_ERROR); + } + // other state, or client is closed + return 0; +} + +int SSLClient::m_run_until(const unsigned target) { + for (;;) { + unsigned state = m_update_engine(); + /* + * If we reached our target, then we are finished. + */ + if (state & target) return 0; + + /* + * If some application data must be read, and we did not + * exit, then this means that we are trying to write data, + * and that's not possible until the application data is + * read. This may happen if using a shared in/out buffer, + * and the underlying protocol is not strictly half-duplex. + * This is unrecoverable here, so we report an error. + */ + if (state & BR_SSL_RECVAPP && target & BR_SSL_SENDAPP) return -1; + + /* + * We can reach that point if the target RECVAPP, and + * the state contains SENDAPP only. This may happen with + * a shared in/out buffer. In that case, we must flush + * the buffered data to "make room" for a new incoming + * record. + */ + if (state & SENDAPP && target & RECVAPP) br_ssl_engine_flush(m_sslctx->engine, 0); + } +} + +unsigned SSLClient::m_update_engine() { + for(;;) { + // get the state + unsigned state = br_ssl_engine_current_state(m_sslctx->engine); + if (state & BR_SSL_CLOSED) return state; + /* + * If there is some record data to send, do it. This takes + * precedence over everything else. + */ + if (state & BR_SSL_SENDREC) { + unsigned char *buf; + size_t len; + int wlen; + + buf = br_ssl_engine_sendrec_buf(ctx->engine, &len); + wlen = m_client.write(buf, len); + if (wlen < 0) { + /* + * If we received a close_notify and we + * still send something, then we have our + * own response close_notify to send, and + * the peer is allowed by RFC 5246 not to + * wait for it. + */ + if (!ctx->engine->shutdown_recv) { + br_ssl_engine_fail( + ctx->engine, BR_ERR_IO); + } + setWriteError(SSL_BR_WRITE_ERROR); + return 0; + } + if (wlen > 0) { + br_ssl_engine_sendrec_ack(ctx->engine, wlen); + } + continue; + } + + /* + * If there is some record data to recieve, check if we've + * recieved it so far. If we have, then we can update the state. + * else we can return that we're still waiting for the server. + */ + if (state & BR_SSL_RECVREC) { + size_t len; + unsigned char * buf = br_ssl_engine_recvrec_buf(ctx->engine, &len); + // do we have the record you're looking for? + if (m_client.available() >= len) { + // I suppose so! + int rlen = m_client.readBytes((char *)buf, len); + if (rlen < 0) { + br_ssl_engine_fail(ctx->engine, BR_ERR_IO); + setWriteError(SSL_BR_WRITE_ERROR); + return 0; + } + if (rlen > 0) { + br_ssl_engine_recvrec_ack(ctx->engine, rlen); + } + continue; + } + // guess not, tell the state we're waiting still + else return state; + } + // if it's not any of the above states, then it must be waiting to send or recieve app data + // in which case we return + return state; + } } \ No newline at end of file diff --git a/src/SSLClient.h b/src/SSLClient.h index d14135d..9907aa5 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -49,19 +49,35 @@ class SSLClient : public Client { static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!"); +/** error enums + * Static constants defining the possible errors encountered + * Read from getWriteError(); + */ +enum Error { + SSL_OK = 0, + SSL_CLIENT_CONNECT_FAIL, + SSL_BR_CONNECT_FAIL, + SSL_CLIENT_WRTIE_ERROR, + SSL_BR_WRITE_ERROR, +}; + public: /** * @brief copies the client object and initializes SSL contexts for bearSSL + * * We copy the client because we aren't sure the Client object * is going to exists past the inital creation of the SSLClient. - * @param client the (Ethernet)client object + * + * @pre The client class must be able to access the internet, as SSLClient + * cannot manage this for you. + * * @param trust_anchors Trust anchors used in the verification * of the SSL server certificate, generated using the `brssl` command * line utility. For more information see the samples or bearssl.org * @param trust_anchors_num The number of trust anchors stored * @param debug whether to enable or disable debug logging, must be constexpr */ - SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true) + SSLClient(const C client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true) : m_client(client) , m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) @@ -107,6 +123,9 @@ public: * @param ip The ip address to connect to * @param port the port to connect to * @returns 1 if success, 0 if failure (as found in EthernetClient) + * + * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port + * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. */ virtual int connect(IPAddress ip, uint16_t port = 443); /** @@ -128,6 +147,9 @@ public: * @param host The cstring host ("www.google.com") * @param port the port to connect to * @returns 1 of success, 0 if failure (as found in EthernetClient) + * + * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port + * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. */ virtual int connect(const char *host, uint16_t port = 443); virtual size_t write(uint8_t b) { return write(&b, 1); } @@ -140,7 +162,7 @@ public: virtual void stop(); virtual uint8_t connected(); - /** get the client object */ + //! get the client object C& getClient() { return m_client; } private: @@ -152,12 +174,12 @@ private: Serial.println(str); } } - /** Callback function pointing to m_client.read to be used by the br_sslio API */ - int m_readraw(void *ctx, unsigned char *buf, size_t len); - /** Callback function pointing to m_client.write to be used by the br_sslio API */ - int m_writeraw(void *ctx, unsigned char *buf, size_t len); + /** run the bearssl engine until a certain state */ + int m_run_until(const unsigned target); + /** proxy for availble that returns the state */ + int m_update_engine(); // create a copy of the client - C m_client; + const C m_client; // store pointers to the trust anchors // should not be computed at runtime constexpr br_x509_trust_anchor *m_trust_anchors; @@ -167,7 +189,12 @@ private: // store the context values required for SSL br_ssl_client_context m_sslctx; br_x509_minimal_context m_x509ctx; + // use a mono-directional buffer by default to cut memory in half + // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI + // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically + // simply edit this value to change the buffer size to the desired value unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO]; + static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI); br_sslio_context m_ioctx; }; From 0546070cbd2f2235a11f8a5f70396330a9906471 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 26 Feb 2019 12:17:25 -0800 Subject: [PATCH 009/205] finished SSLCLient implementation, in process of fixing syntax errors and need to rigorously document --- src/SSLClient.cpp | 242 ++++++++++++++++++++++++++++++++++++++-------- src/SSLClient.h | 43 ++++---- 2 files changed, 226 insertions(+), 59 deletions(-) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index d4c2981..17ca8d3 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -21,17 +21,28 @@ #include "SSLClient.h" /** see SSLClient.h */ -SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) { +template +SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) + : m_client(client) + , m_trust_anchors(trust_anchors) + , m_trust_anchors_num(trust_anchors_num) + , m_debug(debug) + , m_write_idx(0) { + + // zero the iobuf just in case it's still garbage + memset(m_iobuf, 0, sizeof m_iobuf); // initlalize the various bearssl libraries so they're ready to go when we connect br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // check if the buffer size is half or full duplex constexpr auto duplex = sizeof iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; br_ssl_engine_set_buffer(&m_sslctx, m_iobuf, sizeof m_iobuf, duplex); - br_sslio_init(&m_ioctx, &m_sslctx.eng, m_readraw, NULL, m_writeraw, NULL); } /* see SSLClient.h */ -virtual int SSLClient::connect(IPAddress ip, uint16_t port) { +template +int SSLClient::connect(IPAddress ip, uint16_t port) { + // reset indexs for saftey + m_write_idx = 0; // Warning for security m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible."); // first we need our hidden client member to negotiate the socket for us, @@ -46,7 +57,7 @@ virtual int SSLClient::connect(IPAddress ip, uint16_t port) { // initlalize the SSL socket over the network // normally this would happen in br_sslio_write, but I think it makes // a little more structural sense to put it here - if (m_run_until(ctx, BR_SSL_SENDAPP) < 0) { + if (m_run_until(BR_SSL_SENDAPP) < 0) { m_print("Failed to initlalize the SSL layer"); setWriteError(SSL_BR_CONNECT_FAIL); return 0; @@ -58,7 +69,10 @@ virtual int SSLClient::connect(IPAddress ip, uint16_t port) { } /* see SSLClient.h */ -virtual int SSLClient::connect(const char *host, uint16_t port) { +template +int SSLClient::connect(const char *host, uint16_t port) { + // reset indexs for saftey + m_write_idx = 0; // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!this->m_client.connect(host, port)) { @@ -82,38 +96,62 @@ virtual int SSLClient::connect(const char *host, uint16_t port) { return 1; } -/** see SSLClient.h TODO: fix */ -virtual size_t SSLClient::write(const uint8_t *buf, size_t size) { +/** see SSLClient.h */ +template +size_t SSLClient::write(const uint8_t *buf, size_t size) { // check if the socket is still open and such if(!m_client.connected()) { m_print("Client is not connected! Perhaps something has happened?"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } - // write to the ssl socket using bearssl, and error check - const auto status = br_sslio_write_all(&m_ioctx, buf, size); - if (status != size) { - if (status < 0) { - m_print("Encountered a write error:"); - if (m_client.getWriteError()) { - m_print("m_client write error"); - setWriteError(SSL_CLIENT_WRTIE_ERROR); - } - else { - m_print("bearssl write error: "); - m_print(err = br_ssl_engine_last_error(&m_sslctx.eng)); + // add to the bearssl io buffer, simply appending whatever we want to write + size_t alen; + unsigned char *br_buf = br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen); + size_t cur_idx = 0; + // while there are still elements to write + while (cur_idx < size) { + // run until the ssl socket is ready to write, unless we've already written + // to the buffer in which we conclude it's already safe to write + if(m_write_idx == 0) { + if (m_run_until(BR_SSL_SENDAPP) < 0) { + m_print("Error: could not run until sendapp"); setWriteError(SSL_BR_WRITE_ERROR); + return 0; } + // reset the buffer pointer + br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen); + } + // sanity check + if(br_buf == NULL || alen == 0) { + m_print("Error: recieved null buffer or zero alen in write"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); + setWriteError(SSL_BR_WRITE_ERROR); return 0; } - m_print("Warn: Wrote less than status! Something might be wrong"); - } - return status; + // if we're about to fill the buffer, we need to send the data and then wait + // for another oppurtinity to send + const size_t cpamount = m_write_idx + (size - cur_idx) > alen ? alen : size - cur_idx; + memcpy(br_buf + m_write_idx, buf + cur_idx, cpamount); + // if we filled the buffer, reset m_write_idx + if (cpamount == alen) m_write_idx = 0; + // else increment + else m_write_idx += cpamount; + // increment the buffer pointer + cur_size += cpamount; + } + // works oky + return size; } -virtual int SSLClient::available() { +/** see SSLClient.h */ +template +int SSLClient::available() { if (!m_client.connected()) { - m_print("Cannot check available of disconnected client!"); + m_print("Warn: Cannot check available of disconnected client"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); + setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } // run the SSL engine until we are waiting for either user input or a server response @@ -121,14 +159,14 @@ virtual int SSLClient::available() { if(state & BR_SSL_RECVAPP) { // return how many received bytes we have size_t alen; - br_ssl_engine_recvapp_buf(ctx->engine, &alen); - return (int)alen; + br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen); + return (int)(alen); } - else if (state == BR_SSL_CLOSED) m_print("Tried to check available when engine is closed!"); + else if (state == BR_SSL_CLOSED) m_print("Error: Tried to check available when engine is closed"); // flush the buffer if it's stuck in the SENDAPP state else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(m_sslctx->engine, 0); else if (state == 0) { - m_print("SSL engine failed: "); + m_print("Error: SSL engine failed: "); m_print(br_ssl_engine_last_error(&m_sslctx)); setWriteError(SSL_BR_WRITE_ERROR); } @@ -136,7 +174,71 @@ virtual int SSLClient::available() { return 0; } -int SSLClient::m_run_until(const unsigned target) { +/** see SSLClient.h */ +template +int SSLClient::read(uint8_t *buf, size_t size) { + // check that the engine is ready to read + else if (available()) { + // read the buffer, send the ack, and return the bytes read + size_t alen; + unsigned char* br_buf = br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen); + const size_t read_amount = size > alen ? alen : size; + memcpy(buf, br_buf, read_amount); + // tell engine we read that many bytes + br_ssl_engine_sendapp_ack(m_sslctx->engine, read_amount); + // tell the user we read that many bytes + return read_amount; + } + return -1; +} + +/** see SSLClient.h */ +template +int SSLClient::peek() { + // check that the engine is ready to read + if (available()) { + // read the buffer, send the ack, and return the bytes read + size_t alen; + uint8_t read_num; + read_num = br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen)[0]; + // tell the user we read that many bytes + return (int)read_num; + } + return -1; +} + +/** see SSLClient.h */ +template +void SSLClient::flush() { + // trigger a flush, incase there's any leftover data + br_ssl_engine_flush(m_sslctx->engine, 0); + // run until application data is ready for pickup + if(m_run_until(BR_SSL_RECVAPP) < 0) m_print("Error: could not flush write buffer!"); +} + +/** see SSLClient.h */ +template +void SSLClient::stop() { + // tell the SSL connection to gracefully close + br_ssl_engine_close(m_sslctx->engine); + while (br_ssl_engine_current_state(m_sslctx->engine) != BR_SSL_CLOSED) { + /* + * Discard any incoming application data. + */ + size_t len; + + m_run_until(BR_SSL_RECVAPP); + if (br_ssl_engine_recvapp_buf(m_sslctx->engine, &len) != NULL) { + br_ssl_engine_recvapp_ack(m_sslctx->engine, len); + } + } + // close the ethernet socket + m_client.stop(); +} + +/** see SSLClient.h */ +template +int SSLClient::m_run_until(const unsigned target) { for (;;) { unsigned state = m_update_engine(); /* @@ -150,9 +252,24 @@ int SSLClient::m_run_until(const unsigned target) { * and that's not possible until the application data is * read. This may happen if using a shared in/out buffer, * and the underlying protocol is not strictly half-duplex. - * This is unrecoverable here, so we report an error. + * Normally this would be unrecoverable, however we can attempt + * to remedy the problem by telling the engine to discard + * the data. */ - if (state & BR_SSL_RECVAPP && target & BR_SSL_SENDAPP) return -1; + if (state & BR_SSL_RECVAPP && target & BR_SSL_SENDAPP) { + size_t len; + if (br_ssl_engine_recvapp_buf(m_sslctx->engine, &len) != NULL) { + m_write_idx = 0; + m_print("Warn: discarded unread data to favor a write operation"); + br_ssl_engine_recvapp_ack(m_sslctx->engine, len); + } + else { + m_print("Error: ssl engine state is RECVAPP, however the buffer was null!"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); + setWriteError(SSL_BR_WRITE_ERROR); + return -1; + } + } /* * We can reach that point if the target RECVAPP, and @@ -165,6 +282,8 @@ int SSLClient::m_run_until(const unsigned target) { } } +/** see SSLClient.h */ +template unsigned SSLClient::m_update_engine() { for(;;) { // get the state @@ -179,9 +298,10 @@ unsigned SSLClient::m_update_engine() { size_t len; int wlen; - buf = br_ssl_engine_sendrec_buf(ctx->engine, &len); + buf = br_ssl_engine_sendrec_buf(m_sslctx->engine, &len); wlen = m_client.write(buf, len); if (wlen < 0) { + m_print("Error writing to m_client"); /* * If we received a close_notify and we * still send something, then we have our @@ -189,19 +309,64 @@ unsigned SSLClient::m_update_engine() { * the peer is allowed by RFC 5246 not to * wait for it. */ - if (!ctx->engine->shutdown_recv) { + if (!m_sslctx->engine->shutdown_recv) { br_ssl_engine_fail( - ctx->engine, BR_ERR_IO); + m_sslctx->engine, BR_ERR_IO); } setWriteError(SSL_BR_WRITE_ERROR); return 0; } if (wlen > 0) { - br_ssl_engine_sendrec_ack(ctx->engine, wlen); + br_ssl_engine_sendrec_ack(m_sslctx->engine, wlen); } continue; } + /* + * If the client has specified there is client data to send, and + * the engine is ready to handle it, send it along. + */ + if (m_write_idx > 0) { + // if we've reached the point where BR_SSL_SENDAPP is off but + // data has been written to the io buffer, something is wrong + if (!(state & BR_SSL_SENDAPP)) { + m_print("Error m_write_idx > 0 but the ssl engine is not ready for data"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); + setWriteError(SSL_BR_WRITE_ERROR); + return 0; + } + // else time to send the application data + else if (state & BR_SSL_SENDAPP) { + size_t alen; + unsigned char *buf = br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen); + // engine check + if (alen == 0 || buf == NULL) { + m_print("Error: engine set write flag but returned null buffer"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); + setWriteError(SSL_BR_WRITE_ERROR); + return 0; + } + // sanity check + if (alen < m_write_idx) { + m_print("Error: alen is less than m_write_idx"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); + setWriteError(SSL_INTERNAL_ERROR); + return 0; + } + // all good? lets send the data + // presumably the SSLClient::write function has already added + // data to *buf, so now we tell bearssl it's time for the + // encryption step. + // this will encrypt the data and presumably spit it out + // for BR_SSL_SENDREC to send over ethernet. + br_ssl_engine_sendapp_ack(m_sslctx->engine, m_write_idx); + // reset the iobuffer index + m_write_idx = 0; + // loop again! + continue; + } + } + /* * If there is some record data to recieve, check if we've * recieved it so far. If we have, then we can update the state. @@ -209,18 +374,19 @@ unsigned SSLClient::m_update_engine() { */ if (state & BR_SSL_RECVREC) { size_t len; - unsigned char * buf = br_ssl_engine_recvrec_buf(ctx->engine, &len); + unsigned char * buf = br_ssl_engine_recvrec_buf(m_sslctx->engine, &len); // do we have the record you're looking for? if (m_client.available() >= len) { // I suppose so! int rlen = m_client.readBytes((char *)buf, len); if (rlen < 0) { - br_ssl_engine_fail(ctx->engine, BR_ERR_IO); + m_print("Error reading bytes from m_client"); + br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_BR_WRITE_ERROR); return 0; } if (rlen > 0) { - br_ssl_engine_recvrec_ack(ctx->engine, rlen); + br_ssl_engine_recvrec_ack(m_sslctx->engine, rlen); } continue; } diff --git a/src/SSLClient.h b/src/SSLClient.h index 9907aa5..c7537d7 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -35,7 +35,7 @@ #include "bearssl.h" #include "Client.h" -#ifdef SSLClient_H_ +#ifndef SSLClient_H_ #define SSLClient_H_ template @@ -46,20 +46,23 @@ class SSLClient : public Client { * actually present on class C. It does this by first checking that the * class inherits from Client, and then that it contains a status() function. */ -static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); -static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!"); +//static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); +//static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!"); /** error enums * Static constants defining the possible errors encountered * Read from getWriteError(); */ +/* enum Error { SSL_OK = 0, SSL_CLIENT_CONNECT_FAIL, SSL_BR_CONNECT_FAIL, SSL_CLIENT_WRTIE_ERROR, SSL_BR_WRITE_ERROR, + SSL_INTERNAL_ERROR }; +*/ public: /** @@ -77,12 +80,7 @@ public: * @param trust_anchors_num The number of trust anchors stored * @param debug whether to enable or disable debug logging, must be constexpr */ - SSLClient(const C client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true) - : m_client(client) - , m_trust_anchors(trust_anchors) - , m_trust_anchors_num(trust_anchors_num) - , m_debug(debug); - + explicit SSLClient(const C client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true); /** Dtor is implicit since unique_ptr handles it fine */ /** @@ -127,7 +125,7 @@ public: * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. */ - virtual int connect(IPAddress ip, uint16_t port = 443); + virtual int connect(IPAddress ip, uint16_t port); /** * @brief Connect over SSL using connect(ip, port), but use a DNS lookup to * get the IP Address first. @@ -151,11 +149,11 @@ public: * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. */ - virtual int connect(const char *host, uint16_t port = 443); + virtual int connect(const char *host, uint16_t port); virtual size_t write(uint8_t b) { return write(&b, 1); } virtual size_t write(const uint8_t *buf, size_t size); virtual int available(); - virtual int read(); + virtual int read() { int peeked = peek(); if(peek != -1) br_ssl_engine_recvapp_ack(m_sslctx->engine, 1); return peek; } virtual int read(uint8_t *buf, size_t size); virtual int peek(); virtual void flush(); @@ -167,8 +165,8 @@ public: private: /** @brief debugging print function, only prints if m_debug is true */ - template - constexpr void m_print(const T str) { + template + constexpr void m_print(const T str) const { if (m_debug) { Serial.print("SSLClient: "); Serial.println(str); @@ -177,15 +175,15 @@ private: /** run the bearssl engine until a certain state */ int m_run_until(const unsigned target); /** proxy for availble that returns the state */ - int m_update_engine(); + unsigned m_update_engine(); // create a copy of the client - const C m_client; + C m_client; // store pointers to the trust anchors // should not be computed at runtime - constexpr br_x509_trust_anchor *m_trust_anchors; - constexpr size_t m_trust_anchors_num; + const br_x509_trust_anchor *m_trust_anchors; + const size_t m_trust_anchors_num; // store whether to enable debug logging - constexpr bool m_debug; + const bool m_debug; // store the context values required for SSL br_ssl_client_context m_sslctx; br_x509_minimal_context m_x509ctx; @@ -194,8 +192,11 @@ private: // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically // simply edit this value to change the buffer size to the desired value unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO]; - static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI); - br_sslio_context m_ioctx; + // static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI); + // store the index of where we are writing in the buffer + // so we can send our records all at once to prevent + // weird timing issues + size_t m_write_idx; }; #endif /** SSLClient_H_ */ \ No newline at end of file From 0a98a00ddefec19ce90753b035f677241a0fe77b Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 27 Feb 2019 13:17:04 -0800 Subject: [PATCH 010/205] fixed syntax errors --- src/SSLClient.cpp | 140 ++++++++++++++++++++++++---------------------- src/SSLClient.h | 36 ++++++------ 2 files changed, 90 insertions(+), 86 deletions(-) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 17ca8d3..0a0e6ce 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -34,8 +34,8 @@ SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_ancho // initlalize the various bearssl libraries so they're ready to go when we connect br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // check if the buffer size is half or full duplex - constexpr auto duplex = sizeof iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; - br_ssl_engine_set_buffer(&m_sslctx, m_iobuf, sizeof m_iobuf, duplex); + constexpr auto duplex = sizeof m_iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; + br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); } /* see SSLClient.h */ @@ -53,7 +53,7 @@ int SSLClient::connect(IPAddress ip, uint16_t port) { return 0; } // reset the client context, and look for previous sessions - br_ssl_client_reset(&sc, NULL, 1); + br_ssl_client_reset(&m_sslctx, NULL, 1); // initlalize the SSL socket over the network // normally this would happen in br_sslio_write, but I think it makes // a little more structural sense to put it here @@ -72,6 +72,7 @@ int SSLClient::connect(IPAddress ip, uint16_t port) { template int SSLClient::connect(const char *host, uint16_t port) { // reset indexs for saftey + m_write_idx = 0; // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. @@ -81,7 +82,7 @@ int SSLClient::connect(const char *host, uint16_t port) { return 0; } // reset the client context, and look for previous sessions - br_ssl_client_reset(&sc, host, 1); + br_ssl_client_reset(&m_sslctx, host, 1); // initlalize the SSL socket over the network // normally this would happen in br_sslio_write, but I think it makes // a little more structural sense to put it here @@ -100,15 +101,13 @@ int SSLClient::connect(const char *host, uint16_t port) { template size_t SSLClient::write(const uint8_t *buf, size_t size) { // check if the socket is still open and such - if(!m_client.connected()) { - m_print("Client is not connected! Perhaps something has happened?"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); - setWriteError(SSL_CLIENT_CONNECT_FAIL); + if(!connected()) { + m_print("Client is not connected! Perhaps something has happened?"); return 0; } // add to the bearssl io buffer, simply appending whatever we want to write size_t alen; - unsigned char *br_buf = br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen); + unsigned char *br_buf = br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); size_t cur_idx = 0; // while there are still elements to write while (cur_idx < size) { @@ -121,12 +120,11 @@ size_t SSLClient::write(const uint8_t *buf, size_t size) { return 0; } // reset the buffer pointer - br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen); + br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); } // sanity check if(br_buf == NULL || alen == 0) { m_print("Error: recieved null buffer or zero alen in write"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_BR_WRITE_ERROR); return 0; } @@ -139,7 +137,7 @@ size_t SSLClient::write(const uint8_t *buf, size_t size) { // else increment else m_write_idx += cpamount; // increment the buffer pointer - cur_size += cpamount; + cur_idx += cpamount; } // works oky return size; @@ -148,28 +146,27 @@ size_t SSLClient::write(const uint8_t *buf, size_t size) { /** see SSLClient.h */ template int SSLClient::available() { - if (!m_client.connected()) { + // connection check + if (!connected()) { m_print("Warn: Cannot check available of disconnected client"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); - setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } // run the SSL engine until we are waiting for either user input or a server response unsigned state = m_update_engine(); - if(state & BR_SSL_RECVAPP) { + if (state == 0) { + m_print("Error: SSL engine failed: "); + m_print(br_ssl_engine_last_error(&m_sslctx.eng)); + setWriteError(SSL_BR_WRITE_ERROR); + } + else if(state & BR_SSL_RECVAPP) { // return how many received bytes we have size_t alen; - br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen); + br_ssl_engine_recvapp_buf(&m_sslctx.eng, &alen); return (int)(alen); } else if (state == BR_SSL_CLOSED) m_print("Error: Tried to check available when engine is closed"); // flush the buffer if it's stuck in the SENDAPP state - else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(m_sslctx->engine, 0); - else if (state == 0) { - m_print("Error: SSL engine failed: "); - m_print(br_ssl_engine_last_error(&m_sslctx)); - setWriteError(SSL_BR_WRITE_ERROR); - } + else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); // other state, or client is closed return 0; } @@ -178,40 +175,36 @@ int SSLClient::available() { template int SSLClient::read(uint8_t *buf, size_t size) { // check that the engine is ready to read - else if (available()) { - // read the buffer, send the ack, and return the bytes read - size_t alen; - unsigned char* br_buf = br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen); - const size_t read_amount = size > alen ? alen : size; - memcpy(buf, br_buf, read_amount); - // tell engine we read that many bytes - br_ssl_engine_sendapp_ack(m_sslctx->engine, read_amount); - // tell the user we read that many bytes - return read_amount; - } - return -1; + if (available() <= 0) return -1; + // read the buffer, send the ack, and return the bytes read + size_t alen; + unsigned char* br_buf = br_ssl_engine_recvapp_buf(&m_sslctx.eng, &alen); + const size_t read_amount = size > alen ? alen : size; + memcpy(buf, br_buf, read_amount); + // tell engine we read that many bytes + br_ssl_engine_sendapp_ack(&m_sslctx.eng, read_amount); + // tell the user we read that many bytes + return read_amount; } /** see SSLClient.h */ template int SSLClient::peek() { // check that the engine is ready to read - if (available()) { - // read the buffer, send the ack, and return the bytes read - size_t alen; - uint8_t read_num; - read_num = br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen)[0]; - // tell the user we read that many bytes - return (int)read_num; - } - return -1; + if (available() <= 0) return -1; + // read the buffer, send the ack, and return the bytes read + size_t alen; + uint8_t read_num; + read_num = br_ssl_engine_recvapp_buf(&m_sslctx.eng, &alen)[0]; + // tell the user we read that many bytes + return (int)read_num; } /** see SSLClient.h */ template void SSLClient::flush() { // trigger a flush, incase there's any leftover data - br_ssl_engine_flush(m_sslctx->engine, 0); + br_ssl_engine_flush(&m_sslctx.eng, 0); // run until application data is ready for pickup if(m_run_until(BR_SSL_RECVAPP) < 0) m_print("Error: could not flush write buffer!"); } @@ -220,22 +213,39 @@ void SSLClient::flush() { template void SSLClient::stop() { // tell the SSL connection to gracefully close - br_ssl_engine_close(m_sslctx->engine); - while (br_ssl_engine_current_state(m_sslctx->engine) != BR_SSL_CLOSED) { + br_ssl_engine_close(&m_sslctx.eng); + while (br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED) { /* * Discard any incoming application data. */ size_t len; m_run_until(BR_SSL_RECVAPP); - if (br_ssl_engine_recvapp_buf(m_sslctx->engine, &len) != NULL) { - br_ssl_engine_recvapp_ack(m_sslctx->engine, len); + if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != NULL) { + br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); } } // close the ethernet socket m_client.stop(); } +template +uint8_t SSLClient::connected() { + // check all of the error cases + const auto c_con = m_client.connected(); + const auto br_con = br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED; + const auto wr_ok = getWriteError() == 0; + // if we're in an error state, close the connection and set a write error + if ((br_con && !c_con) || !wr_ok) { + m_print("Error: Socket was unexpectedly interrupted"); + m_print("Terminated with: "); + m_print(m_client.getWriteError()); + setWriteError(SSL_CLIENT_WRTIE_ERROR); + stop(); + } + return c_con && br_con && wr_ok; +} + /** see SSLClient.h */ template int SSLClient::m_run_until(const unsigned target) { @@ -258,14 +268,13 @@ int SSLClient::m_run_until(const unsigned target) { */ if (state & BR_SSL_RECVAPP && target & BR_SSL_SENDAPP) { size_t len; - if (br_ssl_engine_recvapp_buf(m_sslctx->engine, &len) != NULL) { + if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != NULL) { m_write_idx = 0; m_print("Warn: discarded unread data to favor a write operation"); - br_ssl_engine_recvapp_ack(m_sslctx->engine, len); + br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); } else { m_print("Error: ssl engine state is RECVAPP, however the buffer was null!"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_BR_WRITE_ERROR); return -1; } @@ -278,16 +287,16 @@ int SSLClient::m_run_until(const unsigned target) { * the buffered data to "make room" for a new incoming * record. */ - if (state & SENDAPP && target & RECVAPP) br_ssl_engine_flush(m_sslctx->engine, 0); + if (state & BR_SSL_SENDAPP && target & BR_SSL_RECVAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); } } /** see SSLClient.h */ template -unsigned SSLClient::m_update_engine() { +unsigned SSLClient::m_update_engine() { for(;;) { // get the state - unsigned state = br_ssl_engine_current_state(m_sslctx->engine); + unsigned state = br_ssl_engine_current_state(&m_sslctx.eng); if (state & BR_SSL_CLOSED) return state; /* * If there is some record data to send, do it. This takes @@ -298,7 +307,7 @@ unsigned SSLClient::m_update_engine() { size_t len; int wlen; - buf = br_ssl_engine_sendrec_buf(m_sslctx->engine, &len); + buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); wlen = m_client.write(buf, len); if (wlen < 0) { m_print("Error writing to m_client"); @@ -309,15 +318,14 @@ unsigned SSLClient::m_update_engine() { * the peer is allowed by RFC 5246 not to * wait for it. */ - if (!m_sslctx->engine->shutdown_recv) { - br_ssl_engine_fail( - m_sslctx->engine, BR_ERR_IO); + if (!&m_sslctx.eng.shutdown_recv) { + return 0; } setWriteError(SSL_BR_WRITE_ERROR); return 0; } if (wlen > 0) { - br_ssl_engine_sendrec_ack(m_sslctx->engine, wlen); + br_ssl_engine_sendrec_ack(&m_sslctx.eng, wlen); } continue; } @@ -331,25 +339,22 @@ unsigned SSLClient::m_update_engine() { // data has been written to the io buffer, something is wrong if (!(state & BR_SSL_SENDAPP)) { m_print("Error m_write_idx > 0 but the ssl engine is not ready for data"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_BR_WRITE_ERROR); return 0; } // else time to send the application data else if (state & BR_SSL_SENDAPP) { size_t alen; - unsigned char *buf = br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen); + unsigned char *buf = br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); // engine check if (alen == 0 || buf == NULL) { m_print("Error: engine set write flag but returned null buffer"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_BR_WRITE_ERROR); return 0; } // sanity check if (alen < m_write_idx) { m_print("Error: alen is less than m_write_idx"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_INTERNAL_ERROR); return 0; } @@ -359,7 +364,7 @@ unsigned SSLClient::m_update_engine() { // encryption step. // this will encrypt the data and presumably spit it out // for BR_SSL_SENDREC to send over ethernet. - br_ssl_engine_sendapp_ack(m_sslctx->engine, m_write_idx); + br_ssl_engine_sendapp_ack(&m_sslctx.eng, m_write_idx); // reset the iobuffer index m_write_idx = 0; // loop again! @@ -374,19 +379,18 @@ unsigned SSLClient::m_update_engine() { */ if (state & BR_SSL_RECVREC) { size_t len; - unsigned char * buf = br_ssl_engine_recvrec_buf(m_sslctx->engine, &len); + unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? if (m_client.available() >= len) { // I suppose so! int rlen = m_client.readBytes((char *)buf, len); if (rlen < 0) { m_print("Error reading bytes from m_client"); - br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO); setWriteError(SSL_BR_WRITE_ERROR); return 0; } if (rlen > 0) { - br_ssl_engine_recvrec_ack(m_sslctx->engine, rlen); + br_ssl_engine_recvrec_ack(&m_sslctx.eng, rlen); } continue; } diff --git a/src/SSLClient.h b/src/SSLClient.h index c7537d7..7990a0f 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -33,6 +33,7 @@ #include #include "bearssl.h" +#include "Arduino.h" #include "Client.h" #ifndef SSLClient_H_ @@ -46,14 +47,14 @@ class SSLClient : public Client { * actually present on class C. It does this by first checking that the * class inherits from Client, and then that it contains a status() function. */ -//static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!"); -//static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!"); +static_assert(std::is_base_of::value, "C must be a Client Class!"); +// static_assert(std::is_function::value, "C must have a status() function!"); /** error enums * Static constants defining the possible errors encountered * Read from getWriteError(); */ -/* + enum Error { SSL_OK = 0, SSL_CLIENT_CONNECT_FAIL, @@ -62,7 +63,6 @@ enum Error { SSL_BR_WRITE_ERROR, SSL_INTERNAL_ERROR }; -*/ public: /** @@ -80,27 +80,27 @@ public: * @param trust_anchors_num The number of trust anchors stored * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClient(const C client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true); + explicit SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true); /** Dtor is implicit since unique_ptr handles it fine */ /** * The virtual functions defining a Client are below * Most of them smply pass through */ - virtual int availableForWrite(void) const { return m_client.availableForWrite(); }; - virtual operator bool() const { return m_client.bool(); } - virtual bool operator==(const bool value) const { return bool() == value; } - virtual bool operator!=(const bool value) const { return bool() != value; } - virtual bool operator==(const C& rhs) const { return m_client.operator==(rhs); } - virtual bool operator!=(const C& rhs) const { return !this->operator==(rhs); } - virtual uint16_t localPort() const { return m_client.localPort(); } - virtual IPAddress remoteIP() const { return m_client.remoteIP(); } - virtual uint16_t remotePort() const { return m_client.remotePort(); } + virtual int availableForWrite(void) { return m_client.availableForWrite(); }; + virtual operator bool() { return static_cast(m_client); } + // virtual bool operator==(const bool value) { return bool() == value; } + // virtual bool operator!=(const bool value) { return bool() != value; } + // virtual bool operator==(const C& rhs) const { return m_client.operator==(rhs); } + // virtual bool operator!=(const C& rhs) const { return !this->operator==(rhs); } + virtual uint16_t localPort() { return m_client.localPort(); } + virtual IPAddress remoteIP() { return m_client.remoteIP(); } + virtual uint16_t remotePort() { return m_client.remotePort(); } virtual void setConnectionTimeout(uint16_t timeout) { m_client.setConnectionTimeout(timeout); } /** functions specific to the EthernetClient which I'll have to override */ - uint8_t status() const; - uint8_t getSocketNumber() const; + // uint8_t status(); + // uint8_t getSocketNumber() const; /** functions dealing with read/write that BearSSL will be injected into */ /** @@ -153,7 +153,7 @@ public: virtual size_t write(uint8_t b) { return write(&b, 1); } virtual size_t write(const uint8_t *buf, size_t size); virtual int available(); - virtual int read() { int peeked = peek(); if(peek != -1) br_ssl_engine_recvapp_ack(m_sslctx->engine, 1); return peek; } + virtual int read() { int peeked = peek(); if(peeked != -1) br_ssl_engine_recvapp_ack(&m_sslctx.eng, 1); return peeked; } virtual int read(uint8_t *buf, size_t size); virtual int peek(); virtual void flush(); @@ -192,7 +192,7 @@ private: // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically // simply edit this value to change the buffer size to the desired value unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO]; - // static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI); + static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); // store the index of where we are writing in the buffer // so we can send our records all at once to prevent // weird timing issues From 5a0debb2fbb437ca566b027b6b4b582245def12c Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 27 Feb 2019 13:22:31 -0800 Subject: [PATCH 011/205] restructuring to separate the template based functionality from the rest of the class. --- src/SSLClient.h | 4 ++++ src/{SSLClient.cpp => SSLClientImpl.cpp} | 0 src/SSLClientImpl.h | 25 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+) rename src/{SSLClient.cpp => SSLClientImpl.cpp} (100%) create mode 100644 src/SSLClientImpl.h diff --git a/src/SSLClient.h b/src/SSLClient.h index 7990a0f..158bf19 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -29,6 +29,10 @@ * simply need to start with: * SSLCLient client(ethCLient); * And then call the functions they normally would with EthernetClient using SSLCLient. + * + * This file specifically controls the class templating used to allow SSLClient to interface + * with all of the CLient-based classes. To see details on the implementations of the functions + * in SSLClient, please see {@link ./SSLClientImpl.h}. */ #include diff --git a/src/SSLClient.cpp b/src/SSLClientImpl.cpp similarity index 100% rename from src/SSLClient.cpp rename to src/SSLClientImpl.cpp diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h new file mode 100644 index 0000000..a88cf64 --- /dev/null +++ b/src/SSLClientImpl.h @@ -0,0 +1,25 @@ +/* Copyright 2019 OSU OPEnS Lab + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SSLClientImpl_H_ +#define SSLClientImpl_H_ + + +#endif /* SSLClientImpl_H_ */ \ No newline at end of file From 797a3cdf940693ea5952f828a0479dcc10b80838 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 27 Feb 2019 17:22:42 -0800 Subject: [PATCH 012/205] fixed syntax errors, switched internal Client to pointers, and finally got it to compile! --- src/SSLClient.h | 162 +++++++++---------------------- src/SSLClientImpl.cpp | 75 ++++++-------- src/SSLClientImpl.h | 135 ++++++++++++++++++++++++++ src/bearssl/TLS12_only_profile.c | 3 +- 4 files changed, 212 insertions(+), 163 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 158bf19..176e51d 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -36,29 +36,16 @@ */ #include -#include "bearssl.h" -#include "Arduino.h" #include "Client.h" +#include "SSLClientImpl.h" #ifndef SSLClient_H_ #define SSLClient_H_ -template -class SSLClient : public Client { -/** static type checks - * I'm a java developer, so I want to ensure that my inheritance is safe. - * These checks ensure that all the functions we use on class C are - * actually present on class C. It does this by first checking that the - * class inherits from Client, and then that it contains a status() function. - */ -static_assert(std::is_base_of::value, "C must be a Client Class!"); -// static_assert(std::is_function::value, "C must have a status() function!"); - /** error enums * Static constants defining the possible errors encountered * Read from getWriteError(); */ - enum Error { SSL_OK = 0, SSL_CLIENT_CONNECT_FAIL, @@ -68,9 +55,35 @@ enum Error { SSL_INTERNAL_ERROR }; +/** + * \brief This class serves as a templating proxy class for the SSLClientImpl to do the real work. + * + * A problem arose when writing this class: I wanted the user to be able to construct + * this class in a single line of code (e.g. SSLClient(EthernetClient())), but I also + * wanted to avoid the use of dynamic memory if possible. In an attempt to solve this + * problem I used a templated classes. However, becuase of the Arduino build process + * this meant that the implementations for all the functions had to be in a header + * file (a weird effect of using templated classes and linking) which would slow down + * the build quite a bit. As a comprimise, I instead decided to build the main class (SSLCLient) + * as a templated class, and have use a not templated implementation class (SSLClientImpl) + * that would be able to reside in a seperate file. This gets the best of both worlds + * from the client side, however from the developer side it can be a bit confusing. + */ + +template +class SSLClient : public SSLClientImpl { +/** static type checks + * I'm a java developer, so I want to ensure that my inheritance is safe. + * These checks ensure that all the functions we use on class C are + * actually present on class C. It does this by first checking that the + * class inherits from Client, and then that it contains a status() function. + */ +static_assert(std::is_base_of::value, "C must be a Client Class!"); +// static_assert(std::is_function::value, "C must have a status() function!"); + public: /** - * @brief copies the client object and initializes SSL contexts for bearSSL + * @brief copies the client object, and passes the various parameters to the SSLCLientImpl functions. * * We copy the client because we aren't sure the Client object * is going to exists past the inital creation of the SSLClient. @@ -84,123 +97,36 @@ public: * @param trust_anchors_num The number of trust anchors stored * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true); - /** Dtor is implicit since unique_ptr handles it fine */ - + SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true) + : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, debug) + , m_client(client) + { + // since we are copying the client in the ctor, we have to set + // the client pointer after the class is constructed + set_client(&m_client); + } + /** - * The virtual functions defining a Client are below + * The special functions most clients have are below * Most of them smply pass through */ - virtual int availableForWrite(void) { return m_client.availableForWrite(); }; - virtual operator bool() { return static_cast(m_client); } - // virtual bool operator==(const bool value) { return bool() == value; } - // virtual bool operator!=(const bool value) { return bool() != value; } - // virtual bool operator==(const C& rhs) const { return m_client.operator==(rhs); } - // virtual bool operator!=(const C& rhs) const { return !this->operator==(rhs); } + virtual int availableForWrite(void) { return m_client.availableForWrite(); } + virtual operator bool() { return connected() > 0; } + virtual bool operator==(const bool value) { return bool() == value; } + virtual bool operator!=(const bool value) { return bool() != value; } + virtual bool operator==(const C& rhs) { return m_client == rhs; } + virtual bool operator!=(const C& rhs) { return m_client != rhs; } virtual uint16_t localPort() { return m_client.localPort(); } virtual IPAddress remoteIP() { return m_client.remoteIP(); } virtual uint16_t remotePort() { return m_client.remotePort(); } virtual void setConnectionTimeout(uint16_t timeout) { m_client.setConnectionTimeout(timeout); } - /** functions specific to the EthernetClient which I'll have to override */ - // uint8_t status(); - // uint8_t getSocketNumber() const; - - /** functions dealing with read/write that BearSSL will be injected into */ - /** - * @brief Connect over SSL to a host specified by an ip address - * - * SSLClient::connect(host, port) should be preffered over this function, - * as verifying the domain name is a step in ensuring the certificate is - * legitimate, which is important to the security of the device. Additionally, - * SSL sessions cannot be resumed, which can drastically increase initial - * connect time. - * - * This function initializes EthernetClient by calling EthernetClient::connect - * with the parameters supplied, then once the socket is open initializes - * the appropriete bearssl contexts using the TLS_only_profile. Due to the - * design of the SSL standard, this function will probably take an extended - * period (1-2sec) to negotiate the handshake and finish the connection. - * - * @param ip The ip address to connect to - * @param port the port to connect to - * @returns 1 if success, 0 if failure (as found in EthernetClient) - * - * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port - * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. - */ - virtual int connect(IPAddress ip, uint16_t port); - /** - * @brief Connect over SSL using connect(ip, port), but use a DNS lookup to - * get the IP Address first. - * - * This function initializes EthernetClient by calling EthernetClient::connect - * with the parameters supplied, then once the socket is open initializes - * the appropriete bearssl contexts using the TLS_only_profile. - * - * Due to the design of the SSL standard, this function will probably take an - * extended period (1-2sec) to negotiate the handshake and finish the - * connection. Since the hostname is provided, however, BearSSL is able to keep - * a session cache of the clients we have connected to. This should reduce - * connection time greatly. In order to use this feature, you must reuse the - * same SSLClient object to connect to the reused host. Doing this will allow - * BearSSL to automatically match the hostname to a cached session. - * - * @param host The cstring host ("www.google.com") - * @param port the port to connect to - * @returns 1 of success, 0 if failure (as found in EthernetClient) - * - * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port - * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. - */ - virtual int connect(const char *host, uint16_t port); - virtual size_t write(uint8_t b) { return write(&b, 1); } - virtual size_t write(const uint8_t *buf, size_t size); - virtual int available(); - virtual int read() { int peeked = peek(); if(peeked != -1) br_ssl_engine_recvapp_ack(&m_sslctx.eng, 1); return peeked; } - virtual int read(uint8_t *buf, size_t size); - virtual int peek(); - virtual void flush(); - virtual void stop(); - virtual uint8_t connected(); - //! get the client object C& getClient() { return m_client; } private: - /** @brief debugging print function, only prints if m_debug is true */ - template - constexpr void m_print(const T str) const { - if (m_debug) { - Serial.print("SSLClient: "); - Serial.println(str); - } - } - /** run the bearssl engine until a certain state */ - int m_run_until(const unsigned target); - /** proxy for availble that returns the state */ - unsigned m_update_engine(); // create a copy of the client C m_client; - // store pointers to the trust anchors - // should not be computed at runtime - const br_x509_trust_anchor *m_trust_anchors; - const size_t m_trust_anchors_num; - // store whether to enable debug logging - const bool m_debug; - // store the context values required for SSL - br_ssl_client_context m_sslctx; - br_x509_minimal_context m_x509ctx; - // use a mono-directional buffer by default to cut memory in half - // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI - // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically - // simply edit this value to change the buffer size to the desired value - unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO]; - static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); - // store the index of where we are writing in the buffer - // so we can send our records all at once to prevent - // weird timing issues - size_t m_write_idx; }; #endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 0a0e6ce..f28ed75 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -20,9 +20,8 @@ #include "SSLClient.h" -/** see SSLClient.h */ -template -SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) +/** see SSLClientImpl.h */ +SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) : m_client(client) , m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) @@ -38,16 +37,15 @@ SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_ancho br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); } -/* see SSLClient.h */ -template -int SSLClient::connect(IPAddress ip, uint16_t port) { +/* see SSLClientImpl.h*/ +int SSLClientImpl::connect(IPAddress ip, uint16_t port) { // reset indexs for saftey m_write_idx = 0; // Warning for security m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible."); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. - if (!this->m_client.connect(ip, port)) { + if (!m_client->connect(ip, port)) { m_print("Failed to connect using m_client"); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; @@ -68,15 +66,13 @@ int SSLClient::connect(IPAddress ip, uint16_t port) { return 1; } -/* see SSLClient.h */ -template -int SSLClient::connect(const char *host, uint16_t port) { +/* see SSLClientImpl.h*/ +int SSLClientImpl::connect(const char *host, uint16_t port) { // reset indexs for saftey - m_write_idx = 0; // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. - if (!this->m_client.connect(host, port)) { + if (!m_client->connect(host, port)) { m_print("Failed to connect using m_client"); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; @@ -97,9 +93,8 @@ int SSLClient::connect(const char *host, uint16_t port) { return 1; } -/** see SSLClient.h */ -template -size_t SSLClient::write(const uint8_t *buf, size_t size) { +/** see SSLClientImpl.h*/ +size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { // check if the socket is still open and such if(!connected()) { m_print("Client is not connected! Perhaps something has happened?"); @@ -143,9 +138,8 @@ size_t SSLClient::write(const uint8_t *buf, size_t size) { return size; } -/** see SSLClient.h */ -template -int SSLClient::available() { +/** see SSLClientImpl.h*/ +int SSLClientImpl::available() { // connection check if (!connected()) { m_print("Warn: Cannot check available of disconnected client"); @@ -171,9 +165,8 @@ int SSLClient::available() { return 0; } -/** see SSLClient.h */ -template -int SSLClient::read(uint8_t *buf, size_t size) { +/** see SSLClientImpl.h */ +int SSLClientImpl::read(uint8_t *buf, size_t size) { // check that the engine is ready to read if (available() <= 0) return -1; // read the buffer, send the ack, and return the bytes read @@ -187,9 +180,8 @@ int SSLClient::read(uint8_t *buf, size_t size) { return read_amount; } -/** see SSLClient.h */ -template -int SSLClient::peek() { +/** see SSLClientImpl.h */ +int SSLClientImpl::peek() { // check that the engine is ready to read if (available() <= 0) return -1; // read the buffer, send the ack, and return the bytes read @@ -200,18 +192,16 @@ int SSLClient::peek() { return (int)read_num; } -/** see SSLClient.h */ -template -void SSLClient::flush() { +/** see SSLClientImpl.h*/ +void SSLClientImpl::flush() { // trigger a flush, incase there's any leftover data br_ssl_engine_flush(&m_sslctx.eng, 0); // run until application data is ready for pickup if(m_run_until(BR_SSL_RECVAPP) < 0) m_print("Error: could not flush write buffer!"); } -/** see SSLClient.h */ -template -void SSLClient::stop() { +/** see SSLClientImpl.h*/ +void SSLClientImpl::stop() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); while (br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED) { @@ -226,29 +216,27 @@ void SSLClient::stop() { } } // close the ethernet socket - m_client.stop(); + m_client->stop(); } -template -uint8_t SSLClient::connected() { +uint8_t SSLClientImpl::connected() { // check all of the error cases - const auto c_con = m_client.connected(); + const auto c_con = m_client->connected(); const auto br_con = br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED; const auto wr_ok = getWriteError() == 0; // if we're in an error state, close the connection and set a write error if ((br_con && !c_con) || !wr_ok) { m_print("Error: Socket was unexpectedly interrupted"); m_print("Terminated with: "); - m_print(m_client.getWriteError()); + m_print(m_client->getWriteError()); setWriteError(SSL_CLIENT_WRTIE_ERROR); stop(); } return c_con && br_con && wr_ok; } -/** see SSLClient.h */ -template -int SSLClient::m_run_until(const unsigned target) { +/** see SSLClientImpl.h*/ +int SSLClientImpl::m_run_until(const unsigned target) { for (;;) { unsigned state = m_update_engine(); /* @@ -291,9 +279,8 @@ int SSLClient::m_run_until(const unsigned target) { } } -/** see SSLClient.h */ -template -unsigned SSLClient::m_update_engine() { +/** see SSLClientImpl.h*/ +unsigned SSLClientImpl::m_update_engine() { for(;;) { // get the state unsigned state = br_ssl_engine_current_state(&m_sslctx.eng); @@ -308,7 +295,7 @@ unsigned SSLClient::m_update_engine() { int wlen; buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); - wlen = m_client.write(buf, len); + wlen = m_client->write(buf, len); if (wlen < 0) { m_print("Error writing to m_client"); /* @@ -381,9 +368,9 @@ unsigned SSLClient::m_update_engine() { size_t len; unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? - if (m_client.available() >= len) { + if (m_client->available() >= len) { // I suppose so! - int rlen = m_client.readBytes((char *)buf, len); + int rlen = m_client->readBytes((char *)buf, len); if (rlen < 0) { m_print("Error reading bytes from m_client"); setWriteError(SSL_BR_WRITE_ERROR); diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index a88cf64..0bde340 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -18,8 +18,143 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "bearssl.h" +#include "Client.h" +#include "Arduino.h" + #ifndef SSLClientImpl_H_ #define SSLClientImpl_H_ +/** TODO: Write what this is */ + +class SSLClientImpl : public Client { +public: + /** + * @brief initializes SSL contexts for bearSSL + * + * @pre The client class must be able to access the internet, as SSLClient + * cannot manage this for you. + * + * @post set_client must be called immediatly after to set the client class + * pointer. + * + * @param trust_anchors Trust anchors used in the verification + * of the SSL server certificate, generated using the `brssl` command + * line utility. For more information see the samples or bearssl.org + * @param trust_anchors_num The number of trust anchors stored + * @param debug whether to enable or disable debug logging, must be constexpr + */ + explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true); + /** Dtor is implicit since unique_ptr handles it fine */ + + /** functions specific to the EthernetClient which I'll have to override */ + // uint8_t status(); + // uint8_t getSocketNumber() const; + + /** functions dealing with read/write that BearSSL will be injected into */ + /** + * @brief Connect over SSL to a host specified by an ip address + * + * SSLClient::connect(host, port) should be preffered over this function, + * as verifying the domain name is a step in ensuring the certificate is + * legitimate, which is important to the security of the device. Additionally, + * SSL sessions cannot be resumed, which can drastically increase initial + * connect time. + * + * This function initializes EthernetClient by calling EthernetClient::connect + * with the parameters supplied, then once the socket is open initializes + * the appropriete bearssl contexts using the TLS_only_profile. Due to the + * design of the SSL standard, this function will probably take an extended + * period (1-2sec) to negotiate the handshake and finish the connection. + * + * @param ip The ip address to connect to + * @param port the port to connect to + * @returns 1 if success, 0 if failure (as found in EthernetClient) + * + * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port + * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. + */ + virtual int connect(IPAddress ip, uint16_t port); + /** + * @brief Connect over SSL using connect(ip, port), but use a DNS lookup to + * get the IP Address first. + * + * This function initializes EthernetClient by calling EthernetClient::connect + * with the parameters supplied, then once the socket is open initializes + * the appropriete bearssl contexts using the TLS_only_profile. + * + * Due to the design of the SSL standard, this function will probably take an + * extended period (1-2sec) to negotiate the handshake and finish the + * connection. Since the hostname is provided, however, BearSSL is able to keep + * a session cache of the clients we have connected to. This should reduce + * connection time greatly. In order to use this feature, you must reuse the + * same SSLClient object to connect to the reused host. Doing this will allow + * BearSSL to automatically match the hostname to a cached session. + * + * @param host The cstring host ("www.google.com") + * @param port the port to connect to + * @returns 1 of success, 0 if failure (as found in EthernetClient) + * + * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port + * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. + */ + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t b) { return write(&b, 1); } + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; } + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + +protected: + /** + * @brief set the pointer to the Client class that we wil use + * + * Call this function immediatly after the ctor. This functionality + * is placed in it's own function for flexibility reasons, but it + * is critical that this function is called before anything else + */ + void set_client(Client* c) { m_client = c; } +private: + + /** @brief debugging print function, only prints if m_debug is true */ + template + constexpr void m_print(const T str) const { + if (m_debug) { + Serial.print("SSLClientImpl: "); + Serial.println(str); + } + } + /** run the bearssl engine until a certain state */ + int m_run_until(const unsigned target); + /** proxy for availble that returns the state */ + unsigned m_update_engine(); + // hold a reference to the client + Client* m_client; + // store pointers to the trust anchors + // should not be computed at runtime + const br_x509_trust_anchor *m_trust_anchors; + const size_t m_trust_anchors_num; + // store whether to enable debug logging + const bool m_debug; + // store the context values required for SSL + br_ssl_client_context m_sslctx; + br_x509_minimal_context m_x509ctx; + // use a mono-directional buffer by default to cut memory in half + // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI + // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically + // simply edit this value to change the buffer size to the desired value + unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO]; + static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); + // store the index of where we are writing in the buffer + // so we can send our records all at once to prevent + // weird timing issues + size_t m_write_idx; + // store the last error code + +}; #endif /* SSLClientImpl_H_ */ \ No newline at end of file diff --git a/src/bearssl/TLS12_only_profile.c b/src/bearssl/TLS12_only_profile.c index 4400b5a..f253e2b 100644 --- a/src/bearssl/TLS12_only_profile.c +++ b/src/bearssl/TLS12_only_profile.c @@ -23,6 +23,7 @@ */ #include "bearssl.h" +#include "bearssl_ssl.h" /* * A "profile" is an initialisation function for a SSL context, that @@ -234,7 +235,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, // br_ssl_engine_set_default_ecdsa(&cc->eng); //* Alternate: set implementations explicitly. // br_ssl_client_set_rsapub(cc, &br_rsa_i31_public); - br_ssl_client_set_rsavrfy(cc, &br_rsa_i15_pkcs1_vrfy); + br_ssl_engine_set_rsavrfy(&cc->eng, &br_rsa_i15_pkcs1_vrfy); br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1); //*/ From e7fdbfc00e62eb51b13ec9ea68a15cef03ee4c48 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 27 Feb 2019 21:26:54 -0800 Subject: [PATCH 013/205] refactored a bit, added code debugging --- src/SSLClient.h | 8 +- src/SSLClientImpl.cpp | 123 +++++++++++++++++-------- src/SSLClientImpl.h | 24 ++++- src/{bearssl => }/TLS12_only_profile.c | 0 4 files changed, 113 insertions(+), 42 deletions(-) rename src/{bearssl => }/TLS12_only_profile.c (100%) diff --git a/src/SSLClient.h b/src/SSLClient.h index 176e51d..1ce3647 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -89,16 +89,18 @@ public: * is going to exists past the inital creation of the SSLClient. * * @pre The client class must be able to access the internet, as SSLClient - * cannot manage this for you. + * cannot manage this for you. Additionally it is recommended that the analog_pin + * be set to input. * * @param trust_anchors Trust anchors used in the verification * of the SSL server certificate, generated using the `brssl` command * line utility. For more information see the samples or bearssl.org * @param trust_anchors_num The number of trust anchors stored + * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG * @param debug whether to enable or disable debug logging, must be constexpr */ - SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true) - : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, debug) + explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug = true) + : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) { // since we are copying the client in the ctor, we have to set diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index f28ed75..6156a0e 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -21,17 +21,19 @@ #include "SSLClient.h" /** see SSLClientImpl.h */ -SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) +SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug) : m_client(client) , m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) + , m_analog_pin(analog_pin) , m_debug(debug) , m_write_idx(0) { // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); // initlalize the various bearssl libraries so they're ready to go when we connect - br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // check if the buffer size is half or full duplex constexpr auto duplex = sizeof m_iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); @@ -46,24 +48,12 @@ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!m_client->connect(ip, port)) { - m_print("Failed to connect using m_client"); + m_print("Error: Failed to connect using m_client"); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } - // reset the client context, and look for previous sessions - br_ssl_client_reset(&m_sslctx, NULL, 1); - // initlalize the SSL socket over the network - // normally this would happen in br_sslio_write, but I think it makes - // a little more structural sense to put it here - if (m_run_until(BR_SSL_SENDAPP) < 0) { - m_print("Failed to initlalize the SSL layer"); - setWriteError(SSL_BR_CONNECT_FAIL); - return 0; - } - // all good to go! the SSL socket should be up and running - m_print("SSL Initialized"); - setWriteError(SSL_OK); - return 1; + m_print("Base ethernet client connected!"); + return m_start_ssl(); } /* see SSLClientImpl.h*/ @@ -73,24 +63,12 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!m_client->connect(host, port)) { - m_print("Failed to connect using m_client"); + m_print("Error: Failed to connect using m_client"); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } - // reset the client context, and look for previous sessions - br_ssl_client_reset(&m_sslctx, host, 1); - // initlalize the SSL socket over the network - // normally this would happen in br_sslio_write, but I think it makes - // a little more structural sense to put it here - if (m_run_until(BR_SSL_SENDAPP) < 0) { - m_print("Failed to initlalize the SSL layer"); - setWriteError(SSL_BR_CONNECT_FAIL); - return 0; - } - // all good to go! the SSL socket should be up and running - m_print("SSL Initialized"); - setWriteError(SSL_OK); - return 1; + m_print("Base ethernet client connected!"); + return m_start_ssl(host); } /** see SSLClientImpl.h*/ @@ -235,11 +213,60 @@ uint8_t SSLClientImpl::connected() { return c_con && br_con && wr_ok; } +/** see SSLClientImpl.h */ +int SSLClientImpl::m_start_ssl(const char* host) { + // get some random data by reading the analog pin we've been handed + // we want 128 bits to be safe, as recommended by the bearssl docs + uint8_t rng_seeds[16]; + // take the bottom 8 bits of the analog read + for (uint8_t i = 0; i < sizeof rng_seeds; i++) rng_seeds[i] = static_cast(analogRead(m_analog_pin)); + br_ssl_engine_inject_entropy(&m_sslctx.eng, rng_seeds, sizeof rng_seeds); + // reset the client context, and look for previous sessions + auto ret = br_ssl_client_reset(&m_sslctx, host, 1); + if (!ret) { + m_print("Error: reset failed"); + m_print(br_ssl_engine_last_error(&m_sslctx.eng)); + } + // initlalize the SSL socket over the network + // normally this would happen in br_sslio_write, but I think it makes + // a little more structural sense to put it here + if (m_run_until(BR_SSL_SENDAPP) < 0) { + m_print("Error: Failed to initlalize the SSL layer"); + setWriteError(SSL_BR_CONNECT_FAIL); + return 0; + } + // all good to go! the SSL socket should be up and running + m_print("SSL Initialized"); + setWriteError(SSL_OK); + return 1; +} + /** see SSLClientImpl.h*/ int SSLClientImpl::m_run_until(const unsigned target) { + unsigned lastState = 0; + size_t lastLen = 0; for (;;) { + // error check + if (!connected()) { + m_print("Error: tried to run_until when the engine is closed"); + return -1; + } unsigned state = m_update_engine(); - /* + // debug + if (state != lastState) { + lastState = state; + m_print("m_run stuck:"); + printState(state); + } + if (state & BR_SSL_RECVREC) { + size_t len; + unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); + if (lastLen != len) { + m_print("Expected bytes count: "); + m_print(lastLen = len); + } + } + /* * If we reached our target, then we are finished. */ if (state & target) return 0; @@ -260,6 +287,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { m_write_idx = 0; m_print("Warn: discarded unread data to favor a write operation"); br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); + continue; } else { m_print("Error: ssl engine state is RECVAPP, however the buffer was null!"); @@ -276,6 +304,9 @@ int SSLClientImpl::m_run_until(const unsigned target) { * record. */ if (state & BR_SSL_SENDAPP && target & BR_SSL_RECVAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); + + // debug delay + delay(500); } } @@ -368,10 +399,24 @@ unsigned SSLClientImpl::m_update_engine() { size_t len; unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? - if (m_client->available() >= len) { + const auto avail = m_client->available(); + if (avail >= len) { + m_print("Read bytes from client: "); + m_print(avail); + m_print(len); + /* + unsigned char debug[avail]; + m_client->read(debug, avail); + for (size_t i = 0; i < avail; i++) { + Serial.print("0x"); + Serial.print(debug[i], HEX); + Serial.print(", "); + } + while(true) {} + */ // I suppose so! - int rlen = m_client->readBytes((char *)buf, len); - if (rlen < 0) { + int rlen = m_client->read(buf, len); + if (rlen <= 0) { m_print("Error reading bytes from m_client"); setWriteError(SSL_BR_WRITE_ERROR); return 0; @@ -382,7 +427,11 @@ unsigned SSLClientImpl::m_update_engine() { continue; } // guess not, tell the state we're waiting still - else return state; + else { + m_print("Bytes avail: "); + m_print(avail); + return state; + } } // if it's not any of the above states, then it must be waiting to send or recieve app data // in which case we return diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 0bde340..21fe88f 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -33,7 +33,8 @@ public: * @brief initializes SSL contexts for bearSSL * * @pre The client class must be able to access the internet, as SSLClient - * cannot manage this for you. + * cannot manage this for you. Additionally it is recommended that the analog_pin + * be set to input. * * @post set_client must be called immediatly after to set the client class * pointer. @@ -42,9 +43,10 @@ public: * of the SSL server certificate, generated using the `brssl` command * line utility. For more information see the samples or bearssl.org * @param trust_anchors_num The number of trust anchors stored + * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true); + explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug = true); /** Dtor is implicit since unique_ptr handles it fine */ /** functions specific to the EthernetClient which I'll have to override */ @@ -128,6 +130,22 @@ private: Serial.println(str); } } + + void printState(unsigned state) const { + if(m_debug) { + m_print("State: "); + if(state == 0) m_print(" Invalid"); + else if (state & BR_SSL_CLOSED) m_print(" Connection closed"); + else { + if (state & BR_SSL_SENDREC) m_print(" SENDREC"); + if (state & BR_SSL_RECVREC) m_print(" RECVREC"); + if (state & BR_SSL_SENDAPP) m_print(" SENDAPP"); + if (state & BR_SSL_RECVAPP) m_print(" RECVAPP"); + } + } + } + /** start the ssl engine on the connected client */ + int m_start_ssl(const char* host = NULL); /** run the bearssl engine until a certain state */ int m_run_until(const unsigned target); /** proxy for availble that returns the state */ @@ -138,6 +156,8 @@ private: // should not be computed at runtime const br_x509_trust_anchor *m_trust_anchors; const size_t m_trust_anchors_num; + // store the pin to fetch an RNG see from + const int m_analog_pin; // store whether to enable debug logging const bool m_debug; // store the context values required for SSL diff --git a/src/bearssl/TLS12_only_profile.c b/src/TLS12_only_profile.c similarity index 100% rename from src/bearssl/TLS12_only_profile.c rename to src/TLS12_only_profile.c From 79a0a6135b0db5de94d02f119c980172bc64ecf9 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 28 Feb 2019 15:44:21 -0800 Subject: [PATCH 014/205] added unix timestamp macro, fixed RNG implementation with analog pin, fixed bugs (client works now!) --- src/SSLClientImpl.cpp | 42 +++++------ src/TLS12_only_profile.c | 34 +++++++-- src/bearssl/src/ssl/ssl_client_full.c | 19 +++++ src/time_macros.h | 101 ++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 31 deletions(-) create mode 100644 src/time_macros.h diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 6156a0e..90ba029 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -32,8 +32,8 @@ SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_a // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); // initlalize the various bearssl libraries so they're ready to go when we connect - // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); - br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // check if the buffer size is half or full duplex constexpr auto duplex = sizeof m_iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); @@ -74,7 +74,7 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { /** see SSLClientImpl.h*/ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { // check if the socket is still open and such - if(!connected()) { + if(br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED || getWriteError()) { m_print("Client is not connected! Perhaps something has happened?"); return 0; } @@ -119,7 +119,7 @@ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { /** see SSLClientImpl.h*/ int SSLClientImpl::available() { // connection check - if (!connected()) { + if (br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED || getWriteError()) { m_print("Warn: Cannot check available of disconnected client"); return 0; } @@ -153,7 +153,7 @@ int SSLClientImpl::read(uint8_t *buf, size_t size) { const size_t read_amount = size > alen ? alen : size; memcpy(buf, br_buf, read_amount); // tell engine we read that many bytes - br_ssl_engine_sendapp_ack(&m_sslctx.eng, read_amount); + br_ssl_engine_recvapp_ack(&m_sslctx.eng, read_amount); // tell the user we read that many bytes return read_amount; } @@ -221,7 +221,6 @@ int SSLClientImpl::m_start_ssl(const char* host) { // take the bottom 8 bits of the analog read for (uint8_t i = 0; i < sizeof rng_seeds; i++) rng_seeds[i] = static_cast(analogRead(m_analog_pin)); br_ssl_engine_inject_entropy(&m_sslctx.eng, rng_seeds, sizeof rng_seeds); - // reset the client context, and look for previous sessions auto ret = br_ssl_client_reset(&m_sslctx, host, 1); if (!ret) { m_print("Error: reset failed"); @@ -232,11 +231,13 @@ int SSLClientImpl::m_start_ssl(const char* host) { // a little more structural sense to put it here if (m_run_until(BR_SSL_SENDAPP) < 0) { m_print("Error: Failed to initlalize the SSL layer"); + m_print(br_ssl_engine_last_error(&m_sslctx.eng)); setWriteError(SSL_BR_CONNECT_FAIL); return 0; } // all good to go! the SSL socket should be up and running m_print("SSL Initialized"); + m_print(m_sslctx.eng.selected_protocol); setWriteError(SSL_OK); return 1; } @@ -246,12 +247,12 @@ int SSLClientImpl::m_run_until(const unsigned target) { unsigned lastState = 0; size_t lastLen = 0; for (;;) { + unsigned state = m_update_engine(); // error check - if (!connected()) { + if (state == BR_SSL_CLOSED || getWriteError()) { m_print("Error: tried to run_until when the engine is closed"); return -1; } - unsigned state = m_update_engine(); // debug if (state != lastState) { lastState = state; @@ -304,10 +305,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { * record. */ if (state & BR_SSL_SENDAPP && target & BR_SSL_RECVAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); - - // debug delay - delay(500); - } + } } /** see SSLClientImpl.h*/ @@ -327,6 +325,7 @@ unsigned SSLClientImpl::m_update_engine() { buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); wlen = m_client->write(buf, len); + // let the chip recover if (wlen < 0) { m_print("Error writing to m_client"); /* @@ -404,16 +403,7 @@ unsigned SSLClientImpl::m_update_engine() { m_print("Read bytes from client: "); m_print(avail); m_print(len); - /* - unsigned char debug[avail]; - m_client->read(debug, avail); - for (size_t i = 0; i < avail; i++) { - Serial.print("0x"); - Serial.print(debug[i], HEX); - Serial.print(", "); - } - while(true) {} - */ + // I suppose so! int rlen = m_client->read(buf, len); if (rlen <= 0) { @@ -428,8 +418,12 @@ unsigned SSLClientImpl::m_update_engine() { } // guess not, tell the state we're waiting still else { - m_print("Bytes avail: "); - m_print(avail); + // m_print("Bytes avail: "); + // m_print(avail); + // m_print("Bytes needed: "); + // m_print(len); + // add a delay since spamming m_client->availible breaks the poor wiz chip + delay(10); return state; } } diff --git a/src/TLS12_only_profile.c b/src/TLS12_only_profile.c index f253e2b..e0b8295 100644 --- a/src/TLS12_only_profile.c +++ b/src/TLS12_only_profile.c @@ -24,6 +24,7 @@ #include "bearssl.h" #include "bearssl_ssl.h" +#include "time_macros.h" /* * A "profile" is an initialisation function for a SSL context, that @@ -420,6 +421,24 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, br_x509_minimal_init(xc, &br_sha256_vtable, trust_anchors, trust_anchors_num); + /* + * Set a fixed epoch time to validate certificates against. + * Since we are working with an embedded device, there isn't + * really a reliable source of time. To remedy this, we simply + * store the time this program was compiled, and assume that + * any certificate valid under that time is also valid at the + * current time. This is vulnerable to the use of expired + * certificates, however an attacker would have to use a + * certificate valid after the compile date, which is fairly + * difficult given the lifespan of projects here at the lab. + * For now, this solution is good enough. + */ + br_x509_minimal_set_time(xc, + // days since 1970 + days from 1970 to year 0 + (UNIX_TIMESTAMP_UTC / SEC_PER_DAY) + 719528UL, + // seconds over start of day + UNIX_TIMESTAMP_UTC % SEC_PER_DAY); + /* * Set suites and asymmetric crypto implementations. We use the * "i31" code for RSA (it is somewhat faster than the "i32" @@ -431,11 +450,12 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * the RSA verification function below. */ // br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy); - br_x509_minimal_set_rsa(xc, &br_rsa_i15_pkcs1_vrfy); + br_x509_minimal_set_rsa(xc, br_ssl_engine_get_rsavrfy(&cc->eng)); // br_x509_minimal_set_ecdsa(xc, // &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); br_x509_minimal_set_ecdsa(xc, - &br_ec_all_m15, &br_ecdsa_i15_vrfy_asn1); + br_ssl_engine_get_ec(&cc->eng), + br_ssl_engine_get_ecdsa(&cc->eng)); /* * Set supported hash functions. These are for signatures on @@ -447,11 +467,11 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * Note: the engine explicitly rejects signatures that use MD5. * Thus, there is no need for MD5 here. */ - // br_ssl_engine_set_hash(xc, br_sha1_ID, &br_sha1_vtable); - br_ssl_engine_set_hash(xc, br_sha224_ID, &br_sha224_vtable); - br_ssl_engine_set_hash(xc, br_sha256_ID, &br_sha256_vtable); - br_ssl_engine_set_hash(xc, br_sha384_ID, &br_sha384_vtable); - // br_ssl_engine_set_hash(xc, br_sha512_ID, &br_sha512_vtable); + // br_x509_minimal_set_hash(xc, br_sha1_ID, &br_sha1_vtable); + br_x509_minimal_set_hash(xc, br_sha224_ID, &br_sha224_vtable); + br_x509_minimal_set_hash(xc, br_sha256_ID, &br_sha256_vtable); + br_x509_minimal_set_hash(xc, br_sha384_ID, &br_sha384_vtable); + // br_x509_minimal_set_hash(xc, br_sha512_ID, &br_sha512_vtable); /* * Link the X.509 engine in the SSL engine. diff --git a/src/bearssl/src/ssl/ssl_client_full.c b/src/bearssl/src/ssl/ssl_client_full.c index 9814349..fd35b3c 100644 --- a/src/bearssl/src/ssl/ssl_client_full.c +++ b/src/bearssl/src/ssl/ssl_client_full.c @@ -23,6 +23,7 @@ */ #include "inner.h" +#include "time_macros.h" /* see bearssl_ssl.h */ void @@ -155,6 +156,24 @@ br_ssl_client_init_full(br_ssl_client_context *cc, br_x509_minimal_set_hash(xc, id, hc); } + /* + * Set a fixed epoch time to validate certificates against. + * Since we are working with an embedded device, there isn't + * really a reliable source of time. To remedy this, we simply + * store the time this program was compiled, and assume that + * any certificate valid under that time is also valid at the + * current time. This is vulnerable to the use of expired + * certificates, however an attacker would have to use a + * certificate valid after the compile date, which is fairly + * difficult given the lifespan of projects here at the lab. + * For now, this solution is good enough. + */ + br_x509_minimal_set_time(xc, + // days since 1970 + days from 1970 to year 0 + (UNIX_TIMESTAMP_UTC / SEC_PER_DAY) + 719528UL, + // seconds over start of day + UNIX_TIMESTAMP_UTC % SEC_PER_DAY); + /* * Link the X.509 engine in the SSL engine. */ diff --git a/src/time_macros.h b/src/time_macros.h new file mode 100644 index 0000000..937eddc --- /dev/null +++ b/src/time_macros.h @@ -0,0 +1,101 @@ +/* + * + * Created: 29.03.2018 + * + * Authors: + * + * Assembled from the code released on Stackoverflow by: + * Dennis (instructable.com/member/nqtronix) | https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string + * and + * Alexis Wilke | https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date + * + * Assembled by Jean Rabault + * + * UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of compilation from macros using the compiler defined __TIME__ macro. + * This should include Gregorian calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps. + * + * Careful: __TIME__ is the local time of the computer, NOT the UTC time in general! + * + */ + +#ifndef COMPILE_TIME_H_ +#define COMPILE_TIME_H_ + +// add offset for pacific standard time +#define PST_OFFSET (8UL) + +// Some definitions for calculation +#define SEC_PER_MIN (60UL) +#define SEC_PER_HOUR (3600UL) +#define SEC_PER_DAY (86400UL) +#define SEC_PER_YEAR (SEC_PER_DAY*365) + +// extracts 1..4 characters from a string and interprets it as a decimal value +#define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0) +#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0') +#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0') +#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0') + +// Custom "glue logic" to convert the month name to a usable number +#define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \ + str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \ + str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \ + str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \ + str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \ + str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \ + str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \ + str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \ + str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \ + str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \ + str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \ + str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0) + +// extract the information from the time string given by __TIME__ and __DATE__ +#define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6) +#define __TIME_MINUTES__ CONV_STR2DEC_2(__TIME__, 3) +#define __TIME_HOURS__ CONV_STR2DEC_2(__TIME__, 0) +#define __TIME_DAYS__ CONV_STR2DEC_2(__DATE__, 4) +#define __TIME_MONTH__ GET_MONTH(__DATE__, 0) +#define __TIME_YEARS__ CONV_STR2DEC_4(__DATE__, 7) + +// Days in February +#define _UNIX_TIMESTAMP_FDAY(year) \ + (((year) % 400) == 0UL ? 29UL : \ + (((year) % 100) == 0UL ? 28UL : \ + (((year) % 4) == 0UL ? 29UL : \ + 28UL))) + +// Days in the year +#define _UNIX_TIMESTAMP_YDAY(year, month, day) \ + ( \ + /* January */ day \ + /* February */ + (month >= 2 ? 31UL : 0UL) \ + /* March */ + (month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \ + /* April */ + (month >= 4 ? 31UL : 0UL) \ + /* May */ + (month >= 5 ? 30UL : 0UL) \ + /* June */ + (month >= 6 ? 31UL : 0UL) \ + /* July */ + (month >= 7 ? 30UL : 0UL) \ + /* August */ + (month >= 8 ? 31UL : 0UL) \ + /* September */+ (month >= 9 ? 31UL : 0UL) \ + /* October */ + (month >= 10 ? 30UL : 0UL) \ + /* November */ + (month >= 11 ? 31UL : 0UL) \ + /* December */ + (month >= 12 ? 30UL : 0UL) \ + ) + +// get the UNIX timestamp from a digits representation +#define _UNIX_TIMESTAMP(year, month, day, hour, minute, second) \ + ( /* time */ second \ + + minute * SEC_PER_MIN \ + + hour * SEC_PER_HOUR \ + + /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \ + + /* year */ (year - 1970UL) * SEC_PER_YEAR \ + + ((year - 1969UL) / 4UL) * SEC_PER_DAY \ + - ((year - 1901UL) / 100UL) * SEC_PER_DAY \ + + ((year - 1601UL) / 400UL) * SEC_PER_DAY \ + ) + +// the UNIX timestamp +#define UNIX_TIMESTAMP _UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__) +#define UNIX_TIMESTAMP_UTC (UNIX_TIMESTAMP + (PST_OFFSET*SEC_PER_HOUR)) + +#endif \ No newline at end of file From ddb4045959ba45e105eeecf31b4cc8d08eeeac65 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 5 Mar 2019 18:30:50 -0800 Subject: [PATCH 015/205] added session resumption (need to ensure the client is always contacting the same IP), fixed a bug where if the socket was unexpectedly closed bearssl would loop (it still soft locks, need to figure out why) --- src/SSLClientImpl.cpp | 42 ++++++++++++++++++++++++++++++++++-------- src/SSLClientImpl.h | 4 ++-- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 90ba029..11d4b9c 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -31,6 +31,8 @@ SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_a // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); + // zero the session parameters for similar reason + memset(&m_ses_param, 0, sizeof m_ses_param); // initlalize the various bearssl libraries so they're ready to go when we connect br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); @@ -182,13 +184,14 @@ void SSLClientImpl::flush() { void SSLClientImpl::stop() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); - while (br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED) { - /* + // if the engine isn't closed, and the socket is still open + while (br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED + && m_run_until(BR_SSL_RECVAPP) == 0) { + /* * Discard any incoming application data. */ size_t len; - m_run_until(BR_SSL_RECVAPP); if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != NULL) { br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); } @@ -221,13 +224,19 @@ int SSLClientImpl::m_start_ssl(const char* host) { // take the bottom 8 bits of the analog read for (uint8_t i = 0; i < sizeof rng_seeds; i++) rng_seeds[i] = static_cast(analogRead(m_analog_pin)); br_ssl_engine_inject_entropy(&m_sslctx.eng, rng_seeds, sizeof rng_seeds); - auto ret = br_ssl_client_reset(&m_sslctx, host, 1); + // inject session parameters for faster reconnection, if we have any + if(m_ses_param.session_id_len > 0) { + m_print("Set session!"); + br_ssl_engine_set_session_parameters(&m_sslctx.eng, &m_ses_param); + } + // reset the engine, but make sure that it reset successfully + int ret = br_ssl_client_reset(&m_sslctx, host, 1); if (!ret) { m_print("Error: reset failed"); m_print(br_ssl_engine_last_error(&m_sslctx.eng)); - } + } // initlalize the SSL socket over the network - // normally this would happen in br_sslio_write, but I think it makes + // normally this would happen in write, but I think it makes // a little more structural sense to put it here if (m_run_until(BR_SSL_SENDAPP) < 0) { m_print("Error: Failed to initlalize the SSL layer"); @@ -236,8 +245,16 @@ int SSLClientImpl::m_start_ssl(const char* host) { return 0; } // all good to go! the SSL socket should be up and running - m_print("SSL Initialized"); - m_print(m_sslctx.eng.selected_protocol); + // debug print the session parameters to see if they exist + br_ssl_engine_get_session_parameters(&m_sslctx.eng, &m_ses_param); + m_print("Session:"); + for (uint8_t i = 0; i < m_ses_param.session_id_len; i++) { + Serial.print(", 0x"); + Serial.print(m_ses_param.session_id[i], HEX); + } + Serial.println(); + Serial.println(m_ses_param.cipher_suite, HEX); + // clear the error flag: we've connected! setWriteError(SSL_OK); return 1; } @@ -324,6 +341,15 @@ unsigned SSLClientImpl::m_update_engine() { int wlen; buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); + Serial.print("Payload: "); + for (int i = 0; i < len; i++) { + if (buf[i] <= 0x0f) Serial.print("0x0"); + else Serial.print("0x"); + Serial.print(buf[i], HEX); + Serial.print(", "); + } + Serial.println(); + //delay(100); wlen = m_client->write(buf, len); // let the chip recover if (wlen < 0) { diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 21fe88f..8e323ef 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -173,8 +173,8 @@ private: // so we can send our records all at once to prevent // weird timing issues size_t m_write_idx; - // store the last error code - + // store the last SSL session, so reconnection later is speedy fast + br_ssl_session_parameters m_ses_param; }; #endif /* SSLClientImpl_H_ */ \ No newline at end of file From d59faf1f7d70e9c60a510ea805d7883057710e68 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Mar 2019 08:26:41 -0800 Subject: [PATCH 016/205] fixed a bug where a write error would persist across sessions --- src/SSLClientImpl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 11d4b9c..4778308 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -70,6 +70,9 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { return 0; } m_print("Base ethernet client connected!"); + // clear the write error + setWriteError(SSL_OK); + // start ssl! return m_start_ssl(host); } @@ -254,8 +257,6 @@ int SSLClientImpl::m_start_ssl(const char* host) { } Serial.println(); Serial.println(m_ses_param.cipher_suite, HEX); - // clear the error flag: we've connected! - setWriteError(SSL_OK); return 1; } From ac03dc943a0be5a2a9b079f0956c7a40266a5041 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Mar 2019 15:41:38 -0800 Subject: [PATCH 017/205] implemented IP-based session caching --- src/SSLClient.h | 10 ++++------ src/SSLClientImpl.cpp | 39 ++++++++++++++++++++++++++------------- src/SSLClientImpl.h | 16 +++++++++++++--- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 1ce3647..f25d4d8 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -108,20 +108,18 @@ public: set_client(&m_client); } - /** + /* * The special functions most clients have are below * Most of them smply pass through */ - virtual int availableForWrite(void) { return m_client.availableForWrite(); } virtual operator bool() { return connected() > 0; } virtual bool operator==(const bool value) { return bool() == value; } virtual bool operator!=(const bool value) { return bool() != value; } virtual bool operator==(const C& rhs) { return m_client == rhs; } virtual bool operator!=(const C& rhs) { return m_client != rhs; } - virtual uint16_t localPort() { return m_client.localPort(); } - virtual IPAddress remoteIP() { return m_client.remoteIP(); } - virtual uint16_t remotePort() { return m_client.remotePort(); } - virtual void setConnectionTimeout(uint16_t timeout) { m_client.setConnectionTimeout(timeout); } + virtual uint16_t localPort() { return std::is_member_function_pointer::value ? m_client.localPort() : 0; } + virtual IPAddress remoteIP() { return std::is_member_function_pointer::value ? m_client.remoteIP() : INADDR_NONE; } + virtual uint16_t remotePort() { return std::is_member_function_pointer::value ? m_client.remotePort() : 0; } //! get the client object C& getClient() { return m_client; } diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 4778308..3217766 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -21,18 +21,18 @@ #include "SSLClient.h" /** see SSLClientImpl.h */ -SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug) +SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, const int analog_pin, const bool debug) : m_client(client) , m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) , m_analog_pin(analog_pin) , m_debug(debug) - , m_write_idx(0) { + , m_write_idx(0) + , m_session() { // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); - // zero the session parameters for similar reason - memset(&m_ses_param, 0, sizeof m_ses_param); // initlalize the various bearssl libraries so they're ready to go when we connect br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); @@ -62,16 +62,25 @@ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { int SSLClientImpl::connect(const char *host, uint16_t port) { // reset indexs for saftey m_write_idx = 0; + // first, if we have a session, check if we're trying to resolve the same host + // as before + bool connect_ok; + if (m_session.is_valid_session() + && strcmp(m_session.get_hostname(), host) == 0) { + // if so, then connect using the stored session + m_print("Connecting using a cached IP"); + connect_ok = m_client->connect(m_session.get_ip(), port); + } + // else connect with the provided hostname + else connect_ok = m_client->connect(host, port); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. - if (!m_client->connect(host, port)) { + if (!connect_ok) { m_print("Error: Failed to connect using m_client"); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } m_print("Base ethernet client connected!"); - // clear the write error - setWriteError(SSL_OK); // start ssl! return m_start_ssl(host); } @@ -221,6 +230,8 @@ uint8_t SSLClientImpl::connected() { /** see SSLClientImpl.h */ int SSLClientImpl::m_start_ssl(const char* host) { + // clear the write error + setWriteError(SSL_OK); // get some random data by reading the analog pin we've been handed // we want 128 bits to be safe, as recommended by the bearssl docs uint8_t rng_seeds[16]; @@ -228,9 +239,9 @@ int SSLClientImpl::m_start_ssl(const char* host) { for (uint8_t i = 0; i < sizeof rng_seeds; i++) rng_seeds[i] = static_cast(analogRead(m_analog_pin)); br_ssl_engine_inject_entropy(&m_sslctx.eng, rng_seeds, sizeof rng_seeds); // inject session parameters for faster reconnection, if we have any - if(m_ses_param.session_id_len > 0) { + if(m_session.is_valid_session()) { + br_ssl_engine_set_session_parameters(&m_sslctx.eng, m_session.to_br_session()); m_print("Set session!"); - br_ssl_engine_set_session_parameters(&m_sslctx.eng, &m_ses_param); } // reset the engine, but make sure that it reset successfully int ret = br_ssl_client_reset(&m_sslctx, host, 1); @@ -249,14 +260,16 @@ int SSLClientImpl::m_start_ssl(const char* host) { } // all good to go! the SSL socket should be up and running // debug print the session parameters to see if they exist - br_ssl_engine_get_session_parameters(&m_sslctx.eng, &m_ses_param); + br_ssl_engine_get_session_parameters(&m_sslctx.eng, m_session.to_br_session()); + // set the hostname and ip in the session as well + m_session.set_parameters(remoteIP(), host); m_print("Session:"); - for (uint8_t i = 0; i < m_ses_param.session_id_len; i++) { + for (uint8_t i = 0; i < m_session.session_id_len; i++) { Serial.print(", 0x"); - Serial.print(m_ses_param.session_id[i], HEX); + Serial.print(m_session.session_id[i], HEX); } Serial.println(); - Serial.println(m_ses_param.cipher_suite, HEX); + Serial.println(m_session.cipher_suite, HEX); return 1; } diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 8e323ef..ea9ce0f 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -19,8 +19,9 @@ */ #include "bearssl.h" -#include "Client.h" #include "Arduino.h" +#include "Client.h" +#include "SSLSession.h" #ifndef SSLClientImpl_H_ #define SSLClientImpl_H_ @@ -44,9 +45,13 @@ public: * line utility. For more information see the samples or bearssl.org * @param trust_anchors_num The number of trust anchors stored * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG + * @param get_remote_ip Function pointer to get the remote ip from the client. We + * need this value since the Client abstract class has no remoteIP() function, + * however most of the arduino internet client implementations do. * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug = true); + explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, const int analog_pin, const bool debug = true); /** Dtor is implicit since unique_ptr handles it fine */ /** functions specific to the EthernetClient which I'll have to override */ @@ -111,6 +116,10 @@ public: virtual void stop(); virtual uint8_t connected(); + // stub virtual functions to get things from the client + virtual uint16_t localPort() = 0; + virtual IPAddress remoteIP() = 0; + virtual uint16_t remotePort() = 0; protected: /** * @brief set the pointer to the Client class that we wil use @@ -120,6 +129,7 @@ protected: * is critical that this function is called before anything else */ void set_client(Client* c) { m_client = c; } + private: /** @brief debugging print function, only prints if m_debug is true */ @@ -174,7 +184,7 @@ private: // weird timing issues size_t m_write_idx; // store the last SSL session, so reconnection later is speedy fast - br_ssl_session_parameters m_ses_param; + SSLSession m_session; }; #endif /* SSLClientImpl_H_ */ \ No newline at end of file From 257a61e0f3d2918bf604dc6184e16fa31adce2d3 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Mar 2019 15:42:05 -0800 Subject: [PATCH 018/205] forgot to commit this file, see above commit --- src/SSLSession.h | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/SSLSession.h diff --git a/src/SSLSession.h b/src/SSLSession.h new file mode 100644 index 0000000..a4e1f22 --- /dev/null +++ b/src/SSLSession.h @@ -0,0 +1,94 @@ +/* Copyright 2019 OSU OPEnS Lab + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * SSLSession.h + * + * This file contains a simple utility class to store parameters about an SSL Session + * for reuse later. + */ + +#include "bearssl.h" + +#ifndef SSLSession_H_ +#define SSLSession_H_ + +/** + * \brief This class stores values which allow SSLClient to save and resume SSL sessions. + * + * This class was created to extend the values stored in br_ssl_session_parameters, + * which allow BearSSL to resume an SSL session. When testing BearSSL's session + * resumption feature, it was observed that BearSSL can only resume a session that was + * was started with the same server. This becomes an issue when using repeated requests + * to a domain name which can resolve to multiple IP addresses ("api.github.com"), as + * the device will switch between two or three servers. Since BearSSL only stores one + * session at a time, this results in session resumption being few and far between. + * + * To remedy this problem, an SSLSession stores the IPAddress and hostname, along with + * the parameters in br_ssl_session_parameters struct. Using this data, SSLClient is + * able to remember which IPAddress is associated with which session, allowing it to + * reconnect to the last IPAddress, as opposed to any associated with the domain. + */ + +class SSLSession : public br_ssl_session_parameters { + +public: + explicit SSLSession() + : m_valid_session(false) + , m_hostname({}) + , m_ip(INADDR_NONE) {} + + /** + * \pre must call br_ssl_engine_get_session_parameters(engine, toBearSSlSession()); + */ + void set_parameters(const IPAddress& ip, const char* hostname = NULL) { + // copy the hostname + if (hostname != NULL) strncpy(m_hostname, hostname, sizeof m_hostname - 1); + // or if there's no hostname, clear the string + else m_hostname[0] = '\0'; + // and the IP address + m_ip = ip; + // check if both values are valid, and if so set valid to true + if (m_ip != INADDR_NONE && session_id_len > 0 + && (hostname == NULL || strlen(m_hostname) > 0)) m_valid_session = true; + } + + br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; } + + /** + * \pre must check isValidSession + */ + const char* const get_hostname() const { return m_hostname; } + + /** + * \pre must check isValidSession + */ + const IPAddress& get_ip() const { return m_ip; } + + const bool is_valid_session() const { return m_valid_session; } +private: + bool m_valid_session; + // aparently a hostname has a max length of 256 chars. Go figure. + char m_hostname[256]; + // store the IP Address we connected to + IPAddress m_ip; +}; + +#endif /* SSLSession_H_ */ \ No newline at end of file From ab0cf9d52be9faa5b8270fd3f938ae9e64f30288 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Mar 2019 18:15:39 -0800 Subject: [PATCH 019/205] implemented session cache of size n, need to figure out failure cases and account for them --- src/SSLClient.h | 40 +++++++++++++++++++++++++++++++- src/SSLClientImpl.cpp | 54 ++++++++++++++++++++++--------------------- src/SSLClientImpl.h | 11 +++++---- src/SSLSession.h | 6 ++--- 4 files changed, 76 insertions(+), 35 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index f25d4d8..8310bea 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -70,7 +70,7 @@ enum Error { * from the client side, however from the developer side it can be a bit confusing. */ -template +template class SSLClient : public SSLClientImpl { /** static type checks * I'm a java developer, so I want to ensure that my inheritance is safe. @@ -79,6 +79,7 @@ class SSLClient : public SSLClientImpl { * class inherits from Client, and then that it contains a status() function. */ static_assert(std::is_base_of::value, "C must be a Client Class!"); +static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!"); // static_assert(std::is_function::value, "C must have a status() function!"); public: @@ -102,6 +103,8 @@ public: explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug = true) : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) + , m_sessions{} + , m_index(0) { // since we are copying the client in the ctor, we have to set // the client pointer after the class is constructed @@ -124,9 +127,44 @@ public: //! get the client object C& getClient() { return m_client; } + virtual SSLSession& getSession(const char* host, const IPAddress& addr) { + // search for a matching session with the IP + int temp_index = -1; + for (size_t i = 0; i < SessionCache; i++) { + // if we're looking at a real session + if (m_sessions[i].is_valid_session() + && ( + // and the hostname matches, or + (host != NULL && strcmp(host, m_sessions[i].get_hostname()) == 0) + // there is no hostname and the IP address matches + || (host == NULL && addr == m_sessions[i].get_ip()) + )) { + + temp_index = i; + break; + } + } + // if none are availible, use m_index + if (temp_index == -1) { + temp_index = m_index; + // reset the session so we don't try to send one sites session to another + m_sessions[temp_index] = SSLSession(); + } + // increment m_index so the session cache is a circular buffer + if (temp_index == m_index && ++m_index >= SessionCache) m_index = 0; + // return the pointed to value + m_print("Using index: "); + m_print(temp_index); + return m_sessions[temp_index]; + } + private: // create a copy of the client C m_client; + // also store an array of SSLSessions, so we can resume communication with multiple websites + SSLSession m_sessions[SessionCache]; + // store an index of where a new session can be placed if we don't have any corresponding sessions + size_t m_index; }; #endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 3217766..66f1042 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -28,13 +28,13 @@ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_a , m_trust_anchors_num(trust_anchors_num) , m_analog_pin(analog_pin) , m_debug(debug) - , m_write_idx(0) - , m_session() { + , m_write_idx(0) { // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); // initlalize the various bearssl libraries so they're ready to go when we connect br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + // comment the above line and uncomment the line below if you're having trouble connecting over SSL // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // check if the buffer size is half or full duplex constexpr auto duplex = sizeof m_iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; @@ -43,6 +43,11 @@ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_a /* see SSLClientImpl.h*/ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { + // connection check + if (connected()) { + m_print("Error: cannot have two connections at the same time! Please create another SSLClient instance."); + return -1; + } // reset indexs for saftey m_write_idx = 0; // Warning for security @@ -55,21 +60,26 @@ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { return 0; } m_print("Base ethernet client connected!"); - return m_start_ssl(); + return m_start_ssl(NULL, getSession(NULL, ip)); } /* see SSLClientImpl.h*/ int SSLClientImpl::connect(const char *host, uint16_t port) { + // connection check + if (connected()) { + m_print("Error: cannot have two connections at the same time! Please create another SSLClient instance."); + return -1; + } // reset indexs for saftey m_write_idx = 0; // first, if we have a session, check if we're trying to resolve the same host // as before bool connect_ok; - if (m_session.is_valid_session() - && strcmp(m_session.get_hostname(), host) == 0) { + SSLSession& ses = getSession(host, INADDR_NONE); + if (ses.is_valid_session()) { // if so, then connect using the stored session m_print("Connecting using a cached IP"); - connect_ok = m_client->connect(m_session.get_ip(), port); + connect_ok = m_client->connect(ses.get_ip(), port); } // else connect with the provided hostname else connect_ok = m_client->connect(host, port); @@ -82,7 +92,7 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { } m_print("Base ethernet client connected!"); // start ssl! - return m_start_ssl(host); + return m_start_ssl(host, ses); } /** see SSLClientImpl.h*/ @@ -229,7 +239,7 @@ uint8_t SSLClientImpl::connected() { } /** see SSLClientImpl.h */ -int SSLClientImpl::m_start_ssl(const char* host) { +int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { // clear the write error setWriteError(SSL_OK); // get some random data by reading the analog pin we've been handed @@ -239,8 +249,8 @@ int SSLClientImpl::m_start_ssl(const char* host) { for (uint8_t i = 0; i < sizeof rng_seeds; i++) rng_seeds[i] = static_cast(analogRead(m_analog_pin)); br_ssl_engine_inject_entropy(&m_sslctx.eng, rng_seeds, sizeof rng_seeds); // inject session parameters for faster reconnection, if we have any - if(m_session.is_valid_session()) { - br_ssl_engine_set_session_parameters(&m_sslctx.eng, m_session.to_br_session()); + if(ssl_ses.is_valid_session()) { + br_ssl_engine_set_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); m_print("Set session!"); } // reset the engine, but make sure that it reset successfully @@ -259,17 +269,18 @@ int SSLClientImpl::m_start_ssl(const char* host) { return 0; } // all good to go! the SSL socket should be up and running - // debug print the session parameters to see if they exist - br_ssl_engine_get_session_parameters(&m_sslctx.eng, m_session.to_br_session()); + // overwrite the session we got with new parameters + br_ssl_engine_get_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); // set the hostname and ip in the session as well - m_session.set_parameters(remoteIP(), host); + ssl_ses.set_parameters(remoteIP(), host); + // print the session details m_print("Session:"); - for (uint8_t i = 0; i < m_session.session_id_len; i++) { + for (uint8_t i = 0; i < ssl_ses.session_id_len; i++) { Serial.print(", 0x"); - Serial.print(m_session.session_id[i], HEX); + Serial.print(ssl_ses.session_id[i], HEX); } Serial.println(); - Serial.println(m_session.cipher_suite, HEX); + Serial.println(ssl_ses.cipher_suite, HEX); return 1; } @@ -292,7 +303,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { } if (state & BR_SSL_RECVREC) { size_t len; - unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); + br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); if (lastLen != len) { m_print("Expected bytes count: "); m_print(lastLen = len); @@ -355,15 +366,6 @@ unsigned SSLClientImpl::m_update_engine() { int wlen; buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); - Serial.print("Payload: "); - for (int i = 0; i < len; i++) { - if (buf[i] <= 0x0f) Serial.print("0x0"); - else Serial.print("0x"); - Serial.print(buf[i], HEX); - Serial.print(", "); - } - Serial.println(); - //delay(100); wlen = m_client->write(buf, len); // let the chip recover if (wlen < 0) { diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index ea9ce0f..a8e7345 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -120,6 +120,9 @@ public: virtual uint16_t localPort() = 0; virtual IPAddress remoteIP() = 0; virtual uint16_t remotePort() = 0; + + // as well as store and retrieve session data + virtual SSLSession& getSession(const char* host, const IPAddress& addr) = 0; protected: /** * @brief set the pointer to the Client class that we wil use @@ -130,8 +133,6 @@ protected: */ void set_client(Client* c) { m_client = c; } -private: - /** @brief debugging print function, only prints if m_debug is true */ template constexpr void m_print(const T str) const { @@ -141,6 +142,8 @@ private: } } +private: + void printState(unsigned state) const { if(m_debug) { m_print("State: "); @@ -155,7 +158,7 @@ private: } } /** start the ssl engine on the connected client */ - int m_start_ssl(const char* host = NULL); + int m_start_ssl(const char* host, SSLSession& ssl_ses); /** run the bearssl engine until a certain state */ int m_run_until(const unsigned target); /** proxy for availble that returns the state */ @@ -183,8 +186,6 @@ private: // so we can send our records all at once to prevent // weird timing issues size_t m_write_idx; - // store the last SSL session, so reconnection later is speedy fast - SSLSession m_session; }; #endif /* SSLClientImpl_H_ */ \ No newline at end of file diff --git a/src/SSLSession.h b/src/SSLSession.h index a4e1f22..042091f 100644 --- a/src/SSLSession.h +++ b/src/SSLSession.h @@ -52,7 +52,7 @@ class SSLSession : public br_ssl_session_parameters { public: explicit SSLSession() : m_valid_session(false) - , m_hostname({}) + , m_hostname{} , m_ip(INADDR_NONE) {} /** @@ -75,14 +75,14 @@ public: /** * \pre must check isValidSession */ - const char* const get_hostname() const { return m_hostname; } + const char* get_hostname() const { return m_hostname; } /** * \pre must check isValidSession */ const IPAddress& get_ip() const { return m_ip; } - const bool is_valid_session() const { return m_valid_session; } + bool is_valid_session() const { return m_valid_session; } private: bool m_valid_session; // aparently a hostname has a max length of 256 chars. Go figure. From 2375ec0339de43a49360b04b57a2a24baacf1e95 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Mar 2019 18:16:05 -0800 Subject: [PATCH 020/205] untracked some extra files --- .gitignore | 3 +++ .vscode/c_cpp_properties.json | 22 ---------------------- .vscode/settings.json | 25 ------------------------- 3 files changed, 3 insertions(+), 47 deletions(-) delete mode 100644 .vscode/c_cpp_properties.json delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 259148f..6a8fcb1 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ *.exe *.out *.app + +# vscode IDE settings +.vscode/** \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index 89064ed..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "configurations": [ - { - "name": "SAMD", - "includePath": [ - "${workspaceFolder}/**", - "C:/Users/Noah/AppData/Local/Arduino15/packages/adafruit/hardware/samd/1.2.9/cores/arduino/**" - ], - "defines": [ - "_DEBUG", - "UNICODE", - "_UNICODE" - ], - "windowsSdkVersion": "10.0.17763.0", - "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Tools/MSVC/14.16.27023/bin/Hostx64/x64/cl.exe", - "cStandard": "c11", - "cppStandard": "c++17", - "intelliSenseMode": "msvc-x64" - } - ], - "version": 4 -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f76f1b2..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "files.associations": { - "cmath": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "cwchar": "cpp", - "exception": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "limits": "cpp", - "memory": "cpp", - "new": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "utility": "cpp", - "xmemory": "cpp", - "xmemory0": "cpp", - "xstddef": "cpp", - "xtr1common": "cpp", - "xutility": "cpp" - } -} \ No newline at end of file From c212e355a41d3c4206f77e4cc96e7481cb9bf4cb Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 11 Mar 2019 18:31:15 -0700 Subject: [PATCH 021/205] added lots and lots of Serial debugging framework, need to test and make sure it works --- src/SSLClient.h | 19 +--- src/SSLClientImpl.cpp | 250 ++++++++++++++++++++++++++++++------------ src/SSLClientImpl.h | 78 ++++++++++--- 3 files changed, 246 insertions(+), 101 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 8310bea..b47758a 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -42,19 +42,6 @@ #ifndef SSLClient_H_ #define SSLClient_H_ -/** error enums - * Static constants defining the possible errors encountered - * Read from getWriteError(); - */ -enum Error { - SSL_OK = 0, - SSL_CLIENT_CONNECT_FAIL, - SSL_BR_CONNECT_FAIL, - SSL_CLIENT_WRTIE_ERROR, - SSL_BR_WRITE_ERROR, - SSL_INTERNAL_ERROR -}; - /** * \brief This class serves as a templating proxy class for the SSLClientImpl to do the real work. * @@ -100,7 +87,7 @@ public: * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug = true) + explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_ERROR) : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) , m_sessions{} @@ -153,8 +140,8 @@ public: // increment m_index so the session cache is a circular buffer if (temp_index == m_index && ++m_index >= SessionCache) m_index = 0; // return the pointed to value - m_print("Using index: "); - m_print(temp_index); + m_info("Using session index: ", __func__); + Serial.println(temp_index); return m_sessions[temp_index]; } diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 66f1042..d4e85fd 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -22,7 +22,7 @@ /** see SSLClientImpl.h */ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, const bool debug) + const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) : m_client(client) , m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) @@ -43,31 +43,33 @@ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_a /* see SSLClientImpl.h*/ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { + const char* func_name = __func__; // connection check if (connected()) { - m_print("Error: cannot have two connections at the same time! Please create another SSLClient instance."); + m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } // reset indexs for saftey m_write_idx = 0; // Warning for security - m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible."); + m_warn("Using a raw IP Address for an SSL connection bypasses some important verification steps. You should use a domain name (www.google.com) whenever possible.", func_name); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!m_client->connect(ip, port)) { - m_print("Error: Failed to connect using m_client"); + m_error("Failed to connect using m_client. Are you connected to the internet?", func_name); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } - m_print("Base ethernet client connected!"); + m_info("Base client connected!", func_name); return m_start_ssl(NULL, getSession(NULL, ip)); } /* see SSLClientImpl.h*/ int SSLClientImpl::connect(const char *host, uint16_t port) { + const char* func_name = __func__; // connection check if (connected()) { - m_print("Error: cannot have two connections at the same time! Please create another SSLClient instance."); + m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } // reset indexs for saftey @@ -78,7 +80,7 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { SSLSession& ses = getSession(host, INADDR_NONE); if (ses.is_valid_session()) { // if so, then connect using the stored session - m_print("Connecting using a cached IP"); + m_info("Connecting using a cached IP", func_name); connect_ok = m_client->connect(ses.get_ip(), port); } // else connect with the provided hostname @@ -86,22 +88,20 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!connect_ok) { - m_print("Error: Failed to connect using m_client"); + m_error("Failed to connect using m_client. Are you connected to the internet?", func_name); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } - m_print("Base ethernet client connected!"); + m_info("Base client connected!", func_name); // start ssl! return m_start_ssl(host, ses); } /** see SSLClientImpl.h*/ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { + const char* func_name = __func__; // check if the socket is still open and such - if(br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED || getWriteError()) { - m_print("Client is not connected! Perhaps something has happened?"); - return 0; - } + if (!m_soft_connected(func_name)) return 0; // add to the bearssl io buffer, simply appending whatever we want to write size_t alen; unsigned char *br_buf = br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); @@ -112,21 +112,15 @@ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { // to the buffer in which we conclude it's already safe to write if(m_write_idx == 0) { if (m_run_until(BR_SSL_SENDAPP) < 0) { - m_print("Error: could not run until sendapp"); - setWriteError(SSL_BR_WRITE_ERROR); + m_error("Failed while waiting for the engine to enter BR_SSL_SENDAPP", func_name); return 0; } // reset the buffer pointer br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); } - // sanity check - if(br_buf == NULL || alen == 0) { - m_print("Error: recieved null buffer or zero alen in write"); - setWriteError(SSL_BR_WRITE_ERROR); - return 0; - } // if we're about to fill the buffer, we need to send the data and then wait // for another oppurtinity to send + // so we only send the smallest of the buffer size or our data size - how much we've already sent const size_t cpamount = m_write_idx + (size - cur_idx) > alen ? alen : size - cur_idx; memcpy(br_buf + m_write_idx, buf + cur_idx, cpamount); // if we filled the buffer, reset m_write_idx @@ -142,25 +136,19 @@ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { /** see SSLClientImpl.h*/ int SSLClientImpl::available() { + const char* func_name = __func__; // connection check - if (br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED || getWriteError()) { - m_print("Warn: Cannot check available of disconnected client"); - return 0; - } + if (!m_soft_connected(func_name)) return 0; // run the SSL engine until we are waiting for either user input or a server response unsigned state = m_update_engine(); - if (state == 0) { - m_print("Error: SSL engine failed: "); - m_print(br_ssl_engine_last_error(&m_sslctx.eng)); - setWriteError(SSL_BR_WRITE_ERROR); - } + if (state == 0) m_error("SSL engine failed to update.", func_name); else if(state & BR_SSL_RECVAPP) { // return how many received bytes we have size_t alen; br_ssl_engine_recvapp_buf(&m_sslctx.eng, &alen); return (int)(alen); } - else if (state == BR_SSL_CLOSED) m_print("Error: Tried to check available when engine is closed"); + else if (state == BR_SSL_CLOSED) m_warn("Engine closed after update", func_name); // flush the buffer if it's stuck in the SENDAPP state else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); // other state, or client is closed @@ -199,13 +187,15 @@ void SSLClientImpl::flush() { // trigger a flush, incase there's any leftover data br_ssl_engine_flush(&m_sslctx.eng, 0); // run until application data is ready for pickup - if(m_run_until(BR_SSL_RECVAPP) < 0) m_print("Error: could not flush write buffer!"); + if(m_run_until(BR_SSL_RECVAPP) < 0) m_error("Could not flush write buffer!", __func__); } /** see SSLClientImpl.h*/ void SSLClientImpl::stop() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); + // info about the socket connection + if (br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED) m_info("Socket was terminated before graceful closure (probably fine)", __func__); // if the engine isn't closed, and the socket is still open while (br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED && m_run_until(BR_SSL_RECVAPP) == 0) { @@ -223,23 +213,44 @@ void SSLClientImpl::stop() { } uint8_t SSLClientImpl::connected() { + const char* func_name = __func__; // check all of the error cases const auto c_con = m_client->connected(); const auto br_con = br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED; const auto wr_ok = getWriteError() == 0; // if we're in an error state, close the connection and set a write error - if ((br_con && !c_con) || !wr_ok) { - m_print("Error: Socket was unexpectedly interrupted"); - m_print("Terminated with: "); - m_print(m_client->getWriteError()); + if (br_con && !c_con) { + m_error("Socket was unexpectedly interrupted. m_client error: ", func_name); + m_error(m_client->getWriteError(), func_name); setWriteError(SSL_CLIENT_WRTIE_ERROR); stop(); } + else if (!wr_ok) { + m_error("Not connected because write error is set", func_name); + } return c_con && br_con && wr_ok; } +bool SSLClientImpl::m_soft_connected(const char* func_name) { + // check if the socket is still open and such + if (getWriteError()) { + m_error("Cannot operate if the write error is not reset: ", func_name); + m_print_ssl_error(getWriteError(), SSL_ERROR); + return false; + } + // check if the ssl engine is still open + if(br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED) { + m_error("Cannot operate on a closed SSL connection.", func_name); + int error = br_ssl_engine_last_error(&m_sslctx.eng); + if(error != BR_ERR_OK) m_print_br_error(error, SSL_ERROR); + return false; + } + return true; +} + /** see SSLClientImpl.h */ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { + const char* func_name = __func__; // clear the write error setWriteError(SSL_OK); // get some random data by reading the analog pin we've been handed @@ -251,21 +262,22 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { // inject session parameters for faster reconnection, if we have any if(ssl_ses.is_valid_session()) { br_ssl_engine_set_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); - m_print("Set session!"); + m_info("Set SSL session!", func_name); } // reset the engine, but make sure that it reset successfully int ret = br_ssl_client_reset(&m_sslctx, host, 1); if (!ret) { - m_print("Error: reset failed"); - m_print(br_ssl_engine_last_error(&m_sslctx.eng)); + m_error("Reset of bearSSL failed (is bearssl setup properly?)", func_name); + m_print_br_error(br_ssl_engine_last_error(&m_sslctx.eng), SSL_ERROR); + setWriteError(SSL_BR_CONNECT_FAIL); + return 0; } // initlalize the SSL socket over the network // normally this would happen in write, but I think it makes // a little more structural sense to put it here if (m_run_until(BR_SSL_SENDAPP) < 0) { - m_print("Error: Failed to initlalize the SSL layer"); - m_print(br_ssl_engine_last_error(&m_sslctx.eng)); - setWriteError(SSL_BR_CONNECT_FAIL); + m_error("Failed to initlalize the SSL layer", func_name); + m_print_br_error(br_ssl_engine_last_error(&m_sslctx.eng), SSL_ERROR); return 0; } // all good to go! the SSL socket should be up and running @@ -273,40 +285,33 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { br_ssl_engine_get_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); // set the hostname and ip in the session as well ssl_ses.set_parameters(remoteIP(), host); - // print the session details - m_print("Session:"); - for (uint8_t i = 0; i < ssl_ses.session_id_len; i++) { - Serial.print(", 0x"); - Serial.print(ssl_ses.session_id[i], HEX); - } - Serial.println(); - Serial.println(ssl_ses.cipher_suite, HEX); return 1; } /** see SSLClientImpl.h*/ int SSLClientImpl::m_run_until(const unsigned target) { + const char* func_name = __func__; unsigned lastState = 0; size_t lastLen = 0; for (;;) { unsigned state = m_update_engine(); // error check if (state == BR_SSL_CLOSED || getWriteError()) { - m_print("Error: tried to run_until when the engine is closed"); + m_warn("Tried to run_until when the engine is closed", func_name); return -1; } // debug if (state != lastState) { lastState = state; - m_print("m_run stuck:"); + m_info("m_run waiting:", func_name); printState(state); } if (state & BR_SSL_RECVREC) { size_t len; br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); if (lastLen != len) { - m_print("Expected bytes count: "); - m_print(lastLen = len); + m_info("Expected bytes count: ", func_name); + m_info(lastLen = len, func_name); } } /* @@ -328,13 +333,14 @@ int SSLClientImpl::m_run_until(const unsigned target) { size_t len; if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != NULL) { m_write_idx = 0; - m_print("Warn: discarded unread data to favor a write operation"); + m_warn("Discarded unread data to favor a write operation", func_name); br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); continue; } else { - m_print("Error: ssl engine state is RECVAPP, however the buffer was null!"); + m_error("SSL engine state is RECVAPP, however the buffer was null! (This is a problem with BearSSL internals)", func_name); setWriteError(SSL_BR_WRITE_ERROR); + stop(); return -1; } } @@ -352,6 +358,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { /** see SSLClientImpl.h*/ unsigned SSLClientImpl::m_update_engine() { + const char* func_name = __func__; for(;;) { // get the state unsigned state = br_ssl_engine_current_state(&m_sslctx.eng); @@ -369,7 +376,9 @@ unsigned SSLClientImpl::m_update_engine() { wlen = m_client->write(buf, len); // let the chip recover if (wlen < 0) { - m_print("Error writing to m_client"); + m_error("Error writing to m_client", func_name); + m_error(m_client->getWriteError(), func_name); + setWriteError(SSL_CLIENT_WRTIE_ERROR); /* * If we received a close_notify and we * still send something, then we have our @@ -377,10 +386,8 @@ unsigned SSLClientImpl::m_update_engine() { * the peer is allowed by RFC 5246 not to * wait for it. */ - if (!&m_sslctx.eng.shutdown_recv) { - return 0; - } - setWriteError(SSL_BR_WRITE_ERROR); + if (!&m_sslctx.eng.shutdown_recv) return 0; + stop(); return 0; } if (wlen > 0) { @@ -397,8 +404,9 @@ unsigned SSLClientImpl::m_update_engine() { // if we've reached the point where BR_SSL_SENDAPP is off but // data has been written to the io buffer, something is wrong if (!(state & BR_SSL_SENDAPP)) { - m_print("Error m_write_idx > 0 but the ssl engine is not ready for data"); + m_error("Error m_write_idx > 0 but the ssl engine is not ready for data", func_name); setWriteError(SSL_BR_WRITE_ERROR); + stop(); return 0; } // else time to send the application data @@ -407,14 +415,16 @@ unsigned SSLClientImpl::m_update_engine() { unsigned char *buf = br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); // engine check if (alen == 0 || buf == NULL) { - m_print("Error: engine set write flag but returned null buffer"); + m_error("Engine set write flag but returned null buffer", func_name); setWriteError(SSL_BR_WRITE_ERROR); + stop(); return 0; } // sanity check if (alen < m_write_idx) { - m_print("Error: alen is less than m_write_idx"); + m_error("Alen is less than m_write_idx", func_name); setWriteError(SSL_INTERNAL_ERROR); + stop(); return 0; } // all good? lets send the data @@ -442,15 +452,17 @@ unsigned SSLClientImpl::m_update_engine() { // do we have the record you're looking for? const auto avail = m_client->available(); if (avail >= len) { - m_print("Read bytes from client: "); - m_print(avail); - m_print(len); + m_info("Read bytes from client: ", func_name); + m_info(avail, func_name); + m_info(len, func_name); // I suppose so! int rlen = m_client->read(buf, len); if (rlen <= 0) { - m_print("Error reading bytes from m_client"); - setWriteError(SSL_BR_WRITE_ERROR); + m_error("Error reading bytes from m_client. Write Error: ", func_name); + m_error(m_client->getWriteError(), func_name); + setWriteError(SSL_CLIENT_WRTIE_ERROR); + stop(); return 0; } if (rlen > 0) { @@ -473,4 +485,104 @@ unsigned SSLClientImpl::m_update_engine() { // in which case we return return state; } +} + + +/** See SSLClientImpl.h */ +void SSLClientImpl::m_print_prefix(const char* func_name, const DebugLevel level) const +{ + // print the sslclient prefix + Serial.print("(SSLClient)"); + // print the debug level + switch (level) { + case SSL_INFO: Serial.print("SSL_INFO"); break; + case SSL_WARN: Serial.print("SSL_WARN"); break; + case SSL_ERROR: Serial.print("SSL_ERROR"); break; + default: Serial.print("Unknown level"); + } + // print the function name + Serial.print(func_name); + // get ready + Serial.print(": "); +} + +/** See SSLClientImpl.h */ +void SSLClientImpl::m_print_ssl_error(const int ssl_error, const DebugLevel level) const { + if (level < m_debug) return; + m_print_prefix(__func__, level); + switch(ssl_error) { + case SSL_OK: Serial.println("SSL_OK"); break; + case SSL_CLIENT_CONNECT_FAIL: Serial.println("SSL_CLIENT_CONNECT_FAIL"); break; + case SSL_BR_CONNECT_FAIL: Serial.println("SSL_BR_CONNECT_FAIL"); break; + case SSL_CLIENT_WRTIE_ERROR: Serial.println("SSL_CLIENT_WRITE_FAIL"); break; + case SSL_BR_WRITE_ERROR: Serial.println("SSL_BR_WRITE_ERROR"); break; + case SSL_INTERNAL_ERROR: Serial.println("SSL_INTERNAL_ERROR"); break; + } +} + +/* See SSLClientImpl.h */ +void SSLClientImpl::m_print_br_error(const unsigned br_error_code, const DebugLevel level) const { + if (level < m_debug) return; + m_print_prefix(__func__, level); + switch (br_error_code) { + case BR_ERR_BAD_PARAM: Serial.println("Caller-provided parameter is incorrect."); break; + case BR_ERR_BAD_STATE: Serial.println("Operation requested by the caller cannot be applied with the current context state (e.g. reading data while outgoing data is waiting to be sent)."); break; + case BR_ERR_UNSUPPORTED_VERSION: Serial.println("Incoming protocol or record version is unsupported."); break; + case BR_ERR_BAD_VERSION: Serial.println("Incoming record version does not match the expected version."); break; + case BR_ERR_BAD_LENGTH: Serial.println("Incoming record length is invalid."); break; + case BR_ERR_TOO_LARGE: Serial.println("Incoming record is too large to be processed, or buffer is too small for the handshake message to send."); break; + case BR_ERR_BAD_MAC: Serial.println("Decryption found an invalid padding, or the record MAC is not correct."); break; + case BR_ERR_NO_RANDOM: Serial.println("No initial entropy was provided, and none can be obtained from the OS."); break; + case BR_ERR_UNKNOWN_TYPE: Serial.println("Incoming record type is unknown."); break; + case BR_ERR_UNEXPECTED: Serial.println("Incoming record or message has wrong type with regards to the current engine state."); break; + case BR_ERR_BAD_CCS: Serial.println("ChangeCipherSpec message from the peer has invalid contents."); break; + case BR_ERR_BAD_ALERT: Serial.println("Alert message from the peer has invalid contents (odd length)."); break; + case BR_ERR_BAD_HANDSHAKE: Serial.println("Incoming handshake message decoding failed."); break; + case BR_ERR_OVERSIZED_ID: Serial.println("ServerHello contains a session ID which is larger than 32 bytes."); break; + case BR_ERR_BAD_CIPHER_SUITE: Serial.println("Server wants to use a cipher suite that we did not claim to support. This is also reported if we tried to advertise a cipher suite that we do not support."); break; + case BR_ERR_BAD_COMPRESSION: Serial.println("Server wants to use a compression that we did not claim to support."); break; + case BR_ERR_BAD_FRAGLEN: Serial.println("Server's max fragment length does not match client's."); break; + case BR_ERR_BAD_SECRENEG: Serial.println("Secure renegotiation failed."); break; + case BR_ERR_EXTRA_EXTENSION: Serial.println("Server sent an extension type that we did not announce, or used the same extension type several times in a single ServerHello."); break; + case BR_ERR_BAD_SNI: Serial.println("Invalid Server Name Indication contents (when used by the server, this extension shall be empty)."); break; + case BR_ERR_BAD_HELLO_DONE: Serial.println("Invalid ServerHelloDone from the server (length is not 0)."); break; + case BR_ERR_LIMIT_EXCEEDED: Serial.println("Internal limit exceeded (e.g. server's public key is too large)."); break; + case BR_ERR_BAD_FINISHED: Serial.println("Finished message from peer does not match the expected value."); break; + case BR_ERR_RESUME_MISMATCH: Serial.println("Session resumption attempt with distinct version or cipher suite."); break; + case BR_ERR_INVALID_ALGORITHM: Serial.println("Unsupported or invalid algorithm (ECDHE curve, signature algorithm, hash function)."); break; + case BR_ERR_BAD_SIGNATURE: Serial.println("Invalid signature in ServerKeyExchange or CertificateVerify message."); break; + case BR_ERR_WRONG_KEY_USAGE: Serial.println("Peer's public key does not have the proper type or is not allowed for the requested operation."); break; + case BR_ERR_NO_CLIENT_AUTH: Serial.println("Client did not send a certificate upon request, or the client certificate could not be validated."); break; + case BR_ERR_IO: Serial.println("I/O error or premature close on transport stream."); break; + case BR_ERR_X509_INVALID_VALUE: Serial.println("Invalid value in an ASN.1 structure."); break; + case BR_ERR_X509_TRUNCATED: Serial.println("Truncated certificate or other ASN.1 object."); break; + case BR_ERR_X509_EMPTY_CHAIN: Serial.println("Empty certificate chain (no certificate at all)."); break; + case BR_ERR_X509_INNER_TRUNC: Serial.println("Decoding error: inner element extends beyond outer element size."); break; + case BR_ERR_X509_BAD_TAG_CLASS: Serial.println("Decoding error: unsupported tag class (application or private)."); break; + case BR_ERR_X509_BAD_TAG_VALUE: Serial.println("Decoding error: unsupported tag value."); break; + case BR_ERR_X509_INDEFINITE_LENGTH: Serial.println("Decoding error: indefinite length."); break; + case BR_ERR_X509_EXTRA_ELEMENT: Serial.println("Decoding error: extraneous element."); break; + case BR_ERR_X509_UNEXPECTED: Serial.println("Decoding error: unexpected element."); break; + case BR_ERR_X509_NOT_CONSTRUCTED: Serial.println("Decoding error: expected constructed element, but is primitive."); break; + case BR_ERR_X509_NOT_PRIMITIVE: Serial.println("Decoding error: expected primitive element, but is constructed."); break; + case BR_ERR_X509_PARTIAL_BYTE: Serial.println("Decoding error: BIT STRING length is not multiple of 8."); break; + case BR_ERR_X509_BAD_BOOLEAN: Serial.println("Decoding error: BOOLEAN value has invalid length."); break; + case BR_ERR_X509_OVERFLOW: Serial.println("Decoding error: value is off-limits."); break; + case BR_ERR_X509_BAD_DN: Serial.println("Invalid distinguished name."); break; + case BR_ERR_X509_BAD_TIME: Serial.println("Invalid date/time representation."); break; + case BR_ERR_X509_UNSUPPORTED: Serial.println("Certificate contains unsupported features that cannot be ignored."); break; + case BR_ERR_X509_LIMIT_EXCEEDED: Serial.println("Key or signature size exceeds internal limits."); break; + case BR_ERR_X509_WRONG_KEY_TYPE: Serial.println("Key type does not match that which was expected."); break; + case BR_ERR_X509_BAD_SIGNATURE: Serial.println("Signature is invalid."); break; + case BR_ERR_X509_TIME_UNKNOWN: Serial.println("Validation time is unknown."); break; + case BR_ERR_X509_EXPIRED: Serial.println("Certificate is expired or not yet valid."); break; + case BR_ERR_X509_DN_MISMATCH: Serial.println("Issuer/Subject DN mismatch in the chain."); break; + case BR_ERR_X509_BAD_SERVER_NAME: Serial.println("Expected server name was not found in the chain."); break; + case BR_ERR_X509_CRITICAL_EXTENSION: Serial.println("Unknown critical extension in certificate."); break; + case BR_ERR_X509_NOT_CA: Serial.println("Not a CA, or path length constraint violation."); break; + case BR_ERR_X509_FORBIDDEN_KEY_USAGE: Serial.println("Key Usage extension prohibits intended usage."); break; + case BR_ERR_X509_WEAK_PUBLIC_KEY: Serial.println("Public key found in certificate is too small."); break; + case BR_ERR_X509_NOT_TRUSTED: Serial.println("Chain could not be linked to a trust anchor."); break; + default: Serial.println("Unknown error code."); break; + } } \ No newline at end of file diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index a8e7345..e91bc68 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -26,6 +26,30 @@ #ifndef SSLClientImpl_H_ #define SSLClientImpl_H_ +/** error enums + * Static constants defining the possible errors encountered + * Read from getWriteError(); + */ +enum Error { + SSL_OK = 0, + SSL_CLIENT_CONNECT_FAIL, + SSL_BR_CONNECT_FAIL, + SSL_CLIENT_WRTIE_ERROR, + SSL_BR_WRITE_ERROR, + SSL_INTERNAL_ERROR +}; + +/** Debug level enum + * Static enum defining the debugging levels to print + * into the Serial monitor + */ +enum DebugLevel { + SSL_NONE = 0, + SSL_INFO = 1, + SSL_WARN = 2, + SSL_ERROR = 3 +}; + /** TODO: Write what this is */ class SSLClientImpl : public Client { @@ -51,7 +75,7 @@ public: * @param debug whether to enable or disable debug logging, must be constexpr */ explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, const bool debug = true); + const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); /** Dtor is implicit since unique_ptr handles it fine */ /** functions specific to the EthernetClient which I'll have to override */ @@ -133,30 +157,52 @@ protected: */ void set_client(Client* c) { m_client = c; } + /** @brief Prints a debugging prefix to all logs, so we can attatch them to useful information */ + void m_print_prefix(const char* func_name, const DebugLevel level) const; + + /** @brief Prints the string associated with a write error */ + void m_print_ssl_error(const int ssl_error, const DebugLevel level) const; + + /** @brief Print the text string associated with a BearSSL error code */ + void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const; + /** @brief debugging print function, only prints if m_debug is true */ template - constexpr void m_print(const T str) const { - if (m_debug) { - Serial.print("SSLClientImpl: "); - Serial.println(str); - } + void m_print(const T str, const char* func_name, const DebugLevel level) const { + // check the current debug level + if (level < m_debug) return; + // print prefix + m_print_prefix(func_name, level); + // print the message + Serial.println(str); } -private: + /** @brief Prints a info message to serial, if info messages are enabled */ + template + void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); } + template + void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); } + + template + void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); } + +private: void printState(unsigned state) const { - if(m_debug) { - m_print("State: "); - if(state == 0) m_print(" Invalid"); - else if (state & BR_SSL_CLOSED) m_print(" Connection closed"); + if(m_debug == DebugLevel::SSL_INFO) { + m_info("State: ", __func__); + if(state == 0) Serial.println(" Invalid"); + else if (state & BR_SSL_CLOSED) Serial.println(" Connection closed"); else { - if (state & BR_SSL_SENDREC) m_print(" SENDREC"); - if (state & BR_SSL_RECVREC) m_print(" RECVREC"); - if (state & BR_SSL_SENDAPP) m_print(" SENDAPP"); - if (state & BR_SSL_RECVAPP) m_print(" RECVAPP"); + if (state & BR_SSL_SENDREC) Serial.println(" SENDREC"); + if (state & BR_SSL_RECVREC) Serial.println(" RECVREC"); + if (state & BR_SSL_SENDAPP) Serial.println(" SENDAPP"); + if (state & BR_SSL_RECVAPP) Serial.println(" RECVAPP"); } } } + /** Returns whether or not the engine is connected, without polling the client over SPI or other (as opposed to connected()) */ + bool m_soft_connected(const char* func_name); /** start the ssl engine on the connected client */ int m_start_ssl(const char* host, SSLSession& ssl_ses); /** run the bearssl engine until a certain state */ @@ -172,7 +218,7 @@ private: // store the pin to fetch an RNG see from const int m_analog_pin; // store whether to enable debug logging - const bool m_debug; + const DebugLevel m_debug; // store the context values required for SSL br_ssl_client_context m_sslctx; br_x509_minimal_context m_x509ctx; From 7f72073fa6b66b70f98e49c1bd9af1bbaca62758 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 12 Mar 2019 16:59:45 -0700 Subject: [PATCH 022/205] debugged stack overflow error, fixed connection timeout and some error flow problems --- src/SSLClient.h | 92 ++++++++++++++++++--------- src/SSLClientImpl.cpp | 56 +++++++++++----- src/SSLClientImpl.h | 30 +++++++-- src/TLS12_only_profile.c | 1 + src/bearssl/src/ssl/ssl_client_full.c | 1 + 5 files changed, 129 insertions(+), 51 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index b47758a..83d8446 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -67,6 +67,7 @@ class SSLClient : public SSLClientImpl { */ static_assert(std::is_base_of::value, "C must be a Client Class!"); static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!"); +static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur."); // static_assert(std::is_function::value, "C must have a status() function!"); public: @@ -90,12 +91,16 @@ public: explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_ERROR) : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) - , m_sessions{} + , m_sessions{SSLSession()} , m_index(0) { + // for (uint8_t i = 0; i < SessionCache; i++) m_sessions[i] = SSLSession(); // since we are copying the client in the ctor, we have to set // the client pointer after the class is constructed set_client(&m_client); + // set the timeout to a reasonable number (it can always be changes later) + // SSL Connections take a really long time so we don't want to time out a legitimate thing + setTimeout(10 * 1000); } /* @@ -114,38 +119,13 @@ public: //! get the client object C& getClient() { return m_client; } - virtual SSLSession& getSession(const char* host, const IPAddress& addr) { - // search for a matching session with the IP - int temp_index = -1; - for (size_t i = 0; i < SessionCache; i++) { - // if we're looking at a real session - if (m_sessions[i].is_valid_session() - && ( - // and the hostname matches, or - (host != NULL && strcmp(host, m_sessions[i].get_hostname()) == 0) - // there is no hostname and the IP address matches - || (host == NULL && addr == m_sessions[i].get_ip()) - )) { + virtual SSLSession& getSession(const char* host, const IPAddress& addr); - temp_index = i; - break; - } - } - // if none are availible, use m_index - if (temp_index == -1) { - temp_index = m_index; - // reset the session so we don't try to send one sites session to another - m_sessions[temp_index] = SSLSession(); - } - // increment m_index so the session cache is a circular buffer - if (temp_index == m_index && ++m_index >= SessionCache) m_index = 0; - // return the pointed to value - m_info("Using session index: ", __func__); - Serial.println(temp_index); - return m_sessions[temp_index]; - } + virtual void removeSession(const char* host, const IPAddress& addr); private: + // utility function to find a session index based off of a host and IP + int m_getSessionIndex(const char* host, const IPAddress& addr) const; // create a copy of the client C m_client; // also store an array of SSLSessions, so we can resume communication with multiple websites @@ -154,4 +134,56 @@ private: size_t m_index; }; +template +SSLSession& SSLClient::getSession(const char* host, const IPAddress& addr) { + const char* func_name = __func__; + // search for a matching session with the IP + int temp_index = m_getSessionIndex(host, addr); + // if none are availible, use m_index + if (temp_index == -1) { + temp_index = m_index; + // reset the session so we don't try to send one sites session to another + m_sessions[temp_index] = SSLSession(); + } + // increment m_index so the session cache is a circular buffer + if (temp_index == m_index && ++m_index >= SessionCache) m_index = 0; + // return the pointed to value + m_info("Using session index: ", func_name); + Serial.println(temp_index); + return m_sessions[temp_index]; +} + +template +void SSLClient::removeSession(const char* host, const IPAddress& addr) { + const char* func_name = __func__; + int temp_index = m_getSessionIndex(host, addr); + if (temp_index != -1) { + m_info(" Deleted session ", func_name); + m_info(temp_index, func_name); + m_sessions[temp_index] = SSLSession(); + } +} + +template +int SSLClient::m_getSessionIndex(const char* host, const IPAddress& addr) const { + const char* func_name = __func__; + // search for a matching session with the IP + for (uint8_t i = 0; i < SessionCache; i++) { + // if we're looking at a real session + if (m_sessions[i].is_valid_session() + && ( + // and the hostname matches, or + (host != NULL && strcmp(host, m_sessions[i].get_hostname()) == 0) + // there is no hostname and the IP address matches + || (host == NULL && addr == m_sessions[i].get_ip()) + )) { + m_info("Found session match: ", func_name); + m_info(m_sessions[i].get_hostname(), func_name); + return i; + } + } + // none found + return -1; +} + #endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index d4e85fd..997fcb9 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -45,7 +45,7 @@ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_a int SSLClientImpl::connect(IPAddress ip, uint16_t port) { const char* func_name = __func__; // connection check - if (connected()) { + if (m_client->connected()) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } @@ -68,7 +68,7 @@ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { int SSLClientImpl::connect(const char *host, uint16_t port) { const char* func_name = __func__; // connection check - if (connected()) { + if (m_client->connected()) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } @@ -148,7 +148,7 @@ int SSLClientImpl::available() { br_ssl_engine_recvapp_buf(&m_sslctx.eng, &alen); return (int)(alen); } - else if (state == BR_SSL_CLOSED) m_warn("Engine closed after update", func_name); + else if (state == BR_SSL_CLOSED) m_info("Engine closed after update", func_name); // flush the buffer if it's stuck in the SENDAPP state else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); // other state, or client is closed @@ -194,8 +194,6 @@ void SSLClientImpl::flush() { void SSLClientImpl::stop() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); - // info about the socket connection - if (br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED) m_info("Socket was terminated before graceful closure (probably fine)", __func__); // if the engine isn't closed, and the socket is still open while (br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED && m_run_until(BR_SSL_RECVAPP) == 0) { @@ -220,8 +218,14 @@ uint8_t SSLClientImpl::connected() { const auto wr_ok = getWriteError() == 0; // if we're in an error state, close the connection and set a write error if (br_con && !c_con) { - m_error("Socket was unexpectedly interrupted. m_client error: ", func_name); - m_error(m_client->getWriteError(), func_name); + // If we've got a write error, the client probably failed for some reason + if (m_client->getWriteError()) { + m_error("Socket was unexpectedly interrupted. m_client error: ", func_name); + m_error(m_client->getWriteError(), func_name); + } + // Else tell the user the endpoint closed the socket on us (ouch) + else m_warn("Socket was dropped unexpectedly (this can be an alternative to closing the connection)", func_name); + // set the write error so the engine doesn't try to close the connection setWriteError(SSL_CLIENT_WRTIE_ERROR); stop(); } @@ -280,11 +284,18 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { m_print_br_error(br_ssl_engine_last_error(&m_sslctx.eng), SSL_ERROR); return 0; } + m_info("Connection successful!", func_name); // all good to go! the SSL socket should be up and running // overwrite the session we got with new parameters br_ssl_engine_get_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); // set the hostname and ip in the session as well ssl_ses.set_parameters(remoteIP(), host); + // print the handshake cipher chioce + m_info("Cipher suite: ", func_name); + if (m_debug >= SSL_INFO) { + m_print_prefix(func_name, SSL_INFO); + Serial.println(ssl_ses.cipher_suite, HEX); + } return 1; } @@ -293,6 +304,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { const char* func_name = __func__; unsigned lastState = 0; size_t lastLen = 0; + const unsigned long start = millis(); for (;;) { unsigned state = m_update_engine(); // error check @@ -300,11 +312,20 @@ int SSLClientImpl::m_run_until(const unsigned target) { m_warn("Tried to run_until when the engine is closed", func_name); return -1; } + // timeout check + if (millis() - start > getTimeout()) { + m_error("SSL internals timed out! This could be an internal error or bad data sent from the server", func_name); + setWriteError(SSL_BR_WRITE_ERROR); + stop(); + return -1; + } // debug if (state != lastState) { lastState = state; - m_info("m_run waiting:", func_name); + m_info("m_run changed state:", func_name); printState(state); + m_info("Memory: ", func_name); + m_info(freeMemory(), func_name); } if (state & BR_SSL_RECVREC) { size_t len; @@ -455,7 +476,8 @@ unsigned SSLClientImpl::m_update_engine() { m_info("Read bytes from client: ", func_name); m_info(avail, func_name); m_info(len, func_name); - + m_info("Memory: ", func_name); + m_info(freeMemory(), func_name); // I suppose so! int rlen = m_client->read(buf, len); if (rlen <= 0) { @@ -495,20 +517,20 @@ void SSLClientImpl::m_print_prefix(const char* func_name, const DebugLevel level Serial.print("(SSLClient)"); // print the debug level switch (level) { - case SSL_INFO: Serial.print("SSL_INFO"); break; - case SSL_WARN: Serial.print("SSL_WARN"); break; - case SSL_ERROR: Serial.print("SSL_ERROR"); break; - default: Serial.print("Unknown level"); + case SSL_INFO: Serial.print("(SSL_INFO)"); break; + case SSL_WARN: Serial.print("(SSL_WARN)"); break; + case SSL_ERROR: Serial.print("(SSL_ERROR)"); break; + default: Serial.print("(Unknown level)"); } // print the function name + Serial.print("("); Serial.print(func_name); - // get ready - Serial.print(": "); + Serial.print("): "); } /** See SSLClientImpl.h */ void SSLClientImpl::m_print_ssl_error(const int ssl_error, const DebugLevel level) const { - if (level < m_debug) return; + if (level > m_debug) return; m_print_prefix(__func__, level); switch(ssl_error) { case SSL_OK: Serial.println("SSL_OK"); break; @@ -522,7 +544,7 @@ void SSLClientImpl::m_print_ssl_error(const int ssl_error, const DebugLevel leve /* See SSLClientImpl.h */ void SSLClientImpl::m_print_br_error(const unsigned br_error_code, const DebugLevel level) const { - if (level < m_debug) return; + if (level > m_debug) return; m_print_prefix(__func__, level); switch (br_error_code) { case BR_ERR_BAD_PARAM: Serial.println("Caller-provided parameter is incorrect."); break; diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index e91bc68..7ea6774 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -45,11 +45,31 @@ enum Error { */ enum DebugLevel { SSL_NONE = 0, - SSL_INFO = 1, + SSL_ERROR = 1, SSL_WARN = 2, - SSL_ERROR = 3 + SSL_INFO = 3, }; + +#ifdef __arm__ +// should use uinstd.h to define sbrk but Due causes a conflict +extern "C" char* sbrk(int incr); +#else // __ARM__ +extern char *__brkval; +#endif // __arm__ + +static int freeMemory() { + char top; +#ifdef __arm__ + return &top - reinterpret_cast(sbrk(0)); +#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) + return &top - __brkval; +#else // __arm__ + return __brkval ? &top - __brkval : &top - __malloc_heap_start; +#endif // __arm__ +} + + /** TODO: Write what this is */ class SSLClientImpl : public Client { @@ -170,7 +190,7 @@ protected: template void m_print(const T str, const char* func_name, const DebugLevel level) const { // check the current debug level - if (level < m_debug) return; + if (level > m_debug) return; // print prefix m_print_prefix(func_name, level); // print the message @@ -226,7 +246,9 @@ private: // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically // simply edit this value to change the buffer size to the desired value - unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO]; + // additionally, we need to correct buffer size based off of how many sessions we decide to cache + // since SSL takes so much memory if we don't it will cause the stack and heap to collide + unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 4]; static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); // store the index of where we are writing in the buffer // so we can send our records all at once to prevent diff --git a/src/TLS12_only_profile.c b/src/TLS12_only_profile.c index e0b8295..bfe242a 100644 --- a/src/TLS12_only_profile.c +++ b/src/TLS12_only_profile.c @@ -418,6 +418,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * supported hash function is appropriate; here we use SHA-256. * The trust an */ + memset(xc, 0, sizeof *xc); br_x509_minimal_init(xc, &br_sha256_vtable, trust_anchors, trust_anchors_num); diff --git a/src/bearssl/src/ssl/ssl_client_full.c b/src/bearssl/src/ssl/ssl_client_full.c index fd35b3c..bc34e92 100644 --- a/src/bearssl/src/ssl/ssl_client_full.c +++ b/src/bearssl/src/ssl/ssl_client_full.c @@ -119,6 +119,7 @@ br_ssl_client_init_full(br_ssl_client_context *cc, * to TLS-1.2 (inclusive). */ br_ssl_client_zero(cc); + memset(xc, 0, sizeof *xc); br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); /* From b430e403fe1279bde8539d91dade87fbcbfec20d Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 12 Mar 2019 23:56:02 -0700 Subject: [PATCH 023/205] Updated README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cc0f487..17820d3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # SSLClient Arduino library to add SSL functionality to any Client class +Currently work in progress (documentation on the way!) From 24eaebf341c8e8c48d7106956b28e9ab33a9b790 Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 12 Mar 2019 23:56:29 -0700 Subject: [PATCH 024/205] Fixed punctuation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 17820d3..d20ce29 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # SSLClient -Arduino library to add SSL functionality to any Client class -Currently work in progress (documentation on the way!) +Arduino library to add SSL functionality to any Client class. +Currently work in progress (documentation on the way!). From ef4a55cbe80411545e6fa502dd33164ef401b104 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 13 Mar 2019 13:24:55 -0700 Subject: [PATCH 025/205] Switched hostname storage from stack to heap since hostnames are much smaller than max 256 bytes, need to add free memory error detection before stack overflows (8000 bytes?) Signed-off-by: Noah Laptop --- src/SSLClient.h | 6 +++--- src/SSLSession.h | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 83d8446..1ae0b9f 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -143,7 +143,7 @@ SSLSession& SSLClient::getSession(const char* host, const IPAdd if (temp_index == -1) { temp_index = m_index; // reset the session so we don't try to send one sites session to another - m_sessions[temp_index] = SSLSession(); + m_sessions[temp_index].clear_parameters(); } // increment m_index so the session cache is a circular buffer if (temp_index == m_index && ++m_index >= SessionCache) m_index = 0; @@ -160,7 +160,7 @@ void SSLClient::removeSession(const char* host, const IPAddress if (temp_index != -1) { m_info(" Deleted session ", func_name); m_info(temp_index, func_name); - m_sessions[temp_index] = SSLSession(); + m_sessions[temp_index].clear_parameters(); } } @@ -173,7 +173,7 @@ int SSLClient::m_getSessionIndex(const char* host, const IPAddr if (m_sessions[i].is_valid_session() && ( // and the hostname matches, or - (host != NULL && strcmp(host, m_sessions[i].get_hostname()) == 0) + (host != NULL && m_sessions[i].get_hostname().equals(host)) // there is no hostname and the IP address matches || (host == NULL && addr == m_sessions[i].get_ip()) )) { diff --git a/src/SSLSession.h b/src/SSLSession.h index 042091f..b881084 100644 --- a/src/SSLSession.h +++ b/src/SSLSession.h @@ -52,7 +52,7 @@ class SSLSession : public br_ssl_session_parameters { public: explicit SSLSession() : m_valid_session(false) - , m_hostname{} + , m_hostname() , m_ip(INADDR_NONE) {} /** @@ -60,22 +60,31 @@ public: */ void set_parameters(const IPAddress& ip, const char* hostname = NULL) { // copy the hostname - if (hostname != NULL) strncpy(m_hostname, hostname, sizeof m_hostname - 1); + if (hostname != NULL) m_hostname = hostname; // or if there's no hostname, clear the string - else m_hostname[0] = '\0'; + else m_hostname = ""; // and the IP address m_ip = ip; // check if both values are valid, and if so set valid to true if (m_ip != INADDR_NONE && session_id_len > 0 - && (hostname == NULL || strlen(m_hostname) > 0)) m_valid_session = true; + && (hostname == NULL || m_hostname)) m_valid_session = true; } + void clear_parameters() { + // clear the hostname , ip, and valid session flags + m_hostname = ""; + m_ip = INADDR_NONE; + m_valid_session = false; + } + + SSLSession& operator=(const SSLSession&) = delete; + br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; } /** * \pre must check isValidSession */ - const char* get_hostname() const { return m_hostname; } + const String& get_hostname() const { return m_hostname; } /** * \pre must check isValidSession @@ -86,7 +95,7 @@ public: private: bool m_valid_session; // aparently a hostname has a max length of 256 chars. Go figure. - char m_hostname[256]; + String m_hostname; // store the IP Address we connected to IPAddress m_ip; }; From ac951f1b30e18a33888ec14f3fb1693048984a1c Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 13 Mar 2019 16:13:20 -0700 Subject: [PATCH 026/205] Wrote small python utility based off of pycert to autogenerate bearSSL trust anchor header files, need to finish commenting it and created web hosted version --- tools/pycert_bearssl/cert_util.py | 286 +++++++++++++++++++++++++ tools/pycert_bearssl/pycert_bearssl.py | 125 +++++++++++ 2 files changed, 411 insertions(+) create mode 100644 tools/pycert_bearssl/cert_util.py create mode 100644 tools/pycert_bearssl/pycert_bearssl.py diff --git a/tools/pycert_bearssl/cert_util.py b/tools/pycert_bearssl/cert_util.py new file mode 100644 index 0000000..4fa4cd8 --- /dev/null +++ b/tools/pycert_bearssl/cert_util.py @@ -0,0 +1,286 @@ +# Utility functions for a Python SSL certificate conversion tool. +# These functions are in this file so the can also be used in +# A web API implementing this tool. +# Author: Tony DiCola, Modified by Noah Koontz +# +# Dependencies: +# click - Install with 'sudo pip install click' (omit sudo on windows) +# PyOpenSSL - See homepage: https://pyopenssl.readthedocs.org/en/latest/ +# Should just be a 'sudo pip install pyopenssl' command, HOWEVER +# on Windows you probably need a precompiled binary version. Try +# installing with pip and if you see errors when running that +# OpenSSL can't be found then try installing egenix's prebuilt +# PyOpenSSL library and OpenSSL lib: +# http://www.egenix.com/products/python/pyOpenSSL/ +# certifi - Install with 'sudo pip install certifi' (omit sudo on windows) + +import re +from OpenSSL import SSL, crypto +import socket +import textwrap +import math +import os + +CERT_PATTERN = re.compile("^\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-[a-z,A-Z,0-9,\n,\/,+]+={0,2}\n\-\-\-\-\-END CERTIFICATE-\-\-\-\-", re.MULTILINE) + +# Default name prefixes for varibles used in the hearder autogeneration +# Autogenerator will follow these names with a number +# e.g. "TA_DN0" +# Distinguished name array prefix +DN_PRE = "TA_DN" +# RSA public key number prefix +RSA_N_PRE = "TA_RSA_N" +# RSA public key exponent prefix +RSA_E_PRE = "TA_RSA_E" + + +# Template that defines the C header output format. +# This takes in a few named parameters: +# - guard_name: Unique name to apply to the #ifndef header guard. +# - cert_length_var: Variable/define name for the length of the certificate. +# - cert_length: Length of the certificate (in bytes). +# - cert_var: Variable name for the certificate data. +# - cert_data: Certificate data, formatted as a bearssl trust anchor array +# - cert_description: Any descriptive info about the certs to put in comments. +# NOTE: If you're changing the template make sure to escape all curly braces +# with a double brace (like {{ or }}) or else Python will try to interpret as a +# string format variable. +CFILE_TEMPLATE = """\ +#ifndef _{guard_name}_H_ +#define _{guard_name}_H_ + +#ifdef __cplusplus +extern "C" +{{ +#endif + +/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. + * Certificates are BearSSL br_x509_trust_anchor format. Included certs: + * +{cert_description} + */ + +#define {cert_length_var} {cert_length} + +{cert_data} + +#ifdef __cplusplus +}} /* extern "C" */ +#endif + +#endif /* ifndef _{guard_name}_H_ */ +""" + +# Template that defines a static array of bytes +# This takes in a few named parameters: +# - ray_type: The type (int, unsigned char) to use for the static array +# - ray_name: The varible name of the static array +# - ray_data: The comma seperated data of the array (ex. "0x12, 0x34, ...") +CRAY_TEMPLATE = """\ +static const {ray_type} {ray_name}[] = {{ +{ray_data} +}};""" + +# Template that defines a single root certificate entry in the BearSSL trust +# anchor list +# This takes in a few named parameters: +# - ta_dn_name: The name of the static byte array containing the distunguished +# name of the certificate. +# - rsa_number_name: Varible name of the static array containing the RSA number +# - rsa_exp_name: Varible name of the static array containing the RSA exponent +CROOTCA_TEMPLATE = """\ + {{ + {{ (unsigned char *){ta_dn_name}, sizeof {ta_dn_name} }}, + BR_X509_TA_CA, + {{ + BR_KEYTYPE_RSA, + {{ .rsa = {{ + (unsigned char *){rsa_number_name}, sizeof {rsa_number_name}, + (unsigned char *){rsa_exp_name}, sizeof {rsa_exp_name}, + }} }} + }} + }},""" + +# Template that defines a description of the certificate, so that the header +# file can be slightly more human readable +# This takes in a few named parameters: +# - cert_num: The index used to represent the certificate to the computer +# - cert_label: The certificate's name field (Usually CN, in the subject) +# - cert_issue: The certificate's issuer string +# - cert_subject: The certificate's subject string +CCERT_DESC_TEMPLATE = """\ + * Index: {cert_num} + * Label: {cert_label} + * Subject: {cert_subject}""" + +def PEM_split(cert_pem): + """Split a certificate / certificate chain in PEM format into multiple + PEM certificates. This is useful for extracting the last / root PEM cert + in a chain for example. Will return a list of strings with each string + being an individual PEM certificate (including its '-----BEGIN CERTIFICATE...' + delineaters). + """ + # Split cert based on begin certificate sections, then reconstruct as an + # array of individual cert strings. + return re.findall(CERT_PATTERN, cert_pem) + +def parse_root_certificate_store(store): + """Parses a list of trusted root certificates, which we + can match to the respective certificates sent from the websites. The where + parameter takes a loaded certificate file (certifi.where()), + and the function returns a list of crypto.x509 objects. + """ + # perform file operations + certStore = PEM_split(store.read()) + # convert the raw PEM files into x509 object + return [crypto.load_certificate(crypto.FILETYPE_PEM, pem) for pem in certStore] + +def get_server_root_cert(address, port, certDict): + """Attempt to retrieve the the root certificate in the full SSL cert chain + from the provided server address & port. The certDict parameter should + contain a dictionary of { certificate.get_subject().hash() md5 hash : certificate }, + which this function will use to match the certificate chain to a stored root + certificate. This function will return a single certificate as a PyOpenSSL X509 + object, or None if the chain couldn't be retrieved for some reason, or the + certDict did not contain a matching certificate. + """ + # Use PyOpenSSL to initiate an SSL connection and get the full cert chain. + # Sadly Python's built in SSL library can't do this so we must use this + # OpenSSL-based library. + cert = None + ctx = SSL.Context(SSL.TLSv1_2_METHOD) + # do the connection, and fetch the cert chain + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + ssl_soc = SSL.Connection(ctx, soc) + ssl_soc.connect((address, port)) + try: + ssl_soc.do_handshake() + cert = ssl_soc.get_peer_cert_chain()[-1] + finally: + ssl_soc.shutdown() + soc.close() + # match the certificate in the chain to the respective root certificate using the common name + if cert == None: + print("Failed to fetch certificate on domain: " + address) + return None + cn_hash = cert.get_issuer().hash() + # if there is a respective certificate, return it + # else print an error and return None + if cn_hash not in certDict: + print("Could not find matching root certificate for domain: " + address) + return None + return certDict[cn_hash] + +def filter_duplicate_x509(certs): + serial_numbers = set() + out_certs = list() + # filter duplicate certs + for cert in certs: + # Skip duplicate certs where required. + if cert.get_serial_number() in serial_numbers: + continue + out_certs.append(cert) + serial_numbers.add(cert.get_serial_number()) + return out_certs + +def bytes_to_c_data(mah_bytes, length=None): + """Converts a byte array to a CSV C array data format, with endlines! + e.g: 0x12, 0xA4, etc. + mah_bytes is the bytearray, and length is the number of bytes to + generate in the array, and indent is how much to indent the output + """ + ret = [] + # create an array of byte strings, including an endline every 10 or so bytes + for i, bytestr in enumerate(textwrap.wrap(mah_bytes.hex(), 2)): + ret.append("0x" + bytestr + ", ") + # pad with extra zeros + while length != None and len(ret) < length: + ret.append("0x00, ") + # join, wrap, and return + return textwrap.fill(''.join(ret), width=6*12 + 5, initial_indent=' ', subsequent_indent=' ', break_long_words=False) + +def decribe_cert_object(cert, cert_num): + # get the label from the subject feild on the certificate + label = "" + com = dict(cert.get_subject().get_components()) + if b'CN' in com: + label = com[b'CN'].decode("utf-8") + elif b'OU' in com: + label = com[b'OU'].decode("utf-8") + elif b'O' in com: + label = com[b'O'].decode("utf-8") + # return the formated string + crypto = cert.to_cryptography() + return CCERT_DESC_TEMPLATE.format( + cert_num=cert_num, + cert_label=label, + cert_subject=crypto.subject.rfc4514_string(), + ) + + +def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes): + """Combine a collection of PEM format certificates into a single C header with the + combined cert data in BearSSL format. x509Certs should be a list of pyOpenSSL x590 objects, + cert_var controls the name of the cert data variable in the output header, cert_length_var + controls the name of the cert data length variable/define, output is the output file + (which must be open for writing). Keep_dupes is a boolean to indicate if duplicate + certificates should be left intact (true) or removed (false). + """ + cert_description = '' + certs = x509Certs + if not keep_dupes: + certs = filter_duplicate_x509(x509Certs) + # Save cert data as a C style header. + # start by building each component + cert_data = "" + static_arrays = list() + CAs = list() + cert_desc = list() + for i, cert in enumerate(certs): + # add a description of the certificate to the array + cert_desc.append(decribe_cert_object(cert, i)) + # build static arrays containing all the keys of the certificate + # start with distinguished name + # get the distinguished name in bytes + dn_bytes_str = bytes_to_c_data(cert.get_subject().der()) + static_arrays.append(CRAY_TEMPLATE.format( + ray_type="unsigned char", + ray_name=DN_PRE + str(i), + ray_data=dn_bytes_str)) + # next, the RSA public numbers + pubkey = cert.get_pubkey() + numbers = pubkey.to_cryptography_key().public_numbers() + # starting with the modulous + n_bytes_str = bytes_to_c_data(numbers.n.to_bytes(pubkey.bits() // 8, byteorder="big")) + static_arrays.append(CRAY_TEMPLATE.format( + ray_type="unsigned char", + ray_name=RSA_N_PRE + str(i), + ray_data=n_bytes_str)) + # and then the exponent + e_bytes_str = bytes_to_c_data(numbers.e.to_bytes(math.ceil(numbers.e.bit_length() / 8), byteorder="big")) + static_arrays.append(CRAY_TEMPLATE.format( + ray_type="unsigned char", + ray_name=RSA_E_PRE + str(i), + ray_data=e_bytes_str)) + # format the root certificate entry + CAs.append(CROOTCA_TEMPLATE.format( + ta_dn_name=DN_PRE + str(i), + rsa_number_name=RSA_N_PRE + str(i), + rsa_exp_name=RSA_E_PRE + str(i))) + # concatonate it all into the big header file template + # cert descriptions + cert_desc_out = '\n * \n'.join(cert_desc) + # static arrays + cert_data_out = '\n\n'.join(static_arrays) + cert_data_out += '\n\n' + CRAY_TEMPLATE.format( + ray_type="br_x509_trust_anchor", + ray_name=cert_var, + ray_data='\n'.join(CAs)) + # create final header file + output_file.write(CFILE_TEMPLATE.format( + guard_name=os.path.splitext(output_file.name)[0].upper(), + cert_description=cert_desc_out, + cert_length_var=cert_length_var, + cert_length=str(len(certs)), + cert_data=cert_data_out, + )) \ No newline at end of file diff --git a/tools/pycert_bearssl/pycert_bearssl.py b/tools/pycert_bearssl/pycert_bearssl.py new file mode 100644 index 0000000..a92beaa --- /dev/null +++ b/tools/pycert_bearssl/pycert_bearssl.py @@ -0,0 +1,125 @@ +# Python SSL certificate conversion tool. +# Download and converts SSL certs from PEM format into a C header that can be +# referenced from a sketch to load the certificate data (in binary DER format). +# Modified by the OPEnS lab to output certificate data in a format supported by +# BearSSL. +# Author: Tony DiCola, Modified by Noah Koontz +# +# Dependencies: +# click - Install with 'sudo pip install click' (omit sudo on windows) +# PyOpenSSL - See homepage: https://pyopenssl.readthedocs.org/en/latest/ +# Should just be a 'sudo pip install pyopenssl' command, HOWEVER +# on Windows you probably need a precompiled binary version. Try +# installing with pip and if you see errors when running that +# OpenSSL can't be found then try installing egenix's prebuilt +# PyOpenSSL library and OpenSSL lib: +# http://www.egenix.com/products/python/pyOpenSSL/ +# +import cert_util +import click +import certifi + +# Default name for the cert length varible +CERT_LENGTH_NAME = "TAs_NUM" +# Defualt name for the cert array varible +CERT_ARRAY_NAME = "TAs" + +# Click setup and commands: +@click.group() +def pycert_bearssl(): + """OPEnS Python Certificate Tool + This is a tool to download and convert SSL certificates and certificate + chains into a C header format that can be imported into BearSSL + """ + pass + +@pycert_bearssl.command(short_help='Download SSL certs and save as a C header.') +@click.option('--port', '-p', type=click.INT, default=443, + help='port to use for reading certificate (default 443, SSL)') +@click.option('--cert-var', '-c', default=CERT_ARRAY_NAME, + help='name of the variable in the header which will contain certificate data (default: {0})'.format(CERT_ARRAY_NAME)) +@click.option('--cert-length-var', '-l', default=CERT_LENGTH_NAME, + help='name of the define in the header which will contain the length of the certificate data (default: {0})'.format(CERT_LENGTH_NAME)) +@click.option('--output', '-o', type=click.File('w'), default='certificates.h', + help='name of the output file (default: certificates.h)') +@click.option('--use-store', '-s', type=click.File('r'), default=certifi.where(), + help='the location of the .pem file containing a list of trusted root certificates (default: use certifi.where())') +@click.option('--keep-dupes', '-d', is_flag=True, default=False, + help='write all certs including any duplicates across domains (default: remove duplicates)') +@click.argument('domain', nargs=-1) +def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, domain): + """Download the SSL certificates for specified domain(s) and save them as a C + header file that can be imported into a sketch. + Provide at least one argument that is the domain to query for its SSL + certificate, for example google.com for Google's SSL certificate. You can + provide any number of domains as additional arguments. All of the certificates + will be combined into a single output header. + By default the file 'certificates.h' will be created, however you can change + the name of the file with the --output option. + If a chain of certificates is retrieved then only the root certificate (i.e. + the last in the chain) will be saved. However you can override this and + force the full chain to be saved with the --full-chain option. + Example of downloading google.com's SSL certificate and storing it in + certificates.h: + pycert download google.com + Example of downloading google.com and adafruit.com's SSL certificates and + storing them in data.h: + pycert download --output data.h google.com adafruit.com + Note that the certificates will be validated before they are downloaded! + """ + # prepare the root certificate store + cert_obj_store = cert_util.parse_root_certificate_store(use_store) + cert_dict = dict([(cert.get_subject().hash(), cert) for cert in cert_obj_store]) + # Download the cert object for each provided domain. + down_certs = [] + for d in domain: + # Download the certificate (unfortunately python will _always_ try to + # validate it so we have no control over turning that off). + cert = cert_util.get_server_root_cert(d, port, cert_dict) + if cert is None: + raise click.ClickException('Could not download and/or validate the certificate for {0} port {1}!'.format(d, port)) + click.echo('Retrieved certificate for {0}'.format(d)) + # append cert to array + down_certs.append(cert) + # Combine PEMs and write output header. + cert_util.x509_to_header(down_certs, cert_var, cert_length_var, output, keep_dupes) + + +@pycert_bearssl.command(short_help='Convert PEM certs into a C header.') +@click.option('--cert-var', '-c', default=CERT_ARRAY_NAME, + help='name of the variable in the header which will contain certificate data (default: {0})'.format(CERT_ARRAY_NAME)) +@click.option('--cert-length-var', '-l', default=CERT_LENGTH_NAME, + help='name of the define in the header which will contain the length of the certificate data (default: {0})'.format(CERT_LENGTH_NAME)) +@click.option('--output', '-o', type=click.File('w'), default='certificates.h', + help='name of the output file (default: certificates.h)') +@click.option('--full-chain', '-f', is_flag=True, default=False, + help='use the full certificate chain and not just the root/last cert (default: false, root cert only)') +@click.option('--keep-dupes', '-d', is_flag=True, default=False, + help='write all certs including any duplicates (default: remove duplicates)') +@click.argument('cert', type=click.File('r'), nargs=-1) +def convert(cert_var, cert_length_var, output, full_chain, keep_dupes, cert): + """Convert PEM certificates into a C header that can be imported into a + sketch. Specify each certificate to encode as a separate argument (each + must be in PEM format) and they will be merged into a single file. + By default the file 'certificates.h' will be created, however you can change + the name of the file with the --output option. + If a chain of certificates is found then only the root certificate (i.e. + the last in the chain) will be saved. However you can override this and + force the full chain to be saved with the --full-chain option. + Example of converting a foo.pem certificate into a certificates.h header: + pycert convert foo.pem + Example of converting foo.pem and bar.pem certificates into data.h: + pycert convert foo.pem bar.pem + """ + # Load all the provided PEM files. + pems = [] + for c in cert: + cert_pem = c.read() + click.echo('Loaded certificate {0}'.format(c.name)) + pems.append(cert_pem) + # Combine PEMs and write output header. + PEM_to_header(pems, cert_var, cert_length_var, output, full_chain, keep_dupes) + + +if __name__ == '__main__': + pycert_bearssl() \ No newline at end of file From 99920111ff6fe9b04eb2ba3f84a8c494420f23f5 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 13 Mar 2019 20:33:37 -0700 Subject: [PATCH 027/205] added domain to description, fixed the "convert" command --- tools/pycert_bearssl/cert_util.py | 68 ++++++++++++++++---------- tools/pycert_bearssl/pycert_bearssl.py | 35 +++++++++---- 2 files changed, 67 insertions(+), 36 deletions(-) diff --git a/tools/pycert_bearssl/cert_util.py b/tools/pycert_bearssl/cert_util.py index 4fa4cd8..75b286e 100644 --- a/tools/pycert_bearssl/cert_util.py +++ b/tools/pycert_bearssl/cert_util.py @@ -108,6 +108,7 @@ CROOTCA_TEMPLATE = """\ # - cert_label: The certificate's name field (Usually CN, in the subject) # - cert_issue: The certificate's issuer string # - cert_subject: The certificate's subject string +# - cert_domain: The domains polled by this tool that returned this certificate CCERT_DESC_TEMPLATE = """\ * Index: {cert_num} * Label: {cert_label} @@ -171,18 +172,6 @@ def get_server_root_cert(address, port, certDict): return None return certDict[cn_hash] -def filter_duplicate_x509(certs): - serial_numbers = set() - out_certs = list() - # filter duplicate certs - for cert in certs: - # Skip duplicate certs where required. - if cert.get_serial_number() in serial_numbers: - continue - out_certs.append(cert) - serial_numbers.add(cert.get_serial_number()) - return out_certs - def bytes_to_c_data(mah_bytes, length=None): """Converts a byte array to a CSV C array data format, with endlines! e.g: 0x12, 0xA4, etc. @@ -199,7 +188,13 @@ def bytes_to_c_data(mah_bytes, length=None): # join, wrap, and return return textwrap.fill(''.join(ret), width=6*12 + 5, initial_indent=' ', subsequent_indent=' ', break_long_words=False) -def decribe_cert_object(cert, cert_num): +def decribe_cert_object(cert, cert_num, domain=None): + """ + Formats a string describing a certificate object, including the domain + being used and the index in the trust anchor array. Cert should be a + x509 object, domain should be a string name, and cert_num should be + an integer. + """ # get the label from the subject feild on the certificate label = "" com = dict(cert.get_subject().get_components()) @@ -211,16 +206,20 @@ def decribe_cert_object(cert, cert_num): label = com[b'O'].decode("utf-8") # return the formated string crypto = cert.to_cryptography() - return CCERT_DESC_TEMPLATE.format( + out_str = CCERT_DESC_TEMPLATE.format( cert_num=cert_num, cert_label=label, cert_subject=crypto.subject.rfc4514_string(), ) - + # if domain, then add domain entry + if domain is not None: + out_str += "\n * Domain(s): " + domain + return out_str -def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes): +def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes, domains=None): """Combine a collection of PEM format certificates into a single C header with the combined cert data in BearSSL format. x509Certs should be a list of pyOpenSSL x590 objects, + domains should be a list of respective domain strings (in same order as x509Certs), cert_var controls the name of the cert data variable in the output header, cert_length_var controls the name of the cert data length variable/define, output is the output file (which must be open for writing). Keep_dupes is a boolean to indicate if duplicate @@ -228,24 +227,41 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes """ cert_description = '' certs = x509Certs - if not keep_dupes: - certs = filter_duplicate_x509(x509Certs) # Save cert data as a C style header. # start by building each component cert_data = "" + # hold an array of static array strings (TA_RSA_N) static_arrays = list() + # same with CA entries CAs = list() + # descriptions cert_desc = list() + # track the serial numbers so we can find duplicates + cert_ser = list() for i, cert in enumerate(certs): + # calculate the index shifted from duplicates (if any) + cert_index = len(CAs) + # deduplicate certificates + if not keep_dupes and cert.get_serial_number() in cert_ser: + # append the domain we used it for into the cert description + if domains is not None: + cert_desc[cert_ser.index(cert.get_serial_number())] += ", " + domains[i] + # we don't need to generate stuff for this certificate + continue + # record the serial number for later + cert_ser.append(cert.get_serial_number()) # add a description of the certificate to the array - cert_desc.append(decribe_cert_object(cert, i)) + if domains is None: + cert_desc.append(decribe_cert_object(cert, cert_index)) + else: + cert_desc.append(decribe_cert_object(cert, cert_index, domain=domains[i])) # build static arrays containing all the keys of the certificate # start with distinguished name # get the distinguished name in bytes dn_bytes_str = bytes_to_c_data(cert.get_subject().der()) static_arrays.append(CRAY_TEMPLATE.format( ray_type="unsigned char", - ray_name=DN_PRE + str(i), + ray_name=DN_PRE + str(cert_index), ray_data=dn_bytes_str)) # next, the RSA public numbers pubkey = cert.get_pubkey() @@ -254,19 +270,19 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes n_bytes_str = bytes_to_c_data(numbers.n.to_bytes(pubkey.bits() // 8, byteorder="big")) static_arrays.append(CRAY_TEMPLATE.format( ray_type="unsigned char", - ray_name=RSA_N_PRE + str(i), + ray_name=RSA_N_PRE + str(cert_index), ray_data=n_bytes_str)) # and then the exponent e_bytes_str = bytes_to_c_data(numbers.e.to_bytes(math.ceil(numbers.e.bit_length() / 8), byteorder="big")) static_arrays.append(CRAY_TEMPLATE.format( ray_type="unsigned char", - ray_name=RSA_E_PRE + str(i), + ray_name=RSA_E_PRE + str(cert_index), ray_data=e_bytes_str)) # format the root certificate entry CAs.append(CROOTCA_TEMPLATE.format( - ta_dn_name=DN_PRE + str(i), - rsa_number_name=RSA_N_PRE + str(i), - rsa_exp_name=RSA_E_PRE + str(i))) + ta_dn_name=DN_PRE + str(cert_index), + rsa_number_name=RSA_N_PRE + str(cert_index), + rsa_exp_name=RSA_E_PRE + str(cert_index))) # concatonate it all into the big header file template # cert descriptions cert_desc_out = '\n * \n'.join(cert_desc) @@ -281,6 +297,6 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes guard_name=os.path.splitext(output_file.name)[0].upper(), cert_description=cert_desc_out, cert_length_var=cert_length_var, - cert_length=str(len(certs)), + cert_length=str(len(CAs)), cert_data=cert_data_out, )) \ No newline at end of file diff --git a/tools/pycert_bearssl/pycert_bearssl.py b/tools/pycert_bearssl/pycert_bearssl.py index a92beaa..c76df3a 100644 --- a/tools/pycert_bearssl/pycert_bearssl.py +++ b/tools/pycert_bearssl/pycert_bearssl.py @@ -18,6 +18,7 @@ import cert_util import click import certifi +from OpenSSL import crypto # Default name for the cert length varible CERT_LENGTH_NAME = "TAs_NUM" @@ -82,7 +83,7 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom # append cert to array down_certs.append(cert) # Combine PEMs and write output header. - cert_util.x509_to_header(down_certs, cert_var, cert_length_var, output, keep_dupes) + cert_util.x509_to_header(down_certs, cert_var, cert_length_var, output, keep_dupes, domains=domain) @pycert_bearssl.command(short_help='Convert PEM certs into a C header.') @@ -92,33 +93,47 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom help='name of the define in the header which will contain the length of the certificate data (default: {0})'.format(CERT_LENGTH_NAME)) @click.option('--output', '-o', type=click.File('w'), default='certificates.h', help='name of the output file (default: certificates.h)') -@click.option('--full-chain', '-f', is_flag=True, default=False, - help='use the full certificate chain and not just the root/last cert (default: false, root cert only)') +@click.option('--use-store', '-s', type=click.File('r'), default=certifi.where(), + help='the location of the .pem file containing a list of trusted root certificates (default: use certifi.where())') @click.option('--keep-dupes', '-d', is_flag=True, default=False, help='write all certs including any duplicates (default: remove duplicates)') @click.argument('cert', type=click.File('r'), nargs=-1) -def convert(cert_var, cert_length_var, output, full_chain, keep_dupes, cert): +def convert(cert_var, cert_length_var, output, use_store, keep_dupes, cert): """Convert PEM certificates into a C header that can be imported into a sketch. Specify each certificate to encode as a separate argument (each must be in PEM format) and they will be merged into a single file. By default the file 'certificates.h' will be created, however you can change the name of the file with the --output option. If a chain of certificates is found then only the root certificate (i.e. - the last in the chain) will be saved. However you can override this and - force the full chain to be saved with the --full-chain option. + the last in the chain) will be saved. Example of converting a foo.pem certificate into a certificates.h header: pycert convert foo.pem Example of converting foo.pem and bar.pem certificates into data.h: pycert convert foo.pem bar.pem """ + # prepare root certificate store + cert_obj_store = cert_util.parse_root_certificate_store(use_store) + cert_dict = dict([(cert.get_subject().hash(), cert) for cert in cert_obj_store]) # Load all the provided PEM files. - pems = [] + cert_objs = [] for c in cert: cert_pem = c.read() - click.echo('Loaded certificate {0}'.format(c.name)) - pems.append(cert_pem) + cert_parsed = crypto.load_certificate(crypto.FILETYPE_PEM, cert_pem) + if cert_parsed is None: + click.echo('Failed to load certificate {0}'.format(c.name)) + else: + click.echo('Loaded certificate {0}'.format(c.name)) + cert_objs.append(cert_parsed) + # find a root certificate for each + root_certs = [] + for i, c in enumerate(cert_objs): + cn_hash = c.get_issuer().hash() + if cn_hash not in cert_dict: + click.echo('Could not find a root certificate for {0}'.format(cert[i].name)) + else: + root_certs.append(cert_dict[cn_hash]) # Combine PEMs and write output header. - PEM_to_header(pems, cert_var, cert_length_var, output, full_chain, keep_dupes) + cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes) if __name__ == '__main__': From 292dd7a8073cae1d32e789f8d2c5c4a85eb0eb59 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 14 Mar 2019 11:04:51 -0700 Subject: [PATCH 028/205] Added out of memory warning and reset --- src/SSLClientImpl.cpp | 34 ++++++++++++++++++++++++++++------ src/SSLClientImpl.h | 10 +++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 997fcb9..478af65 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -195,7 +195,8 @@ void SSLClientImpl::stop() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); // if the engine isn't closed, and the socket is still open - while (br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED + while (getWriteError() == SSL_OK + && br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED && m_run_until(BR_SSL_RECVAPP) == 0) { /* * Discard any incoming application data. @@ -308,7 +309,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { for (;;) { unsigned state = m_update_engine(); // error check - if (state == BR_SSL_CLOSED || getWriteError()) { + if (state == BR_SSL_CLOSED || getWriteError() != SSL_OK) { m_warn("Tried to run_until when the engine is closed", func_name); return -1; } @@ -324,8 +325,6 @@ int SSLClientImpl::m_run_until(const unsigned target) { lastState = state; m_info("m_run changed state:", func_name); printState(state); - m_info("Memory: ", func_name); - m_info(freeMemory(), func_name); } if (state & BR_SSL_RECVREC) { size_t len; @@ -473,11 +472,33 @@ unsigned SSLClientImpl::m_update_engine() { // do we have the record you're looking for? const auto avail = m_client->available(); if (avail >= len) { + int mem = freeMemory(); + m_info("Memory: ", func_name); + m_info(mem, func_name); + // free memory check + // BearSSL takes up so much memory on the stack it tends + // to overflow if there isn't at least 8000 bytes available + // when it starts + if(mem < 8000) { + m_error("Out of memory! Decrease the number of sessions or the size of m_iobuf", func_name); + setWriteError(SSL_OUT_OF_MEMORY); + stop(); + return 0; + } + // check for a stack overflow + // if the stack overflows we basically have to crash, and + // hope the user is ok with that + // since all memory is garbage we can't trust the cpu to + // execute anything properly + if (mem > 32 * 1024) { + // software reset + REQUEST_EXTERNAL_RESET; + // can't print anything, so pray for reset + while (1) { } + } m_info("Read bytes from client: ", func_name); m_info(avail, func_name); m_info(len, func_name); - m_info("Memory: ", func_name); - m_info(freeMemory(), func_name); // I suppose so! int rlen = m_client->read(buf, len); if (rlen <= 0) { @@ -539,6 +560,7 @@ void SSLClientImpl::m_print_ssl_error(const int ssl_error, const DebugLevel leve case SSL_CLIENT_WRTIE_ERROR: Serial.println("SSL_CLIENT_WRITE_FAIL"); break; case SSL_BR_WRITE_ERROR: Serial.println("SSL_BR_WRITE_ERROR"); break; case SSL_INTERNAL_ERROR: Serial.println("SSL_INTERNAL_ERROR"); break; + case SSL_OUT_OF_MEMORY: Serial.println("SSL_OUT_OF_MEMORY"); break; } } diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 7ea6774..82ea3fe 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -26,6 +26,13 @@ #ifndef SSLClientImpl_H_ #define SSLClientImpl_H_ +// system reset definitions +#define SYSRESETREQ (1<<2) +#define VECTKEY (0x05fa0000UL) +#define VECTKEY_MASK (0x0000ffffUL) +#define AIRCR (*(uint32_t*)0xe000ed0cUL) // fixed arch-defined address +#define REQUEST_EXTERNAL_RESET (AIRCR=(AIRCR&VECTKEY_MASK)|VECTKEY|SYSRESETREQ) + /** error enums * Static constants defining the possible errors encountered * Read from getWriteError(); @@ -36,7 +43,8 @@ enum Error { SSL_BR_CONNECT_FAIL, SSL_CLIENT_WRTIE_ERROR, SSL_BR_WRITE_ERROR, - SSL_INTERNAL_ERROR + SSL_INTERNAL_ERROR, + SSL_OUT_OF_MEMORY }; /** Debug level enum From 6389c24bc1a000cf8ad76baa7817c72c1dbd2fe4 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Fri, 15 Mar 2019 17:01:50 -0700 Subject: [PATCH 029/205] refactored a bit, in process of documenting --- src/SSLClient.h | 95 ++++++++++++++---- src/SSLClientImpl.cpp | 50 +++++++--- src/SSLClientImpl.h | 225 ++++++++++++++++++++++++++++++------------ src/SSLSession.h | 70 ++++++++++--- 4 files changed, 334 insertions(+), 106 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 1ae0b9f..44baf6d 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -24,11 +24,8 @@ * This library was created to provide SSL functionality to the {@link https://learn.adafruit.com/adafruit-wiz5500-wiznet-ethernet-featherwing/overview} * Adafruit Ethernet shield. Since this shield does not implement SSL functionality on * its own, we need to use an external library: in this case BearSSL {@link https://bearssl.org/}, - * which is also use in the Arduino ESP8266 core. SSLClient will serve to implement the - * BearSSL functionality inbetween EthernetCLient and the User, such that the user will - * simply need to start with: - * SSLCLient client(ethCLient); - * And then call the functions they normally would with EthernetClient using SSLCLient. + * which is also used in the Arduino ESP8266 core. SSLClient will serve to implement the + * BearSSL functionality inbetween EthernetClient and the User, such that the user. * * This file specifically controls the class templating used to allow SSLClient to interface * with all of the CLient-based classes. To see details on the implementations of the functions @@ -38,12 +35,17 @@ #include #include "Client.h" #include "SSLClientImpl.h" +#include "SSLSession.h" #ifndef SSLClient_H_ #define SSLClient_H_ /** - * \brief This class serves as a templating proxy class for the SSLClientImpl to do the real work. + * \brief The main SSLClient class + * + * TODO: fix this blurb + * + * This class serves as a templating proxy class for the SSLClientImpl to do the real work. * * A problem arose when writing this class: I wanted the user to be able to construct * this class in a single line of code (e.g. SSLClient(EthernetClient())), but I also @@ -59,16 +61,23 @@ template class SSLClient : public SSLClientImpl { -/** static type checks +/** + * static checks * I'm a java developer, so I want to ensure that my inheritance is safe. * These checks ensure that all the functions we use on class C are - * actually present on class C. It does this by first checking that the - * class inherits from Client, and then that it contains a status() function. + * actually present on class C. It does this by checking that the + * class inherits from Client. + * + * Additionally, I ran into a lot of memory issues with large sessions caches. + * Since each session contains at max 352 bytes of memory, they eat of the + * stack quite quickly and can cause overflows. As a result, I have added a + * warning here to discourage the use of more than 3 sessions at a time. Any + * amount past that will require special modification of this library, and + * assumes you know what you are doing. */ static_assert(std::is_base_of::value, "C must be a Client Class!"); static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!"); static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur."); -// static_assert(std::is_function::value, "C must have a status() function!"); public: /** @@ -77,9 +86,10 @@ public: * We copy the client because we aren't sure the Client object * is going to exists past the inital creation of the SSLClient. * - * @pre The client class must be able to access the internet, as SSLClient - * cannot manage this for you. Additionally it is recommended that the analog_pin - * be set to input. + * @pre You will need to generate an array of trust_anchors (root certificates) + * based off of the domains you want to make SSL connections to. Check out the + * Wiki on the pycert-bearssl tool for a simple way to do this. + * @pre The analog_pin should be set to input. * * @param trust_anchors Trust anchors used in the verification * of the SSL server certificate, generated using the `brssl` command @@ -88,13 +98,12 @@ public: * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_ERROR) + explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN) : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) , m_sessions{SSLSession()} , m_index(0) { - // for (uint8_t i = 0; i < SessionCache; i++) m_sessions[i] = SSLSession(); // since we are copying the client in the ctor, we have to set // the client pointer after the class is constructed set_client(&m_client); @@ -106,23 +115,69 @@ public: /* * The special functions most clients have are below * Most of them smply pass through + */ + /** + * @brief Equivalent to SSLClient::connected() > 0 + * @returns true if connected, false if not */ virtual operator bool() { return connected() > 0; } + /** {@link SSLClient::bool()} */ virtual bool operator==(const bool value) { return bool() == value; } + /** {@link SSLClient::bool()} */ virtual bool operator!=(const bool value) { return bool() != value; } + /** @brief Returns whether or not two SSLClient objects have the same underlying client object */ virtual bool operator==(const C& rhs) { return m_client == rhs; } + /** @brief Returns whether or not two SSLClient objects do not have the same underlying client object */ virtual bool operator!=(const C& rhs) { return m_client != rhs; } - virtual uint16_t localPort() { return std::is_member_function_pointer::value ? m_client.localPort() : 0; } - virtual IPAddress remoteIP() { return std::is_member_function_pointer::value ? m_client.remoteIP() : INADDR_NONE; } - virtual uint16_t remotePort() { return std::is_member_function_pointer::value ? m_client.remotePort() : 0; } + /** @brief Returns the local port, if the Client class has a localPort() function. Else return 0. */ + virtual uint16_t localPort() { + if (std::is_member_function_pointer::value) return m_client.localPort(); + else { + m_warn("Client class has no localPort function, so localPort() will always return 0", __func__); + return 0; + } + } + /** @brief Returns the remote IP, if the Client class has a remoteIP() function. Else return INADDR_NONE. */ + virtual IPAddress remoteIP() { + if (std::is_member_function_pointer::value) return m_client.remoteIP(); + else { + m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__); + return INADDR_NONE; + } + } + /** @brief Returns the remote port, if the Client class has a remotePort() function. Else return 0. */ + virtual uint16_t remotePort() { + if (std::is_member_function_pointer::value) return m_client.remotePort(); + else { + m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__); + return 0; + } + } - //! get the client object + /** @brief returns a refernence to the client object stored in this class. Take care not to break it. */ C& getClient() { return m_client; } + /** + * @brief Get a sesssion reference corressponding to a host and IP, or a reference to a emptey session if none exist + * + * If no session corresponding to the host and ip exist, then this function will cycle through + * sessions in a rotating order. This allows the ssession cache to continuially store sessions, + * however it will also result in old sessions being cleared and returned. In general, it is a + * good idea to use a SessionCache size equal to the number of domains you plan on connecting to. + * + * @param host A hostname c string, or NULL if one is not availible + * @param ip An IP address + * @returns A reference to an SSLSession object + */ virtual SSLSession& getSession(const char* host, const IPAddress& addr); + /** + * @brief Clear the session corresponding to a host and IP + * + * @param host A hostname c string, or NULL if one is not availible + * @param ip An IP address + */ virtual void removeSession(const char* host, const IPAddress& addr); - private: // utility function to find a session index based off of a host and IP int m_getSessionIndex(const char* host, const IPAddress& addr) const; diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 478af65..79f8fd8 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -20,6 +20,35 @@ #include "SSLClient.h" +// system reset definitions +static constexpr auto SYSRESETREQ = (1<<2); +static constexpr auto VECTKEY = (0x05fa0000UL); +static constexpr auto VECTKEY_MASK = (0x0000ffffUL); +/** Trigger a software reset. Only use if in unrecoverable state */ +[[ noreturn ]] static void RESET() { + (*(uint32_t*)0xe000ed0cUL)=((*(uint32_t*)0xe000ed0cUL)&VECTKEY_MASK)|VECTKEY|SYSRESETREQ; + while(1) { } +} + +#ifdef __arm__ +// should use uinstd.h to define sbrk but Due causes a conflict +extern "C" char* sbrk(int incr); +#else // __ARM__ +extern char *__brkval; +#endif // __arm__ + +/** Get the free memory availible in bytes (stack - heap) */ +static int freeMemory() { + char top; +#ifdef __arm__ + return &top - reinterpret_cast(sbrk(0)); +#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) + return &top - __brkval; +#else // __arm__ + return __brkval ? &top - __brkval : &top - __malloc_heap_start; +#endif // __arm__ +} + /** see SSLClientImpl.h */ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) @@ -473,6 +502,16 @@ unsigned SSLClientImpl::m_update_engine() { const auto avail = m_client->available(); if (avail >= len) { int mem = freeMemory(); + // check for a stack overflow + // if the stack overflows we basically have to crash, and + // hope the user is ok with that + // since all memory is garbage we can't trust the cpu to + // execute anything properly + if (mem > 32 * 1024) { + // software reset + RESET(); + } + // debug info m_info("Memory: ", func_name); m_info(mem, func_name); // free memory check @@ -485,17 +524,6 @@ unsigned SSLClientImpl::m_update_engine() { stop(); return 0; } - // check for a stack overflow - // if the stack overflows we basically have to crash, and - // hope the user is ok with that - // since all memory is garbage we can't trust the cpu to - // execute anything properly - if (mem > 32 * 1024) { - // software reset - REQUEST_EXTERNAL_RESET; - // can't print anything, so pray for reset - while (1) { } - } m_info("Read bytes from client: ", func_name); m_info(avail, func_name); m_info(len, func_name); diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 82ea3fe..b38ebb3 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -26,68 +26,60 @@ #ifndef SSLClientImpl_H_ #define SSLClientImpl_H_ -// system reset definitions -#define SYSRESETREQ (1<<2) -#define VECTKEY (0x05fa0000UL) -#define VECTKEY_MASK (0x0000ffffUL) -#define AIRCR (*(uint32_t*)0xe000ed0cUL) // fixed arch-defined address -#define REQUEST_EXTERNAL_RESET (AIRCR=(AIRCR&VECTKEY_MASK)|VECTKEY|SYSRESETREQ) - -/** error enums - * Static constants defining the possible errors encountered - * Read from getWriteError(); +/** + * @brief Static constants defining the possible errors encountered. + * + * If SSLClient encounters an error, it will generally output + * logs into the serial moniter. If you need a way of programmatically + * checking the errors, you can do so with SSLCLient.getWriteError(), + * which will return one of these values. */ enum Error { SSL_OK = 0, + /** The underlying client failed to connect, probably not an issue with SSL */ SSL_CLIENT_CONNECT_FAIL, + /** BearSSL failed to complete the SSL handshake, check logs for bear ssl error output */ SSL_BR_CONNECT_FAIL, + /** The underlying client failed to write a payload, probably not an issue with SSL */ SSL_CLIENT_WRTIE_ERROR, + /** An internal error occurred with BearSSL, check logs for diagnosis. */ SSL_BR_WRITE_ERROR, + /** An internal error occured with SSLClient, and you probably need to submit an issue on Github. */ SSL_INTERNAL_ERROR, + /** SSLClient detected that there was not enough memory (>8000 bytes) to continue. */ SSL_OUT_OF_MEMORY }; -/** Debug level enum - * Static enum defining the debugging levels to print - * into the Serial monitor +/** + * @brief Level of verbosity used in logging for SSLClient. + * + * Use these values when initializing SSLCLient to set how many logs you + * would like to see in the Serial moniter. */ enum DebugLevel { + /** No logging output */ SSL_NONE = 0, + /** Only output errors that result in connection failure */ SSL_ERROR = 1, + /** Ouput errors and warnings (useful when just starting to develop) */ SSL_WARN = 2, + /** Output errors, warnings, and internal information (very verbose) */ SSL_INFO = 3, }; - -#ifdef __arm__ -// should use uinstd.h to define sbrk but Due causes a conflict -extern "C" char* sbrk(int incr); -#else // __ARM__ -extern char *__brkval; -#endif // __arm__ - -static int freeMemory() { - char top; -#ifdef __arm__ - return &top - reinterpret_cast(sbrk(0)); -#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) - return &top - __brkval; -#else // __arm__ - return __brkval ? &top - __brkval : &top - __malloc_heap_start; -#endif // __arm__ -} - - -/** TODO: Write what this is */ +/** + * On error, any function in this class will terminate the socket. + * TODO: Write what this is */ class SSLClientImpl : public Client { public: /** * @brief initializes SSL contexts for bearSSL * - * @pre The client class must be able to access the internet, as SSLClient - * cannot manage this for you. Additionally it is recommended that the analog_pin - * be set to input. + * @pre You will need to generate an array of trust_anchors (root certificates) + * based off of the domains you want to make SSL connections to. Check out the + * Wiki on the pycert-bearssl tool for a simple way to do this. + * @pre The analog_pin should be set to input. * * @post set_client must be called immediatly after to set the client class * pointer. @@ -104,13 +96,8 @@ public: */ explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); - /** Dtor is implicit since unique_ptr handles it fine */ - /** functions specific to the EthernetClient which I'll have to override */ - // uint8_t status(); - // uint8_t getSocketNumber() const; - - /** functions dealing with read/write that BearSSL will be injected into */ + /* functions dealing with read/write that BearSSL will be injected into */ /** * @brief Connect over SSL to a host specified by an ip address * @@ -122,46 +109,162 @@ public: * * This function initializes EthernetClient by calling EthernetClient::connect * with the parameters supplied, then once the socket is open initializes - * the appropriete bearssl contexts using the TLS_only_profile. Due to the - * design of the SSL standard, this function will probably take an extended - * period (1-2sec) to negotiate the handshake and finish the connection. + * the appropriete bearssl contexts. Due to the design of the SSL standard, + * this function will probably take an extended period (1-4sec) to negotiate + * the handshake and finish the connection. This function runs until the SSL + * handshake succeeds or fails, as found in most Arduino libraries, so be + * sure to design around this in your code. + * + * @pre The underlying client object (passed in through the ctor) in a non- + * error state, and must be able to access the server being connected to. + * @pre SSLCLient can only have one connection at a time, so the client + * object must not already have a socket open. + * @pre There must be sufficient memory availible on the device to verify + * the certificate (if the free memory drops below 8000 bytes during certain + * points in the connection, SSLCLient will fail). + * @pre There must be a trust anchor given to the ctor that corresponds to + * the certificate provided by the IP address being connected to. For more + * information check out the wiki on the pycert-bearssl tool. + * @pre The analog pin passed to the ctor must be set to input, and must + * be wired to something sort of random (floating is fine). * * @param ip The ip address to connect to * @param port the port to connect to * @returns 1 if success, 0 if failure (as found in EthernetClient) - * - * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port - * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. */ virtual int connect(IPAddress ip, uint16_t port); + /** - * @brief Connect over SSL using connect(ip, port), but use a DNS lookup to + * @brief Connect over SSL using connect(ip, port), using a DNS lookup to * get the IP Address first. * * This function initializes EthernetClient by calling EthernetClient::connect - * with the parameters supplied, then once the socket is open initializes - * the appropriete bearssl contexts using the TLS_only_profile. + * with the parameters supplied, then once the socket is open uses BearSSL to + * to complete a SSL handshake. This function runs until the SSL handshake + * succeeds or fails, as found in most Arduino libraries. + * + * SSL requires the client to generate some random bits (to be later combined + * with some random bits from the server), so SSLClient uses the least signinigant + * bits from the analog pin supplied in the ctor. The random bits are generated + * from 16 consecutive analogReads, and given to BearSSL before the handshake + * starts. * * Due to the design of the SSL standard, this function will probably take an - * extended period (1-2sec) to negotiate the handshake and finish the + * extended period (1-4sec) to negotiate the handshake and finish the * connection. Since the hostname is provided, however, BearSSL is able to keep * a session cache of the clients we have connected to. This should reduce - * connection time greatly. In order to use this feature, you must reuse the - * same SSLClient object to connect to the reused host. Doing this will allow - * BearSSL to automatically match the hostname to a cached session. + * connection time to about 100-200ms. In order to use this feature, the website + * you are connecting to must support it (most do by default), you must + * reuse the same SSLClient object, and you must reconnect to the same server. + * SSLClient automatcally stores an IP address and hostname in each session, + * ensuring that if you call connect("www.google.com") SSLClient will use a + * cached IP address instead of another DNS lookup. Because some websites have + * multiple servers on a single IP address (github.com is an example), however, + * you may find that even if you are connecting to the same host the connection + * does not resume. This is a flaw in the SSL session protocol, and has been + * resolved in future versions. On top of all that, SSL sessions can expire + * based on server criteria, which will result in a regular connection time. + * Because of all these factors, it is generally prudent to assume the + * connection will not be resumed, and go from there. + * + * @pre The underlying client object (passed in through the ctor) in a non- + * error state, and must be able to access the server being connected to. + * @pre SSLCLient can only have one connection at a time, so the client + * object must not already have a socket open. + * @pre There must be sufficient memory availible on the device to verify + * the certificate (if the free memory drops below 8000 bytes during certain + * points in the connection, SSLCLient will fail). + * @pre There must be a trust anchor given to the ctor that corresponds to + * the certificate provided by the IP address being connected to. For more + * information check out the wiki on the pycert-bearssl tool. + * @pre The analog pin passed to the ctor must be set to input, and must + * be wired to something sort of random (floating is fine). * * @param host The cstring host ("www.google.com") - * @param port the port to connect to - * @returns 1 of success, 0 if failure (as found in EthernetClient) - * - * @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port - * @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection. + * @param port the port to connect to (443) + * @returns 1 of success, 0 if failure (as found in EthernetClient). */ virtual int connect(const char *host, uint16_t port); + + /** @see SSLClient::write(uint8_t*, size_t) */ virtual size_t write(uint8_t b) { return write(&b, 1); } + /** + * @brief Write some bytes to the SSL connection + * + * Assuming all preconditions are met, this function waits for BearSSL + * to be ready for data to be sent, then writes data to the BearSSL IO + * buffer, BUT does not initally send the data. Insead, it is + * then checked if the BearSSL IO buffer is full, and if so, this function + * waits until BearSSL has flushed the buffer (written it to the + * network client) and fills the buffer again. If the function finds + * that the BearSSL buffer is not full, it returns the number of + * bytes written. In other words, this function will only write data + * to the network if the BearSSL IO buffer is full. Instead, you must call + * SSLClient::availible or SSLClient::flush, which will detect that + * the buffer is ready for writing, and will write the data to the network. + * + * This was implemented as a buffered function because users of Arduino Client + * libraries will often write to the network as such: + * @code{.cpp} + * Client client; + * ... + * client.println("GET /asciilogo.txt HTTP/1.1"); + * client.println("Host: arduino.cc"); + * client.println("Connection: close"); + * while (!client.available()) { ... } + * ... + * @endcode + * This is fine with most network clients. With SSL, however, if we are encryting and + * writing to the network every write() call this will result in a lot of + * small encryption tasks. Encryption takes a lot of time and code, and in general + * the larger the batch we can do it in the better. For this reason, write() + * implicitly buffers until SSLClient::availible is called, or until the buffer is full. + * If you would like to trigger a network write manually without using the SSLClient::available, + * you can also call SSLClient::flush, which will write all data and return when finished. + * + * @pre The socket and SSL layer must be connected, meaning SSLClient::connected must be true. + * @pre BearSSL must not be waiting for the recipt of user data (if it is, there is + * probably an error with how the protocol in implemented in your code). + * + * @param buf the pointer to a buffer of bytes to copy + * @param size the number of bytes to copy from the buffer + * @returns The number of bytes copied to the buffer (size), or zero if the BearSSL engine + * fails to become ready for writing data. + */ virtual size_t write(const uint8_t *buf, size_t size); + + /** + * @brief Returns the number of bytes availible to read from the SSL Socket + * + * This function updates the state of the SSL engine (including writing any data, + * see SSLClient::write) and as a result should be called periodically when writing + * or expecting data. Additionally, since this function returns zero if there are + * no bytes and if SSLClient::connected is false (this same behavior is found + * in EthernetClient), it is prudent to ensure in your own code that the + * preconditions are met before checking this function to prevent an ambigious + * result. + * + * @pre SSLClient::connected must be true. + * + * @returns The number of bytes availible (can be zero), or zero if any of the pre + * conditions aren't satisfied. + */ virtual int available(); + + /** @see SSLClient::read(uint8_t*, size_t) */ virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; } + /** + * @brief Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. + * + * This function checks if bytes are ready to be read by calling SSLClient::availible, + * and if there are some copies size number of bytes from the IO buffer into buf. + * + * It should be noted that a common problem I encountered with SSL connections is + * buffer overflow, caused by the server sending too much data at once. This problem + * only occurs... + * + * TODO: finish + */ virtual int read(uint8_t *buf, size_t size); virtual int peek(); virtual void flush(); diff --git a/src/SSLSession.h b/src/SSLSession.h index b881084..64442f9 100644 --- a/src/SSLSession.h +++ b/src/SSLSession.h @@ -50,13 +50,59 @@ class SSLSession : public br_ssl_session_parameters { public: + /** + * @brief SSLSession constructor + * + * Sets all parameters to zero, and invalidates the session + */ explicit SSLSession() : m_valid_session(false) , m_hostname() , m_ip(INADDR_NONE) {} + /** @brief use clear_parameters or set_parameters instead */ + SSLSession& operator=(const SSLSession&) = delete; + /** - * \pre must call br_ssl_engine_get_session_parameters(engine, toBearSSlSession()); + * @brief Get the hostname string associated with this session + * + * @returns A String object or "" if there is no hostname + * @pre must check isValidSession before getting this value, + * as if this session in invalid this value is not guarented + * to be reset to "". + */ + const String& get_hostname() const { return m_hostname; } + + /** + * @brief Get ::IPAddress associated with this session + * + * @returns A ::IPAddress object, #INADDR_NONE if there is no IP + * @pre must check isValidSession before getting this value, + * as if this session in invalid this value is not guarented + * to be reset to #INADDR_NONE. + */ + const IPAddress& get_ip() const { return m_ip; } + + bool is_valid_session() const { return m_valid_session; } + + /** + * @brief Set the ip address and hostname of the session. + * + * This function stores the ip Address object and hostname object into + * the session object. If hostname is not null or ip address is + * not blank, and the ::br_ssl_session_parameters values are non-zero + * it then validates the session. + * + * @pre You must call + * ::br_ssl_engine_get_session_parameters + * with this session before calling this function. This is because + * there is no way to completly validate the ::br_ssl_session_parameters + * and the session may end up in a corrupted state if this is not observed. + * + * @param ip The IP address of the host associated with the session + * @param hostname The string hostname ("www.google.com") associated with the session. + * Take care that this value is corrent, SSLSession performs no validation + * of the hostname. */ void set_parameters(const IPAddress& ip, const char* hostname = NULL) { // copy the hostname @@ -68,8 +114,16 @@ public: // check if both values are valid, and if so set valid to true if (m_ip != INADDR_NONE && session_id_len > 0 && (hostname == NULL || m_hostname)) m_valid_session = true; + // else clear + else clear_parameters(); } + /** + * @brief delete the parameters and invalidate the session + * Roughly equivalent to this_session = SSLSession(), however + * this function preserves the String object, allowing it + * to better handle the dynamic memory needed. + */ void clear_parameters() { // clear the hostname , ip, and valid session flags m_hostname = ""; @@ -77,21 +131,9 @@ public: m_valid_session = false; } - SSLSession& operator=(const SSLSession&) = delete; - + /** @brief returns a pointer to the ::br_ssl_session_parameters component of this class */ br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; } - /** - * \pre must check isValidSession - */ - const String& get_hostname() const { return m_hostname; } - - /** - * \pre must check isValidSession - */ - const IPAddress& get_ip() const { return m_ip; } - - bool is_valid_session() const { return m_valid_session; } private: bool m_valid_session; // aparently a hostname has a max length of 256 chars. Go figure. From 6e7215b0b83221afa170a984be0c6287b70cc5b5 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 21 Mar 2019 11:17:00 -0700 Subject: [PATCH 030/205] moved documentation and almost finished, need to fix forward definitions in header file --- src/SSLClient.h | 259 +++++++++++++++++++++++++++++++++++++++++- src/SSLClientImpl.cpp | 12 +- src/SSLClientImpl.h | 216 +++++++---------------------------- 3 files changed, 306 insertions(+), 181 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 44baf6d..d12ff56 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -112,10 +112,263 @@ public: setTimeout(10 * 1000); } - /* - * The special functions most clients have are below - * Most of them smply pass through + //======================================== + //= Functions implemented in SSLClientImpl + //======================================== + + /** + * @brief Connect over SSL to a host specified by an ip address + * + * SSLClient::connect(host, port) should be preffered over this function, + * as verifying the domain name is a step in ensuring the certificate is + * legitimate, which is important to the security of the device. Additionally, + * SSL sessions cannot be resumed, which can drastically increase initial + * connect time. + * + * This function initializes EthernetClient by calling EthernetClient::connect + * with the parameters supplied, then once the socket is open initializes + * the appropriete bearssl contexts. Due to the design of the SSL standard, + * this function will probably take an extended period (1-4sec) to negotiate + * the handshake and finish the connection. This function runs until the SSL + * handshake succeeds or fails, as found in most Arduino libraries, so be + * sure to design around this in your code. + * + * The implementation for this function can be found in SSLClientImpl::connect(IPAddress, uint16_t) + * + * @pre The underlying client object (passed in through the ctor) in a non- + * error state, and must be able to access the server being connected to. + * @pre SSLCLient can only have one connection at a time, so the client + * object must not already have a socket open. + * @pre There must be sufficient memory availible on the device to verify + * the certificate (if the free memory drops below 8000 bytes during certain + * points in the connection, SSLCLient will fail). + * @pre There must be a trust anchor given to the ctor that corresponds to + * the certificate provided by the IP address being connected to. For more + * information check out the wiki on the pycert-bearssl tool. + * @pre The analog pin passed to the ctor must be set to input, and must + * be wired to something sort of random (floating is fine). + * + * @param ip The ip address to connect to + * @param port the port to connect to + * @returns 1 if success, 0 if failure (as found in EthernetClient) */ + // virtual int connect(IPAddress ip, uint16_t port) = 0; + + /** + * @brief Connect over SSL using connect(ip, port), using a DNS lookup to + * get the IP Address first. + * + * This function initializes EthernetClient by calling EthernetClient::connect + * with the parameters supplied, then once the socket is open uses BearSSL to + * to complete a SSL handshake. This function runs until the SSL handshake + * succeeds or fails, as found in most Arduino libraries. + * + * SSL requires the client to generate some random bits (to be later combined + * with some random bits from the server), so SSLClient uses the least signinigant + * bits from the analog pin supplied in the ctor. The random bits are generated + * from 16 consecutive analogReads, and given to BearSSL before the handshake + * starts. + * + * Due to the design of the SSL standard, this function will probably take an + * extended period (1-4sec) to negotiate the handshake and finish the + * connection. Since the hostname is provided, however, BearSSL is able to keep + * a session cache of the clients we have connected to. This should reduce + * connection time to about 100-200ms. In order to use this feature, the website + * you are connecting to must support it (most do by default), you must + * reuse the same SSLClient object, and you must reconnect to the same server. + * SSLClient automatcally stores an IP address and hostname in each session, + * ensuring that if you call connect("www.google.com") SSLClient will use a + * cached IP address instead of another DNS lookup. Because some websites have + * multiple servers on a single IP address (github.com is an example), however, + * you may find that even if you are connecting to the same host the connection + * does not resume. This is a flaw in the SSL session protocol, and has been + * resolved in future versions. On top of all that, SSL sessions can expire + * based on server criteria, which will result in a regular connection time. + * Because of all these factors, it is generally prudent to assume the + * connection will not be resumed, and go from there. + * + * The implementation for this function can be found in SSLClientImpl::connect(const char*, uint16_t) + * + * @pre The underlying client object (passed in through the ctor) in a non- + * error state, and must be able to access the server being connected to. + * @pre SSLCLient can only have one connection at a time, so the client + * object must not already have a socket open. + * @pre There must be sufficient memory availible on the device to verify + * the certificate (if the free memory drops below 8000 bytes during certain + * points in the connection, SSLCLient will fail). + * @pre There must be a trust anchor given to the ctor that corresponds to + * the certificate provided by the IP address being connected to. For more + * information check out the wiki on the pycert-bearssl tool. + * @pre The analog pin passed to the ctor must be set to input, and must + * be wired to something sort of random (floating is fine). + * + * @param host The cstring host ("www.google.com") + * @param port the port to connect to (443) + * @returns 1 of success, 0 if failure (as found in EthernetClient). + */ + // virtual int connect(const char *host, uint16_t port) = 0; + + /** @see SSLClient::write(uint8_t*, size_t) */ + // virtual size_t write(uint8_t b) = 0; + /** + * @brief Write some bytes to the SSL connection + * + * Assuming all preconditions are met, this function waits for BearSSL + * to be ready for data to be sent, then writes data to the BearSSL IO + * buffer, BUT does not initally send the data. Insead, it is + * then checked if the BearSSL IO buffer is full, and if so, this function + * waits until BearSSL has flushed the buffer (written it to the + * network client) and fills the buffer again. If the function finds + * that the BearSSL buffer is not full, it returns the number of + * bytes written. In other words, this function will only write data + * to the network if the BearSSL IO buffer is full. Instead, you must call + * SSLClient::availible or SSLClient::flush, which will detect that + * the buffer is ready for writing, and will write the data to the network. + * + * This was implemented as a buffered function because users of Arduino Client + * libraries will often write to the network as such: + * @code{.cpp} + * Client client; + * ... + * client.println("GET /asciilogo.txt HTTP/1.1"); + * client.println("Host: arduino.cc"); + * client.println("Connection: close"); + * while (!client.available()) { ... } + * ... + * @endcode + * This is fine with most network clients. With SSL, however, if we are encryting and + * writing to the network every write() call this will result in a lot of + * small encryption tasks. Encryption takes a lot of time and code, and in general + * the larger the batch we can do it in the better. For this reason, write() + * implicitly buffers until SSLClient::availible is called, or until the buffer is full. + * If you would like to trigger a network write manually without using the SSLClient::available, + * you can also call SSLClient::flush, which will write all data and return when finished. + * + * The implementation for this function can be found in SSLClientImpl::write(const uint8_t*, size_t) + * + * @pre The socket and SSL layer must be connected, meaning SSLClient::connected must be true. + * @pre BearSSL must not be waiting for the recipt of user data (if it is, there is + * probably an error with how the protocol in implemented in your code). + * + * @param buf the pointer to a buffer of bytes to copy + * @param size the number of bytes to copy from the buffer + * @returns The number of bytes copied to the buffer (size), or zero if the BearSSL engine + * fails to become ready for writing data. + */ + // virtual size_t write(const uint8_t *buf, size_t size) = 0; + + /** + * @brief Returns the number of bytes availible to read from the SSL Socket + * + * This function updates the state of the SSL engine (including writing any data, + * see SSLClient::write) and as a result should be called periodically when writing + * or expecting data. Additionally, since this function returns zero if there are + * no bytes and if SSLClient::connected is false (this same behavior is found + * in EthernetClient), it is prudent to ensure in your own code that the + * preconditions are met before checking this function to prevent an ambigious + * result. + * + * The implementation for this function can be found in SSLClientImpl::available + * + * @pre SSLClient::connected must be true. + * + * @returns The number of bytes availible (can be zero), or zero if any of the pre + * conditions aren't satisfied. + */ + //virtual int available() = 0; + + /** @see SSLClient::read(uint8_t*, size_t) */ + //virtual int read() = 0; + /** + * @brief Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. + * + * This function checks if bytes are ready to be read by calling SSLClient::availible, + * and if so copies size number of bytes from the IO buffer into the buf pointer, and deletes + * that number of bytes from the SSLClient buffer. Data read using this function will not + * include any SSL or socket commands, as the Client and BearSSL will capture those and + * process them seperatley. + * + * It should be noted that a common problem I encountered with SSL connections is + * buffer overflow, caused by the server sending too much data at once. This problem + * is caused by the microcontroller being unable to copy and decrypt data faster + * than it is being recieved, forcing some data to be discarded. This usually puts BearSSL + * in an invalid state in which it is unable to recover, causing SSLClient to close + * the connection with a write error. If you are experiencing frequent timeout problems, + * this could be the reason why. + * + * In order to remedy this problem the device must be able to read the data faster than + * it is being recieved, or have a cache large enough to store the entire recieve payload. + * Since SSL's encryption forces the device to read slowly, this means we must increase + * the cache size. Depending on your platform, there are a number of ways this can be + * done: + * - Sometimes your communication sheild will have an internal buffer, which can be expanded + * through the driver code. This is the case with the Arduino Ethernet library (in the form + * of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be + * modified for the change to take effect. + * - SSLClient has an internal buffer SSLClientImpl::m_iobuf, which can be expanded. This will have very + * limited usefulness, however, as BearSSL limits the amount of data that can be processed + * based on the stage in the SSL handshake. + * - If none of the above are viable, it is possible to implement your own Client class which + * has an internal buffer much larger than both the driver and BearSSL. This would require + * in-depth knowlege of programming and the communication shield you are working with. + * Another important question to ask with this problem is: do I need to acsess this website? + * Often times there are other ways to get data that we need that do the same thing, + * and these other ways may offer smaller and more managable response payloads. + * + * The implementation for this function can be found in SSLClientImpl::read(uint8_t*, size_t) + * + * @pre SSLClient::available must be >0 + * + * @param buf The pointer to the buffer to put SSL application data into + * @param size The size (in bytes) to copy to the buffer + * + * @returns The number of bytes copied (<= size), or -1 if the preconditions are not satisfied. + */ + //virtual int read(uint8_t *buf, size_t size) = 0; + + /** + * @brief view the first byte of the buffer, without removing it from the SSLClient Buffer + * The implementation for this function can be found in SSLClientImpl::peek + * @pre SSLClient::available must be >0 + * @returns The first byte recieved, or -1 if the preconditions are not satisfied (warning: + * do not use if your data may be -1, as the return value is ambigious) + */ + //virtual int peek() = 0; + + /** + * @brief Force writing the buffered bytes from SSLClient::write to the network. + * This function is blocking until all bytes from the buffer are written. For + * an explanation of how writing with SSLClient works, please see SSLCLient::write. + * The implementation for this function can be found in SSLClientImpl::flush. + */ + //virtual void flush() = 0; + + /** + * @brief Close the connection + * If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to + * close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an + * error was encountered previously, this function will simply call m_client::stop. + * The implementation for this function can be found in SSLClientImpl::peek. + */ + //virtual void stop() = 0; + + /** + * @brief Check if the device is connected. + * Use this function to determine if SSLClient is still connected and a SSL connection is active. + * It should be noted that SSLClient::availible should be prefered over this function for rapid + * polling--both functions send and recieve data to the Client device, however SSLClient::availible + * has some delays built in to protect the Client device from being polled too frequently. + * + * The implementation for this function can be found in SSLClientImpl::connected. + * + * @returns 1 if connected, 0 if not + */ + //virtual uint8_t connected() = 0; + + //======================================== + //= Functions Not in the Client Interface + //======================================== + /** * @brief Equivalent to SSLClient::connected() > 0 * @returns true if connected, false if not diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 79f8fd8..515d38f 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -353,7 +353,17 @@ int SSLClientImpl::m_run_until(const unsigned target) { if (state != lastState) { lastState = state; m_info("m_run changed state:", func_name); - printState(state); + if(m_debug == DebugLevel::SSL_INFO) { + m_info("State: ", __func__); + if(state == 0) Serial.println(" Invalid"); + else if (state & BR_SSL_CLOSED) Serial.println(" Connection closed"); + else { + if (state & BR_SSL_SENDREC) Serial.println(" SENDREC"); + if (state & BR_SSL_RECVREC) Serial.println(" RECVREC"); + if (state & BR_SSL_SENDAPP) Serial.println(" SENDAPP"); + if (state & BR_SSL_RECVAPP) Serial.println(" RECVAPP"); + } + } } if (state & BR_SSL_RECVREC) { size_t len; diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index b38ebb3..527783d 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -97,188 +97,51 @@ public: explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); - /* functions dealing with read/write that BearSSL will be injected into */ - /** - * @brief Connect over SSL to a host specified by an ip address - * - * SSLClient::connect(host, port) should be preffered over this function, - * as verifying the domain name is a step in ensuring the certificate is - * legitimate, which is important to the security of the device. Additionally, - * SSL sessions cannot be resumed, which can drastically increase initial - * connect time. - * - * This function initializes EthernetClient by calling EthernetClient::connect - * with the parameters supplied, then once the socket is open initializes - * the appropriete bearssl contexts. Due to the design of the SSL standard, - * this function will probably take an extended period (1-4sec) to negotiate - * the handshake and finish the connection. This function runs until the SSL - * handshake succeeds or fails, as found in most Arduino libraries, so be - * sure to design around this in your code. - * - * @pre The underlying client object (passed in through the ctor) in a non- - * error state, and must be able to access the server being connected to. - * @pre SSLCLient can only have one connection at a time, so the client - * object must not already have a socket open. - * @pre There must be sufficient memory availible on the device to verify - * the certificate (if the free memory drops below 8000 bytes during certain - * points in the connection, SSLCLient will fail). - * @pre There must be a trust anchor given to the ctor that corresponds to - * the certificate provided by the IP address being connected to. For more - * information check out the wiki on the pycert-bearssl tool. - * @pre The analog pin passed to the ctor must be set to input, and must - * be wired to something sort of random (floating is fine). - * - * @param ip The ip address to connect to - * @param port the port to connect to - * @returns 1 if success, 0 if failure (as found in EthernetClient) - */ + //============================================ + //= Functions implemented in SSLClientImpl.cpp + //============================================ + + /** @see SSLClient::connect(IPAddress, uint16_t) */ virtual int connect(IPAddress ip, uint16_t port); - - /** - * @brief Connect over SSL using connect(ip, port), using a DNS lookup to - * get the IP Address first. - * - * This function initializes EthernetClient by calling EthernetClient::connect - * with the parameters supplied, then once the socket is open uses BearSSL to - * to complete a SSL handshake. This function runs until the SSL handshake - * succeeds or fails, as found in most Arduino libraries. - * - * SSL requires the client to generate some random bits (to be later combined - * with some random bits from the server), so SSLClient uses the least signinigant - * bits from the analog pin supplied in the ctor. The random bits are generated - * from 16 consecutive analogReads, and given to BearSSL before the handshake - * starts. - * - * Due to the design of the SSL standard, this function will probably take an - * extended period (1-4sec) to negotiate the handshake and finish the - * connection. Since the hostname is provided, however, BearSSL is able to keep - * a session cache of the clients we have connected to. This should reduce - * connection time to about 100-200ms. In order to use this feature, the website - * you are connecting to must support it (most do by default), you must - * reuse the same SSLClient object, and you must reconnect to the same server. - * SSLClient automatcally stores an IP address and hostname in each session, - * ensuring that if you call connect("www.google.com") SSLClient will use a - * cached IP address instead of another DNS lookup. Because some websites have - * multiple servers on a single IP address (github.com is an example), however, - * you may find that even if you are connecting to the same host the connection - * does not resume. This is a flaw in the SSL session protocol, and has been - * resolved in future versions. On top of all that, SSL sessions can expire - * based on server criteria, which will result in a regular connection time. - * Because of all these factors, it is generally prudent to assume the - * connection will not be resumed, and go from there. - * - * @pre The underlying client object (passed in through the ctor) in a non- - * error state, and must be able to access the server being connected to. - * @pre SSLCLient can only have one connection at a time, so the client - * object must not already have a socket open. - * @pre There must be sufficient memory availible on the device to verify - * the certificate (if the free memory drops below 8000 bytes during certain - * points in the connection, SSLCLient will fail). - * @pre There must be a trust anchor given to the ctor that corresponds to - * the certificate provided by the IP address being connected to. For more - * information check out the wiki on the pycert-bearssl tool. - * @pre The analog pin passed to the ctor must be set to input, and must - * be wired to something sort of random (floating is fine). - * - * @param host The cstring host ("www.google.com") - * @param port the port to connect to (443) - * @returns 1 of success, 0 if failure (as found in EthernetClient). - */ + /** @see SSLClient::connect(const char*, uint16_t) */ virtual int connect(const char *host, uint16_t port); - - /** @see SSLClient::write(uint8_t*, size_t) */ + /** @see SSLClient::write(const uint8_t*, size_t) */ virtual size_t write(uint8_t b) { return write(&b, 1); } - /** - * @brief Write some bytes to the SSL connection - * - * Assuming all preconditions are met, this function waits for BearSSL - * to be ready for data to be sent, then writes data to the BearSSL IO - * buffer, BUT does not initally send the data. Insead, it is - * then checked if the BearSSL IO buffer is full, and if so, this function - * waits until BearSSL has flushed the buffer (written it to the - * network client) and fills the buffer again. If the function finds - * that the BearSSL buffer is not full, it returns the number of - * bytes written. In other words, this function will only write data - * to the network if the BearSSL IO buffer is full. Instead, you must call - * SSLClient::availible or SSLClient::flush, which will detect that - * the buffer is ready for writing, and will write the data to the network. - * - * This was implemented as a buffered function because users of Arduino Client - * libraries will often write to the network as such: - * @code{.cpp} - * Client client; - * ... - * client.println("GET /asciilogo.txt HTTP/1.1"); - * client.println("Host: arduino.cc"); - * client.println("Connection: close"); - * while (!client.available()) { ... } - * ... - * @endcode - * This is fine with most network clients. With SSL, however, if we are encryting and - * writing to the network every write() call this will result in a lot of - * small encryption tasks. Encryption takes a lot of time and code, and in general - * the larger the batch we can do it in the better. For this reason, write() - * implicitly buffers until SSLClient::availible is called, or until the buffer is full. - * If you would like to trigger a network write manually without using the SSLClient::available, - * you can also call SSLClient::flush, which will write all data and return when finished. - * - * @pre The socket and SSL layer must be connected, meaning SSLClient::connected must be true. - * @pre BearSSL must not be waiting for the recipt of user data (if it is, there is - * probably an error with how the protocol in implemented in your code). - * - * @param buf the pointer to a buffer of bytes to copy - * @param size the number of bytes to copy from the buffer - * @returns The number of bytes copied to the buffer (size), or zero if the BearSSL engine - * fails to become ready for writing data. - */ + /** @see SSLClient::write(const uint8_t*, size_t) */ virtual size_t write(const uint8_t *buf, size_t size); - - /** - * @brief Returns the number of bytes availible to read from the SSL Socket - * - * This function updates the state of the SSL engine (including writing any data, - * see SSLClient::write) and as a result should be called periodically when writing - * or expecting data. Additionally, since this function returns zero if there are - * no bytes and if SSLClient::connected is false (this same behavior is found - * in EthernetClient), it is prudent to ensure in your own code that the - * preconditions are met before checking this function to prevent an ambigious - * result. - * - * @pre SSLClient::connected must be true. - * - * @returns The number of bytes availible (can be zero), or zero if any of the pre - * conditions aren't satisfied. - */ + /** @see SSLClient::available */ virtual int available(); - /** @see SSLClient::read(uint8_t*, size_t) */ virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; } - /** - * @brief Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. - * - * This function checks if bytes are ready to be read by calling SSLClient::availible, - * and if there are some copies size number of bytes from the IO buffer into buf. - * - * It should be noted that a common problem I encountered with SSL connections is - * buffer overflow, caused by the server sending too much data at once. This problem - * only occurs... - * - * TODO: finish - */ + /** @see SSLClient::read(uint8_t*, size_t) */ virtual int read(uint8_t *buf, size_t size); + /** @see SSLClient::peek */ virtual int peek(); + /** @see SSLClient::flush */ virtual void flush(); + /** @see SSLClient::stop */ virtual void stop(); + /** @see SSLClient::connected */ virtual uint8_t connected(); - // stub virtual functions to get things from the client + //============================================ + //= Functions implemented in SSLClient.h + //============================================ + /** See SSLClient::localPort */ virtual uint16_t localPort() = 0; + /** See SSLClient::remoteIP */ virtual IPAddress remoteIP() = 0; + /** See SSLClient::localPort */ virtual uint16_t remotePort() = 0; - - // as well as store and retrieve session data + /** See SSLClient::getSession */ virtual SSLSession& getSession(const char* host, const IPAddress& addr) = 0; + protected: + + //============================================ + //= Functions implemented in SSLClientImpl.cpp + //============================================ + /** * @brief set the pointer to the Client class that we wil use * @@ -319,19 +182,6 @@ protected: void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); } private: - void printState(unsigned state) const { - if(m_debug == DebugLevel::SSL_INFO) { - m_info("State: ", __func__); - if(state == 0) Serial.println(" Invalid"); - else if (state & BR_SSL_CLOSED) Serial.println(" Connection closed"); - else { - if (state & BR_SSL_SENDREC) Serial.println(" SENDREC"); - if (state & BR_SSL_RECVREC) Serial.println(" RECVREC"); - if (state & BR_SSL_SENDAPP) Serial.println(" SENDAPP"); - if (state & BR_SSL_RECVAPP) Serial.println(" RECVAPP"); - } - } - } /** Returns whether or not the engine is connected, without polling the client over SPI or other (as opposed to connected()) */ bool m_soft_connected(const char* func_name); /** start the ssl engine on the connected client */ @@ -340,6 +190,11 @@ private: int m_run_until(const unsigned target); /** proxy for availble that returns the state */ unsigned m_update_engine(); + + //============================================ + //= Data Members + //============================================ + // hold a reference to the client Client* m_client; // store pointers to the trust anchors @@ -359,6 +214,13 @@ private: // simply edit this value to change the buffer size to the desired value // additionally, we need to correct buffer size based off of how many sessions we decide to cache // since SSL takes so much memory if we don't it will cause the stack and heap to collide + /** + * @brief The internal buffer to use with BearSSL. + * This buffer controls how much data BearSSL can encrypt/decrypt at a given time. It can be expanded + * or shrunk to [255, BR_SSL_BUFSIZE_BIDI], depending on the memory and speed needs of your application. + * As a rule of thumb SSLClient will fail if it does not have at least 8000 bytes when starting a + * connection. + */ unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 4]; static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); // store the index of where we are writing in the buffer From 010ccab4576dcb20804c4686459f7c163466e600 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Fri, 22 Mar 2019 17:42:51 -0700 Subject: [PATCH 031/205] continued creating documentation --- README.md | 56 +++++++++++++++++++++++++++-- TrustAnchors.md | 0 readme/cert.h | 88 +++++++++++++++++++++++++++++++++++++++++++++ src/SSLClientImpl.h | 4 +-- 4 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 TrustAnchors.md create mode 100644 readme/cert.h diff --git a/README.md b/README.md index d20ce29..5f10827 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,53 @@ -# SSLClient -Arduino library to add SSL functionality to any Client class. -Currently work in progress (documentation on the way!). +# SSLClient - Arduino Library For SSL + +**SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.** + +SSLClient is a simple library to add SSL [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. + +## Overview + +Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few things extra things, however, that you will need to get started: + +1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Notes](#Implementation-Notes)). +2. A header containing array of trust anchors, which will look like [this file](./readme/cert.h). These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out [this document](./TrustAnchors.md) on how to generate this file for your project. +3. A Client class associated with a network interface. We tested this library using [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient), however in theory it will work for and class implementing Client. +4. An analog pin, used for generating random data at the start of the connection (see the [Implementation Notes](#Implementation-Notes)). + +Once all those are ready, you can create a simple SSLClient object like this: +```C++ +SSLClient client(BaseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin); +``` +Where: +* BaseClientType - The type of BaseClientInstance +* BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3) +* TAs - The name of the trust anchor array created in step 2. If you generated a header using the tutorial this will probably be `TAs`. +* TAs_NUM - The number of trust anchors in TAs. If you generated a header using the tutorial this will probably be `TAs_NUM`. +* AnalogPin - The analog pin to pull random data from (step 4). + + For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using: + ```C++ +SSLClient client(EthernetClient(), TAs, (size_t)2, A7); + ``` +Once that is setup, simply use SSLClient as you would the base client class: +```C++ +// connect to ardiuino.cc over ssl +client.connect("www.arduino.cc", 443); +// Make a HTTP request +client.println("GET /asciilogo.txt HTTP/1.1"); +client.println("User-Agent: AdafruitFeatherM0WiFi"); +client.print("Host: "); +client.println(server); +client.println("Connection: close"); +client.println(); +client.flush(); +// read and print the data +... +``` + + +### Logging +SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor. +```C++ +SSLClient client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO); +``` + The log levels are Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. diff --git a/TrustAnchors.md b/TrustAnchors.md new file mode 100644 index 0000000..e69de29 diff --git a/readme/cert.h b/readme/cert.h new file mode 100644 index 0000000..365ce0b --- /dev/null +++ b/readme/cert.h @@ -0,0 +1,88 @@ +#ifndef _CERTIFICATES_H_ +#define _CERTIFICATES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. + * Certificates are BearSSL br_x509_trust_anchor format. Included certs: + * + * Index: 0 + * Label: VeriSign Class 3 Public Primary Certification Authority - G5 + * Subject: C=US,O=VeriSign\, Inc.,OU=VeriSign Trust Network,OU=(c) 2006 VeriSign\, Inc. - For authorized use only,CN=VeriSign Class 3 Public Primary Certification Authority - G5 + * Domain(s): www.amazon.com + */ + +#define TAs_NUM 1 + +static const unsigned char TA_DN0[] = { + 0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x31, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x3c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, + 0x35, +}; + +static const unsigned char TA_RSA_N0[] = { + 0xaf, 0x24, 0x08, 0x08, 0x29, 0x7a, 0x35, 0x9e, 0x60, 0x0c, 0xaa, 0xe7, + 0x4b, 0x3b, 0x4e, 0xdc, 0x7c, 0xbc, 0x3c, 0x45, 0x1c, 0xbb, 0x2b, 0xe0, + 0xfe, 0x29, 0x02, 0xf9, 0x57, 0x08, 0xa3, 0x64, 0x85, 0x15, 0x27, 0xf5, + 0xf1, 0xad, 0xc8, 0x31, 0x89, 0x5d, 0x22, 0xe8, 0x2a, 0xaa, 0xa6, 0x42, + 0xb3, 0x8f, 0xf8, 0xb9, 0x55, 0xb7, 0xb1, 0xb7, 0x4b, 0xb3, 0xfe, 0x8f, + 0x7e, 0x07, 0x57, 0xec, 0xef, 0x43, 0xdb, 0x66, 0x62, 0x15, 0x61, 0xcf, + 0x60, 0x0d, 0xa4, 0xd8, 0xde, 0xf8, 0xe0, 0xc3, 0x62, 0x08, 0x3d, 0x54, + 0x13, 0xeb, 0x49, 0xca, 0x59, 0x54, 0x85, 0x26, 0xe5, 0x2b, 0x8f, 0x1b, + 0x9f, 0xeb, 0xf5, 0xa1, 0x91, 0xc2, 0x33, 0x49, 0xd8, 0x43, 0x63, 0x6a, + 0x52, 0x4b, 0xd2, 0x8f, 0xe8, 0x70, 0x51, 0x4d, 0xd1, 0x89, 0x69, 0x7b, + 0xc7, 0x70, 0xf6, 0xb3, 0xdc, 0x12, 0x74, 0xdb, 0x7b, 0x5d, 0x4b, 0x56, + 0xd3, 0x96, 0xbf, 0x15, 0x77, 0xa1, 0xb0, 0xf4, 0xa2, 0x25, 0xf2, 0xaf, + 0x1c, 0x92, 0x67, 0x18, 0xe5, 0xf4, 0x06, 0x04, 0xef, 0x90, 0xb9, 0xe4, + 0x00, 0xe4, 0xdd, 0x3a, 0xb5, 0x19, 0xff, 0x02, 0xba, 0xf4, 0x3c, 0xee, + 0xe0, 0x8b, 0xeb, 0x37, 0x8b, 0xec, 0xf4, 0xd7, 0xac, 0xf2, 0xf6, 0xf0, + 0x3d, 0xaf, 0xdd, 0x75, 0x91, 0x33, 0x19, 0x1d, 0x1c, 0x40, 0xcb, 0x74, + 0x24, 0x19, 0x21, 0x93, 0xd9, 0x14, 0xfe, 0xac, 0x2a, 0x52, 0xc7, 0x8f, + 0xd5, 0x04, 0x49, 0xe4, 0x8d, 0x63, 0x47, 0x88, 0x3c, 0x69, 0x83, 0xcb, + 0xfe, 0x47, 0xbd, 0x2b, 0x7e, 0x4f, 0xc5, 0x95, 0xae, 0x0e, 0x9d, 0xd4, + 0xd1, 0x43, 0xc0, 0x67, 0x73, 0xe3, 0x14, 0x08, 0x7e, 0xe5, 0x3f, 0x9f, + 0x73, 0xb8, 0x33, 0x0a, 0xcf, 0x5d, 0x3f, 0x34, 0x87, 0x96, 0x8a, 0xee, + 0x53, 0xe8, 0x25, 0x15, +}; + +static const unsigned char TA_RSA_E0[] = { + 0x01, 0x00, 0x01, +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef _CERTIFICATES_H_ */ \ No newline at end of file diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 527783d..4e590ff 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -163,8 +163,8 @@ protected: /** @brief debugging print function, only prints if m_debug is true */ template void m_print(const T str, const char* func_name, const DebugLevel level) const { - // check the current debug level - if (level > m_debug) return; + // check the current debug level and serial status + if (level > m_debug || !Serial) return; // print prefix m_print_prefix(func_name, level); // print the message From bd890ae834c14ab9362614413cef27a61e693148 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 24 Mar 2019 16:12:16 -0700 Subject: [PATCH 032/205] continued documenting, saftey commit before tinkering --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++---- src/SSLClient.h | 3 +-- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5f10827..abf4799 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.** -SSLClient is a simple library to add SSL [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. +SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. ## Overview @@ -30,7 +30,7 @@ SSLClient client(EthernetClient(), TAs, (size_t)2, A7); ``` Once that is setup, simply use SSLClient as you would the base client class: ```C++ -// connect to ardiuino.cc over ssl +// connect to ardiuino.cc over ssl (port 443 for websites) client.connect("www.arduino.cc", 443); // Make a HTTP request client.println("GET /asciilogo.txt HTTP/1.1"); @@ -43,11 +43,49 @@ client.flush(); // read and print the data ... ``` +**Note**: `client.connect("www.arduino.cc", 443)` can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in [Implementation Notes](#Implementation-Notes). +For more information on SSLClient, check out the [examples](./examples), [API documentation](./docs/index.html), or the rest of this README. + +## How It Works + +SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](link-here) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, helping debugging be a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint. + +## Implementation Notes + +Some ideas that didn't quite fit in the API documentation. + +### Certificate Verification + +SSLClient uses BearSSL's [minimal x509 verification engine](link-me) to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out [this document](./TrustAnchors.md) for more details on this component of SSLClient. + +### Cipher Support + +SSLClient supports only TLS1.2 and the ciphers listed in [this file under `suites[]`](./src/TLS12_only_profile) by default, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: +```C++ +br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); +// comment the above line and uncomment the line below if you're having trouble connecting over SSL +// br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); +``` +to this: +```C++ +// br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); +// comment the above line and uncomment the line below if you're having trouble connecting over SSL +br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); +``` +If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the [BearSSL Documentation](link-me) and I wish you the best of luck. + +### Resources + +The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive. + +To illustrate this, I will run some tests on various domains below. I haven't yet, but I will. + +If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from `SSLClient.h`, `SSLClientImpl.h`, and `SSLClientImpl.cpp`. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself. ### Logging -SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor. +SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor: ```C++ SSLClient client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO); ``` - The log levels are Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. +Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in [Error](./src/SSLClientImpl.h). The log level is set to `SSL_WARN` by default. \ No newline at end of file diff --git a/src/SSLClient.h b/src/SSLClient.h index d12ff56..e2b00cc 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -130,8 +130,7 @@ public: * the appropriete bearssl contexts. Due to the design of the SSL standard, * this function will probably take an extended period (1-4sec) to negotiate * the handshake and finish the connection. This function runs until the SSL - * handshake succeeds or fails, as found in most Arduino libraries, so be - * sure to design around this in your code. + * handshake succeeds or fails, as found in most Arduino libraries. * * The implementation for this function can be found in SSLClientImpl::connect(IPAddress, uint16_t) * From 843d19bf6c1996ac14e2b04cb335bf03497e5efe Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 24 Mar 2019 16:40:21 -0700 Subject: [PATCH 033/205] refactored a bit, need to refactor more to merge SSLClientImpl with SSLClient to cut down flash footprint and code footprint --- README.md | 3 +++ src/SSLClient.h | 41 ++++++++++++++++++++++------------------- src/SSLClientImpl.cpp | 18 +++++++++--------- src/SSLClientImpl.h | 26 +++++++++++--------------- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index abf4799..977f226 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,9 @@ Some ideas that didn't quite fit in the API documentation. SSLClient uses BearSSL's [minimal x509 verification engine](link-me) to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out [this document](./TrustAnchors.md) for more details on this component of SSLClient. +### Session Caching + + ### Cipher Support SSLClient supports only TLS1.2 and the ciphers listed in [this file under `suites[]`](./src/TLS12_only_profile) by default, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: diff --git a/src/SSLClient.h b/src/SSLClient.h index e2b00cc..19b5d52 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -75,7 +75,7 @@ class SSLClient : public SSLClientImpl { * amount past that will require special modification of this library, and * assumes you know what you are doing. */ -static_assert(std::is_base_of::value, "C must be a Client Class!"); +static_assert(std::is_base_of::value, "SSLClient can only accept a type with base class Client!"); static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!"); static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur."); @@ -132,7 +132,7 @@ public: * the handshake and finish the connection. This function runs until the SSL * handshake succeeds or fails, as found in most Arduino libraries. * - * The implementation for this function can be found in SSLClientImpl::connect(IPAddress, uint16_t) + * The implementation for this function can be found in SSLClientImpl::connect_impl(IPAddress, uint16_t) * * @pre The underlying client object (passed in through the ctor) in a non- * error state, and must be able to access the server being connected to. @@ -151,7 +151,7 @@ public: * @param port the port to connect to * @returns 1 if success, 0 if failure (as found in EthernetClient) */ - // virtual int connect(IPAddress ip, uint16_t port) = 0; + virtual int connect(IPAddress ip, uint16_t port) { return connect_impl(ip, port); } /** * @brief Connect over SSL using connect(ip, port), using a DNS lookup to @@ -186,7 +186,7 @@ public: * Because of all these factors, it is generally prudent to assume the * connection will not be resumed, and go from there. * - * The implementation for this function can be found in SSLClientImpl::connect(const char*, uint16_t) + * The implementation for this function can be found in SSLClientImpl::connect_impl(const char*, uint16_t) * * @pre The underlying client object (passed in through the ctor) in a non- * error state, and must be able to access the server being connected to. @@ -205,10 +205,10 @@ public: * @param port the port to connect to (443) * @returns 1 of success, 0 if failure (as found in EthernetClient). */ - // virtual int connect(const char *host, uint16_t port) = 0; + virtual int connect(const char *host, uint16_t port) { return connect_impl(host, port); } /** @see SSLClient::write(uint8_t*, size_t) */ - // virtual size_t write(uint8_t b) = 0; + virtual size_t write(uint8_t b) { return write_impl(&b, 1); } /** * @brief Write some bytes to the SSL connection * @@ -243,7 +243,7 @@ public: * If you would like to trigger a network write manually without using the SSLClient::available, * you can also call SSLClient::flush, which will write all data and return when finished. * - * The implementation for this function can be found in SSLClientImpl::write(const uint8_t*, size_t) + * The implementation for this function can be found in SSLClientImpl::write_impl(const uint8_t*, size_t) * * @pre The socket and SSL layer must be connected, meaning SSLClient::connected must be true. * @pre BearSSL must not be waiting for the recipt of user data (if it is, there is @@ -254,7 +254,7 @@ public: * @returns The number of bytes copied to the buffer (size), or zero if the BearSSL engine * fails to become ready for writing data. */ - // virtual size_t write(const uint8_t *buf, size_t size) = 0; + virtual size_t write(const uint8_t *buf, size_t size) { return write_impl(buf, size); } /** * @brief Returns the number of bytes availible to read from the SSL Socket @@ -274,10 +274,13 @@ public: * @returns The number of bytes availible (can be zero), or zero if any of the pre * conditions aren't satisfied. */ - //virtual int available() = 0; + virtual int available() { return available_impl(); } - /** @see SSLClient::read(uint8_t*, size_t) */ - //virtual int read() = 0; + /** + * @brief Read a single byte, or -1 if none is available. + * @see SSLClient::read(uint8_t*, size_t) + */ + virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; }; /** * @brief Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. * @@ -314,7 +317,7 @@ public: * Often times there are other ways to get data that we need that do the same thing, * and these other ways may offer smaller and more managable response payloads. * - * The implementation for this function can be found in SSLClientImpl::read(uint8_t*, size_t) + * The implementation for this function can be found in SSLClientImpl::read_impl(uint8_t*, size_t) * * @pre SSLClient::available must be >0 * @@ -323,7 +326,7 @@ public: * * @returns The number of bytes copied (<= size), or -1 if the preconditions are not satisfied. */ - //virtual int read(uint8_t *buf, size_t size) = 0; + virtual int read(uint8_t *buf, size_t size) { return read_impl(buf, size); } /** * @brief view the first byte of the buffer, without removing it from the SSLClient Buffer @@ -332,7 +335,7 @@ public: * @returns The first byte recieved, or -1 if the preconditions are not satisfied (warning: * do not use if your data may be -1, as the return value is ambigious) */ - //virtual int peek() = 0; + virtual int peek() { return peek_impl(); } /** * @brief Force writing the buffered bytes from SSLClient::write to the network. @@ -340,7 +343,7 @@ public: * an explanation of how writing with SSLClient works, please see SSLCLient::write. * The implementation for this function can be found in SSLClientImpl::flush. */ - //virtual void flush() = 0; + virtual void flush() { return flush_impl(); } /** * @brief Close the connection @@ -349,7 +352,7 @@ public: * error was encountered previously, this function will simply call m_client::stop. * The implementation for this function can be found in SSLClientImpl::peek. */ - //virtual void stop() = 0; + virtual void stop() { return stop_impl(); } /** * @brief Check if the device is connected. @@ -358,11 +361,11 @@ public: * polling--both functions send and recieve data to the Client device, however SSLClient::availible * has some delays built in to protect the Client device from being polled too frequently. * - * The implementation for this function can be found in SSLClientImpl::connected. + * The implementation for this function can be found in SSLClientImpl::connected_impl. * * @returns 1 if connected, 0 if not */ - //virtual uint8_t connected() = 0; + virtual uint8_t connected() { return connected_impl(); } //======================================== //= Functions Not in the Client Interface @@ -456,7 +459,7 @@ SSLSession& SSLClient::getSession(const char* host, const IPAdd if (temp_index == m_index && ++m_index >= SessionCache) m_index = 0; // return the pointed to value m_info("Using session index: ", func_name); - Serial.println(temp_index); + m_info(temp_index, func_name); return m_sessions[temp_index]; } diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 515d38f..3e653d8 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -71,7 +71,7 @@ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_a } /* see SSLClientImpl.h*/ -int SSLClientImpl::connect(IPAddress ip, uint16_t port) { +int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { const char* func_name = __func__; // connection check if (m_client->connected()) { @@ -94,7 +94,7 @@ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { } /* see SSLClientImpl.h*/ -int SSLClientImpl::connect(const char *host, uint16_t port) { +int SSLClientImpl::connect_impl(const char *host, uint16_t port) { const char* func_name = __func__; // connection check if (m_client->connected()) { @@ -127,7 +127,7 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { } /** see SSLClientImpl.h*/ -size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { +size_t SSLClientImpl::write_impl(const uint8_t *buf, size_t size) { const char* func_name = __func__; // check if the socket is still open and such if (!m_soft_connected(func_name)) return 0; @@ -164,7 +164,7 @@ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { } /** see SSLClientImpl.h*/ -int SSLClientImpl::available() { +int SSLClientImpl::available_impl() { const char* func_name = __func__; // connection check if (!m_soft_connected(func_name)) return 0; @@ -185,7 +185,7 @@ int SSLClientImpl::available() { } /** see SSLClientImpl.h */ -int SSLClientImpl::read(uint8_t *buf, size_t size) { +int SSLClientImpl::read_impl(uint8_t *buf, size_t size) { // check that the engine is ready to read if (available() <= 0) return -1; // read the buffer, send the ack, and return the bytes read @@ -200,7 +200,7 @@ int SSLClientImpl::read(uint8_t *buf, size_t size) { } /** see SSLClientImpl.h */ -int SSLClientImpl::peek() { +int SSLClientImpl::peek_impl() { // check that the engine is ready to read if (available() <= 0) return -1; // read the buffer, send the ack, and return the bytes read @@ -212,7 +212,7 @@ int SSLClientImpl::peek() { } /** see SSLClientImpl.h*/ -void SSLClientImpl::flush() { +void SSLClientImpl::flush_impl() { // trigger a flush, incase there's any leftover data br_ssl_engine_flush(&m_sslctx.eng, 0); // run until application data is ready for pickup @@ -220,7 +220,7 @@ void SSLClientImpl::flush() { } /** see SSLClientImpl.h*/ -void SSLClientImpl::stop() { +void SSLClientImpl::stop_impl() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); // if the engine isn't closed, and the socket is still open @@ -240,7 +240,7 @@ void SSLClientImpl::stop() { m_client->stop(); } -uint8_t SSLClientImpl::connected() { +uint8_t SSLClientImpl::connected_impl() { const char* func_name = __func__; // check all of the error cases const auto c_con = m_client->connected(); diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 4e590ff..0c29e74 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -31,7 +31,7 @@ * * If SSLClient encounters an error, it will generally output * logs into the serial moniter. If you need a way of programmatically - * checking the errors, you can do so with SSLCLient.getWriteError(), + * checking the errors, you can do so with SSLClient::getWriteError(), * which will return one of these values. */ enum Error { @@ -71,7 +71,7 @@ enum DebugLevel { * On error, any function in this class will terminate the socket. * TODO: Write what this is */ -class SSLClientImpl : public Client { +class SSLClientImpl: public Client { public: /** * @brief initializes SSL contexts for bearSSL @@ -102,27 +102,23 @@ public: //============================================ /** @see SSLClient::connect(IPAddress, uint16_t) */ - virtual int connect(IPAddress ip, uint16_t port); + int connect_impl(IPAddress ip, uint16_t port); /** @see SSLClient::connect(const char*, uint16_t) */ - virtual int connect(const char *host, uint16_t port); + int connect_impl(const char *host, uint16_t port); /** @see SSLClient::write(const uint8_t*, size_t) */ - virtual size_t write(uint8_t b) { return write(&b, 1); } - /** @see SSLClient::write(const uint8_t*, size_t) */ - virtual size_t write(const uint8_t *buf, size_t size); + size_t write_impl(const uint8_t *buf, size_t size); /** @see SSLClient::available */ - virtual int available(); + int available_impl(); /** @see SSLClient::read(uint8_t*, size_t) */ - virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; } - /** @see SSLClient::read(uint8_t*, size_t) */ - virtual int read(uint8_t *buf, size_t size); + int read_impl(uint8_t *buf, size_t size); /** @see SSLClient::peek */ - virtual int peek(); + int peek_impl(); /** @see SSLClient::flush */ - virtual void flush(); + void flush_impl(); /** @see SSLClient::stop */ - virtual void stop(); + void stop_impl(); /** @see SSLClient::connected */ - virtual uint8_t connected(); + uint8_t connected_impl(); //============================================ //= Functions implemented in SSLClient.h From c5790a701298c4b7fe23a6cfa286664b8cc307c2 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 26 Mar 2019 12:54:22 -0700 Subject: [PATCH 034/205] Moved SSLSession stuff to SSLClientImpl --- src/SSLClient.h | 116 ++++++++++++++---------------------------- src/SSLClientImpl.cpp | 89 +++++++++++++++++++++++++------- src/SSLClientImpl.h | 33 ++++++++---- 3 files changed, 131 insertions(+), 107 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 19b5d52..945c59d 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -99,14 +99,13 @@ public: * @param debug whether to enable or disable debug logging, must be constexpr */ explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN) - : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug) + : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, NULL, debug) , m_client(client) , m_sessions{SSLSession()} - , m_index(0) { // since we are copying the client in the ctor, we have to set // the client pointer after the class is constructed - set_client(&m_client); + set_client(&m_client, m_sessions); // set the timeout to a reasonable number (it can always be changes later) // SSL Connections take a really long time so we don't want to time out a legitimate thing setTimeout(10 * 1000); @@ -371,6 +370,38 @@ public: //= Functions Not in the Client Interface //======================================== + /** + * @brief Get a sesssion reference corressponding to a host and IP, or a reference to a emptey session if none exist + * + * If no session corresponding to the host and ip exist, then this function will cycle through + * sessions in a rotating order. This allows the ssession cache to continuially store sessions, + * however it will also result in old sessions being cleared and returned. In general, it is a + * good idea to use a SessionCache size equal to the number of domains you plan on connecting to. + * + * The implementation for this function can be found at SSLClientImpl::get_session_impl. + * + * @param host A hostname c string, or NULL if one is not availible + * @param ip An IP address + * @returns A reference to an SSLSession object + */ + virtual SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); } + + /** + * @brief Clear the session corresponding to a host and IP + * + * The implementation for this function can be found at SSLClientImpl::remove_session_impl. + * + * @param host A hostname c string, or NULL if one is not availible + * @param ip An IP address + */ + virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); } + + /** + * @brief Get the meximum number of SSL sessions that can be stored at once + * @returns The SessionCache template parameter. + */ + virtual size_t getSessionCount() const { return SessionCache; } + /** * @brief Equivalent to SSLClient::connected() > 0 * @returns true if connected, false if not @@ -412,88 +443,15 @@ public: /** @brief returns a refernence to the client object stored in this class. Take care not to break it. */ C& getClient() { return m_client; } - /** - * @brief Get a sesssion reference corressponding to a host and IP, or a reference to a emptey session if none exist - * - * If no session corresponding to the host and ip exist, then this function will cycle through - * sessions in a rotating order. This allows the ssession cache to continuially store sessions, - * however it will also result in old sessions being cleared and returned. In general, it is a - * good idea to use a SessionCache size equal to the number of domains you plan on connecting to. - * - * @param host A hostname c string, or NULL if one is not availible - * @param ip An IP address - * @returns A reference to an SSLSession object - */ - virtual SSLSession& getSession(const char* host, const IPAddress& addr); +protected: + //virtual Client& get_arduino_client() { return m_client; } + //virtual SSLSession* get_session_array() { return m_sessions; } - /** - * @brief Clear the session corresponding to a host and IP - * - * @param host A hostname c string, or NULL if one is not availible - * @param ip An IP address - */ - virtual void removeSession(const char* host, const IPAddress& addr); private: - // utility function to find a session index based off of a host and IP - int m_getSessionIndex(const char* host, const IPAddress& addr) const; // create a copy of the client C m_client; // also store an array of SSLSessions, so we can resume communication with multiple websites SSLSession m_sessions[SessionCache]; - // store an index of where a new session can be placed if we don't have any corresponding sessions - size_t m_index; }; -template -SSLSession& SSLClient::getSession(const char* host, const IPAddress& addr) { - const char* func_name = __func__; - // search for a matching session with the IP - int temp_index = m_getSessionIndex(host, addr); - // if none are availible, use m_index - if (temp_index == -1) { - temp_index = m_index; - // reset the session so we don't try to send one sites session to another - m_sessions[temp_index].clear_parameters(); - } - // increment m_index so the session cache is a circular buffer - if (temp_index == m_index && ++m_index >= SessionCache) m_index = 0; - // return the pointed to value - m_info("Using session index: ", func_name); - m_info(temp_index, func_name); - return m_sessions[temp_index]; -} - -template -void SSLClient::removeSession(const char* host, const IPAddress& addr) { - const char* func_name = __func__; - int temp_index = m_getSessionIndex(host, addr); - if (temp_index != -1) { - m_info(" Deleted session ", func_name); - m_info(temp_index, func_name); - m_sessions[temp_index].clear_parameters(); - } -} - -template -int SSLClient::m_getSessionIndex(const char* host, const IPAddress& addr) const { - const char* func_name = __func__; - // search for a matching session with the IP - for (uint8_t i = 0; i < SessionCache; i++) { - // if we're looking at a real session - if (m_sessions[i].is_valid_session() - && ( - // and the hostname matches, or - (host != NULL && m_sessions[i].get_hostname().equals(host)) - // there is no hostname and the IP address matches - || (host == NULL && addr == m_sessions[i].get_ip()) - )) { - m_info("Found session match: ", func_name); - m_info(m_sessions[i].get_hostname(), func_name); - return i; - } - } - // none found - return -1; -} - #endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 3e653d8..6453eba 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -51,11 +51,14 @@ static int freeMemory() { /** see SSLClientImpl.h */ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) + const size_t trust_anchors_num, const int analog_pin, SSLSession* session_ray, + const DebugLevel debug) : m_client(client) , m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) , m_analog_pin(analog_pin) + , m_session_ptr(session_ray) + , m_session_index(0) , m_debug(debug) , m_write_idx(0) { @@ -90,7 +93,7 @@ int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { return 0; } m_info("Base client connected!", func_name); - return m_start_ssl(NULL, getSession(NULL, ip)); + return m_start_ssl(NULL, get_session_impl(NULL, ip)); } /* see SSLClientImpl.h*/ @@ -106,7 +109,7 @@ int SSLClientImpl::connect_impl(const char *host, uint16_t port) { // first, if we have a session, check if we're trying to resolve the same host // as before bool connect_ok; - SSLSession& ses = getSession(host, INADDR_NONE); + SSLSession& ses = get_session_impl(host, INADDR_NONE); if (ses.is_valid_session()) { // if so, then connect using the stored session m_info("Connecting using a cached IP", func_name); @@ -187,7 +190,7 @@ int SSLClientImpl::available_impl() { /** see SSLClientImpl.h */ int SSLClientImpl::read_impl(uint8_t *buf, size_t size) { // check that the engine is ready to read - if (available() <= 0) return -1; + if (available_impl() <= 0) return -1; // read the buffer, send the ack, and return the bytes read size_t alen; unsigned char* br_buf = br_ssl_engine_recvapp_buf(&m_sslctx.eng, &alen); @@ -202,7 +205,7 @@ int SSLClientImpl::read_impl(uint8_t *buf, size_t size) { /** see SSLClientImpl.h */ int SSLClientImpl::peek_impl() { // check that the engine is ready to read - if (available() <= 0) return -1; + if (available_impl() <= 0) return -1; // read the buffer, send the ack, and return the bytes read size_t alen; uint8_t read_num; @@ -211,7 +214,7 @@ int SSLClientImpl::peek_impl() { return (int)read_num; } -/** see SSLClientImpl.h*/ +/** see SSLClientImpl.h */ void SSLClientImpl::flush_impl() { // trigger a flush, incase there's any leftover data br_ssl_engine_flush(&m_sslctx.eng, 0); @@ -219,7 +222,7 @@ void SSLClientImpl::flush_impl() { if(m_run_until(BR_SSL_RECVAPP) < 0) m_error("Could not flush write buffer!", __func__); } -/** see SSLClientImpl.h*/ +/** see SSLClientImpl.h */ void SSLClientImpl::stop_impl() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); @@ -240,6 +243,7 @@ void SSLClientImpl::stop_impl() { m_client->stop(); } +/** see SSLClientImpl.h */ uint8_t SSLClientImpl::connected_impl() { const char* func_name = __func__; // check all of the error cases @@ -257,7 +261,7 @@ uint8_t SSLClientImpl::connected_impl() { else m_warn("Socket was dropped unexpectedly (this can be an alternative to closing the connection)", func_name); // set the write error so the engine doesn't try to close the connection setWriteError(SSL_CLIENT_WRTIE_ERROR); - stop(); + stop_impl(); } else if (!wr_ok) { m_error("Not connected because write error is set", func_name); @@ -265,6 +269,36 @@ uint8_t SSLClientImpl::connected_impl() { return c_con && br_con && wr_ok; } +/** see SSLClientImpl.h */ +SSLSession& SSLClientImpl::get_session_impl(const char* host, const IPAddress& addr) { + const char* func_name = __func__; + // search for a matching session with the IP + int temp_index = m_get_session_index(host, addr); + // if none are availible, use m_session_index + if (temp_index == -1) { + temp_index = m_session_index; + // reset the session so we don't try to send one sites session to another + m_session_ptr[temp_index].clear_parameters(); + } + // increment m_session_index so the session cache is a circular buffer + if (temp_index == m_session_index && ++m_session_index >= getSessionCount()) m_session_index = 0; + // return the pointed to value + m_info("Using session index: ", func_name); + m_info(temp_index, func_name); + return m_session_ptr[temp_index]; +} + +/** see SSLClientImpl.h */ +void SSLClientImpl::remove_session_impl(const char* host, const IPAddress& addr) { + const char* func_name = __func__; + int temp_index = m_get_session_index(host, addr); + if (temp_index != -1) { + m_info(" Deleted session ", func_name); + m_info(temp_index, func_name); + m_session_ptr[temp_index].clear_parameters(); + } +} + bool SSLClientImpl::m_soft_connected(const char* func_name) { // check if the socket is still open and such if (getWriteError()) { @@ -346,7 +380,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { if (millis() - start > getTimeout()) { m_error("SSL internals timed out! This could be an internal error or bad data sent from the server", func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop(); + stop_impl(); return -1; } // debug @@ -399,7 +433,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { else { m_error("SSL engine state is RECVAPP, however the buffer was null! (This is a problem with BearSSL internals)", func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop(); + stop_impl(); return -1; } } @@ -446,7 +480,7 @@ unsigned SSLClientImpl::m_update_engine() { * wait for it. */ if (!&m_sslctx.eng.shutdown_recv) return 0; - stop(); + stop_impl(); return 0; } if (wlen > 0) { @@ -465,7 +499,7 @@ unsigned SSLClientImpl::m_update_engine() { if (!(state & BR_SSL_SENDAPP)) { m_error("Error m_write_idx > 0 but the ssl engine is not ready for data", func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop(); + stop_impl(); return 0; } // else time to send the application data @@ -476,14 +510,14 @@ unsigned SSLClientImpl::m_update_engine() { if (alen == 0 || buf == NULL) { m_error("Engine set write flag but returned null buffer", func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop(); + stop_impl(); return 0; } // sanity check if (alen < m_write_idx) { m_error("Alen is less than m_write_idx", func_name); setWriteError(SSL_INTERNAL_ERROR); - stop(); + stop_impl(); return 0; } // all good? lets send the data @@ -510,7 +544,7 @@ unsigned SSLClientImpl::m_update_engine() { unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? const auto avail = m_client->available(); - if (avail >= len) { + if (avail > 0 && avail >= len) { int mem = freeMemory(); // check for a stack overflow // if the stack overflows we basically have to crash, and @@ -531,7 +565,7 @@ unsigned SSLClientImpl::m_update_engine() { if(mem < 8000) { m_error("Out of memory! Decrease the number of sessions or the size of m_iobuf", func_name); setWriteError(SSL_OUT_OF_MEMORY); - stop(); + stop_impl(); return 0; } m_info("Read bytes from client: ", func_name); @@ -543,7 +577,7 @@ unsigned SSLClientImpl::m_update_engine() { m_error("Error reading bytes from m_client. Write Error: ", func_name); m_error(m_client->getWriteError(), func_name); setWriteError(SSL_CLIENT_WRTIE_ERROR); - stop(); + stop_impl(); return 0; } if (rlen > 0) { @@ -568,6 +602,27 @@ unsigned SSLClientImpl::m_update_engine() { } } +/** see SSLClientImpl.h */ +int SSLClientImpl::m_get_session_index(const char* host, const IPAddress& addr) const { + const char* func_name = __func__; + // search for a matching session with the IP + for (uint8_t i = 0; i < getSessionCount(); i++) { + // if we're looking at a real session + if (m_session_ptr[i].is_valid_session() + && ( + // and the hostname matches, or + (host != NULL && m_session_ptr[i].get_hostname().equals(host)) + // there is no hostname and the IP address matches + || (host == NULL && addr == m_session_ptr[i].get_ip()) + )) { + m_info("Found session match: ", func_name); + m_info(m_session_ptr[i].get_hostname(), func_name); + return i; + } + } + // none found + return -1; +} /** See SSLClientImpl.h */ void SSLClientImpl::m_print_prefix(const char* func_name, const DebugLevel level) const diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 0c29e74..e5a9069 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -71,7 +71,7 @@ enum DebugLevel { * On error, any function in this class will terminate the socket. * TODO: Write what this is */ -class SSLClientImpl: public Client { +class SSLClientImpl : public Client { public: /** * @brief initializes SSL contexts for bearSSL @@ -80,22 +80,23 @@ public: * based off of the domains you want to make SSL connections to. Check out the * Wiki on the pycert-bearssl tool for a simple way to do this. * @pre The analog_pin should be set to input. + * @pre The session_ray must be an array of the size returned by SSLClient::getSessionCount() + * filled with SSLSession objects. * * @post set_client must be called immediatly after to set the client class - * pointer. + * pointer and Session pointer. * * @param trust_anchors Trust anchors used in the verification * of the SSL server certificate, generated using the `brssl` command * line utility. For more information see the samples or bearssl.org * @param trust_anchors_num The number of trust anchors stored * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG - * @param get_remote_ip Function pointer to get the remote ip from the client. We - * need this value since the Client abstract class has no remoteIP() function, - * however most of the arduino internet client implementations do. + * @param session_ray A pointer to the array of SSLSessions created by SSLClient * @param debug whether to enable or disable debug logging, must be constexpr */ explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); + const size_t trust_anchors_num, const int analog_pin, SSLSession* session_ray, + const DebugLevel debug); //============================================ //= Functions implemented in SSLClientImpl.cpp @@ -119,6 +120,10 @@ public: void stop_impl(); /** @see SSLClient::connected */ uint8_t connected_impl(); + /** See SSLClient::getSession */ + SSLSession& get_session_impl(const char* host, const IPAddress& addr); + /** See SSLClient::removeSession */ + void remove_session_impl(const char* host, const IPAddress& addr); //============================================ //= Functions implemented in SSLClient.h @@ -129,11 +134,10 @@ public: virtual IPAddress remoteIP() = 0; /** See SSLClient::localPort */ virtual uint16_t remotePort() = 0; - /** See SSLClient::getSession */ - virtual SSLSession& getSession(const char* host, const IPAddress& addr) = 0; + /** See SSLClient::getSessionCount */ + virtual size_t getSessionCount() const = 0; protected: - //============================================ //= Functions implemented in SSLClientImpl.cpp //============================================ @@ -145,7 +149,7 @@ protected: * is placed in it's own function for flexibility reasons, but it * is critical that this function is called before anything else */ - void set_client(Client* c) { m_client = c; } + void set_client(Client* c, SSLSession* sessions) { m_client = c; m_session_ptr = sessions; } /** @brief Prints a debugging prefix to all logs, so we can attatch them to useful information */ void m_print_prefix(const char* func_name, const DebugLevel level) const; @@ -185,7 +189,9 @@ private: /** run the bearssl engine until a certain state */ int m_run_until(const unsigned target); /** proxy for availble that returns the state */ - unsigned m_update_engine(); + unsigned m_update_engine(); + /** utility function to find a session index based off of a host and IP */ + int m_get_session_index(const char* host, const IPAddress& addr) const; //============================================ //= Data Members @@ -199,6 +205,11 @@ private: const size_t m_trust_anchors_num; // store the pin to fetch an RNG see from const int m_analog_pin; + // store a pointer to the SSL Session array, since it's size + // is deduced at compile time + SSLSession* m_session_ptr; + // store an index of where a new session can be placed if we don't have any corresponding sessions + size_t m_session_index; // store whether to enable debug logging const DebugLevel m_debug; // store the context values required for SSL From cd94d0bf3bd8e6445981b29f603158766249bc36 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 26 Mar 2019 13:19:56 -0700 Subject: [PATCH 035/205] refatored to use a better system for passing object up the inheritance heirchy --- src/SSLClient.h | 13 ++++++----- src/SSLClientImpl.cpp | 53 ++++++++++++++++++++----------------------- src/SSLClientImpl.h | 26 ++++++++------------- 3 files changed, 41 insertions(+), 51 deletions(-) diff --git a/src/SSLClient.h b/src/SSLClient.h index 945c59d..0155339 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -99,13 +99,10 @@ public: * @param debug whether to enable or disable debug logging, must be constexpr */ explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN) - : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, NULL, debug) + : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) , m_sessions{SSLSession()} { - // since we are copying the client in the ctor, we have to set - // the client pointer after the class is constructed - set_client(&m_client, m_sessions); // set the timeout to a reasonable number (it can always be changes later) // SSL Connections take a really long time so we don't want to time out a legitimate thing setTimeout(10 * 1000); @@ -444,8 +441,12 @@ public: C& getClient() { return m_client; } protected: - //virtual Client& get_arduino_client() { return m_client; } - //virtual SSLSession* get_session_array() { return m_sessions; } + /** @brief return an instance of m_client that is polymorphic and can be used by SSLClientImpl */ + virtual Client& get_arduino_client() { return m_client; } + virtual const Client& get_arduino_client() const { return m_client; } + /** @brief return an instance of the session array that is on the stack */ + virtual SSLSession* get_session_array() { return m_sessions; } + virtual const SSLSession* get_session_array() const { return m_sessions; } private: // create a copy of the client diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 6453eba..1c1fcce 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -50,14 +50,11 @@ static int freeMemory() { } /** see SSLClientImpl.h */ -SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, SSLSession* session_ray, - const DebugLevel debug) - : m_client(client) - , m_trust_anchors(trust_anchors) +SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) + : m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) , m_analog_pin(analog_pin) - , m_session_ptr(session_ray) , m_session_index(0) , m_debug(debug) , m_write_idx(0) { @@ -77,7 +74,7 @@ SSLClientImpl::SSLClientImpl(Client *client, const br_x509_trust_anchor *trust_a int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { const char* func_name = __func__; // connection check - if (m_client->connected()) { + if (get_arduino_client().connected()) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } @@ -87,7 +84,7 @@ int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { m_warn("Using a raw IP Address for an SSL connection bypasses some important verification steps. You should use a domain name (www.google.com) whenever possible.", func_name); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. - if (!m_client->connect(ip, port)) { + if (!get_arduino_client().connect(ip, port)) { m_error("Failed to connect using m_client. Are you connected to the internet?", func_name); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; @@ -100,7 +97,7 @@ int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { int SSLClientImpl::connect_impl(const char *host, uint16_t port) { const char* func_name = __func__; // connection check - if (m_client->connected()) { + if (get_arduino_client().connected()) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } @@ -113,10 +110,10 @@ int SSLClientImpl::connect_impl(const char *host, uint16_t port) { if (ses.is_valid_session()) { // if so, then connect using the stored session m_info("Connecting using a cached IP", func_name); - connect_ok = m_client->connect(ses.get_ip(), port); + connect_ok = get_arduino_client().connect(ses.get_ip(), port); } // else connect with the provided hostname - else connect_ok = m_client->connect(host, port); + else connect_ok = get_arduino_client().connect(host, port); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!connect_ok) { @@ -240,22 +237,22 @@ void SSLClientImpl::stop_impl() { } } // close the ethernet socket - m_client->stop(); + get_arduino_client().stop(); } /** see SSLClientImpl.h */ uint8_t SSLClientImpl::connected_impl() { const char* func_name = __func__; // check all of the error cases - const auto c_con = m_client->connected(); + const auto c_con = get_arduino_client().connected(); const auto br_con = br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED; const auto wr_ok = getWriteError() == 0; // if we're in an error state, close the connection and set a write error if (br_con && !c_con) { // If we've got a write error, the client probably failed for some reason - if (m_client->getWriteError()) { + if (get_arduino_client().getWriteError()) { m_error("Socket was unexpectedly interrupted. m_client error: ", func_name); - m_error(m_client->getWriteError(), func_name); + m_error(get_arduino_client().getWriteError(), func_name); } // Else tell the user the endpoint closed the socket on us (ouch) else m_warn("Socket was dropped unexpectedly (this can be an alternative to closing the connection)", func_name); @@ -278,14 +275,14 @@ SSLSession& SSLClientImpl::get_session_impl(const char* host, const IPAddress& a if (temp_index == -1) { temp_index = m_session_index; // reset the session so we don't try to send one sites session to another - m_session_ptr[temp_index].clear_parameters(); + get_session_array()[temp_index].clear_parameters(); } // increment m_session_index so the session cache is a circular buffer if (temp_index == m_session_index && ++m_session_index >= getSessionCount()) m_session_index = 0; // return the pointed to value m_info("Using session index: ", func_name); m_info(temp_index, func_name); - return m_session_ptr[temp_index]; + return get_session_array()[temp_index]; } /** see SSLClientImpl.h */ @@ -295,7 +292,7 @@ void SSLClientImpl::remove_session_impl(const char* host, const IPAddress& addr) if (temp_index != -1) { m_info(" Deleted session ", func_name); m_info(temp_index, func_name); - m_session_ptr[temp_index].clear_parameters(); + get_session_array()[temp_index].clear_parameters(); } } @@ -466,11 +463,11 @@ unsigned SSLClientImpl::m_update_engine() { int wlen; buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); - wlen = m_client->write(buf, len); + wlen = get_arduino_client().write(buf, len); // let the chip recover if (wlen < 0) { m_error("Error writing to m_client", func_name); - m_error(m_client->getWriteError(), func_name); + m_error(get_arduino_client().getWriteError(), func_name); setWriteError(SSL_CLIENT_WRTIE_ERROR); /* * If we received a close_notify and we @@ -543,7 +540,7 @@ unsigned SSLClientImpl::m_update_engine() { size_t len; unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? - const auto avail = m_client->available(); + const auto avail = get_arduino_client().available(); if (avail > 0 && avail >= len) { int mem = freeMemory(); // check for a stack overflow @@ -572,10 +569,10 @@ unsigned SSLClientImpl::m_update_engine() { m_info(avail, func_name); m_info(len, func_name); // I suppose so! - int rlen = m_client->read(buf, len); + int rlen = get_arduino_client().read(buf, len); if (rlen <= 0) { m_error("Error reading bytes from m_client. Write Error: ", func_name); - m_error(m_client->getWriteError(), func_name); + m_error(get_arduino_client().getWriteError(), func_name); setWriteError(SSL_CLIENT_WRTIE_ERROR); stop_impl(); return 0; @@ -591,7 +588,7 @@ unsigned SSLClientImpl::m_update_engine() { // m_print(avail); // m_print("Bytes needed: "); // m_print(len); - // add a delay since spamming m_client->availible breaks the poor wiz chip + // add a delay since spamming get_arduino_client().availible breaks the poor wiz chip delay(10); return state; } @@ -608,15 +605,15 @@ int SSLClientImpl::m_get_session_index(const char* host, const IPAddress& addr) // search for a matching session with the IP for (uint8_t i = 0; i < getSessionCount(); i++) { // if we're looking at a real session - if (m_session_ptr[i].is_valid_session() + if (get_session_array()[i].is_valid_session() && ( // and the hostname matches, or - (host != NULL && m_session_ptr[i].get_hostname().equals(host)) + (host != NULL && get_session_array()[i].get_hostname().equals(host)) // there is no hostname and the IP address matches - || (host == NULL && addr == m_session_ptr[i].get_ip()) + || (host == NULL && addr == get_session_array()[i].get_ip()) )) { m_info("Found session match: ", func_name); - m_info(m_session_ptr[i].get_hostname(), func_name); + m_info(get_session_array()[i].get_hostname(), func_name); return i; } } diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index e5a9069..e4ffc5d 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -94,9 +94,8 @@ public: * @param session_ray A pointer to the array of SSLSessions created by SSLClient * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, SSLSession* session_ray, - const DebugLevel debug); + explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); //============================================ //= Functions implemented in SSLClientImpl.cpp @@ -138,19 +137,17 @@ public: virtual size_t getSessionCount() const = 0; protected: + /** See SSLClient::get_arduino_client */ + virtual Client& get_arduino_client() = 0; + virtual const Client& get_arduino_client() const = 0; + /** See SSLClient::get_session_array */ + virtual SSLSession* get_session_array() = 0; + virtual const SSLSession* get_session_array() const = 0; + //============================================ //= Functions implemented in SSLClientImpl.cpp //============================================ - /** - * @brief set the pointer to the Client class that we wil use - * - * Call this function immediatly after the ctor. This functionality - * is placed in it's own function for flexibility reasons, but it - * is critical that this function is called before anything else - */ - void set_client(Client* c, SSLSession* sessions) { m_client = c; m_session_ptr = sessions; } - /** @brief Prints a debugging prefix to all logs, so we can attatch them to useful information */ void m_print_prefix(const char* func_name, const DebugLevel level) const; @@ -197,17 +194,12 @@ private: //= Data Members //============================================ - // hold a reference to the client - Client* m_client; // store pointers to the trust anchors // should not be computed at runtime const br_x509_trust_anchor *m_trust_anchors; const size_t m_trust_anchors_num; // store the pin to fetch an RNG see from const int m_analog_pin; - // store a pointer to the SSL Session array, since it's size - // is deduced at compile time - SSLSession* m_session_ptr; // store an index of where a new session can be placed if we don't have any corresponding sessions size_t m_session_index; // store whether to enable debug logging From 648104c7e3a01c284f5496238095658f1a6ac6ae Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 31 Mar 2019 12:55:58 -0700 Subject: [PATCH 036/205] almost finished documenting, moved SSLSession implementation into it's own file, fixed infinite loop when overflowing m_iobuf --- README.md | 88 ++++++--- TrustAnchors.md | 61 ++++++ src/SSLClient.h | 260 ++++++++----------------- src/SSLClientImpl.cpp | 10 +- src/SSLClientImpl.h | 39 +--- src/SSLSession.cpp | 24 +++ src/SSLSession.h | 25 +-- tools/pycert_bearssl/pycert_bearssl.py | 8 +- 8 files changed, 265 insertions(+), 250 deletions(-) create mode 100644 src/SSLSession.cpp diff --git a/README.md b/README.md index 977f226..ff16827 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Where: For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using: ```C++ -SSLClient client(EthernetClient(), TAs, (size_t)2, A7); +SSLClient client(EthernetClient(), TAs, 2, A7); ``` Once that is setup, simply use SSLClient as you would the base client class: ```C++ @@ -49,22 +49,79 @@ For more information on SSLClient, check out the [examples](./examples), [API do ## How It Works -SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](link-here) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, helping debugging be a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint. +SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](https://bearssl.org/) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, helping debugging be a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint. -## Implementation Notes +Additionally, the bulk of SSLClient is split into two components: a template class [SSLClient](./src/SSLClient.h), and an implementation class [SSLClientImpl](./src/SSLClientImpl.h). The template class serves to abstract some functions not implemented in the Arduino Client interface (such as `EthernetClient::remoteIP`), and the implementation class is the rest of the SSLClient library. + +## Other Features + +### Logging +SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor: +```C++ +SSLClient client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO); +``` +Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in [Error](./src/SSLClientImpl.h). The log level is set to `SSL_WARN` by default. + +### Errors +When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from `SSLClient::getWriteError()`, which will return a value from [this enumeration](link-me). For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at `SSL_ERROR` or lower. + +### Write Buffering +As you may have noticed in the documentation for [SSLClient::write](link-me), calling this function does not actually write to the network. Instead, you must call [SSLClient::available](link-me) or [SSLClient::flush](link-me), which will detect that the buffer is ready and write to the network (see [SSLClient::write](link-me) for details). + +This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so: +```C++ +EthernetClient client; +// ... +client.println("GET /asciilogo.txt HTTP/1.1"); +client.println("Host: arduino.cc"); +client.println("Connection: close"); +while (!client.available()) { /* ... */ } +// ... +``` +This is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, and so to reduce the overhead of an SSL connection SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. + +If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished. + +### Session Caching +As detailed in the [resources section](#resources), SSL handshakes take an extended period (1-4sec) to negotiate. To remedy this problem, BearSSL is able to keep a [SSL session cache](https://bearssl.org/api1.html#session-cache) of the clients it has connected to. If BearSSL successfully resumes an SSL session, it can reduce connection time to 100-500ms. + +In order to use SSL session resumption: + * The website you are connecting to must support it. Support is widespread, but you can verify easily using the [SSLLabs tool](https://www.ssllabs.com/ssltest/). + * you must reuse the same SSLClient object (SSL Sessions are stored in the object itself). + * you must reconnect to the exact same server. + +SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with `"www.google.com"`. Because some websites have multiple servers on a single IP address (github.com is an example), however, you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol, and has been resolved in future versions. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection. + +You can test whether or not a website can resume SSL Sessions using the [Session Example](./examples/Session_Example/Session_Example.ino) included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume. + +## Implementation Gotchas Some ideas that didn't quite fit in the API documentation. ### Certificate Verification -SSLClient uses BearSSL's [minimal x509 verification engine](link-me) to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out [this document](./TrustAnchors.md) for more details on this component of SSLClient. +SSLClient uses BearSSL's [minimal x509 verification engine](https://bearssl.org/x509.html#the-minimal-engine) to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out [this document](./TrustAnchors.md) for more details on this component of SSLClient. -### Session Caching +BearSSL also features a [known certificate validation engine](https://bearssl.org/x509.html#the-known-key-engine), which only allows for a single domain in exchange for a significantly reduced resource usage (flash and CPU time). This functionality is planned to be implemented in the future. +### Resources +The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive. + +To illustrate this, I will run some tests on various domains below. I haven't yet, but I will. + +If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from `SSLClient.h`, `SSLClientImpl.h`, and `SSLClientImpl.cpp`. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself. + +### Read Buffer Overflow +SSL is a buffered protocol, and since most microcontrollers have limited resources (see [Resources](#resources)), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow, caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received, forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems, this could be the reason why. + +In order to remedy this problem, the device must be able to read the data faster than it is being received, or alternatively have a cache large enough to store the entire payload. Since SSL's encryption forces the device to read slowly, this means we must increase the cache size. Depending on your platform, there are a number of ways this can be done: +* Sometimes your communication shield will have an internal buffer, which can be expanded through the driver code. This is the case with the Arduino Ethernet library (in the form of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be modified for the change to take effect. +* SSLClient has an internal buffer SSLClientImpl::m_iobuf, which can be expanded. BearSSL limits the amount of data that can be processed based on the stage in the SSL handshake, and so this will change will have limited usefulness. +* In some cases, a website will send so much data that even with the above solutions SSLClient will be unable to keep up (a website with a lot of HTML is an example). In these cases you will have to find another method of retrieving the data you need. +* If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM. ### Cipher Support - -SSLClient supports only TLS1.2 and the ciphers listed in [this file under `suites[]`](./src/TLS12_only_profile) by default, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: +SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile) under `suites[]` by default, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: ```C++ br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // comment the above line and uncomment the line below if you're having trouble connecting over SSL @@ -76,19 +133,4 @@ to this: // comment the above line and uncomment the line below if you're having trouble connecting over SSL br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); ``` -If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the [BearSSL Documentation](link-me) and I wish you the best of luck. - -### Resources - -The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive. - -To illustrate this, I will run some tests on various domains below. I haven't yet, but I will. - -If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from `SSLClient.h`, `SSLClientImpl.h`, and `SSLClientImpl.cpp`. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself. - -### Logging -SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor: -```C++ -SSLClient client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO); -``` -Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in [Error](./src/SSLClientImpl.h). The log level is set to `SSL_WARN` by default. \ No newline at end of file +If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the [BearSSL profiles documentation](https://bearssl.org/api1.html#profiles) and I wish you the best of luck. \ No newline at end of file diff --git a/TrustAnchors.md b/TrustAnchors.md index e69de29..851e626 100644 --- a/TrustAnchors.md +++ b/TrustAnchors.md @@ -0,0 +1,61 @@ +# Trust Anchors + +SSLClient uses BearSSL's [minimal x509 verification engine](https://bearssl.org/x509.html#the-minimal-engine) to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. In short, these trust anchor arrays allow BearSSL to verify that the server being connected to is who they say they are, and not someone malicious. You can read more about certificates and why they are important [here](https://www.globalsign.com/en/ssl-information-center/what-is-an-ssl-certificate/). + +SSLClient stores trust anchors in hardcoded constant variables, passed into `SSLClient::SSLClient` during setup. These constants are generally stored in their own header file as found in [the BearSSL docs](https://bearssl.org/api1.html#profiles). This header file will look something like: +```C++ +#define TAs_NUM 1 + +static const unsigned char TA_DN0[] = { + // lots of raw bytes here + // ... +}; + +static const unsigned char TA_RSA_N0[] = { + // lots of raw bytes here + //... +}; + +static const unsigned char TA_RSA_E0[] = { + // 1-3 bytes here +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, +}; +``` +A full example of a trust anchor header can be found in [this file](./readme/cert.h). Full documentation for the format of these variables can be found in the [BearSSL documentation for br_x509_trust_anchor](https://bearssl.org/apidoc/structbr__x509__trust__anchor.html). + +## Generating Trust Anchors + +### HTTPS + +For HTTPS, there a couple of tools you can use. Ordered from easy to hard: +* [This website, written to simplify the creation of trust anchor headers](https://openslab-osu.github.io/bearssl-certificate-utility/). Simply plug and play. +* [pycert_bearssl](./tools/pycert_bearssl/pycert_bearssl.py), a command line utility based on a [pycert](https://learn.adafruit.com/introducing-the-adafruit-wiced-feather-wifi/pycert-dot-py). You will need to install Python 3, and follow the instructions in the [pycert_bearssl.py file](./tools/pycert_bearssl/pycert_bearssl.py). You'll want to use the `pycert_bearssl.py download` command once the utility is set up. +* The brssl command line utility, included in the [BearSSL source](https://bearssl.org/gitweb/?p=BearSSL;a=blob_plain;f=tools/brssl.h;hb=HEAD). You will need to compile this file yourself. + +### Other Connections + +For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out [this StackExchange post](https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file) for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use [this website](https://www.sslshopper.com/ssl-converter.html)), and use the `pycert_bearssl.py convert` command to convert the certificate into a trust anchor header. + +## Using Trust Anchors + +Once you've generated a trust anchor array, add it to your Arduino sketch using the `Sketch->Add File` button in the Arduino IDE, and link it to your SSLClient like so: +```C++ +#include "yourtrustanchorfile.h" +// ... +SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin); +// ... +``` +Where `yourtrustanchorfile.h` contains a generated trust anchor array names `TAs`, with length `TAs_NUM`. BearSSL will now automatically use these trust anchors when `SSLClient::connect` is called. \ No newline at end of file diff --git a/src/SSLClient.h b/src/SSLClient.h index 0155339..6c06c8c 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -18,20 +18,6 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/** - * SSLCLient.h - * - * This library was created to provide SSL functionality to the {@link https://learn.adafruit.com/adafruit-wiz5500-wiznet-ethernet-featherwing/overview} - * Adafruit Ethernet shield. Since this shield does not implement SSL functionality on - * its own, we need to use an external library: in this case BearSSL {@link https://bearssl.org/}, - * which is also used in the Arduino ESP8266 core. SSLClient will serve to implement the - * BearSSL functionality inbetween EthernetClient and the User, such that the user. - * - * This file specifically controls the class templating used to allow SSLClient to interface - * with all of the CLient-based classes. To see details on the implementations of the functions - * in SSLClient, please see {@link ./SSLClientImpl.h}. - */ - #include #include "Client.h" #include "SSLClientImpl.h" @@ -41,27 +27,13 @@ #define SSLClient_H_ /** - * \brief The main SSLClient class - * - * TODO: fix this blurb - * - * This class serves as a templating proxy class for the SSLClientImpl to do the real work. - * - * A problem arose when writing this class: I wanted the user to be able to construct - * this class in a single line of code (e.g. SSLClient(EthernetClient())), but I also - * wanted to avoid the use of dynamic memory if possible. In an attempt to solve this - * problem I used a templated classes. However, becuase of the Arduino build process - * this meant that the implementations for all the functions had to be in a header - * file (a weird effect of using templated classes and linking) which would slow down - * the build quite a bit. As a comprimise, I instead decided to build the main class (SSLCLient) - * as a templated class, and have use a not templated implementation class (SSLClientImpl) - * that would be able to reside in a seperate file. This gets the best of both worlds - * from the client side, however from the developer side it can be a bit confusing. + * @brief The main SSLClient class + * Check out README.md for more info. */ template class SSLClient : public SSLClientImpl { -/** +/* * static checks * I'm a java developer, so I want to ensure that my inheritance is safe. * These checks ensure that all the functions we use on class C are @@ -81,22 +53,20 @@ static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in or public: /** - * @brief copies the client object, and passes the various parameters to the SSLCLientImpl functions. - * - * We copy the client because we aren't sure the Client object - * is going to exists past the inital creation of the SSLClient. + * @brief Initialize SSLClient with all of the prerequisites needed. * * @pre You will need to generate an array of trust_anchors (root certificates) * based off of the domains you want to make SSL connections to. Check out the - * Wiki on the pycert-bearssl tool for a simple way to do this. + * TrustAnchors.md file for more info. * @pre The analog_pin should be set to input. * + * @param client The base network device to create an SSL socket on. This object will be copied + * and the copy will be stored in SSLClient. * @param trust_anchors Trust anchors used in the verification - * of the SSL server certificate, generated using the `brssl` command - * line utility. For more information see the samples or bearssl.org - * @param trust_anchors_num The number of trust anchors stored - * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG - * @param debug whether to enable or disable debug logging, must be constexpr + * of the SSL server certificate. Check out TrustAnchors.md for more info. + * @param trust_anchors_num The number of objects in the trust_anchors array. + * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG. + * @param debug whether to enable or disable debug logging. */ explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN) : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) @@ -113,93 +83,81 @@ public: //======================================== /** - * @brief Connect over SSL to a host specified by an ip address + * @brief Connect over SSL to a host specified by an IP address. * - * SSLClient::connect(host, port) should be preffered over this function, + * SSLClient::connect(host, port) should be preferred over this function, * as verifying the domain name is a step in ensuring the certificate is * legitimate, which is important to the security of the device. Additionally, * SSL sessions cannot be resumed, which can drastically increase initial * connect time. * - * This function initializes EthernetClient by calling EthernetClient::connect - * with the parameters supplied, then once the socket is open initializes - * the appropriete bearssl contexts. Due to the design of the SSL standard, + * This function initializes the socket by calling m_client::connect(IPAddress, uint16_t) + * with the parameters supplied, then once the socket uses BearSSL to + * to complete a SSL handshake. Due to the design of the SSL standard, * this function will probably take an extended period (1-4sec) to negotiate * the handshake and finish the connection. This function runs until the SSL - * handshake succeeds or fails, as found in most Arduino libraries. + * handshake succeeds or fails. * - * The implementation for this function can be found in SSLClientImpl::connect_impl(IPAddress, uint16_t) + * SSL requires the client to generate some random bits (to be later combined + * with some random bits from the server), so SSLClient uses the least significant + * bits from the analog pin supplied in the constructor. The random bits are generated + * from 16 consecutive analogReads, and given to BearSSL before the handshake + * starts. * - * @pre The underlying client object (passed in through the ctor) in a non- - * error state, and must be able to access the server being connected to. - * @pre SSLCLient can only have one connection at a time, so the client - * object must not already have a socket open. - * @pre There must be sufficient memory availible on the device to verify + * The implementation for this function can be found in SSLClientImpl::connect_impl(IPAddress, uint16_t). + * + * @pre The underlying client object (passed in through the constructor) is in a non- + * error state, and must be able to access the IP. + * @pre SSLClient can only have one connection at a time, so the client + * object must not already be connected. + * @pre There must be sufficient memory available on the device to verify * the certificate (if the free memory drops below 8000 bytes during certain - * points in the connection, SSLCLient will fail). - * @pre There must be a trust anchor given to the ctor that corresponds to + * points in the connection, SSLClient will fail). + * @pre There must be a trust anchor given to the constructor that corresponds to * the certificate provided by the IP address being connected to. For more - * information check out the wiki on the pycert-bearssl tool. - * @pre The analog pin passed to the ctor must be set to input, and must - * be wired to something sort of random (floating is fine). + * information check out TrustAnchors.md . * - * @param ip The ip address to connect to + * @param ip The IP address to connect to * @param port the port to connect to - * @returns 1 if success, 0 if failure (as found in EthernetClient) + * @returns 1 if success, 0 if failure */ virtual int connect(IPAddress ip, uint16_t port) { return connect_impl(ip, port); } /** - * @brief Connect over SSL using connect(ip, port), using a DNS lookup to - * get the IP Address first. + * @brief Connect over SSL to a host specified by a hostname. * - * This function initializes EthernetClient by calling EthernetClient::connect + * This function initializes the socket by calling m_client::connect(const char*, uint16_t) * with the parameters supplied, then once the socket is open uses BearSSL to * to complete a SSL handshake. This function runs until the SSL handshake - * succeeds or fails, as found in most Arduino libraries. + * succeeds or fails. * * SSL requires the client to generate some random bits (to be later combined - * with some random bits from the server), so SSLClient uses the least signinigant - * bits from the analog pin supplied in the ctor. The random bits are generated + * with some random bits from the server), so SSLClient uses the least significant + * bits from the analog pin supplied in the constructor. The random bits are generated * from 16 consecutive analogReads, and given to BearSSL before the handshake * starts. * - * Due to the design of the SSL standard, this function will probably take an - * extended period (1-4sec) to negotiate the handshake and finish the - * connection. Since the hostname is provided, however, BearSSL is able to keep - * a session cache of the clients we have connected to. This should reduce - * connection time to about 100-200ms. In order to use this feature, the website - * you are connecting to must support it (most do by default), you must - * reuse the same SSLClient object, and you must reconnect to the same server. - * SSLClient automatcally stores an IP address and hostname in each session, - * ensuring that if you call connect("www.google.com") SSLClient will use a - * cached IP address instead of another DNS lookup. Because some websites have - * multiple servers on a single IP address (github.com is an example), however, - * you may find that even if you are connecting to the same host the connection - * does not resume. This is a flaw in the SSL session protocol, and has been - * resolved in future versions. On top of all that, SSL sessions can expire - * based on server criteria, which will result in a regular connection time. - * Because of all these factors, it is generally prudent to assume the - * connection will not be resumed, and go from there. + * This function will usually take around 4-10 seconds. If possible, this function + * also attempts to resume the SSL session if one is present matching the hostname + * string, which will reduce connection time to 100-500ms. To read more about this + * functionality, check out Session Caching in the README. * * The implementation for this function can be found in SSLClientImpl::connect_impl(const char*, uint16_t) * - * @pre The underlying client object (passed in through the ctor) in a non- - * error state, and must be able to access the server being connected to. - * @pre SSLCLient can only have one connection at a time, so the client - * object must not already have a socket open. - * @pre There must be sufficient memory availible on the device to verify + * @pre The underlying client object (passed in through the constructor) is in a non- + * error state, and must be able to access the IP. + * @pre SSLClient can only have one connection at a time, so the client + * object must not already be connected. + * @pre There must be sufficient memory available on the device to verify * the certificate (if the free memory drops below 8000 bytes during certain - * points in the connection, SSLCLient will fail). - * @pre There must be a trust anchor given to the ctor that corresponds to + * points in the connection, SSLClient will fail). + * @pre There must be a trust anchor given to the constructor that corresponds to * the certificate provided by the IP address being connected to. For more - * information check out the wiki on the pycert-bearssl tool. - * @pre The analog pin passed to the ctor must be set to input, and must - * be wired to something sort of random (floating is fine). + * information check out TrustAnchors.md . * - * @param host The cstring host ("www.google.com") - * @param port the port to connect to (443) - * @returns 1 of success, 0 if failure (as found in EthernetClient). + * @param host The hostname as a null-terminated c-string ("www.google.com") + * @param port The port to connect to on the host (443 for HTTPS) + * @returns 1 of success, 0 if failure */ virtual int connect(const char *host, uint16_t port) { return connect_impl(host, port); } @@ -208,36 +166,14 @@ public: /** * @brief Write some bytes to the SSL connection * - * Assuming all preconditions are met, this function waits for BearSSL - * to be ready for data to be sent, then writes data to the BearSSL IO - * buffer, BUT does not initally send the data. Insead, it is - * then checked if the BearSSL IO buffer is full, and if so, this function - * waits until BearSSL has flushed the buffer (written it to the - * network client) and fills the buffer again. If the function finds - * that the BearSSL buffer is not full, it returns the number of - * bytes written. In other words, this function will only write data - * to the network if the BearSSL IO buffer is full. Instead, you must call - * SSLClient::availible or SSLClient::flush, which will detect that - * the buffer is ready for writing, and will write the data to the network. - * - * This was implemented as a buffered function because users of Arduino Client - * libraries will often write to the network as such: - * @code{.cpp} - * Client client; - * ... - * client.println("GET /asciilogo.txt HTTP/1.1"); - * client.println("Host: arduino.cc"); - * client.println("Connection: close"); - * while (!client.available()) { ... } - * ... - * @endcode - * This is fine with most network clients. With SSL, however, if we are encryting and - * writing to the network every write() call this will result in a lot of - * small encryption tasks. Encryption takes a lot of time and code, and in general - * the larger the batch we can do it in the better. For this reason, write() - * implicitly buffers until SSLClient::availible is called, or until the buffer is full. - * If you would like to trigger a network write manually without using the SSLClient::available, - * you can also call SSLClient::flush, which will write all data and return when finished. + * Assuming all preconditions are met, this function writes data to the BearSSL IO + * buffer, BUT does not initially send the data. Instead, you must call + * SSLClient::available or SSLClient::flush, which will detect that + * the buffer is ready for writing, and will write the data to the network. + * Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf + * can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until + * all the data in buf is sent--attempting to keep all writes to the network grouped together. For information + * on why this is the case check out README.md . * * The implementation for this function can be found in SSLClientImpl::write_impl(const uint8_t*, size_t) * @@ -256,18 +192,18 @@ public: * @brief Returns the number of bytes availible to read from the SSL Socket * * This function updates the state of the SSL engine (including writing any data, - * see SSLClient::write) and as a result should be called periodically when writing - * or expecting data. Additionally, since this function returns zero if there are - * no bytes and if SSLClient::connected is false (this same behavior is found + * see SSLClient::write) and as a result should be called periodically when expecting data. + * Additionally, since if there are no bytes and if SSLClient::connected is false + * this function returns zero (this same behavior is found * in EthernetClient), it is prudent to ensure in your own code that the - * preconditions are met before checking this function to prevent an ambigious + * preconditions are met before checking this function to prevent an ambiguous * result. * * The implementation for this function can be found in SSLClientImpl::available * * @pre SSLClient::connected must be true. * - * @returns The number of bytes availible (can be zero), or zero if any of the pre + * @returns The number of bytes available (can be zero), or zero if any of the pre * conditions aren't satisfied. */ virtual int available() { return available_impl(); } @@ -280,38 +216,14 @@ public: /** * @brief Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. * - * This function checks if bytes are ready to be read by calling SSLClient::availible, - * and if so copies size number of bytes from the IO buffer into the buf pointer, and deletes - * that number of bytes from the SSLClient buffer. Data read using this function will not + * This function checks if bytes are ready to be read by calling SSLClient::available, + * and if so copies size number of bytes from the IO buffer into the buf pointer. + * Data read using this function will not * include any SSL or socket commands, as the Client and BearSSL will capture those and - * process them seperatley. + * process them separately. * - * It should be noted that a common problem I encountered with SSL connections is - * buffer overflow, caused by the server sending too much data at once. This problem - * is caused by the microcontroller being unable to copy and decrypt data faster - * than it is being recieved, forcing some data to be discarded. This usually puts BearSSL - * in an invalid state in which it is unable to recover, causing SSLClient to close - * the connection with a write error. If you are experiencing frequent timeout problems, - * this could be the reason why. - * - * In order to remedy this problem the device must be able to read the data faster than - * it is being recieved, or have a cache large enough to store the entire recieve payload. - * Since SSL's encryption forces the device to read slowly, this means we must increase - * the cache size. Depending on your platform, there are a number of ways this can be - * done: - * - Sometimes your communication sheild will have an internal buffer, which can be expanded - * through the driver code. This is the case with the Arduino Ethernet library (in the form - * of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be - * modified for the change to take effect. - * - SSLClient has an internal buffer SSLClientImpl::m_iobuf, which can be expanded. This will have very - * limited usefulness, however, as BearSSL limits the amount of data that can be processed - * based on the stage in the SSL handshake. - * - If none of the above are viable, it is possible to implement your own Client class which - * has an internal buffer much larger than both the driver and BearSSL. This would require - * in-depth knowlege of programming and the communication shield you are working with. - * Another important question to ask with this problem is: do I need to acsess this website? - * Often times there are other ways to get data that we need that do the same thing, - * and these other ways may offer smaller and more managable response payloads. + * If you find that you are having a lot of timeout errors, SSLClient may be experiencing a buffer + * overflow. Checkout README.md for more information. * * The implementation for this function can be found in SSLClientImpl::read_impl(uint8_t*, size_t) * @@ -328,15 +240,15 @@ public: * @brief view the first byte of the buffer, without removing it from the SSLClient Buffer * The implementation for this function can be found in SSLClientImpl::peek * @pre SSLClient::available must be >0 - * @returns The first byte recieved, or -1 if the preconditions are not satisfied (warning: - * do not use if your data may be -1, as the return value is ambigious) + * @returns The first byte received, or -1 if the preconditions are not satisfied (warning: + * do not use if your data may be -1, as the return value is ambiguous) */ virtual int peek() { return peek_impl(); } /** * @brief Force writing the buffered bytes from SSLClient::write to the network. * This function is blocking until all bytes from the buffer are written. For - * an explanation of how writing with SSLClient works, please see SSLCLient::write. + * an explanation of how writing with SSLClient works, please see SSLClient::write. * The implementation for this function can be found in SSLClientImpl::flush. */ virtual void flush() { return flush_impl(); } @@ -353,9 +265,9 @@ public: /** * @brief Check if the device is connected. * Use this function to determine if SSLClient is still connected and a SSL connection is active. - * It should be noted that SSLClient::availible should be prefered over this function for rapid - * polling--both functions send and recieve data to the Client device, however SSLClient::availible - * has some delays built in to protect the Client device from being polled too frequently. + * It should be noted that SSLClient::available should be preferred over this function for rapid + * polling--both functions send and receive data with the SSLClient::m_client device, however SSLClient::available + * has some delays built in to protect SSLClient::m_client from being polled too frequently. * * The implementation for this function can be found in SSLClientImpl::connected_impl. * @@ -368,16 +280,16 @@ public: //======================================== /** - * @brief Get a sesssion reference corressponding to a host and IP, or a reference to a emptey session if none exist + * @brief Get a session reference corresponding to a host and IP, or a reference to a empty session if none exist * - * If no session corresponding to the host and ip exist, then this function will cycle through - * sessions in a rotating order. This allows the ssession cache to continuially store sessions, + * If no session corresponding to the host and IP exist, then this function will cycle through + * sessions in a rotating order. This allows the session cache to continually store sessions, * however it will also result in old sessions being cleared and returned. In general, it is a * good idea to use a SessionCache size equal to the number of domains you plan on connecting to. * * The implementation for this function can be found at SSLClientImpl::get_session_impl. * - * @param host A hostname c string, or NULL if one is not availible + * @param host A hostname c string, or NULL if one is not available * @param ip An IP address * @returns A reference to an SSLSession object */ @@ -388,13 +300,13 @@ public: * * The implementation for this function can be found at SSLClientImpl::remove_session_impl. * - * @param host A hostname c string, or NULL if one is not availible + * @param host A hostname c string, or NULL if one is not available * @param ip An IP address */ virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); } /** - * @brief Get the meximum number of SSL sessions that can be stored at once + * @brief Get the maximum number of SSL sessions that can be stored at once * @returns The SessionCache template parameter. */ virtual size_t getSessionCount() const { return SessionCache; } @@ -437,7 +349,7 @@ public: } } - /** @brief returns a refernence to the client object stored in this class. Take care not to break it. */ + /** @brief returns a reference to the client object stored in this class. Take care not to break it. */ C& getClient() { return m_client; } protected: diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 1c1fcce..096665c 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -135,6 +135,7 @@ size_t SSLClientImpl::write_impl(const uint8_t *buf, size_t size) { size_t alen; unsigned char *br_buf = br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); size_t cur_idx = 0; + bool did_overflow = false; // while there are still elements to write while (cur_idx < size) { // run until the ssl socket is ready to write, unless we've already written @@ -152,8 +153,13 @@ size_t SSLClientImpl::write_impl(const uint8_t *buf, size_t size) { // so we only send the smallest of the buffer size or our data size - how much we've already sent const size_t cpamount = m_write_idx + (size - cur_idx) > alen ? alen : size - cur_idx; memcpy(br_buf + m_write_idx, buf + cur_idx, cpamount); - // if we filled the buffer, reset m_write_idx - if (cpamount == alen) m_write_idx = 0; + // if we filled the buffer, reset m_write_idx, and mark the data for sending + // or if we've overflowed since we're writing to the network already we may as well finish + if (cpamount == alen || did_overflow) { + m_write_idx = 0; + br_ssl_engine_sendapp_ack(&m_sslctx.eng, alen); + did_overflow = true; + } // else increment else m_write_idx += cpamount; // increment the buffer pointer diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index e4ffc5d..5c570d0 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -30,7 +30,7 @@ * @brief Static constants defining the possible errors encountered. * * If SSLClient encounters an error, it will generally output - * logs into the serial moniter. If you need a way of programmatically + * logs into the serial monitor. If you need a way of programmatically * checking the errors, you can do so with SSLClient::getWriteError(), * which will return one of these values. */ @@ -44,7 +44,7 @@ enum Error { SSL_CLIENT_WRTIE_ERROR, /** An internal error occurred with BearSSL, check logs for diagnosis. */ SSL_BR_WRITE_ERROR, - /** An internal error occured with SSLClient, and you probably need to submit an issue on Github. */ + /** An internal error occurred with SSLClient, and you probably need to submit an issue on Github. */ SSL_INTERNAL_ERROR, /** SSLClient detected that there was not enough memory (>8000 bytes) to continue. */ SSL_OUT_OF_MEMORY @@ -53,47 +53,24 @@ enum Error { /** * @brief Level of verbosity used in logging for SSLClient. * - * Use these values when initializing SSLCLient to set how many logs you - * would like to see in the Serial moniter. + * Use these values when initializing SSLClient to set how many logs you + * would like to see in the Serial monitor. */ enum DebugLevel { /** No logging output */ SSL_NONE = 0, /** Only output errors that result in connection failure */ SSL_ERROR = 1, - /** Ouput errors and warnings (useful when just starting to develop) */ + /** Output errors and warnings (useful when just starting to develop) */ SSL_WARN = 2, /** Output errors, warnings, and internal information (very verbose) */ SSL_INFO = 3, }; -/** - * On error, any function in this class will terminate the socket. - * TODO: Write what this is */ - +/** @brief Implementation code to be inherited by SSLClient */ class SSLClientImpl : public Client { public: - /** - * @brief initializes SSL contexts for bearSSL - * - * @pre You will need to generate an array of trust_anchors (root certificates) - * based off of the domains you want to make SSL connections to. Check out the - * Wiki on the pycert-bearssl tool for a simple way to do this. - * @pre The analog_pin should be set to input. - * @pre The session_ray must be an array of the size returned by SSLClient::getSessionCount() - * filled with SSLSession objects. - * - * @post set_client must be called immediatly after to set the client class - * pointer and Session pointer. - * - * @param trust_anchors Trust anchors used in the verification - * of the SSL server certificate, generated using the `brssl` command - * line utility. For more information see the samples or bearssl.org - * @param trust_anchors_num The number of trust anchors stored - * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG - * @param session_ray A pointer to the array of SSLSessions created by SSLClient - * @param debug whether to enable or disable debug logging, must be constexpr - */ + /** See SSLClient::SSLClient */ explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); @@ -185,7 +162,7 @@ private: int m_start_ssl(const char* host, SSLSession& ssl_ses); /** run the bearssl engine until a certain state */ int m_run_until(const unsigned target); - /** proxy for availble that returns the state */ + /** proxy for available that returns the state */ unsigned m_update_engine(); /** utility function to find a session index based off of a host and IP */ int m_get_session_index(const char* host, const IPAddress& addr) const; diff --git a/src/SSLSession.cpp b/src/SSLSession.cpp new file mode 100644 index 0000000..6338ad3 --- /dev/null +++ b/src/SSLSession.cpp @@ -0,0 +1,24 @@ +#include "SSLSession.h" + +/* See SSLSession.h */ +void SSLSession::set_parameters(const IPAddress& ip, const char* hostname) { + // copy the hostname + if (hostname != NULL) m_hostname = hostname; + // or if there's no hostname, clear the string + else m_hostname = ""; + // and the IP address + m_ip = ip; + // check if both values are valid, and if so set valid to true + if (m_ip != INADDR_NONE && session_id_len > 0 + && (hostname == NULL || m_hostname)) m_valid_session = true; + // else clear + else clear_parameters(); +} + +/* see SSLSession.h */ +void SSLSession::clear_parameters() { + // clear the hostname , ip, and valid session flags + m_hostname = ""; + m_ip = INADDR_NONE; + m_valid_session = false; +} \ No newline at end of file diff --git a/src/SSLSession.h b/src/SSLSession.h index 64442f9..716b4c8 100644 --- a/src/SSLSession.h +++ b/src/SSLSession.h @@ -26,6 +26,8 @@ */ #include "bearssl.h" +#include "Arduino.h" +#include "IPAddress.h" #ifndef SSLSession_H_ #define SSLSession_H_ @@ -104,19 +106,7 @@ public: * Take care that this value is corrent, SSLSession performs no validation * of the hostname. */ - void set_parameters(const IPAddress& ip, const char* hostname = NULL) { - // copy the hostname - if (hostname != NULL) m_hostname = hostname; - // or if there's no hostname, clear the string - else m_hostname = ""; - // and the IP address - m_ip = ip; - // check if both values are valid, and if so set valid to true - if (m_ip != INADDR_NONE && session_id_len > 0 - && (hostname == NULL || m_hostname)) m_valid_session = true; - // else clear - else clear_parameters(); - } + void set_parameters(const IPAddress& ip, const char* hostname = NULL); /** * @brief delete the parameters and invalidate the session @@ -124,12 +114,7 @@ public: * this function preserves the String object, allowing it * to better handle the dynamic memory needed. */ - void clear_parameters() { - // clear the hostname , ip, and valid session flags - m_hostname = ""; - m_ip = INADDR_NONE; - m_valid_session = false; - } + void clear_parameters(); /** @brief returns a pointer to the ::br_ssl_session_parameters component of this class */ br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; } @@ -142,4 +127,6 @@ private: IPAddress m_ip; }; + + #endif /* SSLSession_H_ */ \ No newline at end of file diff --git a/tools/pycert_bearssl/pycert_bearssl.py b/tools/pycert_bearssl/pycert_bearssl.py index c76df3a..327be0f 100644 --- a/tools/pycert_bearssl/pycert_bearssl.py +++ b/tools/pycert_bearssl/pycert_bearssl.py @@ -14,7 +14,7 @@ # OpenSSL can't be found then try installing egenix's prebuilt # PyOpenSSL library and OpenSSL lib: # http://www.egenix.com/products/python/pyOpenSSL/ -# +# certifi - Install with 'sudo pip install certifi' (omit sudo on windows) import cert_util import click import certifi @@ -68,6 +68,9 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom pycert download --output data.h google.com adafruit.com Note that the certificates will be validated before they are downloaded! """ + # if array is emptey, exit + if len(domain) is 0: + return # prepare the root certificate store cert_obj_store = cert_util.parse_root_certificate_store(use_store) cert_dict = dict([(cert.get_subject().hash(), cert) for cert in cert_obj_store]) @@ -111,6 +114,9 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, cert): Example of converting foo.pem and bar.pem certificates into data.h: pycert convert foo.pem bar.pem """ + # if array is emptey, exit + if len(cert) is 0: + return # prepare root certificate store cert_obj_store = cert_util.parse_root_certificate_store(use_store) cert_dict = dict([(cert.get_subject().hash(), cert) for cert in cert_obj_store]) From 4885bc3da141e8d5615b3447f1b03ea1d16c5eba Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 31 Mar 2019 15:44:34 -0700 Subject: [PATCH 037/205] Update README.md with edits for comprehension --- README.md | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ff16827..c172b38 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,15 @@ **SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.** -SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. +SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. ## Overview -Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few things extra things, however, that you will need to get started: +Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few extra things, however, that you will need to get started: 1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Notes](#Implementation-Notes)). -2. A header containing array of trust anchors, which will look like [this file](./readme/cert.h). These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out [this document](./TrustAnchors.md) on how to generate this file for your project. -3. A Client class associated with a network interface. We tested this library using [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient), however in theory it will work for and class implementing Client. +2. A header containing array of trust anchors, which will look like [this file](./readme/cert.h). These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out [this document](./TrustAnchors.md) on how to generate this file for your project, and for more information about what a trust anchor is. +3. A Client class associated with a network interface. We tested this library using [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient), however in theory it will work for any class implementing Client. 4. An analog pin, used for generating random data at the start of the connection (see the [Implementation Notes](#Implementation-Notes)). Once all those are ready, you can create a simple SSLClient object like this: @@ -49,7 +49,7 @@ For more information on SSLClient, check out the [examples](./examples), [API do ## How It Works -SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](https://bearssl.org/) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, helping debugging be a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint. +SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](https://bearssl.org/) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, making debugging a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint. Additionally, the bulk of SSLClient is split into two components: a template class [SSLClient](./src/SSLClient.h), and an implementation class [SSLClientImpl](./src/SSLClientImpl.h). The template class serves to abstract some functions not implemented in the Arduino Client interface (such as `EthernetClient::remoteIP`), and the implementation class is the rest of the SSLClient library. @@ -72,13 +72,33 @@ This was implemented as a buffered function because examples in Arduino librarie ```C++ EthernetClient client; // ... -client.println("GET /asciilogo.txt HTTP/1.1"); -client.println("Host: arduino.cc"); -client.println("Connection: close"); +// connect to ardiuino.cc over ssl (port 443 for websites) +client.connect("www.arduino.cc", 443); +// ... +// write an http request to the network +client.write("GET /asciilogo.txt HTTP/1.1\r\n"); +client.write("Host: arduino.cc\r\n"); +client.write("Connection: close\r\n"); +// wait for response +while (!client.available()) { /* ... */ } +// ... +``` +Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below: + +```C++ +SSLClient client(EthernetClient(), TAs, 2, A7); +// ... +// connect to ardiuino.cc over ssl (port 443 for websites) +client.connect("www.arduino.cc", 443); +// ... +// add http request to the buffer +client.write("GET /asciilogo.txt HTTP/1.1\r\n"); +client.write("Host: arduino.cc\r\n"); +client.write("Connection: close\r\n"); +// write the bytes to the network, then wait for response while (!client.available()) { /* ... */ } // ... ``` -This is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, and so to reduce the overhead of an SSL connection SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished. @@ -87,10 +107,10 @@ As detailed in the [resources section](#resources), SSL handshakes take an exten In order to use SSL session resumption: * The website you are connecting to must support it. Support is widespread, but you can verify easily using the [SSLLabs tool](https://www.ssllabs.com/ssltest/). - * you must reuse the same SSLClient object (SSL Sessions are stored in the object itself). - * you must reconnect to the exact same server. + * You must reuse the same SSLClient object (SSL Sessions are stored in the object itself). + * You must reconnect to the exact same server. -SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with `"www.google.com"`. Because some websites have multiple servers on a single IP address (github.com is an example), however, you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol, and has been resolved in future versions. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection. +SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with `"www.google.com"`. However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection. You can test whether or not a website can resume SSL Sessions using the [Session Example](./examples/Session_Example/Session_Example.ino) included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume. @@ -117,11 +137,11 @@ SSL is a buffered protocol, and since most microcontrollers have limited resourc In order to remedy this problem, the device must be able to read the data faster than it is being received, or alternatively have a cache large enough to store the entire payload. Since SSL's encryption forces the device to read slowly, this means we must increase the cache size. Depending on your platform, there are a number of ways this can be done: * Sometimes your communication shield will have an internal buffer, which can be expanded through the driver code. This is the case with the Arduino Ethernet library (in the form of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be modified for the change to take effect. * SSLClient has an internal buffer SSLClientImpl::m_iobuf, which can be expanded. BearSSL limits the amount of data that can be processed based on the stage in the SSL handshake, and so this will change will have limited usefulness. -* In some cases, a website will send so much data that even with the above solutions SSLClient will be unable to keep up (a website with a lot of HTML is an example). In these cases you will have to find another method of retrieving the data you need. +* In some cases, a website will send so much data that even with the above solutions, SSLClient will be unable to keep up (a website with a lot of HTML is an example). In these cases you will have to find another method of retrieving the data you need. * If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM. ### Cipher Support -SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile) under `suites[]` by default, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: +By default, SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile) under `suites[]`, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: ```C++ br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // comment the above line and uncomment the line below if you're having trouble connecting over SSL From 8656bf9eb057df6235240a060be1d21e9ef5fd7f Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 31 Mar 2019 15:52:50 -0700 Subject: [PATCH 038/205] Initial documentation creation! --- .gitignore | 4 +- docs/html/_r_e_a_d_m_e_8md.html | 106 + docs/html/_s_s_l_client_8h.html | 142 ++ docs/html/_s_s_l_client_8h.js | 5 + docs/html/_s_s_l_client_8h_source.html | 151 ++ docs/html/_s_s_l_client_impl_8cpp.html | 130 ++ docs/html/_s_s_l_client_impl_8cpp.js | 4 + docs/html/_s_s_l_client_impl_8h.html | 205 ++ docs/html/_s_s_l_client_impl_8h.js | 19 + docs/html/_s_s_l_client_impl_8h_source.html | 146 ++ docs/html/_s_s_l_session_8cpp.html | 107 + docs/html/_s_s_l_session_8h.html | 120 ++ docs/html/_s_s_l_session_8h_source.html | 115 ++ docs/html/_t_l_s12__only__profile_8c.html | 158 ++ docs/html/_t_l_s12__only__profile_8c.js | 4 + docs/html/_trust_anchors_8md.html | 106 + docs/html/annotated.html | 112 ++ docs/html/annotated_dup.js | 6 + docs/html/bc_s.png | Bin 0 -> 676 bytes docs/html/bdwn.png | Bin 0 -> 147 bytes docs/html/cert_8h.html | 131 ++ docs/html/cert_8h.js | 4 + docs/html/cert_8h_source.html | 106 + docs/html/class_s_s_l_client-members.html | 155 ++ docs/html/class_s_s_l_client.html | 1295 ++++++++++++ docs/html/class_s_s_l_client.js | 31 + docs/html/class_s_s_l_client.png | Bin 0 -> 861 bytes .../html/class_s_s_l_client_impl-members.html | 135 ++ docs/html/class_s_s_l_client_impl.html | 1013 ++++++++++ docs/html/class_s_s_l_client_impl.js | 30 + docs/html/class_s_s_l_client_impl.png | Bin 0 -> 870 bytes docs/html/class_s_s_l_session-members.html | 116 ++ docs/html/class_s_s_l_session.html | 382 ++++ docs/html/class_s_s_l_session.js | 11 + docs/html/class_s_s_l_session.png | Bin 0 -> 609 bytes docs/html/classes.html | 114 ++ docs/html/closed.png | Bin 0 -> 132 bytes .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 124 ++ .../dir_68267d1309a1af8e8297ef4c3efbcdba.js | 12 + .../dir_dfc5a9f91fbfb9426c406a3f10131a54.html | 112 ++ .../dir_dfc5a9f91fbfb9426c406a3f10131a54.js | 4 + docs/html/doc.png | Bin 0 -> 746 bytes docs/html/doxygen.css | 1764 +++++++++++++++++ docs/html/doxygen.png | Bin 0 -> 3779 bytes docs/html/dynsections.js | 120 ++ docs/html/files.html | 119 ++ docs/html/files_dup.js | 5 + docs/html/folderclosed.png | Bin 0 -> 616 bytes docs/html/folderopen.png | Bin 0 -> 597 bytes docs/html/functions.html | 300 +++ docs/html/functions_func.html | 300 +++ docs/html/globals.html | 255 +++ docs/html/globals_defs.html | 172 ++ docs/html/globals_enum.html | 109 + docs/html/globals_eval.html | 136 ++ docs/html/globals_func.html | 106 + docs/html/globals_vars.html | 106 + docs/html/hierarchy.html | 114 ++ docs/html/hierarchy.js | 11 + docs/html/index.html | 105 + docs/html/jquery.js | 87 + ..._libraries__s_s_l_client__r_e_a_d_m_e.html | 166 ++ ...ibraries__s_s_l_client__trust_anchors.html | 119 ++ docs/html/menu.js | 50 + docs/html/menudata.js | 78 + docs/html/nav_f.png | Bin 0 -> 153 bytes docs/html/nav_g.png | Bin 0 -> 95 bytes docs/html/nav_h.png | Bin 0 -> 98 bytes docs/html/navtree.css | 146 ++ docs/html/navtree.js | 540 +++++ docs/html/navtreedata.js | 58 + docs/html/navtreeindex0.js | 138 ++ docs/html/open.png | Bin 0 -> 123 bytes docs/html/pages.html | 111 ++ docs/html/resize.js | 136 ++ docs/html/search/all_0.html | 30 + docs/html/search/all_0.js | 13 + docs/html/search/all_1.html | 30 + docs/html/search/all_1.js | 5 + docs/html/search/all_10.html | 30 + docs/html/search/all_10.js | 5 + docs/html/search/all_11.html | 30 + docs/html/search/all_11.js | 5 + docs/html/search/all_2.html | 30 + docs/html/search/all_2.js | 4 + docs/html/search/all_3.html | 30 + docs/html/search/all_3.js | 13 + docs/html/search/all_4.html | 30 + docs/html/search/all_4.js | 4 + docs/html/search/all_5.html | 30 + docs/html/search/all_5.js | 4 + docs/html/search/all_6.html | 30 + docs/html/search/all_6.js | 5 + docs/html/search/all_7.html | 30 + docs/html/search/all_7.js | 12 + docs/html/search/all_8.html | 30 + docs/html/search/all_8.js | 4 + docs/html/search/all_9.html | 30 + docs/html/search/all_9.js | 4 + docs/html/search/all_a.html | 30 + docs/html/search/all_a.js | 10 + docs/html/search/all_b.html | 30 + docs/html/search/all_b.js | 7 + docs/html/search/all_c.html | 30 + docs/html/search/all_c.js | 6 + docs/html/search/all_d.html | 30 + docs/html/search/all_d.js | 10 + docs/html/search/all_e.html | 30 + docs/html/search/all_e.js | 31 + docs/html/search/all_f.html | 30 + docs/html/search/all_f.js | 9 + docs/html/search/classes_0.html | 30 + docs/html/search/classes_0.js | 6 + docs/html/search/close.png | Bin 0 -> 273 bytes docs/html/search/defines_0.html | 30 + docs/html/search/defines_0.js | 12 + docs/html/search/defines_1.html | 30 + docs/html/search/defines_1.js | 7 + docs/html/search/defines_2.html | 30 + docs/html/search/defines_2.js | 4 + docs/html/search/defines_3.html | 30 + docs/html/search/defines_3.js | 4 + docs/html/search/defines_4.html | 30 + docs/html/search/defines_4.js | 8 + docs/html/search/defines_5.html | 30 + docs/html/search/defines_5.js | 4 + docs/html/search/defines_6.html | 30 + docs/html/search/defines_6.js | 5 + docs/html/search/enums_0.html | 30 + docs/html/search/enums_0.js | 4 + docs/html/search/enums_1.html | 30 + docs/html/search/enums_1.js | 4 + docs/html/search/enumvalues_0.html | 30 + docs/html/search/enumvalues_0.js | 14 + docs/html/search/files_0.html | 30 + docs/html/search/files_0.js | 4 + docs/html/search/files_1.html | 30 + docs/html/search/files_1.js | 4 + docs/html/search/files_2.html | 30 + docs/html/search/files_2.js | 8 + docs/html/search/files_3.html | 30 + docs/html/search/files_3.js | 6 + docs/html/search/functions_0.html | 30 + docs/html/search/functions_0.js | 5 + docs/html/search/functions_1.html | 30 + docs/html/search/functions_1.js | 4 + docs/html/search/functions_2.html | 30 + docs/html/search/functions_2.js | 8 + docs/html/search/functions_3.html | 30 + docs/html/search/functions_3.js | 5 + docs/html/search/functions_4.html | 30 + docs/html/search/functions_4.js | 11 + docs/html/search/functions_5.html | 30 + docs/html/search/functions_5.js | 4 + docs/html/search/functions_6.html | 30 + docs/html/search/functions_6.js | 4 + docs/html/search/functions_7.html | 30 + docs/html/search/functions_7.js | 10 + docs/html/search/functions_8.html | 30 + docs/html/search/functions_8.js | 7 + docs/html/search/functions_9.html | 30 + docs/html/search/functions_9.js | 5 + docs/html/search/functions_a.html | 30 + docs/html/search/functions_a.js | 9 + docs/html/search/functions_b.html | 30 + docs/html/search/functions_b.js | 9 + docs/html/search/functions_c.html | 30 + docs/html/search/functions_c.js | 4 + docs/html/search/functions_d.html | 30 + docs/html/search/functions_d.js | 5 + docs/html/search/mag_sel.png | Bin 0 -> 465 bytes docs/html/search/nomatches.html | 12 + docs/html/search/pages_0.html | 30 + docs/html/search/pages_0.js | 4 + docs/html/search/pages_1.html | 30 + docs/html/search/pages_1.js | 4 + docs/html/search/search.css | 271 +++ docs/html/search/search.js | 814 ++++++++ docs/html/search/search_l.png | Bin 0 -> 567 bytes docs/html/search/search_m.png | Bin 0 -> 158 bytes docs/html/search/search_r.png | Bin 0 -> 553 bytes docs/html/search/searchdata.js | 39 + docs/html/search/variables_0.html | 30 + docs/html/search/variables_0.js | 4 + docs/html/splitbar.png | Bin 0 -> 314 bytes docs/html/sync_off.png | Bin 0 -> 853 bytes docs/html/sync_on.png | Bin 0 -> 845 bytes docs/html/tab_a.png | Bin 0 -> 142 bytes docs/html/tab_b.png | Bin 0 -> 169 bytes docs/html/tab_h.png | Bin 0 -> 177 bytes docs/html/tab_s.png | Bin 0 -> 184 bytes docs/html/tabs.css | 1 + docs/html/time__macros_8h.html | 589 ++++++ docs/html/time__macros_8h.js | 24 + docs/html/time__macros_8h_source.html | 106 + src/Client.h | 45 - src/SSLClient.h | 16 +- src/SSLClientImpl.cpp | 32 +- 198 files changed, 14492 insertions(+), 70 deletions(-) create mode 100644 docs/html/_r_e_a_d_m_e_8md.html create mode 100644 docs/html/_s_s_l_client_8h.html create mode 100644 docs/html/_s_s_l_client_8h.js create mode 100644 docs/html/_s_s_l_client_8h_source.html create mode 100644 docs/html/_s_s_l_client_impl_8cpp.html create mode 100644 docs/html/_s_s_l_client_impl_8cpp.js create mode 100644 docs/html/_s_s_l_client_impl_8h.html create mode 100644 docs/html/_s_s_l_client_impl_8h.js create mode 100644 docs/html/_s_s_l_client_impl_8h_source.html create mode 100644 docs/html/_s_s_l_session_8cpp.html create mode 100644 docs/html/_s_s_l_session_8h.html create mode 100644 docs/html/_s_s_l_session_8h_source.html create mode 100644 docs/html/_t_l_s12__only__profile_8c.html create mode 100644 docs/html/_t_l_s12__only__profile_8c.js create mode 100644 docs/html/_trust_anchors_8md.html create mode 100644 docs/html/annotated.html create mode 100644 docs/html/annotated_dup.js create mode 100644 docs/html/bc_s.png create mode 100644 docs/html/bdwn.png create mode 100644 docs/html/cert_8h.html create mode 100644 docs/html/cert_8h.js create mode 100644 docs/html/cert_8h_source.html create mode 100644 docs/html/class_s_s_l_client-members.html create mode 100644 docs/html/class_s_s_l_client.html create mode 100644 docs/html/class_s_s_l_client.js create mode 100644 docs/html/class_s_s_l_client.png create mode 100644 docs/html/class_s_s_l_client_impl-members.html create mode 100644 docs/html/class_s_s_l_client_impl.html create mode 100644 docs/html/class_s_s_l_client_impl.js create mode 100644 docs/html/class_s_s_l_client_impl.png create mode 100644 docs/html/class_s_s_l_session-members.html create mode 100644 docs/html/class_s_s_l_session.html create mode 100644 docs/html/class_s_s_l_session.js create mode 100644 docs/html/class_s_s_l_session.png create mode 100644 docs/html/classes.html create mode 100644 docs/html/closed.png create mode 100644 docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html create mode 100644 docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js create mode 100644 docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html create mode 100644 docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.js create mode 100644 docs/html/doc.png create mode 100644 docs/html/doxygen.css create mode 100644 docs/html/doxygen.png create mode 100644 docs/html/dynsections.js create mode 100644 docs/html/files.html create mode 100644 docs/html/files_dup.js create mode 100644 docs/html/folderclosed.png create mode 100644 docs/html/folderopen.png create mode 100644 docs/html/functions.html create mode 100644 docs/html/functions_func.html create mode 100644 docs/html/globals.html create mode 100644 docs/html/globals_defs.html create mode 100644 docs/html/globals_enum.html create mode 100644 docs/html/globals_eval.html create mode 100644 docs/html/globals_func.html create mode 100644 docs/html/globals_vars.html create mode 100644 docs/html/hierarchy.html create mode 100644 docs/html/hierarchy.js create mode 100644 docs/html/index.html create mode 100644 docs/html/jquery.js create mode 100644 docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html create mode 100644 docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html create mode 100644 docs/html/menu.js create mode 100644 docs/html/menudata.js create mode 100644 docs/html/nav_f.png create mode 100644 docs/html/nav_g.png create mode 100644 docs/html/nav_h.png create mode 100644 docs/html/navtree.css create mode 100644 docs/html/navtree.js create mode 100644 docs/html/navtreedata.js create mode 100644 docs/html/navtreeindex0.js create mode 100644 docs/html/open.png create mode 100644 docs/html/pages.html create mode 100644 docs/html/resize.js create mode 100644 docs/html/search/all_0.html create mode 100644 docs/html/search/all_0.js create mode 100644 docs/html/search/all_1.html create mode 100644 docs/html/search/all_1.js create mode 100644 docs/html/search/all_10.html create mode 100644 docs/html/search/all_10.js create mode 100644 docs/html/search/all_11.html create mode 100644 docs/html/search/all_11.js create mode 100644 docs/html/search/all_2.html create mode 100644 docs/html/search/all_2.js create mode 100644 docs/html/search/all_3.html create mode 100644 docs/html/search/all_3.js create mode 100644 docs/html/search/all_4.html create mode 100644 docs/html/search/all_4.js create mode 100644 docs/html/search/all_5.html create mode 100644 docs/html/search/all_5.js create mode 100644 docs/html/search/all_6.html create mode 100644 docs/html/search/all_6.js create mode 100644 docs/html/search/all_7.html create mode 100644 docs/html/search/all_7.js create mode 100644 docs/html/search/all_8.html create mode 100644 docs/html/search/all_8.js create mode 100644 docs/html/search/all_9.html create mode 100644 docs/html/search/all_9.js create mode 100644 docs/html/search/all_a.html create mode 100644 docs/html/search/all_a.js create mode 100644 docs/html/search/all_b.html create mode 100644 docs/html/search/all_b.js create mode 100644 docs/html/search/all_c.html create mode 100644 docs/html/search/all_c.js create mode 100644 docs/html/search/all_d.html create mode 100644 docs/html/search/all_d.js create mode 100644 docs/html/search/all_e.html create mode 100644 docs/html/search/all_e.js create mode 100644 docs/html/search/all_f.html create mode 100644 docs/html/search/all_f.js create mode 100644 docs/html/search/classes_0.html create mode 100644 docs/html/search/classes_0.js create mode 100644 docs/html/search/close.png create mode 100644 docs/html/search/defines_0.html create mode 100644 docs/html/search/defines_0.js create mode 100644 docs/html/search/defines_1.html create mode 100644 docs/html/search/defines_1.js create mode 100644 docs/html/search/defines_2.html create mode 100644 docs/html/search/defines_2.js create mode 100644 docs/html/search/defines_3.html create mode 100644 docs/html/search/defines_3.js create mode 100644 docs/html/search/defines_4.html create mode 100644 docs/html/search/defines_4.js create mode 100644 docs/html/search/defines_5.html create mode 100644 docs/html/search/defines_5.js create mode 100644 docs/html/search/defines_6.html create mode 100644 docs/html/search/defines_6.js create mode 100644 docs/html/search/enums_0.html create mode 100644 docs/html/search/enums_0.js create mode 100644 docs/html/search/enums_1.html create mode 100644 docs/html/search/enums_1.js create mode 100644 docs/html/search/enumvalues_0.html create mode 100644 docs/html/search/enumvalues_0.js create mode 100644 docs/html/search/files_0.html create mode 100644 docs/html/search/files_0.js create mode 100644 docs/html/search/files_1.html create mode 100644 docs/html/search/files_1.js create mode 100644 docs/html/search/files_2.html create mode 100644 docs/html/search/files_2.js create mode 100644 docs/html/search/files_3.html create mode 100644 docs/html/search/files_3.js create mode 100644 docs/html/search/functions_0.html create mode 100644 docs/html/search/functions_0.js create mode 100644 docs/html/search/functions_1.html create mode 100644 docs/html/search/functions_1.js create mode 100644 docs/html/search/functions_2.html create mode 100644 docs/html/search/functions_2.js create mode 100644 docs/html/search/functions_3.html create mode 100644 docs/html/search/functions_3.js create mode 100644 docs/html/search/functions_4.html create mode 100644 docs/html/search/functions_4.js create mode 100644 docs/html/search/functions_5.html create mode 100644 docs/html/search/functions_5.js create mode 100644 docs/html/search/functions_6.html create mode 100644 docs/html/search/functions_6.js create mode 100644 docs/html/search/functions_7.html create mode 100644 docs/html/search/functions_7.js create mode 100644 docs/html/search/functions_8.html create mode 100644 docs/html/search/functions_8.js create mode 100644 docs/html/search/functions_9.html create mode 100644 docs/html/search/functions_9.js create mode 100644 docs/html/search/functions_a.html create mode 100644 docs/html/search/functions_a.js create mode 100644 docs/html/search/functions_b.html create mode 100644 docs/html/search/functions_b.js create mode 100644 docs/html/search/functions_c.html create mode 100644 docs/html/search/functions_c.js create mode 100644 docs/html/search/functions_d.html create mode 100644 docs/html/search/functions_d.js create mode 100644 docs/html/search/mag_sel.png create mode 100644 docs/html/search/nomatches.html create mode 100644 docs/html/search/pages_0.html create mode 100644 docs/html/search/pages_0.js create mode 100644 docs/html/search/pages_1.html create mode 100644 docs/html/search/pages_1.js create mode 100644 docs/html/search/search.css create mode 100644 docs/html/search/search.js create mode 100644 docs/html/search/search_l.png create mode 100644 docs/html/search/search_m.png create mode 100644 docs/html/search/search_r.png create mode 100644 docs/html/search/searchdata.js create mode 100644 docs/html/search/variables_0.html create mode 100644 docs/html/search/variables_0.js create mode 100644 docs/html/splitbar.png create mode 100644 docs/html/sync_off.png create mode 100644 docs/html/sync_on.png create mode 100644 docs/html/tab_a.png create mode 100644 docs/html/tab_b.png create mode 100644 docs/html/tab_h.png create mode 100644 docs/html/tab_s.png create mode 100644 docs/html/tabs.css create mode 100644 docs/html/time__macros_8h.html create mode 100644 docs/html/time__macros_8h.js create mode 100644 docs/html/time__macros_8h_source.html delete mode 100644 src/Client.h diff --git a/.gitignore b/.gitignore index 6a8fcb1..99ca00b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,6 @@ *.app # vscode IDE settings -.vscode/** \ No newline at end of file +.vscode/** + +doxy \ No newline at end of file diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/html/_r_e_a_d_m_e_8md.html new file mode 100644 index 0000000..1db9a61 --- /dev/null +++ b/docs/html/_r_e_a_d_m_e_8md.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/README.md File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
C:/Users/Noah/Documents/Arduino/libraries/SSLClient/README.md File Reference
+
+
+
+
+ + + + diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html new file mode 100644 index 0000000..8112e78 --- /dev/null +++ b/docs/html/_s_s_l_client_8h.html @@ -0,0 +1,142 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClient.h File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SSLClient.h File Reference
+
+
+
#include <type_traits>
+#include "Client.h"
+#include "SSLClientImpl.h"
+#include "SSLSession.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  SSLClient< C, SessionCache >
 The main SSLClient class Check out README.md for more info. More...
 
+ + + +

+Macros

#define SSLClient_H_
 
+

Macro Definition Documentation

+ +

◆ SSLClient_H_

+ +
+
+ + + + +
#define SSLClient_H_
+
+ +
+
+
+
+ + + + diff --git a/docs/html/_s_s_l_client_8h.js b/docs/html/_s_s_l_client_8h.js new file mode 100644 index 0000000..f129b07 --- /dev/null +++ b/docs/html/_s_s_l_client_8h.js @@ -0,0 +1,5 @@ +var _s_s_l_client_8h = +[ + [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ], + [ "SSLClient_H_", "_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569", null ] +]; \ No newline at end of file diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html new file mode 100644 index 0000000..3788ec1 --- /dev/null +++ b/docs/html/_s_s_l_client_8h_source.html @@ -0,0 +1,151 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClient.h Source File + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLClient.h
+
+
+Go to the documentation of this file.
1 /* Copyright 2019 OSU OPEnS Lab
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
4  * software and associated documentation files (the "Software"), to deal in the Software
5  * without restriction, including without limitation the rights to use, copy, modify,
6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7  * permit persons to whom the Software is furnished to do so, subject to the following
8  * conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in all
11  * copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include <type_traits>
22 #include "Client.h"
23 #include "SSLClientImpl.h"
24 #include "SSLSession.h"
25 
26 #ifndef SSLClient_H_
27 #define SSLClient_H_
28 
34 template <class C, size_t SessionCache = 1>
35 class SSLClient : public SSLClientImpl {
36 /*
37  * static checks
38  * I'm a java developer, so I want to ensure that my inheritance is safe.
39  * These checks ensure that all the functions we use on class C are
40  * actually present on class C. It does this by checking that the
41  * class inherits from Client.
42  *
43  * Additionally, I ran into a lot of memory issues with large sessions caches.
44  * Since each session contains at max 352 bytes of memory, they eat of the
45  * stack quite quickly and can cause overflows. As a result, I have added a
46  * warning here to discourage the use of more than 3 sessions at a time. Any
47  * amount past that will require special modification of this library, and
48  * assumes you know what you are doing.
49  */
50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
53 
54 public:
71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
73  , m_client(client)
74  , m_sessions{SSLSession()}
75  {
76  // set the timeout to a reasonable number (it can always be changes later)
77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
78  setTimeout(10 * 1000);
79  }
80 
81  //========================================
82  //= Functions implemented in SSLClientImpl
83  //========================================
84 
124  virtual int connect(IPAddress ip, uint16_t port) { return connect_impl(ip, port); }
125 
162  virtual int connect(const char *host, uint16_t port) { return connect_impl(host, port); }
163 
165  virtual size_t write(uint8_t b) { return write_impl(&b, 1); }
189  virtual size_t write(const uint8_t *buf, size_t size) { return write_impl(buf, size); }
190 
209  virtual int available() { return available_impl(); }
210 
215  virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
237  virtual int read(uint8_t *buf, size_t size) { return read_impl(buf, size); }
238 
246  virtual int peek() { return peek_impl(); }
247 
254  virtual void flush() { return flush_impl(); }
255 
263  virtual void stop() { return stop_impl(); }
264 
276  virtual uint8_t connected() { return connected_impl(); }
277 
278  //========================================
279  //= Functions Not in the Client Interface
280  //========================================
281 
296  virtual SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
297 
306  virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
307 
312  virtual size_t getSessionCount() const { return SessionCache; }
313 
318  virtual operator bool() { return connected() > 0; }
320  virtual bool operator==(const bool value) { return bool() == value; }
322  virtual bool operator!=(const bool value) { return bool() != value; }
324  virtual bool operator==(const C& rhs) { return m_client == rhs; }
326  virtual bool operator!=(const C& rhs) { return m_client != rhs; }
328  virtual uint16_t localPort() {
329  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
330  else {
331  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
332  return 0;
333  }
334  }
336  virtual IPAddress remoteIP() {
337  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
338  else {
339  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
340  return INADDR_NONE;
341  }
342  }
344  virtual uint16_t remotePort() {
345  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
346  else {
347  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
348  return 0;
349  }
350  }
351 
353  C& getClient() { return m_client; }
354 
355 protected:
357  virtual Client& get_arduino_client() { return m_client; }
358  virtual const Client& get_arduino_client() const { return m_client; }
360  virtual SSLSession* get_session_array() { return m_sessions; }
361  virtual const SSLSession* get_session_array() const { return m_sessions; }
362 
363 private:
364  // create a copy of the client
365  C m_client;
366  // also store an array of SSLSessions, so we can resume communication with multiple websites
367  SSLSession m_sessions[SessionCache];
368 };
369 
370 #endif
virtual uint8_t connected()
Check if the device is connected. Use this function to determine if SSLClient is still connected and ...
Definition: SSLClient.h:276
+
virtual bool operator!=(const bool value)
Definition: SSLClient.h:322
+
size_t write_impl(const uint8_t *buf, size_t size)
Definition: SSLClientImpl.cpp:130
+
virtual const SSLSession * get_session_array() const
Definition: SSLClient.h:361
+
virtual uint16_t remotePort()
Returns the remote port, if C::remotePort exists. Else return 0.
Definition: SSLClient.h:344
+
Definition: SSLClientImpl.h:65
+
SSLSession & get_session_impl(const char *host, const IPAddress &addr)
Definition: SSLClientImpl.cpp:276
+
virtual int available()
Returns the number of bytes availible to read from the SSL Socket.
Definition: SSLClient.h:209
+
This class stores values which allow SSLClient to save and resume SSL sessions.
Definition: SSLSession.h:52
+
virtual uint16_t localPort()
Returns the local port, C::localPort exists. Else return 0.
Definition: SSLClient.h:328
+
virtual IPAddress remoteIP()
Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
Definition: SSLClient.h:336
+
C & getClient()
returns a reference to the client object stored in this class. Take care not to break it.
Definition: SSLClient.h:353
+
virtual int peek()
view the first byte of the buffer, without removing it from the SSLClient Buffer The implementation f...
Definition: SSLClient.h:246
+
int peek_impl()
Definition: SSLClientImpl.cpp:209
+
virtual SSLSession & getSession(const char *host, const IPAddress &addr)
Get a session reference corresponding to a host and IP, or a reference to a empty session if none exi...
Definition: SSLClient.h:296
+
virtual size_t write(const uint8_t *buf, size_t size)
Write some bytes to the SSL connection.
Definition: SSLClient.h:189
+
The main SSLClient class Check out README.md for more info.
Definition: SSLClient.h:35
+
SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
Initialize SSLClient with all of the prerequisites needed.
Definition: SSLClient.h:71
+
virtual void stop()
Close the connection If the SSL session is still active, all incoming data is discarded and BearSSL w...
Definition: SSLClient.h:263
+
int available_impl()
Definition: SSLClientImpl.cpp:173
+
int read_impl(uint8_t *buf, size_t size)
Definition: SSLClientImpl.cpp:194
+
void remove_session_impl(const char *host, const IPAddress &addr)
Definition: SSLClientImpl.cpp:295
+
virtual size_t getSessionCount() const
Get the maximum number of SSL sessions that can be stored at once.
Definition: SSLClient.h:312
+
virtual int read()
Read a single byte, or -1 if none is available.
Definition: SSLClient.h:215
+
virtual size_t write(uint8_t b)
Definition: SSLClient.h:165
+ +
void m_warn(const T str, const char *func_name) const
Definition: SSLClientImpl.h:153
+
virtual bool operator==(const bool value)
Definition: SSLClient.h:320
+
virtual void flush()
Force writing the buffered bytes from SSLClient::write to the network. This function is blocking unti...
Definition: SSLClient.h:254
+
virtual const Client & get_arduino_client() const
Definition: SSLClient.h:358
+
virtual int connect(const char *host, uint16_t port)
Connect over SSL to a host specified by a hostname.
Definition: SSLClient.h:162
+
virtual SSLSession * get_session_array()
return an instance of the session array that is on the stack
Definition: SSLClient.h:360
+ +
virtual bool operator!=(const C &rhs)
Returns whether or not two SSLClient objects do not have the same underlying client object.
Definition: SSLClient.h:326
+
virtual void removeSession(const char *host, const IPAddress &addr)
Clear the session corresponding to a host and IP.
Definition: SSLClient.h:306
+
virtual int connect(IPAddress ip, uint16_t port)
Connect over SSL to a host specified by an IP address.
Definition: SSLClient.h:124
+
int connect_impl(IPAddress ip, uint16_t port)
Definition: SSLClientImpl.cpp:74
+
void stop_impl()
Definition: SSLClientImpl.cpp:229
+
void flush_impl()
Definition: SSLClientImpl.cpp:221
+
Implementation code to be inherited by SSLClient.
Definition: SSLClientImpl.h:71
+
virtual int read(uint8_t *buf, size_t size)
Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes re...
Definition: SSLClient.h:237
+
virtual bool operator==(const C &rhs)
Returns whether or not two SSLClient objects have the same underlying client object.
Definition: SSLClient.h:324
+
uint8_t connected_impl()
Definition: SSLClientImpl.cpp:250
+
virtual Client & get_arduino_client()
return an instance of m_client that is polymorphic and can be used by SSLClientImpl
Definition: SSLClient.h:357
+
DebugLevel
Level of verbosity used in logging for SSLClient.
Definition: SSLClientImpl.h:59
+
+
+ + + + diff --git a/docs/html/_s_s_l_client_impl_8cpp.html b/docs/html/_s_s_l_client_impl_8cpp.html new file mode 100644 index 0000000..96141e4 --- /dev/null +++ b/docs/html/_s_s_l_client_impl_8cpp.html @@ -0,0 +1,130 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClientImpl.cpp File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SSLClientImpl.cpp File Reference
+
+
+
#include "SSLClient.h"
+
+ + + +

+Variables

char * __brkval
 
+

Variable Documentation

+ +

◆ __brkval

+ +
+
+ + + + +
char* __brkval
+
+ +
+
+
+
+ + + + diff --git a/docs/html/_s_s_l_client_impl_8cpp.js b/docs/html/_s_s_l_client_impl_8cpp.js new file mode 100644 index 0000000..439f6bc --- /dev/null +++ b/docs/html/_s_s_l_client_impl_8cpp.js @@ -0,0 +1,4 @@ +var _s_s_l_client_impl_8cpp = +[ + [ "__brkval", "_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56", null ] +]; \ No newline at end of file diff --git a/docs/html/_s_s_l_client_impl_8h.html b/docs/html/_s_s_l_client_impl_8h.html new file mode 100644 index 0000000..c98b0d7 --- /dev/null +++ b/docs/html/_s_s_l_client_impl_8h.html @@ -0,0 +1,205 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClientImpl.h File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SSLClientImpl.h File Reference
+
+
+
#include "bearssl.h"
+#include "Arduino.h"
+#include "Client.h"
+#include "SSLSession.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  SSLClientImpl
 Implementation code to be inherited by SSLClient. More...
 
+ + + + + + + +

+Enumerations

enum  Error {
+  SSL_OK = 0, +SSL_CLIENT_CONNECT_FAIL, +SSL_BR_CONNECT_FAIL, +SSL_CLIENT_WRTIE_ERROR, +
+  SSL_BR_WRITE_ERROR, +SSL_INTERNAL_ERROR, +SSL_OUT_OF_MEMORY +
+ }
 Static constants defining the possible errors encountered. More...
 
enum  DebugLevel { SSL_NONE = 0, +SSL_ERROR = 1, +SSL_WARN = 2, +SSL_INFO = 3 + }
 Level of verbosity used in logging for SSLClient. More...
 
+

Enumeration Type Documentation

+ +

◆ DebugLevel

+ +
+
+ + + + +
enum DebugLevel
+
+ +

Level of verbosity used in logging for SSLClient.

+

Use these values when initializing SSLClient to set how many logs you would like to see in the Serial monitor.

+ + + + + +
Enumerator
SSL_NONE 

No logging output

+
SSL_ERROR 

Only output errors that result in connection failure

+
SSL_WARN 

Output errors and warnings (useful when just starting to develop)

+
SSL_INFO 

Output errors, warnings, and internal information (very verbose)

+
+ +
+
+ +

◆ Error

+ +
+
+ + + + +
enum Error
+
+ +

Static constants defining the possible errors encountered.

+

If SSLClient encounters an error, it will generally output logs into the serial monitor. If you need a way of programmatically checking the errors, you can do so with SSLClient::getWriteError(), which will return one of these values.

+ + + + + + + + +
Enumerator
SSL_OK 
SSL_CLIENT_CONNECT_FAIL 

The underlying client failed to connect, probably not an issue with SSL

+
SSL_BR_CONNECT_FAIL 

BearSSL failed to complete the SSL handshake, check logs for bear ssl error output

+
SSL_CLIENT_WRTIE_ERROR 

The underlying client failed to write a payload, probably not an issue with SSL

+
SSL_BR_WRITE_ERROR 

An internal error occurred with BearSSL, check logs for diagnosis.

+
SSL_INTERNAL_ERROR 

An internal error occurred with SSLClient, and you probably need to submit an issue on Github.

+
SSL_OUT_OF_MEMORY 

SSLClient detected that there was not enough memory (>8000 bytes) to continue.

+
+ +
+
+
+
+ + + + diff --git a/docs/html/_s_s_l_client_impl_8h.js b/docs/html/_s_s_l_client_impl_8h.js new file mode 100644 index 0000000..9315330 --- /dev/null +++ b/docs/html/_s_s_l_client_impl_8h.js @@ -0,0 +1,19 @@ +var _s_s_l_client_impl_8h = +[ + [ "SSLClientImpl", "class_s_s_l_client_impl.html", "class_s_s_l_client_impl" ], + [ "DebugLevel", "_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395", [ + [ "SSL_NONE", "_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f", null ], + [ "SSL_ERROR", "_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec", null ], + [ "SSL_WARN", "_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d", null ], + [ "SSL_INFO", "_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91", null ] + ] ], + [ "Error", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5", [ + [ "SSL_OK", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c", null ], + [ "SSL_CLIENT_CONNECT_FAIL", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b", null ], + [ "SSL_BR_CONNECT_FAIL", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3", null ], + [ "SSL_CLIENT_WRTIE_ERROR", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b", null ], + [ "SSL_BR_WRITE_ERROR", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9", null ], + [ "SSL_INTERNAL_ERROR", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc", null ], + [ "SSL_OUT_OF_MEMORY", "_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/html/_s_s_l_client_impl_8h_source.html b/docs/html/_s_s_l_client_impl_8h_source.html new file mode 100644 index 0000000..b33a4e3 --- /dev/null +++ b/docs/html/_s_s_l_client_impl_8h_source.html @@ -0,0 +1,146 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClientImpl.h Source File + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLClientImpl.h
+
+
+Go to the documentation of this file.
1 /* Copyright 2019 OSU OPEnS Lab
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
4  * software and associated documentation files (the "Software"), to deal in the Software
5  * without restriction, including without limitation the rights to use, copy, modify,
6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7  * permit persons to whom the Software is furnished to do so, subject to the following
8  * conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in all
11  * copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "bearssl.h"
22 #include "Arduino.h"
23 #include "Client.h"
24 #include "SSLSession.h"
25 
26 #ifndef SSLClientImpl_H_
27 #define SSLClientImpl_H_
28 
37 enum Error {
38  SSL_OK = 0,
51 };
52 
59 enum DebugLevel {
61  SSL_NONE = 0,
63  SSL_ERROR = 1,
65  SSL_WARN = 2,
67  SSL_INFO = 3,
68 };
69 
71 class SSLClientImpl : public Client {
72 public:
74  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
75  const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug);
76 
77  //============================================
78  //= Functions implemented in SSLClientImpl.cpp
79  //============================================
80 
82  int connect_impl(IPAddress ip, uint16_t port);
84  int connect_impl(const char *host, uint16_t port);
86  size_t write_impl(const uint8_t *buf, size_t size);
88  int available_impl();
90  int read_impl(uint8_t *buf, size_t size);
92  int peek_impl();
94  void flush_impl();
96  void stop_impl();
98  uint8_t connected_impl();
100  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
102  void remove_session_impl(const char* host, const IPAddress& addr);
103 
104  //============================================
105  //= Functions implemented in SSLClient.h
106  //============================================
108  virtual uint16_t localPort() = 0;
110  virtual IPAddress remoteIP() = 0;
112  virtual uint16_t remotePort() = 0;
114  virtual size_t getSessionCount() const = 0;
115 
116 protected:
118  virtual Client& get_arduino_client() = 0;
119  virtual const Client& get_arduino_client() const = 0;
121  virtual SSLSession* get_session_array() = 0;
122  virtual const SSLSession* get_session_array() const = 0;
123 
124  //============================================
125  //= Functions implemented in SSLClientImpl.cpp
126  //============================================
127 
129  void m_print_prefix(const char* func_name, const DebugLevel level) const;
130 
132  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
133 
135  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
136 
138  template<typename T>
139  void m_print(const T str, const char* func_name, const DebugLevel level) const {
140  // check the current debug level and serial status
141  if (level > m_debug || !Serial) return;
142  // print prefix
143  m_print_prefix(func_name, level);
144  // print the message
145  Serial.println(str);
146  }
147 
149  template<typename T>
150  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
151 
152  template<typename T>
153  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
154 
155  template<typename T>
156  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
157 
158 private:
160  bool m_soft_connected(const char* func_name);
162  int m_start_ssl(const char* host, SSLSession& ssl_ses);
164  int m_run_until(const unsigned target);
166  unsigned m_update_engine();
168  int m_get_session_index(const char* host, const IPAddress& addr) const;
169 
170  //============================================
171  //= Data Members
172  //============================================
173 
174  // store pointers to the trust anchors
175  // should not be computed at runtime
176  const br_x509_trust_anchor *m_trust_anchors;
177  const size_t m_trust_anchors_num;
178  // store the pin to fetch an RNG see from
179  const int m_analog_pin;
180  // store an index of where a new session can be placed if we don't have any corresponding sessions
181  size_t m_session_index;
182  // store whether to enable debug logging
183  const DebugLevel m_debug;
184  // store the context values required for SSL
185  br_ssl_client_context m_sslctx;
186  br_x509_minimal_context m_x509ctx;
187  // use a mono-directional buffer by default to cut memory in half
188  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
189  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
190  // simply edit this value to change the buffer size to the desired value
191  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
192  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
200  unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 4];
201  static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size");
202  // store the index of where we are writing in the buffer
203  // so we can send our records all at once to prevent
204  // weird timing issues
205  size_t m_write_idx;
206 };
207 
208 #endif /* SSLClientImpl_H_ */
size_t write_impl(const uint8_t *buf, size_t size)
Definition: SSLClientImpl.cpp:130
+
virtual uint16_t remotePort()=0
+
void m_print(const T str, const char *func_name, const DebugLevel level) const
debugging print function, only prints if m_debug is true
Definition: SSLClientImpl.h:139
+
Definition: SSLClientImpl.h:65
+
virtual IPAddress remoteIP()=0
+
SSLSession & get_session_impl(const char *host, const IPAddress &addr)
Definition: SSLClientImpl.cpp:276
+
This class stores values which allow SSLClient to save and resume SSL sessions.
Definition: SSLSession.h:52
+
void m_info(const T str, const char *func_name) const
Prints a info message to serial, if info messages are enabled.
Definition: SSLClientImpl.h:150
+
SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
Definition: SSLClientImpl.cpp:53
+
void m_error(const T str, const char *func_name) const
Definition: SSLClientImpl.h:156
+
int peek_impl()
Definition: SSLClientImpl.cpp:209
+
Definition: SSLClientImpl.h:67
+
Definition: SSLClientImpl.h:63
+
Definition: SSLClientImpl.h:48
+
virtual size_t getSessionCount() const =0
+
virtual SSLSession * get_session_array()=0
+
Definition: SSLClientImpl.h:46
+
Definition: SSLClientImpl.h:38
+
void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
Prints the string associated with a write error.
Definition: SSLClientImpl.cpp:649
+
int available_impl()
Definition: SSLClientImpl.cpp:173
+
Error
Static constants defining the possible errors encountered.
Definition: SSLClientImpl.h:37
+
Definition: SSLClientImpl.h:42
+
int read_impl(uint8_t *buf, size_t size)
Definition: SSLClientImpl.cpp:194
+
void remove_session_impl(const char *host, const IPAddress &addr)
Definition: SSLClientImpl.cpp:295
+
Definition: SSLClientImpl.h:44
+
virtual Client & get_arduino_client()=0
+
Definition: SSLClientImpl.h:40
+
void m_print_prefix(const char *func_name, const DebugLevel level) const
Prints a debugging prefix to all logs, so we can attatch them to useful information.
Definition: SSLClientImpl.cpp:631
+
Definition: SSLClientImpl.h:61
+
void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
Print the text string associated with a BearSSL error code.
Definition: SSLClientImpl.cpp:664
+
void m_warn(const T str, const char *func_name) const
Definition: SSLClientImpl.h:153
+ +
int connect_impl(IPAddress ip, uint16_t port)
Definition: SSLClientImpl.cpp:74
+
Definition: SSLClientImpl.h:50
+
void stop_impl()
Definition: SSLClientImpl.cpp:229
+
void flush_impl()
Definition: SSLClientImpl.cpp:221
+
Implementation code to be inherited by SSLClient.
Definition: SSLClientImpl.h:71
+
virtual uint16_t localPort()=0
+
uint8_t connected_impl()
Definition: SSLClientImpl.cpp:250
+
DebugLevel
Level of verbosity used in logging for SSLClient.
Definition: SSLClientImpl.h:59
+
+
+ + + + diff --git a/docs/html/_s_s_l_session_8cpp.html b/docs/html/_s_s_l_session_8cpp.html new file mode 100644 index 0000000..5a05643 --- /dev/null +++ b/docs/html/_s_s_l_session_8cpp.html @@ -0,0 +1,107 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLSession.cpp File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLSession.cpp File Reference
+
+
+
#include "SSLSession.h"
+
+
+ + + + diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html new file mode 100644 index 0000000..4382701 --- /dev/null +++ b/docs/html/_s_s_l_session_8h.html @@ -0,0 +1,120 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLSession.h File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SSLSession.h File Reference
+
+
+
#include "bearssl.h"
+#include "Arduino.h"
+#include "IPAddress.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  SSLSession
 This class stores values which allow SSLClient to save and resume SSL sessions. More...
 
+
+
+ + + + diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html new file mode 100644 index 0000000..1bd7bf5 --- /dev/null +++ b/docs/html/_s_s_l_session_8h_source.html @@ -0,0 +1,115 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLSession.h Source File + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLSession.h
+
+
+Go to the documentation of this file.
1 /* Copyright 2019 OSU OPEnS Lab
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
4  * software and associated documentation files (the "Software"), to deal in the Software
5  * without restriction, including without limitation the rights to use, copy, modify,
6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7  * permit persons to whom the Software is furnished to do so, subject to the following
8  * conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in all
11  * copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
28 #include "bearssl.h"
29 #include "Arduino.h"
30 #include "IPAddress.h"
31 
32 #ifndef SSLSession_H_
33 #define SSLSession_H_
34 
52 class SSLSession : public br_ssl_session_parameters {
53 
54 public:
60  explicit SSLSession()
61  : m_valid_session(false)
62  , m_hostname()
63  , m_ip(INADDR_NONE) {}
64 
66  SSLSession& operator=(const SSLSession&) = delete;
67 
76  const String& get_hostname() const { return m_hostname; }
77 
86  const IPAddress& get_ip() const { return m_ip; }
87 
88  bool is_valid_session() const { return m_valid_session; }
89 
109  void set_parameters(const IPAddress& ip, const char* hostname = NULL);
110 
117  void clear_parameters();
118 
120  br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; }
121 
122 private:
123  bool m_valid_session;
124  // aparently a hostname has a max length of 256 chars. Go figure.
125  String m_hostname;
126  // store the IP Address we connected to
127  IPAddress m_ip;
128 };
129 
130 
131 
132 #endif /* SSLSession_H_ */
This class stores values which allow SSLClient to save and resume SSL sessions.
Definition: SSLSession.h:52
+
br_ssl_session_parameters * to_br_session()
returns a pointer to the ::br_ssl_session_parameters component of this class
Definition: SSLSession.h:120
+
void set_parameters(const IPAddress &ip, const char *hostname=NULL)
Set the ip address and hostname of the session.
Definition: SSLSession.cpp:4
+
void clear_parameters()
delete the parameters and invalidate the session Roughly equivalent to this_session = SSLSession(),...
Definition: SSLSession.cpp:19
+
bool is_valid_session() const
Definition: SSLSession.h:88
+
SSLSession & operator=(const SSLSession &)=delete
use clear_parameters or set_parameters instead
+
const IPAddress & get_ip() const
Get ::IPAddress associated with this session.
Definition: SSLSession.h:86
+
SSLSession()
SSLSession constructor.
Definition: SSLSession.h:60
+
const String & get_hostname() const
Get the hostname string associated with this session.
Definition: SSLSession.h:76
+
+
+ + + + diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html new file mode 100644 index 0000000..3df9e79 --- /dev/null +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -0,0 +1,158 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/TLS12_only_profile.c File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
TLS12_only_profile.c File Reference
+
+
+
#include "bearssl.h"
+#include "bearssl_ssl.h"
+#include "time_macros.h"
+
+ + + +

+Functions

void br_client_init_TLS12_only (br_ssl_client_context *cc, br_x509_minimal_context *xc, const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
 
+

Function Documentation

+ +

◆ br_client_init_TLS12_only()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void br_client_init_TLS12_only (br_ssl_client_context * cc,
br_x509_minimal_context * xc,
const br_x509_trust_anchor * trust_anchors,
size_t trust_anchors_num 
)
+
+ +
+
+
+
+ + + + diff --git a/docs/html/_t_l_s12__only__profile_8c.js b/docs/html/_t_l_s12__only__profile_8c.js new file mode 100644 index 0000000..798897c --- /dev/null +++ b/docs/html/_t_l_s12__only__profile_8c.js @@ -0,0 +1,4 @@ +var _t_l_s12__only__profile_8c = +[ + [ "br_client_init_TLS12_only", "_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3", null ] +]; \ No newline at end of file diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html new file mode 100644 index 0000000..1bcd811 --- /dev/null +++ b/docs/html/_trust_anchors_8md.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/TrustAnchors.md File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
C:/Users/Noah/Documents/Arduino/libraries/SSLClient/TrustAnchors.md File Reference
+
+
+
+
+ + + + diff --git a/docs/html/annotated.html b/docs/html/annotated.html new file mode 100644 index 0000000..45f5447 --- /dev/null +++ b/docs/html/annotated.html @@ -0,0 +1,112 @@ + + + + + + + +SSLClient: Class List + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Class List
+
+
+
Here are the classes, structs, unions and interfaces with brief descriptions:
+ + + + +
 CSSLClientThe main SSLClient class Check out README.md for more info
 CSSLClientImplImplementation code to be inherited by SSLClient
 CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
+
+
+
+ + + + diff --git a/docs/html/annotated_dup.js b/docs/html/annotated_dup.js new file mode 100644 index 0000000..c7c5acd --- /dev/null +++ b/docs/html/annotated_dup.js @@ -0,0 +1,6 @@ +var annotated_dup = +[ + [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ], + [ "SSLClientImpl", "class_s_s_l_client_impl.html", "class_s_s_l_client_impl" ], + [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] +]; \ No newline at end of file diff --git a/docs/html/bc_s.png b/docs/html/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..224b29aa9847d5a4b3902efd602b7ddf7d33e6c2 GIT binary patch literal 676 zcmV;V0$crwP)y__>=_9%My z{n931IS})GlGUF8K#6VIbs%684A^L3@%PlP2>_sk`UWPq@f;rU*V%rPy_ekbhXT&s z(GN{DxFv}*vZp`F>S!r||M`I*nOwwKX+BC~3P5N3-)Y{65c;ywYiAh-1*hZcToLHK ztpl1xomJ+Yb}K(cfbJr2=GNOnT!UFA7Vy~fBz8?J>XHsbZoDad^8PxfSa0GDgENZS zuLCEqzb*xWX2CG*b&5IiO#NzrW*;`VC9455M`o1NBh+(k8~`XCEEoC1Ybwf;vr4K3 zg|EB<07?SOqHp9DhLpS&bzgo70I+ghB_#)K7H%AMU3v}xuyQq9&Bm~++VYhF09a+U zl7>n7Jjm$K#b*FONz~fj;I->Bf;ule1prFN9FovcDGBkpg>)O*-}eLnC{6oZHZ$o% zXKW$;0_{8hxHQ>l;_*HATI(`7t#^{$(zLe}h*mqwOc*nRY9=?Sx4OOeVIfI|0V(V2 zBrW#G7Ss9wvzr@>H*`r>zE z+e8bOBgqIgldUJlG(YUDviMB`9+DH8n-s9SXRLyJHO1!=wY^79WYZMTa(wiZ!zP66 zA~!21vmF3H2{ngD;+`6j#~6j;$*f*G_2ZD1E;9(yaw7d-QnSCpK(cR1zU3qU0000< KMNUMnLSTYoA~SLT literal 0 HcmV?d00001 diff --git a/docs/html/bdwn.png b/docs/html/bdwn.png new file mode 100644 index 0000000000000000000000000000000000000000..940a0b950443a0bb1b216ac03c45b8a16c955452 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!3HEvS)PKZC{Gv1kP61Pb5HX&C2wk~_T + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/readme/cert.h File Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
cert.h File Reference
+
+
+ +

Go to the source code of this file.

+ + + + +

+Macros

#define TAs_NUM   1
 
+

Macro Definition Documentation

+ +

◆ TAs_NUM

+ +
+
+ + + + +
#define TAs_NUM   1
+
+ +
+
+
+
+ + + + diff --git a/docs/html/cert_8h.js b/docs/html/cert_8h.js new file mode 100644 index 0000000..ecc0439 --- /dev/null +++ b/docs/html/cert_8h.js @@ -0,0 +1,4 @@ +var cert_8h = +[ + [ "TAs_NUM", "cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948", null ] +]; \ No newline at end of file diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html new file mode 100644 index 0000000..aa6730c --- /dev/null +++ b/docs/html/cert_8h_source.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/readme/cert.h Source File + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
cert.h
+
+
+Go to the documentation of this file.
1 #ifndef _CERTIFICATES_H_
2 #define _CERTIFICATES_H_
3 
4 #ifdef __cplusplus
5 extern "C"
6 {
7 #endif
8 
9 /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually.
10  * Certificates are BearSSL br_x509_trust_anchor format. Included certs:
11  *
12  * Index: 0
13  * Label: VeriSign Class 3 Public Primary Certification Authority - G5
14  * Subject: C=US,O=VeriSign\, Inc.,OU=VeriSign Trust Network,OU=(c) 2006 VeriSign\, Inc. - For authorized use only,CN=VeriSign Class 3 Public Primary Certification Authority - G5
15  * Domain(s): www.amazon.com
16  */
17 
18 #define TAs_NUM 1
19 
20 static const unsigned char TA_DN0[] = {
21  0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
22  0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
23  0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c,
24  0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55,
25  0x04, 0x0b, 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
26  0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f,
27  0x72, 0x6b, 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
28  0x31, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65,
29  0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
30  0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f,
31  0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e,
32  0x6c, 0x79, 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
33  0x3c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c,
34  0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
35  0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72,
36  0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
37  0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47,
38  0x35,
39 };
40 
41 static const unsigned char TA_RSA_N0[] = {
42  0xaf, 0x24, 0x08, 0x08, 0x29, 0x7a, 0x35, 0x9e, 0x60, 0x0c, 0xaa, 0xe7,
43  0x4b, 0x3b, 0x4e, 0xdc, 0x7c, 0xbc, 0x3c, 0x45, 0x1c, 0xbb, 0x2b, 0xe0,
44  0xfe, 0x29, 0x02, 0xf9, 0x57, 0x08, 0xa3, 0x64, 0x85, 0x15, 0x27, 0xf5,
45  0xf1, 0xad, 0xc8, 0x31, 0x89, 0x5d, 0x22, 0xe8, 0x2a, 0xaa, 0xa6, 0x42,
46  0xb3, 0x8f, 0xf8, 0xb9, 0x55, 0xb7, 0xb1, 0xb7, 0x4b, 0xb3, 0xfe, 0x8f,
47  0x7e, 0x07, 0x57, 0xec, 0xef, 0x43, 0xdb, 0x66, 0x62, 0x15, 0x61, 0xcf,
48  0x60, 0x0d, 0xa4, 0xd8, 0xde, 0xf8, 0xe0, 0xc3, 0x62, 0x08, 0x3d, 0x54,
49  0x13, 0xeb, 0x49, 0xca, 0x59, 0x54, 0x85, 0x26, 0xe5, 0x2b, 0x8f, 0x1b,
50  0x9f, 0xeb, 0xf5, 0xa1, 0x91, 0xc2, 0x33, 0x49, 0xd8, 0x43, 0x63, 0x6a,
51  0x52, 0x4b, 0xd2, 0x8f, 0xe8, 0x70, 0x51, 0x4d, 0xd1, 0x89, 0x69, 0x7b,
52  0xc7, 0x70, 0xf6, 0xb3, 0xdc, 0x12, 0x74, 0xdb, 0x7b, 0x5d, 0x4b, 0x56,
53  0xd3, 0x96, 0xbf, 0x15, 0x77, 0xa1, 0xb0, 0xf4, 0xa2, 0x25, 0xf2, 0xaf,
54  0x1c, 0x92, 0x67, 0x18, 0xe5, 0xf4, 0x06, 0x04, 0xef, 0x90, 0xb9, 0xe4,
55  0x00, 0xe4, 0xdd, 0x3a, 0xb5, 0x19, 0xff, 0x02, 0xba, 0xf4, 0x3c, 0xee,
56  0xe0, 0x8b, 0xeb, 0x37, 0x8b, 0xec, 0xf4, 0xd7, 0xac, 0xf2, 0xf6, 0xf0,
57  0x3d, 0xaf, 0xdd, 0x75, 0x91, 0x33, 0x19, 0x1d, 0x1c, 0x40, 0xcb, 0x74,
58  0x24, 0x19, 0x21, 0x93, 0xd9, 0x14, 0xfe, 0xac, 0x2a, 0x52, 0xc7, 0x8f,
59  0xd5, 0x04, 0x49, 0xe4, 0x8d, 0x63, 0x47, 0x88, 0x3c, 0x69, 0x83, 0xcb,
60  0xfe, 0x47, 0xbd, 0x2b, 0x7e, 0x4f, 0xc5, 0x95, 0xae, 0x0e, 0x9d, 0xd4,
61  0xd1, 0x43, 0xc0, 0x67, 0x73, 0xe3, 0x14, 0x08, 0x7e, 0xe5, 0x3f, 0x9f,
62  0x73, 0xb8, 0x33, 0x0a, 0xcf, 0x5d, 0x3f, 0x34, 0x87, 0x96, 0x8a, 0xee,
63  0x53, 0xe8, 0x25, 0x15,
64 };
65 
66 static const unsigned char TA_RSA_E0[] = {
67  0x01, 0x00, 0x01,
68 };
69 
70 static const br_x509_trust_anchor TAs[] = {
71  {
72  { (unsigned char *)TA_DN0, sizeof TA_DN0 },
73  BR_X509_TA_CA,
74  {
75  BR_KEYTYPE_RSA,
76  { .rsa = {
77  (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
78  (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
79  } }
80  }
81  },
82 };
83 
84 #ifdef __cplusplus
85 } /* extern "C" */
86 #endif
87 
88 #endif /* ifndef _CERTIFICATES_H_ */
+
+ + + + diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html new file mode 100644 index 0000000..45f2498 --- /dev/null +++ b/docs/html/class_s_s_l_client-members.html @@ -0,0 +1,155 @@ + + + + + + + +SSLClient: Member List + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLClient< C, SessionCache > Member List
+
+
+ +

This is the complete list of members for SSLClient< C, SessionCache >, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
available()SSLClient< C, SessionCache >inlinevirtual
available_impl()SSLClientImpl
connect(IPAddress ip, uint16_t port)SSLClient< C, SessionCache >inlinevirtual
connect(const char *host, uint16_t port)SSLClient< C, SessionCache >inlinevirtual
connect_impl(IPAddress ip, uint16_t port)SSLClientImpl
connect_impl(const char *host, uint16_t port)SSLClientImpl
connected()SSLClient< C, SessionCache >inlinevirtual
connected_impl()SSLClientImpl
flush()SSLClient< C, SessionCache >inlinevirtual
flush_impl()SSLClientImpl
get_arduino_client()SSLClient< C, SessionCache >inlineprotectedvirtual
get_arduino_client() constSSLClient< C, SessionCache >inlineprotectedvirtual
get_session_array()SSLClient< C, SessionCache >inlineprotectedvirtual
get_session_array() constSSLClient< C, SessionCache >inlineprotectedvirtual
get_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
getClient()SSLClient< C, SessionCache >inline
getSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inlinevirtual
getSessionCount() constSSLClient< C, SessionCache >inlinevirtual
localPort()SSLClient< C, SessionCache >inlinevirtual
m_error(const T str, const char *func_name) constSSLClientImplinlineprotected
m_info(const T str, const char *func_name) constSSLClientImplinlineprotected
m_print(const T str, const char *func_name, const DebugLevel level) constSSLClientImplinlineprotected
m_print_br_error(const unsigned br_error_code, const DebugLevel level) constSSLClientImplprotected
m_print_prefix(const char *func_name, const DebugLevel level) constSSLClientImplprotected
m_print_ssl_error(const int ssl_error, const DebugLevel level) constSSLClientImplprotected
m_warn(const T str, const char *func_name) constSSLClientImplinlineprotected
operator bool()SSLClient< C, SessionCache >inlinevirtual
operator!=(const bool value)SSLClient< C, SessionCache >inlinevirtual
operator!=(const C &rhs)SSLClient< C, SessionCache >inlinevirtual
operator==(const bool value)SSLClient< C, SessionCache >inlinevirtual
operator==(const C &rhs)SSLClient< C, SessionCache >inlinevirtual
peek()SSLClient< C, SessionCache >inlinevirtual
peek_impl()SSLClientImpl
read()SSLClient< C, SessionCache >inlinevirtual
read(uint8_t *buf, size_t size)SSLClient< C, SessionCache >inlinevirtual
read_impl(uint8_t *buf, size_t size)SSLClientImpl
remoteIP()SSLClient< C, SessionCache >inlinevirtual
remotePort()SSLClient< C, SessionCache >inlinevirtual
remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
removeSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inlinevirtual
SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)SSLClient< C, SessionCache >inlineexplicit
SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit
stop()SSLClient< C, SessionCache >inlinevirtual
stop_impl()SSLClientImpl
write(uint8_t b)SSLClient< C, SessionCache >inlinevirtual
write(const uint8_t *buf, size_t size)SSLClient< C, SessionCache >inlinevirtual
write_impl(const uint8_t *buf, size_t size)SSLClientImpl
+
+ + + + diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html new file mode 100644 index 0000000..abed69b --- /dev/null +++ b/docs/html/class_s_s_l_client.html @@ -0,0 +1,1295 @@ + + + + + + + +SSLClient: SSLClient< C, SessionCache > Class Template Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SSLClient< C, SessionCache > Class Template Reference
+
+
+ +

The main SSLClient class Check out README.md for more info. + More...

+ +

#include <SSLClient.h>

+
+Inheritance diagram for SSLClient< C, SessionCache >:
+
+
+ + +SSLClientImpl + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
 Initialize SSLClient with all of the prerequisites needed. More...
 
virtual int connect (IPAddress ip, uint16_t port)
 Connect over SSL to a host specified by an IP address. More...
 
virtual int connect (const char *host, uint16_t port)
 Connect over SSL to a host specified by a hostname. More...
 
virtual size_t write (uint8_t b)
 
virtual size_t write (const uint8_t *buf, size_t size)
 Write some bytes to the SSL connection. More...
 
virtual int available ()
 Returns the number of bytes availible to read from the SSL Socket. More...
 
virtual int read ()
 Read a single byte, or -1 if none is available. More...
 
virtual int read (uint8_t *buf, size_t size)
 Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. More...
 
virtual int peek ()
 view the first byte of the buffer, without removing it from the SSLClient Buffer The implementation for this function can be found in SSLClientImpl::peek More...
 
virtual void flush ()
 Force writing the buffered bytes from SSLClient::write to the network. This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush. More...
 
virtual void stop ()
 Close the connection If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an error was encountered previously, this function will simply call m_client::stop. The implementation for this function can be found in SSLClientImpl::peek. More...
 
virtual uint8_t connected ()
 Check if the device is connected. Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently. More...
 
virtual SSLSessiongetSession (const char *host, const IPAddress &addr)
 Get a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
 
virtual void removeSession (const char *host, const IPAddress &addr)
 Clear the session corresponding to a host and IP. More...
 
virtual size_t getSessionCount () const
 Get the maximum number of SSL sessions that can be stored at once. More...
 
virtual operator bool ()
 Equivalent to SSLClient::connected() > 0. More...
 
virtual bool operator== (const bool value)
 
virtual bool operator!= (const bool value)
 
virtual bool operator== (const C &rhs)
 Returns whether or not two SSLClient objects have the same underlying client object. More...
 
virtual bool operator!= (const C &rhs)
 Returns whether or not two SSLClient objects do not have the same underlying client object. More...
 
virtual uint16_t localPort ()
 Returns the local port, C::localPort exists. Else return 0. More...
 
virtual IPAddress remoteIP ()
 Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE. More...
 
virtual uint16_t remotePort ()
 Returns the remote port, if C::remotePort exists. Else return 0. More...
 
C & getClient ()
 returns a reference to the client object stored in this class. Take care not to break it. More...
 
- Public Member Functions inherited from SSLClientImpl
 SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
 
int connect_impl (IPAddress ip, uint16_t port)
 
int connect_impl (const char *host, uint16_t port)
 
size_t write_impl (const uint8_t *buf, size_t size)
 
int available_impl ()
 
int read_impl (uint8_t *buf, size_t size)
 
int peek_impl ()
 
void flush_impl ()
 
void stop_impl ()
 
uint8_t connected_impl ()
 
SSLSessionget_session_impl (const char *host, const IPAddress &addr)
 
void remove_session_impl (const char *host, const IPAddress &addr)
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Protected Member Functions

virtual Client & get_arduino_client ()
 return an instance of m_client that is polymorphic and can be used by SSLClientImpl More...
 
virtual const Client & get_arduino_client () const
 
virtual SSLSessionget_session_array ()
 return an instance of the session array that is on the stack More...
 
virtual const SSLSessionget_session_array () const
 
- Protected Member Functions inherited from SSLClientImpl
void m_print_prefix (const char *func_name, const DebugLevel level) const
 Prints a debugging prefix to all logs, so we can attatch them to useful information. More...
 
void m_print_ssl_error (const int ssl_error, const DebugLevel level) const
 Prints the string associated with a write error. More...
 
void m_print_br_error (const unsigned br_error_code, const DebugLevel level) const
 Print the text string associated with a BearSSL error code. More...
 
template<typename T >
void m_print (const T str, const char *func_name, const DebugLevel level) const
 debugging print function, only prints if m_debug is true More...
 
template<typename T >
void m_info (const T str, const char *func_name) const
 Prints a info message to serial, if info messages are enabled. More...
 
template<typename T >
void m_warn (const T str, const char *func_name) const
 
template<typename T >
void m_error (const T str, const char *func_name) const
 
+

Detailed Description

+

template<class C, size_t SessionCache = 1>
+class SSLClient< C, SessionCache >

+ +

The main SSLClient class Check out README.md for more info.

+

Constructor & Destructor Documentation

+ +

◆ SSLClient()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SSLClient< C, SessionCache >::SSLClient (const C & client,
const br_x509_trust_anchor * trust_anchors,
const size_t trust_anchors_num,
const int analog_pin,
const DebugLevel debug = SSL_WARN 
)
+
+inlineexplicit
+
+ +

Initialize SSLClient with all of the prerequisites needed.

+
Precondition
You will need to generate an array of trust_anchors (root certificates) based off of the domains you want to make SSL connections to. Check out the TrustAnchors.md file for more info.
+
+The analog_pin should be set to input.
+
Parameters
+ + + + + + +
clientThe base network device to create an SSL socket on. This object will be copied and the copy will be stored in SSLClient.
trust_anchorsTrust anchors used in the verification of the SSL server certificate. Check out TrustAnchors.md for more info.
trust_anchors_numThe number of objects in the trust_anchors array.
analog_pinAn analog pin to pull random bytes from, used in seeding the RNG.
debugThe level of debug logging (use the DebugLevel enum).
+
+
+ +
+
+

Member Function Documentation

+ +

◆ available()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual int SSLClient< C, SessionCache >::available ()
+
+inlinevirtual
+
+ +

Returns the number of bytes availible to read from the SSL Socket.

+

This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

+

The implementation for this function can be found in SSLClientImpl::available

+
Precondition
SSLClient::connected must be true.
+
Returns
The number of bytes available (can be zero), or zero if any of the pre conditions aren't satisfied.
+ +
+
+ +

◆ connect() [1/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int SSLClient< C, SessionCache >::connect (IPAddress ip,
uint16_t port 
)
+
+inlinevirtual
+
+ +

Connect over SSL to a host specified by an IP address.

+

SSLClient::connect(host, port) should be preferred over this function, as verifying the domain name is a step in ensuring the certificate is legitimate, which is important to the security of the device. Additionally, SSL sessions cannot be resumed, which can drastically increase initial connect time.

+

This function initializes the socket by calling m_client::connect(IPAddress, uint16_t) with the parameters supplied, then once the socket uses BearSSL to to complete a SSL handshake. Due to the design of the SSL standard, this function will probably take an extended period (1-4sec) to negotiate the handshake and finish the connection. This function runs until the SSL handshake succeeds or fails.

+

SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

+

The implementation for this function can be found in SSLClientImpl::connect_impl(IPAddress, uint16_t).

+
Precondition
The underlying client object (passed in through the constructor) is in a non- error state, and must be able to access the IP.
+
+SSLClient can only have one connection at a time, so the client object must not already be connected.
+
+There must be sufficient memory available on the device to verify the certificate (if the free memory drops below 8000 bytes during certain points in the connection, SSLClient will fail).
+
+There must be a trust anchor given to the constructor that corresponds to the certificate provided by the IP address being connected to. For more information check out TrustAnchors.md .
+
Parameters
+ + + +
ipThe IP address to connect to
portthe port to connect to
+
+
+
Returns
1 if success, 0 if failure
+ +
+
+ +

◆ connect() [2/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int SSLClient< C, SessionCache >::connect (const char * host,
uint16_t port 
)
+
+inlinevirtual
+
+ +

Connect over SSL to a host specified by a hostname.

+

This function initializes the socket by calling m_client::connect(const char*, uint16_t) with the parameters supplied, then once the socket is open uses BearSSL to to complete a SSL handshake. This function runs until the SSL handshake succeeds or fails.

+

SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

+

This function will usually take around 4-10 seconds. If possible, this function also attempts to resume the SSL session if one is present matching the hostname string, which will reduce connection time to 100-500ms. To read more about this functionality, check out Session Caching in the README.

+

The implementation for this function can be found in SSLClientImpl::connect_impl(const char*, uint16_t)

+
Precondition
The underlying client object (passed in through the constructor) is in a non- error state, and must be able to access the IP.
+
+SSLClient can only have one connection at a time, so the client object must not already be connected.
+
+There must be sufficient memory available on the device to verify the certificate (if the free memory drops below 8000 bytes during certain points in the connection, SSLClient will fail).
+
+There must be a trust anchor given to the constructor that corresponds to the certificate provided by the IP address being connected to. For more information check out TrustAnchors.md .
+
Parameters
+ + + +
hostThe hostname as a null-terminated c-string ("www.google.com")
portThe port to connect to on the host (443 for HTTPS)
+
+
+
Returns
1 of success, 0 if failure
+ +
+
+ +

◆ connected()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual uint8_t SSLClient< C, SessionCache >::connected ()
+
+inlinevirtual
+
+ +

Check if the device is connected. Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently.

+

The implementation for this function can be found in SSLClientImpl::connected_impl.

+
Returns
1 if connected, 0 if not
+ +
+
+ +

◆ flush()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual void SSLClient< C, SessionCache >::flush ()
+
+inlinevirtual
+
+ +

Force writing the buffered bytes from SSLClient::write to the network. This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush.

+ +
+
+ +

◆ get_arduino_client() [1/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual Client& SSLClient< C, SessionCache >::get_arduino_client ()
+
+inlineprotectedvirtual
+
+ +

return an instance of m_client that is polymorphic and can be used by SSLClientImpl

+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ get_arduino_client() [2/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual const Client& SSLClient< C, SessionCache >::get_arduino_client () const
+
+inlineprotectedvirtual
+
+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ get_session_array() [1/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual SSLSession* SSLClient< C, SessionCache >::get_session_array ()
+
+inlineprotectedvirtual
+
+ +

return an instance of the session array that is on the stack

+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ get_session_array() [2/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual const SSLSession* SSLClient< C, SessionCache >::get_session_array () const
+
+inlineprotectedvirtual
+
+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ getClient()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
C& SSLClient< C, SessionCache >::getClient ()
+
+inline
+
+ +

returns a reference to the client object stored in this class. Take care not to break it.

+ +
+
+ +

◆ getSession()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual SSLSession& SSLClient< C, SessionCache >::getSession (const char * host,
const IPAddress & addr 
)
+
+inlinevirtual
+
+ +

Get a session reference corresponding to a host and IP, or a reference to a empty session if none exist.

+

If no session corresponding to the host and IP exist, then this function will cycle through sessions in a rotating order. This allows the session cache to continually store sessions, however it will also result in old sessions being cleared and returned. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

+

The implementation for this function can be found at SSLClientImpl::get_session_impl.

+
Parameters
+ + + +
hostA hostname c string, or NULL if one is not available
addrAn IP address
+
+
+
Returns
A reference to an SSLSession object
+ +
+
+ +

◆ getSessionCount()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual size_t SSLClient< C, SessionCache >::getSessionCount () const
+
+inlinevirtual
+
+ +

Get the maximum number of SSL sessions that can be stored at once.

+
Returns
The SessionCache template parameter.
+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ localPort()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual uint16_t SSLClient< C, SessionCache >::localPort ()
+
+inlinevirtual
+
+ +

Returns the local port, C::localPort exists. Else return 0.

+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ operator bool()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual SSLClient< C, SessionCache >::operator bool ()
+
+inlinevirtual
+
+ +

Equivalent to SSLClient::connected() > 0.

+
Returns
true if connected, false if not
+ +
+
+ +

◆ operator!=() [1/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + +
virtual bool SSLClient< C, SessionCache >::operator!= (const bool value)
+
+inlinevirtual
+
+
See also
SSLClient::operator bool
+ +
+
+ +

◆ operator!=() [2/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + +
virtual bool SSLClient< C, SessionCache >::operator!= (const C & rhs)
+
+inlinevirtual
+
+ +

Returns whether or not two SSLClient objects do not have the same underlying client object.

+ +
+
+ +

◆ operator==() [1/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + +
virtual bool SSLClient< C, SessionCache >::operator== (const bool value)
+
+inlinevirtual
+
+
See also
SSLClient::operator bool
+ +
+
+ +

◆ operator==() [2/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + +
virtual bool SSLClient< C, SessionCache >::operator== (const C & rhs)
+
+inlinevirtual
+
+ +

Returns whether or not two SSLClient objects have the same underlying client object.

+ +
+
+ +

◆ peek()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual int SSLClient< C, SessionCache >::peek ()
+
+inlinevirtual
+
+ +

view the first byte of the buffer, without removing it from the SSLClient Buffer The implementation for this function can be found in SSLClientImpl::peek

+
Precondition
SSLClient::available must be >0
+
Returns
The first byte received, or -1 if the preconditions are not satisfied (warning: do not use if your data may be -1, as the return value is ambiguous)
+ +
+
+ +

◆ read() [1/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual int SSLClient< C, SessionCache >::read ()
+
+inlinevirtual
+
+ +

Read a single byte, or -1 if none is available.

+
See also
SSLClient::read(uint8_t*, size_t)
+ +
+
+ +

◆ read() [2/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int SSLClient< C, SessionCache >::read (uint8_t * buf,
size_t size 
)
+
+inlinevirtual
+
+ +

Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read.

+

This function checks if bytes are ready to be read by calling SSLClient::available, and if so copies size number of bytes from the IO buffer into the buf pointer. Data read using this function will not include any SSL or socket commands, as the Client and BearSSL will capture those and process them separately.

+

If you find that you are having a lot of timeout errors, SSLClient may be experiencing a buffer overflow. Checkout README.md for more information.

+

The implementation for this function can be found in SSLClientImpl::read_impl(uint8_t*, size_t)

+
Precondition
SSLClient::available must be >0
+
Parameters
+ + + +
bufThe pointer to the buffer to put SSL application data into
sizeThe size (in bytes) to copy to the buffer
+
+
+
Returns
The number of bytes copied (<= size), or -1 if the preconditions are not satisfied.
+ +
+
+ +

◆ remoteIP()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual IPAddress SSLClient< C, SessionCache >::remoteIP ()
+
+inlinevirtual
+
+ +

Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.

+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ remotePort()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual uint16_t SSLClient< C, SessionCache >::remotePort ()
+
+inlinevirtual
+
+ +

Returns the remote port, if C::remotePort exists. Else return 0.

+ +

Implements SSLClientImpl.

+ +
+
+ +

◆ removeSession()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void SSLClient< C, SessionCache >::removeSession (const char * host,
const IPAddress & addr 
)
+
+inlinevirtual
+
+ +

Clear the session corresponding to a host and IP.

+

The implementation for this function can be found at SSLClientImpl::remove_session_impl.

+
Parameters
+ + + +
hostA hostname c string, or NULL if one is not available
addrAn IP address
+
+
+ +
+
+ +

◆ stop()

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + +
virtual void SSLClient< C, SessionCache >::stop ()
+
+inlinevirtual
+
+ +

Close the connection If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an error was encountered previously, this function will simply call m_client::stop. The implementation for this function can be found in SSLClientImpl::peek.

+ +
+
+ +

◆ write() [1/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + +
virtual size_t SSLClient< C, SessionCache >::write (uint8_t b)
+
+inlinevirtual
+
+
See also
SSLClient::write(uint8_t*, size_t)
+ +
+
+ +

◆ write() [2/2]

+ +
+
+
+template<class C , size_t SessionCache = 1>
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual size_t SSLClient< C, SessionCache >::write (const uint8_t * buf,
size_t size 
)
+
+inlinevirtual
+
+ +

Write some bytes to the SSL connection.

+

Assuming all preconditions are met, this function writes data to the BearSSL IO buffer, BUT does not initially send the data. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready for writing, and will write the data to the network. Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until all the data in buf is sent–attempting to keep all writes to the network grouped together. For information on why this is the case check out README.md .

+

The implementation for this function can be found in SSLClientImpl::write_impl(const uint8_t*, size_t)

+
Precondition
The socket and SSL layer must be connected, meaning SSLClient::connected must be true.
+
+BearSSL must not be waiting for the recipt of user data (if it is, there is probably an error with how the protocol in implemented in your code).
+
Parameters
+ + + +
bufthe pointer to a buffer of bytes to copy
sizethe number of bytes to copy from the buffer
+
+
+
Returns
The number of bytes copied to the buffer (size), or zero if the BearSSL engine fails to become ready for writing data.
+ +
+
+
The documentation for this class was generated from the following file:
    +
  • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClient.h
  • +
+
+
+ + + + diff --git a/docs/html/class_s_s_l_client.js b/docs/html/class_s_s_l_client.js new file mode 100644 index 0000000..0c36bb8 --- /dev/null +++ b/docs/html/class_s_s_l_client.js @@ -0,0 +1,31 @@ +var class_s_s_l_client = +[ + [ "SSLClient", "class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0", null ], + [ "available", "class_s_s_l_client.html#a40ec85568d0aec376219125b604dbc29", null ], + [ "connect", "class_s_s_l_client.html#ae6540b9a02f1392bf2ac48421189f70e", null ], + [ "connect", "class_s_s_l_client.html#a5814c11e96848c2bcea78210f099aad5", null ], + [ "connected", "class_s_s_l_client.html#a7318aadc0ec9775bffaaac0b1f00aaf8", null ], + [ "flush", "class_s_s_l_client.html#a51eb668f6a328a6a66298c6bc1361d41", null ], + [ "get_arduino_client", "class_s_s_l_client.html#ab3ebfbca41a56bfa11e34aac2c2e0106", null ], + [ "get_arduino_client", "class_s_s_l_client.html#a20742b36588c45435139a4f47fe0f1f6", null ], + [ "get_session_array", "class_s_s_l_client.html#aaa52b481eb1d36a0ae1d208daa2fec51", null ], + [ "get_session_array", "class_s_s_l_client.html#ab076a76b142b553c0dfd29174d4e17e7", null ], + [ "getClient", "class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41", null ], + [ "getSession", "class_s_s_l_client.html#ae3f27a36ff9c0cd1e2bea5e1708b6e4f", null ], + [ "getSessionCount", "class_s_s_l_client.html#a36bb344866e4cbcba3bbfcf4d33e5187", null ], + [ "localPort", "class_s_s_l_client.html#ac725067566ee411680c88575c148300b", null ], + [ "operator bool", "class_s_s_l_client.html#a319a722dae252efdd85fdbaf5c7fbf17", null ], + [ "operator!=", "class_s_s_l_client.html#a9a060e49d0685c6c6795558e41cd3323", null ], + [ "operator!=", "class_s_s_l_client.html#a518f4ed733814f2f4a8c7f838555eb35", null ], + [ "operator==", "class_s_s_l_client.html#a6fb2e8a1cc54dd82a72217e5c4533e02", null ], + [ "operator==", "class_s_s_l_client.html#a26f9418e33d4ca459f78de98d3af43bb", null ], + [ "peek", "class_s_s_l_client.html#a227b1cbbe91bcb21153c09f97d0dd484", null ], + [ "read", "class_s_s_l_client.html#ac70b900ff798f9fd33f6367fcc9fad77", null ], + [ "read", "class_s_s_l_client.html#ae31dd88a1af8ec3794fb48f26a3dd4bf", null ], + [ "remoteIP", "class_s_s_l_client.html#ae2d1d17ee568ec2a37756bf6894dcd05", null ], + [ "remotePort", "class_s_s_l_client.html#ae8bd9420fec3b11f855729c4ecfe1c2c", null ], + [ "removeSession", "class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0", null ], + [ "stop", "class_s_s_l_client.html#a158d87df3fe118b7565a19b72f310322", null ], + [ "write", "class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270", null ], + [ "write", "class_s_s_l_client.html#a3a48b190985cdea2eba79ef0bdc80461", null ] +]; \ No newline at end of file diff --git a/docs/html/class_s_s_l_client.png b/docs/html/class_s_s_l_client.png new file mode 100644 index 0000000000000000000000000000000000000000..0519c9e396e13e9d09044f374bcda247c9e4d98d GIT binary patch literal 861 zcmeAS@N?(olHy`uVBq!ia0vp^`+&HEgBeKXbuN?#QW60^A+G=b{|7Q(y!l$%e`o@b z1;z&s9ANFd15(3L666=m08|75S5Ji)F)%Q_@pN$vsbG9N_jTW9D;@@Qw^jH5_xf|I zh9A1QUbj@Ya_Y^7oh6ejp6P2YeIh<-)v9o(_|U6e7s5lgKH~c8?pjfj9ej0F?XTl{ z7vke9p1gCi-~ZmSsa8|&ZrPeuzZCVZ-@m+K&dODFUF%<-7xoJM8oKWKeX~u`e}zgH z#)r$bpS*niZ_TFn387d01><8wL$%?iD}4zKUAyD;@+p&|8P+{vdmw)Q*Y?@j_4j|3 zSD*iP?(5=D3^xRSF@&|)HHa?cPjG#~9D$eX6FDvQBX@U42hja4N4hSE3vPTQ`?uu( z>R(@X*q&cl^HQNqLP+o@bN-9`SF!hxyDrJwzs&wys^GTAAiq4W;C+An+KS$P-!3n; zzjpt!M(31mS>}O)6U8g?Uz;&oTwl*zy7@}JQTn3&xlit2o}Y8K`DVS_53T0ude=YdY!{cn>_ zH+B5%sj0eu0>d65XgImn-#xzc{9>)=haHX|_$>SRz@M8Z&pzKg`>Xlab?+ZL-2HW< z?!66z!Q&s#>MzRw-o$bH<35r8yct;yZB?Ax_5Qz)53`NEv>-;dF2`ryGEgwAm@}2V z|FdGer@^*|sb|mLy?SrU?OkUX&V7CT)FS@5(bdWwXS2%0Z*P@jyUf2}t<6;%zc1V0 zPQ8C~&5N4JcJi+$r7w%GTYTyLx6-(4pVw9!{JuM7&e?xE-oIWs|Hby_?V zRQJ35&;BNU*6u(!M=gW4ll%d$|G$8#ciMl3_GPnL-A&t00rLWbr>mdKI;Vst092>5 AfB*mh literal 0 HcmV?d00001 diff --git a/docs/html/class_s_s_l_client_impl-members.html b/docs/html/class_s_s_l_client_impl-members.html new file mode 100644 index 0000000..49c0e58 --- /dev/null +++ b/docs/html/class_s_s_l_client_impl-members.html @@ -0,0 +1,135 @@ + + + + + + + +SSLClient: Member List + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLClientImpl Member List
+
+
+ +

This is the complete list of members for SSLClientImpl, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
available_impl()SSLClientImpl
connect_impl(IPAddress ip, uint16_t port)SSLClientImpl
connect_impl(const char *host, uint16_t port)SSLClientImpl
connected_impl()SSLClientImpl
flush_impl()SSLClientImpl
get_arduino_client()=0SSLClientImplprotectedpure virtual
get_arduino_client() const =0SSLClientImplprotectedpure virtual
get_session_array()=0SSLClientImplprotectedpure virtual
get_session_array() const =0SSLClientImplprotectedpure virtual
get_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
getSessionCount() const =0SSLClientImplpure virtual
localPort()=0SSLClientImplpure virtual
m_error(const T str, const char *func_name) constSSLClientImplinlineprotected
m_info(const T str, const char *func_name) constSSLClientImplinlineprotected
m_print(const T str, const char *func_name, const DebugLevel level) constSSLClientImplinlineprotected
m_print_br_error(const unsigned br_error_code, const DebugLevel level) constSSLClientImplprotected
m_print_prefix(const char *func_name, const DebugLevel level) constSSLClientImplprotected
m_print_ssl_error(const int ssl_error, const DebugLevel level) constSSLClientImplprotected
m_warn(const T str, const char *func_name) constSSLClientImplinlineprotected
peek_impl()SSLClientImpl
read_impl(uint8_t *buf, size_t size)SSLClientImpl
remoteIP()=0SSLClientImplpure virtual
remotePort()=0SSLClientImplpure virtual
remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit
stop_impl()SSLClientImpl
write_impl(const uint8_t *buf, size_t size)SSLClientImpl
+
+ + + + diff --git a/docs/html/class_s_s_l_client_impl.html b/docs/html/class_s_s_l_client_impl.html new file mode 100644 index 0000000..7ecee39 --- /dev/null +++ b/docs/html/class_s_s_l_client_impl.html @@ -0,0 +1,1013 @@ + + + + + + + +SSLClient: SSLClientImpl Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SSLClientImpl Class Referenceabstract
+
+
+ +

Implementation code to be inherited by SSLClient. + More...

+ +

#include <SSLClientImpl.h>

+
+Inheritance diagram for SSLClientImpl:
+
+
+ + +SSLClient< C, SessionCache > + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
 
int connect_impl (IPAddress ip, uint16_t port)
 
int connect_impl (const char *host, uint16_t port)
 
size_t write_impl (const uint8_t *buf, size_t size)
 
int available_impl ()
 
int read_impl (uint8_t *buf, size_t size)
 
int peek_impl ()
 
void flush_impl ()
 
void stop_impl ()
 
uint8_t connected_impl ()
 
SSLSessionget_session_impl (const char *host, const IPAddress &addr)
 
void remove_session_impl (const char *host, const IPAddress &addr)
 
virtual uint16_t localPort ()=0
 
virtual IPAddress remoteIP ()=0
 
virtual uint16_t remotePort ()=0
 
virtual size_t getSessionCount () const =0
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Protected Member Functions

virtual Client & get_arduino_client ()=0
 
virtual const Client & get_arduino_client () const =0
 
virtual SSLSessionget_session_array ()=0
 
virtual const SSLSessionget_session_array () const =0
 
void m_print_prefix (const char *func_name, const DebugLevel level) const
 Prints a debugging prefix to all logs, so we can attatch them to useful information. More...
 
void m_print_ssl_error (const int ssl_error, const DebugLevel level) const
 Prints the string associated with a write error. More...
 
void m_print_br_error (const unsigned br_error_code, const DebugLevel level) const
 Print the text string associated with a BearSSL error code. More...
 
template<typename T >
void m_print (const T str, const char *func_name, const DebugLevel level) const
 debugging print function, only prints if m_debug is true More...
 
template<typename T >
void m_info (const T str, const char *func_name) const
 Prints a info message to serial, if info messages are enabled. More...
 
template<typename T >
void m_warn (const T str, const char *func_name) const
 
template<typename T >
void m_error (const T str, const char *func_name) const
 
+

Detailed Description

+

Implementation code to be inherited by SSLClient.

+

Constructor & Destructor Documentation

+ +

◆ SSLClientImpl()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SSLClientImpl::SSLClientImpl (const br_x509_trust_anchor * trust_anchors,
const size_t trust_anchors_num,
const int analog_pin,
const DebugLevel debug 
)
+
+explicit
+
+
+

Member Function Documentation

+ +

◆ available_impl()

+ +
+
+ + + + + + + +
int SSLClientImpl::available_impl ()
+
+
See also
SSLClient::available
+ +
+
+ +

◆ connect_impl() [1/2]

+ +
+
+ + + + + + + + + + + + + + + + + + +
int SSLClientImpl::connect_impl (IPAddress ip,
uint16_t port 
)
+
+
+ +

◆ connect_impl() [2/2]

+ +
+
+ + + + + + + + + + + + + + + + + + +
int SSLClientImpl::connect_impl (const char * host,
uint16_t port 
)
+
+
+ +

◆ connected_impl()

+ +
+
+ + + + + + + +
uint8_t SSLClientImpl::connected_impl ()
+
+
See also
SSLClient::connected
+ +
+
+ +

◆ flush_impl()

+ +
+
+ + + + + + + +
void SSLClientImpl::flush_impl ()
+
+
See also
SSLClient::flush
+ +
+
+ +

◆ get_arduino_client() [1/2]

+ +
+
+ + + + + +
+ + + + + + + +
virtual Client& SSLClientImpl::get_arduino_client ()
+
+protectedpure virtual
+
+
+ +

◆ get_arduino_client() [2/2]

+ +
+
+ + + + + +
+ + + + + + + +
virtual const Client& SSLClientImpl::get_arduino_client () const
+
+protectedpure virtual
+
+ +

Implemented in SSLClient< C, SessionCache >.

+ +
+
+ +

◆ get_session_array() [1/2]

+ +
+
+ + + + + +
+ + + + + + + +
virtual SSLSession* SSLClientImpl::get_session_array ()
+
+protectedpure virtual
+
+
+ +

◆ get_session_array() [2/2]

+ +
+
+ + + + + +
+ + + + + + + +
virtual const SSLSession* SSLClientImpl::get_session_array () const
+
+protectedpure virtual
+
+ +

Implemented in SSLClient< C, SessionCache >.

+ +
+
+ +

◆ get_session_impl()

+ +
+
+ + + + + + + + + + + + + + + + + + +
SSLSession & SSLClientImpl::get_session_impl (const char * host,
const IPAddress & addr 
)
+
+
+ +

◆ getSessionCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual size_t SSLClientImpl::getSessionCount () const
+
+pure virtual
+
+
+ +

◆ localPort()

+ +
+
+ + + + + +
+ + + + + + + +
virtual uint16_t SSLClientImpl::localPort ()
+
+pure virtual
+
+
+ +

◆ m_error()

+ +
+
+
+template<typename T >
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
void SSLClientImpl::m_error (const T str,
const char * func_name 
) const
+
+inlineprotected
+
+ +
+
+ +

◆ m_info()

+ +
+
+
+template<typename T >
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
void SSLClientImpl::m_info (const T str,
const char * func_name 
) const
+
+inlineprotected
+
+ +

Prints a info message to serial, if info messages are enabled.

+ +
+
+ +

◆ m_print()

+ +
+
+
+template<typename T >
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
void SSLClientImpl::m_print (const T str,
const char * func_name,
const DebugLevel level 
) const
+
+inlineprotected
+
+ +

debugging print function, only prints if m_debug is true

+ +
+
+ +

◆ m_print_br_error()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
void SSLClientImpl::m_print_br_error (const unsigned br_error_code,
const DebugLevel level 
) const
+
+protected
+
+ +

Print the text string associated with a BearSSL error code.

+ +
+
+ +

◆ m_print_prefix()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
void SSLClientImpl::m_print_prefix (const char * func_name,
const DebugLevel level 
) const
+
+protected
+
+ +

Prints a debugging prefix to all logs, so we can attatch them to useful information.

+ +
+
+ +

◆ m_print_ssl_error()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
void SSLClientImpl::m_print_ssl_error (const int ssl_error,
const DebugLevel level 
) const
+
+protected
+
+ +

Prints the string associated with a write error.

+ +
+
+ +

◆ m_warn()

+ +
+
+
+template<typename T >
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
void SSLClientImpl::m_warn (const T str,
const char * func_name 
) const
+
+inlineprotected
+
+ +
+
+ +

◆ peek_impl()

+ +
+
+ + + + + + + +
int SSLClientImpl::peek_impl ()
+
+
See also
SSLClient::peek
+ +
+
+ +

◆ read_impl()

+ +
+
+ + + + + + + + + + + + + + + + + + +
int SSLClientImpl::read_impl (uint8_t * buf,
size_t size 
)
+
+
+ +

◆ remoteIP()

+ +
+
+ + + + + +
+ + + + + + + +
virtual IPAddress SSLClientImpl::remoteIP ()
+
+pure virtual
+
+
+ +

◆ remotePort()

+ +
+
+ + + + + +
+ + + + + + + +
virtual uint16_t SSLClientImpl::remotePort ()
+
+pure virtual
+
+
+ +

◆ remove_session_impl()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void SSLClientImpl::remove_session_impl (const char * host,
const IPAddress & addr 
)
+
+
+ +

◆ stop_impl()

+ +
+
+ + + + + + + +
void SSLClientImpl::stop_impl ()
+
+
See also
SSLClient::stop
+ +
+
+ +

◆ write_impl()

+ +
+
+ + + + + + + + + + + + + + + + + + +
size_t SSLClientImpl::write_impl (const uint8_t * buf,
size_t size 
)
+
+
+
The documentation for this class was generated from the following files: +
+
+ + + + diff --git a/docs/html/class_s_s_l_client_impl.js b/docs/html/class_s_s_l_client_impl.js new file mode 100644 index 0000000..6a702fd --- /dev/null +++ b/docs/html/class_s_s_l_client_impl.js @@ -0,0 +1,30 @@ +var class_s_s_l_client_impl = +[ + [ "SSLClientImpl", "class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b", null ], + [ "available_impl", "class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b", null ], + [ "connect_impl", "class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b", null ], + [ "connect_impl", "class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba", null ], + [ "connected_impl", "class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb", null ], + [ "flush_impl", "class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788", null ], + [ "get_arduino_client", "class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3", null ], + [ "get_arduino_client", "class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336", null ], + [ "get_session_array", "class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b", null ], + [ "get_session_array", "class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4", null ], + [ "get_session_impl", "class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e", null ], + [ "getSessionCount", "class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b", null ], + [ "localPort", "class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5", null ], + [ "m_error", "class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83", null ], + [ "m_info", "class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c", null ], + [ "m_print", "class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117", null ], + [ "m_print_br_error", "class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed", null ], + [ "m_print_prefix", "class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f", null ], + [ "m_print_ssl_error", "class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075", null ], + [ "m_warn", "class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f", null ], + [ "peek_impl", "class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d", null ], + [ "read_impl", "class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe", null ], + [ "remoteIP", "class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387", null ], + [ "remotePort", "class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5", null ], + [ "remove_session_impl", "class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1", null ], + [ "stop_impl", "class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6", null ], + [ "write_impl", "class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d", null ] +]; \ No newline at end of file diff --git a/docs/html/class_s_s_l_client_impl.png b/docs/html/class_s_s_l_client_impl.png new file mode 100644 index 0000000000000000000000000000000000000000..57bba5e0b5364acf5d0c30364446f9ee2aaf817d GIT binary patch literal 870 zcmeAS@N?(olHy`uVBq!ia0vp^`+&HEgBeKXbuN?#QW60^A+G=b{|7Q(y!l$%e`o@b z1;z&s9ANFd15(3L666=m08|75S5Ji)F)%QF^>lFzsbG9N_wA(B3Oo+{g~#^%m%hI( z%x>xJ-Pe4LC(E7-3V6t&_)m4|ls`^Epr*_-oawu$YDQ=Q+N=3Jlq*HGke4 zroYD<+~4Va`CM_{{Koc2ak=|LL+y_|{Z%b7b=s;|%YPXEt#nwq>ff~2U$-~E3ETf= z*M;@Q{f8gC{9Kp!Mm-|*Yw(fq@X)JW7s5lgDt!qJUCU7$8mgW5OLOTHu?Fo(#y^ju z>tkbo|Gu{WX7#u7b@DUW5AR2-KOjBl!u>0|cfDtS^(psPa;#b6@4fj)_g1OBdcJ?}b+`K2yRIAu zdPP;^>B75TnEo^syKk>-y#A}yJyz%I>=QFzAa~e&Wo%QsnR%=7PS<#qD+n^b6PV7r@-RquwIO>!dbA_$HpW zwe_37zj+^HZ^YjqyO2M@^#yZ;;4g--7P|&feB1+5QX{8vM@~{Qc$k6qSq~ z|9JNQqWtSkoVVZCYQMX>;fj(H?^m(B(0}*&!)#*@Er^j-lWtzVvj6LM1Ff~69u(R< z(e_NyIh=6z?A@z2{xetD?K;c7=i2)1kH6YYUwUr+?Kf%V8}Gh;nEFdR!`OdopYY$e z6;BOk%g&X*^gKEC!V(=#qQl@slM%7oM7fD)A+mP z!FxMSXzE@3Z~VJEEZ*gbKS!;gpte)I%Mq^szfNz`$@|Ifv3{n*m&N;T0y71Jr>mdK II;Vst0O;YlPyhe` literal 0 HcmV?d00001 diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html new file mode 100644 index 0000000..b854c41 --- /dev/null +++ b/docs/html/class_s_s_l_session-members.html @@ -0,0 +1,116 @@ + + + + + + + +SSLClient: Member List + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLSession Member List
+
+
+ +

This is the complete list of members for SSLSession, including all inherited members.

+ + + + + + + + + +
clear_parameters()SSLSession
get_hostname() constSSLSessioninline
get_ip() constSSLSessioninline
is_valid_session() constSSLSessioninline
operator=(const SSLSession &)=deleteSSLSession
set_parameters(const IPAddress &ip, const char *hostname=NULL)SSLSession
SSLSession()SSLSessioninlineexplicit
to_br_session()SSLSessioninline
+
+ + + + diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html new file mode 100644 index 0000000..07d85e0 --- /dev/null +++ b/docs/html/class_s_s_l_session.html @@ -0,0 +1,382 @@ + + + + + + + +SSLClient: SSLSession Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SSLSession Class Reference
+
+
+ +

This class stores values which allow SSLClient to save and resume SSL sessions. + More...

+ +

#include <SSLSession.h>

+
+Inheritance diagram for SSLSession:
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 SSLSession ()
 SSLSession constructor. More...
 
SSLSessionoperator= (const SSLSession &)=delete
 use clear_parameters or set_parameters instead More...
 
const String & get_hostname () const
 Get the hostname string associated with this session. More...
 
const IPAddress & get_ip () const
 Get ::IPAddress associated with this session. More...
 
bool is_valid_session () const
 
void set_parameters (const IPAddress &ip, const char *hostname=NULL)
 Set the ip address and hostname of the session. More...
 
void clear_parameters ()
 delete the parameters and invalidate the session Roughly equivalent to this_session = SSLSession(), however this function preserves the String object, allowing it to better handle the dynamic memory needed. More...
 
br_ssl_session_parameters * to_br_session ()
 returns a pointer to the ::br_ssl_session_parameters component of this class More...
 
+

Detailed Description

+

This class stores values which allow SSLClient to save and resume SSL sessions.

+

SSLSession.h

+

This file contains a simple utility class to store parameters about an SSL Session for reuse later.This class was created to extend the values stored in br_ssl_session_parameters, which allow BearSSL to resume an SSL session. When testing BearSSL's session resumption feature, it was observed that BearSSL can only resume a session that was was started with the same server. This becomes an issue when using repeated requests to a domain name which can resolve to multiple IP addresses ("api.github.com"), as the device will switch between two or three servers. Since BearSSL only stores one session at a time, this results in session resumption being few and far between.

+

To remedy this problem, an SSLSession stores the IPAddress and hostname, along with the parameters in br_ssl_session_parameters struct. Using this data, SSLClient is able to remember which IPAddress is associated with which session, allowing it to reconnect to the last IPAddress, as opposed to any associated with the domain.

+

Constructor & Destructor Documentation

+ +

◆ SSLSession()

+ +
+
+ + + + + +
+ + + + + + + +
SSLSession::SSLSession ()
+
+inlineexplicit
+
+ +

SSLSession constructor.

+

Sets all parameters to zero, and invalidates the session

+ +
+
+

Member Function Documentation

+ +

◆ clear_parameters()

+ +
+
+ + + + + + + +
void SSLSession::clear_parameters ()
+
+ +

delete the parameters and invalidate the session Roughly equivalent to this_session = SSLSession(), however this function preserves the String object, allowing it to better handle the dynamic memory needed.

+ +
+
+ +

◆ get_hostname()

+ +
+
+ + + + + +
+ + + + + + + +
const String& SSLSession::get_hostname () const
+
+inline
+
+ +

Get the hostname string associated with this session.

+
Returns
A String object or "" if there is no hostname
+
Precondition
must check isValidSession before getting this value, as if this session in invalid this value is not guarented to be reset to "".
+ +
+
+ +

◆ get_ip()

+ +
+
+ + + + + +
+ + + + + + + +
const IPAddress& SSLSession::get_ip () const
+
+inline
+
+ +

Get ::IPAddress associated with this session.

+
Returns
A ::IPAddress object, #INADDR_NONE if there is no IP
+
Precondition
must check isValidSession before getting this value, as if this session in invalid this value is not guarented to be reset to #INADDR_NONE.
+ +
+
+ +

◆ is_valid_session()

+ +
+
+ + + + + +
+ + + + + + + +
bool SSLSession::is_valid_session () const
+
+inline
+
+ +
+
+ +

◆ operator=()

+ +
+
+ + + + + +
+ + + + + + + + +
SSLSession& SSLSession::operator= (const SSLSession)
+
+delete
+
+ +

use clear_parameters or set_parameters instead

+ +
+
+ +

◆ set_parameters()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void SSLSession::set_parameters (const IPAddress & ip,
const char * hostname = NULL 
)
+
+ +

Set the ip address and hostname of the session.

+

This function stores the ip Address object and hostname object into the session object. If hostname is not null or ip address is not blank, and the ::br_ssl_session_parameters values are non-zero it then validates the session.

+
Precondition
You must call ::br_ssl_engine_get_session_parameters with this session before calling this function. This is because there is no way to completly validate the ::br_ssl_session_parameters and the session may end up in a corrupted state if this is not observed.
+
Parameters
+ + + +
ipThe IP address of the host associated with the session
hostnameThe string hostname ("www.google.com") associated with the session. Take care that this value is corrent, SSLSession performs no validation of the hostname.
+
+
+ +
+
+ +

◆ to_br_session()

+ +
+
+ + + + + +
+ + + + + + + +
br_ssl_session_parameters* SSLSession::to_br_session ()
+
+inline
+
+ +

returns a pointer to the ::br_ssl_session_parameters component of this class

+ +
+
+
The documentation for this class was generated from the following files:
    +
  • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLSession.h
  • +
  • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLSession.cpp
  • +
+
+
+ + + + diff --git a/docs/html/class_s_s_l_session.js b/docs/html/class_s_s_l_session.js new file mode 100644 index 0000000..c5d362a --- /dev/null +++ b/docs/html/class_s_s_l_session.js @@ -0,0 +1,11 @@ +var class_s_s_l_session = +[ + [ "SSLSession", "class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb", null ], + [ "clear_parameters", "class_s_s_l_session.html#a3305941fa615f7134526b718917716ee", null ], + [ "get_hostname", "class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820", null ], + [ "get_ip", "class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0", null ], + [ "is_valid_session", "class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076", null ], + [ "operator=", "class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f", null ], + [ "set_parameters", "class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e", null ], + [ "to_br_session", "class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc", null ] +]; \ No newline at end of file diff --git a/docs/html/class_s_s_l_session.png b/docs/html/class_s_s_l_session.png new file mode 100644 index 0000000000000000000000000000000000000000..fc6de7ec782aa79f2b51dfa52521c4158cd2b26f GIT binary patch literal 609 zcmeAS@N?(olHy`uVBq!ia0vp^OMy6mgBeKruX1$)QW60^A+G=b{|7Q(y!l$%e`o@b z1;z&s9ANFdBM;Th`B*87t>ANzX6JD~Kmk)6+2IH2)^+eNTU%ua#E35Hx9D za{p3a|MT1a{*d~)Hnzd&R$WeT++x*h0ypjotZ^^dGPA(O&BE ze*f0L*WyfU|4mbzH9z!8&9URY(N}8syRFm@VmdNm z8iU~yRR!qTCr%a~-5VtIGhwP_rw5(}Q+o@ literal 0 HcmV?d00001 diff --git a/docs/html/classes.html b/docs/html/classes.html new file mode 100644 index 0000000..2fe6ffe --- /dev/null +++ b/docs/html/classes.html @@ -0,0 +1,114 @@ + + + + + + + +SSLClient: Class Index + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Class Index
+
+
+ + + + + + +
  s  
+
SSLClientImpl   SSLSession   
SSLClient   
+ +
+
+ + + + diff --git a/docs/html/closed.png b/docs/html/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..98cc2c909da37a6df914fbf67780eebd99c597f5 GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{V-kvUwAr*{o@8{^CZMh(5KoB^r_<4^zF@3)Cp&&t3hdujKf f*?bjBoY!V+E))@{xMcbjXe@)LtDnm{r-UW|*e5JT literal 0 HcmV?d00001 diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html new file mode 100644 index 0000000..05e7cd3 --- /dev/null +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -0,0 +1,124 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src Directory Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
src Directory Reference
+
+
+ + + + + + + + + + + + + + + + +

+Files

file  SSLClient.h [code]
 
file  SSLClientImpl.cpp
 
file  SSLClientImpl.h [code]
 
file  SSLSession.cpp
 
file  SSLSession.h [code]
 
file  time_macros.h [code]
 
file  TLS12_only_profile.c
 
+
+
+ + + + diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js new file mode 100644 index 0000000..4896506 --- /dev/null +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js @@ -0,0 +1,12 @@ +var dir_68267d1309a1af8e8297ef4c3efbcdba = +[ + [ "SSLClient.h", "_s_s_l_client_8h.html", "_s_s_l_client_8h" ], + [ "SSLClientImpl.cpp", "_s_s_l_client_impl_8cpp.html", "_s_s_l_client_impl_8cpp" ], + [ "SSLClientImpl.h", "_s_s_l_client_impl_8h.html", "_s_s_l_client_impl_8h" ], + [ "SSLSession.cpp", "_s_s_l_session_8cpp.html", null ], + [ "SSLSession.h", "_s_s_l_session_8h.html", [ + [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] + ] ], + [ "time_macros.h", "time__macros_8h.html", "time__macros_8h" ], + [ "TLS12_only_profile.c", "_t_l_s12__only__profile_8c.html", "_t_l_s12__only__profile_8c" ] +]; \ No newline at end of file diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html new file mode 100644 index 0000000..deb9b96 --- /dev/null +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -0,0 +1,112 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/readme Directory Reference + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
readme Directory Reference
+
+
+ + + + +

+Files

file  cert.h [code]
 
+
+
+ + + + diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.js b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.js new file mode 100644 index 0000000..d20d909 --- /dev/null +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.js @@ -0,0 +1,4 @@ +var dir_dfc5a9f91fbfb9426c406a3f10131a54 = +[ + [ "cert.h", "cert_8h.html", "cert_8h" ] +]; \ No newline at end of file diff --git a/docs/html/doc.png b/docs/html/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..17edabff95f7b8da13c9516a04efe05493c29501 GIT binary patch literal 746 zcmV7=@pnbNXRFEm&G8P!&WHG=d)>K?YZ1bzou)2{$)) zumDct!>4SyxL;zgaG>wy`^Hv*+}0kUfCrz~BCOViSb$_*&;{TGGn2^x9K*!Sf0=lV zpP=7O;GA0*Jm*tTYj$IoXvimpnV4S1Z5f$p*f$Db2iq2zrVGQUz~yq`ahn7ck(|CE z7Gz;%OP~J6)tEZWDzjhL9h2hdfoU2)Nd%T<5Kt;Y0XLt&<@6pQx!nw*5`@bq#?l*?3z{Hlzoc=Pr>oB5(9i6~_&-}A(4{Q$>c>%rV&E|a(r&;?i5cQB=} zYSDU5nXG)NS4HEs0it2AHe2>shCyr7`6@4*6{r@8fXRbTA?=IFVWAQJL&H5H{)DpM#{W(GL+Idzf^)uRV@oB8u$ z8v{MfJbTiiRg4bza<41NAzrl{=3fl_D+$t+^!xlQ8S}{UtY`e z;;&9UhyZqQRN%2pot{*Ei0*4~hSF_3AH2@fKU!$NSflS>{@tZpDT4`M2WRTTVH+D? z)GFlEGGHe?koB}i|1w45!BF}N_q&^HJ&-tyR{(afC6H7|aml|tBBbv}55C5DNP8p3 z)~jLEO4Z&2hZmP^i-e%(@d!(E|KRafiU8Q5u(wU((j8un3OR*Hvj+t literal 0 HcmV?d00001 diff --git a/docs/html/doxygen.css b/docs/html/doxygen.css new file mode 100644 index 0000000..e251592 --- /dev/null +++ b/docs/html/doxygen.css @@ -0,0 +1,1764 @@ +/* The standard CSS for doxygen 1.8.15 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +p.reference, p.definition { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +p.interli { +} + +p.interdd { +} + +p.intertd { +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #FFFFFF; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #FFFFFF; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +ul { + overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ +} + +#side-nav ul { + overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ +} + +#main-nav ul { + overflow: visible; /* reset ul rule for the navigation bar drop down lists */ +} + +.fragment { + text-align: left; + direction: ltr; + overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-y: hidden; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #FFFFFF; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl, img.inline { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +blockquote.DocNodeRTL { + border-left: 0; + border-right: 2px solid #9CAFD4; + margin: 0 4px 0 24px; + padding: 0 16px 0 12px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: url('nav_f.png'); + background-repeat: repeat-x; + background-color: #E2E8F2; + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: 400; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-color: #DFE5F1; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + +} + +.overload { + font-family: "courier new",courier,monospace; + font-size: 65%; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname, .tparams .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype, .tparams .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir, .tparams .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +.PageDocRTL-title div.headertitle { + text-align: right; + direction: rtl; +} + +dl { + padding: 0 0 0 0; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +dl.section { + margin-left: 0px; + padding-left: 0px; +} + +dl.section.DocNodeRTL { + margin-right: 0px; + padding-right: 0px; +} + +dl.note { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #D0C000; +} + +dl.note.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #FF0000; +} + +dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00D000; +} + +dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00D000; +} + +dl.deprecated { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #505050; +} + +dl.deprecated.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #505050; +} + +dl.todo { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00C0E0; +} + +dl.todo.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00C0E0; +} + +dl.test { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #3030E0; +} + +dl.test.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #3030E0; +} + +dl.bug { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #C08050; +} + +dl.bug.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +.PageDocRTL-title div.toc { + float: left !important; + text-align: right; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +.PageDocRTL-title div.toc li { + background-position-x: right !important; + padding-left: 0 !important; + padding-right: 10px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.PageDocRTL-title div.toc li.level1 { + margin-left: 0 !important; + margin-right: 0; +} + +.PageDocRTL-title div.toc li.level2 { + margin-left: 0 !important; + margin-right: 15px; +} + +.PageDocRTL-title div.toc li.level3 { + margin-left: 0 !important; + margin-right: 30px; +} + +.PageDocRTL-title div.toc li.level4 { + margin-left: 0 !important; + margin-right: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +/* +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTableHead tr { +} + +table.markdownTableBodyLeft td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft { + text-align: left +} + +th.markdownTableHeadRight { + text-align: right +} + +th.markdownTableHeadCenter { + text-align: center +} +*/ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + +.DocNodeRTL { + text-align: right; + direction: rtl; +} + +.DocNodeLTR { + text-align: left; + direction: ltr; +} + +table.DocNodeRTL { + width: auto; + margin-right: 0; + margin-left: auto; +} + +table.DocNodeLTR { + width: auto; + margin-right: auto; + margin-left: 0; +} + +tt, code, kbd, samp +{ + display: inline-block; + direction:ltr; +} +/* @end */ + +u { + text-decoration: underline; +} + diff --git a/docs/html/doxygen.png b/docs/html/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff17d807fd8aa003bed8bb2a69e8f0909592fd1 GIT binary patch literal 3779 zcmV;!4m|ORP)tMIv#Q0*~7*`IBSO7_x;@a8#Zk6_PeKR_s92J&)(m+);m9Iz3blw)z#Gi zP!9lj4$%+*>Hz@HCmM9L9|8c+0u=!H$O3?R0Kgx|#WP<6fKfC8fM-CQZT|_r@`>VO zX^Hgb|9cJqpdJA5$MCEK`F_2@2Y@s>^+;pF`~jdI0Pvr|vl4`=C)EH@1IFe7pdJ8F zH(qGi004~QnF)Ggga~8v08kGAs2hKTATxr7pwfNk|4#_AaT>w8P6TV+R2kbS$v==} zAjf`s0g#V8lB+b3)5oEI*q+{Yt$MZDruD2^;$+(_%Qn+%v0X-bJO=;@kiJ^ygLBnC z?1OVv_%aex1M@jKU|Z~$eI?PoF4Vj>fDzyo zAiLfpXY*a^Sj-S5D0S3@#V$sRW)g)_1e#$%8xdM>Jm7?!h zu0P2X=xoN>^!4DoPRgph2(2va07yfpXF+WH7EOg1GY%Zn z7~1A<(z7Q$ktEXhW_?GMpHp9l_UL18F3KOsxu81pqoBiNbFSGsof-W z6~eloMoz=4?OOnl2J268x5rOY`dCk0us(uS#Ud4yqOr@?=Q57a}tit|BhY>}~frH1sP`ScHS_d)oqH^lYy zZ%VP`#10MlE~P?cE(%(#(AUSv_T{+;t@$U}El}(1ig`vZo`Rm;+5&(AYzJ^Ae=h2X z@Re%vHwZU>|f0NI&%$*4eJweC5OROQrpPMA@*w|o z()A==l}(@bv^&>H1Ob3C=<^|hob?0+xJ?QQ3-ueQC}zy&JQNib!OqSO@-=>XzxlSF zAZ^U*1l6EEmg3r};_HY>&Jo_{dOPEFTWPmt=U&F#+0(O59^UIlHbNX+eF8UzyDR*T z(=5X$VF3!gm@RooS-&iiUYGG^`hMR(07zr_xP`d!^BH?uD>Phl8Rdifx3Af^Zr`Ku ztL+~HkVeL#bJ)7;`=>;{KNRvjmc}1}c58Sr#Treq=4{xo!ATy|c>iRSp4`dzMMVd@ zL8?uwXDY}Wqgh4mH`|$BTXpUIu6A1-cSq%hJw;@^Zr8TP=GMh*p(m(tN7@!^D~sl$ zz^tf4II4|};+irE$Fnm4NTc5%p{PRA`%}Zk`CE5?#h3|xcyQsS#iONZ z6H(@^i9td!$z~bZiJLTax$o>r(p}3o@< zyD7%(>ZYvy=6$U3e!F{Z`uSaYy`xQyl?b{}eg|G3&fz*`QH@mDUn)1%#5u`0m$%D} z?;tZ0u(mWeMV0QtzjgN!lT*pNRj;6510Wwx?Yi_=tYw|J#7@(Xe7ifDzXuK;JB;QO z#bg~K$cgm$@{QiL_3yr}y&~wuv=P=#O&Tj=Sr)aCUlYmZMcw?)T?c%0rUe1cS+o!qs_ zQ6Gp)-{)V!;=q}llyK3|^WeLKyjf%y;xHku;9(vM!j|~<7w1c*Mk-;P{T&yG) z@C-8E?QPynNQ<8f01D`2qexcVEIOU?y}MG)TAE6&VT5`rK8s(4PE;uQ92LTXUQ<>^ ztyQ@=@kRdh@ebUG^Z6NWWIL;_IGJ2ST>$t!$m$qvtj0Qmw8moN6GUV^!QKNK zHBXCtUH8)RY9++gH_TUV4^=-j$t}dD3qsN7GclJ^Zc&(j6&a_!$jCf}%c5ey`pm~1)@{yI3 zTdWyB+*X{JFw#z;PwRr5evb2!ueWF;v`B0HoUu4-(~aL=z;OXUUEtG`_$)Oxw6FKg zEzY`CyKaSBK3xt#8gA|r_|Kehn_HYVBMpEwbn9-fI*!u*eTA1ef8Mkl1=!jV4oYwWYM}i`A>_F4nhmlCIC6WLa zY%;4&@AlnaG11ejl61Jev21|r*m+?Kru3;1tFDl}#!OzUp6c>go4{C|^erwpG*&h6bspUPJag}oOkN2912Y3I?(eRc@U9>z#HPBHC?nps7H5!zP``90!Q1n80jo+B3TWXp!8Pe zwuKuLLI6l3Gv@+QH*Y}2wPLPQ1^EZhT#+Ed8q8Wo z1pTmIBxv14-{l&QVKxAyQF#8Q@NeJwWdKk>?cpiJLkJr+aZ!Me+Cfp!?FWSRf^j2k z73BRR{WSKaMkJ>1Nbx5dan5hg^_}O{Tj6u%iV%#QGz0Q@j{R^Ik)Z*+(YvY2ziBG)?AmJa|JV%4UT$k`hcOg5r9R?5>?o~JzK zJCrj&{i#hG>N7!B4kNX(%igb%kDj0fOQThC-8mtfap82PNRXr1D>lbgg)dYTQ(kbx z`Ee5kXG~Bh+BHQBf|kJEy6(ga%WfhvdQNDuOfQoe377l#ht&DrMGeIsI5C<&ai zWG$|hop2@@q5YDa)_-A?B02W;#fH!%k`daQLEItaJJ8Yf1L%8x;kg?)k)00P-lH+w z)5$QNV6r2$YtnV(4o=0^3{kmaXn*Dm0F*fU(@o)yVVjk|ln8ea6BMy%vZAhW9|wvA z8RoDkVoMEz1d>|5(k0Nw>22ZT){V<3$^C-cN+|~hKt2)){+l-?3m@-$c?-dlzQ)q- zZ)j%n^gerV{|+t}9m1_&&Ly!9$rtG4XX|WQ8`xYzGC~U@nYh~g(z9)bdAl#xH)xd5a=@|qql z|FzEil{P5(@gy!4ek05i$>`E^G~{;pnf6ftpLh$h#W?^#4UkPfa;;?bsIe&kz!+40 zI|6`F2n020)-r`pFaZ38F!S-lJM-o&inOw|66=GMeP@xQU5ghQH{~5Uh~TMTd;I9` z>YhVB`e^EVj*S7JF39ZgNf}A-0DwOcTT63ydN$I3b?yBQtUI*_fae~kPvzoD$zjX3 zoqBe#>12im4WzZ=f^4+u=!lA|#r%1`WB0-6*3BL#at`47#ebPpR|D1b)3BjT34nYY z%Ds%d?5$|{LgOIaRO{{oC&RK`O91$fqwM0(C_TALcozu*fWHb%%q&p-q{_8*2Zsi^ zh1ZCnr^UYa;4vQEtHk{~zi>wwMC5o{S=$P0X681y`SXwFH?Ewn{x-MOZynmc)JT5v zuHLwh;tLfxRrr%|k370}GofLl7thg>ACWWY&msqaVu&ry+`7+Ss>NL^%T1|z{IGMA zW-SKl=V-^{(f!Kf^#3(|T2W47d(%JVCI4JgRrT1pNz>+ietmFToNv^`gzC@&O-)+i zPQ~RwK8%C_vf%;%e>NyTp~dM5;!C|N0Q^6|CEb7Bw=Vz~$1#FA;Z*?mKSC)Hl-20s t8QyHj(g6VK0RYbl8UjE)0O0w=e*@m04r>stuEhWV002ovPDHLkV1hl;dM*F} literal 0 HcmV?d00001 diff --git a/docs/html/dynsections.js b/docs/html/dynsections.js new file mode 100644 index 0000000..ea0a7b3 --- /dev/null +++ b/docs/html/dynsections.js @@ -0,0 +1,120 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + 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. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l + + + + + + +SSLClient: File List + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
File List
+
+
+
Here is a list of all files with brief descriptions:
+
+
+ + + + diff --git a/docs/html/files_dup.js b/docs/html/files_dup.js new file mode 100644 index 0000000..282bf42 --- /dev/null +++ b/docs/html/files_dup.js @@ -0,0 +1,5 @@ +var files_dup = +[ + [ "readme", "dir_dfc5a9f91fbfb9426c406a3f10131a54.html", "dir_dfc5a9f91fbfb9426c406a3f10131a54" ], + [ "src", "dir_68267d1309a1af8e8297ef4c3efbcdba.html", "dir_68267d1309a1af8e8297ef4c3efbcdba" ] +]; \ No newline at end of file diff --git a/docs/html/folderclosed.png b/docs/html/folderclosed.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8ab35edce8e97554e360005ee9fc5bffb36e66 GIT binary patch literal 616 zcmV-u0+;=XP)a9#ETzayK)T~Jw&MMH>OIr#&;dC}is*2Mqdf&akCc=O@`qC+4i z5Iu3w#1M@KqXCz8TIZd1wli&kkl2HVcAiZ8PUn5z_kG@-y;?yK06=cA0U%H0PH+kU zl6dp}OR(|r8-RG+YLu`zbI}5TlOU6ToR41{9=uz^?dGTNL;wIMf|V3`d1Wj3y!#6` zBLZ?xpKR~^2x}?~zA(_NUu3IaDB$tKma*XUdOZN~c=dLt_h_k!dbxm_*ibDM zlFX`g{k$X}yIe%$N)cn1LNu=q9_CS)*>A zsX_mM4L@`(cSNQKMFc$RtYbx{79#j-J7hk*>*+ZZhM4Hw?I?rsXCi#mRWJ=-0LGV5a-WR0Qgt<|Nqf)C-@80`5gIz45^_20000IqP)X=#(TiCT&PiIIVc55T}TU}EUh*{q$|`3@{d>{Tc9Bo>e= zfmF3!f>fbI9#GoEHh0f`i5)wkLpva0ztf%HpZneK?w-7AK@b4Itw{y|Zd3k!fH?q2 zlhckHd_V2M_X7+)U&_Xcfvtw60l;--DgZmLSw-Y?S>)zIqMyJ1#FwLU*%bl38ok+! zh78H87n`ZTS;uhzAR$M`zZ`bVhq=+%u9^$5jDplgxd44}9;IRqUH1YHH|@6oFe%z( zo4)_>E$F&^P-f(#)>(TrnbE>Pefs9~@iN=|)Rz|V`sGfHNrJ)0gJb8xx+SBmRf@1l zvuzt=vGfI)<-F9!o&3l?>9~0QbUDT(wFdnQPv%xdD)m*g%!20>Bc9iYmGAp<9YAa( z0QgYgTWqf1qN++Gqp z8@AYPTB3E|6s=WLG?xw0tm|U!o=&zd+H0oRYE;Dbx+Na9s^STqX|Gnq%H8s(nGDGJ j8vwW|`Ts`)fSK|Kx=IK@RG@g200000NkvXXu0mjfauFEA literal 0 HcmV?d00001 diff --git a/docs/html/functions.html b/docs/html/functions.html new file mode 100644 index 0000000..2848a51 --- /dev/null +++ b/docs/html/functions.html @@ -0,0 +1,300 @@ + + + + + + + +SSLClient: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all class members with links to the classes they belong to:
+ +

- a -

+ + +

- c -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- l -

+ + +

- m -

+ + +

- o -

+ + +

- p -

+ + +

- r -

+ + +

- s -

+ + +

- t -

+ + +

- w -

+
+
+ + + + diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html new file mode 100644 index 0000000..e587094 --- /dev/null +++ b/docs/html/functions_func.html @@ -0,0 +1,300 @@ + + + + + + + +SSLClient: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- a -

+ + +

- c -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- l -

+ + +

- m -

+ + +

- o -

+ + +

- p -

+ + +

- r -

+ + +

- s -

+ + +

- t -

+ + +

- w -

+
+
+ + + + diff --git a/docs/html/globals.html b/docs/html/globals.html new file mode 100644 index 0000000..ba0590e --- /dev/null +++ b/docs/html/globals.html @@ -0,0 +1,255 @@ + + + + + + + +SSLClient: File Members + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all file members with links to the files they belong to:
+ +

- _ -

+ + +

- b -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- g -

+ + +

- p -

+ + +

- s -

+ + +

- t -

+ + +

- u -

+
+
+ + + + diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html new file mode 100644 index 0000000..08d9a11 --- /dev/null +++ b/docs/html/globals_defs.html @@ -0,0 +1,172 @@ + + + + + + + +SSLClient: File Members + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/html/globals_enum.html b/docs/html/globals_enum.html new file mode 100644 index 0000000..9ddaa5f --- /dev/null +++ b/docs/html/globals_enum.html @@ -0,0 +1,109 @@ + + + + + + + +SSLClient: File Members + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/html/globals_eval.html b/docs/html/globals_eval.html new file mode 100644 index 0000000..eae7b57 --- /dev/null +++ b/docs/html/globals_eval.html @@ -0,0 +1,136 @@ + + + + + + + +SSLClient: File Members + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html new file mode 100644 index 0000000..ecab3f9 --- /dev/null +++ b/docs/html/globals_func.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: File Members + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html new file mode 100644 index 0000000..99e9fff --- /dev/null +++ b/docs/html/globals_vars.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: File Members + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html new file mode 100644 index 0000000..85eafea --- /dev/null +++ b/docs/html/hierarchy.html @@ -0,0 +1,114 @@ + + + + + + + +SSLClient: Class Hierarchy + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Class Hierarchy
+
+
+
This inheritance list is sorted roughly, but not completely, alphabetically:
+
[detail level 123]
+ + + + + +
 Cbr_ssl_session_parameters
 CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
 CClient
 CSSLClientImplImplementation code to be inherited by SSLClient
 CSSLClient< C, SessionCache >The main SSLClient class Check out README.md for more info
+
+
+
+ + + + diff --git a/docs/html/hierarchy.js b/docs/html/hierarchy.js new file mode 100644 index 0000000..926851d --- /dev/null +++ b/docs/html/hierarchy.js @@ -0,0 +1,11 @@ +var hierarchy = +[ + [ "br_ssl_session_parameters", null, [ + [ "SSLSession", "class_s_s_l_session.html", null ] + ] ], + [ "Client", null, [ + [ "SSLClientImpl", "class_s_s_l_client_impl.html", [ + [ "SSLClient< C, SessionCache >", "class_s_s_l_client.html", null ] + ] ] + ] ] +]; \ No newline at end of file diff --git a/docs/html/index.html b/docs/html/index.html new file mode 100644 index 0000000..b209a0b --- /dev/null +++ b/docs/html/index.html @@ -0,0 +1,105 @@ + + + + + + + +SSLClient: Main Page + + + + + + + + + + + + + + +
+
+ + + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
SSLClient Documentation
+
+
+
+
+ + + + diff --git a/docs/html/jquery.js b/docs/html/jquery.js new file mode 100644 index 0000000..1ee895c --- /dev/null +++ b/docs/html/jquery.js @@ -0,0 +1,87 @@ +/*! + * jQuery JavaScript Library v1.7.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Wed Mar 21 12:46:34 2012 -0700 + */ +(function(bd,L){var av=bd.document,bu=bd.navigator,bm=bd.location;var b=(function(){var bF=function(b0,b1){return new bF.fn.init(b0,b1,bD)},bU=bd.jQuery,bH=bd.$,bD,bY=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,bM=/\S/,bI=/^\s+/,bE=/\s+$/,bA=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bN=/^[\],:{}\s]*$/,bW=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,bP=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bJ=/(?:^|:|,)(?:\s*\[)+/g,by=/(webkit)[ \/]([\w.]+)/,bR=/(opera)(?:.*version)?[ \/]([\w.]+)/,bQ=/(msie) ([\w.]+)/,bS=/(mozilla)(?:.*? rv:([\w.]+))?/,bB=/-([a-z]|[0-9])/ig,bZ=/^-ms-/,bT=function(b0,b1){return(b1+"").toUpperCase()},bX=bu.userAgent,bV,bC,e,bL=Object.prototype.toString,bG=Object.prototype.hasOwnProperty,bz=Array.prototype.push,bK=Array.prototype.slice,bO=String.prototype.trim,bv=Array.prototype.indexOf,bx={};bF.fn=bF.prototype={constructor:bF,init:function(b0,b4,b3){var b2,b5,b1,b6;if(!b0){return this}if(b0.nodeType){this.context=this[0]=b0;this.length=1;return this}if(b0==="body"&&!b4&&av.body){this.context=av;this[0]=av.body;this.selector=b0;this.length=1;return this}if(typeof b0==="string"){if(b0.charAt(0)==="<"&&b0.charAt(b0.length-1)===">"&&b0.length>=3){b2=[null,b0,null]}else{b2=bY.exec(b0)}if(b2&&(b2[1]||!b4)){if(b2[1]){b4=b4 instanceof bF?b4[0]:b4;b6=(b4?b4.ownerDocument||b4:av);b1=bA.exec(b0);if(b1){if(bF.isPlainObject(b4)){b0=[av.createElement(b1[1])];bF.fn.attr.call(b0,b4,true)}else{b0=[b6.createElement(b1[1])]}}else{b1=bF.buildFragment([b2[1]],[b6]);b0=(b1.cacheable?bF.clone(b1.fragment):b1.fragment).childNodes}return bF.merge(this,b0)}else{b5=av.getElementById(b2[2]);if(b5&&b5.parentNode){if(b5.id!==b2[2]){return b3.find(b0)}this.length=1;this[0]=b5}this.context=av;this.selector=b0;return this}}else{if(!b4||b4.jquery){return(b4||b3).find(b0)}else{return this.constructor(b4).find(b0)}}}else{if(bF.isFunction(b0)){return b3.ready(b0)}}if(b0.selector!==L){this.selector=b0.selector;this.context=b0.context}return bF.makeArray(b0,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return bK.call(this,0)},get:function(b0){return b0==null?this.toArray():(b0<0?this[this.length+b0]:this[b0])},pushStack:function(b1,b3,b0){var b2=this.constructor();if(bF.isArray(b1)){bz.apply(b2,b1)}else{bF.merge(b2,b1)}b2.prevObject=this;b2.context=this.context;if(b3==="find"){b2.selector=this.selector+(this.selector?" ":"")+b0}else{if(b3){b2.selector=this.selector+"."+b3+"("+b0+")"}}return b2},each:function(b1,b0){return bF.each(this,b1,b0)},ready:function(b0){bF.bindReady();bC.add(b0);return this},eq:function(b0){b0=+b0;return b0===-1?this.slice(b0):this.slice(b0,b0+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bK.apply(this,arguments),"slice",bK.call(arguments).join(","))},map:function(b0){return this.pushStack(bF.map(this,function(b2,b1){return b0.call(b2,b1,b2)}))},end:function(){return this.prevObject||this.constructor(null)},push:bz,sort:[].sort,splice:[].splice};bF.fn.init.prototype=bF.fn;bF.extend=bF.fn.extend=function(){var b9,b2,b0,b1,b6,b7,b5=arguments[0]||{},b4=1,b3=arguments.length,b8=false;if(typeof b5==="boolean"){b8=b5;b5=arguments[1]||{};b4=2}if(typeof b5!=="object"&&!bF.isFunction(b5)){b5={}}if(b3===b4){b5=this;--b4}for(;b40){return}bC.fireWith(av,[bF]);if(bF.fn.trigger){bF(av).trigger("ready").off("ready")}}},bindReady:function(){if(bC){return}bC=bF.Callbacks("once memory");if(av.readyState==="complete"){return setTimeout(bF.ready,1)}if(av.addEventListener){av.addEventListener("DOMContentLoaded",e,false);bd.addEventListener("load",bF.ready,false)}else{if(av.attachEvent){av.attachEvent("onreadystatechange",e);bd.attachEvent("onload",bF.ready);var b0=false;try{b0=bd.frameElement==null}catch(b1){}if(av.documentElement.doScroll&&b0){bw()}}}},isFunction:function(b0){return bF.type(b0)==="function"},isArray:Array.isArray||function(b0){return bF.type(b0)==="array"},isWindow:function(b0){return b0!=null&&b0==b0.window},isNumeric:function(b0){return !isNaN(parseFloat(b0))&&isFinite(b0)},type:function(b0){return b0==null?String(b0):bx[bL.call(b0)]||"object"},isPlainObject:function(b2){if(!b2||bF.type(b2)!=="object"||b2.nodeType||bF.isWindow(b2)){return false}try{if(b2.constructor&&!bG.call(b2,"constructor")&&!bG.call(b2.constructor.prototype,"isPrototypeOf")){return false}}catch(b1){return false}var b0;for(b0 in b2){}return b0===L||bG.call(b2,b0)},isEmptyObject:function(b1){for(var b0 in b1){return false}return true},error:function(b0){throw new Error(b0)},parseJSON:function(b0){if(typeof b0!=="string"||!b0){return null}b0=bF.trim(b0);if(bd.JSON&&bd.JSON.parse){return bd.JSON.parse(b0)}if(bN.test(b0.replace(bW,"@").replace(bP,"]").replace(bJ,""))){return(new Function("return "+b0))()}bF.error("Invalid JSON: "+b0)},parseXML:function(b2){if(typeof b2!=="string"||!b2){return null}var b0,b1;try{if(bd.DOMParser){b1=new DOMParser();b0=b1.parseFromString(b2,"text/xml")}else{b0=new ActiveXObject("Microsoft.XMLDOM");b0.async="false";b0.loadXML(b2)}}catch(b3){b0=L}if(!b0||!b0.documentElement||b0.getElementsByTagName("parsererror").length){bF.error("Invalid XML: "+b2)}return b0},noop:function(){},globalEval:function(b0){if(b0&&bM.test(b0)){(bd.execScript||function(b1){bd["eval"].call(bd,b1)})(b0)}},camelCase:function(b0){return b0.replace(bZ,"ms-").replace(bB,bT)},nodeName:function(b1,b0){return b1.nodeName&&b1.nodeName.toUpperCase()===b0.toUpperCase()},each:function(b3,b6,b2){var b1,b4=0,b5=b3.length,b0=b5===L||bF.isFunction(b3);if(b2){if(b0){for(b1 in b3){if(b6.apply(b3[b1],b2)===false){break}}}else{for(;b40&&b0[0]&&b0[b1-1])||b1===0||bF.isArray(b0));if(b3){for(;b21?aK.call(arguments,0):bG;if(!(--bw)){bC.resolveWith(bC,bx)}}}function bz(bF){return function(bG){bB[bF]=arguments.length>1?aK.call(arguments,0):bG;bC.notifyWith(bE,bB)}}if(e>1){for(;bv
a";bH=bv.getElementsByTagName("*");bE=bv.getElementsByTagName("a")[0];if(!bH||!bH.length||!bE){return{}}bF=av.createElement("select");bx=bF.appendChild(av.createElement("option"));bD=bv.getElementsByTagName("input")[0];bI={leadingWhitespace:(bv.firstChild.nodeType===3),tbody:!bv.getElementsByTagName("tbody").length,htmlSerialize:!!bv.getElementsByTagName("link").length,style:/top/.test(bE.getAttribute("style")),hrefNormalized:(bE.getAttribute("href")==="/a"),opacity:/^0.55/.test(bE.style.opacity),cssFloat:!!bE.style.cssFloat,checkOn:(bD.value==="on"),optSelected:bx.selected,getSetAttribute:bv.className!=="t",enctype:!!av.createElement("form").enctype,html5Clone:av.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,pixelMargin:true};b.boxModel=bI.boxModel=(av.compatMode==="CSS1Compat");bD.checked=true;bI.noCloneChecked=bD.cloneNode(true).checked;bF.disabled=true;bI.optDisabled=!bx.disabled;try{delete bv.test}catch(bB){bI.deleteExpando=false}if(!bv.addEventListener&&bv.attachEvent&&bv.fireEvent){bv.attachEvent("onclick",function(){bI.noCloneEvent=false});bv.cloneNode(true).fireEvent("onclick")}bD=av.createElement("input");bD.value="t";bD.setAttribute("type","radio");bI.radioValue=bD.value==="t";bD.setAttribute("checked","checked");bD.setAttribute("name","t");bv.appendChild(bD);bC=av.createDocumentFragment();bC.appendChild(bv.lastChild);bI.checkClone=bC.cloneNode(true).cloneNode(true).lastChild.checked;bI.appendChecked=bD.checked;bC.removeChild(bD);bC.appendChild(bv);if(bv.attachEvent){for(by in {submit:1,change:1,focusin:1}){bA="on"+by;bw=(bA in bv);if(!bw){bv.setAttribute(bA,"return;");bw=(typeof bv[bA]==="function")}bI[by+"Bubbles"]=bw}}bC.removeChild(bv);bC=bF=bx=bv=bD=null;b(function(){var bM,bV,bW,bU,bO,bP,bR,bL,bK,bQ,bN,e,bT,bS=av.getElementsByTagName("body")[0];if(!bS){return}bL=1;bT="padding:0;margin:0;border:";bN="position:absolute;top:0;left:0;width:1px;height:1px;";e=bT+"0;visibility:hidden;";bK="style='"+bN+bT+"5px solid #000;";bQ="
";bM=av.createElement("div");bM.style.cssText=e+"width:0;height:0;position:static;top:0;margin-top:"+bL+"px";bS.insertBefore(bM,bS.firstChild);bv=av.createElement("div");bM.appendChild(bv);bv.innerHTML="
t
";bz=bv.getElementsByTagName("td");bw=(bz[0].offsetHeight===0);bz[0].style.display="";bz[1].style.display="none";bI.reliableHiddenOffsets=bw&&(bz[0].offsetHeight===0);if(bd.getComputedStyle){bv.innerHTML="";bR=av.createElement("div");bR.style.width="0";bR.style.marginRight="0";bv.style.width="2px";bv.appendChild(bR);bI.reliableMarginRight=(parseInt((bd.getComputedStyle(bR,null)||{marginRight:0}).marginRight,10)||0)===0}if(typeof bv.style.zoom!=="undefined"){bv.innerHTML="";bv.style.width=bv.style.padding="1px";bv.style.border=0;bv.style.overflow="hidden";bv.style.display="inline";bv.style.zoom=1;bI.inlineBlockNeedsLayout=(bv.offsetWidth===3);bv.style.display="block";bv.style.overflow="visible";bv.innerHTML="
";bI.shrinkWrapBlocks=(bv.offsetWidth!==3)}bv.style.cssText=bN+e;bv.innerHTML=bQ;bV=bv.firstChild;bW=bV.firstChild;bO=bV.nextSibling.firstChild.firstChild;bP={doesNotAddBorder:(bW.offsetTop!==5),doesAddBorderForTableAndCells:(bO.offsetTop===5)};bW.style.position="fixed";bW.style.top="20px";bP.fixedPosition=(bW.offsetTop===20||bW.offsetTop===15);bW.style.position=bW.style.top="";bV.style.overflow="hidden";bV.style.position="relative";bP.subtractsBorderForOverflowNotVisible=(bW.offsetTop===-5);bP.doesNotIncludeMarginInBodyOffset=(bS.offsetTop!==bL);if(bd.getComputedStyle){bv.style.marginTop="1%";bI.pixelMargin=(bd.getComputedStyle(bv,null)||{marginTop:0}).marginTop!=="1%"}if(typeof bM.style.zoom!=="undefined"){bM.style.zoom=1}bS.removeChild(bM);bR=bv=bM=null;b.extend(bI,bP)});return bI})();var aT=/^(?:\{.*\}|\[.*\])$/,aA=/([A-Z])/g;b.extend({cache:{},uuid:0,expando:"jQuery"+(b.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?b.cache[e[b.expando]]:e[b.expando];return !!e&&!S(e)},data:function(bx,bv,bz,by){if(!b.acceptData(bx)){return}var bG,bA,bD,bE=b.expando,bC=typeof bv==="string",bF=bx.nodeType,e=bF?b.cache:bx,bw=bF?bx[bE]:bx[bE]&&bE,bB=bv==="events";if((!bw||!e[bw]||(!bB&&!by&&!e[bw].data))&&bC&&bz===L){return}if(!bw){if(bF){bx[bE]=bw=++b.uuid}else{bw=bE}}if(!e[bw]){e[bw]={};if(!bF){e[bw].toJSON=b.noop}}if(typeof bv==="object"||typeof bv==="function"){if(by){e[bw]=b.extend(e[bw],bv)}else{e[bw].data=b.extend(e[bw].data,bv)}}bG=bA=e[bw];if(!by){if(!bA.data){bA.data={}}bA=bA.data}if(bz!==L){bA[b.camelCase(bv)]=bz}if(bB&&!bA[bv]){return bG.events}if(bC){bD=bA[bv];if(bD==null){bD=bA[b.camelCase(bv)]}}else{bD=bA}return bD},removeData:function(bx,bv,by){if(!b.acceptData(bx)){return}var bB,bA,bz,bC=b.expando,bD=bx.nodeType,e=bD?b.cache:bx,bw=bD?bx[bC]:bC;if(!e[bw]){return}if(bv){bB=by?e[bw]:e[bw].data;if(bB){if(!b.isArray(bv)){if(bv in bB){bv=[bv]}else{bv=b.camelCase(bv);if(bv in bB){bv=[bv]}else{bv=bv.split(" ")}}}for(bA=0,bz=bv.length;bA1,null,false)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function a6(bx,bw,by){if(by===L&&bx.nodeType===1){var bv="data-"+bw.replace(aA,"-$1").toLowerCase();by=bx.getAttribute(bv);if(typeof by==="string"){try{by=by==="true"?true:by==="false"?false:by==="null"?null:b.isNumeric(by)?+by:aT.test(by)?b.parseJSON(by):by}catch(bz){}b.data(bx,bw,by)}else{by=L}}return by}function S(bv){for(var e in bv){if(e==="data"&&b.isEmptyObject(bv[e])){continue}if(e!=="toJSON"){return false}}return true}function bj(by,bx,bA){var bw=bx+"defer",bv=bx+"queue",e=bx+"mark",bz=b._data(by,bw);if(bz&&(bA==="queue"||!b._data(by,bv))&&(bA==="mark"||!b._data(by,e))){setTimeout(function(){if(!b._data(by,bv)&&!b._data(by,e)){b.removeData(by,bw,true);bz.fire()}},0)}}b.extend({_mark:function(bv,e){if(bv){e=(e||"fx")+"mark";b._data(bv,e,(b._data(bv,e)||0)+1)}},_unmark:function(by,bx,bv){if(by!==true){bv=bx;bx=by;by=false}if(bx){bv=bv||"fx";var e=bv+"mark",bw=by?0:((b._data(bx,e)||1)-1);if(bw){b._data(bx,e,bw)}else{b.removeData(bx,e,true);bj(bx,bv,"mark")}}},queue:function(bv,e,bx){var bw;if(bv){e=(e||"fx")+"queue";bw=b._data(bv,e);if(bx){if(!bw||b.isArray(bx)){bw=b._data(bv,e,b.makeArray(bx))}else{bw.push(bx)}}return bw||[]}},dequeue:function(by,bx){bx=bx||"fx";var bv=b.queue(by,bx),bw=bv.shift(),e={};if(bw==="inprogress"){bw=bv.shift()}if(bw){if(bx==="fx"){bv.unshift("inprogress")}b._data(by,bx+".run",e);bw.call(by,function(){b.dequeue(by,bx)},e)}if(!bv.length){b.removeData(by,bx+"queue "+bx+".run",true);bj(by,bx,"queue")}}});b.fn.extend({queue:function(e,bv){var bw=2;if(typeof e!=="string"){bv=e;e="fx";bw--}if(arguments.length1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,bv){return b.access(this,b.prop,e,bv,arguments.length>1)},removeProp:function(e){e=b.propFix[e]||e;return this.each(function(){try{this[e]=L;delete this[e]}catch(bv){}})},addClass:function(by){var bA,bw,bv,bx,bz,bB,e;if(b.isFunction(by)){return this.each(function(bC){b(this).addClass(by.call(this,bC,this.className))})}if(by&&typeof by==="string"){bA=by.split(ag);for(bw=0,bv=this.length;bw-1){return true}}return false},val:function(bx){var e,bv,by,bw=this[0];if(!arguments.length){if(bw){e=b.valHooks[bw.type]||b.valHooks[bw.nodeName.toLowerCase()];if(e&&"get" in e&&(bv=e.get(bw,"value"))!==L){return bv}bv=bw.value;return typeof bv==="string"?bv.replace(aV,""):bv==null?"":bv}return}by=b.isFunction(bx);return this.each(function(bA){var bz=b(this),bB;if(this.nodeType!==1){return}if(by){bB=bx.call(this,bA,bz.val())}else{bB=bx}if(bB==null){bB=""}else{if(typeof bB==="number"){bB+=""}else{if(b.isArray(bB)){bB=b.map(bB,function(bC){return bC==null?"":bC+""})}}}e=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()];if(!e||!("set" in e)||e.set(this,bB,"value")===L){this.value=bB}})}});b.extend({valHooks:{option:{get:function(e){var bv=e.attributes.value;return !bv||bv.specified?e.value:e.text}},select:{get:function(e){var bA,bv,bz,bx,by=e.selectedIndex,bB=[],bC=e.options,bw=e.type==="select-one";if(by<0){return null}bv=bw?by:0;bz=bw?by+1:bC.length;for(;bv=0});if(!e.length){bv.selectedIndex=-1}return e}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bA,bx,bB,bz){var bw,e,by,bv=bA.nodeType;if(!bA||bv===3||bv===8||bv===2){return}if(bz&&bx in b.attrFn){return b(bA)[bx](bB)}if(typeof bA.getAttribute==="undefined"){return b.prop(bA,bx,bB)}by=bv!==1||!b.isXMLDoc(bA);if(by){bx=bx.toLowerCase();e=b.attrHooks[bx]||(ao.test(bx)?aZ:bf)}if(bB!==L){if(bB===null){b.removeAttr(bA,bx);return}else{if(e&&"set" in e&&by&&(bw=e.set(bA,bB,bx))!==L){return bw}else{bA.setAttribute(bx,""+bB);return bB}}}else{if(e&&"get" in e&&by&&(bw=e.get(bA,bx))!==null){return bw}else{bw=bA.getAttribute(bx);return bw===null?L:bw}}},removeAttr:function(by,bA){var bz,bB,bw,e,bv,bx=0;if(bA&&by.nodeType===1){bB=bA.toLowerCase().split(ag);e=bB.length;for(;bx=0)}}})});var be=/^(?:textarea|input|select)$/i,n=/^([^\.]*)?(?:\.(.+))?$/,J=/(?:^|\s)hover(\.\S+)?\b/,aP=/^key/,bg=/^(?:mouse|contextmenu)|click/,T=/^(?:focusinfocus|focusoutblur)$/,U=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,Y=function(e){var bv=U.exec(e);if(bv){bv[1]=(bv[1]||"").toLowerCase();bv[3]=bv[3]&&new RegExp("(?:^|\\s)"+bv[3]+"(?:\\s|$)")}return bv},j=function(bw,e){var bv=bw.attributes||{};return((!e[1]||bw.nodeName.toLowerCase()===e[1])&&(!e[2]||(bv.id||{}).value===e[2])&&(!e[3]||e[3].test((bv["class"]||{}).value)))},bt=function(e){return b.event.special.hover?e:e.replace(J,"mouseenter$1 mouseleave$1")};b.event={add:function(bx,bC,bJ,bA,by){var bD,bB,bK,bI,bH,bF,e,bG,bv,bz,bw,bE;if(bx.nodeType===3||bx.nodeType===8||!bC||!bJ||!(bD=b._data(bx))){return}if(bJ.handler){bv=bJ;bJ=bv.handler;by=bv.selector}if(!bJ.guid){bJ.guid=b.guid++}bK=bD.events;if(!bK){bD.events=bK={}}bB=bD.handle;if(!bB){bD.handle=bB=function(bL){return typeof b!=="undefined"&&(!bL||b.event.triggered!==bL.type)?b.event.dispatch.apply(bB.elem,arguments):L};bB.elem=bx}bC=b.trim(bt(bC)).split(" ");for(bI=0;bI=0){bG=bG.slice(0,-1);bw=true}if(bG.indexOf(".")>=0){bx=bG.split(".");bG=bx.shift();bx.sort()}if((!bA||b.event.customEvent[bG])&&!b.event.global[bG]){return}bv=typeof bv==="object"?bv[b.expando]?bv:new b.Event(bG,bv):new b.Event(bG);bv.type=bG;bv.isTrigger=true;bv.exclusive=bw;bv.namespace=bx.join(".");bv.namespace_re=bv.namespace?new RegExp("(^|\\.)"+bx.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;by=bG.indexOf(":")<0?"on"+bG:"";if(!bA){e=b.cache;for(bC in e){if(e[bC].events&&e[bC].events[bG]){b.event.trigger(bv,bD,e[bC].handle.elem,true)}}return}bv.result=L;if(!bv.target){bv.target=bA}bD=bD!=null?b.makeArray(bD):[];bD.unshift(bv);bF=b.event.special[bG]||{};if(bF.trigger&&bF.trigger.apply(bA,bD)===false){return}bB=[[bA,bF.bindType||bG]];if(!bJ&&!bF.noBubble&&!b.isWindow(bA)){bI=bF.delegateType||bG;bH=T.test(bI+bG)?bA:bA.parentNode;bz=null;for(;bH;bH=bH.parentNode){bB.push([bH,bI]);bz=bH}if(bz&&bz===bA.ownerDocument){bB.push([bz.defaultView||bz.parentWindow||bd,bI])}}for(bC=0;bCbC){bv.push({elem:this,matches:bD.slice(bC)})}for(bJ=0;bJ0?this.on(e,null,bx,bw):this.trigger(e)};if(b.attrFn){b.attrFn[e]=true}if(aP.test(e)){b.event.fixHooks[e]=b.event.keyHooks}if(bg.test(e)){b.event.fixHooks[e]=b.event.mouseHooks}}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var bH=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bC="sizcache"+(Math.random()+"").replace(".",""),bI=0,bL=Object.prototype.toString,bB=false,bA=true,bK=/\\/g,bO=/\r\n/g,bQ=/\W/;[0,0].sort(function(){bA=false;return 0});var by=function(bV,e,bY,bZ){bY=bY||[];e=e||av;var b1=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bV||typeof bV!=="string"){return bY}var bS,b3,b6,bR,b2,b5,b4,bX,bU=true,bT=by.isXML(e),bW=[],b0=bV;do{bH.exec("");bS=bH.exec(b0);if(bS){b0=bS[3];bW.push(bS[1]);if(bS[2]){bR=bS[3];break}}}while(bS);if(bW.length>1&&bD.exec(bV)){if(bW.length===2&&bE.relative[bW[0]]){b3=bM(bW[0]+bW[1],e,bZ)}else{b3=bE.relative[bW[0]]?[e]:by(bW.shift(),e);while(bW.length){bV=bW.shift();if(bE.relative[bV]){bV+=bW.shift()}b3=bM(bV,b3,bZ)}}}else{if(!bZ&&bW.length>1&&e.nodeType===9&&!bT&&bE.match.ID.test(bW[0])&&!bE.match.ID.test(bW[bW.length-1])){b2=by.find(bW.shift(),e,bT);e=b2.expr?by.filter(b2.expr,b2.set)[0]:b2.set[0]}if(e){b2=bZ?{expr:bW.pop(),set:bF(bZ)}:by.find(bW.pop(),bW.length===1&&(bW[0]==="~"||bW[0]==="+")&&e.parentNode?e.parentNode:e,bT);b3=b2.expr?by.filter(b2.expr,b2.set):b2.set;if(bW.length>0){b6=bF(b3)}else{bU=false}while(bW.length){b5=bW.pop();b4=b5;if(!bE.relative[b5]){b5=""}else{b4=bW.pop()}if(b4==null){b4=e}bE.relative[b5](b6,b4,bT)}}else{b6=bW=[]}}if(!b6){b6=b3}if(!b6){by.error(b5||bV)}if(bL.call(b6)==="[object Array]"){if(!bU){bY.push.apply(bY,b6)}else{if(e&&e.nodeType===1){for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&(b6[bX]===true||b6[bX].nodeType===1&&by.contains(e,b6[bX]))){bY.push(b3[bX])}}}else{for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&b6[bX].nodeType===1){bY.push(b3[bX])}}}}}else{bF(b6,bY)}if(bR){by(bR,b1,bY,bZ);by.uniqueSort(bY)}return bY};by.uniqueSort=function(bR){if(bJ){bB=bA;bR.sort(bJ);if(bB){for(var e=1;e0};by.find=function(bX,e,bY){var bW,bS,bU,bT,bV,bR;if(!bX){return[]}for(bS=0,bU=bE.order.length;bS":function(bW,bR){var bV,bU=typeof bR==="string",bS=0,e=bW.length;if(bU&&!bQ.test(bR)){bR=bR.toLowerCase();for(;bS=0)){if(!bS){e.push(bV)}}else{if(bS){bR[bU]=false}}}}return false},ID:function(e){return e[1].replace(bK,"")},TAG:function(bR,e){return bR[1].replace(bK,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){by.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bR=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bR[1]+(bR[2]||1))-0;e[3]=bR[3]-0}else{if(e[2]){by.error(e[0])}}e[0]=bI++;return e},ATTR:function(bU,bR,bS,e,bV,bW){var bT=bU[1]=bU[1].replace(bK,"");if(!bW&&bE.attrMap[bT]){bU[1]=bE.attrMap[bT]}bU[4]=(bU[4]||bU[5]||"").replace(bK,"");if(bU[2]==="~="){bU[4]=" "+bU[4]+" "}return bU},PSEUDO:function(bU,bR,bS,e,bV){if(bU[1]==="not"){if((bH.exec(bU[3])||"").length>1||/^\w/.test(bU[3])){bU[3]=by(bU[3],null,null,bR)}else{var bT=by.filter(bU[3],bR,bS,true^bV);if(!bS){e.push.apply(e,bT)}return false}}else{if(bE.match.POS.test(bU[0])||bE.match.CHILD.test(bU[0])){return true}}return bU},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bS,bR,e){return !!by(e[3],bS).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(bS){var e=bS.getAttribute("type"),bR=bS.type;return bS.nodeName.toLowerCase()==="input"&&"text"===bR&&(e===bR||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===bR.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===bR.type},button:function(bR){var e=bR.nodeName.toLowerCase();return e==="input"&&"button"===bR.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(bR,e){return e===0},last:function(bS,bR,e,bT){return bR===bT.length-1},even:function(bR,e){return e%2===0},odd:function(bR,e){return e%2===1},lt:function(bS,bR,e){return bRe[3]-0},nth:function(bS,bR,e){return e[3]-0===bR},eq:function(bS,bR,e){return e[3]-0===bR}},filter:{PSEUDO:function(bS,bX,bW,bY){var e=bX[1],bR=bE.filters[e];if(bR){return bR(bS,bW,bX,bY)}else{if(e==="contains"){return(bS.textContent||bS.innerText||bw([bS])||"").indexOf(bX[3])>=0}else{if(e==="not"){var bT=bX[3];for(var bV=0,bU=bT.length;bV=0)}}},ID:function(bR,e){return bR.nodeType===1&&bR.getAttribute("id")===e},TAG:function(bR,e){return(e==="*"&&bR.nodeType===1)||!!bR.nodeName&&bR.nodeName.toLowerCase()===e},CLASS:function(bR,e){return(" "+(bR.className||bR.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bV,bT){var bS=bT[1],e=by.attr?by.attr(bV,bS):bE.attrHandle[bS]?bE.attrHandle[bS](bV):bV[bS]!=null?bV[bS]:bV.getAttribute(bS),bW=e+"",bU=bT[2],bR=bT[4];return e==null?bU==="!=":!bU&&by.attr?e!=null:bU==="="?bW===bR:bU==="*="?bW.indexOf(bR)>=0:bU==="~="?(" "+bW+" ").indexOf(bR)>=0:!bR?bW&&e!==false:bU==="!="?bW!==bR:bU==="^="?bW.indexOf(bR)===0:bU==="$="?bW.substr(bW.length-bR.length)===bR:bU==="|="?bW===bR||bW.substr(0,bR.length+1)===bR+"-":false},POS:function(bU,bR,bS,bV){var e=bR[2],bT=bE.setFilters[e];if(bT){return bT(bU,bS,bR,bV)}}}};var bD=bE.match.POS,bx=function(bR,e){return"\\"+(e-0+1)};for(var bz in bE.match){bE.match[bz]=new RegExp(bE.match[bz].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bE.leftMatch[bz]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bE.match[bz].source.replace(/\\(\d+)/g,bx))}bE.match.globalPOS=bD;var bF=function(bR,e){bR=Array.prototype.slice.call(bR,0);if(e){e.push.apply(e,bR);return e}return bR};try{Array.prototype.slice.call(av.documentElement.childNodes,0)[0].nodeType}catch(bP){bF=function(bU,bT){var bS=0,bR=bT||[];if(bL.call(bU)==="[object Array]"){Array.prototype.push.apply(bR,bU)}else{if(typeof bU.length==="number"){for(var e=bU.length;bS";e.insertBefore(bR,e.firstChild);if(av.getElementById(bS)){bE.find.ID=function(bU,bV,bW){if(typeof bV.getElementById!=="undefined"&&!bW){var bT=bV.getElementById(bU[1]);return bT?bT.id===bU[1]||typeof bT.getAttributeNode!=="undefined"&&bT.getAttributeNode("id").nodeValue===bU[1]?[bT]:L:[]}};bE.filter.ID=function(bV,bT){var bU=typeof bV.getAttributeNode!=="undefined"&&bV.getAttributeNode("id");return bV.nodeType===1&&bU&&bU.nodeValue===bT}}e.removeChild(bR);e=bR=null})();(function(){var e=av.createElement("div");e.appendChild(av.createComment(""));if(e.getElementsByTagName("*").length>0){bE.find.TAG=function(bR,bV){var bU=bV.getElementsByTagName(bR[1]);if(bR[1]==="*"){var bT=[];for(var bS=0;bU[bS];bS++){if(bU[bS].nodeType===1){bT.push(bU[bS])}}bU=bT}return bU}}e.innerHTML="";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bE.attrHandle.href=function(bR){return bR.getAttribute("href",2)}}e=null})();if(av.querySelectorAll){(function(){var e=by,bT=av.createElement("div"),bS="__sizzle__";bT.innerHTML="

";if(bT.querySelectorAll&&bT.querySelectorAll(".TEST").length===0){return}by=function(b4,bV,bZ,b3){bV=bV||av;if(!b3&&!by.isXML(bV)){var b2=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b4);if(b2&&(bV.nodeType===1||bV.nodeType===9)){if(b2[1]){return bF(bV.getElementsByTagName(b4),bZ)}else{if(b2[2]&&bE.find.CLASS&&bV.getElementsByClassName){return bF(bV.getElementsByClassName(b2[2]),bZ)}}}if(bV.nodeType===9){if(b4==="body"&&bV.body){return bF([bV.body],bZ)}else{if(b2&&b2[3]){var bY=bV.getElementById(b2[3]);if(bY&&bY.parentNode){if(bY.id===b2[3]){return bF([bY],bZ)}}else{return bF([],bZ)}}}try{return bF(bV.querySelectorAll(b4),bZ)}catch(b0){}}else{if(bV.nodeType===1&&bV.nodeName.toLowerCase()!=="object"){var bW=bV,bX=bV.getAttribute("id"),bU=bX||bS,b6=bV.parentNode,b5=/^\s*[+~]/.test(b4);if(!bX){bV.setAttribute("id",bU)}else{bU=bU.replace(/'/g,"\\$&")}if(b5&&b6){bV=bV.parentNode}try{if(!b5||b6){return bF(bV.querySelectorAll("[id='"+bU+"'] "+b4),bZ)}}catch(b1){}finally{if(!bX){bW.removeAttribute("id")}}}}}return e(b4,bV,bZ,b3)};for(var bR in e){by[bR]=e[bR]}bT=null})()}(function(){var e=av.documentElement,bS=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(bS){var bU=!bS.call(av.createElement("div"),"div"),bR=false;try{bS.call(av.documentElement,"[test!='']:sizzle")}catch(bT){bR=true}by.matchesSelector=function(bW,bY){bY=bY.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!by.isXML(bW)){try{if(bR||!bE.match.PSEUDO.test(bY)&&!/!=/.test(bY)){var bV=bS.call(bW,bY);if(bV||!bU||bW.document&&bW.document.nodeType!==11){return bV}}}catch(bX){}}return by(bY,null,null,[bW]).length>0}}})();(function(){var e=av.createElement("div");e.innerHTML="
";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bE.order.splice(1,0,"CLASS");bE.find.CLASS=function(bR,bS,bT){if(typeof bS.getElementsByClassName!=="undefined"&&!bT){return bS.getElementsByClassName(bR[1])}};e=null})();function bv(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT0){bU=e;break}}}e=e[bR]}bZ[bT]=bU}}}if(av.documentElement.contains){by.contains=function(bR,e){return bR!==e&&(bR.contains?bR.contains(e):true)}}else{if(av.documentElement.compareDocumentPosition){by.contains=function(bR,e){return !!(bR.compareDocumentPosition(e)&16)}}else{by.contains=function(){return false}}}by.isXML=function(e){var bR=(e?e.ownerDocument||e:0).documentElement;return bR?bR.nodeName!=="HTML":false};var bM=function(bS,e,bW){var bV,bX=[],bU="",bY=e.nodeType?[e]:e;while((bV=bE.match.PSEUDO.exec(bS))){bU+=bV[0];bS=bS.replace(bE.match.PSEUDO,"")}bS=bE.relative[bS]?bS+"*":bS;for(var bT=0,bR=bY.length;bT0){for(bB=bA;bB=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(by,bx){var bv=[],bw,e,bz=this[0];if(b.isArray(by)){var bB=1;while(bz&&bz.ownerDocument&&bz!==bx){for(bw=0;bw-1:b.find.matchesSelector(bz,by)){bv.push(bz);break}else{bz=bz.parentNode;if(!bz||!bz.ownerDocument||bz===bx||bz.nodeType===11){break}}}}bv=bv.length>1?b.unique(bv):bv;return this.pushStack(bv,"closest",by)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return b.inArray(this[0],b(e))}return b.inArray(e.jquery?e[0]:e,this)},add:function(e,bv){var bx=typeof e==="string"?b(e,bv):b.makeArray(e&&e.nodeType?[e]:e),bw=b.merge(this.get(),bx);return this.pushStack(B(bx[0])||B(bw[0])?bw:b.unique(bw))},andSelf:function(){return this.add(this.prevObject)}});function B(e){return !e||!e.parentNode||e.parentNode.nodeType===11}b.each({parent:function(bv){var e=bv.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(bv,e,bw){return b.dir(bv,"parentNode",bw)},next:function(e){return b.nth(e,2,"nextSibling")},prev:function(e){return b.nth(e,2,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(bv,e,bw){return b.dir(bv,"nextSibling",bw)},prevUntil:function(bv,e,bw){return b.dir(bv,"previousSibling",bw)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.makeArray(e.childNodes)}},function(e,bv){b.fn[e]=function(by,bw){var bx=b.map(this,bv,by);if(!ab.test(e)){bw=by}if(bw&&typeof bw==="string"){bx=b.filter(bw,bx)}bx=this.length>1&&!ay[e]?b.unique(bx):bx;if((this.length>1||bb.test(bw))&&aq.test(e)){bx=bx.reverse()}return this.pushStack(bx,e,P.call(arguments).join(","))}});b.extend({filter:function(bw,e,bv){if(bv){bw=":not("+bw+")"}return e.length===1?b.find.matchesSelector(e[0],bw)?[e[0]]:[]:b.find.matches(bw,e)},dir:function(bw,bv,by){var e=[],bx=bw[bv];while(bx&&bx.nodeType!==9&&(by===L||bx.nodeType!==1||!b(bx).is(by))){if(bx.nodeType===1){e.push(bx)}bx=bx[bv]}return e},nth:function(by,e,bw,bx){e=e||1;var bv=0;for(;by;by=by[bw]){if(by.nodeType===1&&++bv===e){break}}return by},sibling:function(bw,bv){var e=[];for(;bw;bw=bw.nextSibling){if(bw.nodeType===1&&bw!==bv){e.push(bw)}}return e}});function aH(bx,bw,e){bw=bw||0;if(b.isFunction(bw)){return b.grep(bx,function(bz,by){var bA=!!bw.call(bz,by,bz);return bA===e})}else{if(bw.nodeType){return b.grep(bx,function(bz,by){return(bz===bw)===e})}else{if(typeof bw==="string"){var bv=b.grep(bx,function(by){return by.nodeType===1});if(bp.test(bw)){return b.filter(bw,bv,!e)}else{bw=b.filter(bw,bv)}}}}return b.grep(bx,function(bz,by){return(b.inArray(bz,bw)>=0)===e})}function a(e){var bw=aS.split("|"),bv=e.createDocumentFragment();if(bv.createElement){while(bw.length){bv.createElement(bw.pop())}}return bv}var aS="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ah=/ jQuery\d+="(?:\d+|null)"/g,ar=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,d=/<([\w:]+)/,v=/]","i"),o=/checked\s*(?:[^=]|=\s*.checked.)/i,bn=/\/(java|ecma)script/i,aO=/^\s*",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},ac=a(av);ax.optgroup=ax.option;ax.tbody=ax.tfoot=ax.colgroup=ax.caption=ax.thead;ax.th=ax.td;if(!b.support.htmlSerialize){ax._default=[1,"div
","
"]}b.fn.extend({text:function(e){return b.access(this,function(bv){return bv===L?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||av).createTextNode(bv))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e)){return this.each(function(bw){b(this).wrapAll(e.call(this,bw))})}if(this[0]){var bv=b(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bv.insertBefore(this[0])}bv.map(function(){var bw=this;while(bw.firstChild&&bw.firstChild.nodeType===1){bw=bw.firstChild}return bw}).append(this)}return this},wrapInner:function(e){if(b.isFunction(e)){return this.each(function(bv){b(this).wrapInner(e.call(this,bv))})}return this.each(function(){var bv=b(this),bw=bv.contents();if(bw.length){bw.wrapAll(e)}else{bv.append(e)}})},wrap:function(e){var bv=b.isFunction(e);return this.each(function(bw){b(this).wrapAll(bv?e.call(this,bw):e)})},unwrap:function(){return this.parent().each(function(){if(!b.nodeName(this,"body")){b(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this)})}else{if(arguments.length){var e=b.clean(arguments);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,b.clean(arguments));return e}}},remove:function(e,bx){for(var bv=0,bw;(bw=this[bv])!=null;bv++){if(!e||b.filter(e,[bw]).length){if(!bx&&bw.nodeType===1){b.cleanData(bw.getElementsByTagName("*"));b.cleanData([bw])}if(bw.parentNode){bw.parentNode.removeChild(bw)}}}return this},empty:function(){for(var e=0,bv;(bv=this[e])!=null;e++){if(bv.nodeType===1){b.cleanData(bv.getElementsByTagName("*"))}while(bv.firstChild){bv.removeChild(bv.firstChild)}}return this},clone:function(bv,e){bv=bv==null?false:bv;e=e==null?bv:e;return this.map(function(){return b.clone(this,bv,e)})},html:function(e){return b.access(this,function(by){var bx=this[0]||{},bw=0,bv=this.length;if(by===L){return bx.nodeType===1?bx.innerHTML.replace(ah,""):null}if(typeof by==="string"&&!ae.test(by)&&(b.support.leadingWhitespace||!ar.test(by))&&!ax[(d.exec(by)||["",""])[1].toLowerCase()]){by=by.replace(R,"<$1>");try{for(;bw1&&bw0?this.clone(true):this).get();b(bC[bA])[bv](by);bz=bz.concat(by)}return this.pushStack(bz,e,bC.selector)}}});function bh(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function az(e){if(e.type==="checkbox"||e.type==="radio"){e.defaultChecked=e.checked}}function D(e){var bv=(e.nodeName||"").toLowerCase();if(bv==="input"){az(e)}else{if(bv!=="script"&&typeof e.getElementsByTagName!=="undefined"){b.grep(e.getElementsByTagName("input"),az)}}}function am(e){var bv=av.createElement("div");ac.appendChild(bv);bv.innerHTML=e.outerHTML;return bv.firstChild}b.extend({clone:function(by,bA,bw){var e,bv,bx,bz=b.support.html5Clone||b.isXMLDoc(by)||!ai.test("<"+by.nodeName+">")?by.cloneNode(true):am(by);if((!b.support.noCloneEvent||!b.support.noCloneChecked)&&(by.nodeType===1||by.nodeType===11)&&!b.isXMLDoc(by)){aj(by,bz);e=bh(by);bv=bh(bz);for(bx=0;e[bx];++bx){if(bv[bx]){aj(e[bx],bv[bx])}}}if(bA){s(by,bz);if(bw){e=bh(by);bv=bh(bz);for(bx=0;e[bx];++bx){s(e[bx],bv[bx])}}}e=bv=null;return bz},clean:function(bI,bw,bv,bx){var bA,bH,bD,bJ=[];bw=bw||av;if(typeof bw.createElement==="undefined"){bw=bw.ownerDocument||bw[0]&&bw[0].ownerDocument||av}for(var bE=0,bG;(bG=bI[bE])!=null;bE++){if(typeof bG==="number"){bG+=""}if(!bG){continue}if(typeof bG==="string"){if(!W.test(bG)){bG=bw.createTextNode(bG)}else{bG=bG.replace(R,"<$1>");var bN=(d.exec(bG)||["",""])[1].toLowerCase(),bz=ax[bN]||ax._default,bK=bz[0],bB=bw.createElement("div"),bL=ac.childNodes,bM;if(bw===av){ac.appendChild(bB)}else{a(bw).appendChild(bB)}bB.innerHTML=bz[1]+bG+bz[2];while(bK--){bB=bB.lastChild}if(!b.support.tbody){var by=v.test(bG),e=bN==="table"&&!by?bB.firstChild&&bB.firstChild.childNodes:bz[1]===""&&!by?bB.childNodes:[];for(bD=e.length-1;bD>=0;--bD){if(b.nodeName(e[bD],"tbody")&&!e[bD].childNodes.length){e[bD].parentNode.removeChild(e[bD])}}}if(!b.support.leadingWhitespace&&ar.test(bG)){bB.insertBefore(bw.createTextNode(ar.exec(bG)[0]),bB.firstChild)}bG=bB.childNodes;if(bB){bB.parentNode.removeChild(bB);if(bL.length>0){bM=bL[bL.length-1];if(bM&&bM.parentNode){bM.parentNode.removeChild(bM)}}}}}var bF;if(!b.support.appendChecked){if(bG[0]&&typeof(bF=bG.length)==="number"){for(bD=0;bD1)};b.extend({cssHooks:{opacity:{get:function(bw,bv){if(bv){var e=Z(bw,"opacity");return e===""?"1":e}else{return bw.style.opacity}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(bx,bw,bD,by){if(!bx||bx.nodeType===3||bx.nodeType===8||!bx.style){return}var bB,bC,bz=b.camelCase(bw),bv=bx.style,bE=b.cssHooks[bz];bw=b.cssProps[bz]||bz;if(bD!==L){bC=typeof bD;if(bC==="string"&&(bB=I.exec(bD))){bD=(+(bB[1]+1)*+bB[2])+parseFloat(b.css(bx,bw));bC="number"}if(bD==null||bC==="number"&&isNaN(bD)){return}if(bC==="number"&&!b.cssNumber[bz]){bD+="px"}if(!bE||!("set" in bE)||(bD=bE.set(bx,bD))!==L){try{bv[bw]=bD}catch(bA){}}}else{if(bE&&"get" in bE&&(bB=bE.get(bx,false,by))!==L){return bB}return bv[bw]}},css:function(by,bx,bv){var bw,e;bx=b.camelCase(bx);e=b.cssHooks[bx];bx=b.cssProps[bx]||bx;if(bx==="cssFloat"){bx="float"}if(e&&"get" in e&&(bw=e.get(by,true,bv))!==L){return bw}else{if(Z){return Z(by,bx)}}},swap:function(by,bx,bz){var e={},bw,bv;for(bv in bx){e[bv]=by.style[bv];by.style[bv]=bx[bv]}bw=bz.call(by);for(bv in bx){by.style[bv]=e[bv]}return bw}});b.curCSS=b.css;if(av.defaultView&&av.defaultView.getComputedStyle){aJ=function(bA,bw){var bv,bz,e,by,bx=bA.style;bw=bw.replace(y,"-$1").toLowerCase();if((bz=bA.ownerDocument.defaultView)&&(e=bz.getComputedStyle(bA,null))){bv=e.getPropertyValue(bw);if(bv===""&&!b.contains(bA.ownerDocument.documentElement,bA)){bv=b.style(bA,bw)}}if(!b.support.pixelMargin&&e&&aE.test(bw)&&a1.test(bv)){by=bx.width;bx.width=bv;bv=e.width;bx.width=by}return bv}}if(av.documentElement.currentStyle){aY=function(bz,bw){var bA,e,by,bv=bz.currentStyle&&bz.currentStyle[bw],bx=bz.style;if(bv==null&&bx&&(by=bx[bw])){bv=by}if(a1.test(bv)){bA=bx.left;e=bz.runtimeStyle&&bz.runtimeStyle.left;if(e){bz.runtimeStyle.left=bz.currentStyle.left}bx.left=bw==="fontSize"?"1em":bv;bv=bx.pixelLeft+"px";bx.left=bA;if(e){bz.runtimeStyle.left=e}}return bv===""?"auto":bv}}Z=aJ||aY;function af(by,bw,bv){var bz=bw==="width"?by.offsetWidth:by.offsetHeight,bx=bw==="width"?1:0,e=4;if(bz>0){if(bv!=="border"){for(;bx=1&&b.trim(bw.replace(al,""))===""){bx.removeAttribute("filter");if(bv&&!bv.filter){return}}bx.filter=al.test(bw)?bw.replace(al,e):bw+" "+e}}}b(function(){if(!b.support.reliableMarginRight){b.cssHooks.marginRight={get:function(bv,e){return b.swap(bv,{display:"inline-block"},function(){if(e){return Z(bv,"margin-right")}else{return bv.style.marginRight}})}}}});if(b.expr&&b.expr.filters){b.expr.filters.hidden=function(bw){var bv=bw.offsetWidth,e=bw.offsetHeight;return(bv===0&&e===0)||(!b.support.reliableHiddenOffsets&&((bw.style&&bw.style.display)||b.css(bw,"display"))==="none")};b.expr.filters.visible=function(e){return !b.expr.filters.hidden(e)}}b.each({margin:"",padding:"",border:"Width"},function(e,bv){b.cssHooks[e+bv]={expand:function(by){var bx,bz=typeof by==="string"?by.split(" "):[by],bw={};for(bx=0;bx<4;bx++){bw[e+G[bx]+bv]=bz[bx]||bz[bx-2]||bz[0]}return bw}}});var k=/%20/g,ap=/\[\]$/,bs=/\r?\n/g,bq=/#.*$/,aD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,a0=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,aN=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,aR=/^(?:GET|HEAD)$/,c=/^\/\//,M=/\?/,a7=/)<[^<]*)*<\/script>/gi,p=/^(?:select|textarea)/i,h=/\s+/,br=/([?&])_=[^&]*/,K=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,z=b.fn.load,aa={},q={},aF,r,aW=["*/"]+["*"];try{aF=bm.href}catch(aw){aF=av.createElement("a");aF.href="";aF=aF.href}r=K.exec(aF.toLowerCase())||[];function f(e){return function(by,bA){if(typeof by!=="string"){bA=by;by="*"}if(b.isFunction(bA)){var bx=by.toLowerCase().split(h),bw=0,bz=bx.length,bv,bB,bC;for(;bw=0){var e=bw.slice(by,bw.length);bw=bw.slice(0,by)}var bx="GET";if(bz){if(b.isFunction(bz)){bA=bz;bz=L}else{if(typeof bz==="object"){bz=b.param(bz,b.ajaxSettings.traditional);bx="POST"}}}var bv=this;b.ajax({url:bw,type:bx,dataType:"html",data:bz,complete:function(bC,bB,bD){bD=bC.responseText;if(bC.isResolved()){bC.done(function(bE){bD=bE});bv.html(e?b("
").append(bD.replace(a7,"")).find(e):bD)}if(bA){bv.each(bA,[bD,bB,bC])}}});return this},serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?b.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||p.test(this.nodeName)||a0.test(this.type))}).map(function(e,bv){var bw=b(this).val();return bw==null?null:b.isArray(bw)?b.map(bw,function(by,bx){return{name:bv.name,value:by.replace(bs,"\r\n")}}):{name:bv.name,value:bw.replace(bs,"\r\n")}}).get()}});b.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bv){b.fn[bv]=function(bw){return this.on(bv,bw)}});b.each(["get","post"],function(e,bv){b[bv]=function(bw,by,bz,bx){if(b.isFunction(by)){bx=bx||bz;bz=by;by=L}return b.ajax({type:bv,url:bw,data:by,success:bz,dataType:bx})}});b.extend({getScript:function(e,bv){return b.get(e,L,bv,"script")},getJSON:function(e,bv,bw){return b.get(e,bv,bw,"json")},ajaxSetup:function(bv,e){if(e){an(bv,b.ajaxSettings)}else{e=bv;bv=b.ajaxSettings}an(bv,e);return bv},ajaxSettings:{url:aF,isLocal:aN.test(r[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":bd.String,"text html":true,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:f(aa),ajaxTransport:f(q),ajax:function(bz,bx){if(typeof bz==="object"){bx=bz;bz=L}bx=bx||{};var bD=b.ajaxSetup({},bx),bS=bD.context||bD,bG=bS!==bD&&(bS.nodeType||bS instanceof b)?b(bS):b.event,bR=b.Deferred(),bN=b.Callbacks("once memory"),bB=bD.statusCode||{},bC,bH={},bO={},bQ,by,bL,bE,bI,bA=0,bw,bK,bJ={readyState:0,setRequestHeader:function(bT,bU){if(!bA){var e=bT.toLowerCase();bT=bO[e]=bO[e]||bT;bH[bT]=bU}return this},getAllResponseHeaders:function(){return bA===2?bQ:null},getResponseHeader:function(bT){var e;if(bA===2){if(!by){by={};while((e=aD.exec(bQ))){by[e[1].toLowerCase()]=e[2]}}e=by[bT.toLowerCase()]}return e===L?null:e},overrideMimeType:function(e){if(!bA){bD.mimeType=e}return this},abort:function(e){e=e||"abort";if(bL){bL.abort(e)}bF(0,e);return this}};function bF(bZ,bU,b0,bW){if(bA===2){return}bA=2;if(bE){clearTimeout(bE)}bL=L;bQ=bW||"";bJ.readyState=bZ>0?4:0;var bT,b4,b3,bX=bU,bY=b0?bk(bD,bJ,b0):L,bV,b2;if(bZ>=200&&bZ<300||bZ===304){if(bD.ifModified){if((bV=bJ.getResponseHeader("Last-Modified"))){b.lastModified[bC]=bV}if((b2=bJ.getResponseHeader("Etag"))){b.etag[bC]=b2}}if(bZ===304){bX="notmodified";bT=true}else{try{b4=F(bD,bY);bX="success";bT=true}catch(b1){bX="parsererror";b3=b1}}}else{b3=bX;if(!bX||bZ){bX="error";if(bZ<0){bZ=0}}}bJ.status=bZ;bJ.statusText=""+(bU||bX);if(bT){bR.resolveWith(bS,[b4,bX,bJ])}else{bR.rejectWith(bS,[bJ,bX,b3])}bJ.statusCode(bB);bB=L;if(bw){bG.trigger("ajax"+(bT?"Success":"Error"),[bJ,bD,bT?b4:b3])}bN.fireWith(bS,[bJ,bX]);if(bw){bG.trigger("ajaxComplete",[bJ,bD]);if(!(--b.active)){b.event.trigger("ajaxStop")}}}bR.promise(bJ);bJ.success=bJ.done;bJ.error=bJ.fail;bJ.complete=bN.add;bJ.statusCode=function(bT){if(bT){var e;if(bA<2){for(e in bT){bB[e]=[bB[e],bT[e]]}}else{e=bT[bJ.status];bJ.then(e,e)}}return this};bD.url=((bz||bD.url)+"").replace(bq,"").replace(c,r[1]+"//");bD.dataTypes=b.trim(bD.dataType||"*").toLowerCase().split(h);if(bD.crossDomain==null){bI=K.exec(bD.url.toLowerCase());bD.crossDomain=!!(bI&&(bI[1]!=r[1]||bI[2]!=r[2]||(bI[3]||(bI[1]==="http:"?80:443))!=(r[3]||(r[1]==="http:"?80:443))))}if(bD.data&&bD.processData&&typeof bD.data!=="string"){bD.data=b.param(bD.data,bD.traditional)}aX(aa,bD,bx,bJ);if(bA===2){return false}bw=bD.global;bD.type=bD.type.toUpperCase();bD.hasContent=!aR.test(bD.type);if(bw&&b.active++===0){b.event.trigger("ajaxStart")}if(!bD.hasContent){if(bD.data){bD.url+=(M.test(bD.url)?"&":"?")+bD.data;delete bD.data}bC=bD.url;if(bD.cache===false){var bv=b.now(),bP=bD.url.replace(br,"$1_="+bv);bD.url=bP+((bP===bD.url)?(M.test(bD.url)?"&":"?")+"_="+bv:"")}}if(bD.data&&bD.hasContent&&bD.contentType!==false||bx.contentType){bJ.setRequestHeader("Content-Type",bD.contentType)}if(bD.ifModified){bC=bC||bD.url;if(b.lastModified[bC]){bJ.setRequestHeader("If-Modified-Since",b.lastModified[bC])}if(b.etag[bC]){bJ.setRequestHeader("If-None-Match",b.etag[bC])}}bJ.setRequestHeader("Accept",bD.dataTypes[0]&&bD.accepts[bD.dataTypes[0]]?bD.accepts[bD.dataTypes[0]]+(bD.dataTypes[0]!=="*"?", "+aW+"; q=0.01":""):bD.accepts["*"]);for(bK in bD.headers){bJ.setRequestHeader(bK,bD.headers[bK])}if(bD.beforeSend&&(bD.beforeSend.call(bS,bJ,bD)===false||bA===2)){bJ.abort();return false}for(bK in {success:1,error:1,complete:1}){bJ[bK](bD[bK])}bL=aX(q,bD,bx,bJ);if(!bL){bF(-1,"No Transport")}else{bJ.readyState=1;if(bw){bG.trigger("ajaxSend",[bJ,bD])}if(bD.async&&bD.timeout>0){bE=setTimeout(function(){bJ.abort("timeout")},bD.timeout)}try{bA=1;bL.send(bH,bF)}catch(bM){if(bA<2){bF(-1,bM)}else{throw bM}}}return bJ},param:function(e,bw){var bv=[],by=function(bz,bA){bA=b.isFunction(bA)?bA():bA;bv[bv.length]=encodeURIComponent(bz)+"="+encodeURIComponent(bA)};if(bw===L){bw=b.ajaxSettings.traditional}if(b.isArray(e)||(e.jquery&&!b.isPlainObject(e))){b.each(e,function(){by(this.name,this.value)})}else{for(var bx in e){u(bx,e[bx],bw,by)}}return bv.join("&").replace(k,"+")}});function u(bw,by,bv,bx){if(b.isArray(by)){b.each(by,function(bA,bz){if(bv||ap.test(bw)){bx(bw,bz)}else{u(bw+"["+(typeof bz==="object"?bA:"")+"]",bz,bv,bx)}})}else{if(!bv&&b.type(by)==="object"){for(var e in by){u(bw+"["+e+"]",by[e],bv,bx)}}else{bx(bw,by)}}}b.extend({active:0,lastModified:{},etag:{}});function bk(bD,bC,bz){var bv=bD.contents,bB=bD.dataTypes,bw=bD.responseFields,by,bA,bx,e;for(bA in bw){if(bA in bz){bC[bw[bA]]=bz[bA]}}while(bB[0]==="*"){bB.shift();if(by===L){by=bD.mimeType||bC.getResponseHeader("content-type")}}if(by){for(bA in bv){if(bv[bA]&&bv[bA].test(by)){bB.unshift(bA);break}}}if(bB[0] in bz){bx=bB[0]}else{for(bA in bz){if(!bB[0]||bD.converters[bA+" "+bB[0]]){bx=bA;break}if(!e){e=bA}}bx=bx||e}if(bx){if(bx!==bB[0]){bB.unshift(bx)}return bz[bx]}}function F(bH,bz){if(bH.dataFilter){bz=bH.dataFilter(bz,bH.dataType)}var bD=bH.dataTypes,bG={},bA,bE,bw=bD.length,bB,bC=bD[0],bx,by,bF,bv,e;for(bA=1;bA=bw.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();bw.animatedProperties[this.prop]=true;for(bA in bw.animatedProperties){if(bw.animatedProperties[bA]!==true){e=false}}if(e){if(bw.overflow!=null&&!b.support.shrinkWrapBlocks){b.each(["","X","Y"],function(bC,bD){bz.style["overflow"+bD]=bw.overflow[bC]})}if(bw.hide){b(bz).hide()}if(bw.hide||bw.show){for(bA in bw.animatedProperties){b.style(bz,bA,bw.orig[bA]);b.removeData(bz,"fxshow"+bA,true);b.removeData(bz,"toggle"+bA,true)}}bv=bw.complete;if(bv){bw.complete=false;bv.call(bz)}}return false}else{if(bw.duration==Infinity){this.now=bx}else{bB=bx-this.startTime;this.state=bB/bw.duration;this.pos=b.easing[bw.animatedProperties[this.prop]](this.state,bB,0,1,bw.duration);this.now=this.start+((this.end-this.start)*this.pos)}this.update()}return true}};b.extend(b.fx,{tick:function(){var bw,bv=b.timers,e=0;for(;e").appendTo(e),bw=bv.css("display");bv.remove();if(bw==="none"||bw===""){if(!ba){ba=av.createElement("iframe");ba.frameBorder=ba.width=ba.height=0}e.appendChild(ba);if(!m||!ba.createElement){m=(ba.contentWindow||ba.contentDocument).document;m.write((b.support.boxModel?"":"")+"");m.close()}bv=m.createElement(bx);m.body.appendChild(bv);bw=b.css(bv,"display");e.removeChild(ba)}Q[bx]=bw}return Q[bx]}var a8,V=/^t(?:able|d|h)$/i,ad=/^(?:body|html)$/i;if("getBoundingClientRect" in av.documentElement){a8=function(by,bH,bw,bB){try{bB=by.getBoundingClientRect()}catch(bF){}if(!bB||!b.contains(bw,by)){return bB?{top:bB.top,left:bB.left}:{top:0,left:0}}var bC=bH.body,bD=aL(bH),bA=bw.clientTop||bC.clientTop||0,bE=bw.clientLeft||bC.clientLeft||0,bv=bD.pageYOffset||b.support.boxModel&&bw.scrollTop||bC.scrollTop,bz=bD.pageXOffset||b.support.boxModel&&bw.scrollLeft||bC.scrollLeft,bG=bB.top+bv-bA,bx=bB.left+bz-bE;return{top:bG,left:bx}}}else{a8=function(bz,bE,bx){var bC,bw=bz.offsetParent,bv=bz,bA=bE.body,bB=bE.defaultView,e=bB?bB.getComputedStyle(bz,null):bz.currentStyle,bD=bz.offsetTop,by=bz.offsetLeft;while((bz=bz.parentNode)&&bz!==bA&&bz!==bx){if(b.support.fixedPosition&&e.position==="fixed"){break}bC=bB?bB.getComputedStyle(bz,null):bz.currentStyle;bD-=bz.scrollTop;by-=bz.scrollLeft;if(bz===bw){bD+=bz.offsetTop;by+=bz.offsetLeft;if(b.support.doesNotAddBorder&&!(b.support.doesAddBorderForTableAndCells&&V.test(bz.nodeName))){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}bv=bw;bw=bz.offsetParent}if(b.support.subtractsBorderForOverflowNotVisible&&bC.overflow!=="visible"){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}e=bC}if(e.position==="relative"||e.position==="static"){bD+=bA.offsetTop;by+=bA.offsetLeft}if(b.support.fixedPosition&&e.position==="fixed"){bD+=Math.max(bx.scrollTop,bA.scrollTop);by+=Math.max(bx.scrollLeft,bA.scrollLeft)}return{top:bD,left:by}}}b.fn.offset=function(e){if(arguments.length){return e===L?this:this.each(function(bx){b.offset.setOffset(this,e,bx)})}var bv=this[0],bw=bv&&bv.ownerDocument;if(!bw){return null}if(bv===bw.body){return b.offset.bodyOffset(bv)}return a8(bv,bw,bw.documentElement)};b.offset={bodyOffset:function(e){var bw=e.offsetTop,bv=e.offsetLeft;if(b.support.doesNotIncludeMarginInBodyOffset){bw+=parseFloat(b.css(e,"marginTop"))||0;bv+=parseFloat(b.css(e,"marginLeft"))||0}return{top:bw,left:bv}},setOffset:function(bx,bG,bA){var bB=b.css(bx,"position");if(bB==="static"){bx.style.position="relative"}var bz=b(bx),bv=bz.offset(),e=b.css(bx,"top"),bE=b.css(bx,"left"),bF=(bB==="absolute"||bB==="fixed")&&b.inArray("auto",[e,bE])>-1,bD={},bC={},bw,by;if(bF){bC=bz.position();bw=bC.top;by=bC.left}else{bw=parseFloat(e)||0;by=parseFloat(bE)||0}if(b.isFunction(bG)){bG=bG.call(bx,bA,bv)}if(bG.top!=null){bD.top=(bG.top-bv.top)+bw}if(bG.left!=null){bD.left=(bG.left-bv.left)+by}if("using" in bG){bG.using.call(bx,bD)}else{bz.css(bD)}}};b.fn.extend({position:function(){if(!this[0]){return null}var bw=this[0],bv=this.offsetParent(),bx=this.offset(),e=ad.test(bv[0].nodeName)?{top:0,left:0}:bv.offset();bx.top-=parseFloat(b.css(bw,"marginTop"))||0;bx.left-=parseFloat(b.css(bw,"marginLeft"))||0;e.top+=parseFloat(b.css(bv[0],"borderTopWidth"))||0;e.left+=parseFloat(b.css(bv[0],"borderLeftWidth"))||0;return{top:bx.top-e.top,left:bx.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||av.body;while(e&&(!ad.test(e.nodeName)&&b.css(e,"position")==="static")){e=e.offsetParent}return e})}});b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(bw,bv){var e=/Y/.test(bv);b.fn[bw]=function(bx){return b.access(this,function(by,bB,bA){var bz=aL(by);if(bA===L){return bz?(bv in bz)?bz[bv]:b.support.boxModel&&bz.document.documentElement[bB]||bz.document.body[bB]:by[bB]}if(bz){bz.scrollTo(!e?bA:b(bz).scrollLeft(),e?bA:b(bz).scrollTop())}else{by[bB]=bA}},bw,bx,arguments.length,null)}});function aL(e){return b.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}b.each({Height:"height",Width:"width"},function(bw,bx){var bv="client"+bw,e="scroll"+bw,by="offset"+bw;b.fn["inner"+bw]=function(){var bz=this[0];return bz?bz.style?parseFloat(b.css(bz,bx,"padding")):this[bx]():null};b.fn["outer"+bw]=function(bA){var bz=this[0];return bz?bz.style?parseFloat(b.css(bz,bx,bA?"margin":"border")):this[bx]():null};b.fn[bx]=function(bz){return b.access(this,function(bC,bB,bD){var bF,bE,bG,bA;if(b.isWindow(bC)){bF=bC.document;bE=bF.documentElement[bv];return b.support.boxModel&&bE||bF.body&&bF.body[bv]||bE}if(bC.nodeType===9){bF=bC.documentElement;if(bF[bv]>=bF[e]){return bF[bv]}return Math.max(bC.body[e],bF[e],bC.body[by],bF[by])}if(bD===L){bG=b.css(bC,bB);bA=parseFloat(bG);return b.isNumeric(bA)?bA:bG}b(bC).css(bB,bD)},bx,bz,arguments.length,null)}});bd.jQuery=bd.$=b;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return b})}})(window);/*! + * jQuery UI 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(a,d){a.ui=a.ui||{};if(a.ui.version){return}a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(e,f){return typeof e==="number"?this.each(function(){var g=this;setTimeout(function(){a(g).focus();if(f){f.call(g)}},e)}):this._focus.apply(this,arguments)},scrollParent:function(){var e;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){e=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{e=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!e.length?a(document):e},zIndex:function(h){if(h!==d){return this.css("zIndex",h)}if(this.length){var f=a(this[0]),e,g;while(f.length&&f[0]!==document){e=f.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){g=parseInt(f.css("zIndex"),10);if(!isNaN(g)&&g!==0){return g}}f=f.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(g,e){var f=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),k={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};function j(m,l,i,n){a.each(f,function(){l-=parseFloat(a.curCSS(m,"padding"+this,true))||0;if(i){l-=parseFloat(a.curCSS(m,"border"+this+"Width",true))||0}if(n){l-=parseFloat(a.curCSS(m,"margin"+this,true))||0}});return l}a.fn["inner"+e]=function(i){if(i===d){return k["inner"+e].call(this)}return this.each(function(){a(this).css(h,j(this,i)+"px")})};a.fn["outer"+e]=function(i,l){if(typeof i!=="number"){return k["outer"+e].call(this,i)}return this.each(function(){a(this).css(h,j(this,i,true,l)+"px")})}});function c(g,e){var j=g.nodeName.toLowerCase();if("area"===j){var i=g.parentNode,h=i.name,f;if(!g.href||!h||i.nodeName.toLowerCase()!=="map"){return false}f=a("img[usemap=#"+h+"]")[0];return !!f&&b(f)}return(/input|select|textarea|button|object/.test(j)?!g.disabled:"a"==j?g.href||e:e)&&b(g)}function b(e){return !a(e).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.extend(a.expr[":"],{data:function(g,f,e){return !!a.data(g,e[3])},focusable:function(e){return c(e,!isNaN(a.attr(e,"tabindex")))},tabbable:function(g){var e=a.attr(g,"tabindex"),f=isNaN(e);return(f||e>=0)&&c(g,!f)}});a(function(){var e=document.body,f=e.appendChild(f=document.createElement("div"));f.offsetHeight;a.extend(f.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=f.offsetHeight===100;a.support.selectstart="onselectstart" in f;e.removeChild(f).style.display="none"});a.extend(a.ui,{plugin:{add:function(f,g,j){var h=a.ui[f].prototype;for(var e in j){h.plugins[e]=h.plugins[e]||[];h.plugins[e].push([g,j[e]])}},call:function(e,g,f){var j=e.plugins[g];if(!j||!e.element[0].parentNode){return}for(var h=0;h0){return true}h[e]=1;g=(h[e]>0);h[e]=0;return g},isOverAxis:function(f,e,g){return(f>e)&&(f<(e+g))},isOver:function(j,f,i,h,e,g){return a.ui.isOverAxis(j,i,e)&&a.ui.isOverAxis(f,h,g)}})})(jQuery);/*! + * jQuery UI Widget 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */ +(function(b,d){if(b.cleanData){var c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)}}else{var a=b.fn.remove;b.fn.remove=function(e,f){return this.each(function(){if(!f){if(!e||b.filter(e,[this]).length){b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(g){}})}}return a.call(b(this),e,f)})}}b.widget=function(f,h,e){var g=f.split(".")[0],j;f=f.split(".")[1];j=g+"-"+f;if(!e){e=h;h=b.Widget}b.expr[":"][j]=function(k){return !!b.data(k,f)};b[g]=b[g]||{};b[g][f]=function(k,l){if(arguments.length){this._createWidget(k,l)}};var i=new h();i.options=b.extend(true,{},i.options);b[g][f].prototype=b.extend(true,i,{namespace:g,widgetName:f,widgetEventPrefix:b[g][f].prototype.widgetEventPrefix||f,widgetBaseClass:j},e);b.widget.bridge(f,b[g][f])};b.widget.bridge=function(f,e){b.fn[f]=function(i){var g=typeof i==="string",h=Array.prototype.slice.call(arguments,1),j=this;i=!g&&h.length?b.extend.apply(null,[true,i].concat(h)):i;if(g&&i.charAt(0)==="_"){return j}if(g){this.each(function(){var k=b.data(this,f),l=k&&b.isFunction(k[i])?k[i].apply(k,h):k;if(l!==k&&l!==d){j=l;return false}})}else{this.each(function(){var k=b.data(this,f);if(k){k.option(i||{})._init()}else{b.data(this,f,new e(i,this))}})}return j}};b.Widget=function(e,f){if(arguments.length){this._createWidget(e,f)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(f,g){b.data(g,this.widgetName,this);this.element=b(g);this.options=b.extend(true,{},this.options,this._getCreateOptions(),f);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(f,g){var e=f;if(arguments.length===0){return b.extend({},this.options)}if(typeof f==="string"){if(g===d){return this.options[f]}e={};e[f]=g}this._setOptions(e);return this},_setOptions:function(f){var e=this;b.each(f,function(g,h){e._setOption(g,h)});return this},_setOption:function(e,f){this.options[e]=f;if(e==="disabled"){this.widget()[f?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",f)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(e,f,g){var j,i,h=this.options[e];g=g||{};f=b.Event(f);f.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase();f.target=this.element[0];i=f.originalEvent;if(i){for(j in i){if(!(j in f)){f[j]=i[j]}}}this.element.trigger(f,g);return !(b.isFunction(h)&&h.call(this.element[0],f,g)===false||f.isDefaultPrevented())}}})(jQuery);/*! + * jQuery UI Mouse 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Mouse + * + * Depends: + * jquery.ui.widget.js + */ +(function(b,c){var a=false;b(document).mouseup(function(d){a=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var d=this;this.element.bind("mousedown."+this.widgetName,function(e){return d._mouseDown(e)}).bind("click."+this.widgetName,function(e){if(true===b.data(e.target,d.widgetName+".preventClickEvent")){b.removeData(e.target,d.widgetName+".preventClickEvent");e.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(f){if(a){return}(this._mouseStarted&&this._mouseUp(f));this._mouseDownEvent=f;var e=this,g=(f.which==1),d=(typeof this.options.cancel=="string"&&f.target.nodeName?b(f.target).closest(this.options.cancel).length:false);if(!g||d||!this._mouseCapture(f)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){e.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=(this._mouseStart(f)!==false);if(!this._mouseStarted){f.preventDefault();return true}}if(true===b.data(f.target,this.widgetName+".preventClickEvent")){b.removeData(f.target,this.widgetName+".preventClickEvent")}this._mouseMoveDelegate=function(h){return e._mouseMove(h)};this._mouseUpDelegate=function(h){return e._mouseUp(h)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);f.preventDefault();a=true;return true},_mouseMove:function(d){if(b.browser.msie&&!(document.documentMode>=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target==this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(c,d){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var f=this,k=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(k.aspectRatio),aspectRatio:k.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:k.helper||k.ghost||k.animate?k.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap(c('
').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var g=0;g
');if(/sw|se|ne|nw/.test(j)){h.css({zIndex:++k.zIndex})}if("se"==j){h.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(h)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!f.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}f.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");f._handles.show()},function(){if(k.disabled){return}if(!f.resizing){c(this).addClass("ui-resizable-autohide");f._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;f.after(this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var h=this.helper,g=this.options,m={},q=this,j=this.originalMousePosition,n=this.axis;var r=(e.pageX-j.left)||0,p=(e.pageY-j.top)||0;var i=this._change[n];if(!i){return false}var l=i.apply(this,[e,r,p]),k=c.browser.msie&&c.browser.version<7,f=this.sizeDiff;this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){l=this._updateRatio(l,e)}l=this._respectSize(l,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(l);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,m=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:m.sizeDiff.height,k=e?0:m.sizeDiff.width;var n={width:(m.helper.width()-k),height:(m.helper.height()-f)},j=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,l=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:l,left:j}))}m.helper.height(m.size.height);m.helper.width(m.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(hl.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f');var e=c.browser.msie&&c.browser.version<7,g=(e?1:0),h=(e?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++i.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8.18"});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,n){var p=c(this).data("resizable"),j=p.options;var h=p._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:p.sizeDiff.height,l=e?0:p.sizeDiff.width;var g={width:(p.size.width-l),height:(p.size.height-f)},k=(parseInt(p.element.css("left"),10)+(p.position.left-p.originalPosition.left))||null,m=(parseInt(p.element.css("top"),10)+(p.position.top-p.originalPosition.top))||null;p.element.animate(c.extend(g,m&&k?{top:m,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(p.element.css("width"),10),height:parseInt(p.element.css("height"),10),top:parseInt(p.element.css("top"),10),left:parseInt(p.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}p._updateCache(o);p._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,r){var t=c(this).data("resizable"),j=t.options,l=t.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}t.containerElement=c(k);if(/document/.test(g)||g==document){t.containerOffset={left:0,top:0};t.containerPosition={left:0,top:0};t.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});t.containerOffset=n.offset();t.containerPosition=n.position();t.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var q=t.containerOffset,e=t.containerSize.height,m=t.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),s=(c.ui.hasScroll(k)?k.scrollHeight:e);t.parentData={element:k,left:q.left,top:q.top,width:h,height:s}}},resize:function(g,q){var t=c(this).data("resizable"),i=t.options,f=t.containerSize,p=t.containerOffset,m=t.size,n=t.position,r=t._aspectRatio||g.shiftKey,e={top:0,left:0},h=t.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=p}if(n.left<(t._helper?p.left:0)){t.size.width=t.size.width+(t._helper?(t.position.left-p.left):(t.position.left-e.left));if(r){t.size.height=t.size.width/i.aspectRatio}t.position.left=i.helper?p.left:0}if(n.top<(t._helper?p.top:0)){t.size.height=t.size.height+(t._helper?(t.position.top-p.top):t.position.top);if(r){t.size.width=t.size.height*i.aspectRatio}t.position.top=t._helper?p.top:0}t.offset.left=t.parentData.left+t.position.left;t.offset.top=t.parentData.top+t.position.top;var l=Math.abs((t._helper?t.offset.left-e.left:(t.offset.left-e.left))+t.sizeDiff.width),s=Math.abs((t._helper?t.offset.top-e.top:(t.offset.top-p.top))+t.sizeDiff.height);var k=t.containerElement.get(0)==t.element.parent().get(0),j=/relative|absolute/.test(t.containerElement.css("position"));if(k&&j){l-=t.parentData.left}if(l+t.size.width>=t.parentData.width){t.size.width=t.parentData.width-l;if(r){t.size.height=t.size.width/t.aspectRatio}}if(s+t.size.height>=t.parentData.height){t.size.height=t.parentData.height-s;if(r){t.size.width=t.size.height*t.aspectRatio}}},stop:function(f,n){var q=c(this).data("resizable"),g=q.options,l=q.position,m=q.containerOffset,e=q.containerPosition,i=q.containerElement;var j=c(q.helper),r=j.offset(),p=j.outerWidth()-q.sizeDiff.width,k=j.outerHeight()-q.sizeDiff.height;if(q._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}if(q._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var e=c(this).data("resizable"),i=e.options,f=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");e.ghost.appendTo(e.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,m){var p=c(this).data("resizable"),h=p.options,k=p.size,i=p.originalSize,j=p.originalPosition,n=p.axis,l=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((k.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((k.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f}else{if(/^(ne)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f}else{if(/^(sw)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.left=j.left-g}else{p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f;p.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);/*! + * jQuery hashchange event - v1.3 - 7/21/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$(' + + +
+
+
SSLClient - Arduino Library For SSL
+
+
+

SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.

+

SSLClient is a simple library to add TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it.

+

Overview

+

Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with EthernetClient. There are a few extra things, however, that you will need to get started:

+
    +
  1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Notes).
  2. +
  3. A header containing array of trust anchors, which will look like this file. These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out this document on how to generate this file for your project, and for more information about what a trust anchor is.
  4. +
  5. A Client class associated with a network interface. We tested this library using EthernetClient, however in theory it will work for any class implementing Client.
  6. +
  7. An analog pin, used for generating random data at the start of the connection (see the Implementation Notes).
  8. +
+

Once all those are ready, you can create a simple SSLClient object like this:

{C++}
SSLClient<BaseClientType> client(BaseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin);

Where:

    +
  • BaseClientType - The type of BaseClientInstance
  • +
  • BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3)
  • +
  • TAs - The name of the trust anchor array created in step 2. If you generated a header using the tutorial this will probably be TAs.
  • +
  • TAs_NUM - The number of trust anchors in TAs. If you generated a header using the tutorial this will probably be TAs_NUM.
  • +
  • AnalogPin - The analog pin to pull random data from (step 4).

    +

    For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using:

    {C++}
    SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);

    Once that is setup, simply use SSLClient as you would the base client class:

    {C++}
    // connect to ardiuino.cc over ssl (port 443 for websites)
    client.connect("www.arduino.cc", 443);
    // Make a HTTP request
    client.println("GET /asciilogo.txt HTTP/1.1");
    client.println("User-Agent: AdafruitFeatherM0WiFi");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();
    client.flush();
    // read and print the data
    ...

    Note: client.connect("www.arduino.cc", 443) can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in Implementation Notes.

    +
  • +
+

For more information on SSLClient, check out the examples, API documentation, or the rest of this README.

+

How It Works

+

SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant BearSSL as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, making debugging a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint.

+

Additionally, the bulk of SSLClient is split into two components: a template class SSLClient, and an implementation class SSLClientImpl. The template class serves to abstract some functions not implemented in the Arduino Client interface (such as EthernetClient::remoteIP), and the implementation class is the rest of the SSLClient library.

+

Other Features

+

Logging

+

SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor:

{C++}
SSLClient<EthernetClient> client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO);

Logging is always outputted through the Arduino Serial interface, so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in Error. The log level is set to SSL_WARN by default.

+

Errors

+

When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from SSLClient::getWriteError(), which will return a value from [this enumeration](link-me). For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at SSL_ERROR or lower.

+

Write Buffering

+

As you may have noticed in the documentation for [SSLClient::write](link-me), calling this function does not actually write to the network. Instead, you must call [SSLClient::available](link-me) or [SSLClient::flush](link-me), which will detect that the buffer is ready and write to the network (see [SSLClient::write](link-me) for details).

+

This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so:

{C++}
EthernetClient client;
// ...
// connect to ardiuino.cc over ssl (port 443 for websites)
client.connect("www.arduino.cc", 443);
// ...
// write an http request to the network
client.write("GET /asciilogo.txt HTTP/1.1\r\n");
client.write("Host: arduino.cc\r\n");
client.write("Connection: close\r\n");
// wait for response
while (!client.available()) { /* ... */ }
// ...

Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

+
{C++}
SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);
// ...
// connect to ardiuino.cc over ssl (port 443 for websites)
client.connect("www.arduino.cc", 443);
// ...
// add http request to the buffer
client.write("GET /asciilogo.txt HTTP/1.1\r\n");
client.write("Host: arduino.cc\r\n");
client.write("Connection: close\r\n");
// write the bytes to the network, then wait for response
while (!client.available()) { /* ... */ }
// ...

If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

+

Session Caching

+

As detailed in the resources section, SSL handshakes take an extended period (1-4sec) to negotiate. To remedy this problem, BearSSL is able to keep a SSL session cache of the clients it has connected to. If BearSSL successfully resumes an SSL session, it can reduce connection time to 100-500ms.

+

In order to use SSL session resumption:

    +
  • The website you are connecting to must support it. Support is widespread, but you can verify easily using the SSLLabs tool.
  • +
  • You must reuse the same SSLClient object (SSL Sessions are stored in the object itself).
  • +
  • You must reconnect to the exact same server.
  • +
+

SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call connect("www.google.com") SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with "www.google.com". However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection.

+

You can test whether or not a website can resume SSL Sessions using the Session Example included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume.

+

Implementation Gotchas

+

Some ideas that didn't quite fit in the API documentation.

+

Certificate Verification

+

SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out this document for more details on this component of SSLClient.

+

BearSSL also features a known certificate validation engine, which only allows for a single domain in exchange for a significantly reduced resource usage (flash and CPU time). This functionality is planned to be implemented in the future.

+

Resources

+

The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive.

+

To illustrate this, I will run some tests on various domains below. I haven't yet, but I will.

+

If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from SSLClient.h, SSLClientImpl.h, and SSLClientImpl.cpp. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself.

+

Read Buffer Overflow

+

SSL is a buffered protocol, and since most microcontrollers have limited resources (see Resources), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow, caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received, forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems, this could be the reason why.

+

In order to remedy this problem, the device must be able to read the data faster than it is being received, or alternatively have a cache large enough to store the entire payload. Since SSL's encryption forces the device to read slowly, this means we must increase the cache size. Depending on your platform, there are a number of ways this can be done:

    +
  • Sometimes your communication shield will have an internal buffer, which can be expanded through the driver code. This is the case with the Arduino Ethernet library (in the form of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be modified for the change to take effect.
  • +
  • SSLClient has an internal buffer SSLClientImpl::m_iobuf, which can be expanded. BearSSL limits the amount of data that can be processed based on the stage in the SSL handshake, and so this will change will have limited usefulness.
  • +
  • In some cases, a website will send so much data that even with the above solutions, SSLClient will be unable to keep up (a website with a lot of HTML is an example). In these cases you will have to find another method of retrieving the data you need.
  • +
  • If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM.
  • +
+

Cipher Support

+

By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

{C++}
br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
// comment the above line and uncomment the line below if you're having trouble connecting over SSL
// br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

to this:

{C++}
// br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
// comment the above line and uncomment the line below if you're having trouble connecting over SSL
br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the BearSSL profiles documentation and I wish you the best of luck.

+
+
+ + + + + diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html new file mode 100644 index 0000000..ae62f75 --- /dev/null +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -0,0 +1,119 @@ + + + + + + + +SSLClient: Trust Anchors + + + + + + + + + + + + + + +
+
+
+ + + + + +
+
SSLClient +  1.0 +
+
Add TLS 1.2 functionality to any network library.
+
+ + + + + + + + + +
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Trust Anchors
+
+
+

SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. In short, these trust anchor arrays allow BearSSL to verify that the server being connected to is who they say they are, and not someone malicious. You can read more about certificates and why they are important here.

+

SSLClient stores trust anchors in hardcoded constant variables, passed into SSLClient::SSLClient during setup. These constants are generally stored in their own header file as found in the BearSSL docs. This header file will look something like:

{C++}
#define TAs_NUM 1
static const unsigned char TA_DN0[] = {
// lots of raw bytes here
// ...
};
static const unsigned char TA_RSA_N0[] = {
// lots of raw bytes here
//...
};
static const unsigned char TA_RSA_E0[] = {
// 1-3 bytes here
};
static const br_x509_trust_anchor TAs[] = {
{
{ (unsigned char *)TA_DN0, sizeof TA_DN0 },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
(unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
} }
}
},
};

A full example of a trust anchor header can be found in this file. Full documentation for the format of these variables can be found in the BearSSL documentation for br_x509_trust_anchor.

+

Generating Trust Anchors

+

HTTPS

+

For HTTPS, there a couple of tools you can use. Ordered from easy to hard:

+

Other Connections

+

For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convert command to convert the certificate into a trust anchor header.

+

Using Trust Anchors

+

Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

{C++}
#include "yourtrustanchorfile.h"
// ...
SSLClient<SomeClientType> client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
// ...

Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

+
+
+
+ + + + diff --git a/docs/html/menu.js b/docs/html/menu.js new file mode 100644 index 0000000..433c15b --- /dev/null +++ b/docs/html/menu.js @@ -0,0 +1,50 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + 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. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function initMenu(relPath,searchEnabled,serverSide,searchPage,search) { + function makeTree(data,relPath) { + var result=''; + if ('children' in data) { + result+=''; + } + return result; + } + + $('#main-nav').append(makeTree(menudata,relPath)); + $('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu'); + if (searchEnabled) { + if (serverSide) { + $('#main-menu').append('
  • '); + } else { + $('#main-menu').append('
  • '); + } + } + $('#main-menu').smartmenus(); +} +/* @license-end */ diff --git a/docs/html/menudata.js b/docs/html/menudata.js new file mode 100644 index 0000000..c2595e9 --- /dev/null +++ b/docs/html/menudata.js @@ -0,0 +1,78 @@ +/* +@ @licstart The following is the entire license notice for the +JavaScript code in this file. + +Copyright (C) 1997-2017 by Dimitri van Heesch + +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. + +@licend The above is the entire license notice +for the JavaScript code in this file +*/ +var menudata={children:[ +{text:"Main Page",url:"index.html"}, +{text:"Related Pages",url:"pages.html"}, +{text:"Classes",url:"annotated.html",children:[ +{text:"Class List",url:"annotated.html"}, +{text:"Class Index",url:"classes.html"}, +{text:"Class Hierarchy",url:"hierarchy.html"}, +{text:"Class Members",url:"functions.html",children:[ +{text:"All",url:"functions.html",children:[ +{text:"a",url:"functions.html#index_a"}, +{text:"c",url:"functions.html#index_c"}, +{text:"f",url:"functions.html#index_f"}, +{text:"g",url:"functions.html#index_g"}, +{text:"i",url:"functions.html#index_i"}, +{text:"l",url:"functions.html#index_l"}, +{text:"m",url:"functions.html#index_m"}, +{text:"o",url:"functions.html#index_o"}, +{text:"p",url:"functions.html#index_p"}, +{text:"r",url:"functions.html#index_r"}, +{text:"s",url:"functions.html#index_s"}, +{text:"t",url:"functions.html#index_t"}, +{text:"w",url:"functions.html#index_w"}]}, +{text:"Functions",url:"functions_func.html",children:[ +{text:"a",url:"functions_func.html#index_a"}, +{text:"c",url:"functions_func.html#index_c"}, +{text:"f",url:"functions_func.html#index_f"}, +{text:"g",url:"functions_func.html#index_g"}, +{text:"i",url:"functions_func.html#index_i"}, +{text:"l",url:"functions_func.html#index_l"}, +{text:"m",url:"functions_func.html#index_m"}, +{text:"o",url:"functions_func.html#index_o"}, +{text:"p",url:"functions_func.html#index_p"}, +{text:"r",url:"functions_func.html#index_r"}, +{text:"s",url:"functions_func.html#index_s"}, +{text:"t",url:"functions_func.html#index_t"}, +{text:"w",url:"functions_func.html#index_w"}]}]}]}, +{text:"Files",url:"files.html",children:[ +{text:"File List",url:"files.html"}, +{text:"File Members",url:"globals.html",children:[ +{text:"All",url:"globals.html",children:[ +{text:"_",url:"globals.html#index__5F"}, +{text:"b",url:"globals.html#index_b"}, +{text:"c",url:"globals.html#index_c"}, +{text:"d",url:"globals.html#index_d"}, +{text:"e",url:"globals.html#index_e"}, +{text:"g",url:"globals.html#index_g"}, +{text:"p",url:"globals.html#index_p"}, +{text:"s",url:"globals.html#index_s"}, +{text:"t",url:"globals.html#index_t"}, +{text:"u",url:"globals.html#index_u"}]}, +{text:"Functions",url:"globals_func.html"}, +{text:"Variables",url:"globals_vars.html"}, +{text:"Enumerations",url:"globals_enum.html"}, +{text:"Enumerator",url:"globals_eval.html"}, +{text:"Macros",url:"globals_defs.html"}]}]}]} diff --git a/docs/html/nav_f.png b/docs/html/nav_f.png new file mode 100644 index 0000000000000000000000000000000000000000..72a58a529ed3a9ed6aa0c51a79cf207e026deee2 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQVE_ejv*C{Z|{2ZH7M}7UYxc) zn!W8uqtnIQ>_z8U literal 0 HcmV?d00001 diff --git a/docs/html/nav_g.png b/docs/html/nav_g.png new file mode 100644 index 0000000000000000000000000000000000000000..2093a237a94f6c83e19ec6e5fd42f7ddabdafa81 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrB!3HFm1ilyoDK$?Q$B+ufw|5PB85lU25BhtE tr?otc=hd~V+ws&_A@j8Fiv!KF$B+ufw|5=67#uj90@pIL wZ=Q8~_Ju`#59=RjDrmm`tMD@M=!-l18IR?&vFVdQ&MBb@0HFXL=0 ? varName.substring(i+1) : varName; + return eval(n.replace(/\-/g,'_')); +} + +function stripPath(uri) +{ + return uri.substring(uri.lastIndexOf('/')+1); +} + +function stripPath2(uri) +{ + var i = uri.lastIndexOf('/'); + var s = uri.substring(i+1); + var m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/); + return m ? uri.substring(i-6) : s; +} + +function hashValue() +{ + return $(location).attr('hash').substring(1).replace(/[^\w\-]/g,''); +} + +function hashUrl() +{ + return '#'+hashValue(); +} + +function pathName() +{ + return $(location).attr('pathname').replace(/[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]/g, ''); +} + +function localStorageSupported() +{ + try { + return 'localStorage' in window && window['localStorage'] !== null && window.localStorage.getItem; + } + catch(e) { + return false; + } +} + + +function storeLink(link) +{ + if (!$("#nav-sync").hasClass('sync') && localStorageSupported()) { + window.localStorage.setItem('navpath',link); + } +} + +function deleteLink() +{ + if (localStorageSupported()) { + window.localStorage.setItem('navpath',''); + } +} + +function cachedLink() +{ + if (localStorageSupported()) { + return window.localStorage.getItem('navpath'); + } else { + return ''; + } +} + +function getScript(scriptName,func,show) +{ + var head = document.getElementsByTagName("head")[0]; + var script = document.createElement('script'); + script.id = scriptName; + script.type = 'text/javascript'; + script.onload = func; + script.src = scriptName+'.js'; + if ($.browser.msie && $.browser.version<=8) { + // script.onload does not work with older versions of IE + script.onreadystatechange = function() { + if (script.readyState=='complete' || script.readyState=='loaded') { + func(); if (show) showRoot(); + } + } + } + head.appendChild(script); +} + +function createIndent(o,domNode,node,level) +{ + var level=-1; + var n = node; + while (n.parentNode) { level++; n=n.parentNode; } + if (node.childrenData) { + var imgNode = document.createElement("span"); + imgNode.className = 'arrow'; + imgNode.style.paddingLeft=(16*level).toString()+'px'; + imgNode.innerHTML=arrowRight; + node.plus_img = imgNode; + node.expandToggle = document.createElement("a"); + node.expandToggle.href = "javascript:void(0)"; + node.expandToggle.onclick = function() { + if (node.expanded) { + $(node.getChildrenUL()).slideUp("fast"); + node.plus_img.innerHTML=arrowRight; + node.expanded = false; + } else { + expandNode(o, node, false, false); + } + } + node.expandToggle.appendChild(imgNode); + domNode.appendChild(node.expandToggle); + } else { + var span = document.createElement("span"); + span.className = 'arrow'; + span.style.width = 16*(level+1)+'px'; + span.innerHTML = ' '; + domNode.appendChild(span); + } +} + +var animationInProgress = false; + +function gotoAnchor(anchor,aname,updateLocation) +{ + var pos, docContent = $('#doc-content'); + var ancParent = $(anchor.parent()); + if (ancParent.hasClass('memItemLeft') || + ancParent.hasClass('fieldname') || + ancParent.hasClass('fieldtype') || + ancParent.is(':header')) + { + pos = ancParent.position().top; + } else if (anchor.position()) { + pos = anchor.position().top; + } + if (pos) { + var dist = Math.abs(Math.min( + pos-docContent.offset().top, + docContent[0].scrollHeight- + docContent.height()-docContent.scrollTop())); + animationInProgress=true; + docContent.animate({ + scrollTop: pos + docContent.scrollTop() - docContent.offset().top + },Math.max(50,Math.min(500,dist)),function(){ + if (updateLocation) window.location.href=aname; + animationInProgress=false; + }); + } +} + +function newNode(o, po, text, link, childrenData, lastNode) +{ + var node = new Object(); + node.children = Array(); + node.childrenData = childrenData; + node.depth = po.depth + 1; + node.relpath = po.relpath; + node.isLast = lastNode; + + node.li = document.createElement("li"); + po.getChildrenUL().appendChild(node.li); + node.parentNode = po; + + node.itemDiv = document.createElement("div"); + node.itemDiv.className = "item"; + + node.labelSpan = document.createElement("span"); + node.labelSpan.className = "label"; + + createIndent(o,node.itemDiv,node,0); + node.itemDiv.appendChild(node.labelSpan); + node.li.appendChild(node.itemDiv); + + var a = document.createElement("a"); + node.labelSpan.appendChild(a); + node.label = document.createTextNode(text); + node.expanded = false; + a.appendChild(node.label); + if (link) { + var url; + if (link.substring(0,1)=='^') { + url = link.substring(1); + link = url; + } else { + url = node.relpath+link; + } + a.className = stripPath(link.replace('#',':')); + if (link.indexOf('#')!=-1) { + var aname = '#'+link.split('#')[1]; + var srcPage = stripPath(pathName()); + var targetPage = stripPath(link.split('#')[0]); + a.href = srcPage!=targetPage ? url : "javascript:void(0)"; + a.onclick = function(){ + storeLink(link); + if (!$(a).parent().parent().hasClass('selected')) + { + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + $(a).parent().parent().addClass('selected'); + $(a).parent().parent().attr('id','selected'); + } + var anchor = $(aname); + gotoAnchor(anchor,aname,true); + }; + } else { + a.href = url; + a.onclick = function() { storeLink(link); } + } + } else { + if (childrenData != null) + { + a.className = "nolink"; + a.href = "javascript:void(0)"; + a.onclick = node.expandToggle.onclick; + } + } + + node.childrenUL = null; + node.getChildrenUL = function() { + if (!node.childrenUL) { + node.childrenUL = document.createElement("ul"); + node.childrenUL.className = "children_ul"; + node.childrenUL.style.display = "none"; + node.li.appendChild(node.childrenUL); + } + return node.childrenUL; + }; + + return node; +} + +function showRoot() +{ + var headerHeight = $("#top").height(); + var footerHeight = $("#nav-path").height(); + var windowHeight = $(window).height() - headerHeight - footerHeight; + (function (){ // retry until we can scroll to the selected item + try { + var navtree=$('#nav-tree'); + navtree.scrollTo('#selected',0,{offset:-windowHeight/2}); + } catch (err) { + setTimeout(arguments.callee, 0); + } + })(); +} + +function expandNode(o, node, imm, showRoot) +{ + if (node.childrenData && !node.expanded) { + if (typeof(node.childrenData)==='string') { + var varName = node.childrenData; + getScript(node.relpath+varName,function(){ + node.childrenData = getData(varName); + expandNode(o, node, imm, showRoot); + }, showRoot); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } if (imm || ($.browser.msie && $.browser.version>8)) { + // somehow slideDown jumps to the start of tree for IE9 :-( + $(node.getChildrenUL()).show(); + } else { + $(node.getChildrenUL()).slideDown("fast"); + } + node.plus_img.innerHTML = arrowDown; + node.expanded = true; + } + } +} + +function glowEffect(n,duration) +{ + n.addClass('glow').delay(duration).queue(function(next){ + $(this).removeClass('glow');next(); + }); +} + +function highlightAnchor() +{ + var aname = hashUrl(); + var anchor = $(aname); + if (anchor.parent().attr('class')=='memItemLeft'){ + var rows = $('.memberdecls tr[class$="'+hashValue()+'"]'); + glowEffect(rows.children(),300); // member without details + } else if (anchor.parent().attr('class')=='fieldname'){ + glowEffect(anchor.parent().parent(),1000); // enum value + } else if (anchor.parent().attr('class')=='fieldtype'){ + glowEffect(anchor.parent().parent(),1000); // struct field + } else if (anchor.parent().is(":header")) { + glowEffect(anchor.parent(),1000); // section header + } else { + glowEffect(anchor.next(),1000); // normal member + } + gotoAnchor(anchor,aname,false); +} + +function selectAndHighlight(hash,n) +{ + var a; + if (hash) { + var link=stripPath(pathName())+':'+hash.substring(1); + a=$('.item a[class$="'+link+'"]'); + } + if (a && a.length) { + a.parent().parent().addClass('selected'); + a.parent().parent().attr('id','selected'); + highlightAnchor(); + } else if (n) { + $(n.itemDiv).addClass('selected'); + $(n.itemDiv).attr('id','selected'); + } + if ($('#nav-tree-contents .item:first').hasClass('selected')) { + $('#nav-sync').css('top','30px'); + } else { + $('#nav-sync').css('top','5px'); + } + showRoot(); +} + +function showNode(o, node, index, hash) +{ + if (node && node.childrenData) { + if (typeof(node.childrenData)==='string') { + var varName = node.childrenData; + getScript(node.relpath+varName,function(){ + node.childrenData = getData(varName); + showNode(o,node,index,hash); + },true); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } + $(node.getChildrenUL()).css({'display':'block'}); + node.plus_img.innerHTML = arrowDown; + node.expanded = true; + var n = node.children[o.breadcrumbs[index]]; + if (index+11) hash = '#'+parts[1].replace(/[^\w\-]/g,''); + else hash=''; + } + if (hash.match(/^#l\d+$/)) { + var anchor=$('a[name='+hash.substring(1)+']'); + glowEffect(anchor.parent(),1000); // line number + hash=''; // strip line number anchors + } + var url=root+hash; + var i=-1; + while (NAVTREEINDEX[i+1]<=url) i++; + if (i==-1) { i=0; root=NAVTREE[0][1]; } // fallback: show index + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath) + } else { + getScript(relpath+'navtreeindex'+i,function(){ + navTreeSubIndices[i] = eval('NAVTREEINDEX'+i); + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath); + } + },true); + } +} + +function showSyncOff(n,relpath) +{ + n.html(''); +} + +function showSyncOn(n,relpath) +{ + n.html(''); +} + +function toggleSyncButton(relpath) +{ + var navSync = $('#nav-sync'); + if (navSync.hasClass('sync')) { + navSync.removeClass('sync'); + showSyncOff(navSync,relpath); + storeLink(stripPath2(pathName())+hashUrl()); + } else { + navSync.addClass('sync'); + showSyncOn(navSync,relpath); + deleteLink(); + } +} + +function initNavTree(toroot,relpath) +{ + var o = new Object(); + o.toroot = toroot; + o.node = new Object(); + o.node.li = document.getElementById("nav-tree-contents"); + o.node.childrenData = NAVTREE; + o.node.children = new Array(); + o.node.childrenUL = document.createElement("ul"); + o.node.getChildrenUL = function() { return o.node.childrenUL; }; + o.node.li.appendChild(o.node.childrenUL); + o.node.depth = 0; + o.node.relpath = relpath; + o.node.expanded = false; + o.node.isLast = true; + o.node.plus_img = document.createElement("span"); + o.node.plus_img.className = 'arrow'; + o.node.plus_img.innerHTML = arrowRight; + + if (localStorageSupported()) { + var navSync = $('#nav-sync'); + if (cachedLink()) { + showSyncOff(navSync,relpath); + navSync.removeClass('sync'); + } else { + showSyncOn(navSync,relpath); + } + navSync.click(function(){ toggleSyncButton(relpath); }); + } + + $(window).load(function(){ + navTo(o,toroot,hashUrl(),relpath); + showRoot(); + }); + + $(window).bind('hashchange', function(){ + if (window.location.hash && window.location.hash.length>1){ + var a; + if ($(location).attr('hash')){ + var clslink=stripPath(pathName())+':'+hashValue(); + a=$('.item a[class$="'+clslink.replace(/1|%O$WD@{VPM$7~Ar*{o?;hlAFyLXmaDC0y znK1_#cQqJWPES%4Uujug^TE?jMft$}Eq^WaR~)%f)vSNs&gek&x%A9X9sM + + + + + + +SSLClient: Related Pages + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    Related Pages
    +
    +
    +
    Here is a list of all related documentation pages:
    +
    +
    + + + + diff --git a/docs/html/resize.js b/docs/html/resize.js new file mode 100644 index 0000000..6617aee --- /dev/null +++ b/docs/html/resize.js @@ -0,0 +1,136 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + 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. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function initResizable() +{ + var cookie_namespace = 'doxygen'; + var sidenav,navtree,content,header,collapsed,collapsedWidth=0,barWidth=6,desktop_vp=768,titleHeight; + + function readCookie(cookie) + { + var myCookie = cookie_namespace+"_"+cookie+"="; + if (document.cookie) { + var index = document.cookie.indexOf(myCookie); + if (index != -1) { + var valStart = index + myCookie.length; + var valEnd = document.cookie.indexOf(";", valStart); + if (valEnd == -1) { + valEnd = document.cookie.length; + } + var val = document.cookie.substring(valStart, valEnd); + return val; + } + } + return 0; + } + + function writeCookie(cookie, val, expiration) + { + if (val==undefined) return; + if (expiration == null) { + var date = new Date(); + date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week + expiration = date.toGMTString(); + } + document.cookie = cookie_namespace + "_" + cookie + "=" + val + "; expires=" + expiration+"; path=/"; + } + + function resizeWidth() + { + var windowWidth = $(window).width() + "px"; + var sidenavWidth = $(sidenav).outerWidth(); + content.css({marginLeft:parseInt(sidenavWidth)+"px"}); + writeCookie('width',sidenavWidth-barWidth, null); + } + + function restoreWidth(navWidth) + { + var windowWidth = $(window).width() + "px"; + content.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + sidenav.css({width:navWidth + "px"}); + } + + function resizeHeight() + { + var headerHeight = header.outerHeight(); + var footerHeight = footer.outerHeight(); + var windowHeight = $(window).height() - headerHeight - footerHeight; + content.css({height:windowHeight + "px"}); + navtree.css({height:windowHeight + "px"}); + sidenav.css({height:windowHeight + "px"}); + var width=$(window).width(); + if (width!=collapsedWidth) { + if (width=desktop_vp) { + if (!collapsed) { + collapseExpand(); + } + } else if (width>desktop_vp && collapsedWidth0) { + restoreWidth(0); + collapsed=true; + } + else { + var width = readCookie('width'); + if (width>200 && width<$(window).width()) { restoreWidth(width); } else { restoreWidth(200); } + collapsed=false; + } + } + + header = $("#top"); + sidenav = $("#side-nav"); + content = $("#doc-content"); + navtree = $("#nav-tree"); + footer = $("#nav-path"); + $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); + $(sidenav).resizable({ minWidth: 0 }); + $(window).resize(function() { resizeHeight(); }); + var device = navigator.userAgent.toLowerCase(); + var touch_device = device.match(/(iphone|ipod|ipad|android)/); + if (touch_device) { /* wider split bar for touch only devices */ + $(sidenav).css({ paddingRight:'20px' }); + $('.ui-resizable-e').css({ width:'20px' }); + $('#nav-sync').css({ right:'34px' }); + barWidth=20; + } + var width = readCookie('width'); + if (width) { restoreWidth(width); } else { resizeWidth(); } + resizeHeight(); + var url = location.href; + var i=url.indexOf("#"); + if (i>=0) window.location.hash=url.substr(i); + var _preventDefault = function(evt) { evt.preventDefault(); }; + $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); + $(".ui-resizable-handle").dblclick(collapseExpand); + $(window).load(resizeHeight); +} +/* @license-end */ diff --git a/docs/html/search/all_0.html b/docs/html/search/all_0.html new file mode 100644 index 0000000..5330204 --- /dev/null +++ b/docs/html/search/all_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_0.js b/docs/html/search/all_0.js new file mode 100644 index 0000000..e3a632e --- /dev/null +++ b/docs/html/search/all_0.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClientImpl.cpp']]], + ['_5f_5ftime_5fdays_5f_5f',['__TIME_DAYS__',['../time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf',1,'time_macros.h']]], + ['_5f_5ftime_5fhours_5f_5f',['__TIME_HOURS__',['../time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4',1,'time_macros.h']]], + ['_5f_5ftime_5fminutes_5f_5f',['__TIME_MINUTES__',['../time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8',1,'time_macros.h']]], + ['_5f_5ftime_5fmonth_5f_5f',['__TIME_MONTH__',['../time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1',1,'time_macros.h']]], + ['_5f_5ftime_5fseconds_5f_5f',['__TIME_SECONDS__',['../time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97',1,'time_macros.h']]], + ['_5f_5ftime_5fyears_5f_5f',['__TIME_YEARS__',['../time__macros_8h.html#a56482fcc86a55713dee595c2092ed376',1,'time_macros.h']]], + ['_5funix_5ftimestamp',['_UNIX_TIMESTAMP',['../time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3',1,'time_macros.h']]], + ['_5funix_5ftimestamp_5ffday',['_UNIX_TIMESTAMP_FDAY',['../time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79',1,'time_macros.h']]], + ['_5funix_5ftimestamp_5fyday',['_UNIX_TIMESTAMP_YDAY',['../time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97',1,'time_macros.h']]] +]; diff --git a/docs/html/search/all_1.html b/docs/html/search/all_1.html new file mode 100644 index 0000000..2f46793 --- /dev/null +++ b/docs/html/search/all_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_1.js b/docs/html/search/all_1.js new file mode 100644 index 0000000..e146f72 --- /dev/null +++ b/docs/html/search/all_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['available',['available',['../class_s_s_l_client.html#a40ec85568d0aec376219125b604dbc29',1,'SSLClient']]], + ['available_5fimpl',['available_impl',['../class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/all_10.html b/docs/html/search/all_10.html new file mode 100644 index 0000000..170dc09 --- /dev/null +++ b/docs/html/search/all_10.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_10.js b/docs/html/search/all_10.js new file mode 100644 index 0000000..a658122 --- /dev/null +++ b/docs/html/search/all_10.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['unix_5ftimestamp',['UNIX_TIMESTAMP',['../time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487',1,'time_macros.h']]], + ['unix_5ftimestamp_5futc',['UNIX_TIMESTAMP_UTC',['../time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3',1,'time_macros.h']]] +]; diff --git a/docs/html/search/all_11.html b/docs/html/search/all_11.html new file mode 100644 index 0000000..10fcd09 --- /dev/null +++ b/docs/html/search/all_11.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js new file mode 100644 index 0000000..bd942e1 --- /dev/null +++ b/docs/html/search/all_11.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['write',['write',['../class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270',1,'SSLClient::write(uint8_t b)'],['../class_s_s_l_client.html#a3a48b190985cdea2eba79ef0bdc80461',1,'SSLClient::write(const uint8_t *buf, size_t size)']]], + ['write_5fimpl',['write_impl',['../class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/all_2.html b/docs/html/search/all_2.html new file mode 100644 index 0000000..4c33d85 --- /dev/null +++ b/docs/html/search/all_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_2.js b/docs/html/search/all_2.js new file mode 100644 index 0000000..95d65d8 --- /dev/null +++ b/docs/html/search/all_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['br_5fclient_5finit_5ftls12_5fonly',['br_client_init_TLS12_only',['../_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3',1,'TLS12_only_profile.c']]] +]; diff --git a/docs/html/search/all_3.html b/docs/html/search/all_3.html new file mode 100644 index 0000000..b634070 --- /dev/null +++ b/docs/html/search/all_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js new file mode 100644 index 0000000..81496e7 --- /dev/null +++ b/docs/html/search/all_3.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['cert_2eh',['cert.h',['../cert_8h.html',1,'']]], + ['clear_5fparameters',['clear_parameters',['../class_s_s_l_session.html#a3305941fa615f7134526b718917716ee',1,'SSLSession']]], + ['connect',['connect',['../class_s_s_l_client.html#ae6540b9a02f1392bf2ac48421189f70e',1,'SSLClient::connect(IPAddress ip, uint16_t port)'],['../class_s_s_l_client.html#a5814c11e96848c2bcea78210f099aad5',1,'SSLClient::connect(const char *host, uint16_t port)']]], + ['connect_5fimpl',['connect_impl',['../class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b',1,'SSLClientImpl::connect_impl(IPAddress ip, uint16_t port)'],['../class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba',1,'SSLClientImpl::connect_impl(const char *host, uint16_t port)']]], + ['connected',['connected',['../class_s_s_l_client.html#a7318aadc0ec9775bffaaac0b1f00aaf8',1,'SSLClient']]], + ['connected_5fimpl',['connected_impl',['../class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb',1,'SSLClientImpl']]], + ['conv_5fstr2dec_5f1',['CONV_STR2DEC_1',['../time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a',1,'time_macros.h']]], + ['conv_5fstr2dec_5f2',['CONV_STR2DEC_2',['../time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3',1,'time_macros.h']]], + ['conv_5fstr2dec_5f3',['CONV_STR2DEC_3',['../time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4',1,'time_macros.h']]], + ['conv_5fstr2dec_5f4',['CONV_STR2DEC_4',['../time__macros_8h.html#a9da779a8ca64782ea49babce14122d34',1,'time_macros.h']]] +]; diff --git a/docs/html/search/all_4.html b/docs/html/search/all_4.html new file mode 100644 index 0000000..dd062ae --- /dev/null +++ b/docs/html/search/all_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_4.js b/docs/html/search/all_4.js new file mode 100644 index 0000000..a3cc239 --- /dev/null +++ b/docs/html/search/all_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['debuglevel',['DebugLevel',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395',1,'SSLClientImpl.h']]] +]; diff --git a/docs/html/search/all_5.html b/docs/html/search/all_5.html new file mode 100644 index 0000000..f0780fd --- /dev/null +++ b/docs/html/search/all_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_5.js b/docs/html/search/all_5.js new file mode 100644 index 0000000..212a9a9 --- /dev/null +++ b/docs/html/search/all_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['error',['Error',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5',1,'SSLClientImpl.h']]] +]; diff --git a/docs/html/search/all_6.html b/docs/html/search/all_6.html new file mode 100644 index 0000000..39b0f55 --- /dev/null +++ b/docs/html/search/all_6.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js new file mode 100644 index 0000000..49584f5 --- /dev/null +++ b/docs/html/search/all_6.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['flush',['flush',['../class_s_s_l_client.html#a51eb668f6a328a6a66298c6bc1361d41',1,'SSLClient']]], + ['flush_5fimpl',['flush_impl',['../class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/all_7.html b/docs/html/search/all_7.html new file mode 100644 index 0000000..9cd0196 --- /dev/null +++ b/docs/html/search/all_7.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js new file mode 100644 index 0000000..926ac2d --- /dev/null +++ b/docs/html/search/all_7.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#ab3ebfbca41a56bfa11e34aac2c2e0106',1,'SSLClient::get_arduino_client()'],['../class_s_s_l_client.html#a20742b36588c45435139a4f47fe0f1f6',1,'SSLClient::get_arduino_client() const'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], + ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], + ['get_5fip',['get_ip',['../class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0',1,'SSLSession']]], + ['get_5fmonth',['GET_MONTH',['../time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994',1,'time_macros.h']]], + ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#aaa52b481eb1d36a0ae1d208daa2fec51',1,'SSLClient::get_session_array()'],['../class_s_s_l_client.html#ab076a76b142b553c0dfd29174d4e17e7',1,'SSLClient::get_session_array() const'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], + ['get_5fsession_5fimpl',['get_session_impl',['../class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e',1,'SSLClientImpl']]], + ['getclient',['getClient',['../class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41',1,'SSLClient']]], + ['getsession',['getSession',['../class_s_s_l_client.html#ae3f27a36ff9c0cd1e2bea5e1708b6e4f',1,'SSLClient']]], + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a36bb344866e4cbcba3bbfcf4d33e5187',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] +]; diff --git a/docs/html/search/all_8.html b/docs/html/search/all_8.html new file mode 100644 index 0000000..1e8fb9c --- /dev/null +++ b/docs/html/search/all_8.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js new file mode 100644 index 0000000..7fdc7da --- /dev/null +++ b/docs/html/search/all_8.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['is_5fvalid_5fsession',['is_valid_session',['../class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076',1,'SSLSession']]] +]; diff --git a/docs/html/search/all_9.html b/docs/html/search/all_9.html new file mode 100644 index 0000000..27df366 --- /dev/null +++ b/docs/html/search/all_9.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_9.js b/docs/html/search/all_9.js new file mode 100644 index 0000000..ac8fe09 --- /dev/null +++ b/docs/html/search/all_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['localport',['localPort',['../class_s_s_l_client.html#ac725067566ee411680c88575c148300b',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] +]; diff --git a/docs/html/search/all_a.html b/docs/html/search/all_a.html new file mode 100644 index 0000000..63f9254 --- /dev/null +++ b/docs/html/search/all_a.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_a.js b/docs/html/search/all_a.js new file mode 100644 index 0000000..e250434 --- /dev/null +++ b/docs/html/search/all_a.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['m_5ferror',['m_error',['../class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83',1,'SSLClientImpl']]], + ['m_5finfo',['m_info',['../class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c',1,'SSLClientImpl']]], + ['m_5fprint',['m_print',['../class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117',1,'SSLClientImpl']]], + ['m_5fprint_5fbr_5ferror',['m_print_br_error',['../class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed',1,'SSLClientImpl']]], + ['m_5fprint_5fprefix',['m_print_prefix',['../class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f',1,'SSLClientImpl']]], + ['m_5fprint_5fssl_5ferror',['m_print_ssl_error',['../class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075',1,'SSLClientImpl']]], + ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/all_b.html b/docs/html/search/all_b.html new file mode 100644 index 0000000..44ae3e4 --- /dev/null +++ b/docs/html/search/all_b.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_b.js b/docs/html/search/all_b.js new file mode 100644 index 0000000..7bc0384 --- /dev/null +++ b/docs/html/search/all_b.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a319a722dae252efdd85fdbaf5c7fbf17',1,'SSLClient']]], + ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a9a060e49d0685c6c6795558e41cd3323',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#a518f4ed733814f2f4a8c7f838555eb35',1,'SSLClient::operator!=(const C &rhs)']]], + ['operator_3d',['operator=',['../class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f',1,'SSLSession']]], + ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a6fb2e8a1cc54dd82a72217e5c4533e02',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a26f9418e33d4ca459f78de98d3af43bb',1,'SSLClient::operator==(const C &rhs)']]] +]; diff --git a/docs/html/search/all_c.html b/docs/html/search/all_c.html new file mode 100644 index 0000000..3de1586 --- /dev/null +++ b/docs/html/search/all_c.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_c.js b/docs/html/search/all_c.js new file mode 100644 index 0000000..036e45a --- /dev/null +++ b/docs/html/search/all_c.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['peek',['peek',['../class_s_s_l_client.html#a227b1cbbe91bcb21153c09f97d0dd484',1,'SSLClient']]], + ['peek_5fimpl',['peek_impl',['../class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d',1,'SSLClientImpl']]], + ['pst_5foffset',['PST_OFFSET',['../time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb',1,'time_macros.h']]] +]; diff --git a/docs/html/search/all_d.html b/docs/html/search/all_d.html new file mode 100644 index 0000000..a2d5bd7 --- /dev/null +++ b/docs/html/search/all_d.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_d.js b/docs/html/search/all_d.js new file mode 100644 index 0000000..7dcf3c4 --- /dev/null +++ b/docs/html/search/all_d.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['read',['read',['../class_s_s_l_client.html#ac70b900ff798f9fd33f6367fcc9fad77',1,'SSLClient::read()'],['../class_s_s_l_client.html#ae31dd88a1af8ec3794fb48f26a3dd4bf',1,'SSLClient::read(uint8_t *buf, size_t size)']]], + ['read_5fimpl',['read_impl',['../class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe',1,'SSLClientImpl']]], + ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]], + ['remoteip',['remoteIP',['../class_s_s_l_client.html#ae2d1d17ee568ec2a37756bf6894dcd05',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], + ['remoteport',['remotePort',['../class_s_s_l_client.html#ae8bd9420fec3b11f855729c4ecfe1c2c',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], + ['remove_5fsession_5fimpl',['remove_session_impl',['../class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1',1,'SSLClientImpl']]], + ['removesession',['removeSession',['../class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0',1,'SSLClient']]] +]; diff --git a/docs/html/search/all_e.html b/docs/html/search/all_e.html new file mode 100644 index 0000000..f9a056d --- /dev/null +++ b/docs/html/search/all_e.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js new file mode 100644 index 0000000..2ae3e87 --- /dev/null +++ b/docs/html/search/all_e.js @@ -0,0 +1,31 @@ +var searchData= +[ + ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html',1,'']]], + ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], + ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], + ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], + ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], + ['set_5fparameters',['set_parameters',['../class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e',1,'SSLSession']]], + ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3',1,'SSLClientImpl.h']]], + ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9',1,'SSLClientImpl.h']]], + ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b',1,'SSLClientImpl.h']]], + ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b',1,'SSLClientImpl.h']]], + ['ssl_5ferror',['SSL_ERROR',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec',1,'SSLClientImpl.h']]], + ['ssl_5finfo',['SSL_INFO',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91',1,'SSLClientImpl.h']]], + ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc',1,'SSLClientImpl.h']]], + ['ssl_5fnone',['SSL_NONE',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f',1,'SSLClientImpl.h']]], + ['ssl_5fok',['SSL_OK',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c',1,'SSLClientImpl.h']]], + ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6',1,'SSLClientImpl.h']]], + ['ssl_5fwarn',['SSL_WARN',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d',1,'SSLClientImpl.h']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient< C, SessionCache >'],['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient()']]], + ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], + ['sslclient_5fh_5f',['SSLClient_H_',['../_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569',1,'SSLClient.h']]], + ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'SSLClientImpl'],['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl()']]], + ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], + ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], + ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession::SSLSession()']]], + ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], + ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], + ['stop',['stop',['../class_s_s_l_client.html#a158d87df3fe118b7565a19b72f310322',1,'SSLClient']]], + ['stop_5fimpl',['stop_impl',['../class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/all_f.html b/docs/html/search/all_f.html new file mode 100644 index 0000000..f6997fa --- /dev/null +++ b/docs/html/search/all_f.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_f.js b/docs/html/search/all_f.js new file mode 100644 index 0000000..aa9c0c5 --- /dev/null +++ b/docs/html/search/all_f.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['trust_20anchors',['Trust Anchors',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]], + ['tas_5fnum',['TAs_NUM',['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'cert.h']]], + ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], + ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], + ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]], + ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] +]; diff --git a/docs/html/search/classes_0.html b/docs/html/search/classes_0.html new file mode 100644 index 0000000..b3c6ec6 --- /dev/null +++ b/docs/html/search/classes_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js new file mode 100644 index 0000000..95b55ac --- /dev/null +++ b/docs/html/search/classes_0.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'']]], + ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'']]], + ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'']]] +]; diff --git a/docs/html/search/close.png b/docs/html/search/close.png new file mode 100644 index 0000000000000000000000000000000000000000..9342d3dfeea7b7c4ee610987e717804b5a42ceb9 GIT binary patch literal 273 zcmV+s0q*{ZP)4(RlMby96)VwnbG{ zbe&}^BDn7x>$<{ck4zAK-=nT;=hHG)kmplIF${xqm8db3oX6wT3bvp`TE@m0cg;b) zBuSL}5?N7O(iZLdAlz@)b)Rd~DnSsSX&P5qC`XwuFwcAYLC+d2>+1(8on;wpt8QIC X2MT$R4iQDd00000NkvXXu0mjfia~GN literal 0 HcmV?d00001 diff --git a/docs/html/search/defines_0.html b/docs/html/search/defines_0.html new file mode 100644 index 0000000..dbe0642 --- /dev/null +++ b/docs/html/search/defines_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/defines_0.js b/docs/html/search/defines_0.js new file mode 100644 index 0000000..7708a75 --- /dev/null +++ b/docs/html/search/defines_0.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['_5f_5ftime_5fdays_5f_5f',['__TIME_DAYS__',['../time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf',1,'time_macros.h']]], + ['_5f_5ftime_5fhours_5f_5f',['__TIME_HOURS__',['../time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4',1,'time_macros.h']]], + ['_5f_5ftime_5fminutes_5f_5f',['__TIME_MINUTES__',['../time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8',1,'time_macros.h']]], + ['_5f_5ftime_5fmonth_5f_5f',['__TIME_MONTH__',['../time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1',1,'time_macros.h']]], + ['_5f_5ftime_5fseconds_5f_5f',['__TIME_SECONDS__',['../time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97',1,'time_macros.h']]], + ['_5f_5ftime_5fyears_5f_5f',['__TIME_YEARS__',['../time__macros_8h.html#a56482fcc86a55713dee595c2092ed376',1,'time_macros.h']]], + ['_5funix_5ftimestamp',['_UNIX_TIMESTAMP',['../time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3',1,'time_macros.h']]], + ['_5funix_5ftimestamp_5ffday',['_UNIX_TIMESTAMP_FDAY',['../time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79',1,'time_macros.h']]], + ['_5funix_5ftimestamp_5fyday',['_UNIX_TIMESTAMP_YDAY',['../time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97',1,'time_macros.h']]] +]; diff --git a/docs/html/search/defines_1.html b/docs/html/search/defines_1.html new file mode 100644 index 0000000..7af9324 --- /dev/null +++ b/docs/html/search/defines_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/defines_1.js b/docs/html/search/defines_1.js new file mode 100644 index 0000000..d96070b --- /dev/null +++ b/docs/html/search/defines_1.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['conv_5fstr2dec_5f1',['CONV_STR2DEC_1',['../time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a',1,'time_macros.h']]], + ['conv_5fstr2dec_5f2',['CONV_STR2DEC_2',['../time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3',1,'time_macros.h']]], + ['conv_5fstr2dec_5f3',['CONV_STR2DEC_3',['../time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4',1,'time_macros.h']]], + ['conv_5fstr2dec_5f4',['CONV_STR2DEC_4',['../time__macros_8h.html#a9da779a8ca64782ea49babce14122d34',1,'time_macros.h']]] +]; diff --git a/docs/html/search/defines_2.html b/docs/html/search/defines_2.html new file mode 100644 index 0000000..4629221 --- /dev/null +++ b/docs/html/search/defines_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/defines_2.js b/docs/html/search/defines_2.js new file mode 100644 index 0000000..3b6b52c --- /dev/null +++ b/docs/html/search/defines_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['get_5fmonth',['GET_MONTH',['../time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994',1,'time_macros.h']]] +]; diff --git a/docs/html/search/defines_3.html b/docs/html/search/defines_3.html new file mode 100644 index 0000000..a62cf61 --- /dev/null +++ b/docs/html/search/defines_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/defines_3.js b/docs/html/search/defines_3.js new file mode 100644 index 0000000..437b39a --- /dev/null +++ b/docs/html/search/defines_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['pst_5foffset',['PST_OFFSET',['../time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb',1,'time_macros.h']]] +]; diff --git a/docs/html/search/defines_4.html b/docs/html/search/defines_4.html new file mode 100644 index 0000000..ebd8a20 --- /dev/null +++ b/docs/html/search/defines_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/defines_4.js b/docs/html/search/defines_4.js new file mode 100644 index 0000000..2572f0d --- /dev/null +++ b/docs/html/search/defines_4.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], + ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], + ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], + ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], + ['sslclient_5fh_5f',['SSLClient_H_',['../_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569',1,'SSLClient.h']]] +]; diff --git a/docs/html/search/defines_5.html b/docs/html/search/defines_5.html new file mode 100644 index 0000000..4f88d78 --- /dev/null +++ b/docs/html/search/defines_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/defines_5.js b/docs/html/search/defines_5.js new file mode 100644 index 0000000..c10d695 --- /dev/null +++ b/docs/html/search/defines_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['tas_5fnum',['TAs_NUM',['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'cert.h']]] +]; diff --git a/docs/html/search/defines_6.html b/docs/html/search/defines_6.html new file mode 100644 index 0000000..1314ce7 --- /dev/null +++ b/docs/html/search/defines_6.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/defines_6.js b/docs/html/search/defines_6.js new file mode 100644 index 0000000..a658122 --- /dev/null +++ b/docs/html/search/defines_6.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['unix_5ftimestamp',['UNIX_TIMESTAMP',['../time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487',1,'time_macros.h']]], + ['unix_5ftimestamp_5futc',['UNIX_TIMESTAMP_UTC',['../time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3',1,'time_macros.h']]] +]; diff --git a/docs/html/search/enums_0.html b/docs/html/search/enums_0.html new file mode 100644 index 0000000..7040a9c --- /dev/null +++ b/docs/html/search/enums_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/enums_0.js b/docs/html/search/enums_0.js new file mode 100644 index 0000000..a3cc239 --- /dev/null +++ b/docs/html/search/enums_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['debuglevel',['DebugLevel',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395',1,'SSLClientImpl.h']]] +]; diff --git a/docs/html/search/enums_1.html b/docs/html/search/enums_1.html new file mode 100644 index 0000000..0c65c0e --- /dev/null +++ b/docs/html/search/enums_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/enums_1.js b/docs/html/search/enums_1.js new file mode 100644 index 0000000..212a9a9 --- /dev/null +++ b/docs/html/search/enums_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['error',['Error',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5',1,'SSLClientImpl.h']]] +]; diff --git a/docs/html/search/enumvalues_0.html b/docs/html/search/enumvalues_0.html new file mode 100644 index 0000000..78895c7 --- /dev/null +++ b/docs/html/search/enumvalues_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/enumvalues_0.js b/docs/html/search/enumvalues_0.js new file mode 100644 index 0000000..0dc67d2 --- /dev/null +++ b/docs/html/search/enumvalues_0.js @@ -0,0 +1,14 @@ +var searchData= +[ + ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3',1,'SSLClientImpl.h']]], + ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9',1,'SSLClientImpl.h']]], + ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b',1,'SSLClientImpl.h']]], + ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b',1,'SSLClientImpl.h']]], + ['ssl_5ferror',['SSL_ERROR',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec',1,'SSLClientImpl.h']]], + ['ssl_5finfo',['SSL_INFO',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91',1,'SSLClientImpl.h']]], + ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc',1,'SSLClientImpl.h']]], + ['ssl_5fnone',['SSL_NONE',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f',1,'SSLClientImpl.h']]], + ['ssl_5fok',['SSL_OK',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c',1,'SSLClientImpl.h']]], + ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6',1,'SSLClientImpl.h']]], + ['ssl_5fwarn',['SSL_WARN',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d',1,'SSLClientImpl.h']]] +]; diff --git a/docs/html/search/files_0.html b/docs/html/search/files_0.html new file mode 100644 index 0000000..40cd455 --- /dev/null +++ b/docs/html/search/files_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/files_0.js b/docs/html/search/files_0.js new file mode 100644 index 0000000..1d97411 --- /dev/null +++ b/docs/html/search/files_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['cert_2eh',['cert.h',['../cert_8h.html',1,'']]] +]; diff --git a/docs/html/search/files_1.html b/docs/html/search/files_1.html new file mode 100644 index 0000000..646d1f4 --- /dev/null +++ b/docs/html/search/files_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/files_1.js b/docs/html/search/files_1.js new file mode 100644 index 0000000..66a27ec --- /dev/null +++ b/docs/html/search/files_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]] +]; diff --git a/docs/html/search/files_2.html b/docs/html/search/files_2.html new file mode 100644 index 0000000..9e47a77 --- /dev/null +++ b/docs/html/search/files_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/files_2.js b/docs/html/search/files_2.js new file mode 100644 index 0000000..1750530 --- /dev/null +++ b/docs/html/search/files_2.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], + ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], + ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], + ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], + ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]] +]; diff --git a/docs/html/search/files_3.html b/docs/html/search/files_3.html new file mode 100644 index 0000000..167679b --- /dev/null +++ b/docs/html/search/files_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/files_3.js b/docs/html/search/files_3.js new file mode 100644 index 0000000..377b9b8 --- /dev/null +++ b/docs/html/search/files_3.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], + ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], + ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] +]; diff --git a/docs/html/search/functions_0.html b/docs/html/search/functions_0.html new file mode 100644 index 0000000..bc73761 --- /dev/null +++ b/docs/html/search/functions_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js new file mode 100644 index 0000000..e146f72 --- /dev/null +++ b/docs/html/search/functions_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['available',['available',['../class_s_s_l_client.html#a40ec85568d0aec376219125b604dbc29',1,'SSLClient']]], + ['available_5fimpl',['available_impl',['../class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/functions_1.html b/docs/html/search/functions_1.html new file mode 100644 index 0000000..bfcf880 --- /dev/null +++ b/docs/html/search/functions_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_1.js b/docs/html/search/functions_1.js new file mode 100644 index 0000000..95d65d8 --- /dev/null +++ b/docs/html/search/functions_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['br_5fclient_5finit_5ftls12_5fonly',['br_client_init_TLS12_only',['../_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3',1,'TLS12_only_profile.c']]] +]; diff --git a/docs/html/search/functions_2.html b/docs/html/search/functions_2.html new file mode 100644 index 0000000..2b44474 --- /dev/null +++ b/docs/html/search/functions_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_2.js b/docs/html/search/functions_2.js new file mode 100644 index 0000000..22b749e --- /dev/null +++ b/docs/html/search/functions_2.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['clear_5fparameters',['clear_parameters',['../class_s_s_l_session.html#a3305941fa615f7134526b718917716ee',1,'SSLSession']]], + ['connect',['connect',['../class_s_s_l_client.html#ae6540b9a02f1392bf2ac48421189f70e',1,'SSLClient::connect(IPAddress ip, uint16_t port)'],['../class_s_s_l_client.html#a5814c11e96848c2bcea78210f099aad5',1,'SSLClient::connect(const char *host, uint16_t port)']]], + ['connect_5fimpl',['connect_impl',['../class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b',1,'SSLClientImpl::connect_impl(IPAddress ip, uint16_t port)'],['../class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba',1,'SSLClientImpl::connect_impl(const char *host, uint16_t port)']]], + ['connected',['connected',['../class_s_s_l_client.html#a7318aadc0ec9775bffaaac0b1f00aaf8',1,'SSLClient']]], + ['connected_5fimpl',['connected_impl',['../class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/functions_3.html b/docs/html/search/functions_3.html new file mode 100644 index 0000000..3dca367 --- /dev/null +++ b/docs/html/search/functions_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_3.js b/docs/html/search/functions_3.js new file mode 100644 index 0000000..49584f5 --- /dev/null +++ b/docs/html/search/functions_3.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['flush',['flush',['../class_s_s_l_client.html#a51eb668f6a328a6a66298c6bc1361d41',1,'SSLClient']]], + ['flush_5fimpl',['flush_impl',['../class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/functions_4.html b/docs/html/search/functions_4.html new file mode 100644 index 0000000..e713f28 --- /dev/null +++ b/docs/html/search/functions_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_4.js b/docs/html/search/functions_4.js new file mode 100644 index 0000000..78322fb --- /dev/null +++ b/docs/html/search/functions_4.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#ab3ebfbca41a56bfa11e34aac2c2e0106',1,'SSLClient::get_arduino_client()'],['../class_s_s_l_client.html#a20742b36588c45435139a4f47fe0f1f6',1,'SSLClient::get_arduino_client() const'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], + ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], + ['get_5fip',['get_ip',['../class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0',1,'SSLSession']]], + ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#aaa52b481eb1d36a0ae1d208daa2fec51',1,'SSLClient::get_session_array()'],['../class_s_s_l_client.html#ab076a76b142b553c0dfd29174d4e17e7',1,'SSLClient::get_session_array() const'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], + ['get_5fsession_5fimpl',['get_session_impl',['../class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e',1,'SSLClientImpl']]], + ['getclient',['getClient',['../class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41',1,'SSLClient']]], + ['getsession',['getSession',['../class_s_s_l_client.html#ae3f27a36ff9c0cd1e2bea5e1708b6e4f',1,'SSLClient']]], + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a36bb344866e4cbcba3bbfcf4d33e5187',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] +]; diff --git a/docs/html/search/functions_5.html b/docs/html/search/functions_5.html new file mode 100644 index 0000000..cfe6b17 --- /dev/null +++ b/docs/html/search/functions_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_5.js b/docs/html/search/functions_5.js new file mode 100644 index 0000000..7fdc7da --- /dev/null +++ b/docs/html/search/functions_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['is_5fvalid_5fsession',['is_valid_session',['../class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076',1,'SSLSession']]] +]; diff --git a/docs/html/search/functions_6.html b/docs/html/search/functions_6.html new file mode 100644 index 0000000..a78ec13 --- /dev/null +++ b/docs/html/search/functions_6.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_6.js b/docs/html/search/functions_6.js new file mode 100644 index 0000000..ac8fe09 --- /dev/null +++ b/docs/html/search/functions_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['localport',['localPort',['../class_s_s_l_client.html#ac725067566ee411680c88575c148300b',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] +]; diff --git a/docs/html/search/functions_7.html b/docs/html/search/functions_7.html new file mode 100644 index 0000000..7842361 --- /dev/null +++ b/docs/html/search/functions_7.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_7.js b/docs/html/search/functions_7.js new file mode 100644 index 0000000..e250434 --- /dev/null +++ b/docs/html/search/functions_7.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['m_5ferror',['m_error',['../class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83',1,'SSLClientImpl']]], + ['m_5finfo',['m_info',['../class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c',1,'SSLClientImpl']]], + ['m_5fprint',['m_print',['../class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117',1,'SSLClientImpl']]], + ['m_5fprint_5fbr_5ferror',['m_print_br_error',['../class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed',1,'SSLClientImpl']]], + ['m_5fprint_5fprefix',['m_print_prefix',['../class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f',1,'SSLClientImpl']]], + ['m_5fprint_5fssl_5ferror',['m_print_ssl_error',['../class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075',1,'SSLClientImpl']]], + ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/functions_8.html b/docs/html/search/functions_8.html new file mode 100644 index 0000000..48feafe --- /dev/null +++ b/docs/html/search/functions_8.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_8.js b/docs/html/search/functions_8.js new file mode 100644 index 0000000..7bc0384 --- /dev/null +++ b/docs/html/search/functions_8.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a319a722dae252efdd85fdbaf5c7fbf17',1,'SSLClient']]], + ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a9a060e49d0685c6c6795558e41cd3323',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#a518f4ed733814f2f4a8c7f838555eb35',1,'SSLClient::operator!=(const C &rhs)']]], + ['operator_3d',['operator=',['../class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f',1,'SSLSession']]], + ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a6fb2e8a1cc54dd82a72217e5c4533e02',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a26f9418e33d4ca459f78de98d3af43bb',1,'SSLClient::operator==(const C &rhs)']]] +]; diff --git a/docs/html/search/functions_9.html b/docs/html/search/functions_9.html new file mode 100644 index 0000000..0f05a8b --- /dev/null +++ b/docs/html/search/functions_9.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_9.js b/docs/html/search/functions_9.js new file mode 100644 index 0000000..ce70a60 --- /dev/null +++ b/docs/html/search/functions_9.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['peek',['peek',['../class_s_s_l_client.html#a227b1cbbe91bcb21153c09f97d0dd484',1,'SSLClient']]], + ['peek_5fimpl',['peek_impl',['../class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/functions_a.html b/docs/html/search/functions_a.html new file mode 100644 index 0000000..03faad2 --- /dev/null +++ b/docs/html/search/functions_a.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_a.js b/docs/html/search/functions_a.js new file mode 100644 index 0000000..66237d4 --- /dev/null +++ b/docs/html/search/functions_a.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['read',['read',['../class_s_s_l_client.html#ac70b900ff798f9fd33f6367fcc9fad77',1,'SSLClient::read()'],['../class_s_s_l_client.html#ae31dd88a1af8ec3794fb48f26a3dd4bf',1,'SSLClient::read(uint8_t *buf, size_t size)']]], + ['read_5fimpl',['read_impl',['../class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe',1,'SSLClientImpl']]], + ['remoteip',['remoteIP',['../class_s_s_l_client.html#ae2d1d17ee568ec2a37756bf6894dcd05',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], + ['remoteport',['remotePort',['../class_s_s_l_client.html#ae8bd9420fec3b11f855729c4ecfe1c2c',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], + ['remove_5fsession_5fimpl',['remove_session_impl',['../class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1',1,'SSLClientImpl']]], + ['removesession',['removeSession',['../class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0',1,'SSLClient']]] +]; diff --git a/docs/html/search/functions_b.html b/docs/html/search/functions_b.html new file mode 100644 index 0000000..c690013 --- /dev/null +++ b/docs/html/search/functions_b.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js new file mode 100644 index 0000000..5c6e59a --- /dev/null +++ b/docs/html/search/functions_b.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['set_5fparameters',['set_parameters',['../class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e',1,'SSLSession']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient']]], + ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl']]], + ['sslsession',['SSLSession',['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession']]], + ['stop',['stop',['../class_s_s_l_client.html#a158d87df3fe118b7565a19b72f310322',1,'SSLClient']]], + ['stop_5fimpl',['stop_impl',['../class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/functions_c.html b/docs/html/search/functions_c.html new file mode 100644 index 0000000..3b2976a --- /dev/null +++ b/docs/html/search/functions_c.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_c.js b/docs/html/search/functions_c.js new file mode 100644 index 0000000..96d95c1 --- /dev/null +++ b/docs/html/search/functions_c.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]] +]; diff --git a/docs/html/search/functions_d.html b/docs/html/search/functions_d.html new file mode 100644 index 0000000..0c54246 --- /dev/null +++ b/docs/html/search/functions_d.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_d.js b/docs/html/search/functions_d.js new file mode 100644 index 0000000..bd942e1 --- /dev/null +++ b/docs/html/search/functions_d.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['write',['write',['../class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270',1,'SSLClient::write(uint8_t b)'],['../class_s_s_l_client.html#a3a48b190985cdea2eba79ef0bdc80461',1,'SSLClient::write(const uint8_t *buf, size_t size)']]], + ['write_5fimpl',['write_impl',['../class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/mag_sel.png b/docs/html/search/mag_sel.png new file mode 100644 index 0000000000000000000000000000000000000000..39c0ed52a25dd9d080ee0d42ae6c6042bdfa04d7 GIT binary patch literal 465 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz6!2%?$TA$hhDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~NU84L`?eGCi_EEpJ?t}-xGu`@87+QPtK?83kxQ`TapwHK(CDaqU2h2ejD|C#+j z9%q3^WHAE+w=f7ZGR&GI0Tg5}@$_|Nf5gMiEhFgvHvB$N=!mC_V~EE2vzPXI9ZnEo zd+1zHor@dYLod2Y{ z@R$7$Z!PXTbY$|@#T!bMzm?`b<(R`cbw(gxJHzu zB$lLFB^RXvDF!10LknF)BV7aY5JN*NBMU1-b8Q0yD+2>vd*|CI8glbfGSez?Ylunu RoetE%;OXk;vd$@?2>>CYplSdB literal 0 HcmV?d00001 diff --git a/docs/html/search/nomatches.html b/docs/html/search/nomatches.html new file mode 100644 index 0000000..4377320 --- /dev/null +++ b/docs/html/search/nomatches.html @@ -0,0 +1,12 @@ + + + + + + + +
    +
    No Matches
    +
    + + diff --git a/docs/html/search/pages_0.html b/docs/html/search/pages_0.html new file mode 100644 index 0000000..3d06b05 --- /dev/null +++ b/docs/html/search/pages_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/pages_0.js b/docs/html/search/pages_0.js new file mode 100644 index 0000000..c416cfc --- /dev/null +++ b/docs/html/search/pages_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html',1,'']]] +]; diff --git a/docs/html/search/pages_1.html b/docs/html/search/pages_1.html new file mode 100644 index 0000000..06f1e40 --- /dev/null +++ b/docs/html/search/pages_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/pages_1.js b/docs/html/search/pages_1.js new file mode 100644 index 0000000..cdfc45f --- /dev/null +++ b/docs/html/search/pages_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['trust_20anchors',['Trust Anchors',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]] +]; diff --git a/docs/html/search/search.css b/docs/html/search/search.css new file mode 100644 index 0000000..3cf9df9 --- /dev/null +++ b/docs/html/search/search.css @@ -0,0 +1,271 @@ +/*---------------- Search Box */ + +#FSearchBox { + float: left; +} + +#MSearchBox { + white-space : nowrap; + float: none; + margin-top: 8px; + right: 0px; + width: 170px; + height: 24px; + z-index: 102; +} + +#MSearchBox .left +{ + display:block; + position:absolute; + left:10px; + width:20px; + height:19px; + background:url('search_l.png') no-repeat; + background-position:right; +} + +#MSearchSelect { + display:block; + position:absolute; + width:20px; + height:19px; +} + +.left #MSearchSelect { + left:4px; +} + +.right #MSearchSelect { + right:5px; +} + +#MSearchField { + display:block; + position:absolute; + height:19px; + background:url('search_m.png') repeat-x; + border:none; + width:115px; + margin-left:20px; + padding-left:4px; + color: #909090; + outline: none; + font: 9pt Arial, Verdana, sans-serif; + -webkit-border-radius: 0px; +} + +#FSearchBox #MSearchField { + margin-left:15px; +} + +#MSearchBox .right { + display:block; + position:absolute; + right:10px; + top:8px; + width:20px; + height:19px; + background:url('search_r.png') no-repeat; + background-position:left; +} + +#MSearchClose { + display: none; + position: absolute; + top: 4px; + background : none; + border: none; + margin: 0px 4px 0px 0px; + padding: 0px 0px; + outline: none; +} + +.left #MSearchClose { + left: 6px; +} + +.right #MSearchClose { + right: 2px; +} + +.MSearchBoxActive #MSearchField { + color: #000000; +} + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #90A5CE; + background-color: #F9FAFC; + z-index: 10001; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt Arial, Verdana, sans-serif; + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: monospace; + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: #000000; + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: #000000; + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: #FFFFFF; + background-color: #3D578C; + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + width: 60ex; + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #000; + background-color: #EEF1F7; + z-index:10000; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; + padding-bottom: 15px; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +body.SRPage { + margin: 5px 2px; +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; +} + +.SRResult { + display: none; +} + +DIV.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.searchresult { + background-color: #F0F3F8; +} + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: url("../tab_a.png"); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/docs/html/search/search.js b/docs/html/search/search.js new file mode 100644 index 0000000..a554ab9 --- /dev/null +++ b/docs/html/search/search.js @@ -0,0 +1,814 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + 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. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function convertToId(search) +{ + var result = ''; + for (i=0;i do a search + { + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) // Up + { + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } + else if (e.keyCode==13 || e.keyCode==27) + { + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() + { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() + { + this.keyTimeout = 0; + + // strip leading whitespace + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + var code = searchValue.toLowerCase().charCodeAt(0); + var idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair + { + idxChar = searchValue.substr(0, 2); + } + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) + { + var hexCode=idx.toString(16); + resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else // nothing available for this search term + { + resultsPage = this.resultsPath + '/nomatches.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + } + + window.frames.MSearchResults.location = resultsPageWithSearch; + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (domPopupSearchResultsWindow.style.display!='block') + { + var domSearchBox = this.DOMSearchBox(); + this.DOMSearchClose().style.display = 'inline'; + if (this.insideFrame) + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + domPopupSearchResultsWindow.style.position = 'relative'; + domPopupSearchResultsWindow.style.display = 'block'; + var width = document.body.clientWidth - 8; // the -8 is for IE :-( + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResults.style.width = width + 'px'; + } + else + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; + var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + } + } + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) + { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) + { + this.DOMSearchBox().className = 'MSearchBoxActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == this.searchLabel) // clear "Search" term upon entry + { + searchField.value = ''; + this.searchActive = true; + } + } + else if (!isActive) // directly remove the panel + { + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.DOMSearchField().value = this.searchLabel; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults(name) +{ + // The number of matches from the last run of . + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) + { + var parentElement = document.getElementById(id); + var element = parentElement.firstChild; + + while (element && element!=parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'SRChildren') + { + return element; + } + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { + element = element.firstChild; + } + else if (element.nextSibling) + { + element = element.nextSibling; + } + else + { + do + { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) + { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) + { + var element = this.FindChildElement(id); + if (element) + { + if (element.style.display == 'block') + { + element.style.display = 'none'; + } + else + { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) + { + if (!search) // get search word from URL + { + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) + { + row.style.display = 'block'; + matches++; + } + else + { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) // no results + { + document.getElementById("NoMatches").style.display='block'; + } + else // at least one result + { + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) + { + if (e.type == "keydown") + { + this.repeatOn = false; + this.lastKey = e.keyCode; + } + else if (e.type == "keypress") + { + if (!this.repeatOn) + { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } + else if (e.type == "keyup") + { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + var newIndex = itemIndex-1; + var focusItem = this.NavPrev(newIndex); + if (focusItem) + { + var child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') // children visible + { + var n=0; + var tmpElem; + while (1) // search for last child + { + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) + { + focusItem = tmpElem; + } + else // found it! + { + break; + } + n++; + } + } + } + if (focusItem) + { + focusItem.focus(); + } + else // return focus to search field + { + parent.document.getElementById("MSearchField").focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = itemIndex+1; + var focusItem; + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') // children visible + { + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } + else if (this.lastKey==39) // Right + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } + else if (this.lastKey==37) // Left + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + if (childIndex>0) + { + var newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } + else // already at first child, jump to parent + { + document.getElementById('Item'+itemIndex).focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = childIndex+1; + var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) // last child, jump to parent next parent + { + elem = this.NavNext(itemIndex+1); + } + if (elem) + { + elem.focus(); + } + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } +} + +function setKeyActions(elem,action) +{ + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); +} + +function setClassAttr(elem,attr) +{ + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); +} + +function createResults() +{ + var results = document.getElementById("SRResults"); + for (var e=0; e(R!W8j_r#qQ#gnr4kAxdU#F0+OBry$Z+ z_0PMi;P|#{d%mw(dnw=jM%@$onTJa%@6Nm3`;2S#nwtVFJI#`U@2Q@@JCCctagvF- z8H=anvo~dTmJ2YA%wA6IHRv%{vxvUm|R)kgZeo zmX%Zb;mpflGZdXCTAgit`||AFzkI#z&(3d4(htA?U2FOL4WF6wY&TB#n3n*I4+hl| z*NBpo#FA92vEu822WQ%mvv4FO#qs` BFGc_W literal 0 HcmV?d00001 diff --git a/docs/html/search/search_r.png b/docs/html/search/search_r.png new file mode 100644 index 0000000000000000000000000000000000000000..1af5d21ee13e070d7600f1c4657fde843b953a69 GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9c!2%@BXHTsJQY`6?zK#qG8~eHcB(ehe3dtTp zz6=bxGZ+|(`xqD=STHa&U1eaXVrO7DwS|Gf*oA>XrmV$GYcEhOQT(QLuS{~ooZ2P@v=Xc@RKW@Irliv8_;wroU0*)0O?temdsA~70jrdux+`@W7 z-N(<(C)L?hOO?KV{>8(jC{hpKsws)#Fh zvsO>IB+gb@b+rGWaO&!a9Z{!U+fV*s7TS>fdt&j$L%^U@Epd$~Nl7e8wMs5Z1yT$~ z28I^8hDN#u<{^fLRz?<9hUVG^237_Jy7tbuQ8eV{r(~v8;?@w8^gA7>fx*+&&t;uc GLK6VEQpiUD literal 0 HcmV?d00001 diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js new file mode 100644 index 0000000..26967e0 --- /dev/null +++ b/docs/html/search/searchdata.js @@ -0,0 +1,39 @@ +var indexSectionsWithContent = +{ + 0: "_abcdefgilmoprstuw", + 1: "s", + 2: "crst", + 3: "abcfgilmoprstw", + 4: "_", + 5: "de", + 6: "s", + 7: "_cgpstu", + 8: "st" +}; + +var indexSectionNames = +{ + 0: "all", + 1: "classes", + 2: "files", + 3: "functions", + 4: "variables", + 5: "enums", + 6: "enumvalues", + 7: "defines", + 8: "pages" +}; + +var indexSectionLabels = +{ + 0: "All", + 1: "Classes", + 2: "Files", + 3: "Functions", + 4: "Variables", + 5: "Enumerations", + 6: "Enumerator", + 7: "Macros", + 8: "Pages" +}; + diff --git a/docs/html/search/variables_0.html b/docs/html/search/variables_0.html new file mode 100644 index 0000000..12104bc --- /dev/null +++ b/docs/html/search/variables_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/variables_0.js b/docs/html/search/variables_0.js new file mode 100644 index 0000000..3adb20a --- /dev/null +++ b/docs/html/search/variables_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClientImpl.cpp']]] +]; diff --git a/docs/html/splitbar.png b/docs/html/splitbar.png new file mode 100644 index 0000000000000000000000000000000000000000..fe895f2c58179b471a22d8320b39a4bd7312ec8e GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^Yzz!63>-{AmhX=Jf(#6djGiuzAr*{o?=JLmPLyc> z_*`QK&+BH@jWrYJ7>r6%keRM@)Qyv8R=enp0jiI>aWlGyB58O zFVR20d+y`K7vDw(hJF3;>dD*3-?v=<8M)@x|EEGLnJsniYK!2U1 Y!`|5biEc?d1`HDhPgg&ebxsLQ02F6;9RL6T literal 0 HcmV?d00001 diff --git a/docs/html/sync_off.png b/docs/html/sync_off.png new file mode 100644 index 0000000000000000000000000000000000000000..3b443fc62892114406e3d399421b2a881b897acc GIT binary patch literal 853 zcmV-b1FHOqP)oT|#XixUYy%lpuf3i8{fX!o zUyDD0jOrAiT^tq>fLSOOABs-#u{dV^F$b{L9&!2=9&RmV;;8s^x&UqB$PCj4FdKbh zoB1WTskPUPu05XzFbA}=KZ-GP1fPpAfSs>6AHb12UlR%-i&uOlTpFNS7{jm@mkU1V zh`nrXr~+^lsV-s1dkZOaI|kYyVj3WBpPCY{n~yd%u%e+d=f%`N0FItMPtdgBb@py; zq@v6NVArhyTC7)ULw-Jy8y42S1~4n(3LkrW8mW(F-4oXUP3E`e#g**YyqI7h-J2zK zK{m9##m4ri!7N>CqQqCcnI3hqo1I;Yh&QLNY4T`*ptiQGozK>FF$!$+84Z`xwmeMh zJ0WT+OH$WYFALEaGj2_l+#DC3t7_S`vHpSivNeFbP6+r50cO8iu)`7i%Z4BTPh@_m3Tk!nAm^)5Bqnr%Ov|Baunj#&RPtRuK& z4RGz|D5HNrW83-#ydk}tVKJrNmyYt-sTxLGlJY5nc&Re zU4SgHNPx8~Yxwr$bsju?4q&%T1874xxzq+_%?h8_ofw~(bld=o3iC)LUNR*BY%c0y zWd_jX{Y8`l%z+ol1$@Qa?Cy!(0CVIEeYpKZ`(9{z>3$CIe;pJDQk$m3p}$>xBm4lb zKo{4S)`wdU9Ba9jJbVJ0C=SOefZe%d$8=2r={nu<_^a3~>c#t_U6dye5)JrR(_a^E f@}b6j1K9lwFJq@>o)+Ry00000NkvXXu0mjfWa5j* literal 0 HcmV?d00001 diff --git a/docs/html/sync_on.png b/docs/html/sync_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e08320fb64e6fa33b573005ed6d8fe294e19db76 GIT binary patch literal 845 zcmV-T1G4;yP)Y;xxyHF2B5Wzm| zOOGupOTn@c(JmBOl)e;XMNnZuiTJP>rM8<|Q`7I_))aP?*T)ow&n59{}X4$3Goat zgjs?*aasfbrokzG5cT4K=uG`E14xZl@z)F={P0Y^?$4t z>v!teRnNZym<6h{7sLyF1V0HsfEl+l6TrZpsfr1}luH~F7L}ktXu|*uVX^RG$L0`K zWs3j|0tIvVe(N%_?2{(iCPFGf#B6Hjy6o&}D$A%W%jfO8_W%ZO#-mh}EM$LMn7joJ z05dHr!5Y92g+31l<%i1(=L1a1pXX+OYnalY>31V4K}BjyRe3)9n#;-cCVRD_IG1fT zOKGeNY8q;TL@K{dj@D^scf&VCs*-Jb>8b>|`b*osv52-!A?BpbYtTQBns5EAU**$m zSnVSm(teh>tQi*S*A>#ySc=n;`BHz`DuG4&g4Kf8lLhca+zvZ7t7RflD6-i-mcK=M z!=^P$*u2)bkY5asG4gsss!Hn%u~>}kIW`vMs%lJLH+u*9<4PaV_c6U`KqWXQH%+Nu zTv41O(^ZVi@qhjQdG!fbZw&y+2o!iYymO^?ud3{P*HdoX83YV*Uu_HB=?U&W9%AU# z80}k1SS-CXTU7dcQlsm<^oYLxVSseqY6NO}dc`Nj?8vrhNuCdm@^{a3AQ_>6myOj+ z`1RsLUXF|dm|3k7s2jD(B{rzE>WI2scH8i1;=O5Cc9xB3^aJk%fQjqsu+kH#0=_5a z0nCE8@dbQa-|YIuUVvG0L_IwHMEhOj$Mj4Uq05 X8=0q~qBNan00000NkvXXu0mjfptF>5 literal 0 HcmV?d00001 diff --git a/docs/html/tab_a.png b/docs/html/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..3b725c41c5a527a3a3e40097077d0e206a681247 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QlXwMjv*C{Z|8b*H5dputLHD# z=<0|*y7z(Vor?d;H&?EG&cXR}?!j-Lm&u1OOI7AIF5&c)RFE;&p0MYK>*Kl@eiymD r@|NpwKX@^z+;{u_Z~trSBfrMKa%3`zocFjEXaR$#tDnm{r-UW|TZ1%4 literal 0 HcmV?d00001 diff --git a/docs/html/tab_b.png b/docs/html/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..e2b4a8638cb3496a016eaed9e16ffc12846dea18 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QU#tajv*C{Z}0l@H7kg?K0Lnr z!j&C6_(~HV9oQ0Pa6x{-v0AGV_E?vLn=ZI-;YrdjIl`U`uzuDWSP?o#Dmo{%SgM#oan kX~E1%D-|#H#QbHoIja2U-MgvsK&LQxy85}Sb4q9e0Efg%P5=M^ literal 0 HcmV?d00001 diff --git a/docs/html/tabs.css b/docs/html/tabs.css new file mode 100644 index 0000000..8ea7d54 --- /dev/null +++ b/docs/html/tabs.css @@ -0,0 +1 @@ +.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sm-dox{background-image:url("tab_b.png")}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:"Lucida Grande","Geneva","Helvetica",Arial,sans-serif;font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,0.9);color:#283a5d;outline:0}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace !important;text-align:center;text-shadow:none;background:rgba(255,255,255,0.5);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:rgba(162,162,162,0.1)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:white;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:url("tab_b.png");line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:#283a5d transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:url("tab_s.png");background-repeat:no-repeat;background-position:right;-moz-border-radius:0 !important;-webkit-border-radius:0;border-radius:0 !important}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a:hover span.sub-arrow{border-color:white transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent #fff transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:#fff;-moz-border-radius:5px !important;-webkit-border-radius:5px;border-radius:5px !important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent #555;border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:#555;background-image:none;border:0 !important;color:#555;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent white}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:#fff;height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent #555 transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:#555 transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px !important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:url("tab_b.png")}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:#fff}} \ No newline at end of file diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html new file mode 100644 index 0000000..896b8b7 --- /dev/null +++ b/docs/html/time__macros_8h.html @@ -0,0 +1,589 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/time_macros.h File Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    time_macros.h File Reference
    +
    +
    + +

    Go to the source code of this file.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Macros

    #define PST_OFFSET   (8UL)
     
    #define SEC_PER_MIN   (60UL)
     
    #define SEC_PER_HOUR   (3600UL)
     
    #define SEC_PER_DAY   (86400UL)
     
    #define SEC_PER_YEAR   (SEC_PER_DAY*365)
     
    #define CONV_STR2DEC_1(str, i)   (str[i]>'0'?str[i]-'0':0)
     
    #define CONV_STR2DEC_2(str, i)   (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
     
    #define CONV_STR2DEC_3(str, i)   (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
     
    #define CONV_STR2DEC_4(str, i)   (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
     
    #define GET_MONTH(str, i)
     
    #define __TIME_SECONDS__   CONV_STR2DEC_2(__TIME__, 6)
     
    #define __TIME_MINUTES__   CONV_STR2DEC_2(__TIME__, 3)
     
    #define __TIME_HOURS__   CONV_STR2DEC_2(__TIME__, 0)
     
    #define __TIME_DAYS__   CONV_STR2DEC_2(__DATE__, 4)
     
    #define __TIME_MONTH__   GET_MONTH(__DATE__, 0)
     
    #define __TIME_YEARS__   CONV_STR2DEC_4(__DATE__, 7)
     
    #define _UNIX_TIMESTAMP_FDAY(year)
     
    #define _UNIX_TIMESTAMP_YDAY(year, month, day)
     
    #define _UNIX_TIMESTAMP(year, month, day, hour, minute, second)
     
    #define UNIX_TIMESTAMP   _UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__)
     
    #define UNIX_TIMESTAMP_UTC   (UNIX_TIMESTAMP + (PST_OFFSET*SEC_PER_HOUR))
     
    +

    Macro Definition Documentation

    + +

    ◆ __TIME_DAYS__

    + +
    +
    + + + + +
    #define __TIME_DAYS__   CONV_STR2DEC_2(__DATE__, 4)
    +
    + +
    +
    + +

    ◆ __TIME_HOURS__

    + +
    +
    + + + + +
    #define __TIME_HOURS__   CONV_STR2DEC_2(__TIME__, 0)
    +
    + +
    +
    + +

    ◆ __TIME_MINUTES__

    + +
    +
    + + + + +
    #define __TIME_MINUTES__   CONV_STR2DEC_2(__TIME__, 3)
    +
    + +
    +
    + +

    ◆ __TIME_MONTH__

    + +
    +
    + + + + +
    #define __TIME_MONTH__   GET_MONTH(__DATE__, 0)
    +
    + +
    +
    + +

    ◆ __TIME_SECONDS__

    + +
    +
    + + + + +
    #define __TIME_SECONDS__   CONV_STR2DEC_2(__TIME__, 6)
    +
    + +
    +
    + +

    ◆ __TIME_YEARS__

    + +
    +
    + + + + +
    #define __TIME_YEARS__   CONV_STR2DEC_4(__DATE__, 7)
    +
    + +
    +
    + +

    ◆ _UNIX_TIMESTAMP

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #define _UNIX_TIMESTAMP( year,
     month,
     day,
     hour,
     minute,
     second 
    )
    +
    +Value:
    ( /* time */ second \
    + minute * SEC_PER_MIN \
    + hour * SEC_PER_HOUR \
    + /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \
    + /* year */ (year - 1970UL) * SEC_PER_YEAR \
    + ((year - 1969UL) / 4UL) * SEC_PER_DAY \
    - ((year - 1901UL) / 100UL) * SEC_PER_DAY \
    + ((year - 1601UL) / 400UL) * SEC_PER_DAY \
    )
    #define SEC_PER_MIN
    Definition: time_macros.h:28
    +
    #define _UNIX_TIMESTAMP_YDAY(year, month, day)
    Definition: time_macros.h:69
    +
    #define SEC_PER_HOUR
    Definition: time_macros.h:29
    +
    #define SEC_PER_DAY
    Definition: time_macros.h:30
    +
    #define SEC_PER_YEAR
    Definition: time_macros.h:31
    +
    +
    +
    + +

    ◆ _UNIX_TIMESTAMP_FDAY

    + +
    +
    + + + + + + + + +
    #define _UNIX_TIMESTAMP_FDAY( year)
    +
    +Value:
    (((year) % 400) == 0UL ? 29UL : \
    (((year) % 100) == 0UL ? 28UL : \
    (((year) % 4) == 0UL ? 29UL : \
    28UL)))
    +
    +
    + +

    ◆ _UNIX_TIMESTAMP_YDAY

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    #define _UNIX_TIMESTAMP_YDAY( year,
     month,
     day 
    )
    +
    +Value:
    ( \
    /* January */ day \
    /* February */ + (month >= 2 ? 31UL : 0UL) \
    /* March */ + (month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \
    /* April */ + (month >= 4 ? 31UL : 0UL) \
    /* May */ + (month >= 5 ? 30UL : 0UL) \
    /* June */ + (month >= 6 ? 31UL : 0UL) \
    /* July */ + (month >= 7 ? 30UL : 0UL) \
    /* August */ + (month >= 8 ? 31UL : 0UL) \
    /* September */+ (month >= 9 ? 31UL : 0UL) \
    /* October */ + (month >= 10 ? 30UL : 0UL) \
    /* November */ + (month >= 11 ? 31UL : 0UL) \
    /* December */ + (month >= 12 ? 30UL : 0UL) \
    )
    #define _UNIX_TIMESTAMP_FDAY(year)
    Definition: time_macros.h:62
    +
    +
    +
    + +

    ◆ CONV_STR2DEC_1

    + +
    +
    + + + + + + + + + + + + + + + + + + +
    #define CONV_STR2DEC_1( str,
     
    )   (str[i]>'0'?str[i]-'0':0)
    +
    + +
    +
    + +

    ◆ CONV_STR2DEC_2

    + +
    +
    + + + + + + + + + + + + + + + + + + +
    #define CONV_STR2DEC_2( str,
     
    )   (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
    +
    + +
    +
    + +

    ◆ CONV_STR2DEC_3

    + +
    +
    + + + + + + + + + + + + + + + + + + +
    #define CONV_STR2DEC_3( str,
     
    )   (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
    +
    + +
    +
    + +

    ◆ CONV_STR2DEC_4

    + +
    +
    + + + + + + + + + + + + + + + + + + +
    #define CONV_STR2DEC_4( str,
     
    )   (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
    +
    + +
    +
    + +

    ◆ GET_MONTH

    + +
    +
    + + + + + + + + + + + + + + + + + + +
    #define GET_MONTH( str,
     
    )
    +
    +Value:
    (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \
    str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \
    str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \
    str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \
    str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \
    str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \
    str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \
    str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \
    str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \
    str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \
    str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \
    str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
    +
    +
    + +

    ◆ PST_OFFSET

    + +
    +
    + + + + +
    #define PST_OFFSET   (8UL)
    +
    + +
    +
    + +

    ◆ SEC_PER_DAY

    + +
    +
    + + + + +
    #define SEC_PER_DAY   (86400UL)
    +
    + +
    +
    + +

    ◆ SEC_PER_HOUR

    + +
    +
    + + + + +
    #define SEC_PER_HOUR   (3600UL)
    +
    + +
    +
    + +

    ◆ SEC_PER_MIN

    + +
    +
    + + + + +
    #define SEC_PER_MIN   (60UL)
    +
    + +
    +
    + +

    ◆ SEC_PER_YEAR

    + +
    +
    + + + + +
    #define SEC_PER_YEAR   (SEC_PER_DAY*365)
    +
    + +
    +
    + +

    ◆ UNIX_TIMESTAMP

    + + + +

    ◆ UNIX_TIMESTAMP_UTC

    + +
    +
    + + + + +
    #define UNIX_TIMESTAMP_UTC   (UNIX_TIMESTAMP + (PST_OFFSET*SEC_PER_HOUR))
    +
    + +
    +
    +
    +
    + + + + diff --git a/docs/html/time__macros_8h.js b/docs/html/time__macros_8h.js new file mode 100644 index 0000000..e03251c --- /dev/null +++ b/docs/html/time__macros_8h.js @@ -0,0 +1,24 @@ +var time__macros_8h = +[ + [ "__TIME_DAYS__", "time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf", null ], + [ "__TIME_HOURS__", "time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4", null ], + [ "__TIME_MINUTES__", "time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8", null ], + [ "__TIME_MONTH__", "time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1", null ], + [ "__TIME_SECONDS__", "time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97", null ], + [ "__TIME_YEARS__", "time__macros_8h.html#a56482fcc86a55713dee595c2092ed376", null ], + [ "_UNIX_TIMESTAMP", "time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3", null ], + [ "_UNIX_TIMESTAMP_FDAY", "time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79", null ], + [ "_UNIX_TIMESTAMP_YDAY", "time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97", null ], + [ "CONV_STR2DEC_1", "time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a", null ], + [ "CONV_STR2DEC_2", "time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3", null ], + [ "CONV_STR2DEC_3", "time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4", null ], + [ "CONV_STR2DEC_4", "time__macros_8h.html#a9da779a8ca64782ea49babce14122d34", null ], + [ "GET_MONTH", "time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994", null ], + [ "PST_OFFSET", "time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb", null ], + [ "SEC_PER_DAY", "time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2", null ], + [ "SEC_PER_HOUR", "time__macros_8h.html#a2d540510d5860d7f190d13124956bc57", null ], + [ "SEC_PER_MIN", "time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76", null ], + [ "SEC_PER_YEAR", "time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9", null ], + [ "UNIX_TIMESTAMP", "time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487", null ], + [ "UNIX_TIMESTAMP_UTC", "time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3", null ] +]; \ No newline at end of file diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html new file mode 100644 index 0000000..653873a --- /dev/null +++ b/docs/html/time__macros_8h_source.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/time_macros.h Source File + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    time_macros.h
    +
    +
    +Go to the documentation of this file.
    1 /*
    2  *
    3  * Created: 29.03.2018
    4  *
    5  * Authors:
    6  *
    7  * Assembled from the code released on Stackoverflow by:
    8  * Dennis (instructable.com/member/nqtronix) | https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string
    9  * and
    10  * Alexis Wilke | https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date
    11  *
    12  * Assembled by Jean Rabault
    13  *
    14  * UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of compilation from macros using the compiler defined __TIME__ macro.
    15  * This should include Gregorian calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps.
    16  *
    17  * Careful: __TIME__ is the local time of the computer, NOT the UTC time in general!
    18  *
    19  */
    20 
    21 #ifndef COMPILE_TIME_H_
    22 #define COMPILE_TIME_H_
    23 
    24 // add offset for pacific standard time
    25 #define PST_OFFSET (8UL)
    26 
    27 // Some definitions for calculation
    28 #define SEC_PER_MIN (60UL)
    29 #define SEC_PER_HOUR (3600UL)
    30 #define SEC_PER_DAY (86400UL)
    31 #define SEC_PER_YEAR (SEC_PER_DAY*365)
    32 
    33 // extracts 1..4 characters from a string and interprets it as a decimal value
    34 #define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0)
    35 #define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
    36 #define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
    37 #define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
    38 
    39 // Custom "glue logic" to convert the month name to a usable number
    40 #define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \
    41  str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \
    42  str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \
    43  str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \
    44  str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \
    45  str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \
    46  str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \
    47  str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \
    48  str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \
    49  str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \
    50  str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \
    51  str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
    52 
    53 // extract the information from the time string given by __TIME__ and __DATE__
    54 #define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6)
    55 #define __TIME_MINUTES__ CONV_STR2DEC_2(__TIME__, 3)
    56 #define __TIME_HOURS__ CONV_STR2DEC_2(__TIME__, 0)
    57 #define __TIME_DAYS__ CONV_STR2DEC_2(__DATE__, 4)
    58 #define __TIME_MONTH__ GET_MONTH(__DATE__, 0)
    59 #define __TIME_YEARS__ CONV_STR2DEC_4(__DATE__, 7)
    60 
    61 // Days in February
    62 #define _UNIX_TIMESTAMP_FDAY(year) \
    63  (((year) % 400) == 0UL ? 29UL : \
    64  (((year) % 100) == 0UL ? 28UL : \
    65  (((year) % 4) == 0UL ? 29UL : \
    66  28UL)))
    67 
    68 // Days in the year
    69 #define _UNIX_TIMESTAMP_YDAY(year, month, day) \
    70  ( \
    71  /* January */ day \
    72  /* February */ + (month >= 2 ? 31UL : 0UL) \
    73  /* March */ + (month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \
    74  /* April */ + (month >= 4 ? 31UL : 0UL) \
    75  /* May */ + (month >= 5 ? 30UL : 0UL) \
    76  /* June */ + (month >= 6 ? 31UL : 0UL) \
    77  /* July */ + (month >= 7 ? 30UL : 0UL) \
    78  /* August */ + (month >= 8 ? 31UL : 0UL) \
    79  /* September */+ (month >= 9 ? 31UL : 0UL) \
    80  /* October */ + (month >= 10 ? 30UL : 0UL) \
    81  /* November */ + (month >= 11 ? 31UL : 0UL) \
    82  /* December */ + (month >= 12 ? 30UL : 0UL) \
    83  )
    84 
    85 // get the UNIX timestamp from a digits representation
    86 #define _UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
    87  ( /* time */ second \
    88  + minute * SEC_PER_MIN \
    89  + hour * SEC_PER_HOUR \
    90  + /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \
    91  + /* year */ (year - 1970UL) * SEC_PER_YEAR \
    92  + ((year - 1969UL) / 4UL) * SEC_PER_DAY \
    93  - ((year - 1901UL) / 100UL) * SEC_PER_DAY \
    94  + ((year - 1601UL) / 400UL) * SEC_PER_DAY \
    95  )
    96 
    97 // the UNIX timestamp
    98 #define UNIX_TIMESTAMP _UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__)
    99 #define UNIX_TIMESTAMP_UTC (UNIX_TIMESTAMP + (PST_OFFSET*SEC_PER_HOUR))
    100 
    101 #endif
    +
    + + + + diff --git a/src/Client.h b/src/Client.h deleted file mode 100644 index b8e5d93..0000000 --- a/src/Client.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - Client.h - Base class that provides Client - Copyright (c) 2011 Adrian McEwen. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef client_h -#define client_h -#include "Print.h" -#include "Stream.h" -#include "IPAddress.h" - -class Client : public Stream { - -public: - virtual int connect(IPAddress ip, uint16_t port) =0; - virtual int connect(const char *host, uint16_t port) =0; - virtual size_t write(uint8_t) =0; - virtual size_t write(const uint8_t *buf, size_t size) =0; - virtual int available() = 0; - virtual int read() = 0; - virtual int read(uint8_t *buf, size_t size) = 0; - virtual int peek() = 0; - virtual void flush() = 0; - virtual void stop() = 0; - virtual uint8_t connected() = 0; - virtual operator bool() = 0; -protected: - uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; -}; - -#endif diff --git a/src/SSLClient.h b/src/SSLClient.h index 6c06c8c..3dd88d2 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -66,7 +66,7 @@ public: * of the SSL server certificate. Check out TrustAnchors.md for more info. * @param trust_anchors_num The number of objects in the trust_anchors array. * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG. - * @param debug whether to enable or disable debug logging. + * @param debug The level of debug logging (use the ::DebugLevel enum). */ explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN) : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) @@ -290,7 +290,7 @@ public: * The implementation for this function can be found at SSLClientImpl::get_session_impl. * * @param host A hostname c string, or NULL if one is not available - * @param ip An IP address + * @param addr An IP address * @returns A reference to an SSLSession object */ virtual SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); } @@ -301,7 +301,7 @@ public: * The implementation for this function can be found at SSLClientImpl::remove_session_impl. * * @param host A hostname c string, or NULL if one is not available - * @param ip An IP address + * @param addr An IP address */ virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); } @@ -316,15 +316,15 @@ public: * @returns true if connected, false if not */ virtual operator bool() { return connected() > 0; } - /** {@link SSLClient::bool()} */ + /** @see SSLClient::operator bool */ virtual bool operator==(const bool value) { return bool() == value; } - /** {@link SSLClient::bool()} */ + /** @see SSLClient::operator bool */ virtual bool operator!=(const bool value) { return bool() != value; } /** @brief Returns whether or not two SSLClient objects have the same underlying client object */ virtual bool operator==(const C& rhs) { return m_client == rhs; } /** @brief Returns whether or not two SSLClient objects do not have the same underlying client object */ virtual bool operator!=(const C& rhs) { return m_client != rhs; } - /** @brief Returns the local port, if the Client class has a localPort() function. Else return 0. */ + /** @brief Returns the local port, C::localPort exists. Else return 0. */ virtual uint16_t localPort() { if (std::is_member_function_pointer::value) return m_client.localPort(); else { @@ -332,7 +332,7 @@ public: return 0; } } - /** @brief Returns the remote IP, if the Client class has a remoteIP() function. Else return INADDR_NONE. */ + /** @brief Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE. */ virtual IPAddress remoteIP() { if (std::is_member_function_pointer::value) return m_client.remoteIP(); else { @@ -340,7 +340,7 @@ public: return INADDR_NONE; } } - /** @brief Returns the remote port, if the Client class has a remotePort() function. Else return 0. */ + /** @brief Returns the remote port, if C::remotePort exists. Else return 0. */ virtual uint16_t remotePort() { if (std::is_member_function_pointer::value) return m_client.remotePort(); else { diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 096665c..76a31ec 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -49,7 +49,7 @@ static int freeMemory() { #endif // __arm__ } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) : m_trust_anchors(trust_anchors) @@ -126,7 +126,7 @@ int SSLClientImpl::connect_impl(const char *host, uint16_t port) { return m_start_ssl(host, ses); } -/** see SSLClientImpl.h*/ +/* see SSLClientImpl.h*/ size_t SSLClientImpl::write_impl(const uint8_t *buf, size_t size) { const char* func_name = __func__; // check if the socket is still open and such @@ -169,7 +169,7 @@ size_t SSLClientImpl::write_impl(const uint8_t *buf, size_t size) { return size; } -/** see SSLClientImpl.h*/ +/* see SSLClientImpl.h*/ int SSLClientImpl::available_impl() { const char* func_name = __func__; // connection check @@ -190,7 +190,7 @@ int SSLClientImpl::available_impl() { return 0; } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ int SSLClientImpl::read_impl(uint8_t *buf, size_t size) { // check that the engine is ready to read if (available_impl() <= 0) return -1; @@ -205,7 +205,7 @@ int SSLClientImpl::read_impl(uint8_t *buf, size_t size) { return read_amount; } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ int SSLClientImpl::peek_impl() { // check that the engine is ready to read if (available_impl() <= 0) return -1; @@ -217,7 +217,7 @@ int SSLClientImpl::peek_impl() { return (int)read_num; } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ void SSLClientImpl::flush_impl() { // trigger a flush, incase there's any leftover data br_ssl_engine_flush(&m_sslctx.eng, 0); @@ -225,7 +225,7 @@ void SSLClientImpl::flush_impl() { if(m_run_until(BR_SSL_RECVAPP) < 0) m_error("Could not flush write buffer!", __func__); } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ void SSLClientImpl::stop_impl() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); @@ -246,7 +246,7 @@ void SSLClientImpl::stop_impl() { get_arduino_client().stop(); } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ uint8_t SSLClientImpl::connected_impl() { const char* func_name = __func__; // check all of the error cases @@ -272,7 +272,7 @@ uint8_t SSLClientImpl::connected_impl() { return c_con && br_con && wr_ok; } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ SSLSession& SSLClientImpl::get_session_impl(const char* host, const IPAddress& addr) { const char* func_name = __func__; // search for a matching session with the IP @@ -291,7 +291,7 @@ SSLSession& SSLClientImpl::get_session_impl(const char* host, const IPAddress& a return get_session_array()[temp_index]; } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ void SSLClientImpl::remove_session_impl(const char* host, const IPAddress& addr) { const char* func_name = __func__; int temp_index = m_get_session_index(host, addr); @@ -319,7 +319,7 @@ bool SSLClientImpl::m_soft_connected(const char* func_name) { return true; } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { const char* func_name = __func__; // clear the write error @@ -366,7 +366,7 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { return 1; } -/** see SSLClientImpl.h*/ +/* see SSLClientImpl.h*/ int SSLClientImpl::m_run_until(const unsigned target) { const char* func_name = __func__; unsigned lastState = 0; @@ -452,7 +452,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { } } -/** see SSLClientImpl.h*/ +/* see SSLClientImpl.h*/ unsigned SSLClientImpl::m_update_engine() { const char* func_name = __func__; for(;;) { @@ -605,7 +605,7 @@ unsigned SSLClientImpl::m_update_engine() { } } -/** see SSLClientImpl.h */ +/* see SSLClientImpl.h */ int SSLClientImpl::m_get_session_index(const char* host, const IPAddress& addr) const { const char* func_name = __func__; // search for a matching session with the IP @@ -627,7 +627,7 @@ int SSLClientImpl::m_get_session_index(const char* host, const IPAddress& addr) return -1; } -/** See SSLClientImpl.h */ +/* See SSLClientImpl.h */ void SSLClientImpl::m_print_prefix(const char* func_name, const DebugLevel level) const { // print the sslclient prefix @@ -645,7 +645,7 @@ void SSLClientImpl::m_print_prefix(const char* func_name, const DebugLevel level Serial.print("): "); } -/** See SSLClientImpl.h */ +/* See SSLClientImpl.h */ void SSLClientImpl::m_print_ssl_error(const int ssl_error, const DebugLevel level) const { if (level > m_debug) return; m_print_prefix(__func__, level); From b36f9ca5dc60da27da8773a983f18531d88d3a33 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 31 Mar 2019 16:39:10 -0700 Subject: [PATCH 039/205] Updated documentation for comprehension, readability --- TrustAnchors.md | 2 +- src/SSLClient.h | 30 ++++++++++++++++++------------ src/SSLSession.h | 11 ++++++----- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/TrustAnchors.md b/TrustAnchors.md index 851e626..a04e4cb 100644 --- a/TrustAnchors.md +++ b/TrustAnchors.md @@ -40,7 +40,7 @@ A full example of a trust anchor header can be found in [this file](./readme/cer ### HTTPS -For HTTPS, there a couple of tools you can use. Ordered from easy to hard: +For HTTPS, there a couple of tools you can use. Ordered from easiest to hardest: * [This website, written to simplify the creation of trust anchor headers](https://openslab-osu.github.io/bearssl-certificate-utility/). Simply plug and play. * [pycert_bearssl](./tools/pycert_bearssl/pycert_bearssl.py), a command line utility based on a [pycert](https://learn.adafruit.com/introducing-the-adafruit-wiced-feather-wifi/pycert-dot-py). You will need to install Python 3, and follow the instructions in the [pycert_bearssl.py file](./tools/pycert_bearssl/pycert_bearssl.py). You'll want to use the `pycert_bearssl.py download` command once the utility is set up. * The brssl command line utility, included in the [BearSSL source](https://bearssl.org/gitweb/?p=BearSSL;a=blob_plain;f=tools/brssl.h;hb=HEAD). You will need to compile this file yourself. diff --git a/src/SSLClient.h b/src/SSLClient.h index 3dd88d2..0a08d34 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -88,11 +88,11 @@ public: * SSLClient::connect(host, port) should be preferred over this function, * as verifying the domain name is a step in ensuring the certificate is * legitimate, which is important to the security of the device. Additionally, - * SSL sessions cannot be resumed, which can drastically increase initial + * SSL sessions cannot be resumed when using this function, which can drastically increase initial * connect time. * * This function initializes the socket by calling m_client::connect(IPAddress, uint16_t) - * with the parameters supplied, then once the socket uses BearSSL to + * with the parameters supplied, then once the socket is open, uses BearSSL to * to complete a SSL handshake. Due to the design of the SSL standard, * this function will probably take an extended period (1-4sec) to negotiate * the handshake and finish the connection. This function runs until the SSL @@ -127,8 +127,8 @@ public: * @brief Connect over SSL to a host specified by a hostname. * * This function initializes the socket by calling m_client::connect(const char*, uint16_t) - * with the parameters supplied, then once the socket is open uses BearSSL to - * to complete a SSL handshake. This function runs until the SSL handshake + * with the parameters supplied, then once the socket is open, uses BearSSL to + * complete a SSL handshake. This function runs until the SSL handshake * succeeds or fails. * * SSL requires the client to generate some random bits (to be later combined @@ -189,7 +189,7 @@ public: virtual size_t write(const uint8_t *buf, size_t size) { return write_impl(buf, size); } /** - * @brief Returns the number of bytes availible to read from the SSL Socket + * @brief Returns the number of bytes available to read from the data that has been received and decrypted. * * This function updates the state of the SSL engine (including writing any data, * see SSLClient::write) and as a result should be called periodically when expecting data. @@ -214,7 +214,7 @@ public: */ virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; }; /** - * @brief Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. + * @brief Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. * * This function checks if bytes are ready to be read by calling SSLClient::available, * and if so copies size number of bytes from the IO buffer into the buf pointer. @@ -237,7 +237,8 @@ public: virtual int read(uint8_t *buf, size_t size) { return read_impl(buf, size); } /** - * @brief view the first byte of the buffer, without removing it from the SSLClient Buffer + * @brief View the first byte of the buffer, without removing it from the SSLClient Buffer + * * The implementation for this function can be found in SSLClientImpl::peek * @pre SSLClient::available must be >0 * @returns The first byte received, or -1 if the preconditions are not satisfied (warning: @@ -247,6 +248,7 @@ public: /** * @brief Force writing the buffered bytes from SSLClient::write to the network. + * * This function is blocking until all bytes from the buffer are written. For * an explanation of how writing with SSLClient works, please see SSLClient::write. * The implementation for this function can be found in SSLClientImpl::flush. @@ -255,6 +257,7 @@ public: /** * @brief Close the connection + * * If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to * close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an * error was encountered previously, this function will simply call m_client::stop. @@ -264,6 +267,7 @@ public: /** * @brief Check if the device is connected. + * * Use this function to determine if SSLClient is still connected and a SSL connection is active. * It should be noted that SSLClient::available should be preferred over this function for rapid * polling--both functions send and receive data with the SSLClient::m_client device, however SSLClient::available @@ -280,7 +284,7 @@ public: //======================================== /** - * @brief Get a session reference corresponding to a host and IP, or a reference to a empty session if none exist + * @brief Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist * * If no session corresponding to the host and IP exist, then this function will cycle through * sessions in a rotating order. This allows the session cache to continually store sessions, @@ -307,12 +311,14 @@ public: /** * @brief Get the maximum number of SSL sessions that can be stored at once - * @returns The SessionCache template parameter. + * + * @returns The SessionCache template parameter. */ virtual size_t getSessionCount() const { return SessionCache; } /** * @brief Equivalent to SSLClient::connected() > 0 + * * @returns true if connected, false if not */ virtual operator bool() { return connected() > 0; } @@ -349,14 +355,14 @@ public: } } - /** @brief returns a reference to the client object stored in this class. Take care not to break it. */ + /** @brief Returns a reference to the client object stored in this class. Take care not to break it. */ C& getClient() { return m_client; } protected: - /** @brief return an instance of m_client that is polymorphic and can be used by SSLClientImpl */ + /** @brief Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl */ virtual Client& get_arduino_client() { return m_client; } virtual const Client& get_arduino_client() const { return m_client; } - /** @brief return an instance of the session array that is on the stack */ + /** @brief Returns an instance of the session array that is on the stack */ virtual SSLSession* get_session_array() { return m_sessions; } virtual const SSLSession* get_session_array() const { return m_sessions; } diff --git a/src/SSLSession.h b/src/SSLSession.h index 716b4c8..b6ca188 100644 --- a/src/SSLSession.h +++ b/src/SSLSession.h @@ -70,7 +70,7 @@ public: * * @returns A String object or "" if there is no hostname * @pre must check isValidSession before getting this value, - * as if this session in invalid this value is not guarented + * as if this session in invalid this value is not guarenteed * to be reset to "". */ const String& get_hostname() const { return m_hostname; } @@ -80,7 +80,7 @@ public: * * @returns A ::IPAddress object, #INADDR_NONE if there is no IP * @pre must check isValidSession before getting this value, - * as if this session in invalid this value is not guarented + * as if this session in invalid this value is not guarenteed * to be reset to #INADDR_NONE. */ const IPAddress& get_ip() const { return m_ip; } @@ -98,7 +98,7 @@ public: * @pre You must call * ::br_ssl_engine_get_session_parameters * with this session before calling this function. This is because - * there is no way to completly validate the ::br_ssl_session_parameters + * there is no way to completely validate the ::br_ssl_session_parameters * and the session may end up in a corrupted state if this is not observed. * * @param ip The IP address of the host associated with the session @@ -109,14 +109,15 @@ public: void set_parameters(const IPAddress& ip, const char* hostname = NULL); /** - * @brief delete the parameters and invalidate the session + * @brief Delete the parameters and invalidate the session. + * * Roughly equivalent to this_session = SSLSession(), however * this function preserves the String object, allowing it * to better handle the dynamic memory needed. */ void clear_parameters(); - /** @brief returns a pointer to the ::br_ssl_session_parameters component of this class */ + /** @brief Returns a pointer to the ::br_ssl_session_parameters component of this class. */ br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; } private: From 431df02b5bf120b80ef0fca30736888048bd56d3 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 31 Mar 2019 16:42:28 -0700 Subject: [PATCH 040/205] regenerated documentation --- README.md | 25 ++- docs/html/_s_s_l_client_8h.html | 2 +- docs/html/_s_s_l_client_8h_source.html | 44 +++--- docs/html/_s_s_l_client_impl_8h.html | 14 +- docs/html/_s_s_l_session_8h.html | 2 +- docs/html/_s_s_l_session_8h_source.html | 6 +- docs/html/annotated.html | 6 +- docs/html/class_s_s_l_client.html | 101 ++++++------ docs/html/class_s_s_l_client_impl.html | 36 ++--- docs/html/class_s_s_l_session.html | 21 +-- docs/html/functions_vars.html | 145 ++++++++++++++++++ docs/html/hierarchy.html | 6 +- docs/html/index.html | 69 ++++++++- ...ibraries__s_s_l_client__trust_anchors.html | 8 +- docs/html/navtreedata.js | 2 +- docs/html/navtreeindex0.js | 2 +- docs/html/pages.html | 3 +- docs/html/search/all_e.js | 2 +- docs/html/search/pages_0.js | 2 +- docs/html/search/variables_1.html | 30 ++++ docs/html/search/variables_1.js | 17 ++ src/SSLClient.h | 2 +- src/SSLClientImpl.h | 18 +-- 23 files changed, 416 insertions(+), 147 deletions(-) create mode 100644 docs/html/functions_vars.html create mode 100644 docs/html/search/variables_1.html create mode 100644 docs/html/search/variables_1.js diff --git a/README.md b/README.md index c172b38..8cb8650 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ For more information on SSLClient, check out the [examples](./examples), [API do SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](https://bearssl.org/) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, making debugging a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint. -Additionally, the bulk of SSLClient is split into two components: a template class [SSLClient](./src/SSLClient.h), and an implementation class [SSLClientImpl](./src/SSLClientImpl.h). The template class serves to abstract some functions not implemented in the Arduino Client interface (such as `EthernetClient::remoteIP`), and the implementation class is the rest of the SSLClient library. +Additionally, the bulk of SSLClient is split into two components: a template class [SSLClient](./src/SSLClient.h), and an implementation class [SSLClientImpl](./src/SSLClientImpl.h). The template class serves to abstract some functions not implemented in the Arduino Client interface (such as EthernetClient::remoteIP), and the implementation class is the rest of the SSLClient library. ## Other Features @@ -60,13 +60,13 @@ SSLClient also allows for changing the debugging level by adding an additional p ```C++ SSLClient client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO); ``` -Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in [Error](./src/SSLClientImpl.h). The log level is set to `SSL_WARN` by default. +Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in ::DebugLevel. The log level is set to `SSL_WARN` by default. ### Errors -When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from `SSLClient::getWriteError()`, which will return a value from [this enumeration](link-me). For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at `SSL_ERROR` or lower. +When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from SSLClient::getWriteError(), which will return a value from the ::Error enum. For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at `SSL_ERROR` or lower. ### Write Buffering -As you may have noticed in the documentation for [SSLClient::write](link-me), calling this function does not actually write to the network. Instead, you must call [SSLClient::available](link-me) or [SSLClient::flush](link-me), which will detect that the buffer is ready and write to the network (see [SSLClient::write](link-me) for details). +As you may have noticed in the documentation for SSLClient::write, calling this function does not actually write to the network. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready and write to the network (see SSLClient::write for details). This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so: ```C++ @@ -112,14 +112,25 @@ In order to use SSL session resumption: SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with `"www.google.com"`. However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection. -You can test whether or not a website can resume SSL Sessions using the [Session Example](./examples/Session_Example/Session_Example.ino) included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume. +You can test whether or not a website can resume SSL Sessions using the [Session Example](./examples/Session_Example/Session_Example.ino) included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume. + +SSL sessions take a lot of memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration: +```C++ +SSLClient client(EthernetClient(), TAs, 2, A7); +``` +Where `SomeNumber` is the number of sessions you would like to store. For example this declaration can store 3 sessions: +```C++ +SSLClient client(EthernetClient(), TAs, 2, A7); +``` +Sessions are managed internally using the SSLSession::getSession function. This function will cycle through sessions in a rotating order, allowing the session cache to continually overwrite old sessions. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to. + +If you need to clear a session, you can do so using the SSLSession::removeSession function. ## Implementation Gotchas Some ideas that didn't quite fit in the API documentation. ### Certificate Verification - SSLClient uses BearSSL's [minimal x509 verification engine](https://bearssl.org/x509.html#the-minimal-engine) to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out [this document](./TrustAnchors.md) for more details on this component of SSLClient. BearSSL also features a [known certificate validation engine](https://bearssl.org/x509.html#the-known-key-engine), which only allows for a single domain in exchange for a significantly reduced resource usage (flash and CPU time). This functionality is planned to be implemented in the future. @@ -141,7 +152,7 @@ In order to remedy this problem, the device must be able to read the data faster * If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM. ### Cipher Support -By default, SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile) under `suites[]`, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: +By default, SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile.c) under `suites[]`, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: ```C++ br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // comment the above line and uncomment the line below if you're having trouble connecting over SSL diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index 8112e78..17512cf 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -104,7 +104,7 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h.html','');});

    Classes

    class  SSLClient< C, SessionCache > - The main SSLClient class Check out README.md for more info. More...
    + The main SSLClient class. Check out README.md for more info. More...
      - +

    diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index 3788ec1..b5a6df8 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -91,50 +91,50 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
    SSLClient.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include <type_traits>
    22 #include "Client.h"
    23 #include "SSLClientImpl.h"
    24 #include "SSLSession.h"
    25 
    26 #ifndef SSLClient_H_
    27 #define SSLClient_H_
    28 
    34 template <class C, size_t SessionCache = 1>
    35 class SSLClient : public SSLClientImpl {
    36 /*
    37  * static checks
    38  * I'm a java developer, so I want to ensure that my inheritance is safe.
    39  * These checks ensure that all the functions we use on class C are
    40  * actually present on class C. It does this by checking that the
    41  * class inherits from Client.
    42  *
    43  * Additionally, I ran into a lot of memory issues with large sessions caches.
    44  * Since each session contains at max 352 bytes of memory, they eat of the
    45  * stack quite quickly and can cause overflows. As a result, I have added a
    46  * warning here to discourage the use of more than 3 sessions at a time. Any
    47  * amount past that will require special modification of this library, and
    48  * assumes you know what you are doing.
    49  */
    50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
    51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
    52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
    53 
    54 public:
    71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
    72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
    73  , m_client(client)
    74  , m_sessions{SSLSession()}
    75  {
    76  // set the timeout to a reasonable number (it can always be changes later)
    77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
    78  setTimeout(10 * 1000);
    79  }
    80 
    81  //========================================
    82  //= Functions implemented in SSLClientImpl
    83  //========================================
    84 
    124  virtual int connect(IPAddress ip, uint16_t port) { return connect_impl(ip, port); }
    125 
    162  virtual int connect(const char *host, uint16_t port) { return connect_impl(host, port); }
    163 
    165  virtual size_t write(uint8_t b) { return write_impl(&b, 1); }
    189  virtual size_t write(const uint8_t *buf, size_t size) { return write_impl(buf, size); }
    190 
    209  virtual int available() { return available_impl(); }
    210 
    215  virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    237  virtual int read(uint8_t *buf, size_t size) { return read_impl(buf, size); }
    238 
    246  virtual int peek() { return peek_impl(); }
    247 
    254  virtual void flush() { return flush_impl(); }
    255 
    263  virtual void stop() { return stop_impl(); }
    264 
    276  virtual uint8_t connected() { return connected_impl(); }
    277 
    278  //========================================
    279  //= Functions Not in the Client Interface
    280  //========================================
    281 
    296  virtual SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
    297 
    306  virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
    307 
    312  virtual size_t getSessionCount() const { return SessionCache; }
    313 
    318  virtual operator bool() { return connected() > 0; }
    320  virtual bool operator==(const bool value) { return bool() == value; }
    322  virtual bool operator!=(const bool value) { return bool() != value; }
    324  virtual bool operator==(const C& rhs) { return m_client == rhs; }
    326  virtual bool operator!=(const C& rhs) { return m_client != rhs; }
    328  virtual uint16_t localPort() {
    329  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
    330  else {
    331  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
    332  return 0;
    333  }
    334  }
    336  virtual IPAddress remoteIP() {
    337  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
    338  else {
    339  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
    340  return INADDR_NONE;
    341  }
    342  }
    344  virtual uint16_t remotePort() {
    345  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
    346  else {
    347  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
    348  return 0;
    349  }
    350  }
    351 
    353  C& getClient() { return m_client; }
    354 
    355 protected:
    357  virtual Client& get_arduino_client() { return m_client; }
    358  virtual const Client& get_arduino_client() const { return m_client; }
    360  virtual SSLSession* get_session_array() { return m_sessions; }
    361  virtual const SSLSession* get_session_array() const { return m_sessions; }
    362 
    363 private:
    364  // create a copy of the client
    365  C m_client;
    366  // also store an array of SSLSessions, so we can resume communication with multiple websites
    367  SSLSession m_sessions[SessionCache];
    368 };
    369 
    370 #endif
    virtual uint8_t connected()
    Check if the device is connected. Use this function to determine if SSLClient is still connected and ...
    Definition: SSLClient.h:276
    -
    virtual bool operator!=(const bool value)
    Definition: SSLClient.h:322
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include <type_traits>
    22 #include "Client.h"
    23 #include "SSLClientImpl.h"
    24 #include "SSLSession.h"
    25 
    26 #ifndef SSLClient_H_
    27 #define SSLClient_H_
    28 
    34 template <class C, size_t SessionCache = 1>
    35 class SSLClient : public SSLClientImpl {
    36 /*
    37  * static checks
    38  * I'm a java developer, so I want to ensure that my inheritance is safe.
    39  * These checks ensure that all the functions we use on class C are
    40  * actually present on class C. It does this by checking that the
    41  * class inherits from Client.
    42  *
    43  * Additionally, I ran into a lot of memory issues with large sessions caches.
    44  * Since each session contains at max 352 bytes of memory, they eat of the
    45  * stack quite quickly and can cause overflows. As a result, I have added a
    46  * warning here to discourage the use of more than 3 sessions at a time. Any
    47  * amount past that will require special modification of this library, and
    48  * assumes you know what you are doing.
    49  */
    50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
    51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
    52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
    53 
    54 public:
    71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
    72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
    73  , m_client(client)
    74  , m_sessions{SSLSession()}
    75  {
    76  // set the timeout to a reasonable number (it can always be changes later)
    77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
    78  setTimeout(10 * 1000);
    79  }
    80 
    81  //========================================
    82  //= Functions implemented in SSLClientImpl
    83  //========================================
    84 
    124  virtual int connect(IPAddress ip, uint16_t port) { return connect_impl(ip, port); }
    125 
    162  virtual int connect(const char *host, uint16_t port) { return connect_impl(host, port); }
    163 
    165  virtual size_t write(uint8_t b) { return write_impl(&b, 1); }
    189  virtual size_t write(const uint8_t *buf, size_t size) { return write_impl(buf, size); }
    190 
    209  virtual int available() { return available_impl(); }
    210 
    215  virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    237  virtual int read(uint8_t *buf, size_t size) { return read_impl(buf, size); }
    238 
    247  virtual int peek() { return peek_impl(); }
    248 
    256  virtual void flush() { return flush_impl(); }
    257 
    266  virtual void stop() { return stop_impl(); }
    267 
    280  virtual uint8_t connected() { return connected_impl(); }
    281 
    282  //========================================
    283  //= Functions Not in the Client Interface
    284  //========================================
    285 
    300  virtual SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
    301 
    310  virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
    311 
    317  virtual size_t getSessionCount() const { return SessionCache; }
    318 
    324  virtual operator bool() { return connected() > 0; }
    326  virtual bool operator==(const bool value) { return bool() == value; }
    328  virtual bool operator!=(const bool value) { return bool() != value; }
    330  virtual bool operator==(const C& rhs) { return m_client == rhs; }
    332  virtual bool operator!=(const C& rhs) { return m_client != rhs; }
    334  virtual uint16_t localPort() {
    335  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
    336  else {
    337  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
    338  return 0;
    339  }
    340  }
    342  virtual IPAddress remoteIP() {
    343  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
    344  else {
    345  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
    346  return INADDR_NONE;
    347  }
    348  }
    350  virtual uint16_t remotePort() {
    351  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
    352  else {
    353  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
    354  return 0;
    355  }
    356  }
    357 
    359  C& getClient() { return m_client; }
    360 
    361 protected:
    363  virtual Client& get_arduino_client() { return m_client; }
    364  virtual const Client& get_arduino_client() const { return m_client; }
    366  virtual SSLSession* get_session_array() { return m_sessions; }
    367  virtual const SSLSession* get_session_array() const { return m_sessions; }
    368 
    369 private:
    370  // create a copy of the client
    371  C m_client;
    372  // also store an array of SSLSessions, so we can resume communication with multiple websites
    373  SSLSession m_sessions[SessionCache];
    374 };
    375 
    376 #endif
    virtual uint8_t connected()
    Check if the device is connected.
    Definition: SSLClient.h:280
    +
    virtual bool operator!=(const bool value)
    Definition: SSLClient.h:328
    size_t write_impl(const uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:130
    -
    virtual const SSLSession * get_session_array() const
    Definition: SSLClient.h:361
    -
    virtual uint16_t remotePort()
    Returns the remote port, if C::remotePort exists. Else return 0.
    Definition: SSLClient.h:344
    +
    virtual const SSLSession * get_session_array() const
    Definition: SSLClient.h:367
    +
    virtual uint16_t remotePort()
    Returns the remote port, if C::remotePort exists. Else return 0.
    Definition: SSLClient.h:350
    Definition: SSLClientImpl.h:65
    SSLSession & get_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:276
    -
    virtual int available()
    Returns the number of bytes availible to read from the SSL Socket.
    Definition: SSLClient.h:209
    +
    virtual int available()
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.h:209
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:52
    -
    virtual uint16_t localPort()
    Returns the local port, C::localPort exists. Else return 0.
    Definition: SSLClient.h:328
    -
    virtual IPAddress remoteIP()
    Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
    Definition: SSLClient.h:336
    -
    C & getClient()
    returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:353
    -
    virtual int peek()
    view the first byte of the buffer, without removing it from the SSLClient Buffer The implementation f...
    Definition: SSLClient.h:246
    +
    virtual uint16_t localPort()
    Returns the local port, C::localPort exists. Else return 0.
    Definition: SSLClient.h:334
    +
    virtual IPAddress remoteIP()
    Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
    Definition: SSLClient.h:342
    +
    C & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:359
    +
    virtual int peek()
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.h:247
    int peek_impl()
    Definition: SSLClientImpl.cpp:209
    -
    virtual SSLSession & getSession(const char *host, const IPAddress &addr)
    Get a session reference corresponding to a host and IP, or a reference to a empty session if none exi...
    Definition: SSLClient.h:296
    +
    virtual SSLSession & getSession(const char *host, const IPAddress &addr)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.h:300
    virtual size_t write(const uint8_t *buf, size_t size)
    Write some bytes to the SSL connection.
    Definition: SSLClient.h:189
    -
    The main SSLClient class Check out README.md for more info.
    Definition: SSLClient.h:35
    +
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.h:71
    -
    virtual void stop()
    Close the connection If the SSL session is still active, all incoming data is discarded and BearSSL w...
    Definition: SSLClient.h:263
    +
    virtual void stop()
    Close the connection.
    Definition: SSLClient.h:266
    int available_impl()
    Definition: SSLClientImpl.cpp:173
    int read_impl(uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:194
    void remove_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:295
    -
    virtual size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:312
    +
    virtual size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:317
    virtual int read()
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:215
    virtual size_t write(uint8_t b)
    Definition: SSLClient.h:165
    void m_warn(const T str, const char *func_name) const
    Definition: SSLClientImpl.h:153
    -
    virtual bool operator==(const bool value)
    Definition: SSLClient.h:320
    -
    virtual void flush()
    Force writing the buffered bytes from SSLClient::write to the network. This function is blocking unti...
    Definition: SSLClient.h:254
    -
    virtual const Client & get_arduino_client() const
    Definition: SSLClient.h:358
    +
    virtual bool operator==(const bool value)
    Definition: SSLClient.h:326
    +
    virtual void flush()
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.h:256
    +
    virtual const Client & get_arduino_client() const
    Definition: SSLClient.h:364
    virtual int connect(const char *host, uint16_t port)
    Connect over SSL to a host specified by a hostname.
    Definition: SSLClient.h:162
    -
    virtual SSLSession * get_session_array()
    return an instance of the session array that is on the stack
    Definition: SSLClient.h:360
    +
    virtual SSLSession * get_session_array()
    Returns an instance of the session array that is on the stack.
    Definition: SSLClient.h:366
    -
    virtual bool operator!=(const C &rhs)
    Returns whether or not two SSLClient objects do not have the same underlying client object.
    Definition: SSLClient.h:326
    -
    virtual void removeSession(const char *host, const IPAddress &addr)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.h:306
    +
    virtual bool operator!=(const C &rhs)
    Returns whether or not two SSLClient objects do not have the same underlying client object.
    Definition: SSLClient.h:332
    +
    virtual void removeSession(const char *host, const IPAddress &addr)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.h:310
    virtual int connect(IPAddress ip, uint16_t port)
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.h:124
    int connect_impl(IPAddress ip, uint16_t port)
    Definition: SSLClientImpl.cpp:74
    void stop_impl()
    Definition: SSLClientImpl.cpp:229
    void flush_impl()
    Definition: SSLClientImpl.cpp:221
    Implementation code to be inherited by SSLClient.
    Definition: SSLClientImpl.h:71
    -
    virtual int read(uint8_t *buf, size_t size)
    Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes re...
    Definition: SSLClient.h:237
    -
    virtual bool operator==(const C &rhs)
    Returns whether or not two SSLClient objects have the same underlying client object.
    Definition: SSLClient.h:324
    +
    virtual int read(uint8_t *buf, size_t size)
    Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
    Definition: SSLClient.h:237
    +
    virtual bool operator==(const C &rhs)
    Returns whether or not two SSLClient objects have the same underlying client object.
    Definition: SSLClient.h:330
    uint8_t connected_impl()
    Definition: SSLClientImpl.cpp:250
    -
    virtual Client & get_arduino_client()
    return an instance of m_client that is polymorphic and can be used by SSLClientImpl
    Definition: SSLClient.h:357
    +
    virtual Client & get_arduino_client()
    Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
    Definition: SSLClient.h:363
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClientImpl.h:59
    diff --git a/docs/html/_s_s_l_client_impl_8h.html b/docs/html/_s_s_l_client_impl_8h.html index c98b0d7..505dabd 100644 --- a/docs/html/_s_s_l_client_impl_8h.html +++ b/docs/html/_s_s_l_client_impl_8h.html @@ -104,7 +104,7 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h.html','');});

    Classes

    class  SSLClientImpl
     Implementation code to be inherited by SSLClient. More...
     Implementation code to be inherited by SSLClient. More...
     
    SSL_WARN = 2, SSL_INFO = 3 } - +

    @@ -127,7 +127,7 @@ Enumerations

     Level of verbosity used in logging for SSLClient. More...
     Level of verbosity used in logging for SSLClient. More...
     

    Enumeration Type Documentation

    @@ -143,8 +143,8 @@ Enumerations
    -

    Level of verbosity used in logging for SSLClient.

    -

    Use these values when initializing SSLClient to set how many logs you would like to see in the Serial monitor.

    +

    Level of verbosity used in logging for SSLClient.

    +

    Use these values when initializing SSLClient to set how many logs you would like to see in the Serial monitor.

    @@ -171,7 +171,7 @@ Enumerations

    Static constants defining the possible errors encountered.

    -

    If SSLClient encounters an error, it will generally output logs into the serial monitor. If you need a way of programmatically checking the errors, you can do so with SSLClient::getWriteError(), which will return one of these values.

    +

    If SSLClient encounters an error, it will generally output logs into the serial monitor. If you need a way of programmatically checking the errors, you can do so with SSLClient::getWriteError(), which will return one of these values.

    Enumerator
    SSL_NONE 

    No logging output

    - -
    Enumerator
    SSL_OK 
    SSL_CLIENT_CONNECT_FAIL 

    The underlying client failed to connect, probably not an issue with SSL

    @@ -182,9 +182,9 @@ Enumerations
    SSL_BR_WRITE_ERROR 

    An internal error occurred with BearSSL, check logs for diagnosis.

    SSL_INTERNAL_ERROR 

    An internal error occurred with SSLClient, and you probably need to submit an issue on Github.

    +
    SSL_INTERNAL_ERROR 

    An internal error occurred with SSLClient, and you probably need to submit an issue on Github.

    SSL_OUT_OF_MEMORY 

    SSLClient detected that there was not enough memory (>8000 bytes) to continue.

    +
    SSL_OUT_OF_MEMORY 

    SSLClient detected that there was not enough memory (>8000 bytes) to continue.

    diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index 4382701..9f37a1c 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -102,7 +102,7 @@ $(document).ready(function(){initNavTree('_s_s_l_session_8h.html','');});

    Classes

    class  SSLSession - This class stores values which allow SSLClient to save and resume SSL sessions. More...
    + This class stores values which allow SSLClient to save and resume SSL sessions. More...
     
    diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index 1bd7bf5..9cee101 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -91,10 +91,10 @@ $(document).ready(function(){initNavTree('_s_s_l_session_8h_source.html','');});
    SSLSession.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    28 #include "bearssl.h"
    29 #include "Arduino.h"
    30 #include "IPAddress.h"
    31 
    32 #ifndef SSLSession_H_
    33 #define SSLSession_H_
    34 
    52 class SSLSession : public br_ssl_session_parameters {
    53 
    54 public:
    60  explicit SSLSession()
    61  : m_valid_session(false)
    62  , m_hostname()
    63  , m_ip(INADDR_NONE) {}
    64 
    66  SSLSession& operator=(const SSLSession&) = delete;
    67 
    76  const String& get_hostname() const { return m_hostname; }
    77 
    86  const IPAddress& get_ip() const { return m_ip; }
    87 
    88  bool is_valid_session() const { return m_valid_session; }
    89 
    109  void set_parameters(const IPAddress& ip, const char* hostname = NULL);
    110 
    117  void clear_parameters();
    118 
    120  br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; }
    121 
    122 private:
    123  bool m_valid_session;
    124  // aparently a hostname has a max length of 256 chars. Go figure.
    125  String m_hostname;
    126  // store the IP Address we connected to
    127  IPAddress m_ip;
    128 };
    129 
    130 
    131 
    132 #endif /* SSLSession_H_ */
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:52
    -
    br_ssl_session_parameters * to_br_session()
    returns a pointer to the ::br_ssl_session_parameters component of this class
    Definition: SSLSession.h:120
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    28 #include "bearssl.h"
    29 #include "Arduino.h"
    30 #include "IPAddress.h"
    31 
    32 #ifndef SSLSession_H_
    33 #define SSLSession_H_
    34 
    52 class SSLSession : public br_ssl_session_parameters {
    53 
    54 public:
    60  explicit SSLSession()
    61  : m_valid_session(false)
    62  , m_hostname()
    63  , m_ip(INADDR_NONE) {}
    64 
    66  SSLSession& operator=(const SSLSession&) = delete;
    67 
    76  const String& get_hostname() const { return m_hostname; }
    77 
    86  const IPAddress& get_ip() const { return m_ip; }
    87 
    88  bool is_valid_session() const { return m_valid_session; }
    89 
    109  void set_parameters(const IPAddress& ip, const char* hostname = NULL);
    110 
    118  void clear_parameters();
    119 
    121  br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; }
    122 
    123 private:
    124  bool m_valid_session;
    125  // aparently a hostname has a max length of 256 chars. Go figure.
    126  String m_hostname;
    127  // store the IP Address we connected to
    128  IPAddress m_ip;
    129 };
    130 
    131 
    132 
    133 #endif /* SSLSession_H_ */
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:52
    +
    br_ssl_session_parameters * to_br_session()
    Returns a pointer to the ::br_ssl_session_parameters component of this class.
    Definition: SSLSession.h:121
    void set_parameters(const IPAddress &ip, const char *hostname=NULL)
    Set the ip address and hostname of the session.
    Definition: SSLSession.cpp:4
    -
    void clear_parameters()
    delete the parameters and invalidate the session Roughly equivalent to this_session = SSLSession(),...
    Definition: SSLSession.cpp:19
    +
    void clear_parameters()
    Delete the parameters and invalidate the session.
    Definition: SSLSession.cpp:19
    bool is_valid_session() const
    Definition: SSLSession.h:88
    SSLSession & operator=(const SSLSession &)=delete
    use clear_parameters or set_parameters instead
    const IPAddress & get_ip() const
    Get ::IPAddress associated with this session.
    Definition: SSLSession.h:86
    diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 45f5447..5f354c0 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -93,9 +93,9 @@ $(document).ready(function(){initNavTree('annotated.html','');});
    Here are the classes, structs, unions and interfaces with brief descriptions:
    - - - + + +
     CSSLClientThe main SSLClient class Check out README.md for more info
     CSSLClientImplImplementation code to be inherited by SSLClient
     CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
     CSSLClientThe main SSLClient class. Check out README.md for more info
     CSSLClientImplImplementation code to be inherited by SSLClient
     CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
    diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index abed69b..eadc3cf 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -96,7 +96,7 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');});
    -

    The main SSLClient class Check out README.md for more info. +

    The main SSLClient class. Check out README.md for more info. More...

    #include <SSLClient.h>

    @@ -113,7 +113,7 @@ Inheritance diagram for SSLClient< C, SessionCache >:

    Public Member Functions

     SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN) - Initialize SSLClient with all of the prerequisites needed. More...
    + Initialize SSLClient with all of the prerequisites needed. More...
      virtual int connect (IPAddress ip, uint16_t port)  Connect over SSL to a host specified by an IP address. More...
    @@ -127,28 +127,28 @@ Public Member Functions  Write some bytes to the SSL connection. More...
      virtual int available () - Returns the number of bytes availible to read from the SSL Socket. More...
    + Returns the number of bytes available to read from the data that has been received and decrypted. More...
      virtual int read ()  Read a single byte, or -1 if none is available. More...
      virtual int read (uint8_t *buf, size_t size) - Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read. More...
    + Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. More...
      virtual int peek () - view the first byte of the buffer, without removing it from the SSLClient Buffer The implementation for this function can be found in SSLClientImpl::peek More...
    + View the first byte of the buffer, without removing it from the SSLClient Buffer. More...
      virtual void flush () - Force writing the buffered bytes from SSLClient::write to the network. This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush. More...
    + Force writing the buffered bytes from SSLClient::write to the network. More...
      virtual void stop () - Close the connection If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an error was encountered previously, this function will simply call m_client::stop. The implementation for this function can be found in SSLClientImpl::peek. More...
    + Close the connection. More...
      virtual uint8_t connected () - Check if the device is connected. Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently. More...
    + Check if the device is connected. More...
      virtual SSLSessiongetSession (const char *host, const IPAddress &addr) - Get a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
    + Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
      virtual void removeSession (const char *host, const IPAddress &addr)  Clear the session corresponding to a host and IP. More...
    @@ -157,17 +157,17 @@ Public Member Functions  Get the maximum number of SSL sessions that can be stored at once. More...
      virtual operator bool () - Equivalent to SSLClient::connected() > 0. More...
    + Equivalent to SSLClient::connected() > 0. More...
      virtual bool operator== (const bool value)   virtual bool operator!= (const bool value)   virtual bool operator== (const C &rhs) - Returns whether or not two SSLClient objects have the same underlying client object. More...
    + Returns whether or not two SSLClient objects have the same underlying client object. More...
      virtual bool operator!= (const C &rhs) - Returns whether or not two SSLClient objects do not have the same underlying client object. More...
    + Returns whether or not two SSLClient objects do not have the same underlying client object. More...
      virtual uint16_t localPort ()  Returns the local port, C::localPort exists. Else return 0. More...
    @@ -179,7 +179,7 @@ Public Member Functions  Returns the remote port, if C::remotePort exists. Else return 0. More...
      C & getClient () - returns a reference to the client object stored in this class. Take care not to break it. More...
    + Returns a reference to the client object stored in this class. Take care not to break it. More...
      - Public Member Functions inherited from SSLClientImpl  SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) @@ -210,12 +210,12 @@ Public Member Functions

    Protected Member Functions

    virtual Client & get_arduino_client () - return an instance of m_client that is polymorphic and can be used by SSLClientImpl More...
    + Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl. More...
      virtual const Client & get_arduino_client () const   virtual SSLSessionget_session_array () - return an instance of the session array that is on the stack More...
    + Returns an instance of the session array that is on the stack. More...
      virtual const SSLSessionget_session_array () const   @@ -248,7 +248,7 @@ Protected Member Functions

    template<class C, size_t SessionCache = 1>
    class SSLClient< C, SessionCache >

    -

    The main SSLClient class Check out README.md for more info.

    +

    The main SSLClient class. Check out README.md for more info.

    Constructor & Destructor Documentation

    ◆ SSLClient()

    @@ -304,13 +304,13 @@ template<class C , size_t SessionCache = 1>
    -

    Initialize SSLClient with all of the prerequisites needed.

    +

    Initialize SSLClient with all of the prerequisites needed.

    Precondition
    You will need to generate an array of trust_anchors (root certificates) based off of the domains you want to make SSL connections to. Check out the TrustAnchors.md file for more info.
    The analog_pin should be set to input.
    Parameters
    - + @@ -347,10 +347,10 @@ template<class C , size_t SessionCache = 1>
    clientThe base network device to create an SSL socket on. This object will be copied and the copy will be stored in SSLClient.
    clientThe base network device to create an SSL socket on. This object will be copied and the copy will be stored in SSLClient.
    trust_anchorsTrust anchors used in the verification of the SSL server certificate. Check out TrustAnchors.md for more info.
    trust_anchors_numThe number of objects in the trust_anchors array.
    analog_pinAn analog pin to pull random bytes from, used in seeding the RNG.
    -

    Returns the number of bytes availible to read from the SSL Socket.

    -

    This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

    +

    Returns the number of bytes available to read from the data that has been received and decrypted.

    +

    This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

    The implementation for this function can be found in SSLClientImpl::available

    -
    Precondition
    SSLClient::connected must be true.
    +
    Precondition
    SSLClient::connected must be true.
    Returns
    The number of bytes available (can be zero), or zero if any of the pre conditions aren't satisfied.
    @@ -392,15 +392,15 @@ template<class C , size_t SessionCache = 1>

    Connect over SSL to a host specified by an IP address.

    -

    SSLClient::connect(host, port) should be preferred over this function, as verifying the domain name is a step in ensuring the certificate is legitimate, which is important to the security of the device. Additionally, SSL sessions cannot be resumed, which can drastically increase initial connect time.

    -

    This function initializes the socket by calling m_client::connect(IPAddress, uint16_t) with the parameters supplied, then once the socket uses BearSSL to to complete a SSL handshake. Due to the design of the SSL standard, this function will probably take an extended period (1-4sec) to negotiate the handshake and finish the connection. This function runs until the SSL handshake succeeds or fails.

    -

    SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

    +

    SSLClient::connect(host, port) should be preferred over this function, as verifying the domain name is a step in ensuring the certificate is legitimate, which is important to the security of the device. Additionally, SSL sessions cannot be resumed when using this function, which can drastically increase initial connect time.

    +

    This function initializes the socket by calling m_client::connect(IPAddress, uint16_t) with the parameters supplied, then once the socket is open, uses BearSSL to to complete a SSL handshake. Due to the design of the SSL standard, this function will probably take an extended period (1-4sec) to negotiate the handshake and finish the connection. This function runs until the SSL handshake succeeds or fails.

    +

    SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

    The implementation for this function can be found in SSLClientImpl::connect_impl(IPAddress, uint16_t).

    Precondition
    The underlying client object (passed in through the constructor) is in a non- error state, and must be able to access the IP.
    -SSLClient can only have one connection at a time, so the client object must not already be connected.
    +SSLClient can only have one connection at a time, so the client object must not already be connected.
    -There must be sufficient memory available on the device to verify the certificate (if the free memory drops below 8000 bytes during certain points in the connection, SSLClient will fail).
    +There must be sufficient memory available on the device to verify the certificate (if the free memory drops below 8000 bytes during certain points in the connection, SSLClient will fail).
    There must be a trust anchor given to the constructor that corresponds to the certificate provided by the IP address being connected to. For more information check out TrustAnchors.md .
    Parameters
    @@ -451,15 +451,15 @@ template<class C , size_t SessionCache = 1>

    Connect over SSL to a host specified by a hostname.

    -

    This function initializes the socket by calling m_client::connect(const char*, uint16_t) with the parameters supplied, then once the socket is open uses BearSSL to to complete a SSL handshake. This function runs until the SSL handshake succeeds or fails.

    -

    SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

    +

    This function initializes the socket by calling m_client::connect(const char*, uint16_t) with the parameters supplied, then once the socket is open, uses BearSSL to complete a SSL handshake. This function runs until the SSL handshake succeeds or fails.

    +

    SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

    This function will usually take around 4-10 seconds. If possible, this function also attempts to resume the SSL session if one is present matching the hostname string, which will reduce connection time to 100-500ms. To read more about this functionality, check out Session Caching in the README.

    The implementation for this function can be found in SSLClientImpl::connect_impl(const char*, uint16_t)

    Precondition
    The underlying client object (passed in through the constructor) is in a non- error state, and must be able to access the IP.
    -SSLClient can only have one connection at a time, so the client object must not already be connected.
    +SSLClient can only have one connection at a time, so the client object must not already be connected.
    -There must be sufficient memory available on the device to verify the certificate (if the free memory drops below 8000 bytes during certain points in the connection, SSLClient will fail).
    +There must be sufficient memory available on the device to verify the certificate (if the free memory drops below 8000 bytes during certain points in the connection, SSLClient will fail).
    There must be a trust anchor given to the constructor that corresponds to the certificate provided by the IP address being connected to. For more information check out TrustAnchors.md .
    Parameters
    @@ -498,7 +498,8 @@ template<class C , size_t SessionCache = 1>
    -

    Check if the device is connected. Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently.

    +

    Check if the device is connected.

    +

    Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently.

    The implementation for this function can be found in SSLClientImpl::connected_impl.

    Returns
    1 if connected, 0 if not
    @@ -529,7 +530,8 @@ template<class C , size_t SessionCache = 1>
    -

    Force writing the buffered bytes from SSLClient::write to the network. This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush.

    +

    Force writing the buffered bytes from SSLClient::write to the network.

    +

    This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush.

    @@ -558,7 +560,7 @@ template<class C , size_t SessionCache = 1>
    -

    return an instance of m_client that is polymorphic and can be used by SSLClientImpl

    +

    Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.

    Implements SSLClientImpl.

    @@ -618,7 +620,7 @@ template<class C , size_t SessionCache = 1>
    -

    return an instance of the session array that is on the stack

    +

    Returns an instance of the session array that is on the stack.

    Implements SSLClientImpl.

    @@ -678,7 +680,7 @@ template<class C , size_t SessionCache = 1>
    -

    returns a reference to the client object stored in this class. Take care not to break it.

    +

    Returns a reference to the client object stored in this class. Take care not to break it.

    @@ -718,7 +720,7 @@ template<class C , size_t SessionCache = 1>
    -

    Get a session reference corresponding to a host and IP, or a reference to a empty session if none exist.

    +

    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist.

    If no session corresponding to the host and IP exist, then this function will cycle through sessions in a rotating order. This allows the session cache to continually store sessions, however it will also result in old sessions being cleared and returned. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

    The implementation for this function can be found at SSLClientImpl::get_session_impl.

    Parameters
    @@ -820,7 +822,7 @@ template<class C , size_t SessionCache = 1>
    -

    Equivalent to SSLClient::connected() > 0.

    +

    Equivalent to SSLClient::connected() > 0.

    Returns
    true if connected, false if not
    @@ -880,7 +882,7 @@ template<class C , size_t SessionCache = 1>
    -

    Returns whether or not two SSLClient objects do not have the same underlying client object.

    +

    Returns whether or not two SSLClient objects do not have the same underlying client object.

    @@ -939,7 +941,7 @@ template<class C , size_t SessionCache = 1>
    -

    Returns whether or not two SSLClient objects have the same underlying client object.

    +

    Returns whether or not two SSLClient objects have the same underlying client object.

    @@ -968,8 +970,8 @@ template<class C , size_t SessionCache = 1>
    -

    view the first byte of the buffer, without removing it from the SSLClient Buffer The implementation for this function can be found in SSLClientImpl::peek

    -
    Precondition
    SSLClient::available must be >0
    +

    View the first byte of the buffer, without removing it from the SSLClient Buffer.

    +

    The implementation for this function can be found in SSLClientImpl::peek

    Precondition
    SSLClient::available must be >0
    Returns
    The first byte received, or -1 if the preconditions are not satisfied (warning: do not use if your data may be -1, as the return value is ambiguous)
    @@ -1000,7 +1002,7 @@ template<class C , size_t SessionCache = 1>

    Read a single byte, or -1 if none is available.

    -
    See also
    SSLClient::read(uint8_t*, size_t)
    +
    See also
    SSLClient::read(uint8_t*, size_t)
    @@ -1040,11 +1042,11 @@ template<class C , size_t SessionCache = 1>
    -

    Read size bytes from the SSL socket buffer, copying them into *buf, and return the number of bytes read.

    -

    This function checks if bytes are ready to be read by calling SSLClient::available, and if so copies size number of bytes from the IO buffer into the buf pointer. Data read using this function will not include any SSL or socket commands, as the Client and BearSSL will capture those and process them separately.

    -

    If you find that you are having a lot of timeout errors, SSLClient may be experiencing a buffer overflow. Checkout README.md for more information.

    +

    Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read.

    +

    This function checks if bytes are ready to be read by calling SSLClient::available, and if so copies size number of bytes from the IO buffer into the buf pointer. Data read using this function will not include any SSL or socket commands, as the Client and BearSSL will capture those and process them separately.

    +

    If you find that you are having a lot of timeout errors, SSLClient may be experiencing a buffer overflow. Checkout README.md for more information.

    The implementation for this function can be found in SSLClientImpl::read_impl(uint8_t*, size_t)

    -
    Precondition
    SSLClient::available must be >0
    +
    Precondition
    SSLClient::available must be >0
    Parameters
    @@ -1191,7 +1193,8 @@ template<class C , size_t SessionCache = 1>
    bufThe pointer to the buffer to put SSL application data into
    -

    Close the connection If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an error was encountered previously, this function will simply call m_client::stop. The implementation for this function can be found in SSLClientImpl::peek.

    +

    Close the connection.

    +

    If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an error was encountered previously, this function will simply call m_client::stop. The implementation for this function can be found in SSLClientImpl::peek.

    @@ -1261,9 +1264,9 @@ template<class C , size_t SessionCache = 1>

    Write some bytes to the SSL connection.

    -

    Assuming all preconditions are met, this function writes data to the BearSSL IO buffer, BUT does not initially send the data. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready for writing, and will write the data to the network. Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until all the data in buf is sent–attempting to keep all writes to the network grouped together. For information on why this is the case check out README.md .

    +

    Assuming all preconditions are met, this function writes data to the BearSSL IO buffer, BUT does not initially send the data. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready for writing, and will write the data to the network. Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until all the data in buf is sent–attempting to keep all writes to the network grouped together. For information on why this is the case check out README.md .

    The implementation for this function can be found in SSLClientImpl::write_impl(const uint8_t*, size_t)

    -
    Precondition
    The socket and SSL layer must be connected, meaning SSLClient::connected must be true.
    +
    Precondition
    The socket and SSL layer must be connected, meaning SSLClient::connected must be true.
    BearSSL must not be waiting for the recipt of user data (if it is, there is probably an error with how the protocol in implemented in your code).
    Parameters
    diff --git a/docs/html/class_s_s_l_client_impl.html b/docs/html/class_s_s_l_client_impl.html index 7ecee39..7259c74 100644 --- a/docs/html/class_s_s_l_client_impl.html +++ b/docs/html/class_s_s_l_client_impl.html @@ -96,7 +96,7 @@ $(document).ready(function(){initNavTree('class_s_s_l_client_impl.html','');});
    -

    Implementation code to be inherited by SSLClient. +

    Implementation code to be inherited by SSLClient. More...

    #include <SSLClientImpl.h>

    @@ -106,7 +106,7 @@ Inheritance diagram for SSLClientImpl:
    -SSLClient< C, SessionCache > +SSLClient< C, SessionCache >
    @@ -180,7 +180,7 @@ Protected Member Functions
     

    Detailed Description

    -

    Implementation code to be inherited by SSLClient.

    +

    Implementation code to be inherited by SSLClient.

    Constructor & Destructor Documentation

    ◆ SSLClientImpl()

    @@ -227,7 +227,7 @@ Protected Member Functions
    @@ -246,7 +246,7 @@ Protected Member Functions @@ -322,7 +322,7 @@ Protected Member Functions @@ -340,7 +340,7 @@ Protected Member Functions @@ -366,7 +366,7 @@ Protected Member Functions
    -

    See SSLClient::get_arduino_client

    +
    See also
    SSLClient::get_arduino_client

    Implemented in SSLClient< C, SessionCache >.

    @@ -421,7 +421,7 @@ Protected Member Functions
    -

    See SSLClient::get_session_array

    +
    See also
    SSLClient::get_session_array

    Implemented in SSLClient< C, SessionCache >.

    @@ -479,7 +479,7 @@ Protected Member Functions
    @@ -505,7 +505,7 @@ Protected Member Functions
    -

    See SSLClient::getSessionCount

    +
    See also
    SSLClient::getSessionCount

    Implemented in SSLClient< C, SessionCache >.

    @@ -533,7 +533,7 @@ Protected Member Functions
    -

    See SSLClient::localPort

    +
    See also
    SSLClient::localPort

    Implemented in SSLClient< C, SessionCache >.

    @@ -829,7 +829,7 @@ template<typename T >
    -
    See also
    SSLClient::peek
    +
    See also
    SSLClient::peek
    @@ -858,7 +858,7 @@ template<typename T > @@ -884,7 +884,7 @@ template<typename T >
    -

    See SSLClient::remoteIP

    +
    See also
    SSLClient::remoteIP

    Implemented in SSLClient< C, SessionCache >.

    @@ -912,7 +912,7 @@ template<typename T >
    -

    See SSLClient::localPort

    +
    See also
    SSLClient::localPort

    Implemented in SSLClient< C, SessionCache >.

    @@ -943,7 +943,7 @@ template<typename T >
    @@ -961,7 +961,7 @@ template<typename T >
    -
    See also
    SSLClient::stop
    +
    See also
    SSLClient::stop
    diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index 07d85e0..adb0e30 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -95,7 +95,7 @@ $(document).ready(function(){initNavTree('class_s_s_l_session.html','');});
    -

    This class stores values which allow SSLClient to save and resume SSL sessions. +

    This class stores values which allow SSLClient to save and resume SSL sessions. More...

    #include <SSLSession.h>

    @@ -126,17 +126,17 @@ Public Member Functions  Set the ip address and hostname of the session. More...
      void clear_parameters () - delete the parameters and invalidate the session Roughly equivalent to this_session = SSLSession(), however this function preserves the String object, allowing it to better handle the dynamic memory needed. More...
    + Delete the parameters and invalidate the session. More...
      br_ssl_session_parameters * to_br_session () - returns a pointer to the ::br_ssl_session_parameters component of this class More...
    + Returns a pointer to the ::br_ssl_session_parameters component of this class. More...
     

    Detailed Description

    -

    This class stores values which allow SSLClient to save and resume SSL sessions.

    +

    This class stores values which allow SSLClient to save and resume SSL sessions.

    SSLSession.h

    This file contains a simple utility class to store parameters about an SSL Session for reuse later.This class was created to extend the values stored in br_ssl_session_parameters, which allow BearSSL to resume an SSL session. When testing BearSSL's session resumption feature, it was observed that BearSSL can only resume a session that was was started with the same server. This becomes an issue when using repeated requests to a domain name which can resolve to multiple IP addresses ("api.github.com"), as the device will switch between two or three servers. Since BearSSL only stores one session at a time, this results in session resumption being few and far between.

    -

    To remedy this problem, an SSLSession stores the IPAddress and hostname, along with the parameters in br_ssl_session_parameters struct. Using this data, SSLClient is able to remember which IPAddress is associated with which session, allowing it to reconnect to the last IPAddress, as opposed to any associated with the domain.

    +

    To remedy this problem, an SSLSession stores the IPAddress and hostname, along with the parameters in br_ssl_session_parameters struct. Using this data, SSLClient is able to remember which IPAddress is associated with which session, allowing it to reconnect to the last IPAddress, as opposed to any associated with the domain.

    Constructor & Destructor Documentation

    ◆ SSLSession()

    @@ -182,7 +182,8 @@ Public Member Functions
    -

    delete the parameters and invalidate the session Roughly equivalent to this_session = SSLSession(), however this function preserves the String object, allowing it to better handle the dynamic memory needed.

    +

    Delete the parameters and invalidate the session.

    +

    Roughly equivalent to this_session = SSLSession(), however this function preserves the String object, allowing it to better handle the dynamic memory needed.

    @@ -211,7 +212,7 @@ Public Member Functions

    Get the hostname string associated with this session.

    Returns
    A String object or "" if there is no hostname
    -
    Precondition
    must check isValidSession before getting this value, as if this session in invalid this value is not guarented to be reset to "".
    +
    Precondition
    must check isValidSession before getting this value, as if this session in invalid this value is not guarenteed to be reset to "".
    @@ -240,7 +241,7 @@ Public Member Functions

    Get ::IPAddress associated with this session.

    Returns
    A ::IPAddress object, #INADDR_NONE if there is no IP
    -
    Precondition
    must check isValidSession before getting this value, as if this session in invalid this value is not guarented to be reset to #INADDR_NONE.
    +
    Precondition
    must check isValidSession before getting this value, as if this session in invalid this value is not guarenteed to be reset to #INADDR_NONE.
    @@ -325,7 +326,7 @@ Public Member Functions

    Set the ip address and hostname of the session.

    This function stores the ip Address object and hostname object into the session object. If hostname is not null or ip address is not blank, and the ::br_ssl_session_parameters values are non-zero it then validates the session.

    -
    Precondition
    You must call ::br_ssl_engine_get_session_parameters with this session before calling this function. This is because there is no way to completly validate the ::br_ssl_session_parameters and the session may end up in a corrupted state if this is not observed.
    +
    Precondition
    You must call ::br_ssl_engine_get_session_parameters with this session before calling this function. This is because there is no way to completely validate the ::br_ssl_session_parameters and the session may end up in a corrupted state if this is not observed.
    Parameters
    @@ -359,7 +360,7 @@ Public Member Functions
    ipThe IP address of the host associated with the session
    -

    returns a pointer to the ::br_ssl_session_parameters component of this class

    +

    Returns a pointer to the ::br_ssl_session_parameters component of this class.

    diff --git a/docs/html/functions_vars.html b/docs/html/functions_vars.html new file mode 100644 index 0000000..0b413ef --- /dev/null +++ b/docs/html/functions_vars.html @@ -0,0 +1,145 @@ + + + + + + + +SSLClient: Class Members - Variables + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    + + + + diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 85eafea..7ad10b4 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -94,10 +94,10 @@ $(document).ready(function(){initNavTree('hierarchy.html','');});
    This inheritance list is sorted roughly, but not completely, alphabetically:
    [detail level 123]
    - + - - + +
     Cbr_ssl_session_parameters
     CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
     CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
     CClient
     CSSLClientImplImplementation code to be inherited by SSLClient
     CSSLClient< C, SessionCache >The main SSLClient class Check out README.md for more info
     CSSLClientImplImplementation code to be inherited by SSLClient
     CSSLClient< C, SessionCache >The main SSLClient class. Check out README.md for more info
    diff --git a/docs/html/index.html b/docs/html/index.html index b209a0b..39317ee 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -5,7 +5,7 @@ -SSLClient: Main Page +SSLClient: SSLClient - Arduino Library For SSL @@ -86,11 +86,74 @@ $(document).ready(function(){initNavTree('index.html','');}); -
    +
    -
    SSLClient Documentation
    +
    SSLClient - Arduino Library For SSL
    +

    SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.

    +

    SSLClient is a simple library to add TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it.

    +

    Overview

    +

    Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with EthernetClient. There are a few extra things, however, that you will need to get started:

    +
      +
    1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Notes).
    2. +
    3. A header containing array of trust anchors, which will look like this file. These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out this document on how to generate this file for your project, and for more information about what a trust anchor is.
    4. +
    5. A Client class associated with a network interface. We tested this library using EthernetClient, however in theory it will work for any class implementing Client.
    6. +
    7. An analog pin, used for generating random data at the start of the connection (see the Implementation Notes).
    8. +
    +

    Once all those are ready, you can create a simple SSLClient object like this:

    {C++}
    SSLClient<BaseClientType> client(BaseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin);

    Where:

      +
    • BaseClientType - The type of BaseClientInstance
    • +
    • BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3)
    • +
    • TAs - The name of the trust anchor array created in step 2. If you generated a header using the tutorial this will probably be TAs.
    • +
    • TAs_NUM - The number of trust anchors in TAs. If you generated a header using the tutorial this will probably be TAs_NUM.
    • +
    • AnalogPin - The analog pin to pull random data from (step 4).

      +

      For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using:

      {C++}
      SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);

      Once that is setup, simply use SSLClient as you would the base client class:

      {C++}
      // connect to ardiuino.cc over ssl (port 443 for websites)
      client.connect("www.arduino.cc", 443);
      // Make a HTTP request
      client.println("GET /asciilogo.txt HTTP/1.1");
      client.println("User-Agent: AdafruitFeatherM0WiFi");
      client.print("Host: ");
      client.println(server);
      client.println("Connection: close");
      client.println();
      client.flush();
      // read and print the data
      ...

      Note: client.connect("www.arduino.cc", 443) can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in Implementation Notes.

      +
    • +
    +

    For more information on SSLClient, check out the examples, API documentation, or the rest of this README.

    +

    How It Works

    +

    SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant BearSSL as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, making debugging a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint.

    +

    Additionally, the bulk of SSLClient is split into two components: a template class SSLClient, and an implementation class SSLClientImpl. The template class serves to abstract some functions not implemented in the Arduino Client interface (such as EthernetClient::remoteIP), and the implementation class is the rest of the SSLClient library.

    +

    Other Features

    +

    Logging

    +

    SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor:

    {C++}
    SSLClient<EthernetClient> client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO);

    Logging is always outputted through the Arduino Serial interface, so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in DebugLevel. The log level is set to SSL_WARN by default.

    +

    Errors

    +

    When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from SSLClient::getWriteError(), which will return a value from the Error enum. For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at SSL_ERROR or lower.

    +

    Write Buffering

    +

    As you may have noticed in the documentation for SSLClient::write, calling this function does not actually write to the network. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready and write to the network (see SSLClient::write for details).

    +

    This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so:

    {C++}
    EthernetClient client;
    // ...
    // connect to ardiuino.cc over ssl (port 443 for websites)
    client.connect("www.arduino.cc", 443);
    // ...
    // write an http request to the network
    client.write("GET /asciilogo.txt HTTP/1.1\r\n");
    client.write("Host: arduino.cc\r\n");
    client.write("Connection: close\r\n");
    // wait for response
    while (!client.available()) { /* ... */ }
    // ...

    Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

    +
    {C++}
    SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);
    // ...
    // connect to ardiuino.cc over ssl (port 443 for websites)
    client.connect("www.arduino.cc", 443);
    // ...
    // add http request to the buffer
    client.write("GET /asciilogo.txt HTTP/1.1\r\n");
    client.write("Host: arduino.cc\r\n");
    client.write("Connection: close\r\n");
    // write the bytes to the network, then wait for response
    while (!client.available()) { /* ... */ }
    // ...

    If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

    +

    Session Caching

    +

    As detailed in the resources section, SSL handshakes take an extended period (1-4sec) to negotiate. To remedy this problem, BearSSL is able to keep a SSL session cache of the clients it has connected to. If BearSSL successfully resumes an SSL session, it can reduce connection time to 100-500ms.

    +

    In order to use SSL session resumption:

      +
    • The website you are connecting to must support it. Support is widespread, but you can verify easily using the SSLLabs tool.
    • +
    • You must reuse the same SSLClient object (SSL Sessions are stored in the object itself).
    • +
    • You must reconnect to the exact same server.
    • +
    +

    SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call connect("www.google.com") SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with "www.google.com". However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection.

    +

    You can test whether or not a website can resume SSL Sessions using the Session Example included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume.

    +

    SSL sessions take a lot of memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration:

    {C++}
    SSLClient<EthernetClient, SomeNumber> client(EthernetClient(), TAs, 2, A7);

    Where SomeNumber is the number of sessions you would like to store. For example this declaration can store 3 sessions:

    {C++}
    SSLClient<EthernetClient, 3> client(EthernetClient(), TAs, 2, A7);

    Sessions are managed internally using the SSLSession::getSession function. This function will cycle through sessions in a rotating order, allowing the session cache to continually overwrite old sessions. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

    +

    If you need to clear a session, you can do so using the SSLSession::removeSession function.

    +

    Implementation Gotchas

    +

    Some ideas that didn't quite fit in the API documentation.

    +

    Certificate Verification

    +

    SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out this document for more details on this component of SSLClient.

    +

    BearSSL also features a known certificate validation engine, which only allows for a single domain in exchange for a significantly reduced resource usage (flash and CPU time). This functionality is planned to be implemented in the future.

    +

    Resources

    +

    The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive.

    +

    To illustrate this, I will run some tests on various domains below. I haven't yet, but I will.

    +

    If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from SSLClient.h, SSLClientImpl.h, and SSLClientImpl.cpp. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself.

    +

    Read Buffer Overflow

    +

    SSL is a buffered protocol, and since most microcontrollers have limited resources (see Resources), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow, caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received, forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems, this could be the reason why.

    +

    In order to remedy this problem, the device must be able to read the data faster than it is being received, or alternatively have a cache large enough to store the entire payload. Since SSL's encryption forces the device to read slowly, this means we must increase the cache size. Depending on your platform, there are a number of ways this can be done:

      +
    • Sometimes your communication shield will have an internal buffer, which can be expanded through the driver code. This is the case with the Arduino Ethernet library (in the form of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be modified for the change to take effect.
    • +
    • SSLClient has an internal buffer SSLClientImpl::m_iobuf, which can be expanded. BearSSL limits the amount of data that can be processed based on the stage in the SSL handshake, and so this will change will have limited usefulness.
    • +
    • In some cases, a website will send so much data that even with the above solutions, SSLClient will be unable to keep up (a website with a lot of HTML is an example). In these cases you will have to find another method of retrieving the data you need.
    • +
    • If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM.
    • +
    +

    Cipher Support

    +

    By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

    {C++}
    br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
    // comment the above line and uncomment the line below if you're having trouble connecting over SSL
    // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

    to this:

    {C++}
    // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
    // comment the above line and uncomment the line below if you're having trouble connecting over SSL
    br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

    If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the BearSSL profiles documentation and I wish you the best of luck.

    +
    diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index ae62f75..01d98af 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -91,11 +91,11 @@ $(document).ready(function(){initNavTree('md__c_1__users__noah__documents__ardui
    Trust Anchors
    -

    SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. In short, these trust anchor arrays allow BearSSL to verify that the server being connected to is who they say they are, and not someone malicious. You can read more about certificates and why they are important here.

    -

    SSLClient stores trust anchors in hardcoded constant variables, passed into SSLClient::SSLClient during setup. These constants are generally stored in their own header file as found in the BearSSL docs. This header file will look something like:

    {C++}
    #define TAs_NUM 1
    static const unsigned char TA_DN0[] = {
    // lots of raw bytes here
    // ...
    };
    static const unsigned char TA_RSA_N0[] = {
    // lots of raw bytes here
    //...
    };
    static const unsigned char TA_RSA_E0[] = {
    // 1-3 bytes here
    };
    static const br_x509_trust_anchor TAs[] = {
    {
    { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    BR_X509_TA_CA,
    {
    BR_KEYTYPE_RSA,
    { .rsa = {
    (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
    (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
    } }
    }
    },
    };

    A full example of a trust anchor header can be found in this file. Full documentation for the format of these variables can be found in the BearSSL documentation for br_x509_trust_anchor.

    +

    SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. In short, these trust anchor arrays allow BearSSL to verify that the server being connected to is who they say they are, and not someone malicious. You can read more about certificates and why they are important here.

    +

    SSLClient stores trust anchors in hardcoded constant variables, passed into SSLClient::SSLClient during setup. These constants are generally stored in their own header file as found in the BearSSL docs. This header file will look something like:

    {C++}
    #define TAs_NUM 1
    static const unsigned char TA_DN0[] = {
    // lots of raw bytes here
    // ...
    };
    static const unsigned char TA_RSA_N0[] = {
    // lots of raw bytes here
    //...
    };
    static const unsigned char TA_RSA_E0[] = {
    // 1-3 bytes here
    };
    static const br_x509_trust_anchor TAs[] = {
    {
    { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    BR_X509_TA_CA,
    {
    BR_KEYTYPE_RSA,
    { .rsa = {
    (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
    (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
    } }
    }
    },
    };

    A full example of a trust anchor header can be found in this file. Full documentation for the format of these variables can be found in the BearSSL documentation for br_x509_trust_anchor.

    Generating Trust Anchors

    HTTPS

    -

    For HTTPS, there a couple of tools you can use. Ordered from easy to hard:

      +

      For HTTPS, there a couple of tools you can use. Ordered from easiest to hardest:

      • This website, written to simplify the creation of trust anchor headers. Simply plug and play.
      • pycert_bearssl, a command line utility based on a pycert. You will need to install Python 3, and follow the instructions in the pycert_bearssl.py file. You'll want to use the pycert_bearssl.py download command once the utility is set up.
      • The brssl command line utility, included in the BearSSL source. You will need to compile this file yourself.
      • @@ -103,7 +103,7 @@ $(document).ready(function(){initNavTree('md__c_1__users__noah__documents__ardui

        Other Connections

        For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convert command to convert the certificate into a trust anchor header.

        Using Trust Anchors

        -

        Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

        {C++}
        #include "yourtrustanchorfile.h"
        // ...
        SSLClient<SomeClientType> client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
        // ...

        Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

        +

        Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

        {C++}
        #include "yourtrustanchorfile.h"
        // ...
        SSLClient<SomeClientType> client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
        // ...

        Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

    diff --git a/docs/html/navtreedata.js b/docs/html/navtreedata.js index 2de0edc..6bb2dc3 100644 --- a/docs/html/navtreedata.js +++ b/docs/html/navtreedata.js @@ -24,7 +24,7 @@ for the JavaScript code in this file var NAVTREE = [ [ "SSLClient", "index.html", [ - [ "SSLClient - Arduino Library For SSL", "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html", null ], + [ "SSLClient - Arduino Library For SSL", "index.html", null ], [ "Trust Anchors", "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html", null ], [ "Classes", "annotated.html", [ [ "Class List", "annotated.html", "annotated_dup" ], diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index 00bd01c..97904f6 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -108,8 +108,8 @@ var NAVTREEINDEX0 = "globals_func.html":[3,1,1], "globals_vars.html":[3,1,2], "hierarchy.html":[2,2], +"index.html":[0], "index.html":[], -"md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html":[0], "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[1], "pages.html":[], "time__macros_8h.html":[3,0,1,5], diff --git a/docs/html/pages.html b/docs/html/pages.html index 5f7f3f9..c715a5c 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -93,8 +93,7 @@ $(document).ready(function(){initNavTree('pages.html','');});
    Here is a list of all related documentation pages:
    diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js index 2ae3e87..84c4068 100644 --- a/docs/html/search/all_e.js +++ b/docs/html/search/all_e.js @@ -1,6 +1,6 @@ var searchData= [ - ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html',1,'']]], + ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../index.html',1,'']]], ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], diff --git a/docs/html/search/pages_0.js b/docs/html/search/pages_0.js index c416cfc..54d5ef5 100644 --- a/docs/html/search/pages_0.js +++ b/docs/html/search/pages_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html',1,'']]] + ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../index.html',1,'']]] ]; diff --git a/docs/html/search/variables_1.html b/docs/html/search/variables_1.html new file mode 100644 index 0000000..b784017 --- /dev/null +++ b/docs/html/search/variables_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/variables_1.js b/docs/html/search/variables_1.js new file mode 100644 index 0000000..89036bd --- /dev/null +++ b/docs/html/search/variables_1.js @@ -0,0 +1,17 @@ +var searchData= +[ + ['m_5fanalog_5fpin',['m_analog_pin',['../class_s_s_l_client_impl.html#a9fd03216e71ec0d250b3ed2874f08350',1,'SSLClientImpl']]], + ['m_5fclient',['m_client',['../class_s_s_l_client.html#a3fa6f4acf8149d76dd4fa443df4a2202',1,'SSLClient']]], + ['m_5fdebug',['m_debug',['../class_s_s_l_client_impl.html#a918195d260b3399056bd0477e5249321',1,'SSLClientImpl']]], + ['m_5fhostname',['m_hostname',['../class_s_s_l_session.html#ab5611a1eb7633019a9bfaa7cc86a1645',1,'SSLSession']]], + ['m_5fiobuf',['m_iobuf',['../class_s_s_l_client_impl.html#a6b8064ac811810e00b339f15fbe522c3',1,'SSLClientImpl']]], + ['m_5fip',['m_ip',['../class_s_s_l_session.html#ab080fda0553cff3be60ef134b68ad029',1,'SSLSession']]], + ['m_5fsession_5findex',['m_session_index',['../class_s_s_l_client_impl.html#a7cc5de19274e5ec689017cbb84aa008a',1,'SSLClientImpl']]], + ['m_5fsessions',['m_sessions',['../class_s_s_l_client.html#a680fa57f70d2f3164dd4b117bba8f001',1,'SSLClient']]], + ['m_5fsslctx',['m_sslctx',['../class_s_s_l_client_impl.html#ab6e5219b2edeb01bd949fbb51749adee',1,'SSLClientImpl']]], + ['m_5ftrust_5fanchors',['m_trust_anchors',['../class_s_s_l_client_impl.html#ac84af4c6b35f59642b6814c52cfde5db',1,'SSLClientImpl']]], + ['m_5ftrust_5fanchors_5fnum',['m_trust_anchors_num',['../class_s_s_l_client_impl.html#a4b86754cee9e04742728ca14e1b0db7f',1,'SSLClientImpl']]], + ['m_5fvalid_5fsession',['m_valid_session',['../class_s_s_l_session.html#abfe44b78c7c7d0f83919d6031d1d1857',1,'SSLSession']]], + ['m_5fwrite_5fidx',['m_write_idx',['../class_s_s_l_client_impl.html#a4bdc048774d8be220da7175e1369513f',1,'SSLClientImpl']]], + ['m_5fx509ctx',['m_x509ctx',['../class_s_s_l_client_impl.html#a942c7bd3ebbb03db249096c8bb591b8c',1,'SSLClientImpl']]] +]; diff --git a/src/SSLClient.h b/src/SSLClient.h index 0a08d34..3e69bd9 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -27,7 +27,7 @@ #define SSLClient_H_ /** - * @brief The main SSLClient class + * @brief The main SSLClient class. * Check out README.md for more info. */ diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 5c570d0..a7dd03f 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -70,7 +70,7 @@ enum DebugLevel { /** @brief Implementation code to be inherited by SSLClient */ class SSLClientImpl : public Client { public: - /** See SSLClient::SSLClient */ + /** @see SSLClient::SSLClient */ explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); @@ -96,28 +96,28 @@ public: void stop_impl(); /** @see SSLClient::connected */ uint8_t connected_impl(); - /** See SSLClient::getSession */ + /** @see SSLClient::getSession */ SSLSession& get_session_impl(const char* host, const IPAddress& addr); - /** See SSLClient::removeSession */ + /** @see SSLClient::removeSession */ void remove_session_impl(const char* host, const IPAddress& addr); //============================================ //= Functions implemented in SSLClient.h //============================================ - /** See SSLClient::localPort */ + /** @see SSLClient::localPort */ virtual uint16_t localPort() = 0; - /** See SSLClient::remoteIP */ + /** @see SSLClient::remoteIP */ virtual IPAddress remoteIP() = 0; - /** See SSLClient::localPort */ + /** @see SSLClient::localPort */ virtual uint16_t remotePort() = 0; - /** See SSLClient::getSessionCount */ + /** @see SSLClient::getSessionCount */ virtual size_t getSessionCount() const = 0; protected: - /** See SSLClient::get_arduino_client */ + /** @see SSLClient::get_arduino_client */ virtual Client& get_arduino_client() = 0; virtual const Client& get_arduino_client() const = 0; - /** See SSLClient::get_session_array */ + /** @see SSLClient::get_session_array */ virtual SSLSession* get_session_array() = 0; virtual const SSLSession* get_session_array() const = 0; From c06f75d6ed3783256cb02aa95da93f41e5b0ce6a Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 31 Mar 2019 16:43:54 -0700 Subject: [PATCH 041/205] added link to main docs --- docs/index.html | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/index.html diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..aaad44b --- /dev/null +++ b/docs/index.html @@ -0,0 +1,11 @@ + + + + + + Page Redirection + + + If you are not redirected automatically, follow the link to the documentation + + \ No newline at end of file From d3d625e328f71c4ca4a11ac0b24cb5f57218609c Mon Sep 17 00:00:00 2001 From: Noah Date: Sun, 31 Mar 2019 16:47:23 -0700 Subject: [PATCH 042/205] Added links to the doxygen --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8cb8650..eb52018 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ **SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.** +You can also view this README in [doxygen](https://openslab-osu.github.io/SSLClient/html/index.html). + SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. ## Overview @@ -45,7 +47,7 @@ client.flush(); ``` **Note**: `client.connect("www.arduino.cc", 443)` can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in [Implementation Notes](#Implementation-Notes). -For more information on SSLClient, check out the [examples](./examples), [API documentation](./docs/index.html), or the rest of this README. +For more information on SSLClient, check out the [examples](./examples), [API documentation](https://openslab-osu.github.io/SSLClient/html/index.html), or the rest of this README. ## How It Works @@ -164,4 +166,4 @@ to this: // comment the above line and uncomment the line below if you're having trouble connecting over SSL br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); ``` -If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the [BearSSL profiles documentation](https://bearssl.org/api1.html#profiles) and I wish you the best of luck. \ No newline at end of file +If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the [BearSSL profiles documentation](https://bearssl.org/api1.html#profiles) and I wish you the best of luck. From 6258af2c4b5f46671ec9c30e2696f4d563dbb447 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 1 Apr 2019 12:56:50 -0700 Subject: [PATCH 043/205] updated arduino library metadata --- keywords.txt | 33 +++++++++++++++++++++++++++++++++ library.properties | 7 ++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index e69de29..ad4bcbd 100644 --- a/keywords.txt +++ b/keywords.txt @@ -0,0 +1,33 @@ +# DataTypes +SSLClient KEYWORD1 + +# Methods and Functions +connect KEYWORD2 +write KEYWORD2 +available KEYWORD2 +read KEYWORD2 +peek KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 +localPort KEYWORD2 +setTimeout KEYWORD2 +getClient KEYWORD2 + +# Constants and Literals +SSL_OK LITERAL1 +SSL_CLIENT_CONNECT_FAIL LITERAL1 +SSL_BR_CONNECT_FAIL LITERAL1 +SSL_CLIENT_WRTIE_ERROR LITERAL1 +SSL_BR_WRITE_ERROR LITERAL1 +SSL_INTERNAL_ERROR LITERAL1 +SSL_OUT_OF_MEMORY LITERAL1 + +SSL_NONE LITERAL1 +SSL_ERROR LITERAL1 +SSL_WARN LITERAL1 +SSL_INFO LITERAL1 + + diff --git a/library.properties b/library.properties index 8b31264..1650e51 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,10 @@ name=SSLClient -version=0.1 -author=OPEnS Lab +version=1.0 +author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class -paragraph=Uses BearSSL to communicate over SSL. +paragraph=including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. category=Communication url=https://github.com/OPEnSLab-OSU/SSLClient +architectures=samd includes=SSLClient.h \ No newline at end of file From 720735b4960b63f401e3a04de57d932cbe80852d Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 1 Apr 2019 18:08:46 -0700 Subject: [PATCH 044/205] updated readme to add missing sections --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++--- src/SSLClientImpl.cpp | 2 +- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index eb52018..7f8051f 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec. Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few extra things, however, that you will need to get started: -1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Notes](#Implementation-Notes)). +1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Gotchas](#sslclient-with-ethernet)). 2. A header containing array of trust anchors, which will look like [this file](./readme/cert.h). These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out [this document](./TrustAnchors.md) on how to generate this file for your project, and for more information about what a trust anchor is. 3. A Client class associated with a network interface. We tested this library using [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient), however in theory it will work for any class implementing Client. -4. An analog pin, used for generating random data at the start of the connection (see the [Implementation Notes](#Implementation-Notes)). +4. An analog pin, used for generating random data at the start of the connection (see the [Implementation Gotchas](#implementation-gotchas)). Once all those are ready, you can create a simple SSLClient object like this: ```C++ @@ -45,7 +45,7 @@ client.flush(); // read and print the data ... ``` -**Note**: `client.connect("www.arduino.cc", 443)` can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in [Implementation Notes](#Implementation-Notes). +**Note**: `client.connect("www.arduino.cc", 443)` can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in [Implementation Notes](#resources). For more information on SSLClient, check out the [examples](./examples), [API documentation](https://openslab-osu.github.io/SSLClient/html/index.html), or the rest of this README. @@ -132,6 +132,52 @@ If you need to clear a session, you can do so using the SSLSession::removeSessio Some ideas that didn't quite fit in the API documentation. +### SSLClient with Ethernet +If you are using the [Arduino Ethernet library](https://github.com/arduino-libraries/Ethernet), you will need to modify the library to support the large buffer sizes required by SSL (detailed in [resources](#resources)). To do this, first find the location of the library in the directory where Arduino is installed (`C:\Program Files (x86)\Arduino` on Windows). Inside of this directory, navigate to `libraries\Ethernet\src` (`C:\Program Files (x86)\Arduino\libraries\Ethernet\src` on Windows). Modify `Ethernet.h` to replace these lines: +```C++ +... +// Configure the maximum number of sockets to support. W5100 chips can have +// up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes +// of RAM are used for each socket. Reducing the maximum can save RAM, but +// you are limited to fewer simultaneous connections. +#if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048) +#define MAX_SOCK_NUM 4 +#else +#define MAX_SOCK_NUM 8 +#endif + +// By default, each socket uses 2K buffers inside the Wiznet chip. If +// MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting +// this will use larger buffers within the Wiznet chip. Large buffers +// can really help with UDP protocols like Artnet. In theory larger +// buffers should allow faster TCP over high-latency links, but this +// does not always seem to work in practice (maybe Wiznet bugs?) +//#define ETHERNET_LARGE_BUFFERS +... +``` +With this: +```C++ +... +// Configure the maximum number of sockets to support. W5100 chips can have +// up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes +// of RAM are used for each socket. Reducing the maximum can save RAM, but +// you are limited to fewer simultaneous connections. +#define MAX_SOCK_NUM 2 + +// By default, each socket uses 2K buffers inside the Wiznet chip. If +// MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting +// this will use larger buffers within the Wiznet chip. Large buffers +// can really help with UDP protocols like Artnet. In theory larger +// buffers should allow faster TCP over high-latency links, but this +// does not always seem to work in practice (maybe Wiznet bugs?) +#define ETHERNET_LARGE_BUFFERS +... +``` +You may need to use `sudo` or administrator permissions to make this modification. We change `MAX_SOCK_NUM` and `ETHERNET_LARGE_BUFFERS` so the Ethernet hardware can allocate a larger space for SSLClient, however a downside of this modification is we are now only able to have two sockets concurrently. As most microprocessors barely have enough memory for one SSL connection, this limitation will rarely be encountered in practice. + +### Random Data +The SSL protocol requires that SSLClient generate some random bits before connecting with a server. BearSSL provides a random number generator but requires a [some entropy for a seed](https://bearssl.org/apidoc/bearssl__ssl_8h.html#a7d8e8de2afd49d6794eae02f56f81152). Normally this seed is generated by taking the microsecond time using the internal clock, however since most microcontrollers are not build with this feature another source must be found. As a simple solution, SSLClient uses a floating analog pin as an external source of random data, passed through to the constructor in the `analog_pin` argument. Before every connection, SSLClient will take the bottom byte from 16 analog reads on `analog_pin`, and combine these bytes into a 16 byte random number, which is used as a seed for BearSSL. To ensure the most random data, it is recommended that this analog pin be either floating or connected to a location not modifiable by the microcontroller (i.e. a battery voltage readout). + ### Certificate Verification SSLClient uses BearSSL's [minimal x509 verification engine](https://bearssl.org/x509.html#the-minimal-engine) to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out [this document](./TrustAnchors.md) for more details on this component of SSLClient. diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 76a31ec..f743d69 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -381,7 +381,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { } // timeout check if (millis() - start > getTimeout()) { - m_error("SSL internals timed out! This could be an internal error or bad data sent from the server", func_name); + m_error("SSL internals timed out! This could be an internal error, bad data sent from the server, or data being discarded due to a buffer overflow. If you are using Ethernet, did you modify the library properly (see README)?", func_name); setWriteError(SSL_BR_WRITE_ERROR); stop_impl(); return -1; From 88d40614967fb80995a818045bb447b47dd41275 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 1 Apr 2019 18:53:20 -0700 Subject: [PATCH 045/205] added some example sketchs --- examples/EthernetHTTPS/EthernetHTTPS.ino | 152 ++++++++++++++++ examples/EthernetHTTPS/trust_anchors.h | 79 +++++++++ .../EthernetMultiHTTPS/EthernetMultiHTTPS.ino | 167 ++++++++++++++++++ examples/EthernetMultiHTTPS/trustanchors.h | 137 ++++++++++++++ src/SSLClientImpl.cpp | 2 +- 5 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 examples/EthernetHTTPS/EthernetHTTPS.ino create mode 100644 examples/EthernetHTTPS/trust_anchors.h create mode 100644 examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino create mode 100644 examples/EthernetMultiHTTPS/trustanchors.h diff --git a/examples/EthernetHTTPS/EthernetHTTPS.ino b/examples/EthernetHTTPS/EthernetHTTPS.ino new file mode 100644 index 0000000..fd7416c --- /dev/null +++ b/examples/EthernetHTTPS/EthernetHTTPS.ino @@ -0,0 +1,152 @@ +/* + Web client + + This sketch connects to a website (http://www.arduino.cc/asciilogo.txt) + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Noah Koontz, based on work by Adrian McEwen and Tom Igoe + + */ + + // NOTE: The Ethernet library MUST be modified to use this example! + // For more detailed instructions check out https://github.com/OPEnSLab-OSU/SSLClient#sslclient-with-ethernet + +#include +#include +#include +#include "trust_anchors.h" + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(54,85,55,79); // numeric IP for Google (no DNS) +const char server[] = "www.arduino.cc"; // name address for Arduino (using DNS) +const char server_host[] = "www.arduino.cc"; // leave this alone, change only above two + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 177); +IPAddress myDns(8, 8, 8, 8); + +// Choose the analog pin to get semi-random data from for SSL +// Pick a pin that's not connected or attached to a randomish voltage source +const int rand_pin = A7; + +// Initialize the SSL client library +// We input an EthernetClient, our trust anchors, and the analog pin +SSLClient client(EthernetClient(), TAs, (size_t)TAs_NUM, rand_pin); +// Variables to measure the speed +unsigned long beginMicros, endMicros; +unsigned long byteCount = 0; +bool printWebData = true; // set to false for better speed measurement + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + Ethernet.init(10); // Most Arduino shields + //Ethernet.init(5); // MKR ETH shield + //Ethernet.init(0); // Teensy 2.0 + //Ethernet.init(20); // Teensy++ 2.0 + //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + // try to configure using IP address instead of DHCP: + Ethernet.begin(mac, ip, myDns); + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + // give the Ethernet shield a second to initialize: + delay(2000); + + Serial.print("connecting to "); + Serial.print(server); + Serial.println("..."); + + // if you get a connection, report back via serial: + auto start = millis(); + // specify the server and port, 443 is the standard port for HTTPS + if (client.connect(server, 443)) { + auto time = millis() - start; + Serial.print("connected to "); + Serial.println(client.remoteIP()); + Serial.print("Took: "); + Serial.println(time); + // Make a HTTP request: + client.println("GET /asciilogo.txt HTTP/1.1"); + client.println("User-Agent: SSLClientOverEthernet"); + client.print("Host: "); + client.println(server_host); + client.println("Connection: close"); + client.println(); + } else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } + beginMicros = micros(); +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + int len = client.available(); + if (len > 0) { + byte buffer[80]; + if (len > 80) len = 80; + client.read(buffer, len); + if (printWebData) { + Serial.write(buffer, len); // show in the serial monitor (slows some boards) + } + byteCount = byteCount + len; + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + endMicros = micros(); + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + Serial.print("Received "); + Serial.print(byteCount); + Serial.print(" bytes in "); + float seconds = (float)(endMicros - beginMicros) / 1000000.0; + Serial.print(seconds, 4); + float rate = (float)byteCount / seconds / 1000.0; + Serial.print(", rate = "); + Serial.print(rate); + Serial.print(" kbytes/second"); + Serial.println(); + + // do nothing forevermore: + while (true) { + delay(1); + } + } +} diff --git a/examples/EthernetHTTPS/trust_anchors.h b/examples/EthernetHTTPS/trust_anchors.h new file mode 100644 index 0000000..42e8454 --- /dev/null +++ b/examples/EthernetHTTPS/trust_anchors.h @@ -0,0 +1,79 @@ +#ifndef _CERTIFICATES_H_ +#define _CERTIFICATES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. + * Certificates are BearSSL br_x509_trust_anchor format. Included certs: + * + * Index: 0 + * Label: Starfield Class 2 Certification Authority + * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority + * Domain(s): www.arduino.cc + */ + +#define TAs_NUM 1 + +static const unsigned char TA_DN0[] = { + 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, + 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, + 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, +}; + +static const unsigned char TA_RSA_N0[] = { + 0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11, + 0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab, + 0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b, + 0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec, + 0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0, + 0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66, + 0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb, + 0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26, + 0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a, + 0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4, + 0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66, + 0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b, + 0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51, + 0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c, + 0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3, + 0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c, + 0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64, + 0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87, + 0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b, + 0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d, + 0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2, + 0x44, 0xa0, 0x01, 0xab, +}; + +static const unsigned char TA_RSA_E0[] = { + 0x03, +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef _CERTIFICATES_H_ */ \ No newline at end of file diff --git a/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino new file mode 100644 index 0000000..debc697 --- /dev/null +++ b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino @@ -0,0 +1,167 @@ +/* + Multi Domain HTTPS Client + + This sketch connects to a website (http://www.arduino.cc/asciilogo.txt) + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Noah Koontz, based on work by Adrian McEwen and Tom Igoe + + */ + + + // NOTE: The Ethernet library MUST be modified to use this example! + // For more detailed instructions check out https://github.com/OPEnSLab-OSU/SSLClient#sslclient-with-ethernet + +#include +#include +#include +#include "trustanchors.h" +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + +// the two domains we want to query +char server1[] = "www.arduino.cc"; +char server2[] = "www.cloudflare.com"; +// and the queries we want to send to them +char query1[] = "GET /asciilogo.txt HTTP/1.1"; +char query2[] = "GET /cdn-cgi/trace HTTP/1.1"; + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 177); +IPAddress myDns(8, 8, 8, 8); + +// Choose the analog pin to get semi-random data from for SSL +// Pick a pin that's not connected or attached to a randomish voltage source +const int rand_pin = A7; + +// Initialize the SSL client library +// We input an EthernetClient, our trust anchors, and the analog pin +// Additionally specify that we want to store 2 sessions since we are connecting to 2 domains +SSLClient client(EthernetClient(), TAs, (size_t)TAs_NUM, rand_pin); +// Variables to measure the speed +unsigned long beginMicros, endMicros; +unsigned long byteCount = 0; +bool printWebData = true; // set to false for better speed measurement + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + Ethernet.init(10); // Most Arduino shields + //Ethernet.init(5); // MKR ETH shield + //Ethernet.init(0); // Teensy 2.0 + //Ethernet.init(20); // Teensy++ 2.0 + //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + // try to congifure using IP address instead of DHCP: + Ethernet.begin(mac, ip, myDns); + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + // give the Ethernet shield a second to initialize: + delay(2000); + // connect! + connectSSL(); +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + int len = client.available(); + if (len > 0) { + byte buffer[80]; + if (len > 80) len = 80; + client.read(buffer, len); + if (printWebData) { + Serial.write(buffer, len); // show in the serial monitor (slows some boards) + } + byteCount = byteCount + len; + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + endMicros = micros(); + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + Serial.print("Received "); + Serial.print(byteCount); + Serial.print(" bytes in "); + float seconds = (float)(endMicros - beginMicros) / 1000000.0; + Serial.print(seconds, 4); + float rate = (float)byteCount / seconds / 1000.0; + Serial.print(", rate = "); + Serial.print(rate); + Serial.print(" kbytes/second"); + Serial.println(); + + //quick delay + delay(1000); + // connect again! + connectSSL(); + } +} + +bool r = false; + +void connectSSL() { + // cycle the server we want to connect to back and forth + char* server; + if (r) server = server1; + else server = server2; + r = !r; + + Serial.print("connecting to "); + Serial.print(server); + Serial.println("..."); + + // if you get a connection, report back via serial: + auto start = millis(); + if (client.connect(server, 443)) { + auto time = millis() - start; + Serial.print("connected to "); + Serial.println(client.remoteIP()); + Serial.print("Took: "); + Serial.println(time); + // Make a HTTP request: + if (server == server1) client.println(query1); + else client.println(query2); + client.println("User-Agent: SSLClientOverEthernet"); + client.print("Host: "); + client.println(server); + client.println("Connection: close"); + client.println(); + client.flush(); + } else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } + beginMicros = micros(); +} diff --git a/examples/EthernetMultiHTTPS/trustanchors.h b/examples/EthernetMultiHTTPS/trustanchors.h new file mode 100644 index 0000000..9864cda --- /dev/null +++ b/examples/EthernetMultiHTTPS/trustanchors.h @@ -0,0 +1,137 @@ +#ifndef _CERTIFICATES_H_ +#define _CERTIFICATES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. + * Certificates are BearSSL br_x509_trust_anchor format. Included certs: + * + * Index: 0 + * Label: Starfield Class 2 Certification Authority + * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority + * Domain(s): www.arduino.cc + * + * Index: 1 + * Label: DigiCert High Assurance EV Root CA + * Subject: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert High Assurance EV Root CA + * Domain(s): www.cloudflare.com + */ + +#define TAs_NUM 2 + +static const unsigned char TA_DN0[] = { + 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, + 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, + 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, +}; + +static const unsigned char TA_RSA_N0[] = { + 0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11, + 0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab, + 0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b, + 0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec, + 0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0, + 0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66, + 0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb, + 0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26, + 0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a, + 0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4, + 0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66, + 0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b, + 0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51, + 0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c, + 0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3, + 0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c, + 0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64, + 0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87, + 0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b, + 0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d, + 0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2, + 0x44, 0xa0, 0x01, 0xab, +}; + +static const unsigned char TA_RSA_E0[] = { + 0x03, +}; + +static const unsigned char TA_DN1[] = { + 0x30, 0x6c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, + 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, + 0x6e, 0x63, 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, +}; + +static const unsigned char TA_RSA_N1[] = { + 0xc6, 0xcc, 0xe5, 0x73, 0xe6, 0xfb, 0xd4, 0xbb, 0xe5, 0x2d, 0x2d, 0x32, + 0xa6, 0xdf, 0xe5, 0x81, 0x3f, 0xc9, 0xcd, 0x25, 0x49, 0xb6, 0x71, 0x2a, + 0xc3, 0xd5, 0x94, 0x34, 0x67, 0xa2, 0x0a, 0x1c, 0xb0, 0x5f, 0x69, 0xa6, + 0x40, 0xb1, 0xc4, 0xb7, 0xb2, 0x8f, 0xd0, 0x98, 0xa4, 0xa9, 0x41, 0x59, + 0x3a, 0xd3, 0xdc, 0x94, 0xd6, 0x3c, 0xdb, 0x74, 0x38, 0xa4, 0x4a, 0xcc, + 0x4d, 0x25, 0x82, 0xf7, 0x4a, 0xa5, 0x53, 0x12, 0x38, 0xee, 0xf3, 0x49, + 0x6d, 0x71, 0x91, 0x7e, 0x63, 0xb6, 0xab, 0xa6, 0x5f, 0xc3, 0xa4, 0x84, + 0xf8, 0x4f, 0x62, 0x51, 0xbe, 0xf8, 0xc5, 0xec, 0xdb, 0x38, 0x92, 0xe3, + 0x06, 0xe5, 0x08, 0x91, 0x0c, 0xc4, 0x28, 0x41, 0x55, 0xfb, 0xcb, 0x5a, + 0x89, 0x15, 0x7e, 0x71, 0xe8, 0x35, 0xbf, 0x4d, 0x72, 0x09, 0x3d, 0xbe, + 0x3a, 0x38, 0x50, 0x5b, 0x77, 0x31, 0x1b, 0x8d, 0xb3, 0xc7, 0x24, 0x45, + 0x9a, 0xa7, 0xac, 0x6d, 0x00, 0x14, 0x5a, 0x04, 0xb7, 0xba, 0x13, 0xeb, + 0x51, 0x0a, 0x98, 0x41, 0x41, 0x22, 0x4e, 0x65, 0x61, 0x87, 0x81, 0x41, + 0x50, 0xa6, 0x79, 0x5c, 0x89, 0xde, 0x19, 0x4a, 0x57, 0xd5, 0x2e, 0xe6, + 0x5d, 0x1c, 0x53, 0x2c, 0x7e, 0x98, 0xcd, 0x1a, 0x06, 0x16, 0xa4, 0x68, + 0x73, 0xd0, 0x34, 0x04, 0x13, 0x5c, 0xa1, 0x71, 0xd3, 0x5a, 0x7c, 0x55, + 0xdb, 0x5e, 0x64, 0xe1, 0x37, 0x87, 0x30, 0x56, 0x04, 0xe5, 0x11, 0xb4, + 0x29, 0x80, 0x12, 0xf1, 0x79, 0x39, 0x88, 0xa2, 0x02, 0x11, 0x7c, 0x27, + 0x66, 0xb7, 0x88, 0xb7, 0x78, 0xf2, 0xca, 0x0a, 0xa8, 0x38, 0xab, 0x0a, + 0x64, 0xc2, 0xbf, 0x66, 0x5d, 0x95, 0x84, 0xc1, 0xa1, 0x25, 0x1e, 0x87, + 0x5d, 0x1a, 0x50, 0x0b, 0x20, 0x12, 0xcc, 0x41, 0xbb, 0x6e, 0x0b, 0x51, + 0x38, 0xb8, 0x4b, 0xcb, +}; + +static const unsigned char TA_RSA_E1[] = { + 0x01, 0x00, 0x01, +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, + { + { (unsigned char *)TA_DN1, sizeof TA_DN1 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N1, sizeof TA_RSA_N1, + (unsigned char *)TA_RSA_E1, sizeof TA_RSA_E1, + } } + } + }, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef _CERTIFICATES_H_ */ diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index f743d69..12efbf4 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -343,7 +343,7 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { setWriteError(SSL_BR_CONNECT_FAIL); return 0; } - // initlalize the SSL socket over the network + // initialize the SSL socket over the network // normally this would happen in write, but I think it makes // a little more structural sense to put it here if (m_run_until(BR_SSL_SENDAPP) < 0) { From 8753a7f9184fdd188f9969792d959f8b0cd3acd3 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 1 Apr 2019 19:04:23 -0700 Subject: [PATCH 046/205] updated doxygen generated documentation --- .../dir_386349f6a9bc1e2cd0767d257d5e5b91.html | 112 +++++++++++++++ .../dir_386349f6a9bc1e2cd0767d257d5e5b91.js | 4 + .../dir_9c42dc81377249a918256dbb9cfb2167.html | 112 +++++++++++++++ .../dir_9c42dc81377249a918256dbb9cfb2167.js | 4 + .../dir_d28a4824dc47e487b107a5db32ef43c4.html | 114 +++++++++++++++ .../dir_d28a4824dc47e487b107a5db32ef43c4.js | 5 + docs/html/files.html | 27 ++-- docs/html/files_dup.js | 1 + docs/html/globals.html | 4 +- docs/html/globals_defs.html | 4 +- docs/html/index.html | 13 +- docs/html/navtreeindex0.js | 115 ++++++++------- docs/html/search/all_f.js | 4 +- docs/html/search/defines_5.js | 2 +- docs/html/search/files_3.js | 2 + docs/html/trust__anchors_8h.html | 131 ++++++++++++++++++ docs/html/trust__anchors_8h.js | 4 + docs/html/trust__anchors_8h_source.html | 106 ++++++++++++++ docs/html/trustanchors_8h.html | 131 ++++++++++++++++++ docs/html/trustanchors_8h.js | 4 + docs/html/trustanchors_8h_source.html | 106 ++++++++++++++ 21 files changed, 933 insertions(+), 72 deletions(-) create mode 100644 docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html create mode 100644 docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.js create mode 100644 docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html create mode 100644 docs/html/dir_9c42dc81377249a918256dbb9cfb2167.js create mode 100644 docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html create mode 100644 docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js create mode 100644 docs/html/trust__anchors_8h.html create mode 100644 docs/html/trust__anchors_8h.js create mode 100644 docs/html/trust__anchors_8h_source.html create mode 100644 docs/html/trustanchors_8h.html create mode 100644 docs/html/trustanchors_8h.js create mode 100644 docs/html/trustanchors_8h_source.html diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html new file mode 100644 index 0000000..125fbda --- /dev/null +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -0,0 +1,112 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/examples/EthernetMultiHTTPS Directory Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    EthernetMultiHTTPS Directory Reference
    +
    +
    + + + + +

    +Files

    file  trustanchors.h [code]
     
    +
    +
    + + + + diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.js b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.js new file mode 100644 index 0000000..d585d54 --- /dev/null +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.js @@ -0,0 +1,4 @@ +var dir_386349f6a9bc1e2cd0767d257d5e5b91 = +[ + [ "trustanchors.h", "trustanchors_8h.html", "trustanchors_8h" ] +]; \ No newline at end of file diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html new file mode 100644 index 0000000..36b29ce --- /dev/null +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -0,0 +1,112 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/examples/EthernetHTTPS Directory Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    EthernetHTTPS Directory Reference
    +
    +
    + + + + +

    +Files

    file  trust_anchors.h [code]
     
    +
    +
    + + + + diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.js b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.js new file mode 100644 index 0000000..aa63327 --- /dev/null +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.js @@ -0,0 +1,4 @@ +var dir_9c42dc81377249a918256dbb9cfb2167 = +[ + [ "trust_anchors.h", "trust__anchors_8h.html", "trust__anchors_8h" ] +]; \ No newline at end of file diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html new file mode 100644 index 0000000..46d074e --- /dev/null +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -0,0 +1,114 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/examples Directory Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    examples Directory Reference
    +
    +
    + + + + + + +

    +Directories

    directory  EthernetHTTPS
     
    directory  EthernetMultiHTTPS
     
    +
    +
    + + + + diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js new file mode 100644 index 0000000..55474cc --- /dev/null +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js @@ -0,0 +1,5 @@ +var dir_d28a4824dc47e487b107a5db32ef43c4 = +[ + [ "EthernetHTTPS", "dir_9c42dc81377249a918256dbb9cfb2167.html", "dir_9c42dc81377249a918256dbb9cfb2167" ], + [ "EthernetMultiHTTPS", "dir_386349f6a9bc1e2cd0767d257d5e5b91.html", "dir_386349f6a9bc1e2cd0767d257d5e5b91" ] +]; \ No newline at end of file diff --git a/docs/html/files.html b/docs/html/files.html index 8f6b208..5be5ad7 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -92,17 +92,22 @@ $(document).ready(function(){initNavTree('files.html','');});
    Here is a list of all files with brief descriptions:
    diff --git a/docs/html/files_dup.js b/docs/html/files_dup.js index 282bf42..84896af 100644 --- a/docs/html/files_dup.js +++ b/docs/html/files_dup.js @@ -1,5 +1,6 @@ var files_dup = [ + [ "examples", "dir_d28a4824dc47e487b107a5db32ef43c4.html", "dir_d28a4824dc47e487b107a5db32ef43c4" ], [ "readme", "dir_dfc5a9f91fbfb9426c406a3f10131a54.html", "dir_dfc5a9f91fbfb9426c406a3f10131a54" ], [ "src", "dir_68267d1309a1af8e8297ef4c3efbcdba.html", "dir_68267d1309a1af8e8297ef4c3efbcdba" ] ]; \ No newline at end of file diff --git a/docs/html/globals.html b/docs/html/globals.html index ba0590e..06ac476 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -228,7 +228,9 @@ $(document).ready(function(){initNavTree('globals.html','');});

    - t -

    diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index 08d9a11..29e9042 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -149,7 +149,9 @@ $(document).ready(function(){initNavTree('globals_defs.html','');}); : SSLClient.h
  • TAs_NUM -: cert.h +: trust_anchors.h +, cert.h +, trustanchors.h
  • UNIX_TIMESTAMP : time_macros.h diff --git a/docs/html/index.html b/docs/html/index.html index 39317ee..9a78c88 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -92,14 +92,15 @@ $(document).ready(function(){initNavTree('index.html','');});

    SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.

    +

    You can also view this README in doxygen.

    SSLClient is a simple library to add TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it.

    Overview

    Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with EthernetClient. There are a few extra things, however, that you will need to get started:

      -
    1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Notes).
    2. +
    3. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Gotchas).
    4. A header containing array of trust anchors, which will look like this file. These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out this document on how to generate this file for your project, and for more information about what a trust anchor is.
    5. A Client class associated with a network interface. We tested this library using EthernetClient, however in theory it will work for any class implementing Client.
    6. -
    7. An analog pin, used for generating random data at the start of the connection (see the Implementation Notes).
    8. +
    9. An analog pin, used for generating random data at the start of the connection (see the Implementation Gotchas).

    Once all those are ready, you can create a simple SSLClient object like this:

    {C++}
    SSLClient<BaseClientType> client(BaseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin);

    Where:

    • BaseClientType - The type of BaseClientInstance
    • @@ -107,10 +108,10 @@ $(document).ready(function(){initNavTree('index.html','');});
    • TAs - The name of the trust anchor array created in step 2. If you generated a header using the tutorial this will probably be TAs.
    • TAs_NUM - The number of trust anchors in TAs. If you generated a header using the tutorial this will probably be TAs_NUM.
    • AnalogPin - The analog pin to pull random data from (step 4).

      -

      For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using:

      {C++}
      SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);

      Once that is setup, simply use SSLClient as you would the base client class:

      {C++}
      // connect to ardiuino.cc over ssl (port 443 for websites)
      client.connect("www.arduino.cc", 443);
      // Make a HTTP request
      client.println("GET /asciilogo.txt HTTP/1.1");
      client.println("User-Agent: AdafruitFeatherM0WiFi");
      client.print("Host: ");
      client.println(server);
      client.println("Connection: close");
      client.println();
      client.flush();
      // read and print the data
      ...

      Note: client.connect("www.arduino.cc", 443) can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in Implementation Notes.

      +

      For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using:

      {C++}
      SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);

      Once that is setup, simply use SSLClient as you would the base client class:

      {C++}
      // connect to ardiuino.cc over ssl (port 443 for websites)
      client.connect("www.arduino.cc", 443);
      // Make a HTTP request
      client.println("GET /asciilogo.txt HTTP/1.1");
      client.println("User-Agent: AdafruitFeatherM0WiFi");
      client.print("Host: ");
      client.println(server);
      client.println("Connection: close");
      client.println();
      client.flush();
      // read and print the data
      ...

      Note: client.connect("www.arduino.cc", 443) can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in Implementation Notes.

    -

    For more information on SSLClient, check out the examples, API documentation, or the rest of this README.

    +

    For more information on SSLClient, check out the examples, API documentation, or the rest of this README.

    How It Works

    SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant BearSSL as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, making debugging a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint.

    Additionally, the bulk of SSLClient is split into two components: a template class SSLClient, and an implementation class SSLClientImpl. The template class serves to abstract some functions not implemented in the Arduino Client interface (such as EthernetClient::remoteIP), and the implementation class is the rest of the SSLClient library.

    @@ -136,6 +137,10 @@ $(document).ready(function(){initNavTree('index.html','');});

    If you need to clear a session, you can do so using the SSLSession::removeSession function.

    Implementation Gotchas

    Some ideas that didn't quite fit in the API documentation.

    +

    SSLClient with Ethernet

    +

    If you are using the Arduino Ethernet library, you will need to modify the library to support the large buffer sizes required by SSL (detailed in resources). To do this, first find the location of the library in the directory where Arduino is installed (C:\Program Files (x86)\Arduino on Windows). Inside of this directory, navigate to libraries\Ethernet\src (C:\Program Files (x86)\Arduino\libraries\Ethernet\src on Windows). Modify Ethernet.h to replace these lines:

    {C++}
    ...
    // Configure the maximum number of sockets to support. W5100 chips can have
    // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
    // of RAM are used for each socket. Reducing the maximum can save RAM, but
    // you are limited to fewer simultaneous connections.
    #if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048)
    #define MAX_SOCK_NUM 4
    #else
    #define MAX_SOCK_NUM 8
    #endif
    // By default, each socket uses 2K buffers inside the Wiznet chip. If
    // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
    // this will use larger buffers within the Wiznet chip. Large buffers
    // can really help with UDP protocols like Artnet. In theory larger
    // buffers should allow faster TCP over high-latency links, but this
    // does not always seem to work in practice (maybe Wiznet bugs?)
    //#define ETHERNET_LARGE_BUFFERS
    ...

    With this:

    {C++}
    ...
    // Configure the maximum number of sockets to support. W5100 chips can have
    // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
    // of RAM are used for each socket. Reducing the maximum can save RAM, but
    // you are limited to fewer simultaneous connections.
    #define MAX_SOCK_NUM 2
    // By default, each socket uses 2K buffers inside the Wiznet chip. If
    // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
    // this will use larger buffers within the Wiznet chip. Large buffers
    // can really help with UDP protocols like Artnet. In theory larger
    // buffers should allow faster TCP over high-latency links, but this
    // does not always seem to work in practice (maybe Wiznet bugs?)
    #define ETHERNET_LARGE_BUFFERS
    ...

    You may need to use sudo or administrator permissions to make this modification. We change MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS so the Ethernet hardware can allocate a larger space for SSLClient, however a downside of this modification is we are now only able to have two sockets concurrently. As most microprocessors barely have enough memory for one SSL connection, this limitation will rarely be encountered in practice.

    +

    Random Data

    +

    The SSL protocol requires that SSLClient generate some random bits before connecting with a server. BearSSL provides a random number generator but requires a some entropy for a seed. Normally this seed is generated by taking the microsecond time using the internal clock, however since most microcontrollers are not build with this feature another source must be found. As a simple solution, SSLClient uses a floating analog pin as an external source of random data, passed through to the constructor in the analog_pin argument. Before every connection, SSLClient will take the bottom byte from 16 analog reads on analog_pin, and combine these bytes into a 16 byte random number, which is used as a seed for BearSSL. To ensure the most random data, it is recommended that this analog pin be either floating or connected to a location not modifiable by the microcontroller (i.e. a battery voltage readout).

    Certificate Verification

    SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out this document for more details on this component of SSLClient.

    BearSSL also features a known certificate validation engine, which only allows for a single domain in exchange for a significantly reduced resource usage (flash and CPU time). This functionality is planned to be implemented in the future.

    diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index 97904f6..adb9539 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -1,34 +1,34 @@ var NAVTREEINDEX0 = { -"_s_s_l_client_8h.html":[3,0,1,0], -"_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569":[3,0,1,0,1], -"_s_s_l_client_8h_source.html":[3,0,1,0], -"_s_s_l_client_impl_8cpp.html":[3,0,1,1], -"_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[3,0,1,1,0], -"_s_s_l_client_impl_8h.html":[3,0,1,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5":[3,0,1,2,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c":[3,0,1,2,2,0], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b":[3,0,1,2,2,3], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9":[3,0,1,2,2,4], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b":[3,0,1,2,2,1], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6":[3,0,1,2,2,6], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3":[3,0,1,2,2,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc":[3,0,1,2,2,5], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395":[3,0,1,2,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d":[3,0,1,2,1,2], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91":[3,0,1,2,1,3], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec":[3,0,1,2,1,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f":[3,0,1,2,1,0], -"_s_s_l_client_impl_8h_source.html":[3,0,1,2], -"_s_s_l_session_8cpp.html":[3,0,1,3], -"_s_s_l_session_8h.html":[3,0,1,4], -"_s_s_l_session_8h_source.html":[3,0,1,4], -"_t_l_s12__only__profile_8c.html":[3,0,1,6], -"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[3,0,1,6,0], +"_s_s_l_client_8h.html":[3,0,2,0], +"_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569":[3,0,2,0,1], +"_s_s_l_client_8h_source.html":[3,0,2,0], +"_s_s_l_client_impl_8cpp.html":[3,0,2,1], +"_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[3,0,2,1,0], +"_s_s_l_client_impl_8h.html":[3,0,2,2], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5":[3,0,2,2,2], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c":[3,0,2,2,2,0], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b":[3,0,2,2,2,3], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9":[3,0,2,2,2,4], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b":[3,0,2,2,2,1], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6":[3,0,2,2,2,6], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3":[3,0,2,2,2,2], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc":[3,0,2,2,2,5], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395":[3,0,2,2,1], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d":[3,0,2,2,1,2], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91":[3,0,2,2,1,3], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec":[3,0,2,2,1,1], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f":[3,0,2,2,1,0], +"_s_s_l_client_impl_8h_source.html":[3,0,2,2], +"_s_s_l_session_8cpp.html":[3,0,2,3], +"_s_s_l_session_8h.html":[3,0,2,4], +"_s_s_l_session_8h_source.html":[3,0,2,4], +"_t_l_s12__only__profile_8c.html":[3,0,2,6], +"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[3,0,2,6,0], "annotated.html":[2,0], -"cert_8h.html":[3,0,0,0], -"cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,0,0], -"cert_8h_source.html":[3,0,0,0], +"cert_8h.html":[3,0,1,0], +"cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,1,0,0], +"cert_8h_source.html":[3,0,1,0], "class_s_s_l_client.html":[2,0,0], "class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0":[2,0,0,24], "class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270":[2,0,0,26], @@ -96,8 +96,11 @@ var NAVTREEINDEX0 = "class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[2,0,2,7], "class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb":[2,0,2,0], "classes.html":[2,1], -"dir_68267d1309a1af8e8297ef4c3efbcdba.html":[3,0,1], -"dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[3,0,0], +"dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[3,0,0,1], +"dir_68267d1309a1af8e8297ef4c3efbcdba.html":[3,0,2], +"dir_9c42dc81377249a918256dbb9cfb2167.html":[3,0,0,0], +"dir_d28a4824dc47e487b107a5db32ef43c4.html":[3,0,0], +"dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[3,0,1], "files.html":[3,0], "functions.html":[2,3,0], "functions_func.html":[2,3,1], @@ -112,27 +115,33 @@ var NAVTREEINDEX0 = "index.html":[], "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[1], "pages.html":[], -"time__macros_8h.html":[3,0,1,5], -"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,1,5,19], -"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,1,5,14], -"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,1,5,1], -"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,1,5,20], -"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,1,5,16], -"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,1,5,4], -"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,1,5,15], -"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,1,5,13], -"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,1,5,5], -"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,1,5,8], -"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,1,5,0], -"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,1,5,6], -"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,1,5,18], -"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,1,5,12], -"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,1,5,11], -"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,1,5,2], -"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,1,5,7], -"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,1,5,17], -"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,1,5,3], -"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,1,5,9], -"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,1,5,10], -"time__macros_8h_source.html":[3,0,1,5] +"time__macros_8h.html":[3,0,2,5], +"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,2,5,19], +"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,2,5,14], +"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,2,5,1], +"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,2,5,20], +"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,2,5,16], +"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,2,5,4], +"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,2,5,15], +"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,2,5,13], +"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,2,5,5], +"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,2,5,8], +"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,2,5,0], +"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,2,5,6], +"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,2,5,18], +"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,2,5,12], +"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,2,5,11], +"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,2,5,2], +"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,2,5,7], +"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,2,5,17], +"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,2,5,3], +"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,2,5,9], +"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,2,5,10], +"time__macros_8h_source.html":[3,0,2,5], +"trust__anchors_8h.html":[3,0,0,0,0], +"trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,0,0,0], +"trust__anchors_8h_source.html":[3,0,0,0,0], +"trustanchors_8h.html":[3,0,0,1,0], +"trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,1,0,0], +"trustanchors_8h_source.html":[3,0,0,1,0] }; diff --git a/docs/html/search/all_f.js b/docs/html/search/all_f.js index aa9c0c5..45a40de 100644 --- a/docs/html/search/all_f.js +++ b/docs/html/search/all_f.js @@ -1,9 +1,11 @@ var searchData= [ ['trust_20anchors',['Trust Anchors',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]], - ['tas_5fnum',['TAs_NUM',['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'cert.h']]], + ['tas_5fnum',['TAs_NUM',['../trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trust_anchors.h'],['../trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trustanchors.h'],['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): cert.h']]], ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]], + ['trust_5fanchors_2eh',['trust_anchors.h',['../trust__anchors_8h.html',1,'']]], + ['trustanchors_2eh',['trustanchors.h',['../trustanchors_8h.html',1,'']]], ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] ]; diff --git a/docs/html/search/defines_5.js b/docs/html/search/defines_5.js index c10d695..5de0fdb 100644 --- a/docs/html/search/defines_5.js +++ b/docs/html/search/defines_5.js @@ -1,4 +1,4 @@ var searchData= [ - ['tas_5fnum',['TAs_NUM',['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'cert.h']]] + ['tas_5fnum',['TAs_NUM',['../trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trust_anchors.h'],['../trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trustanchors.h'],['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): cert.h']]] ]; diff --git a/docs/html/search/files_3.js b/docs/html/search/files_3.js index 377b9b8..a75f15b 100644 --- a/docs/html/search/files_3.js +++ b/docs/html/search/files_3.js @@ -2,5 +2,7 @@ var searchData= [ ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], + ['trust_5fanchors_2eh',['trust_anchors.h',['../trust__anchors_8h.html',1,'']]], + ['trustanchors_2eh',['trustanchors.h',['../trustanchors_8h.html',1,'']]], ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] ]; diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html new file mode 100644 index 0000000..a9424eb --- /dev/null +++ b/docs/html/trust__anchors_8h.html @@ -0,0 +1,131 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/examples/EthernetHTTPS/trust_anchors.h File Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    trust_anchors.h File Reference
    +
    +
    + +

    Go to the source code of this file.

    + + + + +

    +Macros

    #define TAs_NUM   1
     
    +

    Macro Definition Documentation

    + +

    ◆ TAs_NUM

    + +
    +
    + + + + +
    #define TAs_NUM   1
    +
    + +
    +
    +
    +
    + + + + diff --git a/docs/html/trust__anchors_8h.js b/docs/html/trust__anchors_8h.js new file mode 100644 index 0000000..54e567a --- /dev/null +++ b/docs/html/trust__anchors_8h.js @@ -0,0 +1,4 @@ +var trust__anchors_8h = +[ + [ "TAs_NUM", "trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948", null ] +]; \ No newline at end of file diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html new file mode 100644 index 0000000..c6e8c34 --- /dev/null +++ b/docs/html/trust__anchors_8h_source.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/examples/EthernetHTTPS/trust_anchors.h Source File + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    trust_anchors.h
    +
    +
    +Go to the documentation of this file.
    1 #ifndef _CERTIFICATES_H_
    2 #define _CERTIFICATES_H_
    3 
    4 #ifdef __cplusplus
    5 extern "C"
    6 {
    7 #endif
    8 
    9 /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually.
    10  * Certificates are BearSSL br_x509_trust_anchor format. Included certs:
    11  *
    12  * Index: 0
    13  * Label: Starfield Class 2 Certification Authority
    14  * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority
    15  * Domain(s): www.arduino.cc
    16  */
    17 
    18 #define TAs_NUM 1
    19 
    20 static const unsigned char TA_DN0[] = {
    21  0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
    22  0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
    23  0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
    24  0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73,
    25  0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03,
    26  0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65,
    27  0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43,
    28  0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
    29  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
    30 };
    31 
    32 static const unsigned char TA_RSA_N0[] = {
    33  0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11,
    34  0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab,
    35  0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b,
    36  0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec,
    37  0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0,
    38  0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66,
    39  0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb,
    40  0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26,
    41  0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a,
    42  0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4,
    43  0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66,
    44  0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b,
    45  0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51,
    46  0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c,
    47  0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3,
    48  0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c,
    49  0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64,
    50  0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87,
    51  0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b,
    52  0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d,
    53  0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2,
    54  0x44, 0xa0, 0x01, 0xab,
    55 };
    56 
    57 static const unsigned char TA_RSA_E0[] = {
    58  0x03,
    59 };
    60 
    61 static const br_x509_trust_anchor TAs[] = {
    62  {
    63  { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    64  BR_X509_TA_CA,
    65  {
    66  BR_KEYTYPE_RSA,
    67  { .rsa = {
    68  (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
    69  (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
    70  } }
    71  }
    72  },
    73 };
    74 
    75 #ifdef __cplusplus
    76 } /* extern "C" */
    77 #endif
    78 
    79 #endif /* ifndef _CERTIFICATES_H_ */
    +
    + + + + diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html new file mode 100644 index 0000000..5c6825e --- /dev/null +++ b/docs/html/trustanchors_8h.html @@ -0,0 +1,131 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/examples/EthernetMultiHTTPS/trustanchors.h File Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    trustanchors.h File Reference
    +
    +
    + +

    Go to the source code of this file.

    + + + + +

    +Macros

    #define TAs_NUM   2
     
    +

    Macro Definition Documentation

    + +

    ◆ TAs_NUM

    + +
    +
    + + + + +
    #define TAs_NUM   2
    +
    + +
    +
    +
    +
    + + + + diff --git a/docs/html/trustanchors_8h.js b/docs/html/trustanchors_8h.js new file mode 100644 index 0000000..a9b507e --- /dev/null +++ b/docs/html/trustanchors_8h.js @@ -0,0 +1,4 @@ +var trustanchors_8h = +[ + [ "TAs_NUM", "trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948", null ] +]; \ No newline at end of file diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html new file mode 100644 index 0000000..abd360c --- /dev/null +++ b/docs/html/trustanchors_8h_source.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/examples/EthernetMultiHTTPS/trustanchors.h Source File + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  1.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    trustanchors.h
    +
    +
    +Go to the documentation of this file.
    1 #ifndef _CERTIFICATES_H_
    2 #define _CERTIFICATES_H_
    3 
    4 #ifdef __cplusplus
    5 extern "C"
    6 {
    7 #endif
    8 
    9 /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually.
    10  * Certificates are BearSSL br_x509_trust_anchor format. Included certs:
    11  *
    12  * Index: 0
    13  * Label: Starfield Class 2 Certification Authority
    14  * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority
    15  * Domain(s): www.arduino.cc
    16  *
    17  * Index: 1
    18  * Label: DigiCert High Assurance EV Root CA
    19  * Subject: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert High Assurance EV Root CA
    20  * Domain(s): www.cloudflare.com
    21  */
    22 
    23 #define TAs_NUM 2
    24 
    25 static const unsigned char TA_DN0[] = {
    26  0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
    27  0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
    28  0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
    29  0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73,
    30  0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03,
    31  0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65,
    32  0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43,
    33  0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
    34  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
    35 };
    36 
    37 static const unsigned char TA_RSA_N0[] = {
    38  0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11,
    39  0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab,
    40  0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b,
    41  0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec,
    42  0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0,
    43  0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66,
    44  0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb,
    45  0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26,
    46  0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a,
    47  0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4,
    48  0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66,
    49  0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b,
    50  0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51,
    51  0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c,
    52  0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3,
    53  0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c,
    54  0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64,
    55  0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87,
    56  0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b,
    57  0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d,
    58  0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2,
    59  0x44, 0xa0, 0x01, 0xab,
    60 };
    61 
    62 static const unsigned char TA_RSA_E0[] = {
    63  0x03,
    64 };
    65 
    66 static const unsigned char TA_DN1[] = {
    67  0x30, 0x6c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
    68  0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a,
    69  0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49,
    70  0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
    71  0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72,
    72  0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55,
    73  0x04, 0x03, 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
    74  0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61,
    75  0x6e, 0x63, 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
    76  0x43, 0x41,
    77 };
    78 
    79 static const unsigned char TA_RSA_N1[] = {
    80  0xc6, 0xcc, 0xe5, 0x73, 0xe6, 0xfb, 0xd4, 0xbb, 0xe5, 0x2d, 0x2d, 0x32,
    81  0xa6, 0xdf, 0xe5, 0x81, 0x3f, 0xc9, 0xcd, 0x25, 0x49, 0xb6, 0x71, 0x2a,
    82  0xc3, 0xd5, 0x94, 0x34, 0x67, 0xa2, 0x0a, 0x1c, 0xb0, 0x5f, 0x69, 0xa6,
    83  0x40, 0xb1, 0xc4, 0xb7, 0xb2, 0x8f, 0xd0, 0x98, 0xa4, 0xa9, 0x41, 0x59,
    84  0x3a, 0xd3, 0xdc, 0x94, 0xd6, 0x3c, 0xdb, 0x74, 0x38, 0xa4, 0x4a, 0xcc,
    85  0x4d, 0x25, 0x82, 0xf7, 0x4a, 0xa5, 0x53, 0x12, 0x38, 0xee, 0xf3, 0x49,
    86  0x6d, 0x71, 0x91, 0x7e, 0x63, 0xb6, 0xab, 0xa6, 0x5f, 0xc3, 0xa4, 0x84,
    87  0xf8, 0x4f, 0x62, 0x51, 0xbe, 0xf8, 0xc5, 0xec, 0xdb, 0x38, 0x92, 0xe3,
    88  0x06, 0xe5, 0x08, 0x91, 0x0c, 0xc4, 0x28, 0x41, 0x55, 0xfb, 0xcb, 0x5a,
    89  0x89, 0x15, 0x7e, 0x71, 0xe8, 0x35, 0xbf, 0x4d, 0x72, 0x09, 0x3d, 0xbe,
    90  0x3a, 0x38, 0x50, 0x5b, 0x77, 0x31, 0x1b, 0x8d, 0xb3, 0xc7, 0x24, 0x45,
    91  0x9a, 0xa7, 0xac, 0x6d, 0x00, 0x14, 0x5a, 0x04, 0xb7, 0xba, 0x13, 0xeb,
    92  0x51, 0x0a, 0x98, 0x41, 0x41, 0x22, 0x4e, 0x65, 0x61, 0x87, 0x81, 0x41,
    93  0x50, 0xa6, 0x79, 0x5c, 0x89, 0xde, 0x19, 0x4a, 0x57, 0xd5, 0x2e, 0xe6,
    94  0x5d, 0x1c, 0x53, 0x2c, 0x7e, 0x98, 0xcd, 0x1a, 0x06, 0x16, 0xa4, 0x68,
    95  0x73, 0xd0, 0x34, 0x04, 0x13, 0x5c, 0xa1, 0x71, 0xd3, 0x5a, 0x7c, 0x55,
    96  0xdb, 0x5e, 0x64, 0xe1, 0x37, 0x87, 0x30, 0x56, 0x04, 0xe5, 0x11, 0xb4,
    97  0x29, 0x80, 0x12, 0xf1, 0x79, 0x39, 0x88, 0xa2, 0x02, 0x11, 0x7c, 0x27,
    98  0x66, 0xb7, 0x88, 0xb7, 0x78, 0xf2, 0xca, 0x0a, 0xa8, 0x38, 0xab, 0x0a,
    99  0x64, 0xc2, 0xbf, 0x66, 0x5d, 0x95, 0x84, 0xc1, 0xa1, 0x25, 0x1e, 0x87,
    100  0x5d, 0x1a, 0x50, 0x0b, 0x20, 0x12, 0xcc, 0x41, 0xbb, 0x6e, 0x0b, 0x51,
    101  0x38, 0xb8, 0x4b, 0xcb,
    102 };
    103 
    104 static const unsigned char TA_RSA_E1[] = {
    105  0x01, 0x00, 0x01,
    106 };
    107 
    108 static const br_x509_trust_anchor TAs[] = {
    109  {
    110  { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    111  BR_X509_TA_CA,
    112  {
    113  BR_KEYTYPE_RSA,
    114  { .rsa = {
    115  (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
    116  (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
    117  } }
    118  }
    119  },
    120  {
    121  { (unsigned char *)TA_DN1, sizeof TA_DN1 },
    122  BR_X509_TA_CA,
    123  {
    124  BR_KEYTYPE_RSA,
    125  { .rsa = {
    126  (unsigned char *)TA_RSA_N1, sizeof TA_RSA_N1,
    127  (unsigned char *)TA_RSA_E1, sizeof TA_RSA_E1,
    128  } }
    129  }
    130  },
    131 };
    132 
    133 #ifdef __cplusplus
    134 } /* extern "C" */
    135 #endif
    136 
    137 #endif /* ifndef _CERTIFICATES_H_ */
    +
    + + + + From 28e1555e762e57f9e26bfb7fc5709ac2a4b5f2a1 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 20 May 2019 16:15:08 -0700 Subject: [PATCH 047/205] removed virtual, added override specifiers, regenerated documentation --- docs/html/_s_s_l_client_8h_source.html | 52 +-- docs/html/class_s_s_l_client-members.html | 52 +-- docs/html/class_s_s_l_client.html | 378 +++++++++--------- docs/html/class_s_s_l_client.js | 52 +-- docs/html/class_s_s_l_client_impl.html | 50 +-- docs/html/functions.html | 38 +- docs/html/functions_func.html | 38 +- docs/html/index.html | 6 +- ...ibraries__s_s_l_client__trust_anchors.html | 2 +- docs/html/navtreeindex0.js | 52 +-- docs/html/search/all_1.js | 2 +- docs/html/search/all_11.js | 2 +- docs/html/search/all_3.js | 4 +- docs/html/search/all_6.js | 2 +- docs/html/search/all_7.js | 8 +- docs/html/search/all_9.js | 2 +- docs/html/search/all_b.js | 6 +- docs/html/search/all_c.js | 2 +- docs/html/search/all_d.js | 8 +- docs/html/search/all_e.js | 2 +- docs/html/search/functions_0.js | 2 +- docs/html/search/functions_2.js | 4 +- docs/html/search/functions_3.js | 2 +- docs/html/search/functions_4.js | 8 +- docs/html/search/functions_6.js | 2 +- docs/html/search/functions_8.js | 6 +- docs/html/search/functions_9.js | 2 +- docs/html/search/functions_a.js | 8 +- docs/html/search/functions_b.js | 2 +- docs/html/search/functions_d.js | 2 +- src/SSLClient.h | 52 +-- 31 files changed, 424 insertions(+), 424 deletions(-) diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index b5a6df8..399ab6a 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -91,51 +91,51 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
    SSLClient.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include <type_traits>
    22 #include "Client.h"
    23 #include "SSLClientImpl.h"
    24 #include "SSLSession.h"
    25 
    26 #ifndef SSLClient_H_
    27 #define SSLClient_H_
    28 
    34 template <class C, size_t SessionCache = 1>
    35 class SSLClient : public SSLClientImpl {
    36 /*
    37  * static checks
    38  * I'm a java developer, so I want to ensure that my inheritance is safe.
    39  * These checks ensure that all the functions we use on class C are
    40  * actually present on class C. It does this by checking that the
    41  * class inherits from Client.
    42  *
    43  * Additionally, I ran into a lot of memory issues with large sessions caches.
    44  * Since each session contains at max 352 bytes of memory, they eat of the
    45  * stack quite quickly and can cause overflows. As a result, I have added a
    46  * warning here to discourage the use of more than 3 sessions at a time. Any
    47  * amount past that will require special modification of this library, and
    48  * assumes you know what you are doing.
    49  */
    50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
    51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
    52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
    53 
    54 public:
    71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
    72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
    73  , m_client(client)
    74  , m_sessions{SSLSession()}
    75  {
    76  // set the timeout to a reasonable number (it can always be changes later)
    77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
    78  setTimeout(10 * 1000);
    79  }
    80 
    81  //========================================
    82  //= Functions implemented in SSLClientImpl
    83  //========================================
    84 
    124  virtual int connect(IPAddress ip, uint16_t port) { return connect_impl(ip, port); }
    125 
    162  virtual int connect(const char *host, uint16_t port) { return connect_impl(host, port); }
    163 
    165  virtual size_t write(uint8_t b) { return write_impl(&b, 1); }
    189  virtual size_t write(const uint8_t *buf, size_t size) { return write_impl(buf, size); }
    190 
    209  virtual int available() { return available_impl(); }
    210 
    215  virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    237  virtual int read(uint8_t *buf, size_t size) { return read_impl(buf, size); }
    238 
    247  virtual int peek() { return peek_impl(); }
    248 
    256  virtual void flush() { return flush_impl(); }
    257 
    266  virtual void stop() { return stop_impl(); }
    267 
    280  virtual uint8_t connected() { return connected_impl(); }
    281 
    282  //========================================
    283  //= Functions Not in the Client Interface
    284  //========================================
    285 
    300  virtual SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
    301 
    310  virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
    311 
    317  virtual size_t getSessionCount() const { return SessionCache; }
    318 
    324  virtual operator bool() { return connected() > 0; }
    326  virtual bool operator==(const bool value) { return bool() == value; }
    328  virtual bool operator!=(const bool value) { return bool() != value; }
    330  virtual bool operator==(const C& rhs) { return m_client == rhs; }
    332  virtual bool operator!=(const C& rhs) { return m_client != rhs; }
    334  virtual uint16_t localPort() {
    335  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
    336  else {
    337  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
    338  return 0;
    339  }
    340  }
    342  virtual IPAddress remoteIP() {
    343  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
    344  else {
    345  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
    346  return INADDR_NONE;
    347  }
    348  }
    350  virtual uint16_t remotePort() {
    351  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
    352  else {
    353  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
    354  return 0;
    355  }
    356  }
    357 
    359  C& getClient() { return m_client; }
    360 
    361 protected:
    363  virtual Client& get_arduino_client() { return m_client; }
    364  virtual const Client& get_arduino_client() const { return m_client; }
    366  virtual SSLSession* get_session_array() { return m_sessions; }
    367  virtual const SSLSession* get_session_array() const { return m_sessions; }
    368 
    369 private:
    370  // create a copy of the client
    371  C m_client;
    372  // also store an array of SSLSessions, so we can resume communication with multiple websites
    373  SSLSession m_sessions[SessionCache];
    374 };
    375 
    376 #endif
    virtual uint8_t connected()
    Check if the device is connected.
    Definition: SSLClient.h:280
    -
    virtual bool operator!=(const bool value)
    Definition: SSLClient.h:328
    -
    size_t write_impl(const uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:130
    -
    virtual const SSLSession * get_session_array() const
    Definition: SSLClient.h:367
    -
    virtual uint16_t remotePort()
    Returns the remote port, if C::remotePort exists. Else return 0.
    Definition: SSLClient.h:350
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include <type_traits>
    22 #include "Client.h"
    23 #include "SSLClientImpl.h"
    24 #include "SSLSession.h"
    25 
    26 #ifndef SSLClient_H_
    27 #define SSLClient_H_
    28 
    34 template <class C, size_t SessionCache = 1>
    35 class SSLClient : public SSLClientImpl {
    36 /*
    37  * static checks
    38  * I'm a java developer, so I want to ensure that my inheritance is safe.
    39  * These checks ensure that all the functions we use on class C are
    40  * actually present on class C. It does this by checking that the
    41  * class inherits from Client.
    42  *
    43  * Additionally, I ran into a lot of memory issues with large sessions caches.
    44  * Since each session contains at max 352 bytes of memory, they eat of the
    45  * stack quite quickly and can cause overflows. As a result, I have added a
    46  * warning here to discourage the use of more than 3 sessions at a time. Any
    47  * amount past that will require special modification of this library, and
    48  * assumes you know what you are doing.
    49  */
    50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
    51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
    52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
    53 
    54 public:
    71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
    72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
    73  , m_client(client)
    74  , m_sessions{SSLSession()}
    75  {
    76  // set the timeout to a reasonable number (it can always be changes later)
    77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
    78  setTimeout(10 * 1000);
    79  }
    80 
    81  //========================================
    82  //= Functions implemented in SSLClientImpl
    83  //========================================
    84 
    124  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
    125 
    162  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
    163 
    165  size_t write(uint8_t b) override { return write_impl(&b, 1); }
    189  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
    190 
    209  int available() override { return available_impl(); }
    210 
    215  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    237  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
    238 
    247  int peek() override { return peek_impl(); }
    248 
    256  void flush() override { return flush_impl(); }
    257 
    266  void stop() override { return stop_impl(); }
    267 
    280  uint8_t connected() override { return connected_impl(); }
    281 
    282  //========================================
    283  //= Functions Not in the Client Interface
    284  //========================================
    285 
    300  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
    301 
    310  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
    311 
    317  size_t getSessionCount() const override { return SessionCache; }
    318 
    324  operator bool() { return connected() > 0; }
    326  bool operator==(const bool value) { return bool() == value; }
    328  bool operator!=(const bool value) { return bool() != value; }
    330  bool operator==(const C& rhs) { return m_client == rhs; }
    332  bool operator!=(const C& rhs) { return m_client != rhs; }
    334  uint16_t localPort() override {
    335  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
    336  else {
    337  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
    338  return 0;
    339  }
    340  }
    342  IPAddress remoteIP() override {
    343  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
    344  else {
    345  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
    346  return INADDR_NONE;
    347  }
    348  }
    350  uint16_t remotePort() override {
    351  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
    352  else {
    353  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
    354  return 0;
    355  }
    356  }
    357 
    359  C& getClient() { return m_client; }
    360 
    361 protected:
    363  Client& get_arduino_client() override { return m_client; }
    364  const Client& get_arduino_client() const override { return m_client; }
    366  SSLSession* get_session_array() override { return m_sessions; }
    367  const SSLSession* get_session_array() const override { return m_sessions; }
    368 
    369 private:
    370  // create a copy of the client
    371  C m_client;
    372  // also store an array of SSLSessions, so we can resume communication with multiple websites
    373  SSLSession m_sessions[SessionCache];
    374 };
    375 
    376 #endif
    size_t write_impl(const uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:130
    +
    const SSLSession * get_session_array() const override
    Definition: SSLClient.h:367
    +
    IPAddress remoteIP() override
    Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
    Definition: SSLClient.h:342
    +
    size_t write(uint8_t b) override
    Definition: SSLClient.h:165
    Definition: SSLClientImpl.h:65
    SSLSession & get_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:276
    -
    virtual int available()
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.h:209
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:52
    -
    virtual uint16_t localPort()
    Returns the local port, C::localPort exists. Else return 0.
    Definition: SSLClient.h:334
    -
    virtual IPAddress remoteIP()
    Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
    Definition: SSLClient.h:342
    +
    bool operator!=(const C &rhs)
    Returns whether or not two SSLClient objects do not have the same underlying client object.
    Definition: SSLClient.h:332
    +
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.h:209
    C & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:359
    -
    virtual int peek()
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.h:247
    int peek_impl()
    Definition: SSLClientImpl.cpp:209
    -
    virtual SSLSession & getSession(const char *host, const IPAddress &addr)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.h:300
    -
    virtual size_t write(const uint8_t *buf, size_t size)
    Write some bytes to the SSL connection.
    Definition: SSLClient.h:189
    +
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.h:256
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    +
    bool operator!=(const bool value)
    Definition: SSLClient.h:328
    +
    void stop() override
    Close the connection.
    Definition: SSLClient.h:266
    +
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.h:189
    SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.h:71
    -
    virtual void stop()
    Close the connection.
    Definition: SSLClient.h:266
    +
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.h:247
    int available_impl()
    Definition: SSLClientImpl.cpp:173
    +
    bool operator==(const C &rhs)
    Returns whether or not two SSLClient objects have the same underlying client object.
    Definition: SSLClient.h:330
    int read_impl(uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:194
    +
    SSLSession * get_session_array() override
    Returns an instance of the session array that is on the stack.
    Definition: SSLClient.h:366
    void remove_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:295
    -
    virtual size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:317
    -
    virtual int read()
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:215
    -
    virtual size_t write(uint8_t b)
    Definition: SSLClient.h:165
    +
    Client & get_arduino_client() override
    Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
    Definition: SSLClient.h:363
    +
    uint16_t localPort() override
    Returns the local port, C::localPort exists. Else return 0.
    Definition: SSLClient.h:334
    void m_warn(const T str, const char *func_name) const
    Definition: SSLClientImpl.h:153
    -
    virtual bool operator==(const bool value)
    Definition: SSLClient.h:326
    -
    virtual void flush()
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.h:256
    -
    virtual const Client & get_arduino_client() const
    Definition: SSLClient.h:364
    -
    virtual int connect(const char *host, uint16_t port)
    Connect over SSL to a host specified by a hostname.
    Definition: SSLClient.h:162
    -
    virtual SSLSession * get_session_array()
    Returns an instance of the session array that is on the stack.
    Definition: SSLClient.h:366
    +
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:215
    +
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.h:280
    -
    virtual bool operator!=(const C &rhs)
    Returns whether or not two SSLClient objects do not have the same underlying client object.
    Definition: SSLClient.h:332
    -
    virtual void removeSession(const char *host, const IPAddress &addr)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.h:310
    -
    virtual int connect(IPAddress ip, uint16_t port)
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.h:124
    +
    const Client & get_arduino_client() const override
    Definition: SSLClient.h:364
    +
    int connect(const char *host, uint16_t port) override
    Connect over SSL to a host specified by a hostname.
    Definition: SSLClient.h:162
    +
    bool operator==(const bool value)
    Definition: SSLClient.h:326
    +
    uint16_t remotePort() override
    Returns the remote port, if C::remotePort exists. Else return 0.
    Definition: SSLClient.h:350
    int connect_impl(IPAddress ip, uint16_t port)
    Definition: SSLClientImpl.cpp:74
    +
    size_t getSessionCount() const override
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:317
    void stop_impl()
    Definition: SSLClientImpl.cpp:229
    void flush_impl()
    Definition: SSLClientImpl.cpp:221
    Implementation code to be inherited by SSLClient.
    Definition: SSLClientImpl.h:71
    -
    virtual int read(uint8_t *buf, size_t size)
    Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
    Definition: SSLClient.h:237
    -
    virtual bool operator==(const C &rhs)
    Returns whether or not two SSLClient objects have the same underlying client object.
    Definition: SSLClient.h:330
    +
    void removeSession(const char *host, const IPAddress &addr)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.h:310
    uint8_t connected_impl()
    Definition: SSLClientImpl.cpp:250
    -
    virtual Client & get_arduino_client()
    Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
    Definition: SSLClient.h:363
    +
    SSLSession & getSession(const char *host, const IPAddress &addr)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.h:300
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClientImpl.h:59
    +
    int read(uint8_t *buf, size_t size) override
    Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
    Definition: SSLClient.h:237
    +
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.h:124
    diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 45f2498..d196482 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -94,25 +94,25 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');});

    This is the complete list of members for SSLClient< C, SessionCache >, including all inherited members.

    - + - - + + - + - + - - - - + + + + - - - + + + @@ -120,26 +120,26 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');}); - - - - - - + + + + + + - - + + - - + + - + - + - - + +
    available()SSLClient< C, SessionCache >inlinevirtual
    available() overrideSSLClient< C, SessionCache >inline
    available_impl()SSLClientImpl
    connect(IPAddress ip, uint16_t port)SSLClient< C, SessionCache >inlinevirtual
    connect(const char *host, uint16_t port)SSLClient< C, SessionCache >inlinevirtual
    connect(IPAddress ip, uint16_t port) overrideSSLClient< C, SessionCache >inline
    connect(const char *host, uint16_t port) overrideSSLClient< C, SessionCache >inline
    connect_impl(IPAddress ip, uint16_t port)SSLClientImpl
    connect_impl(const char *host, uint16_t port)SSLClientImpl
    connected()SSLClient< C, SessionCache >inlinevirtual
    connected() overrideSSLClient< C, SessionCache >inline
    connected_impl()SSLClientImpl
    flush()SSLClient< C, SessionCache >inlinevirtual
    flush() overrideSSLClient< C, SessionCache >inline
    flush_impl()SSLClientImpl
    get_arduino_client()SSLClient< C, SessionCache >inlineprotectedvirtual
    get_arduino_client() constSSLClient< C, SessionCache >inlineprotectedvirtual
    get_session_array()SSLClient< C, SessionCache >inlineprotectedvirtual
    get_session_array() constSSLClient< C, SessionCache >inlineprotectedvirtual
    get_arduino_client() overrideSSLClient< C, SessionCache >inlineprotectedvirtual
    get_arduino_client() const overrideSSLClient< C, SessionCache >inlineprotectedvirtual
    get_session_array() overrideSSLClient< C, SessionCache >inlineprotectedvirtual
    get_session_array() const overrideSSLClient< C, SessionCache >inlineprotectedvirtual
    get_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
    getClient()SSLClient< C, SessionCache >inline
    getSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inlinevirtual
    getSessionCount() constSSLClient< C, SessionCache >inlinevirtual
    localPort()SSLClient< C, SessionCache >inlinevirtual
    getSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inline
    getSessionCount() const overrideSSLClient< C, SessionCache >inlinevirtual
    localPort() overrideSSLClient< C, SessionCache >inlinevirtual
    m_error(const T str, const char *func_name) constSSLClientImplinlineprotected
    m_info(const T str, const char *func_name) constSSLClientImplinlineprotected
    m_print(const T str, const char *func_name, const DebugLevel level) constSSLClientImplinlineprotected
    m_print_prefix(const char *func_name, const DebugLevel level) constSSLClientImplprotected
    m_print_ssl_error(const int ssl_error, const DebugLevel level) constSSLClientImplprotected
    m_warn(const T str, const char *func_name) constSSLClientImplinlineprotected
    operator bool()SSLClient< C, SessionCache >inlinevirtual
    operator!=(const bool value)SSLClient< C, SessionCache >inlinevirtual
    operator!=(const C &rhs)SSLClient< C, SessionCache >inlinevirtual
    operator==(const bool value)SSLClient< C, SessionCache >inlinevirtual
    operator==(const C &rhs)SSLClient< C, SessionCache >inlinevirtual
    peek()SSLClient< C, SessionCache >inlinevirtual
    operator bool()SSLClient< C, SessionCache >inline
    operator!=(const bool value)SSLClient< C, SessionCache >inline
    operator!=(const C &rhs)SSLClient< C, SessionCache >inline
    operator==(const bool value)SSLClient< C, SessionCache >inline
    operator==(const C &rhs)SSLClient< C, SessionCache >inline
    peek() overrideSSLClient< C, SessionCache >inline
    peek_impl()SSLClientImpl
    read()SSLClient< C, SessionCache >inlinevirtual
    read(uint8_t *buf, size_t size)SSLClient< C, SessionCache >inlinevirtual
    read() overrideSSLClient< C, SessionCache >inline
    read(uint8_t *buf, size_t size) overrideSSLClient< C, SessionCache >inline
    read_impl(uint8_t *buf, size_t size)SSLClientImpl
    remoteIP()SSLClient< C, SessionCache >inlinevirtual
    remotePort()SSLClient< C, SessionCache >inlinevirtual
    remoteIP() overrideSSLClient< C, SessionCache >inlinevirtual
    remotePort() overrideSSLClient< C, SessionCache >inlinevirtual
    remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
    removeSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inlinevirtual
    removeSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inline
    SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)SSLClient< C, SessionCache >inlineexplicit
    SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit
    stop()SSLClient< C, SessionCache >inlinevirtual
    stop() overrideSSLClient< C, SessionCache >inline
    stop_impl()SSLClientImpl
    write(uint8_t b)SSLClient< C, SessionCache >inlinevirtual
    write(const uint8_t *buf, size_t size)SSLClient< C, SessionCache >inlinevirtual
    write(uint8_t b) overrideSSLClient< C, SessionCache >inline
    write(const uint8_t *buf, size_t size) overrideSSLClient< C, SessionCache >inline
    write_impl(const uint8_t *buf, size_t size)SSLClientImpl
    diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index eadc3cf..a9b36cf 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -115,69 +115,69 @@ Public Member Functions  SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)  Initialize SSLClient with all of the prerequisites needed. More...
      -virtual int connect (IPAddress ip, uint16_t port) - Connect over SSL to a host specified by an IP address. More...
    -  -virtual int connect (const char *host, uint16_t port) - Connect over SSL to a host specified by a hostname. More...
    -  -virtual size_t write (uint8_t b) -  -virtual size_t write (const uint8_t *buf, size_t size) - Write some bytes to the SSL connection. More...
    -  -virtual int available () - Returns the number of bytes available to read from the data that has been received and decrypted. More...
    -  -virtual int read () - Read a single byte, or -1 if none is available. More...
    -  -virtual int read (uint8_t *buf, size_t size) - Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. More...
    -  -virtual int peek () - View the first byte of the buffer, without removing it from the SSLClient Buffer. More...
    -  -virtual void flush () - Force writing the buffered bytes from SSLClient::write to the network. More...
    -  -virtual void stop () - Close the connection. More...
    -  -virtual uint8_t connected () - Check if the device is connected. More...
    -  -virtual SSLSessiongetSession (const char *host, const IPAddress &addr) - Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
    -  -virtual void removeSession (const char *host, const IPAddress &addr) - Clear the session corresponding to a host and IP. More...
    -  -virtual size_t getSessionCount () const - Get the maximum number of SSL sessions that can be stored at once. More...
    -  -virtual operator bool () - Equivalent to SSLClient::connected() > 0. More...
    -  -virtual bool operator== (const bool value) -  -virtual bool operator!= (const bool value) -  -virtual bool operator== (const C &rhs) - Returns whether or not two SSLClient objects have the same underlying client object. More...
    -  -virtual bool operator!= (const C &rhs) - Returns whether or not two SSLClient objects do not have the same underlying client object. More...
    -  -virtual uint16_t localPort () - Returns the local port, C::localPort exists. Else return 0. More...
    -  -virtual IPAddress remoteIP () - Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE. More...
    -  -virtual uint16_t remotePort () - Returns the remote port, if C::remotePort exists. Else return 0. More...
    -  +int connect (IPAddress ip, uint16_t port) override + Connect over SSL to a host specified by an IP address. More...
    +  +int connect (const char *host, uint16_t port) override + Connect over SSL to a host specified by a hostname. More...
    +  +size_t write (uint8_t b) override +  +size_t write (const uint8_t *buf, size_t size) override + Write some bytes to the SSL connection. More...
    +  +int available () override + Returns the number of bytes available to read from the data that has been received and decrypted. More...
    +  +int read () override + Read a single byte, or -1 if none is available. More...
    +  +int read (uint8_t *buf, size_t size) override + Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. More...
    +  +int peek () override + View the first byte of the buffer, without removing it from the SSLClient Buffer. More...
    +  +void flush () override + Force writing the buffered bytes from SSLClient::write to the network. More...
    +  +void stop () override + Close the connection. More...
    +  +uint8_t connected () override + Check if the device is connected. More...
    +  +SSLSessiongetSession (const char *host, const IPAddress &addr) + Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
    +  +void removeSession (const char *host, const IPAddress &addr) + Clear the session corresponding to a host and IP. More...
    +  +size_t getSessionCount () const override + Get the maximum number of SSL sessions that can be stored at once. More...
    +  + operator bool () + Equivalent to SSLClient::connected() > 0. More...
    +  +bool operator== (const bool value) +  +bool operator!= (const bool value) +  +bool operator== (const C &rhs) + Returns whether or not two SSLClient objects have the same underlying client object. More...
    +  +bool operator!= (const C &rhs) + Returns whether or not two SSLClient objects do not have the same underlying client object. More...
    +  +uint16_t localPort () override + Returns the local port, C::localPort exists. Else return 0. More...
    +  +IPAddress remoteIP () override + Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE. More...
    +  +uint16_t remotePort () override + Returns the remote port, if C::remotePort exists. Else return 0. More...
    +  C & getClient ()  Returns a reference to the client object stored in this class. Take care not to break it. More...
      @@ -209,16 +209,16 @@ Public Member Functions - - - - - - - - - - + + + + + + + + + + @@ -322,8 +322,8 @@ The analog_pin should be set to input.

    Member Function Documentation

    - -

    ◆ available()

    + +

    ◆ available()

    @@ -334,7 +334,7 @@ template<class C , size_t SessionCache = 1>
    +inlineoverride

    Protected Member Functions

    virtual Client & get_arduino_client ()
     Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl. More...
     
    virtual const Client & get_arduino_client () const
     
    virtual SSLSessionget_session_array ()
     Returns an instance of the session array that is on the stack. More...
     
    virtual const SSLSessionget_session_array () const
     
    Client & get_arduino_client () override
     Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl. More...
     
    const Client & get_arduino_client () const override
     
    SSLSessionget_session_array () override
     Returns an instance of the session array that is on the stack. More...
     
    const SSLSessionget_session_array () const override
     
    - Protected Member Functions inherited from SSLClientImpl
    void m_print_prefix (const char *func_name, const DebugLevel level) const
     Prints a debugging prefix to all logs, so we can attatch them to useful information. More...
    - + @@ -342,21 +342,21 @@ template<class C , size_t SessionCache = 1>
    virtual int SSLClient< C, SessionCache >::available int SSLClient< C, SessionCache >::available ( )
    -inlinevirtual

    Returns the number of bytes available to read from the data that has been received and decrypted.

    -

    This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

    +

    This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

    The implementation for this function can be found in SSLClientImpl::available

    -
    Precondition
    SSLClient::connected must be true.
    +
    Precondition
    SSLClient::connected must be true.
    Returns
    The number of bytes available (can be zero), or zero if any of the pre conditions aren't satisfied.
    - -

    ◆ connect() [1/2]

    + +

    ◆ connect() [1/2]

    @@ -367,7 +367,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -386,7 +386,7 @@ template<class C , size_t SessionCache = 1>
    virtual int SSLClient< C, SessionCache >::connect int SSLClient< C, SessionCache >::connect ( IPAddress  ip,
    -inlinevirtual +inlineoverride
    @@ -414,8 +414,8 @@ There must be a trust anchor given to the constructor that corresponds to the ce
    - -

    ◆ connect() [2/2]

    + +

    ◆ connect() [2/2]

    @@ -426,7 +426,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -445,7 +445,7 @@ template<class C , size_t SessionCache = 1>
    virtual int SSLClient< C, SessionCache >::connect int SSLClient< C, SessionCache >::connect ( const char *  host,
    -inlinevirtual +inlineoverride
    @@ -473,8 +473,8 @@ There must be a trust anchor given to the constructor that corresponds to the ce
    - -

    ◆ connected()

    + +

    ◆ connected()

    @@ -485,7 +485,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -493,20 +493,20 @@ template<class C , size_t SessionCache = 1>
    virtual uint8_t SSLClient< C, SessionCache >::connected uint8_t SSLClient< C, SessionCache >::connected ( )
    -inlinevirtual +inlineoverride

    Check if the device is connected.

    -

    Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently.

    +

    Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently.

    The implementation for this function can be found in SSLClientImpl::connected_impl.

    Returns
    1 if connected, 0 if not
    - -

    ◆ flush()

    + +

    ◆ flush()

    @@ -517,7 +517,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -525,18 +525,18 @@ template<class C , size_t SessionCache = 1>
    virtual void SSLClient< C, SessionCache >::flush void SSLClient< C, SessionCache >::flush ( )
    -inlinevirtual +inlineoverride
    -

    Force writing the buffered bytes from SSLClient::write to the network.

    -

    This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush.

    +

    Force writing the buffered bytes from SSLClient::write to the network.

    +

    This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush.

    - -

    ◆ get_arduino_client() [1/2]

    + +

    ◆ get_arduino_client() [1/2]

    @@ -547,7 +547,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -555,7 +555,7 @@ template<class C , size_t SessionCache = 1>
    virtual Client& SSLClient< C, SessionCache >::get_arduino_client Client& SSLClient< C, SessionCache >::get_arduino_client ( )
    -inlineprotectedvirtual +inlineoverrideprotectedvirtual
    @@ -566,8 +566,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ get_arduino_client() [2/2]

    + +

    ◆ get_arduino_client() [2/2]

    @@ -578,7 +578,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -586,7 +586,7 @@ template<class C , size_t SessionCache = 1>
    virtual const Client& SSLClient< C, SessionCache >::get_arduino_client const Client& SSLClient< C, SessionCache >::get_arduino_client ( ) const
    -inlineprotectedvirtual +inlineoverrideprotectedvirtual
    @@ -595,8 +595,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ get_session_array() [1/2]

    + +

    ◆ get_session_array() [1/2]

    @@ -607,7 +607,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -615,7 +615,7 @@ template<class C , size_t SessionCache = 1>
    virtual SSLSession* SSLClient< C, SessionCache >::get_session_array SSLSession* SSLClient< C, SessionCache >::get_session_array ( )
    -inlineprotectedvirtual +inlineoverrideprotectedvirtual
    @@ -626,8 +626,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ get_session_array() [2/2]

    + +

    ◆ get_session_array() [2/2]

    @@ -638,7 +638,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -646,7 +646,7 @@ template<class C , size_t SessionCache = 1>
    virtual const SSLSession* SSLClient< C, SessionCache >::get_session_array const SSLSession* SSLClient< C, SessionCache >::get_session_array ( ) const
    -inlineprotectedvirtual +inlineoverrideprotectedvirtual
    @@ -684,8 +684,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ getSession()

    + +

    ◆ getSession()

    @@ -696,7 +696,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -715,7 +715,7 @@ template<class C , size_t SessionCache = 1>
    virtual SSLSession& SSLClient< C, SessionCache >::getSession SSLSession& SSLClient< C, SessionCache >::getSession ( const char *  host,
    -inlinevirtual +inline
    @@ -734,8 +734,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ getSessionCount()

    + +

    ◆ getSessionCount()

    @@ -746,7 +746,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -754,7 +754,7 @@ template<class C , size_t SessionCache = 1>
    virtual size_t SSLClient< C, SessionCache >::getSessionCount size_t SSLClient< C, SessionCache >::getSessionCount ( ) const
    -inlinevirtual +inlineoverridevirtual
    @@ -766,8 +766,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ localPort()

    + +

    ◆ localPort()

    @@ -778,7 +778,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -786,7 +786,7 @@ template<class C , size_t SessionCache = 1>
    virtual uint16_t SSLClient< C, SessionCache >::localPort uint16_t SSLClient< C, SessionCache >::localPort ( )
    -inlinevirtual +inlineoverridevirtual
    @@ -797,8 +797,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ operator bool()

    + +

    ◆ operator bool()

    @@ -809,7 +809,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -817,18 +817,18 @@ template<class C , size_t SessionCache = 1>
    virtual SSLClient< C, SessionCache >::operator bool SSLClient< C, SessionCache >::operator bool ( )
    -inlinevirtual +inline
    -

    Equivalent to SSLClient::connected() > 0.

    +

    Equivalent to SSLClient::connected() > 0.

    Returns
    true if connected, false if not
    - -

    ◆ operator!=() [1/2]

    + +

    ◆ operator!=() [1/2]

    @@ -839,7 +839,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -848,7 +848,7 @@ template<class C , size_t SessionCache = 1>
    virtual bool SSLClient< C, SessionCache >::operator!= bool SSLClient< C, SessionCache >::operator!= ( const bool  value)
    -inlinevirtual +inline
    @@ -856,8 +856,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ operator!=() [2/2]

    + +

    ◆ operator!=() [2/2]

    @@ -868,7 +868,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -877,7 +877,7 @@ template<class C , size_t SessionCache = 1>
    virtual bool SSLClient< C, SessionCache >::operator!= bool SSLClient< C, SessionCache >::operator!= ( const C &  rhs)
    -inlinevirtual +inline
    @@ -886,8 +886,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ operator==() [1/2]

    + +

    ◆ operator==() [1/2]

    @@ -898,7 +898,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -907,7 +907,7 @@ template<class C , size_t SessionCache = 1>
    virtual bool SSLClient< C, SessionCache >::operator== bool SSLClient< C, SessionCache >::operator== ( const bool  value)
    -inlinevirtual +inline
    @@ -915,8 +915,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ operator==() [2/2]

    + +

    ◆ operator==() [2/2]

    @@ -927,7 +927,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -936,7 +936,7 @@ template<class C , size_t SessionCache = 1>
    virtual bool SSLClient< C, SessionCache >::operator== bool SSLClient< C, SessionCache >::operator== ( const C &  rhs)
    -inlinevirtual +inline
    @@ -945,8 +945,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ peek()

    + +

    ◆ peek()

    @@ -957,7 +957,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -965,19 +965,19 @@ template<class C , size_t SessionCache = 1>
    virtual int SSLClient< C, SessionCache >::peek int SSLClient< C, SessionCache >::peek ( )
    -inlinevirtual +inlineoverride

    View the first byte of the buffer, without removing it from the SSLClient Buffer.

    -

    The implementation for this function can be found in SSLClientImpl::peek

    Precondition
    SSLClient::available must be >0
    +

    The implementation for this function can be found in SSLClientImpl::peek

    Precondition
    SSLClient::available must be >0
    Returns
    The first byte received, or -1 if the preconditions are not satisfied (warning: do not use if your data may be -1, as the return value is ambiguous)
    - -

    ◆ read() [1/2]

    + +

    ◆ read() [1/2]

    @@ -988,7 +988,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -996,18 +996,18 @@ template<class C , size_t SessionCache = 1>
    virtual int SSLClient< C, SessionCache >::read int SSLClient< C, SessionCache >::read ( )
    -inlinevirtual +inlineoverride

    Read a single byte, or -1 if none is available.

    -
    See also
    SSLClient::read(uint8_t*, size_t)
    +
    See also
    SSLClient::read(uint8_t*, size_t)
    - -

    ◆ read() [2/2]

    + +

    ◆ read() [2/2]

    @@ -1018,7 +1018,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -1037,16 +1037,16 @@ template<class C , size_t SessionCache = 1>
    virtual int SSLClient< C, SessionCache >::read int SSLClient< C, SessionCache >::read ( uint8_t *  buf,
    -inlinevirtual +inlineoverride

    Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read.

    -

    This function checks if bytes are ready to be read by calling SSLClient::available, and if so copies size number of bytes from the IO buffer into the buf pointer. Data read using this function will not include any SSL or socket commands, as the Client and BearSSL will capture those and process them separately.

    +

    This function checks if bytes are ready to be read by calling SSLClient::available, and if so copies size number of bytes from the IO buffer into the buf pointer. Data read using this function will not include any SSL or socket commands, as the Client and BearSSL will capture those and process them separately.

    If you find that you are having a lot of timeout errors, SSLClient may be experiencing a buffer overflow. Checkout README.md for more information.

    The implementation for this function can be found in SSLClientImpl::read_impl(uint8_t*, size_t)

    -
    Precondition
    SSLClient::available must be >0
    +
    Precondition
    SSLClient::available must be >0
    Parameters
    @@ -1058,8 +1058,8 @@ template<class C , size_t SessionCache = 1> - -

    ◆ remoteIP()

    + +

    ◆ remoteIP()

    @@ -1070,7 +1070,7 @@ template<class C , size_t SessionCache = 1>
    +inlineoverridevirtual
    bufThe pointer to the buffer to put SSL application data into
    - + @@ -1078,7 +1078,7 @@ template<class C , size_t SessionCache = 1>
    virtual IPAddress SSLClient< C, SessionCache >::remoteIP IPAddress SSLClient< C, SessionCache >::remoteIP ( )
    -inlinevirtual
    @@ -1089,8 +1089,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ remotePort()

    + +

    ◆ remotePort()

    @@ -1101,7 +1101,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -1109,7 +1109,7 @@ template<class C , size_t SessionCache = 1>
    virtual uint16_t SSLClient< C, SessionCache >::remotePort uint16_t SSLClient< C, SessionCache >::remotePort ( )
    -inlinevirtual +inlineoverridevirtual
    @@ -1120,8 +1120,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ removeSession()

    + +

    ◆ removeSession()

    @@ -1132,7 +1132,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -1151,7 +1151,7 @@ template<class C , size_t SessionCache = 1>
    virtual void SSLClient< C, SessionCache >::removeSession void SSLClient< C, SessionCache >::removeSession ( const char *  host,
    -inlinevirtual +inline
    @@ -1168,8 +1168,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ stop()

    + +

    ◆ stop()

    @@ -1180,7 +1180,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -1188,7 +1188,7 @@ template<class C , size_t SessionCache = 1>
    virtual void SSLClient< C, SessionCache >::stop void SSLClient< C, SessionCache >::stop ( )
    -inlinevirtual +inlineoverride
    @@ -1198,8 +1198,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ write() [1/2]

    + +

    ◆ write() [1/2]

    @@ -1210,7 +1210,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -1219,7 +1219,7 @@ template<class C , size_t SessionCache = 1>
    virtual size_t SSLClient< C, SessionCache >::write size_t SSLClient< C, SessionCache >::write ( uint8_t  b)
    -inlinevirtual +inlineoverride
    @@ -1227,8 +1227,8 @@ template<class C , size_t SessionCache = 1>
    - -

    ◆ write() [2/2]

    + +

    ◆ write() [2/2]

    @@ -1239,7 +1239,7 @@ template<class C , size_t SessionCache = 1>
    - + @@ -1258,15 +1258,15 @@ template<class C , size_t SessionCache = 1>
    virtual size_t SSLClient< C, SessionCache >::write size_t SSLClient< C, SessionCache >::write ( const uint8_t *  buf,
    -inlinevirtual +inlineoverride

    Write some bytes to the SSL connection.

    -

    Assuming all preconditions are met, this function writes data to the BearSSL IO buffer, BUT does not initially send the data. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready for writing, and will write the data to the network. Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until all the data in buf is sent–attempting to keep all writes to the network grouped together. For information on why this is the case check out README.md .

    +

    Assuming all preconditions are met, this function writes data to the BearSSL IO buffer, BUT does not initially send the data. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready for writing, and will write the data to the network. Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until all the data in buf is sent–attempting to keep all writes to the network grouped together. For information on why this is the case check out README.md .

    The implementation for this function can be found in SSLClientImpl::write_impl(const uint8_t*, size_t)

    -
    Precondition
    The socket and SSL layer must be connected, meaning SSLClient::connected must be true.
    +
    Precondition
    The socket and SSL layer must be connected, meaning SSLClient::connected must be true.
    BearSSL must not be waiting for the recipt of user data (if it is, there is probably an error with how the protocol in implemented in your code).
    Parameters
    diff --git a/docs/html/class_s_s_l_client.js b/docs/html/class_s_s_l_client.js index 0c36bb8..340f3b7 100644 --- a/docs/html/class_s_s_l_client.js +++ b/docs/html/class_s_s_l_client.js @@ -1,31 +1,31 @@ var class_s_s_l_client = [ [ "SSLClient", "class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0", null ], - [ "available", "class_s_s_l_client.html#a40ec85568d0aec376219125b604dbc29", null ], - [ "connect", "class_s_s_l_client.html#ae6540b9a02f1392bf2ac48421189f70e", null ], - [ "connect", "class_s_s_l_client.html#a5814c11e96848c2bcea78210f099aad5", null ], - [ "connected", "class_s_s_l_client.html#a7318aadc0ec9775bffaaac0b1f00aaf8", null ], - [ "flush", "class_s_s_l_client.html#a51eb668f6a328a6a66298c6bc1361d41", null ], - [ "get_arduino_client", "class_s_s_l_client.html#ab3ebfbca41a56bfa11e34aac2c2e0106", null ], - [ "get_arduino_client", "class_s_s_l_client.html#a20742b36588c45435139a4f47fe0f1f6", null ], - [ "get_session_array", "class_s_s_l_client.html#aaa52b481eb1d36a0ae1d208daa2fec51", null ], - [ "get_session_array", "class_s_s_l_client.html#ab076a76b142b553c0dfd29174d4e17e7", null ], + [ "available", "class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e", null ], + [ "connect", "class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630", null ], + [ "connect", "class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf", null ], + [ "connected", "class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc", null ], + [ "flush", "class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44", null ], + [ "get_arduino_client", "class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a", null ], + [ "get_arduino_client", "class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52", null ], + [ "get_session_array", "class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9", null ], + [ "get_session_array", "class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd", null ], [ "getClient", "class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41", null ], - [ "getSession", "class_s_s_l_client.html#ae3f27a36ff9c0cd1e2bea5e1708b6e4f", null ], - [ "getSessionCount", "class_s_s_l_client.html#a36bb344866e4cbcba3bbfcf4d33e5187", null ], - [ "localPort", "class_s_s_l_client.html#ac725067566ee411680c88575c148300b", null ], - [ "operator bool", "class_s_s_l_client.html#a319a722dae252efdd85fdbaf5c7fbf17", null ], - [ "operator!=", "class_s_s_l_client.html#a9a060e49d0685c6c6795558e41cd3323", null ], - [ "operator!=", "class_s_s_l_client.html#a518f4ed733814f2f4a8c7f838555eb35", null ], - [ "operator==", "class_s_s_l_client.html#a6fb2e8a1cc54dd82a72217e5c4533e02", null ], - [ "operator==", "class_s_s_l_client.html#a26f9418e33d4ca459f78de98d3af43bb", null ], - [ "peek", "class_s_s_l_client.html#a227b1cbbe91bcb21153c09f97d0dd484", null ], - [ "read", "class_s_s_l_client.html#ac70b900ff798f9fd33f6367fcc9fad77", null ], - [ "read", "class_s_s_l_client.html#ae31dd88a1af8ec3794fb48f26a3dd4bf", null ], - [ "remoteIP", "class_s_s_l_client.html#ae2d1d17ee568ec2a37756bf6894dcd05", null ], - [ "remotePort", "class_s_s_l_client.html#ae8bd9420fec3b11f855729c4ecfe1c2c", null ], - [ "removeSession", "class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0", null ], - [ "stop", "class_s_s_l_client.html#a158d87df3fe118b7565a19b72f310322", null ], - [ "write", "class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270", null ], - [ "write", "class_s_s_l_client.html#a3a48b190985cdea2eba79ef0bdc80461", null ] + [ "getSession", "class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086", null ], + [ "getSessionCount", "class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd", null ], + [ "localPort", "class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73", null ], + [ "operator bool", "class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1", null ], + [ "operator!=", "class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1", null ], + [ "operator!=", "class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b", null ], + [ "operator==", "class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc", null ], + [ "operator==", "class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9", null ], + [ "peek", "class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd", null ], + [ "read", "class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e", null ], + [ "read", "class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795", null ], + [ "remoteIP", "class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174", null ], + [ "remotePort", "class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22", null ], + [ "removeSession", "class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c", null ], + [ "stop", "class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529", null ], + [ "write", "class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb", null ], + [ "write", "class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9", null ] ]; \ No newline at end of file diff --git a/docs/html/class_s_s_l_client_impl.html b/docs/html/class_s_s_l_client_impl.html index 7259c74..244b09f 100644 --- a/docs/html/class_s_s_l_client_impl.html +++ b/docs/html/class_s_s_l_client_impl.html @@ -246,7 +246,7 @@ Protected Member Functions
    @@ -275,7 +275,7 @@ Protected Member Functions @@ -304,7 +304,7 @@ Protected Member Functions @@ -322,7 +322,7 @@ Protected Member Functions @@ -340,7 +340,7 @@ Protected Member Functions @@ -366,9 +366,9 @@ Protected Member Functions @@ -395,7 +395,7 @@ Protected Member Functions @@ -421,9 +421,9 @@ Protected Member Functions @@ -450,7 +450,7 @@ Protected Member Functions @@ -479,7 +479,7 @@ Protected Member Functions @@ -505,9 +505,9 @@ Protected Member Functions @@ -533,9 +533,9 @@ Protected Member Functions @@ -829,7 +829,7 @@ template<typename T >
    -
    See also
    SSLClient::peek
    +
    See also
    SSLClient::peek
    @@ -858,7 +858,7 @@ template<typename T > @@ -884,9 +884,9 @@ template<typename T > @@ -912,9 +912,9 @@ template<typename T > @@ -943,7 +943,7 @@ template<typename T > @@ -961,7 +961,7 @@ template<typename T >
    -
    See also
    SSLClient::stop
    +
    See also
    SSLClient::stop
    @@ -990,7 +990,7 @@ template<typename T > diff --git a/docs/html/functions.html b/docs/html/functions.html index 2848a51..dea6a9f 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

    - a -

    • available() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
    • available_impl() : SSLClientImpl @@ -104,13 +104,13 @@ $(document).ready(function(){initNavTree('functions.html','');}); : SSLSession
    • connect() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
    • connect_impl() : SSLClientImpl
    • connected() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
    • connected_impl() : SSLClientImpl @@ -120,7 +120,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

      - f -

      • flush() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
      • flush_impl() : SSLClientImpl @@ -130,7 +130,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

        - g -

        @@ -168,7 +168,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

        - l -

        @@ -201,23 +201,23 @@ $(document).ready(function(){initNavTree('functions.html','');});

        - o -

        - p -

        • peek() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
        • peek_impl() : SSLClientImpl @@ -227,24 +227,24 @@ $(document).ready(function(){initNavTree('functions.html','');});

          - r -

          @@ -263,7 +263,7 @@ $(document).ready(function(){initNavTree('functions.html','');}); : SSLSession
        • stop() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
        • stop_impl() : SSLClientImpl @@ -280,7 +280,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

          - w -

          • write() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
          • write_impl() : SSLClientImpl diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index e587094..3a214ff 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

            - a -

            • available() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
            • available_impl() : SSLClientImpl @@ -104,13 +104,13 @@ $(document).ready(function(){initNavTree('functions_func.html','');}); : SSLSession
            • connect() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
            • connect_impl() : SSLClientImpl
            • connected() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
            • connected_impl() : SSLClientImpl @@ -120,7 +120,7 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

              - f -

              • flush() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
              • flush_impl() : SSLClientImpl @@ -130,7 +130,7 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

                - g -

                @@ -168,7 +168,7 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

                - l -

                @@ -201,23 +201,23 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

                - o -

                - p -

                • peek() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
                • peek_impl() : SSLClientImpl @@ -227,24 +227,24 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

                  - r -

                  @@ -263,7 +263,7 @@ $(document).ready(function(){initNavTree('functions_func.html','');}); : SSLSession
                • stop() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
                • stop_impl() : SSLClientImpl @@ -280,7 +280,7 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

                  - w -

                  • write() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache >
                  • write_impl() : SSLClientImpl diff --git a/docs/html/index.html b/docs/html/index.html index 9a78c88..d1a4668 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -121,9 +121,9 @@ $(document).ready(function(){initNavTree('index.html','');});

                    Errors

                    When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from SSLClient::getWriteError(), which will return a value from the Error enum. For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at SSL_ERROR or lower.

                    Write Buffering

                    -

                    As you may have noticed in the documentation for SSLClient::write, calling this function does not actually write to the network. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready and write to the network (see SSLClient::write for details).

                    -

                    This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so:

                    {C++}
                    EthernetClient client;
                    // ...
                    // connect to ardiuino.cc over ssl (port 443 for websites)
                    client.connect("www.arduino.cc", 443);
                    // ...
                    // write an http request to the network
                    client.write("GET /asciilogo.txt HTTP/1.1\r\n");
                    client.write("Host: arduino.cc\r\n");
                    client.write("Connection: close\r\n");
                    // wait for response
                    while (!client.available()) { /* ... */ }
                    // ...

                    Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

                    -
                    {C++}
                    SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);
                    // ...
                    // connect to ardiuino.cc over ssl (port 443 for websites)
                    client.connect("www.arduino.cc", 443);
                    // ...
                    // add http request to the buffer
                    client.write("GET /asciilogo.txt HTTP/1.1\r\n");
                    client.write("Host: arduino.cc\r\n");
                    client.write("Connection: close\r\n");
                    // write the bytes to the network, then wait for response
                    while (!client.available()) { /* ... */ }
                    // ...

                    If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

                    +

                    As you may have noticed in the documentation for SSLClient::write, calling this function does not actually write to the network. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready and write to the network (see SSLClient::write for details).

                    +

                    This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so:

                    {C++}
                    EthernetClient client;
                    // ...
                    // connect to ardiuino.cc over ssl (port 443 for websites)
                    client.connect("www.arduino.cc", 443);
                    // ...
                    // write an http request to the network
                    client.write("GET /asciilogo.txt HTTP/1.1\r\n");
                    client.write("Host: arduino.cc\r\n");
                    client.write("Connection: close\r\n");
                    // wait for response
                    while (!client.available()) { /* ... */ }
                    // ...

                    Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

                    +
                    {C++}
                    SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);
                    // ...
                    // connect to ardiuino.cc over ssl (port 443 for websites)
                    client.connect("www.arduino.cc", 443);
                    // ...
                    // add http request to the buffer
                    client.write("GET /asciilogo.txt HTTP/1.1\r\n");
                    client.write("Host: arduino.cc\r\n");
                    client.write("Connection: close\r\n");
                    // write the bytes to the network, then wait for response
                    while (!client.available()) { /* ... */ }
                    // ...

                    If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

                    Session Caching

                    As detailed in the resources section, SSL handshakes take an extended period (1-4sec) to negotiate. To remedy this problem, BearSSL is able to keep a SSL session cache of the clients it has connected to. If BearSSL successfully resumes an SSL session, it can reduce connection time to 100-500ms.

                    In order to use SSL session resumption:

                      diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index 01d98af..960a2fb 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -103,7 +103,7 @@ $(document).ready(function(){initNavTree('md__c_1__users__noah__documents__ardui

                      Other Connections

                      For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convert command to convert the certificate into a trust anchor header.

                      Using Trust Anchors

                      -

                      Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

                      {C++}
                      #include "yourtrustanchorfile.h"
                      // ...
                      SSLClient<SomeClientType> client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
                      // ...

                      Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

                      +

                      Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

                      {C++}
                      #include "yourtrustanchorfile.h"
                      // ...
                      SSLClient<SomeClientType> client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
                      // ...

                      Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

                      diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index adb9539..cd95985 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -30,34 +30,34 @@ var NAVTREEINDEX0 = "cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,1,0,0], "cert_8h_source.html":[3,0,1,0], "class_s_s_l_client.html":[2,0,0], -"class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0":[2,0,0,24], -"class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270":[2,0,0,26], -"class_s_s_l_client.html#a158d87df3fe118b7565a19b72f310322":[2,0,0,25], -"class_s_s_l_client.html#a20742b36588c45435139a4f47fe0f1f6":[2,0,0,7], -"class_s_s_l_client.html#a227b1cbbe91bcb21153c09f97d0dd484":[2,0,0,19], -"class_s_s_l_client.html#a26f9418e33d4ca459f78de98d3af43bb":[2,0,0,18], -"class_s_s_l_client.html#a319a722dae252efdd85fdbaf5c7fbf17":[2,0,0,14], -"class_s_s_l_client.html#a36bb344866e4cbcba3bbfcf4d33e5187":[2,0,0,12], -"class_s_s_l_client.html#a3a48b190985cdea2eba79ef0bdc80461":[2,0,0,27], -"class_s_s_l_client.html#a40ec85568d0aec376219125b604dbc29":[2,0,0,1], -"class_s_s_l_client.html#a518f4ed733814f2f4a8c7f838555eb35":[2,0,0,16], -"class_s_s_l_client.html#a51eb668f6a328a6a66298c6bc1361d41":[2,0,0,5], -"class_s_s_l_client.html#a5814c11e96848c2bcea78210f099aad5":[2,0,0,3], -"class_s_s_l_client.html#a6fb2e8a1cc54dd82a72217e5c4533e02":[2,0,0,17], -"class_s_s_l_client.html#a7318aadc0ec9775bffaaac0b1f00aaf8":[2,0,0,4], -"class_s_s_l_client.html#a9a060e49d0685c6c6795558e41cd3323":[2,0,0,15], -"class_s_s_l_client.html#aaa52b481eb1d36a0ae1d208daa2fec51":[2,0,0,8], -"class_s_s_l_client.html#ab076a76b142b553c0dfd29174d4e17e7":[2,0,0,9], -"class_s_s_l_client.html#ab3ebfbca41a56bfa11e34aac2c2e0106":[2,0,0,6], -"class_s_s_l_client.html#ac70b900ff798f9fd33f6367fcc9fad77":[2,0,0,20], -"class_s_s_l_client.html#ac725067566ee411680c88575c148300b":[2,0,0,13], -"class_s_s_l_client.html#ae2d1d17ee568ec2a37756bf6894dcd05":[2,0,0,22], -"class_s_s_l_client.html#ae31dd88a1af8ec3794fb48f26a3dd4bf":[2,0,0,21], -"class_s_s_l_client.html#ae3f27a36ff9c0cd1e2bea5e1708b6e4f":[2,0,0,11], -"class_s_s_l_client.html#ae6540b9a02f1392bf2ac48421189f70e":[2,0,0,2], -"class_s_s_l_client.html#ae8bd9420fec3b11f855729c4ecfe1c2c":[2,0,0,23], +"class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd":[2,0,0,9], +"class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc":[2,0,0,4], +"class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1":[2,0,0,14], +"class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd":[2,0,0,12], +"class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086":[2,0,0,11], +"class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44":[2,0,0,5], +"class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd":[2,0,0,19], +"class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52":[2,0,0,7], +"class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630":[2,0,0,2], +"class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc":[2,0,0,17], +"class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73":[2,0,0,13], +"class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22":[2,0,0,23], +"class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c":[2,0,0,24], +"class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e":[2,0,0,1], +"class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9":[2,0,0,18], +"class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb":[2,0,0,26], +"class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9":[2,0,0,27], +"class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1":[2,0,0,15], +"class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf":[2,0,0,3], +"class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a":[2,0,0,6], +"class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9":[2,0,0,8], +"class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529":[2,0,0,25], +"class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b":[2,0,0,16], "class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0":[2,0,0,0], +"class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e":[2,0,0,20], +"class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174":[2,0,0,22], "class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41":[2,0,0,10], +"class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795":[2,0,0,21], "class_s_s_l_client_impl.html":[2,0,1], "class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d":[2,0,1,20], "class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3":[2,0,1,6], diff --git a/docs/html/search/all_1.js b/docs/html/search/all_1.js index e146f72..6e54ada 100644 --- a/docs/html/search/all_1.js +++ b/docs/html/search/all_1.js @@ -1,5 +1,5 @@ var searchData= [ - ['available',['available',['../class_s_s_l_client.html#a40ec85568d0aec376219125b604dbc29',1,'SSLClient']]], + ['available',['available',['../class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e',1,'SSLClient']]], ['available_5fimpl',['available_impl',['../class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js index bd942e1..b1b7f3c 100644 --- a/docs/html/search/all_11.js +++ b/docs/html/search/all_11.js @@ -1,5 +1,5 @@ var searchData= [ - ['write',['write',['../class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270',1,'SSLClient::write(uint8_t b)'],['../class_s_s_l_client.html#a3a48b190985cdea2eba79ef0bdc80461',1,'SSLClient::write(const uint8_t *buf, size_t size)']]], + ['write',['write',['../class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb',1,'SSLClient::write(uint8_t b) override'],['../class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9',1,'SSLClient::write(const uint8_t *buf, size_t size) override']]], ['write_5fimpl',['write_impl',['../class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js index 81496e7..659fa65 100644 --- a/docs/html/search/all_3.js +++ b/docs/html/search/all_3.js @@ -2,9 +2,9 @@ var searchData= [ ['cert_2eh',['cert.h',['../cert_8h.html',1,'']]], ['clear_5fparameters',['clear_parameters',['../class_s_s_l_session.html#a3305941fa615f7134526b718917716ee',1,'SSLSession']]], - ['connect',['connect',['../class_s_s_l_client.html#ae6540b9a02f1392bf2ac48421189f70e',1,'SSLClient::connect(IPAddress ip, uint16_t port)'],['../class_s_s_l_client.html#a5814c11e96848c2bcea78210f099aad5',1,'SSLClient::connect(const char *host, uint16_t port)']]], + ['connect',['connect',['../class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf',1,'SSLClient::connect(const char *host, uint16_t port) override']]], ['connect_5fimpl',['connect_impl',['../class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b',1,'SSLClientImpl::connect_impl(IPAddress ip, uint16_t port)'],['../class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba',1,'SSLClientImpl::connect_impl(const char *host, uint16_t port)']]], - ['connected',['connected',['../class_s_s_l_client.html#a7318aadc0ec9775bffaaac0b1f00aaf8',1,'SSLClient']]], + ['connected',['connected',['../class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc',1,'SSLClient']]], ['connected_5fimpl',['connected_impl',['../class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb',1,'SSLClientImpl']]], ['conv_5fstr2dec_5f1',['CONV_STR2DEC_1',['../time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a',1,'time_macros.h']]], ['conv_5fstr2dec_5f2',['CONV_STR2DEC_2',['../time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3',1,'time_macros.h']]], diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js index 49584f5..3dc70e4 100644 --- a/docs/html/search/all_6.js +++ b/docs/html/search/all_6.js @@ -1,5 +1,5 @@ var searchData= [ - ['flush',['flush',['../class_s_s_l_client.html#a51eb668f6a328a6a66298c6bc1361d41',1,'SSLClient']]], + ['flush',['flush',['../class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44',1,'SSLClient']]], ['flush_5fimpl',['flush_impl',['../class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js index 926ac2d..fcf2600 100644 --- a/docs/html/search/all_7.js +++ b/docs/html/search/all_7.js @@ -1,12 +1,12 @@ var searchData= [ - ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#ab3ebfbca41a56bfa11e34aac2c2e0106',1,'SSLClient::get_arduino_client()'],['../class_s_s_l_client.html#a20742b36588c45435139a4f47fe0f1f6',1,'SSLClient::get_arduino_client() const'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], + ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a',1,'SSLClient::get_arduino_client() override'],['../class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52',1,'SSLClient::get_arduino_client() const override'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], ['get_5fip',['get_ip',['../class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0',1,'SSLSession']]], ['get_5fmonth',['GET_MONTH',['../time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994',1,'time_macros.h']]], - ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#aaa52b481eb1d36a0ae1d208daa2fec51',1,'SSLClient::get_session_array()'],['../class_s_s_l_client.html#ab076a76b142b553c0dfd29174d4e17e7',1,'SSLClient::get_session_array() const'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], + ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9',1,'SSLClient::get_session_array() override'],['../class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd',1,'SSLClient::get_session_array() const override'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], ['get_5fsession_5fimpl',['get_session_impl',['../class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e',1,'SSLClientImpl']]], ['getclient',['getClient',['../class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41',1,'SSLClient']]], - ['getsession',['getSession',['../class_s_s_l_client.html#ae3f27a36ff9c0cd1e2bea5e1708b6e4f',1,'SSLClient']]], - ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a36bb344866e4cbcba3bbfcf4d33e5187',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] + ['getsession',['getSession',['../class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086',1,'SSLClient']]], + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] ]; diff --git a/docs/html/search/all_9.js b/docs/html/search/all_9.js index ac8fe09..0773563 100644 --- a/docs/html/search/all_9.js +++ b/docs/html/search/all_9.js @@ -1,4 +1,4 @@ var searchData= [ - ['localport',['localPort',['../class_s_s_l_client.html#ac725067566ee411680c88575c148300b',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] + ['localport',['localPort',['../class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] ]; diff --git a/docs/html/search/all_b.js b/docs/html/search/all_b.js index 7bc0384..d7f8a71 100644 --- a/docs/html/search/all_b.js +++ b/docs/html/search/all_b.js @@ -1,7 +1,7 @@ var searchData= [ - ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a319a722dae252efdd85fdbaf5c7fbf17',1,'SSLClient']]], - ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a9a060e49d0685c6c6795558e41cd3323',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#a518f4ed733814f2f4a8c7f838555eb35',1,'SSLClient::operator!=(const C &rhs)']]], + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1',1,'SSLClient']]], + ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b',1,'SSLClient::operator!=(const C &rhs)']]], ['operator_3d',['operator=',['../class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f',1,'SSLSession']]], - ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a6fb2e8a1cc54dd82a72217e5c4533e02',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a26f9418e33d4ca459f78de98d3af43bb',1,'SSLClient::operator==(const C &rhs)']]] + ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9',1,'SSLClient::operator==(const C &rhs)']]] ]; diff --git a/docs/html/search/all_c.js b/docs/html/search/all_c.js index 036e45a..6de2fa7 100644 --- a/docs/html/search/all_c.js +++ b/docs/html/search/all_c.js @@ -1,6 +1,6 @@ var searchData= [ - ['peek',['peek',['../class_s_s_l_client.html#a227b1cbbe91bcb21153c09f97d0dd484',1,'SSLClient']]], + ['peek',['peek',['../class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd',1,'SSLClient']]], ['peek_5fimpl',['peek_impl',['../class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d',1,'SSLClientImpl']]], ['pst_5foffset',['PST_OFFSET',['../time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb',1,'time_macros.h']]] ]; diff --git a/docs/html/search/all_d.js b/docs/html/search/all_d.js index 7dcf3c4..6283be9 100644 --- a/docs/html/search/all_d.js +++ b/docs/html/search/all_d.js @@ -1,10 +1,10 @@ var searchData= [ - ['read',['read',['../class_s_s_l_client.html#ac70b900ff798f9fd33f6367fcc9fad77',1,'SSLClient::read()'],['../class_s_s_l_client.html#ae31dd88a1af8ec3794fb48f26a3dd4bf',1,'SSLClient::read(uint8_t *buf, size_t size)']]], + ['read',['read',['../class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e',1,'SSLClient::read() override'],['../class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795',1,'SSLClient::read(uint8_t *buf, size_t size) override']]], ['read_5fimpl',['read_impl',['../class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe',1,'SSLClientImpl']]], ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]], - ['remoteip',['remoteIP',['../class_s_s_l_client.html#ae2d1d17ee568ec2a37756bf6894dcd05',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], - ['remoteport',['remotePort',['../class_s_s_l_client.html#ae8bd9420fec3b11f855729c4ecfe1c2c',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], + ['remoteip',['remoteIP',['../class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], + ['remoteport',['remotePort',['../class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], ['remove_5fsession_5fimpl',['remove_session_impl',['../class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1',1,'SSLClientImpl']]], - ['removesession',['removeSession',['../class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0',1,'SSLClient']]] + ['removesession',['removeSession',['../class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js index 84c4068..f399184 100644 --- a/docs/html/search/all_e.js +++ b/docs/html/search/all_e.js @@ -26,6 +26,6 @@ var searchData= ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession::SSLSession()']]], ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], - ['stop',['stop',['../class_s_s_l_client.html#a158d87df3fe118b7565a19b72f310322',1,'SSLClient']]], + ['stop',['stop',['../class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529',1,'SSLClient']]], ['stop_5fimpl',['stop_impl',['../class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js index e146f72..6e54ada 100644 --- a/docs/html/search/functions_0.js +++ b/docs/html/search/functions_0.js @@ -1,5 +1,5 @@ var searchData= [ - ['available',['available',['../class_s_s_l_client.html#a40ec85568d0aec376219125b604dbc29',1,'SSLClient']]], + ['available',['available',['../class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e',1,'SSLClient']]], ['available_5fimpl',['available_impl',['../class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/functions_2.js b/docs/html/search/functions_2.js index 22b749e..47de2ad 100644 --- a/docs/html/search/functions_2.js +++ b/docs/html/search/functions_2.js @@ -1,8 +1,8 @@ var searchData= [ ['clear_5fparameters',['clear_parameters',['../class_s_s_l_session.html#a3305941fa615f7134526b718917716ee',1,'SSLSession']]], - ['connect',['connect',['../class_s_s_l_client.html#ae6540b9a02f1392bf2ac48421189f70e',1,'SSLClient::connect(IPAddress ip, uint16_t port)'],['../class_s_s_l_client.html#a5814c11e96848c2bcea78210f099aad5',1,'SSLClient::connect(const char *host, uint16_t port)']]], + ['connect',['connect',['../class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf',1,'SSLClient::connect(const char *host, uint16_t port) override']]], ['connect_5fimpl',['connect_impl',['../class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b',1,'SSLClientImpl::connect_impl(IPAddress ip, uint16_t port)'],['../class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba',1,'SSLClientImpl::connect_impl(const char *host, uint16_t port)']]], - ['connected',['connected',['../class_s_s_l_client.html#a7318aadc0ec9775bffaaac0b1f00aaf8',1,'SSLClient']]], + ['connected',['connected',['../class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc',1,'SSLClient']]], ['connected_5fimpl',['connected_impl',['../class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/functions_3.js b/docs/html/search/functions_3.js index 49584f5..3dc70e4 100644 --- a/docs/html/search/functions_3.js +++ b/docs/html/search/functions_3.js @@ -1,5 +1,5 @@ var searchData= [ - ['flush',['flush',['../class_s_s_l_client.html#a51eb668f6a328a6a66298c6bc1361d41',1,'SSLClient']]], + ['flush',['flush',['../class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44',1,'SSLClient']]], ['flush_5fimpl',['flush_impl',['../class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/functions_4.js b/docs/html/search/functions_4.js index 78322fb..18508ae 100644 --- a/docs/html/search/functions_4.js +++ b/docs/html/search/functions_4.js @@ -1,11 +1,11 @@ var searchData= [ - ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#ab3ebfbca41a56bfa11e34aac2c2e0106',1,'SSLClient::get_arduino_client()'],['../class_s_s_l_client.html#a20742b36588c45435139a4f47fe0f1f6',1,'SSLClient::get_arduino_client() const'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], + ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a',1,'SSLClient::get_arduino_client() override'],['../class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52',1,'SSLClient::get_arduino_client() const override'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], ['get_5fip',['get_ip',['../class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0',1,'SSLSession']]], - ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#aaa52b481eb1d36a0ae1d208daa2fec51',1,'SSLClient::get_session_array()'],['../class_s_s_l_client.html#ab076a76b142b553c0dfd29174d4e17e7',1,'SSLClient::get_session_array() const'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], + ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9',1,'SSLClient::get_session_array() override'],['../class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd',1,'SSLClient::get_session_array() const override'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], ['get_5fsession_5fimpl',['get_session_impl',['../class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e',1,'SSLClientImpl']]], ['getclient',['getClient',['../class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41',1,'SSLClient']]], - ['getsession',['getSession',['../class_s_s_l_client.html#ae3f27a36ff9c0cd1e2bea5e1708b6e4f',1,'SSLClient']]], - ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a36bb344866e4cbcba3bbfcf4d33e5187',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] + ['getsession',['getSession',['../class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086',1,'SSLClient']]], + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] ]; diff --git a/docs/html/search/functions_6.js b/docs/html/search/functions_6.js index ac8fe09..0773563 100644 --- a/docs/html/search/functions_6.js +++ b/docs/html/search/functions_6.js @@ -1,4 +1,4 @@ var searchData= [ - ['localport',['localPort',['../class_s_s_l_client.html#ac725067566ee411680c88575c148300b',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] + ['localport',['localPort',['../class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] ]; diff --git a/docs/html/search/functions_8.js b/docs/html/search/functions_8.js index 7bc0384..d7f8a71 100644 --- a/docs/html/search/functions_8.js +++ b/docs/html/search/functions_8.js @@ -1,7 +1,7 @@ var searchData= [ - ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a319a722dae252efdd85fdbaf5c7fbf17',1,'SSLClient']]], - ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a9a060e49d0685c6c6795558e41cd3323',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#a518f4ed733814f2f4a8c7f838555eb35',1,'SSLClient::operator!=(const C &rhs)']]], + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1',1,'SSLClient']]], + ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b',1,'SSLClient::operator!=(const C &rhs)']]], ['operator_3d',['operator=',['../class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f',1,'SSLSession']]], - ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a6fb2e8a1cc54dd82a72217e5c4533e02',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a26f9418e33d4ca459f78de98d3af43bb',1,'SSLClient::operator==(const C &rhs)']]] + ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9',1,'SSLClient::operator==(const C &rhs)']]] ]; diff --git a/docs/html/search/functions_9.js b/docs/html/search/functions_9.js index ce70a60..ceddcf3 100644 --- a/docs/html/search/functions_9.js +++ b/docs/html/search/functions_9.js @@ -1,5 +1,5 @@ var searchData= [ - ['peek',['peek',['../class_s_s_l_client.html#a227b1cbbe91bcb21153c09f97d0dd484',1,'SSLClient']]], + ['peek',['peek',['../class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd',1,'SSLClient']]], ['peek_5fimpl',['peek_impl',['../class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/functions_a.js b/docs/html/search/functions_a.js index 66237d4..6e82845 100644 --- a/docs/html/search/functions_a.js +++ b/docs/html/search/functions_a.js @@ -1,9 +1,9 @@ var searchData= [ - ['read',['read',['../class_s_s_l_client.html#ac70b900ff798f9fd33f6367fcc9fad77',1,'SSLClient::read()'],['../class_s_s_l_client.html#ae31dd88a1af8ec3794fb48f26a3dd4bf',1,'SSLClient::read(uint8_t *buf, size_t size)']]], + ['read',['read',['../class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e',1,'SSLClient::read() override'],['../class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795',1,'SSLClient::read(uint8_t *buf, size_t size) override']]], ['read_5fimpl',['read_impl',['../class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe',1,'SSLClientImpl']]], - ['remoteip',['remoteIP',['../class_s_s_l_client.html#ae2d1d17ee568ec2a37756bf6894dcd05',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], - ['remoteport',['remotePort',['../class_s_s_l_client.html#ae8bd9420fec3b11f855729c4ecfe1c2c',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], + ['remoteip',['remoteIP',['../class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], + ['remoteport',['remotePort',['../class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], ['remove_5fsession_5fimpl',['remove_session_impl',['../class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1',1,'SSLClientImpl']]], - ['removesession',['removeSession',['../class_s_s_l_client.html#a0000d7f1e8656cf4a506a98133391fe0',1,'SSLClient']]] + ['removesession',['removeSession',['../class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js index 5c6e59a..ddd85b5 100644 --- a/docs/html/search/functions_b.js +++ b/docs/html/search/functions_b.js @@ -4,6 +4,6 @@ var searchData= ['sslclient',['SSLClient',['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient']]], ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession']]], - ['stop',['stop',['../class_s_s_l_client.html#a158d87df3fe118b7565a19b72f310322',1,'SSLClient']]], + ['stop',['stop',['../class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529',1,'SSLClient']]], ['stop_5fimpl',['stop_impl',['../class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6',1,'SSLClientImpl']]] ]; diff --git a/docs/html/search/functions_d.js b/docs/html/search/functions_d.js index bd942e1..b1b7f3c 100644 --- a/docs/html/search/functions_d.js +++ b/docs/html/search/functions_d.js @@ -1,5 +1,5 @@ var searchData= [ - ['write',['write',['../class_s_s_l_client.html#a0699ff4b966162cba2ef59ff4a287270',1,'SSLClient::write(uint8_t b)'],['../class_s_s_l_client.html#a3a48b190985cdea2eba79ef0bdc80461',1,'SSLClient::write(const uint8_t *buf, size_t size)']]], + ['write',['write',['../class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb',1,'SSLClient::write(uint8_t b) override'],['../class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9',1,'SSLClient::write(const uint8_t *buf, size_t size) override']]], ['write_5fimpl',['write_impl',['../class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d',1,'SSLClientImpl']]] ]; diff --git a/src/SSLClient.h b/src/SSLClient.h index 3e69bd9..2927a77 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -121,7 +121,7 @@ public: * @param port the port to connect to * @returns 1 if success, 0 if failure */ - virtual int connect(IPAddress ip, uint16_t port) { return connect_impl(ip, port); } + int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); } /** * @brief Connect over SSL to a host specified by a hostname. @@ -159,10 +159,10 @@ public: * @param port The port to connect to on the host (443 for HTTPS) * @returns 1 of success, 0 if failure */ - virtual int connect(const char *host, uint16_t port) { return connect_impl(host, port); } + int connect(const char *host, uint16_t port) override { return connect_impl(host, port); } /** @see SSLClient::write(uint8_t*, size_t) */ - virtual size_t write(uint8_t b) { return write_impl(&b, 1); } + size_t write(uint8_t b) override { return write_impl(&b, 1); } /** * @brief Write some bytes to the SSL connection * @@ -186,7 +186,7 @@ public: * @returns The number of bytes copied to the buffer (size), or zero if the BearSSL engine * fails to become ready for writing data. */ - virtual size_t write(const uint8_t *buf, size_t size) { return write_impl(buf, size); } + size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); } /** * @brief Returns the number of bytes available to read from the data that has been received and decrypted. @@ -206,13 +206,13 @@ public: * @returns The number of bytes available (can be zero), or zero if any of the pre * conditions aren't satisfied. */ - virtual int available() { return available_impl(); } + int available() override { return available_impl(); } /** * @brief Read a single byte, or -1 if none is available. * @see SSLClient::read(uint8_t*, size_t) */ - virtual int read() { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; }; + int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; }; /** * @brief Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. * @@ -234,7 +234,7 @@ public: * * @returns The number of bytes copied (<= size), or -1 if the preconditions are not satisfied. */ - virtual int read(uint8_t *buf, size_t size) { return read_impl(buf, size); } + int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); } /** * @brief View the first byte of the buffer, without removing it from the SSLClient Buffer @@ -244,7 +244,7 @@ public: * @returns The first byte received, or -1 if the preconditions are not satisfied (warning: * do not use if your data may be -1, as the return value is ambiguous) */ - virtual int peek() { return peek_impl(); } + int peek() override { return peek_impl(); } /** * @brief Force writing the buffered bytes from SSLClient::write to the network. @@ -253,7 +253,7 @@ public: * an explanation of how writing with SSLClient works, please see SSLClient::write. * The implementation for this function can be found in SSLClientImpl::flush. */ - virtual void flush() { return flush_impl(); } + void flush() override { return flush_impl(); } /** * @brief Close the connection @@ -263,7 +263,7 @@ public: * error was encountered previously, this function will simply call m_client::stop. * The implementation for this function can be found in SSLClientImpl::peek. */ - virtual void stop() { return stop_impl(); } + void stop() override { return stop_impl(); } /** * @brief Check if the device is connected. @@ -277,7 +277,7 @@ public: * * @returns 1 if connected, 0 if not */ - virtual uint8_t connected() { return connected_impl(); } + uint8_t connected() override { return connected_impl(); } //======================================== //= Functions Not in the Client Interface @@ -297,7 +297,7 @@ public: * @param addr An IP address * @returns A reference to an SSLSession object */ - virtual SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); } + SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); } /** * @brief Clear the session corresponding to a host and IP @@ -307,31 +307,31 @@ public: * @param host A hostname c string, or NULL if one is not available * @param addr An IP address */ - virtual void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); } + void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); } /** * @brief Get the maximum number of SSL sessions that can be stored at once * * @returns The SessionCache template parameter. */ - virtual size_t getSessionCount() const { return SessionCache; } + size_t getSessionCount() const override { return SessionCache; } /** * @brief Equivalent to SSLClient::connected() > 0 * * @returns true if connected, false if not */ - virtual operator bool() { return connected() > 0; } + operator bool() { return connected() > 0; } /** @see SSLClient::operator bool */ - virtual bool operator==(const bool value) { return bool() == value; } + bool operator==(const bool value) { return bool() == value; } /** @see SSLClient::operator bool */ - virtual bool operator!=(const bool value) { return bool() != value; } + bool operator!=(const bool value) { return bool() != value; } /** @brief Returns whether or not two SSLClient objects have the same underlying client object */ - virtual bool operator==(const C& rhs) { return m_client == rhs; } + bool operator==(const C& rhs) { return m_client == rhs; } /** @brief Returns whether or not two SSLClient objects do not have the same underlying client object */ - virtual bool operator!=(const C& rhs) { return m_client != rhs; } + bool operator!=(const C& rhs) { return m_client != rhs; } /** @brief Returns the local port, C::localPort exists. Else return 0. */ - virtual uint16_t localPort() { + uint16_t localPort() override { if (std::is_member_function_pointer::value) return m_client.localPort(); else { m_warn("Client class has no localPort function, so localPort() will always return 0", __func__); @@ -339,7 +339,7 @@ public: } } /** @brief Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE. */ - virtual IPAddress remoteIP() { + IPAddress remoteIP() override { if (std::is_member_function_pointer::value) return m_client.remoteIP(); else { m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__); @@ -347,7 +347,7 @@ public: } } /** @brief Returns the remote port, if C::remotePort exists. Else return 0. */ - virtual uint16_t remotePort() { + uint16_t remotePort() override { if (std::is_member_function_pointer::value) return m_client.remotePort(); else { m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__); @@ -360,11 +360,11 @@ public: protected: /** @brief Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl */ - virtual Client& get_arduino_client() { return m_client; } - virtual const Client& get_arduino_client() const { return m_client; } + Client& get_arduino_client() override { return m_client; } + const Client& get_arduino_client() const override { return m_client; } /** @brief Returns an instance of the session array that is on the stack */ - virtual SSLSession* get_session_array() { return m_sessions; } - virtual const SSLSession* get_session_array() const { return m_sessions; } + SSLSession* get_session_array() override { return m_sessions; } + const SSLSession* get_session_array() const override { return m_sessions; } private: // create a copy of the client From f4561d04156e797142499d892934a028077bae60 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 10 Jun 2019 10:30:06 -0700 Subject: [PATCH 048/205] updated examples and timeout to reflect arduino.cc certificate change --- examples/EthernetHTTPS/trust_anchors.h | 71 ++++++++-------- examples/EthernetMultiHTTPS/trustanchors.h | 95 +++++++++++----------- src/SSLClient.h | 2 +- 3 files changed, 85 insertions(+), 83 deletions(-) diff --git a/examples/EthernetHTTPS/trust_anchors.h b/examples/EthernetHTTPS/trust_anchors.h index 42e8454..c456e9b 100644 --- a/examples/EthernetHTTPS/trust_anchors.h +++ b/examples/EthernetHTTPS/trust_anchors.h @@ -10,52 +10,53 @@ extern "C" * Certificates are BearSSL br_x509_trust_anchor format. Included certs: * * Index: 0 - * Label: Starfield Class 2 Certification Authority - * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority + * Label: AddTrust External CA Root + * Subject: C=SE,O=AddTrust AB,OU=AddTrust External TTP Network,CN=AddTrust External CA Root * Domain(s): www.arduino.cc */ #define TAs_NUM 1 static const unsigned char TA_DN0[] = { - 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, - 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, - 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, - 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, - 0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, + 0x42, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, + 0x20, 0x52, 0x6f, 0x6f, 0x74, }; static const unsigned char TA_RSA_N0[] = { - 0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11, - 0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab, - 0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b, - 0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec, - 0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0, - 0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66, - 0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb, - 0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26, - 0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a, - 0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4, - 0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66, - 0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b, - 0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51, - 0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c, - 0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3, - 0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c, - 0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64, - 0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87, - 0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b, - 0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d, - 0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2, - 0x44, 0xa0, 0x01, 0xab, + 0xb7, 0xf7, 0x1a, 0x33, 0xe6, 0xf2, 0x00, 0x04, 0x2d, 0x39, 0xe0, 0x4e, + 0x5b, 0xed, 0x1f, 0xbc, 0x6c, 0x0f, 0xcd, 0xb5, 0xfa, 0x23, 0xb6, 0xce, + 0xde, 0x9b, 0x11, 0x33, 0x97, 0xa4, 0x29, 0x4c, 0x7d, 0x93, 0x9f, 0xbd, + 0x4a, 0xbc, 0x93, 0xed, 0x03, 0x1a, 0xe3, 0x8f, 0xcf, 0xe5, 0x6d, 0x50, + 0x5a, 0xd6, 0x97, 0x29, 0x94, 0x5a, 0x80, 0xb0, 0x49, 0x7a, 0xdb, 0x2e, + 0x95, 0xfd, 0xb8, 0xca, 0xbf, 0x37, 0x38, 0x2d, 0x1e, 0x3e, 0x91, 0x41, + 0xad, 0x70, 0x56, 0xc7, 0xf0, 0x4f, 0x3f, 0xe8, 0x32, 0x9e, 0x74, 0xca, + 0xc8, 0x90, 0x54, 0xe9, 0xc6, 0x5f, 0x0f, 0x78, 0x9d, 0x9a, 0x40, 0x3c, + 0x0e, 0xac, 0x61, 0xaa, 0x5e, 0x14, 0x8f, 0x9e, 0x87, 0xa1, 0x6a, 0x50, + 0xdc, 0xd7, 0x9a, 0x4e, 0xaf, 0x05, 0xb3, 0xa6, 0x71, 0x94, 0x9c, 0x71, + 0xb3, 0x50, 0x60, 0x0a, 0xc7, 0x13, 0x9d, 0x38, 0x07, 0x86, 0x02, 0xa8, + 0xe9, 0xa8, 0x69, 0x26, 0x18, 0x90, 0xab, 0x4c, 0xb0, 0x4f, 0x23, 0xab, + 0x3a, 0x4f, 0x84, 0xd8, 0xdf, 0xce, 0x9f, 0xe1, 0x69, 0x6f, 0xbb, 0xd7, + 0x42, 0xd7, 0x6b, 0x44, 0xe4, 0xc7, 0xad, 0xee, 0x6d, 0x41, 0x5f, 0x72, + 0x5a, 0x71, 0x08, 0x37, 0xb3, 0x79, 0x65, 0xa4, 0x59, 0xa0, 0x94, 0x37, + 0xf7, 0x00, 0x2f, 0x0d, 0xc2, 0x92, 0x72, 0xda, 0xd0, 0x38, 0x72, 0xdb, + 0x14, 0xa8, 0x45, 0xc4, 0x5d, 0x2a, 0x7d, 0xb7, 0xb4, 0xd6, 0xc4, 0xee, + 0xac, 0xcd, 0x13, 0x44, 0xb7, 0xc9, 0x2b, 0xdd, 0x43, 0x00, 0x25, 0xfa, + 0x61, 0xb9, 0x69, 0x6a, 0x58, 0x23, 0x11, 0xb7, 0xa7, 0x33, 0x8f, 0x56, + 0x75, 0x59, 0xf5, 0xcd, 0x29, 0xd7, 0x46, 0xb7, 0x0a, 0x2b, 0x65, 0xb6, + 0xd3, 0x42, 0x6f, 0x15, 0xb2, 0xb8, 0x7b, 0xfb, 0xef, 0xe9, 0x5d, 0x53, + 0xd5, 0x34, 0x5a, 0x27, }; static const unsigned char TA_RSA_E0[] = { - 0x03, + 0x01, 0x00, 0x01, }; static const br_x509_trust_anchor TAs[] = { @@ -76,4 +77,4 @@ static const br_x509_trust_anchor TAs[] = { } /* extern "C" */ #endif -#endif /* ifndef _CERTIFICATES_H_ */ \ No newline at end of file +#endif /* ifndef _CERTIFICATES_H_ */ diff --git a/examples/EthernetMultiHTTPS/trustanchors.h b/examples/EthernetMultiHTTPS/trustanchors.h index 9864cda..2c7f67b 100644 --- a/examples/EthernetMultiHTTPS/trustanchors.h +++ b/examples/EthernetMultiHTTPS/trustanchors.h @@ -10,60 +10,19 @@ extern "C" * Certificates are BearSSL br_x509_trust_anchor format. Included certs: * * Index: 0 - * Label: Starfield Class 2 Certification Authority - * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority - * Domain(s): www.arduino.cc - * - * Index: 1 * Label: DigiCert High Assurance EV Root CA * Subject: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert High Assurance EV Root CA * Domain(s): www.cloudflare.com + * + * Index: 1 + * Label: AddTrust External CA Root + * Subject: C=SE,O=AddTrust AB,OU=AddTrust External TTP Network,CN=AddTrust External CA Root + * Domain(s): www.arduino.cc */ #define TAs_NUM 2 static const unsigned char TA_DN0[] = { - 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, - 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, - 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, - 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, - 0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, -}; - -static const unsigned char TA_RSA_N0[] = { - 0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11, - 0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab, - 0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b, - 0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec, - 0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0, - 0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66, - 0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb, - 0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26, - 0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a, - 0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4, - 0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66, - 0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b, - 0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51, - 0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c, - 0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3, - 0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c, - 0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64, - 0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87, - 0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b, - 0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d, - 0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2, - 0x44, 0xa0, 0x01, 0xab, -}; - -static const unsigned char TA_RSA_E0[] = { - 0x03, -}; - -static const unsigned char TA_DN1[] = { 0x30, 0x6c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, @@ -76,7 +35,7 @@ static const unsigned char TA_DN1[] = { 0x43, 0x41, }; -static const unsigned char TA_RSA_N1[] = { +static const unsigned char TA_RSA_N0[] = { 0xc6, 0xcc, 0xe5, 0x73, 0xe6, 0xfb, 0xd4, 0xbb, 0xe5, 0x2d, 0x2d, 0x32, 0xa6, 0xdf, 0xe5, 0x81, 0x3f, 0xc9, 0xcd, 0x25, 0x49, 0xb6, 0x71, 0x2a, 0xc3, 0xd5, 0x94, 0x34, 0x67, 0xa2, 0x0a, 0x1c, 0xb0, 0x5f, 0x69, 0xa6, @@ -101,6 +60,48 @@ static const unsigned char TA_RSA_N1[] = { 0x38, 0xb8, 0x4b, 0xcb, }; +static const unsigned char TA_RSA_E0[] = { + 0x01, 0x00, 0x01, +}; + +static const unsigned char TA_DN1[] = { + 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, + 0x42, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, + 0x20, 0x52, 0x6f, 0x6f, 0x74, +}; + +static const unsigned char TA_RSA_N1[] = { + 0xb7, 0xf7, 0x1a, 0x33, 0xe6, 0xf2, 0x00, 0x04, 0x2d, 0x39, 0xe0, 0x4e, + 0x5b, 0xed, 0x1f, 0xbc, 0x6c, 0x0f, 0xcd, 0xb5, 0xfa, 0x23, 0xb6, 0xce, + 0xde, 0x9b, 0x11, 0x33, 0x97, 0xa4, 0x29, 0x4c, 0x7d, 0x93, 0x9f, 0xbd, + 0x4a, 0xbc, 0x93, 0xed, 0x03, 0x1a, 0xe3, 0x8f, 0xcf, 0xe5, 0x6d, 0x50, + 0x5a, 0xd6, 0x97, 0x29, 0x94, 0x5a, 0x80, 0xb0, 0x49, 0x7a, 0xdb, 0x2e, + 0x95, 0xfd, 0xb8, 0xca, 0xbf, 0x37, 0x38, 0x2d, 0x1e, 0x3e, 0x91, 0x41, + 0xad, 0x70, 0x56, 0xc7, 0xf0, 0x4f, 0x3f, 0xe8, 0x32, 0x9e, 0x74, 0xca, + 0xc8, 0x90, 0x54, 0xe9, 0xc6, 0x5f, 0x0f, 0x78, 0x9d, 0x9a, 0x40, 0x3c, + 0x0e, 0xac, 0x61, 0xaa, 0x5e, 0x14, 0x8f, 0x9e, 0x87, 0xa1, 0x6a, 0x50, + 0xdc, 0xd7, 0x9a, 0x4e, 0xaf, 0x05, 0xb3, 0xa6, 0x71, 0x94, 0x9c, 0x71, + 0xb3, 0x50, 0x60, 0x0a, 0xc7, 0x13, 0x9d, 0x38, 0x07, 0x86, 0x02, 0xa8, + 0xe9, 0xa8, 0x69, 0x26, 0x18, 0x90, 0xab, 0x4c, 0xb0, 0x4f, 0x23, 0xab, + 0x3a, 0x4f, 0x84, 0xd8, 0xdf, 0xce, 0x9f, 0xe1, 0x69, 0x6f, 0xbb, 0xd7, + 0x42, 0xd7, 0x6b, 0x44, 0xe4, 0xc7, 0xad, 0xee, 0x6d, 0x41, 0x5f, 0x72, + 0x5a, 0x71, 0x08, 0x37, 0xb3, 0x79, 0x65, 0xa4, 0x59, 0xa0, 0x94, 0x37, + 0xf7, 0x00, 0x2f, 0x0d, 0xc2, 0x92, 0x72, 0xda, 0xd0, 0x38, 0x72, 0xdb, + 0x14, 0xa8, 0x45, 0xc4, 0x5d, 0x2a, 0x7d, 0xb7, 0xb4, 0xd6, 0xc4, 0xee, + 0xac, 0xcd, 0x13, 0x44, 0xb7, 0xc9, 0x2b, 0xdd, 0x43, 0x00, 0x25, 0xfa, + 0x61, 0xb9, 0x69, 0x6a, 0x58, 0x23, 0x11, 0xb7, 0xa7, 0x33, 0x8f, 0x56, + 0x75, 0x59, 0xf5, 0xcd, 0x29, 0xd7, 0x46, 0xb7, 0x0a, 0x2b, 0x65, 0xb6, + 0xd3, 0x42, 0x6f, 0x15, 0xb2, 0xb8, 0x7b, 0xfb, 0xef, 0xe9, 0x5d, 0x53, + 0xd5, 0x34, 0x5a, 0x27, +}; + static const unsigned char TA_RSA_E1[] = { 0x01, 0x00, 0x01, }; diff --git a/src/SSLClient.h b/src/SSLClient.h index 2927a77..d06dcd5 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -75,7 +75,7 @@ public: { // set the timeout to a reasonable number (it can always be changes later) // SSL Connections take a really long time so we don't want to time out a legitimate thing - setTimeout(10 * 1000); + setTimeout(30 * 1000); } //======================================== From f3509c98753e0dc8fb69fcdd4630fd412a847e8b Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 10 Jun 2019 14:25:28 -0700 Subject: [PATCH 049/205] fixed bug where SSLclient would self-corrupt if connected() was called before the first connection --- src/SSLClientImpl.cpp | 9 +++++++-- src/SSLClientImpl.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 12efbf4..130b11a 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -57,6 +57,7 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, , m_analog_pin(analog_pin) , m_session_index(0) , m_debug(debug) + , m_is_connected(false) , m_write_idx(0) { // zero the iobuf just in case it's still garbage @@ -101,6 +102,7 @@ int SSLClientImpl::connect_impl(const char *host, uint16_t port) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } + m_info("Client not connected, continuing...", func_name); // reset indexs for saftey m_write_idx = 0; // first, if we have a session, check if we're trying to resolve the same host @@ -244,6 +246,8 @@ void SSLClientImpl::stop_impl() { } // close the ethernet socket get_arduino_client().stop(); + // we are no longer connected + m_is_connected = false; } /* see SSLClientImpl.h */ @@ -251,7 +255,7 @@ uint8_t SSLClientImpl::connected_impl() { const char* func_name = __func__; // check all of the error cases const auto c_con = get_arduino_client().connected(); - const auto br_con = br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED; + const auto br_con = br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED && m_is_connected; const auto wr_ok = getWriteError() == 0; // if we're in an error state, close the connection and set a write error if (br_con && !c_con) { @@ -310,7 +314,7 @@ bool SSLClientImpl::m_soft_connected(const char* func_name) { return false; } // check if the ssl engine is still open - if(br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED) { + if(!m_is_connected || br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED) { m_error("Cannot operate on a closed SSL connection.", func_name); int error = br_ssl_engine_last_error(&m_sslctx.eng); if(error != BR_ERR_OK) m_print_br_error(error, SSL_ERROR); @@ -352,6 +356,7 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { return 0; } m_info("Connection successful!", func_name); + m_is_connected = true; // all good to go! the SSL socket should be up and running // overwrite the session we got with new parameters br_ssl_engine_get_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index a7dd03f..710458f 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -181,6 +181,8 @@ private: size_t m_session_index; // store whether to enable debug logging const DebugLevel m_debug; + // store if we are connected in bearssl or not + bool m_is_connected; // store the context values required for SSL br_ssl_client_context m_sslctx; br_x509_minimal_context m_x509ctx; From 75bc956a8ec570d7580dbc9350589798c3c6cc2a Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 11 Jun 2019 11:29:37 -0700 Subject: [PATCH 050/205] Fixed documentation to reflect available() requiring connected() for proper operation --- docs/html/_s_s_l_client_8h_source.html | 52 ++++++++++----------- docs/html/_s_s_l_client_impl_8h_source.html | 26 +++++------ docs/html/class_s_s_l_client.html | 4 +- docs/html/trust__anchors_8h_source.html | 2 +- docs/html/trustanchors_8h_source.html | 2 +- src/SSLClient.h | 9 ++-- 6 files changed, 48 insertions(+), 47 deletions(-) diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index 399ab6a..9c2ad57 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -91,48 +91,48 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
                      SSLClient.h
                      -Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include <type_traits>
                      22 #include "Client.h"
                      23 #include "SSLClientImpl.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClient_H_
                      27 #define SSLClient_H_
                      28 
                      34 template <class C, size_t SessionCache = 1>
                      35 class SSLClient : public SSLClientImpl {
                      36 /*
                      37  * static checks
                      38  * I'm a java developer, so I want to ensure that my inheritance is safe.
                      39  * These checks ensure that all the functions we use on class C are
                      40  * actually present on class C. It does this by checking that the
                      41  * class inherits from Client.
                      42  *
                      43  * Additionally, I ran into a lot of memory issues with large sessions caches.
                      44  * Since each session contains at max 352 bytes of memory, they eat of the
                      45  * stack quite quickly and can cause overflows. As a result, I have added a
                      46  * warning here to discourage the use of more than 3 sessions at a time. Any
                      47  * amount past that will require special modification of this library, and
                      48  * assumes you know what you are doing.
                      49  */
                      50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
                      51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
                      52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
                      53 
                      54 public:
                      71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
                      72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
                      73  , m_client(client)
                      74  , m_sessions{SSLSession()}
                      75  {
                      76  // set the timeout to a reasonable number (it can always be changes later)
                      77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
                      78  setTimeout(10 * 1000);
                      79  }
                      80 
                      81  //========================================
                      82  //= Functions implemented in SSLClientImpl
                      83  //========================================
                      84 
                      124  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
                      125 
                      162  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
                      163 
                      165  size_t write(uint8_t b) override { return write_impl(&b, 1); }
                      189  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
                      190 
                      209  int available() override { return available_impl(); }
                      210 
                      215  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
                      237  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
                      238 
                      247  int peek() override { return peek_impl(); }
                      248 
                      256  void flush() override { return flush_impl(); }
                      257 
                      266  void stop() override { return stop_impl(); }
                      267 
                      280  uint8_t connected() override { return connected_impl(); }
                      281 
                      282  //========================================
                      283  //= Functions Not in the Client Interface
                      284  //========================================
                      285 
                      300  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
                      301 
                      310  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
                      311 
                      317  size_t getSessionCount() const override { return SessionCache; }
                      318 
                      324  operator bool() { return connected() > 0; }
                      326  bool operator==(const bool value) { return bool() == value; }
                      328  bool operator!=(const bool value) { return bool() != value; }
                      330  bool operator==(const C& rhs) { return m_client == rhs; }
                      332  bool operator!=(const C& rhs) { return m_client != rhs; }
                      334  uint16_t localPort() override {
                      335  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
                      336  else {
                      337  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
                      338  return 0;
                      339  }
                      340  }
                      342  IPAddress remoteIP() override {
                      343  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
                      344  else {
                      345  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
                      346  return INADDR_NONE;
                      347  }
                      348  }
                      350  uint16_t remotePort() override {
                      351  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
                      352  else {
                      353  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
                      354  return 0;
                      355  }
                      356  }
                      357 
                      359  C& getClient() { return m_client; }
                      360 
                      361 protected:
                      363  Client& get_arduino_client() override { return m_client; }
                      364  const Client& get_arduino_client() const override { return m_client; }
                      366  SSLSession* get_session_array() override { return m_sessions; }
                      367  const SSLSession* get_session_array() const override { return m_sessions; }
                      368 
                      369 private:
                      370  // create a copy of the client
                      371  C m_client;
                      372  // also store an array of SSLSessions, so we can resume communication with multiple websites
                      373  SSLSession m_sessions[SessionCache];
                      374 };
                      375 
                      376 #endif
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:130
                      -
                      const SSLSession * get_session_array() const override
                      Definition: SSLClient.h:367
                      -
                      IPAddress remoteIP() override
                      Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
                      Definition: SSLClient.h:342
                      +Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include <type_traits>
                      22 #include "Client.h"
                      23 #include "SSLClientImpl.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClient_H_
                      27 #define SSLClient_H_
                      28 
                      34 template <class C, size_t SessionCache = 1>
                      35 class SSLClient : public SSLClientImpl {
                      36 /*
                      37  * static checks
                      38  * I'm a java developer, so I want to ensure that my inheritance is safe.
                      39  * These checks ensure that all the functions we use on class C are
                      40  * actually present on class C. It does this by checking that the
                      41  * class inherits from Client.
                      42  *
                      43  * Additionally, I ran into a lot of memory issues with large sessions caches.
                      44  * Since each session contains at max 352 bytes of memory, they eat of the
                      45  * stack quite quickly and can cause overflows. As a result, I have added a
                      46  * warning here to discourage the use of more than 3 sessions at a time. Any
                      47  * amount past that will require special modification of this library, and
                      48  * assumes you know what you are doing.
                      49  */
                      50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
                      51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
                      52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
                      53 
                      54 public:
                      71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
                      72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
                      73  , m_client(client)
                      74  , m_sessions{SSLSession()}
                      75  {
                      76  // set the timeout to a reasonable number (it can always be changes later)
                      77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
                      78  setTimeout(30 * 1000);
                      79  }
                      80 
                      81  //========================================
                      82  //= Functions implemented in SSLClientImpl
                      83  //========================================
                      84 
                      124  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
                      125 
                      162  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
                      163 
                      165  size_t write(uint8_t b) override { return write_impl(&b, 1); }
                      189  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
                      190 
                      209  int available() override { return available_impl(); }
                      210 
                      215  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
                      237  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
                      238 
                      247  int peek() override { return peek_impl(); }
                      248 
                      256  void flush() override { return flush_impl(); }
                      257 
                      266  void stop() override { return stop_impl(); }
                      267 
                      281  uint8_t connected() override { return connected_impl(); }
                      282 
                      283  //========================================
                      284  //= Functions Not in the Client Interface
                      285  //========================================
                      286 
                      301  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
                      302 
                      311  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
                      312 
                      318  size_t getSessionCount() const override { return SessionCache; }
                      319 
                      325  operator bool() { return connected() > 0; }
                      327  bool operator==(const bool value) { return bool() == value; }
                      329  bool operator!=(const bool value) { return bool() != value; }
                      331  bool operator==(const C& rhs) { return m_client == rhs; }
                      333  bool operator!=(const C& rhs) { return m_client != rhs; }
                      335  uint16_t localPort() override {
                      336  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
                      337  else {
                      338  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
                      339  return 0;
                      340  }
                      341  }
                      343  IPAddress remoteIP() override {
                      344  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
                      345  else {
                      346  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
                      347  return INADDR_NONE;
                      348  }
                      349  }
                      351  uint16_t remotePort() override {
                      352  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
                      353  else {
                      354  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
                      355  return 0;
                      356  }
                      357  }
                      358 
                      360  C& getClient() { return m_client; }
                      361 
                      362 protected:
                      364  Client& get_arduino_client() override { return m_client; }
                      365  const Client& get_arduino_client() const override { return m_client; }
                      367  SSLSession* get_session_array() override { return m_sessions; }
                      368  const SSLSession* get_session_array() const override { return m_sessions; }
                      369 
                      370 private:
                      371  // create a copy of the client
                      372  C m_client;
                      373  // also store an array of SSLSessions, so we can resume communication with multiple websites
                      374  SSLSession m_sessions[SessionCache];
                      375 };
                      376 
                      377 #endif
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:132
                      +
                      const SSLSession * get_session_array() const override
                      Definition: SSLClient.h:368
                      +
                      IPAddress remoteIP() override
                      Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
                      Definition: SSLClient.h:343
                      size_t write(uint8_t b) override
                      Definition: SSLClient.h:165
                      Definition: SSLClientImpl.h:65
                      -
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:276
                      +
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:280
                      This class stores values which allow SSLClient to save and resume SSL sessions.
                      Definition: SSLSession.h:52
                      -
                      bool operator!=(const C &rhs)
                      Returns whether or not two SSLClient objects do not have the same underlying client object.
                      Definition: SSLClient.h:332
                      +
                      bool operator!=(const C &rhs)
                      Returns whether or not two SSLClient objects do not have the same underlying client object.
                      Definition: SSLClient.h:333
                      int available() override
                      Returns the number of bytes available to read from the data that has been received and decrypted.
                      Definition: SSLClient.h:209
                      -
                      C & getClient()
                      Returns a reference to the client object stored in this class. Take care not to break it.
                      Definition: SSLClient.h:359
                      -
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:209
                      +
                      C & getClient()
                      Returns a reference to the client object stored in this class. Take care not to break it.
                      Definition: SSLClient.h:360
                      +
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:211
                      void flush() override
                      Force writing the buffered bytes from SSLClient::write to the network.
                      Definition: SSLClient.h:256
                      The main SSLClient class. Check out README.md for more info.
                      Definition: SSLClient.h:35
                      -
                      bool operator!=(const bool value)
                      Definition: SSLClient.h:328
                      +
                      bool operator!=(const bool value)
                      Definition: SSLClient.h:329
                      void stop() override
                      Close the connection.
                      Definition: SSLClient.h:266
                      size_t write(const uint8_t *buf, size_t size) override
                      Write some bytes to the SSL connection.
                      Definition: SSLClient.h:189
                      SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
                      Initialize SSLClient with all of the prerequisites needed.
                      Definition: SSLClient.h:71
                      int peek() override
                      View the first byte of the buffer, without removing it from the SSLClient Buffer.
                      Definition: SSLClient.h:247
                      -
                      int available_impl()
                      Definition: SSLClientImpl.cpp:173
                      -
                      bool operator==(const C &rhs)
                      Returns whether or not two SSLClient objects have the same underlying client object.
                      Definition: SSLClient.h:330
                      -
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:194
                      -
                      SSLSession * get_session_array() override
                      Returns an instance of the session array that is on the stack.
                      Definition: SSLClient.h:366
                      -
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:295
                      -
                      Client & get_arduino_client() override
                      Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
                      Definition: SSLClient.h:363
                      -
                      uint16_t localPort() override
                      Returns the local port, C::localPort exists. Else return 0.
                      Definition: SSLClient.h:334
                      +
                      int available_impl()
                      Definition: SSLClientImpl.cpp:175
                      +
                      bool operator==(const C &rhs)
                      Returns whether or not two SSLClient objects have the same underlying client object.
                      Definition: SSLClient.h:331
                      +
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:196
                      +
                      SSLSession * get_session_array() override
                      Returns an instance of the session array that is on the stack.
                      Definition: SSLClient.h:367
                      +
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:299
                      +
                      Client & get_arduino_client() override
                      Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
                      Definition: SSLClient.h:364
                      +
                      uint16_t localPort() override
                      Returns the local port, C::localPort exists. Else return 0.
                      Definition: SSLClient.h:335
                      void m_warn(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:153
                      int read() override
                      Read a single byte, or -1 if none is available.
                      Definition: SSLClient.h:215
                      -
                      uint8_t connected() override
                      Check if the device is connected.
                      Definition: SSLClient.h:280
                      +
                      uint8_t connected() override
                      Check if the device is connected.
                      Definition: SSLClient.h:281
                      -
                      const Client & get_arduino_client() const override
                      Definition: SSLClient.h:364
                      +
                      const Client & get_arduino_client() const override
                      Definition: SSLClient.h:365
                      int connect(const char *host, uint16_t port) override
                      Connect over SSL to a host specified by a hostname.
                      Definition: SSLClient.h:162
                      -
                      bool operator==(const bool value)
                      Definition: SSLClient.h:326
                      -
                      uint16_t remotePort() override
                      Returns the remote port, if C::remotePort exists. Else return 0.
                      Definition: SSLClient.h:350
                      -
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:74
                      -
                      size_t getSessionCount() const override
                      Get the maximum number of SSL sessions that can be stored at once.
                      Definition: SSLClient.h:317
                      -
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:229
                      -
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:221
                      +
                      bool operator==(const bool value)
                      Definition: SSLClient.h:327
                      +
                      uint16_t remotePort() override
                      Returns the remote port, if C::remotePort exists. Else return 0.
                      Definition: SSLClient.h:351
                      +
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:75
                      +
                      size_t getSessionCount() const override
                      Get the maximum number of SSL sessions that can be stored at once.
                      Definition: SSLClient.h:318
                      +
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:231
                      +
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:223
                      Implementation code to be inherited by SSLClient.
                      Definition: SSLClientImpl.h:71
                      -
                      void removeSession(const char *host, const IPAddress &addr)
                      Clear the session corresponding to a host and IP.
                      Definition: SSLClient.h:310
                      -
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:250
                      -
                      SSLSession & getSession(const char *host, const IPAddress &addr)
                      Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
                      Definition: SSLClient.h:300
                      +
                      void removeSession(const char *host, const IPAddress &addr)
                      Clear the session corresponding to a host and IP.
                      Definition: SSLClient.h:311
                      +
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:254
                      +
                      SSLSession & getSession(const char *host, const IPAddress &addr)
                      Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
                      Definition: SSLClient.h:301
                      DebugLevel
                      Level of verbosity used in logging for SSLClient.
                      Definition: SSLClientImpl.h:59
                      int read(uint8_t *buf, size_t size) override
                      Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
                      Definition: SSLClient.h:237
                      int connect(IPAddress ip, uint16_t port) override
                      Connect over SSL to a host specified by an IP address.
                      Definition: SSLClient.h:124
                      diff --git a/docs/html/_s_s_l_client_impl_8h_source.html b/docs/html/_s_s_l_client_impl_8h_source.html index b33a4e3..1b5e56e 100644 --- a/docs/html/_s_s_l_client_impl_8h_source.html +++ b/docs/html/_s_s_l_client_impl_8h_source.html @@ -91,17 +91,17 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h_source.html','')
                      SSLClientImpl.h
                      -Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include "bearssl.h"
                      22 #include "Arduino.h"
                      23 #include "Client.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClientImpl_H_
                      27 #define SSLClientImpl_H_
                      28 
                      37 enum Error {
                      38  SSL_OK = 0,
                      51 };
                      52 
                      59 enum DebugLevel {
                      61  SSL_NONE = 0,
                      63  SSL_ERROR = 1,
                      65  SSL_WARN = 2,
                      67  SSL_INFO = 3,
                      68 };
                      69 
                      71 class SSLClientImpl : public Client {
                      72 public:
                      74  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
                      75  const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug);
                      76 
                      77  //============================================
                      78  //= Functions implemented in SSLClientImpl.cpp
                      79  //============================================
                      80 
                      82  int connect_impl(IPAddress ip, uint16_t port);
                      84  int connect_impl(const char *host, uint16_t port);
                      86  size_t write_impl(const uint8_t *buf, size_t size);
                      88  int available_impl();
                      90  int read_impl(uint8_t *buf, size_t size);
                      92  int peek_impl();
                      94  void flush_impl();
                      96  void stop_impl();
                      98  uint8_t connected_impl();
                      100  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
                      102  void remove_session_impl(const char* host, const IPAddress& addr);
                      103 
                      104  //============================================
                      105  //= Functions implemented in SSLClient.h
                      106  //============================================
                      108  virtual uint16_t localPort() = 0;
                      110  virtual IPAddress remoteIP() = 0;
                      112  virtual uint16_t remotePort() = 0;
                      114  virtual size_t getSessionCount() const = 0;
                      115 
                      116 protected:
                      118  virtual Client& get_arduino_client() = 0;
                      119  virtual const Client& get_arduino_client() const = 0;
                      121  virtual SSLSession* get_session_array() = 0;
                      122  virtual const SSLSession* get_session_array() const = 0;
                      123 
                      124  //============================================
                      125  //= Functions implemented in SSLClientImpl.cpp
                      126  //============================================
                      127 
                      129  void m_print_prefix(const char* func_name, const DebugLevel level) const;
                      130 
                      132  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
                      133 
                      135  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
                      136 
                      138  template<typename T>
                      139  void m_print(const T str, const char* func_name, const DebugLevel level) const {
                      140  // check the current debug level and serial status
                      141  if (level > m_debug || !Serial) return;
                      142  // print prefix
                      143  m_print_prefix(func_name, level);
                      144  // print the message
                      145  Serial.println(str);
                      146  }
                      147 
                      149  template<typename T>
                      150  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
                      151 
                      152  template<typename T>
                      153  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
                      154 
                      155  template<typename T>
                      156  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
                      157 
                      158 private:
                      160  bool m_soft_connected(const char* func_name);
                      162  int m_start_ssl(const char* host, SSLSession& ssl_ses);
                      164  int m_run_until(const unsigned target);
                      166  unsigned m_update_engine();
                      168  int m_get_session_index(const char* host, const IPAddress& addr) const;
                      169 
                      170  //============================================
                      171  //= Data Members
                      172  //============================================
                      173 
                      174  // store pointers to the trust anchors
                      175  // should not be computed at runtime
                      176  const br_x509_trust_anchor *m_trust_anchors;
                      177  const size_t m_trust_anchors_num;
                      178  // store the pin to fetch an RNG see from
                      179  const int m_analog_pin;
                      180  // store an index of where a new session can be placed if we don't have any corresponding sessions
                      181  size_t m_session_index;
                      182  // store whether to enable debug logging
                      183  const DebugLevel m_debug;
                      184  // store the context values required for SSL
                      185  br_ssl_client_context m_sslctx;
                      186  br_x509_minimal_context m_x509ctx;
                      187  // use a mono-directional buffer by default to cut memory in half
                      188  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
                      189  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
                      190  // simply edit this value to change the buffer size to the desired value
                      191  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
                      192  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
                      200  unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 4];
                      201  static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size");
                      202  // store the index of where we are writing in the buffer
                      203  // so we can send our records all at once to prevent
                      204  // weird timing issues
                      205  size_t m_write_idx;
                      206 };
                      207 
                      208 #endif /* SSLClientImpl_H_ */
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:130
                      +Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include "bearssl.h"
                      22 #include "Arduino.h"
                      23 #include "Client.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClientImpl_H_
                      27 #define SSLClientImpl_H_
                      28 
                      37 enum Error {
                      38  SSL_OK = 0,
                      51 };
                      52 
                      59 enum DebugLevel {
                      61  SSL_NONE = 0,
                      63  SSL_ERROR = 1,
                      65  SSL_WARN = 2,
                      67  SSL_INFO = 3,
                      68 };
                      69 
                      71 class SSLClientImpl : public Client {
                      72 public:
                      74  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
                      75  const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug);
                      76 
                      77  //============================================
                      78  //= Functions implemented in SSLClientImpl.cpp
                      79  //============================================
                      80 
                      82  int connect_impl(IPAddress ip, uint16_t port);
                      84  int connect_impl(const char *host, uint16_t port);
                      86  size_t write_impl(const uint8_t *buf, size_t size);
                      88  int available_impl();
                      90  int read_impl(uint8_t *buf, size_t size);
                      92  int peek_impl();
                      94  void flush_impl();
                      96  void stop_impl();
                      98  uint8_t connected_impl();
                      100  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
                      102  void remove_session_impl(const char* host, const IPAddress& addr);
                      103 
                      104  //============================================
                      105  //= Functions implemented in SSLClient.h
                      106  //============================================
                      108  virtual uint16_t localPort() = 0;
                      110  virtual IPAddress remoteIP() = 0;
                      112  virtual uint16_t remotePort() = 0;
                      114  virtual size_t getSessionCount() const = 0;
                      115 
                      116 protected:
                      118  virtual Client& get_arduino_client() = 0;
                      119  virtual const Client& get_arduino_client() const = 0;
                      121  virtual SSLSession* get_session_array() = 0;
                      122  virtual const SSLSession* get_session_array() const = 0;
                      123 
                      124  //============================================
                      125  //= Functions implemented in SSLClientImpl.cpp
                      126  //============================================
                      127 
                      129  void m_print_prefix(const char* func_name, const DebugLevel level) const;
                      130 
                      132  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
                      133 
                      135  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
                      136 
                      138  template<typename T>
                      139  void m_print(const T str, const char* func_name, const DebugLevel level) const {
                      140  // check the current debug level and serial status
                      141  if (level > m_debug || !Serial) return;
                      142  // print prefix
                      143  m_print_prefix(func_name, level);
                      144  // print the message
                      145  Serial.println(str);
                      146  }
                      147 
                      149  template<typename T>
                      150  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
                      151 
                      152  template<typename T>
                      153  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
                      154 
                      155  template<typename T>
                      156  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
                      157 
                      158 private:
                      160  bool m_soft_connected(const char* func_name);
                      162  int m_start_ssl(const char* host, SSLSession& ssl_ses);
                      164  int m_run_until(const unsigned target);
                      166  unsigned m_update_engine();
                      168  int m_get_session_index(const char* host, const IPAddress& addr) const;
                      169 
                      170  //============================================
                      171  //= Data Members
                      172  //============================================
                      173 
                      174  // store pointers to the trust anchors
                      175  // should not be computed at runtime
                      176  const br_x509_trust_anchor *m_trust_anchors;
                      177  const size_t m_trust_anchors_num;
                      178  // store the pin to fetch an RNG see from
                      179  const int m_analog_pin;
                      180  // store an index of where a new session can be placed if we don't have any corresponding sessions
                      181  size_t m_session_index;
                      182  // store whether to enable debug logging
                      183  const DebugLevel m_debug;
                      184  // store if we are connected in bearssl or not
                      185  bool m_is_connected;
                      186  // store the context values required for SSL
                      187  br_ssl_client_context m_sslctx;
                      188  br_x509_minimal_context m_x509ctx;
                      189  // use a mono-directional buffer by default to cut memory in half
                      190  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
                      191  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
                      192  // simply edit this value to change the buffer size to the desired value
                      193  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
                      194  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
                      202  unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 4];
                      203  static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size");
                      204  // store the index of where we are writing in the buffer
                      205  // so we can send our records all at once to prevent
                      206  // weird timing issues
                      207  size_t m_write_idx;
                      208 };
                      209 
                      210 #endif /* SSLClientImpl_H_ */
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:132
                      virtual uint16_t remotePort()=0
                      void m_print(const T str, const char *func_name, const DebugLevel level) const
                      debugging print function, only prints if m_debug is true
                      Definition: SSLClientImpl.h:139
                      Definition: SSLClientImpl.h:65
                      virtual IPAddress remoteIP()=0
                      -
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:276
                      +
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:280
                      This class stores values which allow SSLClient to save and resume SSL sessions.
                      Definition: SSLSession.h:52
                      void m_info(const T str, const char *func_name) const
                      Prints a info message to serial, if info messages are enabled.
                      Definition: SSLClientImpl.h:150
                      SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
                      Definition: SSLClientImpl.cpp:53
                      void m_error(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:156
                      -
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:209
                      +
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:211
                      Definition: SSLClientImpl.h:67
                      Definition: SSLClientImpl.h:63
                      Definition: SSLClientImpl.h:48
                      @@ -109,27 +109,27 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h_source.html','')
                      virtual SSLSession * get_session_array()=0
                      Definition: SSLClientImpl.h:46
                      Definition: SSLClientImpl.h:38
                      -
                      void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
                      Prints the string associated with a write error.
                      Definition: SSLClientImpl.cpp:649
                      -
                      int available_impl()
                      Definition: SSLClientImpl.cpp:173
                      +
                      void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
                      Prints the string associated with a write error.
                      Definition: SSLClientImpl.cpp:654
                      +
                      int available_impl()
                      Definition: SSLClientImpl.cpp:175
                      Error
                      Static constants defining the possible errors encountered.
                      Definition: SSLClientImpl.h:37
                      Definition: SSLClientImpl.h:42
                      -
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:194
                      -
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:295
                      +
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:196
                      +
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:299
                      Definition: SSLClientImpl.h:44
                      virtual Client & get_arduino_client()=0
                      Definition: SSLClientImpl.h:40
                      -
                      void m_print_prefix(const char *func_name, const DebugLevel level) const
                      Prints a debugging prefix to all logs, so we can attatch them to useful information.
                      Definition: SSLClientImpl.cpp:631
                      +
                      void m_print_prefix(const char *func_name, const DebugLevel level) const
                      Prints a debugging prefix to all logs, so we can attatch them to useful information.
                      Definition: SSLClientImpl.cpp:636
                      Definition: SSLClientImpl.h:61
                      -
                      void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
                      Print the text string associated with a BearSSL error code.
                      Definition: SSLClientImpl.cpp:664
                      +
                      void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
                      Print the text string associated with a BearSSL error code.
                      Definition: SSLClientImpl.cpp:669
                      void m_warn(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:153
                      -
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:74
                      +
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:75
                      Definition: SSLClientImpl.h:50
                      -
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:229
                      -
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:221
                      +
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:231
                      +
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:223
                      Implementation code to be inherited by SSLClient.
                      Definition: SSLClientImpl.h:71
                      virtual uint16_t localPort()=0
                      -
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:250
                      +
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:254
                      DebugLevel
                      Level of verbosity used in logging for SSLClient.
                      Definition: SSLClientImpl.h:59
                      diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index a9b36cf..364ee42 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -350,7 +350,7 @@ template<class C , size_t SessionCache = 1>

                      Returns the number of bytes available to read from the data that has been received and decrypted.

                      This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

                      The implementation for this function can be found in SSLClientImpl::available

                      -
                      Precondition
                      SSLClient::connected must be true.
                      +
                      Precondition
                      SSLClient::connected must be true. (Call SSLClient::connected before this function)
                      Returns
                      The number of bytes available (can be zero), or zero if any of the pre conditions aren't satisfied.
                      @@ -499,7 +499,7 @@ template<class C , size_t SessionCache = 1>

                      Check if the device is connected.

                      -

                      Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that SSLClient::available should be preferred over this function for rapid polling–both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently.

                      +

                      Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that this function should be called before SSLClient::available– both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently, and SSLClient::connected contains logic to ensure that if the socket is dropped SSLClient will react accordingly.

                      The implementation for this function can be found in SSLClientImpl::connected_impl.

                      Returns
                      1 if connected, 0 if not
                      diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index c6e8c34..bb93808 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('trust__anchors_8h_source.html','');});
                      trust_anchors.h
                      -Go to the documentation of this file.
                      1 #ifndef _CERTIFICATES_H_
                      2 #define _CERTIFICATES_H_
                      3 
                      4 #ifdef __cplusplus
                      5 extern "C"
                      6 {
                      7 #endif
                      8 
                      9 /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually.
                      10  * Certificates are BearSSL br_x509_trust_anchor format. Included certs:
                      11  *
                      12  * Index: 0
                      13  * Label: Starfield Class 2 Certification Authority
                      14  * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority
                      15  * Domain(s): www.arduino.cc
                      16  */
                      17 
                      18 #define TAs_NUM 1
                      19 
                      20 static const unsigned char TA_DN0[] = {
                      21  0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
                      22  0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
                      23  0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
                      24  0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73,
                      25  0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03,
                      26  0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65,
                      27  0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43,
                      28  0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
                      29  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
                      30 };
                      31 
                      32 static const unsigned char TA_RSA_N0[] = {
                      33  0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11,
                      34  0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab,
                      35  0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b,
                      36  0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec,
                      37  0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0,
                      38  0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66,
                      39  0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb,
                      40  0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26,
                      41  0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a,
                      42  0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4,
                      43  0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66,
                      44  0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b,
                      45  0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51,
                      46  0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c,
                      47  0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3,
                      48  0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c,
                      49  0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64,
                      50  0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87,
                      51  0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b,
                      52  0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d,
                      53  0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2,
                      54  0x44, 0xa0, 0x01, 0xab,
                      55 };
                      56 
                      57 static const unsigned char TA_RSA_E0[] = {
                      58  0x03,
                      59 };
                      60 
                      61 static const br_x509_trust_anchor TAs[] = {
                      62  {
                      63  { (unsigned char *)TA_DN0, sizeof TA_DN0 },
                      64  BR_X509_TA_CA,
                      65  {
                      66  BR_KEYTYPE_RSA,
                      67  { .rsa = {
                      68  (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
                      69  (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
                      70  } }
                      71  }
                      72  },
                      73 };
                      74 
                      75 #ifdef __cplusplus
                      76 } /* extern "C" */
                      77 #endif
                      78 
                      79 #endif /* ifndef _CERTIFICATES_H_ */
                      +Go to the documentation of this file.
                      1 #ifndef _CERTIFICATES_H_
                      2 #define _CERTIFICATES_H_
                      3 
                      4 #ifdef __cplusplus
                      5 extern "C"
                      6 {
                      7 #endif
                      8 
                      9 /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually.
                      10  * Certificates are BearSSL br_x509_trust_anchor format. Included certs:
                      11  *
                      12  * Index: 0
                      13  * Label: AddTrust External CA Root
                      14  * Subject: C=SE,O=AddTrust AB,OU=AddTrust External TTP Network,CN=AddTrust External CA Root
                      15  * Domain(s): www.arduino.cc
                      16  */
                      17 
                      18 #define TAs_NUM 1
                      19 
                      20 static const unsigned char TA_DN0[] = {
                      21  0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
                      22  0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
                      23  0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41,
                      24  0x42, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d,
                      25  0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74,
                      26  0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65,
                      27  0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55,
                      28  0x04, 0x03, 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74,
                      29  0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41,
                      30  0x20, 0x52, 0x6f, 0x6f, 0x74,
                      31 };
                      32 
                      33 static const unsigned char TA_RSA_N0[] = {
                      34  0xb7, 0xf7, 0x1a, 0x33, 0xe6, 0xf2, 0x00, 0x04, 0x2d, 0x39, 0xe0, 0x4e,
                      35  0x5b, 0xed, 0x1f, 0xbc, 0x6c, 0x0f, 0xcd, 0xb5, 0xfa, 0x23, 0xb6, 0xce,
                      36  0xde, 0x9b, 0x11, 0x33, 0x97, 0xa4, 0x29, 0x4c, 0x7d, 0x93, 0x9f, 0xbd,
                      37  0x4a, 0xbc, 0x93, 0xed, 0x03, 0x1a, 0xe3, 0x8f, 0xcf, 0xe5, 0x6d, 0x50,
                      38  0x5a, 0xd6, 0x97, 0x29, 0x94, 0x5a, 0x80, 0xb0, 0x49, 0x7a, 0xdb, 0x2e,
                      39  0x95, 0xfd, 0xb8, 0xca, 0xbf, 0x37, 0x38, 0x2d, 0x1e, 0x3e, 0x91, 0x41,
                      40  0xad, 0x70, 0x56, 0xc7, 0xf0, 0x4f, 0x3f, 0xe8, 0x32, 0x9e, 0x74, 0xca,
                      41  0xc8, 0x90, 0x54, 0xe9, 0xc6, 0x5f, 0x0f, 0x78, 0x9d, 0x9a, 0x40, 0x3c,
                      42  0x0e, 0xac, 0x61, 0xaa, 0x5e, 0x14, 0x8f, 0x9e, 0x87, 0xa1, 0x6a, 0x50,
                      43  0xdc, 0xd7, 0x9a, 0x4e, 0xaf, 0x05, 0xb3, 0xa6, 0x71, 0x94, 0x9c, 0x71,
                      44  0xb3, 0x50, 0x60, 0x0a, 0xc7, 0x13, 0x9d, 0x38, 0x07, 0x86, 0x02, 0xa8,
                      45  0xe9, 0xa8, 0x69, 0x26, 0x18, 0x90, 0xab, 0x4c, 0xb0, 0x4f, 0x23, 0xab,
                      46  0x3a, 0x4f, 0x84, 0xd8, 0xdf, 0xce, 0x9f, 0xe1, 0x69, 0x6f, 0xbb, 0xd7,
                      47  0x42, 0xd7, 0x6b, 0x44, 0xe4, 0xc7, 0xad, 0xee, 0x6d, 0x41, 0x5f, 0x72,
                      48  0x5a, 0x71, 0x08, 0x37, 0xb3, 0x79, 0x65, 0xa4, 0x59, 0xa0, 0x94, 0x37,
                      49  0xf7, 0x00, 0x2f, 0x0d, 0xc2, 0x92, 0x72, 0xda, 0xd0, 0x38, 0x72, 0xdb,
                      50  0x14, 0xa8, 0x45, 0xc4, 0x5d, 0x2a, 0x7d, 0xb7, 0xb4, 0xd6, 0xc4, 0xee,
                      51  0xac, 0xcd, 0x13, 0x44, 0xb7, 0xc9, 0x2b, 0xdd, 0x43, 0x00, 0x25, 0xfa,
                      52  0x61, 0xb9, 0x69, 0x6a, 0x58, 0x23, 0x11, 0xb7, 0xa7, 0x33, 0x8f, 0x56,
                      53  0x75, 0x59, 0xf5, 0xcd, 0x29, 0xd7, 0x46, 0xb7, 0x0a, 0x2b, 0x65, 0xb6,
                      54  0xd3, 0x42, 0x6f, 0x15, 0xb2, 0xb8, 0x7b, 0xfb, 0xef, 0xe9, 0x5d, 0x53,
                      55  0xd5, 0x34, 0x5a, 0x27,
                      56 };
                      57 
                      58 static const unsigned char TA_RSA_E0[] = {
                      59  0x01, 0x00, 0x01,
                      60 };
                      61 
                      62 static const br_x509_trust_anchor TAs[] = {
                      63  {
                      64  { (unsigned char *)TA_DN0, sizeof TA_DN0 },
                      65  BR_X509_TA_CA,
                      66  {
                      67  BR_KEYTYPE_RSA,
                      68  { .rsa = {
                      69  (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
                      70  (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
                      71  } }
                      72  }
                      73  },
                      74 };
                      75 
                      76 #ifdef __cplusplus
                      77 } /* extern "C" */
                      78 #endif
                      79 
                      80 #endif /* ifndef _CERTIFICATES_H_ */
                      -Go to the documentation of this file.
                      1 #ifndef _CERTIFICATES_H_
                      2 #define _CERTIFICATES_H_
                      3 
                      4 #ifdef __cplusplus
                      5 extern "C"
                      6 {
                      7 #endif
                      8 
                      9 /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually.
                      10  * Certificates are BearSSL br_x509_trust_anchor format. Included certs:
                      11  *
                      12  * Index: 0
                      13  * Label: Starfield Class 2 Certification Authority
                      14  * Subject: C=US,O=Starfield Technologies\, Inc.,OU=Starfield Class 2 Certification Authority
                      15  * Domain(s): www.arduino.cc
                      16  *
                      17  * Index: 1
                      18  * Label: DigiCert High Assurance EV Root CA
                      19  * Subject: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert High Assurance EV Root CA
                      20  * Domain(s): www.cloudflare.com
                      21  */
                      22 
                      23 #define TAs_NUM 2
                      24 
                      25 static const unsigned char TA_DN0[] = {
                      26  0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
                      27  0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
                      28  0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
                      29  0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73,
                      30  0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03,
                      31  0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65,
                      32  0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43,
                      33  0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
                      34  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
                      35 };
                      36 
                      37 static const unsigned char TA_RSA_N0[] = {
                      38  0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11,
                      39  0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab,
                      40  0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b,
                      41  0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec,
                      42  0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0,
                      43  0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66,
                      44  0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb,
                      45  0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26,
                      46  0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a,
                      47  0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4,
                      48  0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66,
                      49  0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b,
                      50  0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51,
                      51  0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c,
                      52  0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3,
                      53  0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c,
                      54  0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64,
                      55  0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87,
                      56  0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b,
                      57  0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d,
                      58  0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2,
                      59  0x44, 0xa0, 0x01, 0xab,
                      60 };
                      61 
                      62 static const unsigned char TA_RSA_E0[] = {
                      63  0x03,
                      64 };
                      65 
                      66 static const unsigned char TA_DN1[] = {
                      67  0x30, 0x6c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
                      68  0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a,
                      69  0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49,
                      70  0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
                      71  0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72,
                      72  0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55,
                      73  0x04, 0x03, 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
                      74  0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61,
                      75  0x6e, 0x63, 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
                      76  0x43, 0x41,
                      77 };
                      78 
                      79 static const unsigned char TA_RSA_N1[] = {
                      80  0xc6, 0xcc, 0xe5, 0x73, 0xe6, 0xfb, 0xd4, 0xbb, 0xe5, 0x2d, 0x2d, 0x32,
                      81  0xa6, 0xdf, 0xe5, 0x81, 0x3f, 0xc9, 0xcd, 0x25, 0x49, 0xb6, 0x71, 0x2a,
                      82  0xc3, 0xd5, 0x94, 0x34, 0x67, 0xa2, 0x0a, 0x1c, 0xb0, 0x5f, 0x69, 0xa6,
                      83  0x40, 0xb1, 0xc4, 0xb7, 0xb2, 0x8f, 0xd0, 0x98, 0xa4, 0xa9, 0x41, 0x59,
                      84  0x3a, 0xd3, 0xdc, 0x94, 0xd6, 0x3c, 0xdb, 0x74, 0x38, 0xa4, 0x4a, 0xcc,
                      85  0x4d, 0x25, 0x82, 0xf7, 0x4a, 0xa5, 0x53, 0x12, 0x38, 0xee, 0xf3, 0x49,
                      86  0x6d, 0x71, 0x91, 0x7e, 0x63, 0xb6, 0xab, 0xa6, 0x5f, 0xc3, 0xa4, 0x84,
                      87  0xf8, 0x4f, 0x62, 0x51, 0xbe, 0xf8, 0xc5, 0xec, 0xdb, 0x38, 0x92, 0xe3,
                      88  0x06, 0xe5, 0x08, 0x91, 0x0c, 0xc4, 0x28, 0x41, 0x55, 0xfb, 0xcb, 0x5a,
                      89  0x89, 0x15, 0x7e, 0x71, 0xe8, 0x35, 0xbf, 0x4d, 0x72, 0x09, 0x3d, 0xbe,
                      90  0x3a, 0x38, 0x50, 0x5b, 0x77, 0x31, 0x1b, 0x8d, 0xb3, 0xc7, 0x24, 0x45,
                      91  0x9a, 0xa7, 0xac, 0x6d, 0x00, 0x14, 0x5a, 0x04, 0xb7, 0xba, 0x13, 0xeb,
                      92  0x51, 0x0a, 0x98, 0x41, 0x41, 0x22, 0x4e, 0x65, 0x61, 0x87, 0x81, 0x41,
                      93  0x50, 0xa6, 0x79, 0x5c, 0x89, 0xde, 0x19, 0x4a, 0x57, 0xd5, 0x2e, 0xe6,
                      94  0x5d, 0x1c, 0x53, 0x2c, 0x7e, 0x98, 0xcd, 0x1a, 0x06, 0x16, 0xa4, 0x68,
                      95  0x73, 0xd0, 0x34, 0x04, 0x13, 0x5c, 0xa1, 0x71, 0xd3, 0x5a, 0x7c, 0x55,
                      96  0xdb, 0x5e, 0x64, 0xe1, 0x37, 0x87, 0x30, 0x56, 0x04, 0xe5, 0x11, 0xb4,
                      97  0x29, 0x80, 0x12, 0xf1, 0x79, 0x39, 0x88, 0xa2, 0x02, 0x11, 0x7c, 0x27,
                      98  0x66, 0xb7, 0x88, 0xb7, 0x78, 0xf2, 0xca, 0x0a, 0xa8, 0x38, 0xab, 0x0a,
                      99  0x64, 0xc2, 0xbf, 0x66, 0x5d, 0x95, 0x84, 0xc1, 0xa1, 0x25, 0x1e, 0x87,
                      100  0x5d, 0x1a, 0x50, 0x0b, 0x20, 0x12, 0xcc, 0x41, 0xbb, 0x6e, 0x0b, 0x51,
                      101  0x38, 0xb8, 0x4b, 0xcb,
                      102 };
                      103 
                      104 static const unsigned char TA_RSA_E1[] = {
                      105  0x01, 0x00, 0x01,
                      106 };
                      107 
                      108 static const br_x509_trust_anchor TAs[] = {
                      109  {
                      110  { (unsigned char *)TA_DN0, sizeof TA_DN0 },
                      111  BR_X509_TA_CA,
                      112  {
                      113  BR_KEYTYPE_RSA,
                      114  { .rsa = {
                      115  (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
                      116  (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
                      117  } }
                      118  }
                      119  },
                      120  {
                      121  { (unsigned char *)TA_DN1, sizeof TA_DN1 },
                      122  BR_X509_TA_CA,
                      123  {
                      124  BR_KEYTYPE_RSA,
                      125  { .rsa = {
                      126  (unsigned char *)TA_RSA_N1, sizeof TA_RSA_N1,
                      127  (unsigned char *)TA_RSA_E1, sizeof TA_RSA_E1,
                      128  } }
                      129  }
                      130  },
                      131 };
                      132 
                      133 #ifdef __cplusplus
                      134 } /* extern "C" */
                      135 #endif
                      136 
                      137 #endif /* ifndef _CERTIFICATES_H_ */
                      +Go to the documentation of this file.
                      1 #ifndef _CERTIFICATES_H_
                      2 #define _CERTIFICATES_H_
                      3 
                      4 #ifdef __cplusplus
                      5 extern "C"
                      6 {
                      7 #endif
                      8 
                      9 /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually.
                      10  * Certificates are BearSSL br_x509_trust_anchor format. Included certs:
                      11  *
                      12  * Index: 0
                      13  * Label: DigiCert High Assurance EV Root CA
                      14  * Subject: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert High Assurance EV Root CA
                      15  * Domain(s): www.cloudflare.com
                      16  *
                      17  * Index: 1
                      18  * Label: AddTrust External CA Root
                      19  * Subject: C=SE,O=AddTrust AB,OU=AddTrust External TTP Network,CN=AddTrust External CA Root
                      20  * Domain(s): www.arduino.cc
                      21  */
                      22 
                      23 #define TAs_NUM 2
                      24 
                      25 static const unsigned char TA_DN0[] = {
                      26  0x30, 0x6c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
                      27  0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a,
                      28  0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49,
                      29  0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
                      30  0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72,
                      31  0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55,
                      32  0x04, 0x03, 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
                      33  0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61,
                      34  0x6e, 0x63, 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
                      35  0x43, 0x41,
                      36 };
                      37 
                      38 static const unsigned char TA_RSA_N0[] = {
                      39  0xc6, 0xcc, 0xe5, 0x73, 0xe6, 0xfb, 0xd4, 0xbb, 0xe5, 0x2d, 0x2d, 0x32,
                      40  0xa6, 0xdf, 0xe5, 0x81, 0x3f, 0xc9, 0xcd, 0x25, 0x49, 0xb6, 0x71, 0x2a,
                      41  0xc3, 0xd5, 0x94, 0x34, 0x67, 0xa2, 0x0a, 0x1c, 0xb0, 0x5f, 0x69, 0xa6,
                      42  0x40, 0xb1, 0xc4, 0xb7, 0xb2, 0x8f, 0xd0, 0x98, 0xa4, 0xa9, 0x41, 0x59,
                      43  0x3a, 0xd3, 0xdc, 0x94, 0xd6, 0x3c, 0xdb, 0x74, 0x38, 0xa4, 0x4a, 0xcc,
                      44  0x4d, 0x25, 0x82, 0xf7, 0x4a, 0xa5, 0x53, 0x12, 0x38, 0xee, 0xf3, 0x49,
                      45  0x6d, 0x71, 0x91, 0x7e, 0x63, 0xb6, 0xab, 0xa6, 0x5f, 0xc3, 0xa4, 0x84,
                      46  0xf8, 0x4f, 0x62, 0x51, 0xbe, 0xf8, 0xc5, 0xec, 0xdb, 0x38, 0x92, 0xe3,
                      47  0x06, 0xe5, 0x08, 0x91, 0x0c, 0xc4, 0x28, 0x41, 0x55, 0xfb, 0xcb, 0x5a,
                      48  0x89, 0x15, 0x7e, 0x71, 0xe8, 0x35, 0xbf, 0x4d, 0x72, 0x09, 0x3d, 0xbe,
                      49  0x3a, 0x38, 0x50, 0x5b, 0x77, 0x31, 0x1b, 0x8d, 0xb3, 0xc7, 0x24, 0x45,
                      50  0x9a, 0xa7, 0xac, 0x6d, 0x00, 0x14, 0x5a, 0x04, 0xb7, 0xba, 0x13, 0xeb,
                      51  0x51, 0x0a, 0x98, 0x41, 0x41, 0x22, 0x4e, 0x65, 0x61, 0x87, 0x81, 0x41,
                      52  0x50, 0xa6, 0x79, 0x5c, 0x89, 0xde, 0x19, 0x4a, 0x57, 0xd5, 0x2e, 0xe6,
                      53  0x5d, 0x1c, 0x53, 0x2c, 0x7e, 0x98, 0xcd, 0x1a, 0x06, 0x16, 0xa4, 0x68,
                      54  0x73, 0xd0, 0x34, 0x04, 0x13, 0x5c, 0xa1, 0x71, 0xd3, 0x5a, 0x7c, 0x55,
                      55  0xdb, 0x5e, 0x64, 0xe1, 0x37, 0x87, 0x30, 0x56, 0x04, 0xe5, 0x11, 0xb4,
                      56  0x29, 0x80, 0x12, 0xf1, 0x79, 0x39, 0x88, 0xa2, 0x02, 0x11, 0x7c, 0x27,
                      57  0x66, 0xb7, 0x88, 0xb7, 0x78, 0xf2, 0xca, 0x0a, 0xa8, 0x38, 0xab, 0x0a,
                      58  0x64, 0xc2, 0xbf, 0x66, 0x5d, 0x95, 0x84, 0xc1, 0xa1, 0x25, 0x1e, 0x87,
                      59  0x5d, 0x1a, 0x50, 0x0b, 0x20, 0x12, 0xcc, 0x41, 0xbb, 0x6e, 0x0b, 0x51,
                      60  0x38, 0xb8, 0x4b, 0xcb,
                      61 };
                      62 
                      63 static const unsigned char TA_RSA_E0[] = {
                      64  0x01, 0x00, 0x01,
                      65 };
                      66 
                      67 static const unsigned char TA_DN1[] = {
                      68  0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
                      69  0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
                      70  0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41,
                      71  0x42, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d,
                      72  0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74,
                      73  0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65,
                      74  0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55,
                      75  0x04, 0x03, 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74,
                      76  0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41,
                      77  0x20, 0x52, 0x6f, 0x6f, 0x74,
                      78 };
                      79 
                      80 static const unsigned char TA_RSA_N1[] = {
                      81  0xb7, 0xf7, 0x1a, 0x33, 0xe6, 0xf2, 0x00, 0x04, 0x2d, 0x39, 0xe0, 0x4e,
                      82  0x5b, 0xed, 0x1f, 0xbc, 0x6c, 0x0f, 0xcd, 0xb5, 0xfa, 0x23, 0xb6, 0xce,
                      83  0xde, 0x9b, 0x11, 0x33, 0x97, 0xa4, 0x29, 0x4c, 0x7d, 0x93, 0x9f, 0xbd,
                      84  0x4a, 0xbc, 0x93, 0xed, 0x03, 0x1a, 0xe3, 0x8f, 0xcf, 0xe5, 0x6d, 0x50,
                      85  0x5a, 0xd6, 0x97, 0x29, 0x94, 0x5a, 0x80, 0xb0, 0x49, 0x7a, 0xdb, 0x2e,
                      86  0x95, 0xfd, 0xb8, 0xca, 0xbf, 0x37, 0x38, 0x2d, 0x1e, 0x3e, 0x91, 0x41,
                      87  0xad, 0x70, 0x56, 0xc7, 0xf0, 0x4f, 0x3f, 0xe8, 0x32, 0x9e, 0x74, 0xca,
                      88  0xc8, 0x90, 0x54, 0xe9, 0xc6, 0x5f, 0x0f, 0x78, 0x9d, 0x9a, 0x40, 0x3c,
                      89  0x0e, 0xac, 0x61, 0xaa, 0x5e, 0x14, 0x8f, 0x9e, 0x87, 0xa1, 0x6a, 0x50,
                      90  0xdc, 0xd7, 0x9a, 0x4e, 0xaf, 0x05, 0xb3, 0xa6, 0x71, 0x94, 0x9c, 0x71,
                      91  0xb3, 0x50, 0x60, 0x0a, 0xc7, 0x13, 0x9d, 0x38, 0x07, 0x86, 0x02, 0xa8,
                      92  0xe9, 0xa8, 0x69, 0x26, 0x18, 0x90, 0xab, 0x4c, 0xb0, 0x4f, 0x23, 0xab,
                      93  0x3a, 0x4f, 0x84, 0xd8, 0xdf, 0xce, 0x9f, 0xe1, 0x69, 0x6f, 0xbb, 0xd7,
                      94  0x42, 0xd7, 0x6b, 0x44, 0xe4, 0xc7, 0xad, 0xee, 0x6d, 0x41, 0x5f, 0x72,
                      95  0x5a, 0x71, 0x08, 0x37, 0xb3, 0x79, 0x65, 0xa4, 0x59, 0xa0, 0x94, 0x37,
                      96  0xf7, 0x00, 0x2f, 0x0d, 0xc2, 0x92, 0x72, 0xda, 0xd0, 0x38, 0x72, 0xdb,
                      97  0x14, 0xa8, 0x45, 0xc4, 0x5d, 0x2a, 0x7d, 0xb7, 0xb4, 0xd6, 0xc4, 0xee,
                      98  0xac, 0xcd, 0x13, 0x44, 0xb7, 0xc9, 0x2b, 0xdd, 0x43, 0x00, 0x25, 0xfa,
                      99  0x61, 0xb9, 0x69, 0x6a, 0x58, 0x23, 0x11, 0xb7, 0xa7, 0x33, 0x8f, 0x56,
                      100  0x75, 0x59, 0xf5, 0xcd, 0x29, 0xd7, 0x46, 0xb7, 0x0a, 0x2b, 0x65, 0xb6,
                      101  0xd3, 0x42, 0x6f, 0x15, 0xb2, 0xb8, 0x7b, 0xfb, 0xef, 0xe9, 0x5d, 0x53,
                      102  0xd5, 0x34, 0x5a, 0x27,
                      103 };
                      104 
                      105 static const unsigned char TA_RSA_E1[] = {
                      106  0x01, 0x00, 0x01,
                      107 };
                      108 
                      109 static const br_x509_trust_anchor TAs[] = {
                      110  {
                      111  { (unsigned char *)TA_DN0, sizeof TA_DN0 },
                      112  BR_X509_TA_CA,
                      113  {
                      114  BR_KEYTYPE_RSA,
                      115  { .rsa = {
                      116  (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
                      117  (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
                      118  } }
                      119  }
                      120  },
                      121  {
                      122  { (unsigned char *)TA_DN1, sizeof TA_DN1 },
                      123  BR_X509_TA_CA,
                      124  {
                      125  BR_KEYTYPE_RSA,
                      126  { .rsa = {
                      127  (unsigned char *)TA_RSA_N1, sizeof TA_RSA_N1,
                      128  (unsigned char *)TA_RSA_E1, sizeof TA_RSA_E1,
                      129  } }
                      130  }
                      131  },
                      132 };
                      133 
                      134 #ifdef __cplusplus
                      135 } /* extern "C" */
                      136 #endif
                      137 
                      138 #endif /* ifndef _CERTIFICATES_H_ */
                      -Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include "bearssl.h"
                      22 #include "Arduino.h"
                      23 #include "Client.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClientImpl_H_
                      27 #define SSLClientImpl_H_
                      28 
                      37 enum Error {
                      38  SSL_OK = 0,
                      51 };
                      52 
                      59 enum DebugLevel {
                      61  SSL_NONE = 0,
                      63  SSL_ERROR = 1,
                      65  SSL_WARN = 2,
                      67  SSL_INFO = 3,
                      68 };
                      69 
                      71 class SSLClientImpl : public Client {
                      72 public:
                      74  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
                      75  const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug);
                      76 
                      77  //============================================
                      78  //= Functions implemented in SSLClientImpl.cpp
                      79  //============================================
                      80 
                      82  int connect_impl(IPAddress ip, uint16_t port);
                      84  int connect_impl(const char *host, uint16_t port);
                      86  size_t write_impl(const uint8_t *buf, size_t size);
                      88  int available_impl();
                      90  int read_impl(uint8_t *buf, size_t size);
                      92  int peek_impl();
                      94  void flush_impl();
                      96  void stop_impl();
                      98  uint8_t connected_impl();
                      100  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
                      102  void remove_session_impl(const char* host, const IPAddress& addr);
                      103 
                      104  //============================================
                      105  //= Functions implemented in SSLClient.h
                      106  //============================================
                      108  virtual uint16_t localPort() = 0;
                      110  virtual IPAddress remoteIP() = 0;
                      112  virtual uint16_t remotePort() = 0;
                      114  virtual size_t getSessionCount() const = 0;
                      115 
                      116 protected:
                      118  virtual Client& get_arduino_client() = 0;
                      119  virtual const Client& get_arduino_client() const = 0;
                      121  virtual SSLSession* get_session_array() = 0;
                      122  virtual const SSLSession* get_session_array() const = 0;
                      123 
                      124  //============================================
                      125  //= Functions implemented in SSLClientImpl.cpp
                      126  //============================================
                      127 
                      129  void m_print_prefix(const char* func_name, const DebugLevel level) const;
                      130 
                      132  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
                      133 
                      135  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
                      136 
                      138  template<typename T>
                      139  void m_print(const T str, const char* func_name, const DebugLevel level) const {
                      140  // check the current debug level and serial status
                      141  if (level > m_debug || !Serial) return;
                      142  // print prefix
                      143  m_print_prefix(func_name, level);
                      144  // print the message
                      145  Serial.println(str);
                      146  }
                      147 
                      149  template<typename T>
                      150  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
                      151 
                      152  template<typename T>
                      153  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
                      154 
                      155  template<typename T>
                      156  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
                      157 
                      158 private:
                      160  bool m_soft_connected(const char* func_name);
                      162  int m_start_ssl(const char* host, SSLSession& ssl_ses);
                      164  int m_run_until(const unsigned target);
                      166  unsigned m_update_engine();
                      168  int m_get_session_index(const char* host, const IPAddress& addr) const;
                      169 
                      170  //============================================
                      171  //= Data Members
                      172  //============================================
                      173 
                      174  // store pointers to the trust anchors
                      175  // should not be computed at runtime
                      176  const br_x509_trust_anchor *m_trust_anchors;
                      177  const size_t m_trust_anchors_num;
                      178  // store the pin to fetch an RNG see from
                      179  const int m_analog_pin;
                      180  // store an index of where a new session can be placed if we don't have any corresponding sessions
                      181  size_t m_session_index;
                      182  // store whether to enable debug logging
                      183  const DebugLevel m_debug;
                      184  // store if we are connected in bearssl or not
                      185  bool m_is_connected;
                      186  // store the context values required for SSL
                      187  br_ssl_client_context m_sslctx;
                      188  br_x509_minimal_context m_x509ctx;
                      189  // use a mono-directional buffer by default to cut memory in half
                      190  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
                      191  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
                      192  // simply edit this value to change the buffer size to the desired value
                      193  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
                      194  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
                      202  unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 4];
                      203  static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size");
                      204  // store the index of where we are writing in the buffer
                      205  // so we can send our records all at once to prevent
                      206  // weird timing issues
                      207  size_t m_write_idx;
                      208 };
                      209 
                      210 #endif /* SSLClientImpl_H_ */
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:132
                      +Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include "bearssl.h"
                      22 #include "Arduino.h"
                      23 #include "Client.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClientImpl_H_
                      27 #define SSLClientImpl_H_
                      28 
                      37 enum Error {
                      38  SSL_OK = 0,
                      51 };
                      52 
                      59 enum DebugLevel {
                      61  SSL_NONE = 0,
                      63  SSL_ERROR = 1,
                      65  SSL_WARN = 2,
                      67  SSL_INFO = 3,
                      68 };
                      69 
                      71 class SSLClientImpl : public Client {
                      72 public:
                      74  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
                      75  const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug);
                      76 
                      77  //============================================
                      78  //= Functions implemented in SSLClientImpl.cpp
                      79  //============================================
                      80 
                      82  int connect_impl(IPAddress ip, uint16_t port);
                      84  int connect_impl(const char *host, uint16_t port);
                      86  size_t write_impl(const uint8_t *buf, size_t size);
                      88  int available_impl();
                      90  int read_impl(uint8_t *buf, size_t size);
                      92  int peek_impl();
                      94  void flush_impl();
                      96  void stop_impl();
                      98  uint8_t connected_impl();
                      100  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
                      102  void remove_session_impl(const char* host, const IPAddress& addr);
                      103 
                      104  //============================================
                      105  //= Functions implemented in SSLClient.h
                      106  //============================================
                      108  virtual uint16_t localPort() = 0;
                      110  virtual IPAddress remoteIP() = 0;
                      112  virtual uint16_t remotePort() = 0;
                      114  virtual size_t getSessionCount() const = 0;
                      115 
                      116 protected:
                      118  virtual Client& get_arduino_client() = 0;
                      119  virtual const Client& get_arduino_client() const = 0;
                      121  virtual SSLSession* get_session_array() = 0;
                      122  virtual const SSLSession* get_session_array() const = 0;
                      123 
                      124  //============================================
                      125  //= Functions implemented in SSLClientImpl.cpp
                      126  //============================================
                      127 
                      129  void m_print_prefix(const char* func_name, const DebugLevel level) const;
                      130 
                      132  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
                      133 
                      135  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
                      136 
                      138  template<typename T>
                      139  void m_print(const T str, const char* func_name, const DebugLevel level) const {
                      140  // check the current debug level and serial status
                      141  if (level > m_debug || !Serial) return;
                      142  // print prefix
                      143  m_print_prefix(func_name, level);
                      144  // print the message
                      145  Serial.println(str);
                      146  }
                      147 
                      149  template<typename T>
                      150  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
                      151 
                      152  template<typename T>
                      153  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
                      154 
                      155  template<typename T>
                      156  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
                      157 
                      158 private:
                      160  bool m_soft_connected(const char* func_name);
                      162  int m_start_ssl(const char* host, SSLSession& ssl_ses);
                      164  int m_run_until(const unsigned target);
                      166  unsigned m_update_engine();
                      168  int m_get_session_index(const char* host, const IPAddress& addr) const;
                      169 
                      170  //============================================
                      171  //= Data Members
                      172  //============================================
                      173 
                      174  // store pointers to the trust anchors
                      175  // should not be computed at runtime
                      176  const br_x509_trust_anchor *m_trust_anchors;
                      177  const size_t m_trust_anchors_num;
                      178  // store the pin to fetch an RNG see from
                      179  const int m_analog_pin;
                      180  // store an index of where a new session can be placed if we don't have any corresponding sessions
                      181  size_t m_session_index;
                      182  // store whether to enable debug logging
                      183  const DebugLevel m_debug;
                      184  // store if we are connected in bearssl or not
                      185  bool m_is_connected;
                      186  // store the context values required for SSL
                      187  br_ssl_client_context m_sslctx;
                      188  br_x509_minimal_context m_x509ctx;
                      189  // use a mono-directional buffer by default to cut memory in half
                      190  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
                      191  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
                      192  // simply edit this value to change the buffer size to the desired value
                      193  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
                      194  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
                      202  unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 8];
                      203  static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size");
                      204  // store the index of where we are writing in the buffer
                      205  // so we can send our records all at once to prevent
                      206  // weird timing issues
                      207  size_t m_write_idx;
                      208 };
                      209 
                      210 #endif /* SSLClientImpl_H_ */
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:132
                      virtual uint16_t remotePort()=0
                      void m_print(const T str, const char *func_name, const DebugLevel level) const
                      debugging print function, only prints if m_debug is true
                      Definition: SSLClientImpl.h:139
                      Definition: SSLClientImpl.h:65
                      virtual IPAddress remoteIP()=0
                      -
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:280
                      +
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:294
                      This class stores values which allow SSLClient to save and resume SSL sessions.
                      Definition: SSLSession.h:52
                      void m_info(const T str, const char *func_name) const
                      Prints a info message to serial, if info messages are enabled.
                      Definition: SSLClientImpl.h:150
                      SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
                      Definition: SSLClientImpl.cpp:53
                      @@ -109,18 +109,18 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h_source.html','')
                      virtual SSLSession * get_session_array()=0
                      Definition: SSLClientImpl.h:46
                      Definition: SSLClientImpl.h:38
                      -
                      void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
                      Prints the string associated with a write error.
                      Definition: SSLClientImpl.cpp:654
                      +
                      void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
                      Prints the string associated with a write error.
                      Definition: SSLClientImpl.cpp:657
                      int available_impl()
                      Definition: SSLClientImpl.cpp:175
                      Error
                      Static constants defining the possible errors encountered.
                      Definition: SSLClientImpl.h:37
                      Definition: SSLClientImpl.h:42
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:196
                      -
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:299
                      +
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:313
                      Definition: SSLClientImpl.h:44
                      virtual Client & get_arduino_client()=0
                      Definition: SSLClientImpl.h:40
                      -
                      void m_print_prefix(const char *func_name, const DebugLevel level) const
                      Prints a debugging prefix to all logs, so we can attatch them to useful information.
                      Definition: SSLClientImpl.cpp:636
                      +
                      void m_print_prefix(const char *func_name, const DebugLevel level) const
                      Prints a debugging prefix to all logs, so we can attatch them to useful information.
                      Definition: SSLClientImpl.cpp:639
                      Definition: SSLClientImpl.h:61
                      -
                      void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
                      Print the text string associated with a BearSSL error code.
                      Definition: SSLClientImpl.cpp:669
                      +
                      void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
                      Print the text string associated with a BearSSL error code.
                      Definition: SSLClientImpl.cpp:672
                      void m_warn(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:153
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:75
                      @@ -129,7 +129,7 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h_source.html','')
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:223
                      Implementation code to be inherited by SSLClient.
                      Definition: SSLClientImpl.h:71
                      virtual uint16_t localPort()=0
                      -
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:254
                      +
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:263
                      DebugLevel
                      Level of verbosity used in logging for SSLClient.
                      Definition: SSLClientImpl.h:59
                      diff --git a/docs/html/_s_s_l_session_8cpp.html b/docs/html/_s_s_l_session_8cpp.html index 5a05643..458ced1 100644 --- a/docs/html/_s_s_l_session_8cpp.html +++ b/docs/html/_s_s_l_session_8cpp.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index 9f37a1c..7f71f53 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index 9cee101..2a0f814 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html index 3df9e79..0562e86 100644 --- a/docs/html/_t_l_s12__only__profile_8c.html +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html index 1bcd811..e73745c 100644 --- a/docs/html/_trust_anchors_8md.html +++ b/docs/html/_trust_anchors_8md.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 5f354c0..10791df 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/cert_8h.html b/docs/html/cert_8h.html index c4a0e50..9bb5578 100644 --- a/docs/html/cert_8h.html +++ b/docs/html/cert_8h.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html index aa6730c..e1db8ed 100644 --- a/docs/html/cert_8h_source.html +++ b/docs/html/cert_8h_source.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index d196482..b0199db 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 364ee42..00e645b 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/class_s_s_l_client_impl-members.html b/docs/html/class_s_s_l_client_impl-members.html index 49c0e58..62d86a9 100644 --- a/docs/html/class_s_s_l_client_impl-members.html +++ b/docs/html/class_s_s_l_client_impl-members.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/class_s_s_l_client_impl.html b/docs/html/class_s_s_l_client_impl.html index 244b09f..0cb6b98 100644 --- a/docs/html/class_s_s_l_client_impl.html +++ b/docs/html/class_s_s_l_client_impl.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index b854c41..79365b7 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index adb0e30..777e8e2 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/classes.html b/docs/html/classes.html index 2fe6ffe..8bd69a7 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html index 125fbda..e1f45cd 100644 --- a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 05e7cd3..c2517de 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html index 36b29ce..0f6fe49 100644 --- a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html index 46d074e..d7796f8 100644 --- a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html index deb9b96..e955a0c 100644 --- a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/files.html b/docs/html/files.html index 5be5ad7..dac1fdb 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/functions.html b/docs/html/functions.html index dea6a9f..fe84459 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index 3a214ff..9d99958 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/globals.html b/docs/html/globals.html index 06ac476..2125a13 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index 29e9042..110a147 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/globals_enum.html b/docs/html/globals_enum.html index 9ddaa5f..44a509d 100644 --- a/docs/html/globals_enum.html +++ b/docs/html/globals_enum.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/globals_eval.html b/docs/html/globals_eval.html index eae7b57..ea1f9be 100644 --- a/docs/html/globals_eval.html +++ b/docs/html/globals_eval.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index ecab3f9..bb7f1cb 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index 99e9fff..4c696ff 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 7ad10b4..7595b1b 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/index.html b/docs/html/index.html index d1a4668..104e104 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      @@ -138,7 +138,9 @@ $(document).ready(function(){initNavTree('index.html','');});

                      Implementation Gotchas

                      Some ideas that didn't quite fit in the API documentation.

                      SSLClient with Ethernet

                      -

                      If you are using the Arduino Ethernet library, you will need to modify the library to support the large buffer sizes required by SSL (detailed in resources). To do this, first find the location of the library in the directory where Arduino is installed (C:\Program Files (x86)\Arduino on Windows). Inside of this directory, navigate to libraries\Ethernet\src (C:\Program Files (x86)\Arduino\libraries\Ethernet\src on Windows). Modify Ethernet.h to replace these lines:

                      {C++}
                      ...
                      // Configure the maximum number of sockets to support. W5100 chips can have
                      // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
                      // of RAM are used for each socket. Reducing the maximum can save RAM, but
                      // you are limited to fewer simultaneous connections.
                      #if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048)
                      #define MAX_SOCK_NUM 4
                      #else
                      #define MAX_SOCK_NUM 8
                      #endif
                      // By default, each socket uses 2K buffers inside the Wiznet chip. If
                      // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
                      // this will use larger buffers within the Wiznet chip. Large buffers
                      // can really help with UDP protocols like Artnet. In theory larger
                      // buffers should allow faster TCP over high-latency links, but this
                      // does not always seem to work in practice (maybe Wiznet bugs?)
                      //#define ETHERNET_LARGE_BUFFERS
                      ...

                      With this:

                      {C++}
                      ...
                      // Configure the maximum number of sockets to support. W5100 chips can have
                      // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
                      // of RAM are used for each socket. Reducing the maximum can save RAM, but
                      // you are limited to fewer simultaneous connections.
                      #define MAX_SOCK_NUM 2
                      // By default, each socket uses 2K buffers inside the Wiznet chip. If
                      // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
                      // this will use larger buffers within the Wiznet chip. Large buffers
                      // can really help with UDP protocols like Artnet. In theory larger
                      // buffers should allow faster TCP over high-latency links, but this
                      // does not always seem to work in practice (maybe Wiznet bugs?)
                      #define ETHERNET_LARGE_BUFFERS
                      ...

                      You may need to use sudo or administrator permissions to make this modification. We change MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS so the Ethernet hardware can allocate a larger space for SSLClient, however a downside of this modification is we are now only able to have two sockets concurrently. As most microprocessors barely have enough memory for one SSL connection, this limitation will rarely be encountered in practice.

                      +

                      If you are using the Arduino Ethernet library, you will need to modify the library to support the large buffer sizes required by SSL (detailed in resources). You can either modify the library yourself, or use this fork of the Ethernet library with the modification. To use the fork, simply install the library using the "add a .zip library" button in Arduino, and replace #include "Ethernet.h" with #include "EthernetLarge.h" in your sketch. Alternatively if for some reason this solution does not work, you can apply the modification using the instructions below.

                      +

                      Manual Modification

                      +

                      First find the location of the library in the directory where Arduino is installed (C:\Program Files (x86)\Arduino on Windows). Inside of this directory, navigate to libraries\Ethernet\src (C:\Program Files (x86)\Arduino\libraries\Ethernet\src on Windows). Modify Ethernet.h to replace these lines:

                      {C++}
                      ...
                      // Configure the maximum number of sockets to support. W5100 chips can have
                      // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
                      // of RAM are used for each socket. Reducing the maximum can save RAM, but
                      // you are limited to fewer simultaneous connections.
                      #if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048)
                      #define MAX_SOCK_NUM 4
                      #else
                      #define MAX_SOCK_NUM 8
                      #endif
                      // By default, each socket uses 2K buffers inside the Wiznet chip. If
                      // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
                      // this will use larger buffers within the Wiznet chip. Large buffers
                      // can really help with UDP protocols like Artnet. In theory larger
                      // buffers should allow faster TCP over high-latency links, but this
                      // does not always seem to work in practice (maybe Wiznet bugs?)
                      //#define ETHERNET_LARGE_BUFFERS
                      ...

                      With this:

                      {C++}
                      ...
                      // Configure the maximum number of sockets to support. W5100 chips can have
                      // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
                      // of RAM are used for each socket. Reducing the maximum can save RAM, but
                      // you are limited to fewer simultaneous connections.
                      #define MAX_SOCK_NUM 2
                      // By default, each socket uses 2K buffers inside the Wiznet chip. If
                      // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
                      // this will use larger buffers within the Wiznet chip. Large buffers
                      // can really help with UDP protocols like Artnet. In theory larger
                      // buffers should allow faster TCP over high-latency links, but this
                      // does not always seem to work in practice (maybe Wiznet bugs?)
                      #define ETHERNET_LARGE_BUFFERS
                      ...

                      You may need to use sudo or administrator permissions to make this modification. We change MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS so the Ethernet hardware can allocate a larger space for SSLClient, however a downside of this modification is we are now only able to have two sockets concurrently. As most microprocessors barely have enough memory for one SSL connection, this limitation will rarely be encountered in practice.

                      Random Data

                      The SSL protocol requires that SSLClient generate some random bits before connecting with a server. BearSSL provides a random number generator but requires a some entropy for a seed. Normally this seed is generated by taking the microsecond time using the internal clock, however since most microcontrollers are not build with this feature another source must be found. As a simple solution, SSLClient uses a floating analog pin as an external source of random data, passed through to the constructor in the analog_pin argument. Before every connection, SSLClient will take the bottom byte from 16 analog reads on analog_pin, and combine these bytes into a 16 byte random number, which is used as a seed for BearSSL. To ensure the most random data, it is recommended that this analog pin be either floating or connected to a location not modifiable by the microcontroller (i.e. a battery voltage readout).

                      Certificate Verification

                      diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index 960a2fb..8ea9d13 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/pages.html b/docs/html/pages.html index c715a5c..40f7260 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html index 896b8b7..e7f6961 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/html/time__macros_8h.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html index 653873a..38aa464 100644 --- a/docs/html/time__macros_8h_source.html +++ b/docs/html/time__macros_8h_source.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html index a9424eb..9256c2b 100644 --- a/docs/html/trust__anchors_8h.html +++ b/docs/html/trust__anchors_8h.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index bb93808..05a0dbe 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html index 5c6825e..72d7454 100644 --- a/docs/html/trustanchors_8h.html +++ b/docs/html/trustanchors_8h.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html index d5a8043..c21f425 100644 --- a/docs/html/trustanchors_8h_source.html +++ b/docs/html/trustanchors_8h_source.html @@ -30,7 +30,7 @@
                      SSLClient -  1.0 +  v1.1.1
                      Add TLS 1.2 functionality to any network library.
                      diff --git a/examples/EthernetHTTPS/EthernetHTTPS.ino b/examples/EthernetHTTPS/EthernetHTTPS.ino index fd7416c..5245554 100644 --- a/examples/EthernetHTTPS/EthernetHTTPS.ino +++ b/examples/EthernetHTTPS/EthernetHTTPS.ino @@ -14,11 +14,11 @@ */ - // NOTE: The Ethernet library MUST be modified to use this example! - // For more detailed instructions check out https://github.com/OPEnSLab-OSU/SSLClient#sslclient-with-ethernet + // NOTE: This example REQUIRES the EthernetLarge library. + // You can get it here: https://github.com/OPEnSLab-OSU/EthernetLarge #include -#include +#include #include #include "trust_anchors.h" diff --git a/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino index debc697..e21f0b1 100644 --- a/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino +++ b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino @@ -15,11 +15,11 @@ */ - // NOTE: The Ethernet library MUST be modified to use this example! - // For more detailed instructions check out https://github.com/OPEnSLab-OSU/SSLClient#sslclient-with-ethernet + // NOTE: This example REQUIRES the EthernetLarge library. + // You can get it here: https://github.com/OPEnSLab-OSU/EthernetLarge #include -#include +#include #include #include "trustanchors.h" // Enter a MAC address for your controller below. diff --git a/library.properties b/library.properties index 3dbb486..a625705 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.1 +version=1.1.1 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From 0538c30081ba02da6e414026e85b86b2d7efddeb Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 22 Jul 2019 17:07:54 -0700 Subject: [PATCH 055/205] reduced memory usage, at the cost of performance --- README.md | 4 ++-- library.properties | 2 +- src/SSLClientImpl.cpp | 4 ++-- src/SSLClientImpl.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6eb75d8..6ffe9c0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SSLClient - Arduino Library For SSL -**SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.** +**SSLClient requires at least 110kb flash and 7kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.** You can also view this README in [doxygen](https://openslab-osu.github.io/SSLClient/html/index.html). @@ -10,7 +10,7 @@ SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec. Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few extra things, however, that you will need to get started: -1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Gotchas](#sslclient-with-ethernet)). +1. A board with a lot of resources (>110kb flash and >7kb RAM), and a network peripheral with a large internal buffer (>7kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Gotchas](#sslclient-with-ethernet)). 2. A header containing array of trust anchors, which will look like [this file](./readme/cert.h). These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out [this document](./TrustAnchors.md) on how to generate this file for your project, and for more information about what a trust anchor is. 3. A Client class associated with a network interface. We tested this library using [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient), however in theory it will work for any class implementing Client. 4. An analog pin, used for generating random data at the start of the connection (see the [Implementation Gotchas](#implementation-gotchas)). diff --git a/library.properties b/library.properties index a625705..e9cec28 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.1.1 +version=1.1.2 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index a02a2c7..d46faa6 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -575,9 +575,9 @@ unsigned SSLClientImpl::m_update_engine() { m_info(mem, func_name); // free memory check // BearSSL takes up so much memory on the stack it tends - // to overflow if there isn't at least 8000 bytes available + // to overflow if there isn't at least 7000 bytes available // when it starts - if(mem < 8000) { + if(mem < 7000) { m_error("Out of memory! Decrease the number of sessions or the size of m_iobuf", func_name); setWriteError(SSL_OUT_OF_MEMORY); stop_impl(); diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 3eccfea..896bc7e 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -199,7 +199,7 @@ private: * As a rule of thumb SSLClient will fail if it does not have at least 8000 bytes when starting a * connection. */ - unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 8]; + unsigned char m_iobuf[1536]; static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); // store the index of where we are writing in the buffer // so we can send our records all at once to prevent From 4b95e7d7a1c250faa3f59378127ed344f12c2315 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 23 Jul 2019 18:29:13 -0700 Subject: [PATCH 056/205] added mutual authentication, tweaked command line tool --- src/SSLClient.h | 29 ++++++++++- src/SSLClientImpl.cpp | 23 +++++++-- src/SSLClientImpl.h | 13 +++-- src/SSLClientParameters.h | 66 ++++++++++++++++++++++++++ tools/pycert_bearssl/pycert_bearssl.py | 19 +++++--- 5 files changed, 132 insertions(+), 18 deletions(-) create mode 100644 src/SSLClientParameters.h diff --git a/src/SSLClient.h b/src/SSLClient.h index cd9291e..0c078e1 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -22,6 +22,7 @@ #include "Client.h" #include "SSLClientImpl.h" #include "SSLSession.h" +#include "SSLClientParameters.h" #ifndef SSLClient_H_ #define SSLClient_H_ @@ -67,17 +68,41 @@ public: * @param trust_anchors_num The number of objects in the trust_anchors array. * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG. * @param debug The level of debug logging (use the ::DebugLevel enum). + * @param mutual_auth_params Configuration to use for mutual authentication, nullptr to disable mutual auth. (see ::SSLClientParameters). */ - explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN) + explicit SSLClient( const C& client, + const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, + const int analog_pin, + const DebugLevel debug = SSL_WARN) : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) - , m_sessions{SSLSession()} + , m_sessions{} { // set the timeout to a reasonable number (it can always be changes later) // SSL Connections take a really long time so we don't want to time out a legitimate thing setTimeout(30 * 1000); } + /** + * Same as SSLClient::SSLClient(const C &, const br_x509_trust_anchor*, const size_t, const int, const DebugLevel), + * but can compile support for mutual authentication. + */ + explicit SSLClient( const C& client, + const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, + const int analog_pin, + const DebugLevel debug, + const SSLClientParameters* mutual_auth_params) + : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug, mutual_auth_params) + , m_client(client) + , m_sessions{} + { + // set the timeout to a reasonable number (it can always be changes later) + // SSL Connections take a really long time so we don't want to time out a legitimate thing + setTimeout(30 * 1000); + } + //======================================== //= Functions implemented in SSLClientImpl //======================================== diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index d46faa6..d0d4255 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -52,9 +52,7 @@ static int freeMemory() { /* see SSLClientImpl.h */ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) - : m_trust_anchors(trust_anchors) - , m_trust_anchors_num(trust_anchors_num) - , m_analog_pin(analog_pin) + : m_analog_pin(analog_pin) , m_session_index(0) , m_debug(debug) , m_is_connected(false) @@ -63,7 +61,7 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); // initlalize the various bearssl libraries so they're ready to go when we connect - br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, trust_anchors, trust_anchors_num); // comment the above line and uncomment the line below if you're having trouble connecting over SSL // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // check if the buffer size is half or full duplex @@ -71,6 +69,23 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); } +/* see SSLClientImpl.h */ +SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, const int analog_pin, + const DebugLevel debug, const SSLClientParameters* mutual_auth_params) + : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) { + // if mutual authentication if needed, configure bearssl to support it. + if (mutual_auth_params != nullptr) + br_ssl_client_set_single_ec( &m_sslctx, + mutual_auth_params->client_cert_chain, + mutual_auth_params->chain_len, + &mutual_auth_params->ec_key, + BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, + BR_KEYTYPE_EC, + br_ssl_engine_get_ec(&m_sslctx.eng), + &br_ecdsa_i15_sign_asn1); + } + /* see SSLClientImpl.h*/ int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { const char* func_name = __func__; diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 896bc7e..f955194 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -22,6 +22,7 @@ #include "Arduino.h" #include "Client.h" #include "SSLSession.h" +#include "SSLClientParameters.h" #ifndef SSLClientImpl_H_ #define SSLClientImpl_H_ @@ -72,7 +73,13 @@ class SSLClientImpl : public Client { public: /** @see SSLClient::SSLClient */ explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug); + const size_t trust_anchors_num, const int analog_pin, + const DebugLevel debug); + + /** @see SSLClient::SSLClient */ + explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, const int analog_pin, + const DebugLevel debug, const SSLClientParameters* mutual_auth_params); //============================================ //= Functions implemented in SSLClientImpl.cpp @@ -171,10 +178,6 @@ private: //= Data Members //============================================ - // store pointers to the trust anchors - // should not be computed at runtime - const br_x509_trust_anchor *m_trust_anchors; - const size_t m_trust_anchors_num; // store the pin to fetch an RNG see from const int m_analog_pin; // store an index of where a new session can be placed if we don't have any corresponding sessions diff --git a/src/SSLClientParameters.h b/src/SSLClientParameters.h new file mode 100644 index 0000000..10d478d --- /dev/null +++ b/src/SSLClientParameters.h @@ -0,0 +1,66 @@ +/* Copyright 2019 OSU OPEnS Lab + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * SSLClientParameters.h + * + * This file contains a simple utility class to store parameters about an SSL Session + * for reuse later. + */ + +#include "bearssl.h" + +#ifndef SSLClientParameters_H_ +#define SSLClientParameters_H_ + +/** + * This file contains a simple struct to package together all the data required to + * use client certificate authentication with SSLClient. + */ + +/** + * \brief This struct stores data required for SSLClient to use mutual authentication. + * + * TLS mutual authentication is a process in which both the server and client + * perform cryptographic operations to verify the authenticity of eachother, for more + * information check out this article: https://medium.com/sitewards/the-magic-of-tls-x509-and-mutual-authentication-explained-b2162dec4401 . + * If this struct is provided to SSLClient::SSLClient, SSLClient will automatically + * send a client certificate if one is requested by the server. This will happen for all + * SSLClient connections, and may cause issues for websites that do not need mutual authentication--- + * as a result, please only turn on mutual authentication if you are sure it is neccesary. + * + * At the moment SSLClient only supports mutual authentication using ECC client certificates. + */ + +struct SSLClientParameters { + /** + * \brief Pointer to the client certificate chain. + * + * Must be availible in memory AT ALL TIMES, should not be a local object. + * Certificates must be ordered from Client->Intermediate->...->Root. + */ + const br_x509_certificate* client_cert_chain; + /** The number of certificates in SSLClientParameters::client_cert_chain */ + const size_t chain_len; + /** The private key corresponding to the first certificate in SSLClientParameters::client_cert_chain */ + const br_ec_private_key ec_key; +}; + +#endif \ No newline at end of file diff --git a/tools/pycert_bearssl/pycert_bearssl.py b/tools/pycert_bearssl/pycert_bearssl.py index 327be0f..392838e 100644 --- a/tools/pycert_bearssl/pycert_bearssl.py +++ b/tools/pycert_bearssl/pycert_bearssl.py @@ -100,8 +100,10 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom help='the location of the .pem file containing a list of trusted root certificates (default: use certifi.where())') @click.option('--keep-dupes', '-d', is_flag=True, default=False, help='write all certs including any duplicates (default: remove duplicates)') +@click.option('--no-verify', '-n', is_flag=True, default=False, + help='Do not attempt to match a root certificate to the provided PEM files') @click.argument('cert', type=click.File('r'), nargs=-1) -def convert(cert_var, cert_length_var, output, use_store, keep_dupes, cert): +def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_verify, cert): """Convert PEM certificates into a C header that can be imported into a sketch. Specify each certificate to encode as a separate argument (each must be in PEM format) and they will be merged into a single file. @@ -132,12 +134,15 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, cert): cert_objs.append(cert_parsed) # find a root certificate for each root_certs = [] - for i, c in enumerate(cert_objs): - cn_hash = c.get_issuer().hash() - if cn_hash not in cert_dict: - click.echo('Could not find a root certificate for {0}'.format(cert[i].name)) - else: - root_certs.append(cert_dict[cn_hash]) + if no_verify: + root_certs = cert_objs + else: + for i, c in enumerate(cert_objs): + cn_hash = c.get_issuer().hash() + if cn_hash not in cert_dict: + click.echo('Could not find a root certificate for {0}'.format(cert[i].name)) + else: + root_certs.append(cert_dict[cn_hash]) # Combine PEMs and write output header. cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes) From 97aee26a1f953714b808a272c46e5a06dc84928a Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 25 Jul 2019 09:16:58 -0700 Subject: [PATCH 057/205] Increased buffer again as the smaller buffer broke client certificates --- src/SSLClientImpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index f955194..7b6cd2c 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -202,7 +202,7 @@ private: * As a rule of thumb SSLClient will fail if it does not have at least 8000 bytes when starting a * connection. */ - unsigned char m_iobuf[1536]; + unsigned char m_iobuf[2048]; static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); // store the index of where we are writing in the buffer // so we can send our records all at once to prevent From 2e2c247a0f56347cb06636cac10aebb2bbbefde4 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 30 Jul 2019 15:33:10 -0700 Subject: [PATCH 058/205] Removed support for some elliptical curves and removed support for SHA384 ciphers to save space --- src/TLS12_only_profile.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/TLS12_only_profile.c b/src/TLS12_only_profile.c index bfe242a..a9921f5 100644 --- a/src/TLS12_only_profile.c +++ b/src/TLS12_only_profile.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Thomas Pornin + * Copyright (c) 2019 OSU OPEnS Lab * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -79,21 +79,13 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, }; /* @@ -125,7 +117,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, */ // br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); - br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + // br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); /* * Set hash functions for the engine. Required hash functions @@ -158,7 +150,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, br_ssl_engine_set_hash(&cc->eng, br_sha224_ID, &br_sha224_vtable); br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable); br_ssl_engine_set_hash(&cc->eng, br_sha384_ID, &br_sha384_vtable); - // br_ssl_engine_set_hash(&cc->eng, br_sha512_ID, &br_sha512_vtable); + br_ssl_engine_set_hash(&cc->eng, br_sha512_ID, &br_sha512_vtable); /* * Set the cipher suites. All specified cipher suite MUST be @@ -237,7 +229,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, //* Alternate: set implementations explicitly. // br_ssl_client_set_rsapub(cc, &br_rsa_i31_public); br_ssl_engine_set_rsavrfy(&cc->eng, &br_rsa_i15_pkcs1_vrfy); - br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); + br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i15); br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1); //*/ @@ -323,11 +315,12 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * implementations only if duly measured performance issues make * it mandatory. */ + /* br_ssl_engine_set_aes_cbc(&cc->eng, &br_aes_ct_cbcenc_vtable, &br_aes_ct_cbcdec_vtable); br_ssl_engine_set_aes_ctr(&cc->eng, - &br_aes_ct_ctr_vtable); + &br_aes_ct_ctr_vtable); */ /* Alternate: aes_ct64 br_ssl_engine_set_aes_cbc(&cc->eng, &br_aes_ct64_cbcenc_vtable, @@ -335,13 +328,12 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_ct64_ctr_vtable); */ - /* Alternate: aes_small + // Alternate: aes_small br_ssl_engine_set_aes_cbc(&cc->eng, &br_aes_small_cbcenc_vtable, &br_aes_small_cbcdec_vtable); br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_small_ctr_vtable); - */ /* Alternate: aes_big br_ssl_engine_set_aes_cbc(&cc->eng, &br_aes_big_cbcenc_vtable, @@ -472,7 +464,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, br_x509_minimal_set_hash(xc, br_sha224_ID, &br_sha224_vtable); br_x509_minimal_set_hash(xc, br_sha256_ID, &br_sha256_vtable); br_x509_minimal_set_hash(xc, br_sha384_ID, &br_sha384_vtable); - // br_x509_minimal_set_hash(xc, br_sha512_ID, &br_sha512_vtable); + br_x509_minimal_set_hash(xc, br_sha512_ID, &br_sha512_vtable); /* * Link the X.509 engine in the SSL engine. From 184aa438020c38526f5ce8c0ecdc6aa0342aa9c6 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 30 Jul 2019 15:35:45 -0700 Subject: [PATCH 059/205] fix readme and bump version --- README.md | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6ffe9c0..ca16297 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ In order to remedy this problem, the device must be able to read the data faster * If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM. ### Cipher Support -By default, SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile.c) under `suites[]`, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: +By default, SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile.c) under `suites[]`, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl/ssl_client_full.c). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: ```C++ br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // comment the above line and uncomment the line below if you're having trouble connecting over SSL diff --git a/library.properties b/library.properties index e9cec28..667b8eb 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.1.2 +version=1.1.3 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From 02a8c5ff7c829411dd3b13b166c839799f842560 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 30 Jul 2019 15:37:01 -0700 Subject: [PATCH 060/205] bump version again --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 667b8eb..35182fe 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.1.3 +version=1.2.0 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From 808bc15a1ec333d4eda44bc695f78e3465dfc367 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 30 Jul 2019 17:32:43 -0700 Subject: [PATCH 061/205] fixed a bug with stopping SSLClient in the middle of a connection --- library.properties | 2 +- src/SSLClientImpl.cpp | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/library.properties b/library.properties index 35182fe..368f3ba 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.2.0 +version=1.2.1 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index d0d4255..b94652b 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -248,10 +248,12 @@ void SSLClientImpl::stop_impl() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); // if the engine isn't closed, and the socket is still open + const auto state = br_ssl_engine_current_state(&m_sslctx.eng); while (getWriteError() == SSL_OK && m_is_connected - && br_ssl_engine_current_state(&m_sslctx.eng) != BR_SSL_CLOSED - && m_run_until(BR_SSL_RECVAPP) == 0) { + && state != BR_SSL_CLOSED + && state != 0 + && m_run_until(BR_SSL_SENDAPP | BR_SSL_RECVAPP) == 0) { /* * Discard any incoming application data. */ @@ -263,12 +265,6 @@ void SSLClientImpl::stop_impl() { } // close the ethernet socket get_arduino_client().flush(); - // clear the intake buffer, if any - const auto avail = get_arduino_client().available(); - if (avail > 0) { - m_info("Flushing bytes from client: ", func_name); - get_arduino_client().read(NULL, avail); - } get_arduino_client().stop(); // we are no longer connected m_is_connected = false; @@ -414,7 +410,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { return -1; } // debug - if (state != lastState) { + if (state != lastState || lastState == 0) { lastState = state; m_info("m_run changed state:", func_name); if(m_debug == DebugLevel::SSL_INFO) { @@ -440,7 +436,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { /* * If we reached our target, then we are finished. */ - if (state & target) return 0; + if (state & target || (target == 0 && state == 0)) return 0; /* * If some application data must be read, and we did not From 86607241611494fc11318858dd89ea56d9b1ae4b Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 31 Jul 2019 10:50:59 -0700 Subject: [PATCH 062/205] added back elliptical curves and reduced cipher suite --- library.properties | 2 +- src/TLS12_only_profile.c | 28 +++++++++------------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/library.properties b/library.properties index 368f3ba..820100e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.2.1 +version=1.2.2 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/src/TLS12_only_profile.c b/src/TLS12_only_profile.c index a9921f5..f464fbe 100644 --- a/src/TLS12_only_profile.c +++ b/src/TLS12_only_profile.c @@ -68,24 +68,14 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * better than RSA key exchange (slightly more expensive on the * client, but much cheaper on the server, and it implies smaller * messages). - * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller code). - * -- GCM is better than CBC. * -- AES-128 is preferred over AES-256 (AES-128 is already * strong enough, and AES-256 is 40% more expensive). */ - static const uint16_t suites[] = { - BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - + static const uint16_t suites[] = { BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, }; /* @@ -229,7 +219,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, //* Alternate: set implementations explicitly. // br_ssl_client_set_rsapub(cc, &br_rsa_i31_public); br_ssl_engine_set_rsavrfy(&cc->eng, &br_rsa_i15_pkcs1_vrfy); - br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i15); + br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1); //*/ @@ -242,9 +232,9 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * -- Cipher suites in CHACHA20_POLY1305 need the ChaCha20+Poly1305 * record handler ("set_chapol"). */ - br_ssl_engine_set_cbc(&cc->eng, - &br_sslrec_in_cbc_vtable, - &br_sslrec_out_cbc_vtable); + // br_ssl_engine_set_cbc(&cc->eng, + // &br_sslrec_in_cbc_vtable, + // &br_sslrec_out_cbc_vtable); br_ssl_engine_set_gcm(&cc->eng, &br_sslrec_in_gcm_vtable, &br_sslrec_out_gcm_vtable); @@ -256,7 +246,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * Set the ChaCha20 and Poly1305 implementations * Not included in this file orignally for some reason */ - br_ssl_engine_set_default_chapol(&cc->eng); + // br_ssl_engine_set_default_chapol(&cc->eng); /* * Symmetric encryption: @@ -329,9 +319,9 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, &br_aes_ct64_ctr_vtable); */ // Alternate: aes_small - br_ssl_engine_set_aes_cbc(&cc->eng, - &br_aes_small_cbcenc_vtable, - &br_aes_small_cbcdec_vtable); + // br_ssl_engine_set_aes_cbc(&cc->eng, + // &br_aes_small_cbcenc_vtable, + // &br_aes_small_cbcdec_vtable);*/ br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_small_ctr_vtable); /* Alternate: aes_big From a7499cc9a4164348f0b5be7e9de65334e7d132bf Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 31 Jul 2019 15:32:06 -0700 Subject: [PATCH 063/205] small fix to cert_util.py to allow for ECC chains --- tools/pycert_bearssl/cert_util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/pycert_bearssl/cert_util.py b/tools/pycert_bearssl/cert_util.py index 75b286e..7b854bb 100644 --- a/tools/pycert_bearssl/cert_util.py +++ b/tools/pycert_bearssl/cert_util.py @@ -154,6 +154,7 @@ def get_server_root_cert(address, port, certDict): soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_soc = SSL.Connection(ctx, soc) ssl_soc.connect((address, port)) + ssl_soc.set_tlsext_host_name(bytes(address, "utf8")) try: ssl_soc.do_handshake() cert = ssl_soc.get_peer_cert_chain()[-1] From a097b3c377a53a8f913be0cce9d89bde44ccb697 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 1 Aug 2019 10:00:00 -0700 Subject: [PATCH 064/205] Fixed a TLS timeout when connecting to servers with large ECC chains, removed curve25519 support to save space, added back chachapoly support for speed benefits --- library.properties | 2 +- src/SSLClientImpl.cpp | 3 ++ src/TLS12_only_profile.c | 10 +++-- src/bearssl_ec.h | 10 +++++ src/ec_prime_fast_256.c | 96 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 src/ec_prime_fast_256.c diff --git a/library.properties b/library.properties index 820100e..db0cf09 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.2.2 +version=1.2.3 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index b94652b..13ed636 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -385,6 +385,9 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { // all good to go! the SSL socket should be up and running // overwrite the session we got with new parameters br_ssl_engine_get_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); + // print the cipher suite + m_info("Used cipher suite: ", func_name); + m_info(ssl_ses.cipher_suite, func_name); // set the hostname and ip in the session as well ssl_ses.set_parameters(remoteIP(), host); return 1; diff --git a/src/TLS12_only_profile.c b/src/TLS12_only_profile.c index f464fbe..f812298 100644 --- a/src/TLS12_only_profile.c +++ b/src/TLS12_only_profile.c @@ -71,7 +71,9 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * -- AES-128 is preferred over AES-256 (AES-128 is already * strong enough, and AES-256 is 40% more expensive). */ - static const uint16_t suites[] = { + static const uint16_t suites[] = { + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, @@ -219,7 +221,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, //* Alternate: set implementations explicitly. // br_ssl_client_set_rsapub(cc, &br_rsa_i31_public); br_ssl_engine_set_rsavrfy(&cc->eng, &br_rsa_i15_pkcs1_vrfy); - br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15); + br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15); br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1); //*/ @@ -246,7 +248,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * Set the ChaCha20 and Poly1305 implementations * Not included in this file orignally for some reason */ - // br_ssl_engine_set_default_chapol(&cc->eng); + br_ssl_engine_set_default_chapol(&cc->eng); /* * Symmetric encryption: @@ -437,7 +439,7 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, // br_x509_minimal_set_ecdsa(xc, // &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); br_x509_minimal_set_ecdsa(xc, - br_ssl_engine_get_ec(&cc->eng), + &br_ec_prime_fast_256, br_ssl_engine_get_ecdsa(&cc->eng)); /* diff --git a/src/bearssl_ec.h b/src/bearssl_ec.h index db22692..b03984a 100644 --- a/src/bearssl_ec.h +++ b/src/bearssl_ec.h @@ -529,6 +529,16 @@ extern const br_ec_impl br_ec_all_m15; */ extern const br_ec_impl br_ec_all_m31; +/** + * \brief Aggregate EC implementation "m31". + * + * This implementation is a wrapper for: + * + * - `br_ec_p256_m31` for NIST P-256 + * - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512) + */ +extern const br_ec_impl br_ec_prime_fast_256; + /** * \brief Get the "default" EC implementation for the current system. * diff --git a/src/ec_prime_fast_256.c b/src/ec_prime_fast_256.c new file mode 100644 index 0000000..d418804 --- /dev/null +++ b/src/ec_prime_fast_256.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2019 OSU OPEnS Lab + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + if (curve == BR_EC_secp256r1) { + return br_ec_p256_m15.generator(curve, len); + } + return br_ec_prime_i15.generator(curve, len); +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + if (curve == BR_EC_secp256r1) { + return br_ec_p256_m15.order(curve, len); + } + return br_ec_prime_i15.order(curve, len); +} + +static size_t +api_xoff(int curve, size_t *len) +{ + if (curve == BR_EC_secp256r1) { + return br_ec_p256_m15.xoff(curve, len); + } + return br_ec_prime_i15.xoff(curve, len); +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + if (curve == BR_EC_secp256r1) { + return br_ec_p256_m15.mul(G, Glen, kb, kblen, curve); + } + return br_ec_prime_i15.mul(G, Glen, kb, kblen, curve); +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + if (curve == BR_EC_secp256r1) { + return br_ec_p256_m15.mulgen(R, x, xlen, curve); + } + return br_ec_prime_i15.mulgen(R, x, xlen, curve); +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + if (curve == BR_EC_secp256r1) { + return br_ec_p256_m15.muladd(A, B, len, + x, xlen, y, ylen, curve); + } + return br_ec_prime_i15.muladd(A, B, len, + x, xlen, y, ylen, curve); +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_prime_fast_256 = { + (uint32_t)0x03800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; From 9766e41dee5539a35028c20bc89132eb000d7c53 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 20:35:32 -0700 Subject: [PATCH 065/205] fix build compatibility issues, add travis build test --- .travis.yml | 22 ++++++++++++++++++++++ src/SSLClient.h | 30 +++++------------------------- src/SSLClientImpl.h | 1 - src/config.h | 2 ++ 4 files changed, 29 insertions(+), 26 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..8537ce1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +language: c +sudo: false +cache: + directories: + - ~/arduino_ide + - ~/.arduino15/packages/ +git: + depth: false + quiet: true +env: + global: + # You can uncomment this to explicitly choose an (old) version of the Arduino IDE + #- ARDUINO_IDE_VERSION="1.8.7" + - INSTALL_PLATFORMS=samd +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) +install: + # Note that every library should be installed in a seperate command + - if [! -d "$HOME/arduino_ide/libraries/EthernetLarge" ]; then git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/arduino_ide/libraries/EthernetLarge; fi + +script: + - build_platform zero \ No newline at end of file diff --git a/src/SSLClient.h b/src/SSLClient.h index 0c078e1..215a2b3 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -18,7 +18,6 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "Client.h" #include "SSLClientImpl.h" #include "SSLSession.h" @@ -48,7 +47,6 @@ class SSLClient : public SSLClientImpl { * amount past that will require special modification of this library, and * assumes you know what you are doing. */ -static_assert(std::is_base_of::value, "SSLClient can only accept a type with base class Client!"); static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!"); static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur."); @@ -356,30 +354,12 @@ public: bool operator==(const C& rhs) { return m_client == rhs; } /** @brief Returns whether or not two SSLClient objects do not have the same underlying client object */ bool operator!=(const C& rhs) { return m_client != rhs; } - /** @brief Returns the local port, C::localPort exists. Else return 0. */ - uint16_t localPort() override { - if (std::is_member_function_pointer::value) return m_client.localPort(); - else { - m_warn("Client class has no localPort function, so localPort() will always return 0", __func__); - return 0; - } - } - /** @brief Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE. */ - IPAddress remoteIP() override { - if (std::is_member_function_pointer::value) return m_client.remoteIP(); - else { - m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__); - return INADDR_NONE; - } - } + /** @brief Returns the local port, if C::localPort exists */ + uint16_t localPort() override { return m_client.localPort(); } + /** @brief Returns the remote IP, if C::remoteIP exists. */ + IPAddress remoteIP() override { return m_client.remoteIP(); } /** @brief Returns the remote port, if C::remotePort exists. Else return 0. */ - uint16_t remotePort() override { - if (std::is_member_function_pointer::value) return m_client.remotePort(); - else { - m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__); - return 0; - } - } + uint16_t remotePort() override { return m_client.remotePort(); } /** @brief Returns a reference to the client object stored in this class. Take care not to break it. */ C& getClient() { return m_client; } diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 7b6cd2c..01af2f1 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -203,7 +203,6 @@ private: * connection. */ unsigned char m_iobuf[2048]; - static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size"); // store the index of where we are writing in the buffer // so we can send our records all at once to prevent // weird timing issues diff --git a/src/config.h b/src/config.h index 001b352..ad4969f 100644 --- a/src/config.h +++ b/src/config.h @@ -159,7 +159,9 @@ * Note: if BR_LOMUL is not explicitly enabled or disabled, then * enabling BR_ARMEL_CORTEXM_GCC also enables BR_LOMUL. */ +#ifdef ARDUINO_ARCH_SAMD #define BR_ARMEL_CORTEXM_GCC 1 +#endif /* * When BR_AES_X86NI is enabled, the AES implementation using the x86 "NI" From beaa07f60d9e29470972398922245da102ca5e84 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 20:56:28 -0700 Subject: [PATCH 066/205] change platforms to fix build script --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8537ce1..26883cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ env: global: # You can uncomment this to explicitly choose an (old) version of the Arduino IDE #- ARDUINO_IDE_VERSION="1.8.7" - - INSTALL_PLATFORMS=samd before_install: - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) install: From 7922e59b1024889f117b27116b1041c62ca20167 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:17:26 -0700 Subject: [PATCH 067/205] update travis build script --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 26883cb..a5116e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,6 @@ env: #- ARDUINO_IDE_VERSION="1.8.7" before_install: - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) -install: - # Note that every library should be installed in a seperate command - - if [! -d "$HOME/arduino_ide/libraries/EthernetLarge" ]; then git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/arduino_ide/libraries/EthernetLarge; fi - + - if [! -d "$HOME/arduino_ide/libraries/" ]; then git clone $HOME/arduino_ide/libraries/; fi script: - build_platform zero \ No newline at end of file From b335dea25673be13dcefbdac7c7b8ca3c15ea68d Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:21:14 -0700 Subject: [PATCH 068/205] fix typo in travis --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a5116e7..34b646c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ env: #- ARDUINO_IDE_VERSION="1.8.7" before_install: - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) - - if [! -d "$HOME/arduino_ide/libraries/" ]; then git clone $HOME/arduino_ide/libraries/; fi + - if [! -d "$HOME/arduino_ide/libraries/EthernetLarge" ]; then git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/arduino_ide/libraries/EthernetLarge; fi + script: - build_platform zero \ No newline at end of file From 5d8d4925d4aabce55c9cb8067ef0547746d92172 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:26:50 -0700 Subject: [PATCH 069/205] fix another typo --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34b646c..6eac9e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ env: #- ARDUINO_IDE_VERSION="1.8.7" before_install: - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) - - if [! -d "$HOME/arduino_ide/libraries/EthernetLarge" ]; then git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/arduino_ide/libraries/EthernetLarge; fi - +install: + - if [ ! -d "$HOME/arduino_ide/libraries/EthernetLarge" ]; then git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/arduino_ide/libraries/EthernetLarge; fi script: - build_platform zero \ No newline at end of file From d884e4d4edb1fe7db1d8addae07294d8dda95fa4 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:33:03 -0700 Subject: [PATCH 070/205] fix analog pin assignment in examples --- examples/EthernetHTTPS/EthernetHTTPS.ino | 2 +- examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/EthernetHTTPS/EthernetHTTPS.ino b/examples/EthernetHTTPS/EthernetHTTPS.ino index 5245554..4ab030c 100644 --- a/examples/EthernetHTTPS/EthernetHTTPS.ino +++ b/examples/EthernetHTTPS/EthernetHTTPS.ino @@ -38,7 +38,7 @@ IPAddress myDns(8, 8, 8, 8); // Choose the analog pin to get semi-random data from for SSL // Pick a pin that's not connected or attached to a randomish voltage source -const int rand_pin = A7; +const int rand_pin = A5; // Initialize the SSL client library // We input an EthernetClient, our trust anchors, and the analog pin diff --git a/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino index e21f0b1..08d919d 100644 --- a/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino +++ b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino @@ -39,7 +39,7 @@ IPAddress myDns(8, 8, 8, 8); // Choose the analog pin to get semi-random data from for SSL // Pick a pin that's not connected or attached to a randomish voltage source -const int rand_pin = A7; +const int rand_pin = A5; // Initialize the SSL client library // We input an EthernetClient, our trust anchors, and the analog pin From 708b564d3002082a3b9512532056958bd26324a1 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:39:49 -0700 Subject: [PATCH 071/205] remove unnecessary explicit ctor --- src/SSLSession.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SSLSession.h b/src/SSLSession.h index b6ca188..ef6e997 100644 --- a/src/SSLSession.h +++ b/src/SSLSession.h @@ -57,7 +57,7 @@ public: * * Sets all parameters to zero, and invalidates the session */ - explicit SSLSession() + SSLSession() : m_valid_session(false) , m_hostname() , m_ip(INADDR_NONE) {} From 81cb0db8970b8dd8547b2ffce7f7a474bd874de7 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:45:04 -0700 Subject: [PATCH 072/205] Add travis badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ca16297..f37a77a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # SSLClient - Arduino Library For SSL +[![Build Status](https://travis-ci.org/OPEnSLab-OSU/SSLClient.svg?branch=master)](https://travis-ci.org/OPEnSLab-OSU/SSLClient) + **SSLClient requires at least 110kb flash and 7kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.** You can also view this README in [doxygen](https://openslab-osu.github.io/SSLClient/html/index.html). From d4e988f6f19dedda2c56dc74b3cccec8b907ba9a Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:47:12 -0700 Subject: [PATCH 073/205] update doxy --- docs/html/_s_s_l_client_8h.html | 4 +- docs/html/_s_s_l_client_8h_source.html | 82 +++--- docs/html/_s_s_l_client_impl_8h.html | 1 + docs/html/_s_s_l_client_impl_8h_source.html | 64 ++--- docs/html/_s_s_l_client_parameters_8h.html | 118 +++++++++ .../_s_s_l_client_parameters_8h_source.html | 110 +++++++++ docs/html/_s_s_l_session_8h_source.html | 2 +- docs/html/annotated.html | 3 +- docs/html/annotated_dup.js | 1 + docs/html/class_s_s_l_client-members.html | 4 +- docs/html/class_s_s_l_client.html | 78 +++++- docs/html/class_s_s_l_client.js | 1 + .../html/class_s_s_l_client_impl-members.html | 5 +- docs/html/class_s_s_l_client_impl.html | 65 ++++- docs/html/class_s_s_l_client_impl.js | 1 + docs/html/class_s_s_l_session-members.html | 2 +- docs/html/class_s_s_l_session.html | 2 +- docs/html/classes.html | 8 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 4 + .../dir_68267d1309a1af8e8297ef4c3efbcdba.js | 4 + docs/html/ec__prime__fast__256_8c.html | 130 ++++++++++ docs/html/ec__prime__fast__256_8c.js | 4 + docs/html/files.html | 16 +- docs/html/functions.html | 19 +- docs/html/functions_vars.html | 47 +--- docs/html/globals.html | 3 + docs/html/globals_vars.html | 3 + docs/html/hierarchy.html | 1 + docs/html/hierarchy.js | 3 +- docs/html/index.html | 8 +- docs/html/menudata.js | 4 +- docs/html/navtreedata.js | 3 +- docs/html/navtreeindex0.js | 233 +++++++++--------- docs/html/search/all_2.js | 3 +- docs/html/search/all_3.js | 2 + docs/html/search/all_5.js | 2 + docs/html/search/all_e.js | 6 +- docs/html/search/classes_0.js | 1 + docs/html/search/files_1.js | 2 +- docs/html/search/files_2.js | 6 +- docs/html/search/files_3.js | 11 +- docs/html/search/files_4.html | 30 +++ docs/html/search/files_4.js | 8 + docs/html/search/functions_b.js | 4 +- docs/html/search/searchdata.js | 4 +- docs/html/search/variables_1.js | 15 +- docs/html/search/variables_2.html | 30 +++ docs/html/search/variables_2.js | 5 + docs/html/search/variables_3.html | 30 +++ docs/html/search/variables_3.js | 4 + ...truct_s_s_l_client_parameters-members.html | 111 +++++++++ docs/html/struct_s_s_l_client_parameters.html | 181 ++++++++++++++ docs/html/struct_s_s_l_client_parameters.js | 6 + .../__pycache__/cert_util.cpython-37.pyc | Bin 0 -> 7329 bytes tools/pycert_bearssl/cert.cer | 20 ++ tools/pycert_bearssl/certificates.h | 77 ++++++ 56 files changed, 1299 insertions(+), 292 deletions(-) create mode 100644 docs/html/_s_s_l_client_parameters_8h.html create mode 100644 docs/html/_s_s_l_client_parameters_8h_source.html create mode 100644 docs/html/ec__prime__fast__256_8c.html create mode 100644 docs/html/ec__prime__fast__256_8c.js create mode 100644 docs/html/search/files_4.html create mode 100644 docs/html/search/files_4.js create mode 100644 docs/html/search/variables_2.html create mode 100644 docs/html/search/variables_2.js create mode 100644 docs/html/search/variables_3.html create mode 100644 docs/html/search/variables_3.js create mode 100644 docs/html/struct_s_s_l_client_parameters-members.html create mode 100644 docs/html/struct_s_s_l_client_parameters.html create mode 100644 docs/html/struct_s_s_l_client_parameters.js create mode 100644 tools/pycert_bearssl/__pycache__/cert_util.cpython-37.pyc create mode 100644 tools/pycert_bearssl/cert.cer create mode 100644 tools/pycert_bearssl/certificates.h diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index ce1fe0c..945261d 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -94,10 +94,10 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h.html','');});
                      SSLClient.h File Reference
                      -
                      #include <type_traits>
                      -#include "Client.h"
                      +
                      #include "Client.h"
                      #include "SSLClientImpl.h"
                      #include "SSLSession.h"
                      +#include "SSLClientParameters.h"

                      Go to the source code of this file.

                      diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index 9ffa230..090a4ef 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -91,51 +91,53 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
                      SSLClient.h
                      -Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include <type_traits>
                      22 #include "Client.h"
                      23 #include "SSLClientImpl.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClient_H_
                      27 #define SSLClient_H_
                      28 
                      34 template <class C, size_t SessionCache = 1>
                      35 class SSLClient : public SSLClientImpl {
                      36 /*
                      37  * static checks
                      38  * I'm a java developer, so I want to ensure that my inheritance is safe.
                      39  * These checks ensure that all the functions we use on class C are
                      40  * actually present on class C. It does this by checking that the
                      41  * class inherits from Client.
                      42  *
                      43  * Additionally, I ran into a lot of memory issues with large sessions caches.
                      44  * Since each session contains at max 352 bytes of memory, they eat of the
                      45  * stack quite quickly and can cause overflows. As a result, I have added a
                      46  * warning here to discourage the use of more than 3 sessions at a time. Any
                      47  * amount past that will require special modification of this library, and
                      48  * assumes you know what you are doing.
                      49  */
                      50 static_assert(std::is_base_of<Client, C>::value, "SSLClient can only accept a type with base class Client!");
                      51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
                      52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
                      53 
                      54 public:
                      71  explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug = SSL_WARN)
                      72  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
                      73  , m_client(client)
                      74  , m_sessions{SSLSession()}
                      75  {
                      76  // set the timeout to a reasonable number (it can always be changes later)
                      77  // SSL Connections take a really long time so we don't want to time out a legitimate thing
                      78  setTimeout(30 * 1000);
                      79  }
                      80 
                      81  //========================================
                      82  //= Functions implemented in SSLClientImpl
                      83  //========================================
                      84 
                      124  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
                      125 
                      162  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
                      163 
                      165  size_t write(uint8_t b) override { return write_impl(&b, 1); }
                      189  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
                      190 
                      209  int available() override { return available_impl(); }
                      210 
                      215  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
                      237  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
                      238 
                      247  int peek() override { return peek_impl(); }
                      248 
                      256  void flush() override { return flush_impl(); }
                      257 
                      266  void stop() override { return stop_impl(); }
                      267 
                      281  uint8_t connected() override { return connected_impl(); }
                      282 
                      283  //========================================
                      284  //= Functions Not in the Client Interface
                      285  //========================================
                      286 
                      301  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
                      302 
                      311  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
                      312 
                      318  size_t getSessionCount() const override { return SessionCache; }
                      319 
                      325  operator bool() { return connected() > 0; }
                      327  bool operator==(const bool value) { return bool() == value; }
                      329  bool operator!=(const bool value) { return bool() != value; }
                      331  bool operator==(const C& rhs) { return m_client == rhs; }
                      333  bool operator!=(const C& rhs) { return m_client != rhs; }
                      335  uint16_t localPort() override {
                      336  if (std::is_member_function_pointer<decltype(&C::localPort)>::value) return m_client.localPort();
                      337  else {
                      338  m_warn("Client class has no localPort function, so localPort() will always return 0", __func__);
                      339  return 0;
                      340  }
                      341  }
                      343  IPAddress remoteIP() override {
                      344  if (std::is_member_function_pointer<decltype(&C::remoteIP)>::value) return m_client.remoteIP();
                      345  else {
                      346  m_warn("Client class has no remoteIP function, so remoteIP() will always return INADDR_NONE. This means that sessions caching will always be disabled.", __func__);
                      347  return INADDR_NONE;
                      348  }
                      349  }
                      351  uint16_t remotePort() override {
                      352  if (std::is_member_function_pointer<decltype(&C::remotePort)>::value) return m_client.remotePort();
                      353  else {
                      354  m_warn("Client class has no remotePort function, so remotePort() will always return 0", __func__);
                      355  return 0;
                      356  }
                      357  }
                      358 
                      360  C& getClient() { return m_client; }
                      361 
                      362 protected:
                      364  Client& get_arduino_client() override { return m_client; }
                      365  const Client& get_arduino_client() const override { return m_client; }
                      367  SSLSession* get_session_array() override { return m_sessions; }
                      368  const SSLSession* get_session_array() const override { return m_sessions; }
                      369 
                      370 private:
                      371  // create a copy of the client
                      372  C m_client;
                      373  // also store an array of SSLSessions, so we can resume communication with multiple websites
                      374  SSLSession m_sessions[SessionCache];
                      375 };
                      376 
                      377 #endif
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:132
                      -
                      const SSLSession * get_session_array() const override
                      Definition: SSLClient.h:368
                      -
                      IPAddress remoteIP() override
                      Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.
                      Definition: SSLClient.h:343
                      -
                      size_t write(uint8_t b) override
                      Definition: SSLClient.h:165
                      -
                      Definition: SSLClientImpl.h:65
                      -
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:294
                      +Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include "Client.h"
                      22 #include "SSLClientImpl.h"
                      23 #include "SSLSession.h"
                      24 #include "SSLClientParameters.h"
                      25 
                      26 #ifndef SSLClient_H_
                      27 #define SSLClient_H_
                      28 
                      34 template <class C, size_t SessionCache = 1>
                      35 class SSLClient : public SSLClientImpl {
                      36 /*
                      37  * static checks
                      38  * I'm a java developer, so I want to ensure that my inheritance is safe.
                      39  * These checks ensure that all the functions we use on class C are
                      40  * actually present on class C. It does this by checking that the
                      41  * class inherits from Client.
                      42  *
                      43  * Additionally, I ran into a lot of memory issues with large sessions caches.
                      44  * Since each session contains at max 352 bytes of memory, they eat of the
                      45  * stack quite quickly and can cause overflows. As a result, I have added a
                      46  * warning here to discourage the use of more than 3 sessions at a time. Any
                      47  * amount past that will require special modification of this library, and
                      48  * assumes you know what you are doing.
                      49  */
                      50 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
                      51 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
                      52 
                      53 public:
                      71  explicit SSLClient( const C& client,
                      72  const br_x509_trust_anchor *trust_anchors,
                      73  const size_t trust_anchors_num,
                      74  const int analog_pin,
                      75  const DebugLevel debug = SSL_WARN)
                      76  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
                      77  , m_client(client)
                      78  , m_sessions{}
                      79  {
                      80  // set the timeout to a reasonable number (it can always be changes later)
                      81  // SSL Connections take a really long time so we don't want to time out a legitimate thing
                      82  setTimeout(30 * 1000);
                      83  }
                      84 
                      89  explicit SSLClient( const C& client,
                      90  const br_x509_trust_anchor *trust_anchors,
                      91  const size_t trust_anchors_num,
                      92  const int analog_pin,
                      93  const DebugLevel debug,
                      94  const SSLClientParameters* mutual_auth_params)
                      95  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug, mutual_auth_params)
                      96  , m_client(client)
                      97  , m_sessions{}
                      98  {
                      99  // set the timeout to a reasonable number (it can always be changes later)
                      100  // SSL Connections take a really long time so we don't want to time out a legitimate thing
                      101  setTimeout(30 * 1000);
                      102  }
                      103 
                      104  //========================================
                      105  //= Functions implemented in SSLClientImpl
                      106  //========================================
                      107 
                      147  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
                      148 
                      185  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
                      186 
                      188  size_t write(uint8_t b) override { return write_impl(&b, 1); }
                      212  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
                      213 
                      232  int available() override { return available_impl(); }
                      233 
                      238  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
                      260  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
                      261 
                      270  int peek() override { return peek_impl(); }
                      271 
                      279  void flush() override { return flush_impl(); }
                      280 
                      289  void stop() override { return stop_impl(); }
                      290 
                      304  uint8_t connected() override { return connected_impl(); }
                      305 
                      306  //========================================
                      307  //= Functions Not in the Client Interface
                      308  //========================================
                      309 
                      324  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
                      325 
                      334  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
                      335 
                      341  size_t getSessionCount() const override { return SessionCache; }
                      342 
                      348  operator bool() { return connected() > 0; }
                      350  bool operator==(const bool value) { return bool() == value; }
                      352  bool operator!=(const bool value) { return bool() != value; }
                      354  bool operator==(const C& rhs) { return m_client == rhs; }
                      356  bool operator!=(const C& rhs) { return m_client != rhs; }
                      358  uint16_t localPort() override { return m_client.localPort(); }
                      360  IPAddress remoteIP() override { return m_client.remoteIP(); }
                      362  uint16_t remotePort() override { return m_client.remotePort(); }
                      363 
                      365  C& getClient() { return m_client; }
                      366 
                      367 protected:
                      369  Client& get_arduino_client() override { return m_client; }
                      370  const Client& get_arduino_client() const override { return m_client; }
                      372  SSLSession* get_session_array() override { return m_sessions; }
                      373  const SSLSession* get_session_array() const override { return m_sessions; }
                      374 
                      375 private:
                      376  // create a copy of the client
                      377  C m_client;
                      378  // also store an array of SSLSessions, so we can resume communication with multiple websites
                      379  SSLSession m_sessions[SessionCache];
                      380 };
                      381 
                      382 #endif
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:147
                      +
                      const SSLSession * get_session_array() const override
                      Definition: SSLClient.h:373
                      +
                      IPAddress remoteIP() override
                      Returns the remote IP, if C::remoteIP exists.
                      Definition: SSLClient.h:360
                      +
                      size_t write(uint8_t b) override
                      Definition: SSLClient.h:188
                      +
                      Definition: SSLClientImpl.h:66
                      +
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:305
                      This class stores values which allow SSLClient to save and resume SSL sessions.
                      Definition: SSLSession.h:52
                      -
                      bool operator!=(const C &rhs)
                      Returns whether or not two SSLClient objects do not have the same underlying client object.
                      Definition: SSLClient.h:333
                      -
                      int available() override
                      Returns the number of bytes available to read from the data that has been received and decrypted.
                      Definition: SSLClient.h:209
                      -
                      C & getClient()
                      Returns a reference to the client object stored in this class. Take care not to break it.
                      Definition: SSLClient.h:360
                      -
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:211
                      -
                      void flush() override
                      Force writing the buffered bytes from SSLClient::write to the network.
                      Definition: SSLClient.h:256
                      +
                      SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)
                      Definition: SSLClient.h:89
                      +
                      bool operator!=(const C &rhs)
                      Returns whether or not two SSLClient objects do not have the same underlying client object.
                      Definition: SSLClient.h:356
                      +
                      int available() override
                      Returns the number of bytes available to read from the data that has been received and decrypted.
                      Definition: SSLClient.h:232
                      +
                      C & getClient()
                      Returns a reference to the client object stored in this class. Take care not to break it.
                      Definition: SSLClient.h:365
                      +
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:226
                      +
                      This struct stores data required for SSLClient to use mutual authentication.
                      Definition: SSLClientParameters.h:52
                      +
                      void flush() override
                      Force writing the buffered bytes from SSLClient::write to the network.
                      Definition: SSLClient.h:279
                      The main SSLClient class. Check out README.md for more info.
                      Definition: SSLClient.h:35
                      -
                      bool operator!=(const bool value)
                      Definition: SSLClient.h:329
                      -
                      void stop() override
                      Close the connection.
                      Definition: SSLClient.h:266
                      -
                      size_t write(const uint8_t *buf, size_t size) override
                      Write some bytes to the SSL connection.
                      Definition: SSLClient.h:189
                      +
                      bool operator!=(const bool value)
                      Definition: SSLClient.h:352
                      +
                      void stop() override
                      Close the connection.
                      Definition: SSLClient.h:289
                      +
                      size_t write(const uint8_t *buf, size_t size) override
                      Write some bytes to the SSL connection.
                      Definition: SSLClient.h:212
                      SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
                      Initialize SSLClient with all of the prerequisites needed.
                      Definition: SSLClient.h:71
                      -
                      int peek() override
                      View the first byte of the buffer, without removing it from the SSLClient Buffer.
                      Definition: SSLClient.h:247
                      -
                      int available_impl()
                      Definition: SSLClientImpl.cpp:175
                      -
                      bool operator==(const C &rhs)
                      Returns whether or not two SSLClient objects have the same underlying client object.
                      Definition: SSLClient.h:331
                      -
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:196
                      -
                      SSLSession * get_session_array() override
                      Returns an instance of the session array that is on the stack.
                      Definition: SSLClient.h:367
                      -
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:313
                      -
                      Client & get_arduino_client() override
                      Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
                      Definition: SSLClient.h:364
                      -
                      uint16_t localPort() override
                      Returns the local port, C::localPort exists. Else return 0.
                      Definition: SSLClient.h:335
                      +
                      int peek() override
                      View the first byte of the buffer, without removing it from the SSLClient Buffer.
                      Definition: SSLClient.h:270
                      +
                      int available_impl()
                      Definition: SSLClientImpl.cpp:190
                      +
                      bool operator==(const C &rhs)
                      Returns whether or not two SSLClient objects have the same underlying client object.
                      Definition: SSLClient.h:354
                      +
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:211
                      +
                      SSLSession * get_session_array() override
                      Returns an instance of the session array that is on the stack.
                      Definition: SSLClient.h:372
                      +
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:324
                      +
                      Client & get_arduino_client() override
                      Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
                      Definition: SSLClient.h:369
                      +
                      uint16_t localPort() override
                      Returns the local port, if C::localPort exists.
                      Definition: SSLClient.h:358
                      -
                      void m_warn(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:153
                      -
                      int read() override
                      Read a single byte, or -1 if none is available.
                      Definition: SSLClient.h:215
                      -
                      uint8_t connected() override
                      Check if the device is connected.
                      Definition: SSLClient.h:281
                      +
                      int read() override
                      Read a single byte, or -1 if none is available.
                      Definition: SSLClient.h:238
                      + +
                      uint8_t connected() override
                      Check if the device is connected.
                      Definition: SSLClient.h:304
                      -
                      const Client & get_arduino_client() const override
                      Definition: SSLClient.h:365
                      -
                      int connect(const char *host, uint16_t port) override
                      Connect over SSL to a host specified by a hostname.
                      Definition: SSLClient.h:162
                      -
                      bool operator==(const bool value)
                      Definition: SSLClient.h:327
                      -
                      uint16_t remotePort() override
                      Returns the remote port, if C::remotePort exists. Else return 0.
                      Definition: SSLClient.h:351
                      -
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:75
                      -
                      size_t getSessionCount() const override
                      Get the maximum number of SSL sessions that can be stored at once.
                      Definition: SSLClient.h:318
                      -
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:231
                      -
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:223
                      -
                      Implementation code to be inherited by SSLClient.
                      Definition: SSLClientImpl.h:71
                      -
                      void removeSession(const char *host, const IPAddress &addr)
                      Clear the session corresponding to a host and IP.
                      Definition: SSLClient.h:311
                      -
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:263
                      -
                      SSLSession & getSession(const char *host, const IPAddress &addr)
                      Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
                      Definition: SSLClient.h:301
                      -
                      DebugLevel
                      Level of verbosity used in logging for SSLClient.
                      Definition: SSLClientImpl.h:59
                      -
                      int read(uint8_t *buf, size_t size) override
                      Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
                      Definition: SSLClient.h:237
                      -
                      int connect(IPAddress ip, uint16_t port) override
                      Connect over SSL to a host specified by an IP address.
                      Definition: SSLClient.h:124
                      +
                      const Client & get_arduino_client() const override
                      Definition: SSLClient.h:370
                      +
                      int connect(const char *host, uint16_t port) override
                      Connect over SSL to a host specified by a hostname.
                      Definition: SSLClient.h:185
                      +
                      bool operator==(const bool value)
                      Definition: SSLClient.h:350
                      +
                      uint16_t remotePort() override
                      Returns the remote port, if C::remotePort exists. Else return 0.
                      Definition: SSLClient.h:362
                      +
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:90
                      +
                      size_t getSessionCount() const override
                      Get the maximum number of SSL sessions that can be stored at once.
                      Definition: SSLClient.h:341
                      +
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:246
                      +
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:238
                      +
                      Implementation code to be inherited by SSLClient.
                      Definition: SSLClientImpl.h:72
                      +
                      void removeSession(const char *host, const IPAddress &addr)
                      Clear the session corresponding to a host and IP.
                      Definition: SSLClient.h:334
                      +
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:274
                      +
                      SSLSession & getSession(const char *host, const IPAddress &addr)
                      Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
                      Definition: SSLClient.h:324
                      +
                      DebugLevel
                      Level of verbosity used in logging for SSLClient.
                      Definition: SSLClientImpl.h:60
                      +
                      int read(uint8_t *buf, size_t size) override
                      Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
                      Definition: SSLClient.h:260
                      +
                      int connect(IPAddress ip, uint16_t port) override
                      Connect over SSL to a host specified by an IP address.
                      Definition: SSLClient.h:147
                      diff --git a/docs/html/_s_s_l_client_impl_8h.html b/docs/html/_s_s_l_client_impl_8h.html index 0acd8c1..6e9ba5d 100644 --- a/docs/html/_s_s_l_client_impl_8h.html +++ b/docs/html/_s_s_l_client_impl_8h.html @@ -98,6 +98,7 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h.html','');}); #include "Arduino.h"
                      #include "Client.h"
                      #include "SSLSession.h"
                      +#include "SSLClientParameters.h"

                      Go to the source code of this file.

                      diff --git a/docs/html/_s_s_l_client_impl_8h_source.html b/docs/html/_s_s_l_client_impl_8h_source.html index 6bd981b..6e50fd6 100644 --- a/docs/html/_s_s_l_client_impl_8h_source.html +++ b/docs/html/_s_s_l_client_impl_8h_source.html @@ -91,46 +91,48 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h_source.html','')
                      SSLClientImpl.h
                      -Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include "bearssl.h"
                      22 #include "Arduino.h"
                      23 #include "Client.h"
                      24 #include "SSLSession.h"
                      25 
                      26 #ifndef SSLClientImpl_H_
                      27 #define SSLClientImpl_H_
                      28 
                      37 enum Error {
                      38  SSL_OK = 0,
                      51 };
                      52 
                      59 enum DebugLevel {
                      61  SSL_NONE = 0,
                      63  SSL_ERROR = 1,
                      65  SSL_WARN = 2,
                      67  SSL_INFO = 3,
                      68 };
                      69 
                      71 class SSLClientImpl : public Client {
                      72 public:
                      74  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
                      75  const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug);
                      76 
                      77  //============================================
                      78  //= Functions implemented in SSLClientImpl.cpp
                      79  //============================================
                      80 
                      82  int connect_impl(IPAddress ip, uint16_t port);
                      84  int connect_impl(const char *host, uint16_t port);
                      86  size_t write_impl(const uint8_t *buf, size_t size);
                      88  int available_impl();
                      90  int read_impl(uint8_t *buf, size_t size);
                      92  int peek_impl();
                      94  void flush_impl();
                      96  void stop_impl();
                      98  uint8_t connected_impl();
                      100  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
                      102  void remove_session_impl(const char* host, const IPAddress& addr);
                      103 
                      104  //============================================
                      105  //= Functions implemented in SSLClient.h
                      106  //============================================
                      108  virtual uint16_t localPort() = 0;
                      110  virtual IPAddress remoteIP() = 0;
                      112  virtual uint16_t remotePort() = 0;
                      114  virtual size_t getSessionCount() const = 0;
                      115 
                      116 protected:
                      118  virtual Client& get_arduino_client() = 0;
                      119  virtual const Client& get_arduino_client() const = 0;
                      121  virtual SSLSession* get_session_array() = 0;
                      122  virtual const SSLSession* get_session_array() const = 0;
                      123 
                      124  //============================================
                      125  //= Functions implemented in SSLClientImpl.cpp
                      126  //============================================
                      127 
                      129  void m_print_prefix(const char* func_name, const DebugLevel level) const;
                      130 
                      132  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
                      133 
                      135  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
                      136 
                      138  template<typename T>
                      139  void m_print(const T str, const char* func_name, const DebugLevel level) const {
                      140  // check the current debug level and serial status
                      141  if (level > m_debug || !Serial) return;
                      142  // print prefix
                      143  m_print_prefix(func_name, level);
                      144  // print the message
                      145  Serial.println(str);
                      146  }
                      147 
                      149  template<typename T>
                      150  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
                      151 
                      152  template<typename T>
                      153  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
                      154 
                      155  template<typename T>
                      156  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
                      157 
                      158 private:
                      160  bool m_soft_connected(const char* func_name);
                      162  int m_start_ssl(const char* host, SSLSession& ssl_ses);
                      164  int m_run_until(const unsigned target);
                      166  unsigned m_update_engine();
                      168  int m_get_session_index(const char* host, const IPAddress& addr) const;
                      169 
                      170  //============================================
                      171  //= Data Members
                      172  //============================================
                      173 
                      174  // store pointers to the trust anchors
                      175  // should not be computed at runtime
                      176  const br_x509_trust_anchor *m_trust_anchors;
                      177  const size_t m_trust_anchors_num;
                      178  // store the pin to fetch an RNG see from
                      179  const int m_analog_pin;
                      180  // store an index of where a new session can be placed if we don't have any corresponding sessions
                      181  size_t m_session_index;
                      182  // store whether to enable debug logging
                      183  const DebugLevel m_debug;
                      184  // store if we are connected in bearssl or not
                      185  bool m_is_connected;
                      186  // store the context values required for SSL
                      187  br_ssl_client_context m_sslctx;
                      188  br_x509_minimal_context m_x509ctx;
                      189  // use a mono-directional buffer by default to cut memory in half
                      190  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
                      191  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
                      192  // simply edit this value to change the buffer size to the desired value
                      193  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
                      194  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
                      202  unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO / 8];
                      203  static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI, "m_iobuf must be below maximum buffer size");
                      204  // store the index of where we are writing in the buffer
                      205  // so we can send our records all at once to prevent
                      206  // weird timing issues
                      207  size_t m_write_idx;
                      208 };
                      209 
                      210 #endif /* SSLClientImpl_H_ */
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:132
                      +Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      21 #include "bearssl.h"
                      22 #include "Arduino.h"
                      23 #include "Client.h"
                      24 #include "SSLSession.h"
                      25 #include "SSLClientParameters.h"
                      26 
                      27 #ifndef SSLClientImpl_H_
                      28 #define SSLClientImpl_H_
                      29 
                      38 enum Error {
                      39  SSL_OK = 0,
                      52 };
                      53 
                      60 enum DebugLevel {
                      62  SSL_NONE = 0,
                      64  SSL_ERROR = 1,
                      66  SSL_WARN = 2,
                      68  SSL_INFO = 3,
                      69 };
                      70 
                      72 class SSLClientImpl : public Client {
                      73 public:
                      75  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
                      76  const size_t trust_anchors_num, const int analog_pin,
                      77  const DebugLevel debug);
                      78 
                      80  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
                      81  const size_t trust_anchors_num, const int analog_pin,
                      82  const DebugLevel debug, const SSLClientParameters* mutual_auth_params);
                      83 
                      84  //============================================
                      85  //= Functions implemented in SSLClientImpl.cpp
                      86  //============================================
                      87 
                      89  int connect_impl(IPAddress ip, uint16_t port);
                      91  int connect_impl(const char *host, uint16_t port);
                      93  size_t write_impl(const uint8_t *buf, size_t size);
                      95  int available_impl();
                      97  int read_impl(uint8_t *buf, size_t size);
                      99  int peek_impl();
                      101  void flush_impl();
                      103  void stop_impl();
                      105  uint8_t connected_impl();
                      107  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
                      109  void remove_session_impl(const char* host, const IPAddress& addr);
                      110 
                      111  //============================================
                      112  //= Functions implemented in SSLClient.h
                      113  //============================================
                      115  virtual uint16_t localPort() = 0;
                      117  virtual IPAddress remoteIP() = 0;
                      119  virtual uint16_t remotePort() = 0;
                      121  virtual size_t getSessionCount() const = 0;
                      122 
                      123 protected:
                      125  virtual Client& get_arduino_client() = 0;
                      126  virtual const Client& get_arduino_client() const = 0;
                      128  virtual SSLSession* get_session_array() = 0;
                      129  virtual const SSLSession* get_session_array() const = 0;
                      130 
                      131  //============================================
                      132  //= Functions implemented in SSLClientImpl.cpp
                      133  //============================================
                      134 
                      136  void m_print_prefix(const char* func_name, const DebugLevel level) const;
                      137 
                      139  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
                      140 
                      142  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
                      143 
                      145  template<typename T>
                      146  void m_print(const T str, const char* func_name, const DebugLevel level) const {
                      147  // check the current debug level and serial status
                      148  if (level > m_debug || !Serial) return;
                      149  // print prefix
                      150  m_print_prefix(func_name, level);
                      151  // print the message
                      152  Serial.println(str);
                      153  }
                      154 
                      156  template<typename T>
                      157  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
                      158 
                      159  template<typename T>
                      160  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
                      161 
                      162  template<typename T>
                      163  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
                      164 
                      165 private:
                      167  bool m_soft_connected(const char* func_name);
                      169  int m_start_ssl(const char* host, SSLSession& ssl_ses);
                      171  int m_run_until(const unsigned target);
                      173  unsigned m_update_engine();
                      175  int m_get_session_index(const char* host, const IPAddress& addr) const;
                      176 
                      177  //============================================
                      178  //= Data Members
                      179  //============================================
                      180 
                      181  // store the pin to fetch an RNG see from
                      182  const int m_analog_pin;
                      183  // store an index of where a new session can be placed if we don't have any corresponding sessions
                      184  size_t m_session_index;
                      185  // store whether to enable debug logging
                      186  const DebugLevel m_debug;
                      187  // store if we are connected in bearssl or not
                      188  bool m_is_connected;
                      189  // store the context values required for SSL
                      190  br_ssl_client_context m_sslctx;
                      191  br_x509_minimal_context m_x509ctx;
                      192  // use a mono-directional buffer by default to cut memory in half
                      193  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
                      194  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
                      195  // simply edit this value to change the buffer size to the desired value
                      196  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
                      197  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
                      205  unsigned char m_iobuf[2048];
                      206  // store the index of where we are writing in the buffer
                      207  // so we can send our records all at once to prevent
                      208  // weird timing issues
                      209  size_t m_write_idx;
                      210 };
                      211 
                      212 #endif /* SSLClientImpl_H_ */
                      size_t write_impl(const uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:147
                      virtual uint16_t remotePort()=0
                      -
                      void m_print(const T str, const char *func_name, const DebugLevel level) const
                      debugging print function, only prints if m_debug is true
                      Definition: SSLClientImpl.h:139
                      -
                      Definition: SSLClientImpl.h:65
                      +
                      void m_print(const T str, const char *func_name, const DebugLevel level) const
                      debugging print function, only prints if m_debug is true
                      Definition: SSLClientImpl.h:146
                      +
                      Definition: SSLClientImpl.h:66
                      virtual IPAddress remoteIP()=0
                      -
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:294
                      +
                      SSLSession & get_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:305
                      This class stores values which allow SSLClient to save and resume SSL sessions.
                      Definition: SSLSession.h:52
                      -
                      void m_info(const T str, const char *func_name) const
                      Prints a info message to serial, if info messages are enabled.
                      Definition: SSLClientImpl.h:150
                      +
                      void m_info(const T str, const char *func_name) const
                      Prints a info message to serial, if info messages are enabled.
                      Definition: SSLClientImpl.h:157
                      SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
                      Definition: SSLClientImpl.cpp:53
                      -
                      void m_error(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:156
                      -
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:211
                      -
                      Definition: SSLClientImpl.h:67
                      -
                      Definition: SSLClientImpl.h:63
                      -
                      Definition: SSLClientImpl.h:48
                      +
                      void m_error(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:163
                      +
                      int peek_impl()
                      Definition: SSLClientImpl.cpp:226
                      +
                      Definition: SSLClientImpl.h:68
                      +
                      Definition: SSLClientImpl.h:64
                      +
                      This struct stores data required for SSLClient to use mutual authentication.
                      Definition: SSLClientParameters.h:52
                      +
                      Definition: SSLClientImpl.h:49
                      virtual size_t getSessionCount() const =0
                      virtual SSLSession * get_session_array()=0
                      -
                      Definition: SSLClientImpl.h:46
                      -
                      Definition: SSLClientImpl.h:38
                      -
                      void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
                      Prints the string associated with a write error.
                      Definition: SSLClientImpl.cpp:657
                      -
                      int available_impl()
                      Definition: SSLClientImpl.cpp:175
                      -
                      Error
                      Static constants defining the possible errors encountered.
                      Definition: SSLClientImpl.h:37
                      -
                      Definition: SSLClientImpl.h:42
                      -
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:196
                      -
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:313
                      -
                      Definition: SSLClientImpl.h:44
                      +
                      Definition: SSLClientImpl.h:47
                      +
                      Definition: SSLClientImpl.h:39
                      +
                      void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
                      Prints the string associated with a write error.
                      Definition: SSLClientImpl.cpp:671
                      +
                      int available_impl()
                      Definition: SSLClientImpl.cpp:190
                      +
                      Error
                      Static constants defining the possible errors encountered.
                      Definition: SSLClientImpl.h:38
                      +
                      Definition: SSLClientImpl.h:43
                      +
                      int read_impl(uint8_t *buf, size_t size)
                      Definition: SSLClientImpl.cpp:211
                      +
                      void remove_session_impl(const char *host, const IPAddress &addr)
                      Definition: SSLClientImpl.cpp:324
                      +
                      Definition: SSLClientImpl.h:45
                      virtual Client & get_arduino_client()=0
                      -
                      Definition: SSLClientImpl.h:40
                      -
                      void m_print_prefix(const char *func_name, const DebugLevel level) const
                      Prints a debugging prefix to all logs, so we can attatch them to useful information.
                      Definition: SSLClientImpl.cpp:639
                      -
                      Definition: SSLClientImpl.h:61
                      -
                      void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
                      Print the text string associated with a BearSSL error code.
                      Definition: SSLClientImpl.cpp:672
                      -
                      void m_warn(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:153
                      +
                      Definition: SSLClientImpl.h:41
                      +
                      void m_print_prefix(const char *func_name, const DebugLevel level) const
                      Prints a debugging prefix to all logs, so we can attatch them to useful information.
                      Definition: SSLClientImpl.cpp:653
                      +
                      Definition: SSLClientImpl.h:62
                      +
                      void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
                      Print the text string associated with a BearSSL error code.
                      Definition: SSLClientImpl.cpp:686
                      +
                      void m_warn(const T str, const char *func_name) const
                      Definition: SSLClientImpl.h:160
                      + -
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:75
                      -
                      Definition: SSLClientImpl.h:50
                      -
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:231
                      -
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:223
                      -
                      Implementation code to be inherited by SSLClient.
                      Definition: SSLClientImpl.h:71
                      +
                      int connect_impl(IPAddress ip, uint16_t port)
                      Definition: SSLClientImpl.cpp:90
                      +
                      Definition: SSLClientImpl.h:51
                      +
                      void stop_impl()
                      Definition: SSLClientImpl.cpp:246
                      +
                      void flush_impl()
                      Definition: SSLClientImpl.cpp:238
                      +
                      Implementation code to be inherited by SSLClient.
                      Definition: SSLClientImpl.h:72
                      virtual uint16_t localPort()=0
                      -
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:263
                      -
                      DebugLevel
                      Level of verbosity used in logging for SSLClient.
                      Definition: SSLClientImpl.h:59
                      +
                      uint8_t connected_impl()
                      Definition: SSLClientImpl.cpp:274
                      +
                      DebugLevel
                      Level of verbosity used in logging for SSLClient.
                      Definition: SSLClientImpl.h:60
                      diff --git a/docs/html/_s_s_l_client_parameters_8h.html b/docs/html/_s_s_l_client_parameters_8h.html new file mode 100644 index 0000000..408fb5b --- /dev/null +++ b/docs/html/_s_s_l_client_parameters_8h.html @@ -0,0 +1,118 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClientParameters.h File Reference + + + + + + + + + + + + + + +
                      +
                      +
                      + + + + + +
                      +
                      SSLClient +  v1.1.1 +
                      +
                      Add TLS 1.2 functionality to any network library.
                      +
                      +
                      + + + + + + + +
                      +
                      + +
                      +
                      +
                      + +
                      + +
                      +
                      + + +
                      + +
                      + +
                      + +
                      +
                      SSLClientParameters.h File Reference
                      +
                      +
                      +
                      #include "bearssl.h"
                      +
                      +

                      Go to the source code of this file.

                      + + + + + +

                      +Classes

                      struct  SSLClientParameters
                       This struct stores data required for SSLClient to use mutual authentication. More...
                       
                      +
                      +
                      + + + + diff --git a/docs/html/_s_s_l_client_parameters_8h_source.html b/docs/html/_s_s_l_client_parameters_8h_source.html new file mode 100644 index 0000000..f1aed41 --- /dev/null +++ b/docs/html/_s_s_l_client_parameters_8h_source.html @@ -0,0 +1,110 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClientParameters.h Source File + + + + + + + + + + + + + + +
                      +
                      + + + + + + +
                      +
                      SSLClient +  v1.1.1 +
                      +
                      Add TLS 1.2 functionality to any network library.
                      +
                      +
                      + + + + + + + +
                      +
                      + +
                      +
                      +
                      + +
                      + +
                      +
                      + + +
                      + +
                      + +
                      +
                      +
                      SSLClientParameters.h
                      +
                      +
                      +Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      28 #include "bearssl.h"
                      29 
                      30 #ifndef SSLClientParameters_H_
                      31 #define SSLClientParameters_H_
                      32 
                      59  const br_x509_certificate* client_cert_chain;
                      61  const size_t chain_len;
                      63  const br_ec_private_key ec_key;
                      64 };
                      65 
                      66 #endif
                      const br_x509_certificate * client_cert_chain
                      Pointer to the client certificate chain.
                      Definition: SSLClientParameters.h:59
                      +
                      This struct stores data required for SSLClient to use mutual authentication.
                      Definition: SSLClientParameters.h:52
                      +
                      const size_t chain_len
                      Definition: SSLClientParameters.h:61
                      +
                      const br_ec_private_key ec_key
                      Definition: SSLClientParameters.h:63
                      +
                      +
                      + + + + diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index 2a0f814..9623d0b 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('_s_s_l_session_8h_source.html','');});
                      SSLSession.h
                      -Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      28 #include "bearssl.h"
                      29 #include "Arduino.h"
                      30 #include "IPAddress.h"
                      31 
                      32 #ifndef SSLSession_H_
                      33 #define SSLSession_H_
                      34 
                      52 class SSLSession : public br_ssl_session_parameters {
                      53 
                      54 public:
                      60  explicit SSLSession()
                      61  : m_valid_session(false)
                      62  , m_hostname()
                      63  , m_ip(INADDR_NONE) {}
                      64 
                      66  SSLSession& operator=(const SSLSession&) = delete;
                      67 
                      76  const String& get_hostname() const { return m_hostname; }
                      77 
                      86  const IPAddress& get_ip() const { return m_ip; }
                      87 
                      88  bool is_valid_session() const { return m_valid_session; }
                      89 
                      109  void set_parameters(const IPAddress& ip, const char* hostname = NULL);
                      110 
                      118  void clear_parameters();
                      119 
                      121  br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; }
                      122 
                      123 private:
                      124  bool m_valid_session;
                      125  // aparently a hostname has a max length of 256 chars. Go figure.
                      126  String m_hostname;
                      127  // store the IP Address we connected to
                      128  IPAddress m_ip;
                      129 };
                      130 
                      131 
                      132 
                      133 #endif /* SSLSession_H_ */
                      This class stores values which allow SSLClient to save and resume SSL sessions.
                      Definition: SSLSession.h:52
                      +Go to the documentation of this file.
                      1 /* Copyright 2019 OSU OPEnS Lab
                      2  *
                      3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
                      4  * software and associated documentation files (the "Software"), to deal in the Software
                      5  * without restriction, including without limitation the rights to use, copy, modify,
                      6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
                      7  * permit persons to whom the Software is furnished to do so, subject to the following
                      8  * conditions:
                      9  *
                      10  * The above copyright notice and this permission notice shall be included in all
                      11  * copies or substantial portions of the Software.
                      12  *
                      13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
                      14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
                      15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
                      16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                      17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                      18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                      19  */
                      20 
                      28 #include "bearssl.h"
                      29 #include "Arduino.h"
                      30 #include "IPAddress.h"
                      31 
                      32 #ifndef SSLSession_H_
                      33 #define SSLSession_H_
                      34 
                      52 class SSLSession : public br_ssl_session_parameters {
                      53 
                      54 public:
                      61  : m_valid_session(false)
                      62  , m_hostname()
                      63  , m_ip(INADDR_NONE) {}
                      64 
                      66  SSLSession& operator=(const SSLSession&) = delete;
                      67 
                      76  const String& get_hostname() const { return m_hostname; }
                      77 
                      86  const IPAddress& get_ip() const { return m_ip; }
                      87 
                      88  bool is_valid_session() const { return m_valid_session; }
                      89 
                      109  void set_parameters(const IPAddress& ip, const char* hostname = NULL);
                      110 
                      118  void clear_parameters();
                      119 
                      121  br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; }
                      122 
                      123 private:
                      124  bool m_valid_session;
                      125  // aparently a hostname has a max length of 256 chars. Go figure.
                      126  String m_hostname;
                      127  // store the IP Address we connected to
                      128  IPAddress m_ip;
                      129 };
                      130 
                      131 
                      132 
                      133 #endif /* SSLSession_H_ */
                      This class stores values which allow SSLClient to save and resume SSL sessions.
                      Definition: SSLSession.h:52
                      br_ssl_session_parameters * to_br_session()
                      Returns a pointer to the ::br_ssl_session_parameters component of this class.
                      Definition: SSLSession.h:121
                      void set_parameters(const IPAddress &ip, const char *hostname=NULL)
                      Set the ip address and hostname of the session.
                      Definition: SSLSession.cpp:4
                      void clear_parameters()
                      Delete the parameters and invalidate the session.
                      Definition: SSLSession.cpp:19
                      diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 10791df..2f4d32a 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -95,7 +95,8 @@ $(document).ready(function(){initNavTree('annotated.html','');}); - + +
                       CSSLClientThe main SSLClient class. Check out README.md for more info
                       CSSLClientImplImplementation code to be inherited by SSLClient
                       CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
                       CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
                       CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
                      diff --git a/docs/html/annotated_dup.js b/docs/html/annotated_dup.js index c7c5acd..1a3e527 100644 --- a/docs/html/annotated_dup.js +++ b/docs/html/annotated_dup.js @@ -2,5 +2,6 @@ var annotated_dup = [ [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ], [ "SSLClientImpl", "class_s_s_l_client_impl.html", "class_s_s_l_client_impl" ], + [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ], [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] ]; \ No newline at end of file diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index b0199db..2685ca5 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -135,7 +135,9 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');}); remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl removeSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inline SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)SSLClient< C, SessionCache >inlineexplicit - SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit + SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClient< C, SessionCache >inlineexplicit + SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit + SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClientImplexplicit stop() overrideSSLClient< C, SessionCache >inline stop_impl()SSLClientImpl write(uint8_t b) overrideSSLClient< C, SessionCache >inline diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 00e645b..b9d4812 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -115,6 +115,8 @@ Public Member Functions  SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)  Initialize SSLClient with all of the prerequisites needed. More...
                        + SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params) +  int connect (IPAddress ip, uint16_t port) override  Connect over SSL to a host specified by an IP address. More...
                        @@ -170,10 +172,10 @@ Public Member Functions  Returns whether or not two SSLClient objects do not have the same underlying client object. More...
                        uint16_t localPort () override - Returns the local port, C::localPort exists. Else return 0. More...
                      + Returns the local port, if C::localPort exists. More...
                        IPAddress remoteIP () override - Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE. More...
                      + Returns the remote IP, if C::remoteIP exists. More...
                        uint16_t remotePort () override  Returns the remote port, if C::remotePort exists. Else return 0. More...
                      @@ -184,6 +186,8 @@ Public Member Functions - Public Member Functions inherited from SSLClientImpl  SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)   + SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params) +  int connect_impl (IPAddress ip, uint16_t port)   int connect_impl (const char *host, uint16_t port) @@ -251,7 +255,7 @@ class SSLClient< C, SessionCache >

                      The main SSLClient class. Check out README.md for more info.

                      Constructor & Destructor Documentation

                      -

                      ◆ SSLClient()

                      +

                      ◆ SSLClient() [1/2]

                      @@ -315,10 +319,74 @@ The analog_pin should be set to input.
  • trust_anchors_numThe number of objects in the trust_anchors array. analog_pinAn analog pin to pull random bytes from, used in seeding the RNG. debugThe level of debug logging (use the DebugLevel enum). + mutual_auth_paramsConfiguration to use for mutual authentication, nullptr to disable mutual auth. (see SSLClientParameters). + + + +

    ◆ SSLClient() [2/2]

    + +
    +
    +
    +template<class C , size_t SessionCache = 1>
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SSLClient< C, SessionCache >::SSLClient (const C & client,
    const br_x509_trust_anchor * trust_anchors,
    const size_t trust_anchors_num,
    const int analog_pin,
    const DebugLevel debug,
    const SSLClientParametersmutual_auth_params 
    )
    +
    +inlineexplicit
    +

    Member Function Documentation

    @@ -791,7 +859,7 @@ template<class C , size_t SessionCache = 1>
    -

    Returns the local port, C::localPort exists. Else return 0.

    +

    Returns the local port, if C::localPort exists.

    Implements SSLClientImpl.

    @@ -1083,7 +1151,7 @@ template<class C , size_t SessionCache = 1>
    -

    Returns the remote IP, if C::remoteIP exists. Else return INADDR_NONE.

    +

    Returns the remote IP, if C::remoteIP exists.

    Implements SSLClientImpl.

    diff --git a/docs/html/class_s_s_l_client.js b/docs/html/class_s_s_l_client.js index 340f3b7..814f6b3 100644 --- a/docs/html/class_s_s_l_client.js +++ b/docs/html/class_s_s_l_client.js @@ -1,6 +1,7 @@ var class_s_s_l_client = [ [ "SSLClient", "class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0", null ], + [ "SSLClient", "class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d", null ], [ "available", "class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e", null ], [ "connect", "class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630", null ], [ "connect", "class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf", null ], diff --git a/docs/html/class_s_s_l_client_impl-members.html b/docs/html/class_s_s_l_client_impl-members.html index 62d86a9..a54731c 100644 --- a/docs/html/class_s_s_l_client_impl-members.html +++ b/docs/html/class_s_s_l_client_impl-members.html @@ -119,8 +119,9 @@ $(document).ready(function(){initNavTree('class_s_s_l_client_impl.html','');}); remotePort()=0SSLClientImplpure virtual remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit - stop_impl()SSLClientImpl - write_impl(const uint8_t *buf, size_t size)SSLClientImpl + SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClientImplexplicit + stop_impl()SSLClientImpl + write_impl(const uint8_t *buf, size_t size)SSLClientImpl
    diff --git a/docs/html/class_s_s_l_client_impl.html b/docs/html/class_s_s_l_client_impl.html index 0cb6b98..bd14620 100644 --- a/docs/html/class_s_s_l_client_impl.html +++ b/docs/html/class_s_s_l_client_impl.html @@ -114,6 +114,8 @@ Inheritance diagram for SSLClientImpl: Public Member Functions  SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)   + SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params) +  int connect_impl (IPAddress ip, uint16_t port)   int connect_impl (const char *host, uint16_t port) @@ -183,7 +185,7 @@ Protected Member Functions

    Implementation code to be inherited by SSLClient.

    Constructor & Destructor Documentation

    -

    ◆ SSLClientImpl()

    +

    ◆ SSLClientImpl() [1/2]

    @@ -229,6 +231,61 @@ Protected Member Functions
    +
    + +

    ◆ SSLClientImpl() [2/2]

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SSLClientImpl::SSLClientImpl (const br_x509_trust_anchor * trust_anchors,
    const size_t trust_anchors_num,
    const int analog_pin,
    const DebugLevel debug,
    const SSLClientParametersmutual_auth_params 
    )
    +
    +explicit
    +

    Member Function Documentation

    @@ -533,7 +590,7 @@ Protected Member Functions
    -
    See also
    SSLClient::localPort
    +
    See also
    SSLClient::localPort

    Implemented in SSLClient< C, SessionCache >.

    @@ -884,7 +941,7 @@ template<typename T >
    -
    See also
    SSLClient::remoteIP
    +
    See also
    SSLClient::remoteIP

    Implemented in SSLClient< C, SessionCache >.

    @@ -912,7 +969,7 @@ template<typename T >
    -
    See also
    SSLClient::localPort
    +
    See also
    SSLClient::localPort

    Implemented in SSLClient< C, SessionCache >.

    diff --git a/docs/html/class_s_s_l_client_impl.js b/docs/html/class_s_s_l_client_impl.js index 6a702fd..a423c6a 100644 --- a/docs/html/class_s_s_l_client_impl.js +++ b/docs/html/class_s_s_l_client_impl.js @@ -1,6 +1,7 @@ var class_s_s_l_client_impl = [ [ "SSLClientImpl", "class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b", null ], + [ "SSLClientImpl", "class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea", null ], [ "available_impl", "class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b", null ], [ "connect_impl", "class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b", null ], [ "connect_impl", "class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba", null ], diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index 79365b7..8512fbe 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -100,7 +100,7 @@ $(document).ready(function(){initNavTree('class_s_s_l_session.html','');}); is_valid_session() constSSLSessioninline operator=(const SSLSession &)=deleteSSLSession set_parameters(const IPAddress &ip, const char *hostname=NULL)SSLSession - SSLSession()SSLSessioninlineexplicit + SSLSession()SSLSessioninline to_br_session()SSLSessioninline
    diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index 777e8e2..bf83f7e 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -156,7 +156,7 @@ Public Member Functions -inlineexplicit +inline
    diff --git a/docs/html/classes.html b/docs/html/classes.html index 8bd69a7..e47714d 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -94,10 +94,10 @@ $(document).ready(function(){initNavTree('classes.html','');}); - - - + + + +
      s  
    -
    SSLClientImpl   SSLSession   
    SSLClient   
    SSLClientImpl   SSLSession   
    SSLClientParameters   
    SSLClient   
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index c2517de..8c0fd50 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -94,12 +94,16 @@ $(document).ready(function(){initNavTree('dir_68267d1309a1af8e8297ef4c3efbcdba.h + + + + diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js index 4896506..703b1e3 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js @@ -1,8 +1,12 @@ var dir_68267d1309a1af8e8297ef4c3efbcdba = [ + [ "ec_prime_fast_256.c", "ec__prime__fast__256_8c.html", "ec__prime__fast__256_8c" ], [ "SSLClient.h", "_s_s_l_client_8h.html", "_s_s_l_client_8h" ], [ "SSLClientImpl.cpp", "_s_s_l_client_impl_8cpp.html", "_s_s_l_client_impl_8cpp" ], [ "SSLClientImpl.h", "_s_s_l_client_impl_8h.html", "_s_s_l_client_impl_8h" ], + [ "SSLClientParameters.h", "_s_s_l_client_parameters_8h.html", [ + [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ] + ] ], [ "SSLSession.cpp", "_s_s_l_session_8cpp.html", null ], [ "SSLSession.h", "_s_s_l_session_8h.html", [ [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] diff --git a/docs/html/ec__prime__fast__256_8c.html b/docs/html/ec__prime__fast__256_8c.html new file mode 100644 index 0000000..e2edbfe --- /dev/null +++ b/docs/html/ec__prime__fast__256_8c.html @@ -0,0 +1,130 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/ec_prime_fast_256.c File Reference + + + + + + + + + + + + + + +
    +
    +

    Files

    file  ec_prime_fast_256.c
     
    file  SSLClient.h [code]
     
    file  SSLClientImpl.cpp
     
    file  SSLClientImpl.h [code]
     
    file  SSLClientParameters.h [code]
     
    file  SSLSession.cpp
     
    file  SSLSession.h [code]
    + + + + + +
    +
    SSLClient +  v1.1.1 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    + + + + + + + + + +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    ec_prime_fast_256.c File Reference
    +
    +
    +
    #include "inner.h"
    +
    + + + +

    +Variables

    const br_ec_impl br_ec_prime_fast_256
     
    +

    Variable Documentation

    + +

    ◆ br_ec_prime_fast_256

    + +
    +
    + + + + +
    const br_ec_impl br_ec_prime_fast_256
    +
    +Initial value:
    = {
    (uint32_t)0x03800000,
    &api_generator,
    &api_order,
    &api_xoff,
    &api_mul,
    &api_mulgen,
    &api_muladd
    }
    +
    +
    +
    +
    + + + + diff --git a/docs/html/ec__prime__fast__256_8c.js b/docs/html/ec__prime__fast__256_8c.js new file mode 100644 index 0000000..633122d --- /dev/null +++ b/docs/html/ec__prime__fast__256_8c.js @@ -0,0 +1,4 @@ +var ec__prime__fast__256_8c = +[ + [ "br_ec_prime_fast_256", "ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab", null ] +]; \ No newline at end of file diff --git a/docs/html/files.html b/docs/html/files.html index dac1fdb..40e5214 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -101,13 +101,15 @@ $(document).ready(function(){initNavTree('files.html','');});   readme  cert.h   src - SSLClient.h - SSLClientImpl.cpp - SSLClientImpl.h - SSLSession.cpp - SSLSession.h - time_macros.h - TLS12_only_profile.c + ec_prime_fast_256.c + SSLClient.h + SSLClientImpl.cpp + SSLClientImpl.h + SSLClientParameters.h + SSLSession.cpp + SSLSession.h + time_macros.h + TLS12_only_profile.c diff --git a/docs/html/functions.html b/docs/html/functions.html index fe84459..b78e046 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -100,14 +100,20 @@ $(document).ready(function(){initNavTree('functions.html','');});

    - c -

    +

    - e -

    + +

    - f -

    diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 7595b1b..bee8ccf 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -98,6 +98,7 @@ $(document).ready(function(){initNavTree('hierarchy.html','');});  CClient  CSSLClientImplImplementation code to be inherited by SSLClient  CSSLClient< C, SessionCache >The main SSLClient class. Check out README.md for more info + CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication diff --git a/docs/html/hierarchy.js b/docs/html/hierarchy.js index 926851d..c7642c5 100644 --- a/docs/html/hierarchy.js +++ b/docs/html/hierarchy.js @@ -7,5 +7,6 @@ var hierarchy = [ "SSLClientImpl", "class_s_s_l_client_impl.html", [ [ "SSLClient< C, SessionCache >", "class_s_s_l_client.html", null ] ] ] - ] ] + ] ], + [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", null ] ]; \ No newline at end of file diff --git a/docs/html/index.html b/docs/html/index.html index 104e104..9411517 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -91,13 +91,15 @@ $(document).ready(function(){initNavTree('index.html','');});
    SSLClient - Arduino Library For SSL
    -

    SSLClient requires at least 110kb flash and 8kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.

    +

    Build Status +

    +

    SSLClient requires at least 110kb flash and 7kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.

    You can also view this README in doxygen.

    SSLClient is a simple library to add TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it.

    Overview

    Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with EthernetClient. There are a few extra things, however, that you will need to get started:

      -
    1. A board with a lot of resources (>110kb flash and >8kb RAM), and a network peripheral with a large internal buffer (>8kb). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Gotchas).
    2. +
    3. A board with a lot of resources (>110kb flash and >7kb RAM), and a network peripheral with a large internal buffer (>7kb). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Gotchas).
    4. A header containing array of trust anchors, which will look like this file. These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out this document on how to generate this file for your project, and for more information about what a trust anchor is.
    5. A Client class associated with a network interface. We tested this library using EthernetClient, however in theory it will work for any class implementing Client.
    6. An analog pin, used for generating random data at the start of the connection (see the Implementation Gotchas).
    7. @@ -159,7 +161,7 @@ $(document).ready(function(){initNavTree('index.html','');});
    8. If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM.
    9. Cipher Support

      -

      By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

      {C++}
      br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
      // comment the above line and uncomment the line below if you're having trouble connecting over SSL
      // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

      to this:

      {C++}
      // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
      // comment the above line and uncomment the line below if you're having trouble connecting over SSL
      br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

      If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the BearSSL profiles documentation and I wish you the best of luck.

      +

      By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

      {C++}
      br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
      // comment the above line and uncomment the line below if you're having trouble connecting over SSL
      // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

      to this:

      {C++}
      // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
      // comment the above line and uncomment the line below if you're having trouble connecting over SSL
      br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

      If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the BearSSL profiles documentation and I wish you the best of luck.

    diff --git a/docs/html/menudata.js b/docs/html/menudata.js index c2595e9..6d24172 100644 --- a/docs/html/menudata.js +++ b/docs/html/menudata.js @@ -32,6 +32,7 @@ var menudata={children:[ {text:"All",url:"functions.html",children:[ {text:"a",url:"functions.html#index_a"}, {text:"c",url:"functions.html#index_c"}, +{text:"e",url:"functions.html#index_e"}, {text:"f",url:"functions.html#index_f"}, {text:"g",url:"functions.html#index_g"}, {text:"i",url:"functions.html#index_i"}, @@ -56,7 +57,8 @@ var menudata={children:[ {text:"r",url:"functions_func.html#index_r"}, {text:"s",url:"functions_func.html#index_s"}, {text:"t",url:"functions_func.html#index_t"}, -{text:"w",url:"functions_func.html#index_w"}]}]}]}, +{text:"w",url:"functions_func.html#index_w"}]}, +{text:"Variables",url:"functions_vars.html"}]}]}, {text:"Files",url:"files.html",children:[ {text:"File List",url:"files.html"}, {text:"File Members",url:"globals.html",children:[ diff --git a/docs/html/navtreedata.js b/docs/html/navtreedata.js index 6bb2dc3..14992b6 100644 --- a/docs/html/navtreedata.js +++ b/docs/html/navtreedata.js @@ -32,7 +32,8 @@ var NAVTREE = [ "Class Hierarchy", "hierarchy.html", "hierarchy" ], [ "Class Members", "functions.html", [ [ "All", "functions.html", null ], - [ "Functions", "functions_func.html", null ] + [ "Functions", "functions_func.html", null ], + [ "Variables", "functions_vars.html", null ] ] ] ] ], [ "Files", "files.html", [ diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index cd95985..dbc5b10 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -1,109 +1,116 @@ var NAVTREEINDEX0 = { -"_s_s_l_client_8h.html":[3,0,2,0], -"_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569":[3,0,2,0,1], -"_s_s_l_client_8h_source.html":[3,0,2,0], -"_s_s_l_client_impl_8cpp.html":[3,0,2,1], -"_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[3,0,2,1,0], -"_s_s_l_client_impl_8h.html":[3,0,2,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5":[3,0,2,2,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c":[3,0,2,2,2,0], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b":[3,0,2,2,2,3], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9":[3,0,2,2,2,4], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b":[3,0,2,2,2,1], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6":[3,0,2,2,2,6], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3":[3,0,2,2,2,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc":[3,0,2,2,2,5], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395":[3,0,2,2,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d":[3,0,2,2,1,2], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91":[3,0,2,2,1,3], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec":[3,0,2,2,1,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f":[3,0,2,2,1,0], -"_s_s_l_client_impl_8h_source.html":[3,0,2,2], -"_s_s_l_session_8cpp.html":[3,0,2,3], -"_s_s_l_session_8h.html":[3,0,2,4], -"_s_s_l_session_8h_source.html":[3,0,2,4], -"_t_l_s12__only__profile_8c.html":[3,0,2,6], -"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[3,0,2,6,0], +"_s_s_l_client_8h.html":[3,0,2,1], +"_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569":[3,0,2,1,1], +"_s_s_l_client_8h_source.html":[3,0,2,1], +"_s_s_l_client_impl_8cpp.html":[3,0,2,2], +"_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[3,0,2,2,0], +"_s_s_l_client_impl_8h.html":[3,0,2,3], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5":[3,0,2,3,2], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c":[3,0,2,3,2,0], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b":[3,0,2,3,2,3], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9":[3,0,2,3,2,4], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b":[3,0,2,3,2,1], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6":[3,0,2,3,2,6], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3":[3,0,2,3,2,2], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc":[3,0,2,3,2,5], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395":[3,0,2,3,1], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d":[3,0,2,3,1,2], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91":[3,0,2,3,1,3], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec":[3,0,2,3,1,1], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f":[3,0,2,3,1,0], +"_s_s_l_client_impl_8h_source.html":[3,0,2,3], +"_s_s_l_client_parameters_8h.html":[3,0,2,4], +"_s_s_l_client_parameters_8h_source.html":[3,0,2,4], +"_s_s_l_session_8cpp.html":[3,0,2,5], +"_s_s_l_session_8h.html":[3,0,2,6], +"_s_s_l_session_8h_source.html":[3,0,2,6], +"_t_l_s12__only__profile_8c.html":[3,0,2,8], +"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[3,0,2,8,0], "annotated.html":[2,0], "cert_8h.html":[3,0,1,0], "cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,1,0,0], "cert_8h_source.html":[3,0,1,0], "class_s_s_l_client.html":[2,0,0], -"class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd":[2,0,0,9], -"class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc":[2,0,0,4], -"class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1":[2,0,0,14], -"class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd":[2,0,0,12], -"class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086":[2,0,0,11], -"class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44":[2,0,0,5], -"class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd":[2,0,0,19], -"class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52":[2,0,0,7], -"class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630":[2,0,0,2], -"class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc":[2,0,0,17], -"class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73":[2,0,0,13], -"class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22":[2,0,0,23], -"class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c":[2,0,0,24], -"class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e":[2,0,0,1], -"class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9":[2,0,0,18], -"class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb":[2,0,0,26], -"class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9":[2,0,0,27], -"class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1":[2,0,0,15], -"class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf":[2,0,0,3], -"class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a":[2,0,0,6], -"class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9":[2,0,0,8], -"class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529":[2,0,0,25], -"class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b":[2,0,0,16], +"class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd":[2,0,0,10], +"class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc":[2,0,0,5], +"class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1":[2,0,0,15], +"class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd":[2,0,0,13], +"class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086":[2,0,0,12], +"class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44":[2,0,0,6], +"class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd":[2,0,0,20], +"class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52":[2,0,0,8], +"class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630":[2,0,0,3], +"class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc":[2,0,0,18], +"class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73":[2,0,0,14], +"class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22":[2,0,0,24], +"class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c":[2,0,0,25], +"class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e":[2,0,0,2], +"class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9":[2,0,0,19], +"class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb":[2,0,0,27], +"class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9":[2,0,0,28], +"class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1":[2,0,0,16], +"class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf":[2,0,0,4], +"class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a":[2,0,0,7], +"class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9":[2,0,0,9], +"class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529":[2,0,0,26], +"class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d":[2,0,0,1], +"class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b":[2,0,0,17], "class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0":[2,0,0,0], -"class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e":[2,0,0,20], -"class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174":[2,0,0,22], -"class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41":[2,0,0,10], -"class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795":[2,0,0,21], +"class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e":[2,0,0,21], +"class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174":[2,0,0,23], +"class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41":[2,0,0,11], +"class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795":[2,0,0,22], "class_s_s_l_client_impl.html":[2,0,1], -"class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d":[2,0,1,20], -"class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3":[2,0,1,6], -"class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788":[2,0,1,5], -"class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe":[2,0,1,21], +"class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d":[2,0,1,21], +"class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3":[2,0,1,7], +"class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788":[2,0,1,6], +"class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe":[2,0,1,22], "class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b":[2,0,1,0], -"class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f":[2,0,1,19], -"class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed":[2,0,1,16], -"class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c":[2,0,1,14], -"class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b":[2,0,1,8], -"class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117":[2,0,1,15], -"class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5":[2,0,1,12], -"class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1":[2,0,1,24], -"class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075":[2,0,1,18], -"class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d":[2,0,1,26], -"class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6":[2,0,1,25], -"class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b":[2,0,1,11], -"class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5":[2,0,1,23], -"class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb":[2,0,1,4], -"class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f":[2,0,1,17], -"class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b":[2,0,1,2], -"class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336":[2,0,1,7], -"class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e":[2,0,1,10], -"class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b":[2,0,1,1], -"class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4":[2,0,1,9], -"class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83":[2,0,1,13], -"class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba":[2,0,1,3], -"class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387":[2,0,1,22], -"class_s_s_l_session.html":[2,0,2], -"class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076":[2,0,2,4], -"class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e":[2,0,2,6], -"class_s_s_l_session.html#a3305941fa615f7134526b718917716ee":[2,0,2,1], -"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[2,0,2,2], -"class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0":[2,0,2,3], -"class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f":[2,0,2,5], -"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[2,0,2,7], -"class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb":[2,0,2,0], +"class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f":[2,0,1,20], +"class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed":[2,0,1,17], +"class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c":[2,0,1,15], +"class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b":[2,0,1,9], +"class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117":[2,0,1,16], +"class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5":[2,0,1,13], +"class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1":[2,0,1,25], +"class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075":[2,0,1,19], +"class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d":[2,0,1,27], +"class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6":[2,0,1,26], +"class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea":[2,0,1,1], +"class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b":[2,0,1,12], +"class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5":[2,0,1,24], +"class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb":[2,0,1,5], +"class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f":[2,0,1,18], +"class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b":[2,0,1,3], +"class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336":[2,0,1,8], +"class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e":[2,0,1,11], +"class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b":[2,0,1,2], +"class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4":[2,0,1,10], +"class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83":[2,0,1,14], +"class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba":[2,0,1,4], +"class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387":[2,0,1,23], +"class_s_s_l_session.html":[2,0,3], +"class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076":[2,0,3,4], +"class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e":[2,0,3,6], +"class_s_s_l_session.html#a3305941fa615f7134526b718917716ee":[2,0,3,1], +"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[2,0,3,2], +"class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0":[2,0,3,3], +"class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f":[2,0,3,5], +"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[2,0,3,7], +"class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb":[2,0,3,0], "classes.html":[2,1], "dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[3,0,0,1], "dir_68267d1309a1af8e8297ef4c3efbcdba.html":[3,0,2], "dir_9c42dc81377249a918256dbb9cfb2167.html":[3,0,0,0], "dir_d28a4824dc47e487b107a5db32ef43c4.html":[3,0,0], "dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[3,0,1], +"ec__prime__fast__256_8c.html":[3,0,2,0], +"ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab":[3,0,2,0,0], "files.html":[3,0], "functions.html":[2,3,0], "functions_func.html":[2,3,1], +"functions_vars.html":[2,3,2], "globals.html":[3,1,0], "globals_defs.html":[3,1,5], "globals_enum.html":[3,1,3], @@ -111,33 +118,37 @@ var NAVTREEINDEX0 = "globals_func.html":[3,1,1], "globals_vars.html":[3,1,2], "hierarchy.html":[2,2], -"index.html":[0], "index.html":[], +"index.html":[0], "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[1], "pages.html":[], -"time__macros_8h.html":[3,0,2,5], -"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,2,5,19], -"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,2,5,14], -"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,2,5,1], -"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,2,5,20], -"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,2,5,16], -"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,2,5,4], -"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,2,5,15], -"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,2,5,13], -"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,2,5,5], -"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,2,5,8], -"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,2,5,0], -"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,2,5,6], -"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,2,5,18], -"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,2,5,12], -"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,2,5,11], -"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,2,5,2], -"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,2,5,7], -"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,2,5,17], -"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,2,5,3], -"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,2,5,9], -"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,2,5,10], -"time__macros_8h_source.html":[3,0,2,5], +"struct_s_s_l_client_parameters.html":[2,0,2], +"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[2,0,2,1], +"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[2,0,2,0], +"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[2,0,2,2], +"time__macros_8h.html":[3,0,2,7], +"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,2,7,19], +"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,2,7,14], +"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,2,7,1], +"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,2,7,20], +"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,2,7,16], +"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,2,7,4], +"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,2,7,15], +"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,2,7,13], +"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,2,7,5], +"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,2,7,8], +"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,2,7,0], +"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,2,7,6], +"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,2,7,18], +"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,2,7,12], +"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,2,7,11], +"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,2,7,2], +"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,2,7,7], +"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,2,7,17], +"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,2,7,3], +"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,2,7,9], +"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,2,7,10], +"time__macros_8h_source.html":[3,0,2,7], "trust__anchors_8h.html":[3,0,0,0,0], "trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,0,0,0], "trust__anchors_8h_source.html":[3,0,0,0,0], diff --git a/docs/html/search/all_2.js b/docs/html/search/all_2.js index 95d65d8..f6e5998 100644 --- a/docs/html/search/all_2.js +++ b/docs/html/search/all_2.js @@ -1,4 +1,5 @@ var searchData= [ - ['br_5fclient_5finit_5ftls12_5fonly',['br_client_init_TLS12_only',['../_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3',1,'TLS12_only_profile.c']]] + ['br_5fclient_5finit_5ftls12_5fonly',['br_client_init_TLS12_only',['../_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3',1,'TLS12_only_profile.c']]], + ['br_5fec_5fprime_5ffast_5f256',['br_ec_prime_fast_256',['../ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab',1,'ec_prime_fast_256.c']]] ]; diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js index 659fa65..e6f18e0 100644 --- a/docs/html/search/all_3.js +++ b/docs/html/search/all_3.js @@ -1,7 +1,9 @@ var searchData= [ ['cert_2eh',['cert.h',['../cert_8h.html',1,'']]], + ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], ['clear_5fparameters',['clear_parameters',['../class_s_s_l_session.html#a3305941fa615f7134526b718917716ee',1,'SSLSession']]], + ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]], ['connect',['connect',['../class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf',1,'SSLClient::connect(const char *host, uint16_t port) override']]], ['connect_5fimpl',['connect_impl',['../class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b',1,'SSLClientImpl::connect_impl(IPAddress ip, uint16_t port)'],['../class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba',1,'SSLClientImpl::connect_impl(const char *host, uint16_t port)']]], ['connected',['connected',['../class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc',1,'SSLClient']]], diff --git a/docs/html/search/all_5.js b/docs/html/search/all_5.js index 212a9a9..e49278d 100644 --- a/docs/html/search/all_5.js +++ b/docs/html/search/all_5.js @@ -1,4 +1,6 @@ var searchData= [ + ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]], + ['ec_5fprime_5ffast_5f256_2ec',['ec_prime_fast_256.c',['../ec__prime__fast__256_8c.html',1,'']]], ['error',['Error',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5',1,'SSLClientImpl.h']]] ]; diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js index f399184..5c98031 100644 --- a/docs/html/search/all_e.js +++ b/docs/html/search/all_e.js @@ -17,12 +17,14 @@ var searchData= ['ssl_5fok',['SSL_OK',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c',1,'SSLClientImpl.h']]], ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6',1,'SSLClientImpl.h']]], ['ssl_5fwarn',['SSL_WARN',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d',1,'SSLClientImpl.h']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient< C, SessionCache >'],['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient()']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient< C, SessionCache >'],['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)'],['../class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], ['sslclient_5fh_5f',['SSLClient_H_',['../_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569',1,'SSLClient.h']]], - ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'SSLClientImpl'],['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl()']]], + ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'SSLClientImpl'],['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)'],['../class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], + ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], + ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession::SSLSession()']]], ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js index 95b55ac..e9cbbc6 100644 --- a/docs/html/search/classes_0.js +++ b/docs/html/search/classes_0.js @@ -2,5 +2,6 @@ var searchData= [ ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'']]], ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'']]], + ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'']]] ]; diff --git a/docs/html/search/files_1.js b/docs/html/search/files_1.js index 66a27ec..c23f9f2 100644 --- a/docs/html/search/files_1.js +++ b/docs/html/search/files_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]] + ['ec_5fprime_5ffast_5f256_2ec',['ec_prime_fast_256.c',['../ec__prime__fast__256_8c.html',1,'']]] ]; diff --git a/docs/html/search/files_2.js b/docs/html/search/files_2.js index 1750530..66a27ec 100644 --- a/docs/html/search/files_2.js +++ b/docs/html/search/files_2.js @@ -1,8 +1,4 @@ var searchData= [ - ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], - ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], - ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], - ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], - ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]] + ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]] ]; diff --git a/docs/html/search/files_3.js b/docs/html/search/files_3.js index a75f15b..1b3b062 100644 --- a/docs/html/search/files_3.js +++ b/docs/html/search/files_3.js @@ -1,8 +1,9 @@ var searchData= [ - ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], - ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], - ['trust_5fanchors_2eh',['trust_anchors.h',['../trust__anchors_8h.html',1,'']]], - ['trustanchors_2eh',['trustanchors.h',['../trustanchors_8h.html',1,'']]], - ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] + ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], + ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], + ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], + ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], + ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], + ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]] ]; diff --git a/docs/html/search/files_4.html b/docs/html/search/files_4.html new file mode 100644 index 0000000..0eaa44a --- /dev/null +++ b/docs/html/search/files_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/files_4.js b/docs/html/search/files_4.js new file mode 100644 index 0000000..a75f15b --- /dev/null +++ b/docs/html/search/files_4.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], + ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], + ['trust_5fanchors_2eh',['trust_anchors.h',['../trust__anchors_8h.html',1,'']]], + ['trustanchors_2eh',['trustanchors.h',['../trustanchors_8h.html',1,'']]], + ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] +]; diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js index ddd85b5..60bd456 100644 --- a/docs/html/search/functions_b.js +++ b/docs/html/search/functions_b.js @@ -1,8 +1,8 @@ var searchData= [ ['set_5fparameters',['set_parameters',['../class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e',1,'SSLSession']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient']]], - ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)'],['../class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], + ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)'],['../class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession']]], ['stop',['stop',['../class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529',1,'SSLClient']]], ['stop_5fimpl',['stop_impl',['../class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6',1,'SSLClientImpl']]] diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js index 26967e0..903807c 100644 --- a/docs/html/search/searchdata.js +++ b/docs/html/search/searchdata.js @@ -2,9 +2,9 @@ var indexSectionsWithContent = { 0: "_abcdefgilmoprstuw", 1: "s", - 2: "crst", + 2: "cerst", 3: "abcfgilmoprstw", - 4: "_", + 4: "_bce", 5: "de", 6: "s", 7: "_cgpstu", diff --git a/docs/html/search/variables_1.js b/docs/html/search/variables_1.js index 89036bd..814f51b 100644 --- a/docs/html/search/variables_1.js +++ b/docs/html/search/variables_1.js @@ -1,17 +1,4 @@ var searchData= [ - ['m_5fanalog_5fpin',['m_analog_pin',['../class_s_s_l_client_impl.html#a9fd03216e71ec0d250b3ed2874f08350',1,'SSLClientImpl']]], - ['m_5fclient',['m_client',['../class_s_s_l_client.html#a3fa6f4acf8149d76dd4fa443df4a2202',1,'SSLClient']]], - ['m_5fdebug',['m_debug',['../class_s_s_l_client_impl.html#a918195d260b3399056bd0477e5249321',1,'SSLClientImpl']]], - ['m_5fhostname',['m_hostname',['../class_s_s_l_session.html#ab5611a1eb7633019a9bfaa7cc86a1645',1,'SSLSession']]], - ['m_5fiobuf',['m_iobuf',['../class_s_s_l_client_impl.html#a6b8064ac811810e00b339f15fbe522c3',1,'SSLClientImpl']]], - ['m_5fip',['m_ip',['../class_s_s_l_session.html#ab080fda0553cff3be60ef134b68ad029',1,'SSLSession']]], - ['m_5fsession_5findex',['m_session_index',['../class_s_s_l_client_impl.html#a7cc5de19274e5ec689017cbb84aa008a',1,'SSLClientImpl']]], - ['m_5fsessions',['m_sessions',['../class_s_s_l_client.html#a680fa57f70d2f3164dd4b117bba8f001',1,'SSLClient']]], - ['m_5fsslctx',['m_sslctx',['../class_s_s_l_client_impl.html#ab6e5219b2edeb01bd949fbb51749adee',1,'SSLClientImpl']]], - ['m_5ftrust_5fanchors',['m_trust_anchors',['../class_s_s_l_client_impl.html#ac84af4c6b35f59642b6814c52cfde5db',1,'SSLClientImpl']]], - ['m_5ftrust_5fanchors_5fnum',['m_trust_anchors_num',['../class_s_s_l_client_impl.html#a4b86754cee9e04742728ca14e1b0db7f',1,'SSLClientImpl']]], - ['m_5fvalid_5fsession',['m_valid_session',['../class_s_s_l_session.html#abfe44b78c7c7d0f83919d6031d1d1857',1,'SSLSession']]], - ['m_5fwrite_5fidx',['m_write_idx',['../class_s_s_l_client_impl.html#a4bdc048774d8be220da7175e1369513f',1,'SSLClientImpl']]], - ['m_5fx509ctx',['m_x509ctx',['../class_s_s_l_client_impl.html#a942c7bd3ebbb03db249096c8bb591b8c',1,'SSLClientImpl']]] + ['br_5fec_5fprime_5ffast_5f256',['br_ec_prime_fast_256',['../ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab',1,'ec_prime_fast_256.c']]] ]; diff --git a/docs/html/search/variables_2.html b/docs/html/search/variables_2.html new file mode 100644 index 0000000..0cb98d3 --- /dev/null +++ b/docs/html/search/variables_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/variables_2.js b/docs/html/search/variables_2.js new file mode 100644 index 0000000..faff15d --- /dev/null +++ b/docs/html/search/variables_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], + ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]] +]; diff --git a/docs/html/search/variables_3.html b/docs/html/search/variables_3.html new file mode 100644 index 0000000..1e83bf5 --- /dev/null +++ b/docs/html/search/variables_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/variables_3.js b/docs/html/search/variables_3.js new file mode 100644 index 0000000..eb3b769 --- /dev/null +++ b/docs/html/search/variables_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]] +]; diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/html/struct_s_s_l_client_parameters-members.html new file mode 100644 index 0000000..3a9f4b6 --- /dev/null +++ b/docs/html/struct_s_s_l_client_parameters-members.html @@ -0,0 +1,111 @@ + + + + + + + +SSLClient: Member List + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.1.1 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    SSLClientParameters Member List
    +
    +
    + +

    This is the complete list of members for SSLClientParameters, including all inherited members.

    + + + + +
    chain_lenSSLClientParameters
    client_cert_chainSSLClientParameters
    ec_keySSLClientParameters
    +
    + + + + diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html new file mode 100644 index 0000000..df4ab25 --- /dev/null +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -0,0 +1,181 @@ + + + + + + + +SSLClient: SSLClientParameters Struct Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.1.1 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    SSLClientParameters Struct Reference
    +
    +
    + +

    This struct stores data required for SSLClient to use mutual authentication. + More...

    + +

    #include <SSLClientParameters.h>

    + + + + + + + + + +

    +Public Attributes

    const br_x509_certificate * client_cert_chain
     Pointer to the client certificate chain. More...
     
    const size_t chain_len
     
    const br_ec_private_key ec_key
     
    +

    Detailed Description

    +

    This struct stores data required for SSLClient to use mutual authentication.

    +

    SSLClientParameters.h

    +

    This file contains a simple utility class to store parameters about an SSL Session for reuse later.This file contains a simple struct to package together all the data required to use client certificate authentication with SSLClient.TLS mutual authentication is a process in which both the server and client perform cryptographic operations to verify the authenticity of eachother, for more information check out this article: https://medium.com/sitewards/the-magic-of-tls-x509-and-mutual-authentication-explained-b2162dec4401 . If this struct is provided to SSLClient::SSLClient, SSLClient will automatically send a client certificate if one is requested by the server. This will happen for all SSLClient connections, and may cause issues for websites that do not need mutual authentication— as a result, please only turn on mutual authentication if you are sure it is neccesary.

    +

    At the moment SSLClient only supports mutual authentication using ECC client certificates.

    +

    Member Data Documentation

    + +

    ◆ chain_len

    + +
    +
    + + + + +
    const size_t SSLClientParameters::chain_len
    +
    +

    The number of certificates in SSLClientParameters::client_cert_chain

    + +
    +
    + +

    ◆ client_cert_chain

    + +
    +
    + + + + +
    const br_x509_certificate* SSLClientParameters::client_cert_chain
    +
    + +

    Pointer to the client certificate chain.

    +

    Must be availible in memory AT ALL TIMES, should not be a local object. Certificates must be ordered from Client->Intermediate->...->Root.

    + +
    +
    + +

    ◆ ec_key

    + +
    +
    + + + + +
    const br_ec_private_key SSLClientParameters::ec_key
    +
    +

    The private key corresponding to the first certificate in SSLClientParameters::client_cert_chain

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/docs/html/struct_s_s_l_client_parameters.js b/docs/html/struct_s_s_l_client_parameters.js new file mode 100644 index 0000000..b5e6dce --- /dev/null +++ b/docs/html/struct_s_s_l_client_parameters.js @@ -0,0 +1,6 @@ +var struct_s_s_l_client_parameters = +[ + [ "chain_len", "struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2", null ], + [ "client_cert_chain", "struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95", null ], + [ "ec_key", "struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449", null ] +]; \ No newline at end of file diff --git a/tools/pycert_bearssl/__pycache__/cert_util.cpython-37.pyc b/tools/pycert_bearssl/__pycache__/cert_util.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea89d36b868c479390e5430355bb49fcd87a5cd3 GIT binary patch literal 7329 zcmai3&vV>Hb_Ot*Um!UoC5n_}uhX`6Esl3Y(T)|{TCZ!VA!Vy9Q7Vy+*H|hja2n)* z!~mm4kN88FtyI~Ss;xvR=a{M-hB>4vw^WWfxb80fA784otYWO!1Y7z&Xd3WW5f7&dKq0d9)5#g`gbU}!Oh5U>25`4$8xPs!7Z4& z-ga%(UUZAsD>EZ5<-JH?CcG%vX`yzJI^#hv9ZjZOtyz{3G|L;x1xEAikJlJF2 z^ZlMLxEK4KpznR*IoD7d#=(yp91Kw-yjC~rrSx-xV;P8;z0-WhdH&qF7Q{T_8x0uM7S5WAO~Va!0uo)Y|D0qcYJI06Hkg>Dm_1LwG+Yi64CJ` zgx-r=QIBJ4nlZf%NzQXMISczdzZXjM) z@kcFVB}Wo}T3T@2{V7rB)vw6G3ig4D;Wd1OMNS_8iTAL3j&D<&#sw551hM=6ZV*k> zNA#{*wtBkMX^IS==`H0%2VmmlVP;dJ;|#uqX#Mt zWser!LSa-z73CNeR9C>SiC=mZg)}nY;>`Hg?3>)=)^|o`uHy|DDfmTTPO-&jxWExpwBf*^C}a}kvF zCajfD-@SK#Lopjx4Nl!!S#=A*h(d@iDj4~L^C6)YL2tFT8Jc(e$U zV!c!*B3St}N?LxDeujt9;JT%dklP~gdEIi0s;65eowjJuYZK>h{$DfvIjKVQVw9&X zF^hYPzLPG}ntlpm|AGf@_6sBPoSA)F76t`bIKcg&cxLsBXe(uQM$e_JG$?0);GT76 zng-q~vYH_p`&PZ5UPg^`W~i2_GlLhd82!T6m;v?Es=hdwq5E%*tia7fOZ>I0aXT}X z0BOW=fOS?F%$^y8xih0*&dQl}SQh_`KE+r1SXucB*0^5s--5l@qzpP;NjL`kU|Ryg z1ZV|nqOXZ{C9b4;kY2Lh~ODu?Q@PDlCpPMHxY<42>vv9 zJ#0yKj{dZr^dhcA!Iev*XPG-spP2L%IBLypk8p1TM7G>Ye55j>{# z6g-STZ_=bb?a@ak54%B37NxjBtEu;BgTc9MCWtb_J!N~XM~mzfUzco`s7EgwSB@x6 zI#lJSNvy`wdX1G-=H?;Sf#cZ1>Wj%mOem(gVKcXTa_{4p|BdVP`duGkDu^awdjWCZ zM0W@K7Lh>TK* z^V$jGU5W+s;_eAZ7)eaxA$aC#8>H)ABrJ6Ugi!QZp0cxBN!vZilcP8u#gXcC0bPFwc>=y6|ZW%$mhljk}ilIQ-ex02b z6s*?JVKl0l61^y=5f@jIEx z?Zbj_Widnl%se!NtNIpIpW9zU=0S-Q*MZk~nOE>v<<5&DIA`kgzpzYT1jHgf(i<5d zH$jX}nDSY3>rYv8SV1BBFeroXRpC#}DL6^rR&YjW!h)6k+idmt{SO)_*FJ18pi<+O zT04H*QwvRr6>S50QL{A=G;yXgmQkY)pNV1g7@3Tx8RcUm`kRmebd!U}1nuMqaib0h zhP5H(ox#dYsy%^4+?f7mq?N+ioq4LmB#! zr-ixmpt&@7+QW3Cs<~b4^FuF6;(hNZ5j?F|@@jw&QQ2c&p-pro{H|+LnHSo@abEJf zU>cqm@b#{ZkRrags0}O?tSQ_bmP8}N(-okT7vNh9@d~`1 zjrw)e+Y|MR@NiV`qP}=u51BSRVNn(jN|~7zvf@E`Pyy0QFADI+7B3%G#b0G5UdgN_ z<0FGSG%#8{{SUQXcU4YIIMq=&(<$&S5t;ug_o;BI0en#MOzpJvn%9&l9jU{=aD_Z- zrDZ)HAxedvXi~Yjg4c>l;F)%a#PYrpG!eZuh7(No8EHx^r$Mf`43IeQrR1ojK?eJQ z(ECOF3@f3+ujb}y5tM)9WA*m%tN)~2>mjlL9q2=p>nNcrU2~_^^Uwuvp3YKYx32ua za$3L5>ebvP|D8`wcxtysFBJ8`uOTzYOFU>LJaA_TNb2NgAAoJ2~$L@Q<7qE@$nSyj;Lma#Kw z!0V8{2wg8Nr_mDAsw$A2NstV~q=z4_!AWIWTaA-8pq#mr`Q`unU# zbe&BD@W0QB+yaPKv#D%)VC$AMvuIoaX=lZ3<_eVf2uabW#?w{wD2{p{$fS`K@ekS5 zpeRdOEt}P0Xngs+MoZxK3v55rkY$X<_8C;wCY{Tw80j3~I8aW@8H_iVjBJiJmkMud zgBmv9d^SH0NiRUcg@gHn3#hw@ZCJi)kZX7WH`2d2A#GtS?czw98hPp9f?OOdLB^%Q zWg7nm+|pRW!i0n?V+ji*37G?JuO3XD>ng|d$Z>zTDW(0>RRrEsgEz7%5YHt(ji)M} z7PCb@t-g5%Zm@=02O8ju6@4rs{C-pZ40F77@J9od6%O7;>nsTA9jw=-%#t&D9pN?? z`P>WTFgcxA%=3=l@rZ|dV-MAgctj{=9`o663W$(MD4(ZTU5 z5qAQAtK!@v0f!EHT47%XLD%EGE;4;Y4v2$r`VoMVv7B%V>dcnHee{U*i(X26@8}R} z!rW1?hX4f05;Cb}IFg`FDT4?)$ulhb@*YyP^{(Gne^=Jqa*=kluh{|6=0400QJS=&YS5JtI!_92FKuMO2} zuKD=k!|mqUxnjQ{#fpTrAg?v)9A?~>TSLDx?^(D7D-iJen z5A=&aAuCL2pnC-L+&LUWI4=(=K-{8kMOuVZd_>PP`dHpm5l!kAnro>(lksRBb%x~O zgg{(JZ{@Uyv4vU-GgGoU!yOk z5LVOYzd@ChqcEzrX%}p(r2i1iRxC=i-mxr;{Qd>&vQ2S-WjZ?fvfdoO{e1j{#0-Cn z1;=t!orQ4~b3w%njwv2tp1O&1RQ2z&pi`&3JUk3g>9C4c#0Augx2d>8#TTj@MNn7_ zxBB3#``h>KBPA9TS&Ls$@f#}Esra0V+f-~&u|frfCF*2LrHLBr3iYJWgoP+t7qsj1 t%BP)#_oCpldAzASREI$od{)J(A>PN|yS8I5*fX|OnZn;MoH^&s{{acqYM1~3 literal 0 HcmV?d00001 diff --git a/tools/pycert_bearssl/cert.cer b/tools/pycert_bearssl/cert.cer new file mode 100644 index 0000000..37b805a --- /dev/null +++ b/tools/pycert_bearssl/cert.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPDCCAiQCCQCzrL/aem1hqTANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCT1IxEjAQBgNVBAcMCUNvcnZhbGxpczESMBAGA1UECgwJT1BF +blMgTGFiMQwwCgYDVQQLDANSJkQxDjAMBgNVBAMMBU9QRW5TMB4XDTE5MDcxODE4 +MzQzM1oXDTIwMDcxNzE4MzQzM1owYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk9S +MRIwEAYDVQQHDAlDb3J2YWxsaXMxEjAQBgNVBAoMCU9QRW5TIExhYjEMMAoGA1UE +CwwDUiZEMQ4wDAYDVQQDDAVPUEVuUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAJQmpP/fydEJL3yh8KdPNmlzuIpINMBjeVgog6zuRlUOrSHlMZx8Ritw +EtkrKfZciNOkEGef0Xn+HGQUBPwZilfEmp9cdaPg9Z1ORX7Vp8CsPIEghv/AR8py +Wg8MTPEde/t1lR1EznuEPkOkiaQrserknOYZPN/jPrqnhgujn3Q2IFhFqO4MId1F +SKdjgTod82wUDHUjnN8kZLUa68mI4UkKyIl+pZxM81MheA4P63x4eFahAzItoGbf +oCrmC6kb9pxjzGpQcyUukHNzfwFLQ/pKP2aXQvv6USt6LB37vqZBRjuaCV36ncGP +r5b7CmOw/1DJ/g6fVsVti/IWa7+eJjECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA +BpB3ljvK1WpKLh0mVHuI6n3TH08kbFSvDw44/SGrWRfMgHGqJOBP2cn1ENKKjQ6N +/fPh6S9i18n4rIP7B1+IphxMlYX8sQU/qIuqcFU8Y++Hsc1UN0SFvEBi3aHLuceN +jShQ9N+VIrk/oAJrrqcqDaeuGBsZdJ158q62lQ3G6bk9te/Ly1YeF/ddOOT4zyQp +VJO5ZlmWstpQIePk1I4ZEhh7TMjm/JjNI8Kn6MZWJw6PE8KodSr6m/YuxJ551pd4 +2u72Ve7UOAAdirVqMvwhKEd50tsaE71PLzyi3cv/A8/i6mHMzI86N1RJlMEbNf1k +VMO9Ofel+PbbwnnNhULR8w== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/tools/pycert_bearssl/certificates.h b/tools/pycert_bearssl/certificates.h new file mode 100644 index 0000000..f271082 --- /dev/null +++ b/tools/pycert_bearssl/certificates.h @@ -0,0 +1,77 @@ +#ifndef _CERTIFICATES_H_ +#define _CERTIFICATES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. + * Certificates are BearSSL br_x509_trust_anchor format. Included certs: + * + * Index: 0 + * Label: GlobalSign + * Subject: OU=GlobalSign Root CA - R2,O=GlobalSign,CN=GlobalSign + * Domain(s): script.google.com + */ + +#define TAs_NUM 1 + +static const unsigned char TA_DN0[] = { + 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x32, + 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, +}; + +static const unsigned char TA_RSA_N0[] = { + 0xa6, 0xcf, 0x24, 0x0e, 0xbe, 0x2e, 0x6f, 0x28, 0x99, 0x45, 0x42, 0xc4, + 0xab, 0x3e, 0x21, 0x54, 0x9b, 0x0b, 0xd3, 0x7f, 0x84, 0x70, 0xfa, 0x12, + 0xb3, 0xcb, 0xbf, 0x87, 0x5f, 0xc6, 0x7f, 0x86, 0xd3, 0xb2, 0x30, 0x5c, + 0xd6, 0xfd, 0xad, 0xf1, 0x7b, 0xdc, 0xe5, 0xf8, 0x60, 0x96, 0x09, 0x92, + 0x10, 0xf5, 0xd0, 0x53, 0xde, 0xfb, 0x7b, 0x7e, 0x73, 0x88, 0xac, 0x52, + 0x88, 0x7b, 0x4a, 0xa6, 0xca, 0x49, 0xa6, 0x5e, 0xa8, 0xa7, 0x8c, 0x5a, + 0x11, 0xbc, 0x7a, 0x82, 0xeb, 0xbe, 0x8c, 0xe9, 0xb3, 0xac, 0x96, 0x25, + 0x07, 0x97, 0x4a, 0x99, 0x2a, 0x07, 0x2f, 0xb4, 0x1e, 0x77, 0xbf, 0x8a, + 0x0f, 0xb5, 0x02, 0x7c, 0x1b, 0x96, 0xb8, 0xc5, 0xb9, 0x3a, 0x2c, 0xbc, + 0xd6, 0x12, 0xb9, 0xeb, 0x59, 0x7d, 0xe2, 0xd0, 0x06, 0x86, 0x5f, 0x5e, + 0x49, 0x6a, 0xb5, 0x39, 0x5e, 0x88, 0x34, 0xec, 0xbc, 0x78, 0x0c, 0x08, + 0x98, 0x84, 0x6c, 0xa8, 0xcd, 0x4b, 0xb4, 0xa0, 0x7d, 0x0c, 0x79, 0x4d, + 0xf0, 0xb8, 0x2d, 0xcb, 0x21, 0xca, 0xd5, 0x6c, 0x5b, 0x7d, 0xe1, 0xa0, + 0x29, 0x84, 0xa1, 0xf9, 0xd3, 0x94, 0x49, 0xcb, 0x24, 0x62, 0x91, 0x20, + 0xbc, 0xdd, 0x0b, 0xd5, 0xd9, 0xcc, 0xf9, 0xea, 0x27, 0x0a, 0x2b, 0x73, + 0x91, 0xc6, 0x9d, 0x1b, 0xac, 0xc8, 0xcb, 0xe8, 0xe0, 0xa0, 0xf4, 0x2f, + 0x90, 0x8b, 0x4d, 0xfb, 0xb0, 0x36, 0x1b, 0xf6, 0x19, 0x7a, 0x85, 0xe0, + 0x6d, 0xf2, 0x61, 0x13, 0x88, 0x5c, 0x9f, 0xe0, 0x93, 0x0a, 0x51, 0x97, + 0x8a, 0x5a, 0xce, 0xaf, 0xab, 0xd5, 0xf7, 0xaa, 0x09, 0xaa, 0x60, 0xbd, + 0xdc, 0xd9, 0x5f, 0xdf, 0x72, 0xa9, 0x60, 0x13, 0x5e, 0x00, 0x01, 0xc9, + 0x4a, 0xfa, 0x3f, 0xa4, 0xea, 0x07, 0x03, 0x21, 0x02, 0x8e, 0x82, 0xca, + 0x03, 0xc2, 0x9b, 0x8f, +}; + +static const unsigned char TA_RSA_E0[] = { + 0x01, 0x00, 0x01, +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef _CERTIFICATES_H_ */ From 43d517c9df5c1f8701cfabc0914070c320765d78 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 5 Aug 2019 21:47:52 -0700 Subject: [PATCH 074/205] remove output files --- .../__pycache__/cert_util.cpython-37.pyc | Bin 7329 -> 0 bytes tools/pycert_bearssl/cert.cer | 20 ----- tools/pycert_bearssl/certificates.h | 77 ------------------ 3 files changed, 97 deletions(-) delete mode 100644 tools/pycert_bearssl/__pycache__/cert_util.cpython-37.pyc delete mode 100644 tools/pycert_bearssl/cert.cer delete mode 100644 tools/pycert_bearssl/certificates.h diff --git a/tools/pycert_bearssl/__pycache__/cert_util.cpython-37.pyc b/tools/pycert_bearssl/__pycache__/cert_util.cpython-37.pyc deleted file mode 100644 index ea89d36b868c479390e5430355bb49fcd87a5cd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7329 zcmai3&vV>Hb_Ot*Um!UoC5n_}uhX`6Esl3Y(T)|{TCZ!VA!Vy9Q7Vy+*H|hja2n)* z!~mm4kN88FtyI~Ss;xvR=a{M-hB>4vw^WWfxb80fA784otYWO!1Y7z&Xd3WW5f7&dKq0d9)5#g`gbU}!Oh5U>25`4$8xPs!7Z4& z-ga%(UUZAsD>EZ5<-JH?CcG%vX`yzJI^#hv9ZjZOtyz{3G|L;x1xEAikJlJF2 z^ZlMLxEK4KpznR*IoD7d#=(yp91Kw-yjC~rrSx-xV;P8;z0-WhdH&qF7Q{T_8x0uM7S5WAO~Va!0uo)Y|D0qcYJI06Hkg>Dm_1LwG+Yi64CJ` zgx-r=QIBJ4nlZf%NzQXMISczdzZXjM) z@kcFVB}Wo}T3T@2{V7rB)vw6G3ig4D;Wd1OMNS_8iTAL3j&D<&#sw551hM=6ZV*k> zNA#{*wtBkMX^IS==`H0%2VmmlVP;dJ;|#uqX#Mt zWser!LSa-z73CNeR9C>SiC=mZg)}nY;>`Hg?3>)=)^|o`uHy|DDfmTTPO-&jxWExpwBf*^C}a}kvF zCajfD-@SK#Lopjx4Nl!!S#=A*h(d@iDj4~L^C6)YL2tFT8Jc(e$U zV!c!*B3St}N?LxDeujt9;JT%dklP~gdEIi0s;65eowjJuYZK>h{$DfvIjKVQVw9&X zF^hYPzLPG}ntlpm|AGf@_6sBPoSA)F76t`bIKcg&cxLsBXe(uQM$e_JG$?0);GT76 zng-q~vYH_p`&PZ5UPg^`W~i2_GlLhd82!T6m;v?Es=hdwq5E%*tia7fOZ>I0aXT}X z0BOW=fOS?F%$^y8xih0*&dQl}SQh_`KE+r1SXucB*0^5s--5l@qzpP;NjL`kU|Ryg z1ZV|nqOXZ{C9b4;kY2Lh~ODu?Q@PDlCpPMHxY<42>vv9 zJ#0yKj{dZr^dhcA!Iev*XPG-spP2L%IBLypk8p1TM7G>Ye55j>{# z6g-STZ_=bb?a@ak54%B37NxjBtEu;BgTc9MCWtb_J!N~XM~mzfUzco`s7EgwSB@x6 zI#lJSNvy`wdX1G-=H?;Sf#cZ1>Wj%mOem(gVKcXTa_{4p|BdVP`duGkDu^awdjWCZ zM0W@K7Lh>TK* z^V$jGU5W+s;_eAZ7)eaxA$aC#8>H)ABrJ6Ugi!QZp0cxBN!vZilcP8u#gXcC0bPFwc>=y6|ZW%$mhljk}ilIQ-ex02b z6s*?JVKl0l61^y=5f@jIEx z?Zbj_Widnl%se!NtNIpIpW9zU=0S-Q*MZk~nOE>v<<5&DIA`kgzpzYT1jHgf(i<5d zH$jX}nDSY3>rYv8SV1BBFeroXRpC#}DL6^rR&YjW!h)6k+idmt{SO)_*FJ18pi<+O zT04H*QwvRr6>S50QL{A=G;yXgmQkY)pNV1g7@3Tx8RcUm`kRmebd!U}1nuMqaib0h zhP5H(ox#dYsy%^4+?f7mq?N+ioq4LmB#! zr-ixmpt&@7+QW3Cs<~b4^FuF6;(hNZ5j?F|@@jw&QQ2c&p-pro{H|+LnHSo@abEJf zU>cqm@b#{ZkRrags0}O?tSQ_bmP8}N(-okT7vNh9@d~`1 zjrw)e+Y|MR@NiV`qP}=u51BSRVNn(jN|~7zvf@E`Pyy0QFADI+7B3%G#b0G5UdgN_ z<0FGSG%#8{{SUQXcU4YIIMq=&(<$&S5t;ug_o;BI0en#MOzpJvn%9&l9jU{=aD_Z- zrDZ)HAxedvXi~Yjg4c>l;F)%a#PYrpG!eZuh7(No8EHx^r$Mf`43IeQrR1ojK?eJQ z(ECOF3@f3+ujb}y5tM)9WA*m%tN)~2>mjlL9q2=p>nNcrU2~_^^Uwuvp3YKYx32ua za$3L5>ebvP|D8`wcxtysFBJ8`uOTzYOFU>LJaA_TNb2NgAAoJ2~$L@Q<7qE@$nSyj;Lma#Kw z!0V8{2wg8Nr_mDAsw$A2NstV~q=z4_!AWIWTaA-8pq#mr`Q`unU# zbe&BD@W0QB+yaPKv#D%)VC$AMvuIoaX=lZ3<_eVf2uabW#?w{wD2{p{$fS`K@ekS5 zpeRdOEt}P0Xngs+MoZxK3v55rkY$X<_8C;wCY{Tw80j3~I8aW@8H_iVjBJiJmkMud zgBmv9d^SH0NiRUcg@gHn3#hw@ZCJi)kZX7WH`2d2A#GtS?czw98hPp9f?OOdLB^%Q zWg7nm+|pRW!i0n?V+ji*37G?JuO3XD>ng|d$Z>zTDW(0>RRrEsgEz7%5YHt(ji)M} z7PCb@t-g5%Zm@=02O8ju6@4rs{C-pZ40F77@J9od6%O7;>nsTA9jw=-%#t&D9pN?? z`P>WTFgcxA%=3=l@rZ|dV-MAgctj{=9`o663W$(MD4(ZTU5 z5qAQAtK!@v0f!EHT47%XLD%EGE;4;Y4v2$r`VoMVv7B%V>dcnHee{U*i(X26@8}R} z!rW1?hX4f05;Cb}IFg`FDT4?)$ulhb@*YyP^{(Gne^=Jqa*=kluh{|6=0400QJS=&YS5JtI!_92FKuMO2} zuKD=k!|mqUxnjQ{#fpTrAg?v)9A?~>TSLDx?^(D7D-iJen z5A=&aAuCL2pnC-L+&LUWI4=(=K-{8kMOuVZd_>PP`dHpm5l!kAnro>(lksRBb%x~O zgg{(JZ{@Uyv4vU-GgGoU!yOk z5LVOYzd@ChqcEzrX%}p(r2i1iRxC=i-mxr;{Qd>&vQ2S-WjZ?fvfdoO{e1j{#0-Cn z1;=t!orQ4~b3w%njwv2tp1O&1RQ2z&pi`&3JUk3g>9C4c#0Augx2d>8#TTj@MNn7_ zxBB3#``h>KBPA9TS&Ls$@f#}Esra0V+f-~&u|frfCF*2LrHLBr3iYJWgoP+t7qsj1 t%BP)#_oCpldAzASREI$od{)J(A>PN|yS8I5*fX|OnZn;MoH^&s{{acqYM1~3 diff --git a/tools/pycert_bearssl/cert.cer b/tools/pycert_bearssl/cert.cer deleted file mode 100644 index 37b805a..0000000 --- a/tools/pycert_bearssl/cert.cer +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDPDCCAiQCCQCzrL/aem1hqTANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJV -UzELMAkGA1UECAwCT1IxEjAQBgNVBAcMCUNvcnZhbGxpczESMBAGA1UECgwJT1BF -blMgTGFiMQwwCgYDVQQLDANSJkQxDjAMBgNVBAMMBU9QRW5TMB4XDTE5MDcxODE4 -MzQzM1oXDTIwMDcxNzE4MzQzM1owYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk9S -MRIwEAYDVQQHDAlDb3J2YWxsaXMxEjAQBgNVBAoMCU9QRW5TIExhYjEMMAoGA1UE -CwwDUiZEMQ4wDAYDVQQDDAVPUEVuUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAJQmpP/fydEJL3yh8KdPNmlzuIpINMBjeVgog6zuRlUOrSHlMZx8Ritw -EtkrKfZciNOkEGef0Xn+HGQUBPwZilfEmp9cdaPg9Z1ORX7Vp8CsPIEghv/AR8py -Wg8MTPEde/t1lR1EznuEPkOkiaQrserknOYZPN/jPrqnhgujn3Q2IFhFqO4MId1F -SKdjgTod82wUDHUjnN8kZLUa68mI4UkKyIl+pZxM81MheA4P63x4eFahAzItoGbf -oCrmC6kb9pxjzGpQcyUukHNzfwFLQ/pKP2aXQvv6USt6LB37vqZBRjuaCV36ncGP -r5b7CmOw/1DJ/g6fVsVti/IWa7+eJjECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA -BpB3ljvK1WpKLh0mVHuI6n3TH08kbFSvDw44/SGrWRfMgHGqJOBP2cn1ENKKjQ6N -/fPh6S9i18n4rIP7B1+IphxMlYX8sQU/qIuqcFU8Y++Hsc1UN0SFvEBi3aHLuceN -jShQ9N+VIrk/oAJrrqcqDaeuGBsZdJ158q62lQ3G6bk9te/Ly1YeF/ddOOT4zyQp -VJO5ZlmWstpQIePk1I4ZEhh7TMjm/JjNI8Kn6MZWJw6PE8KodSr6m/YuxJ551pd4 -2u72Ve7UOAAdirVqMvwhKEd50tsaE71PLzyi3cv/A8/i6mHMzI86N1RJlMEbNf1k -VMO9Ofel+PbbwnnNhULR8w== ------END CERTIFICATE----- \ No newline at end of file diff --git a/tools/pycert_bearssl/certificates.h b/tools/pycert_bearssl/certificates.h deleted file mode 100644 index f271082..0000000 --- a/tools/pycert_bearssl/certificates.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _CERTIFICATES_H_ -#define _CERTIFICATES_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. - * Certificates are BearSSL br_x509_trust_anchor format. Included certs: - * - * Index: 0 - * Label: GlobalSign - * Subject: OU=GlobalSign Root CA - R2,O=GlobalSign,CN=GlobalSign - * Domain(s): script.google.com - */ - -#define TAs_NUM 1 - -static const unsigned char TA_DN0[] = { - 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, - 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, - 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x32, - 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, - 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31, 0x13, 0x30, - 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, - 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, -}; - -static const unsigned char TA_RSA_N0[] = { - 0xa6, 0xcf, 0x24, 0x0e, 0xbe, 0x2e, 0x6f, 0x28, 0x99, 0x45, 0x42, 0xc4, - 0xab, 0x3e, 0x21, 0x54, 0x9b, 0x0b, 0xd3, 0x7f, 0x84, 0x70, 0xfa, 0x12, - 0xb3, 0xcb, 0xbf, 0x87, 0x5f, 0xc6, 0x7f, 0x86, 0xd3, 0xb2, 0x30, 0x5c, - 0xd6, 0xfd, 0xad, 0xf1, 0x7b, 0xdc, 0xe5, 0xf8, 0x60, 0x96, 0x09, 0x92, - 0x10, 0xf5, 0xd0, 0x53, 0xde, 0xfb, 0x7b, 0x7e, 0x73, 0x88, 0xac, 0x52, - 0x88, 0x7b, 0x4a, 0xa6, 0xca, 0x49, 0xa6, 0x5e, 0xa8, 0xa7, 0x8c, 0x5a, - 0x11, 0xbc, 0x7a, 0x82, 0xeb, 0xbe, 0x8c, 0xe9, 0xb3, 0xac, 0x96, 0x25, - 0x07, 0x97, 0x4a, 0x99, 0x2a, 0x07, 0x2f, 0xb4, 0x1e, 0x77, 0xbf, 0x8a, - 0x0f, 0xb5, 0x02, 0x7c, 0x1b, 0x96, 0xb8, 0xc5, 0xb9, 0x3a, 0x2c, 0xbc, - 0xd6, 0x12, 0xb9, 0xeb, 0x59, 0x7d, 0xe2, 0xd0, 0x06, 0x86, 0x5f, 0x5e, - 0x49, 0x6a, 0xb5, 0x39, 0x5e, 0x88, 0x34, 0xec, 0xbc, 0x78, 0x0c, 0x08, - 0x98, 0x84, 0x6c, 0xa8, 0xcd, 0x4b, 0xb4, 0xa0, 0x7d, 0x0c, 0x79, 0x4d, - 0xf0, 0xb8, 0x2d, 0xcb, 0x21, 0xca, 0xd5, 0x6c, 0x5b, 0x7d, 0xe1, 0xa0, - 0x29, 0x84, 0xa1, 0xf9, 0xd3, 0x94, 0x49, 0xcb, 0x24, 0x62, 0x91, 0x20, - 0xbc, 0xdd, 0x0b, 0xd5, 0xd9, 0xcc, 0xf9, 0xea, 0x27, 0x0a, 0x2b, 0x73, - 0x91, 0xc6, 0x9d, 0x1b, 0xac, 0xc8, 0xcb, 0xe8, 0xe0, 0xa0, 0xf4, 0x2f, - 0x90, 0x8b, 0x4d, 0xfb, 0xb0, 0x36, 0x1b, 0xf6, 0x19, 0x7a, 0x85, 0xe0, - 0x6d, 0xf2, 0x61, 0x13, 0x88, 0x5c, 0x9f, 0xe0, 0x93, 0x0a, 0x51, 0x97, - 0x8a, 0x5a, 0xce, 0xaf, 0xab, 0xd5, 0xf7, 0xaa, 0x09, 0xaa, 0x60, 0xbd, - 0xdc, 0xd9, 0x5f, 0xdf, 0x72, 0xa9, 0x60, 0x13, 0x5e, 0x00, 0x01, 0xc9, - 0x4a, 0xfa, 0x3f, 0xa4, 0xea, 0x07, 0x03, 0x21, 0x02, 0x8e, 0x82, 0xca, - 0x03, 0xc2, 0x9b, 0x8f, -}; - -static const unsigned char TA_RSA_E0[] = { - 0x01, 0x00, 0x01, -}; - -static const br_x509_trust_anchor TAs[] = { - { - { (unsigned char *)TA_DN0, sizeof TA_DN0 }, - BR_X509_TA_CA, - { - BR_KEYTYPE_RSA, - { .rsa = { - (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, - (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, - } } - } - }, -}; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ifndef _CERTIFICATES_H_ */ From 2b287f51799de1852f318228fd46eaeb008195c5 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 12 Aug 2019 17:27:14 -0700 Subject: [PATCH 075/205] Rework client certificates, add support for decoding a PEM object --- src/SSLClient.h | 27 ++++++-------------- src/SSLClientImpl.cpp | 31 +++++++++++------------ src/SSLClientImpl.h | 3 ++- src/SSLObj.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++ src/SSLObj.h | 51 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 37 deletions(-) create mode 100644 src/SSLObj.cpp create mode 100644 src/SSLObj.h diff --git a/src/SSLClient.h b/src/SSLClient.h index 215a2b3..6116d61 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -22,6 +22,7 @@ #include "SSLClientImpl.h" #include "SSLSession.h" #include "SSLClientParameters.h" +#include "SSLObj.h" #ifndef SSLClient_H_ #define SSLClient_H_ @@ -81,25 +82,6 @@ public: // SSL Connections take a really long time so we don't want to time out a legitimate thing setTimeout(30 * 1000); } - - /** - * Same as SSLClient::SSLClient(const C &, const br_x509_trust_anchor*, const size_t, const int, const DebugLevel), - * but can compile support for mutual authentication. - */ - explicit SSLClient( const C& client, - const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, - const int analog_pin, - const DebugLevel debug, - const SSLClientParameters* mutual_auth_params) - : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug, mutual_auth_params) - , m_client(client) - , m_sessions{} - { - // set the timeout to a reasonable number (it can always be changes later) - // SSL Connections take a really long time so we don't want to time out a legitimate thing - setTimeout(30 * 1000); - } //======================================== //= Functions implemented in SSLClientImpl @@ -307,6 +289,13 @@ public: //= Functions Not in the Client Interface //======================================== + /** + * @brief Add a client certificate and enable support for mutual auth + * + * This function must be called BEFORE making an SSL connection. + */ + void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); } + /** * @brief Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist * diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 13ed636..eaa94aa 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -69,23 +69,6 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); } -/* see SSLClientImpl.h */ -SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, - const DebugLevel debug, const SSLClientParameters* mutual_auth_params) - : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) { - // if mutual authentication if needed, configure bearssl to support it. - if (mutual_auth_params != nullptr) - br_ssl_client_set_single_ec( &m_sslctx, - mutual_auth_params->client_cert_chain, - mutual_auth_params->chain_len, - &mutual_auth_params->ec_key, - BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, - BR_KEYTYPE_EC, - br_ssl_engine_get_ec(&m_sslctx.eng), - &br_ecdsa_i15_sign_asn1); - } - /* see SSLClientImpl.h*/ int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { const char* func_name = __func__; @@ -331,6 +314,20 @@ void SSLClientImpl::remove_session_impl(const char* host, const IPAddress& addr) } } +/* see SSLClientImpl.h */ +void SSLClientImpl::set_mutual_impl(const SSLClientParameters* params) { + // if mutual authentication if needed, configure bearssl to support it. + if (params != nullptr) + br_ssl_client_set_single_ec( &m_sslctx, + params->client_cert_chain, + params->chain_len, + ¶ms->ec_key, + BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, + BR_KEYTYPE_EC, + br_ssl_engine_get_ec(&m_sslctx.eng), + &br_ecdsa_i15_sign_asn1); +} + bool SSLClientImpl::m_soft_connected(const char* func_name) { // check if the socket is still open and such if (getWriteError()) { diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 01af2f1..931ad77 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -107,7 +107,8 @@ public: SSLSession& get_session_impl(const char* host, const IPAddress& addr); /** @see SSLClient::removeSession */ void remove_session_impl(const char* host, const IPAddress& addr); - + /** @see SSLClient::setMutualAuthParams */ + void set_mutual_impl(const SSLClientParameters* params); //============================================ //= Functions implemented in SSLClient.h //============================================ diff --git a/src/SSLObj.cpp b/src/SSLObj.cpp new file mode 100644 index 0000000..68682ea --- /dev/null +++ b/src/SSLObj.cpp @@ -0,0 +1,57 @@ +#include "SSLObj.h" + +struct ssl_pem_decode_state { + std::vector* vect; + size_t index = 0; +}; + +static void ssl_pem_decode(void *dest_ctx, const void *src, size_t len) { + ssl_pem_decode_state* ctx = static_cast(dest_ctx); + // copy the recieved bytes into the vector, resizing if needed + if (ctx->vect->size() < len + ctx->index) { + Serial.println("Overflow!"); + return; + } + for (size_t i = 0; i < len; i++) (*(ctx->vect))[i + ctx->index] = static_cast(src)[i]; + // update index + ctx->index += len; +} + +const std::vector SSLObj::make_vector_pem(const char* data, const size_t len) { + if (data == nullptr || len == 0) return { 0 }; + // initialize the bearssl PEM context + br_pem_decoder_context pctx; + br_pem_decoder_init(&pctx); + // create a temporary vector + std::vector temp(len * 3 / 4 + 5); + // initialize the DER storage context + ssl_pem_decode_state state; + state.vect = &temp; + state.index = 0; + // set the byte reciever + br_pem_decoder_setdest(&pctx, &ssl_pem_decode, &state); + // start decoding! + int br_state = 0; + size_t index = 0; + do { + index += br_pem_decoder_push(&pctx, static_cast(&data[index]), len - index); + br_state = br_pem_decoder_event(&pctx); + } while (br_state != BR_PEM_ERROR && br_state != BR_PEM_END_OBJ); + // error check + if (br_state == BR_PEM_ERROR) { + // set data to error + temp.clear(); + } + // else we're good! + return { temp }; +} + +const std::vector SSLObj::make_vector_der(const char* data, const size_t len) { + if (data == nullptr || len == 0) return { 0 }; + // create a temporary vector + std::vector temp(len); + // copy the elements over + for (size_t i = 0; i < len; i++) temp[i] = data[i]; + // return the new SSLObj + return { temp }; +} \ No newline at end of file diff --git a/src/SSLObj.h b/src/SSLObj.h new file mode 100644 index 0000000..25e8827 --- /dev/null +++ b/src/SSLObj.h @@ -0,0 +1,51 @@ +/* Copyright 2019 OSU OPEnS Lab + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * SSLObj.h + * + * This file contains a utility class to take PEM input and store it as a DER object + * for later use by BearSSL. + */ + +#include +#include "bearssl_pem.h" +#include "Arduino.h" + +#ifndef SSLObj_H_ +#define SSLObj_H_ + +/** + * \brief This namespace works with raw DER byte arrays for use later with TLS mutual auth. + * + * This namespace was created to store some of the values stored in ::SSLClientParameters, + * which allow BearSSL use client certificates when creating a TLS connection. Since + * most certificates are transmitted over the internet in PEM format, a certificate can + * be provided in PEM or DER format, and will be converted internally to DER format for + * later use. A PEM file provided to this class MUST CONTAIN the `----BEGIN ... -----` + * header in order to be parsed correctly. + */ + +namespace SSLObj { + const std::vector make_vector_pem(const char* data, const size_t len); + const std::vector make_vector_der(const char* data, const size_t len); +} + +#endif \ No newline at end of file From 5e1a3b41ca9ed7ea86064f953e1304d766cc6756 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 13 Aug 2019 12:29:09 -0700 Subject: [PATCH 076/205] fix SSLObj functionality --- src/SSLObj.cpp | 32 ++++++++++++++++++++------------ src/SSLObj.h | 8 +++++--- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/SSLObj.cpp b/src/SSLObj.cpp index 68682ea..73ead13 100644 --- a/src/SSLObj.cpp +++ b/src/SSLObj.cpp @@ -1,5 +1,12 @@ #include "SSLObj.h" +// fix for non-exception arduino platforms +#ifdef ADAFRUIT_FEATHER_M0 +namespace std { + void __throw_length_error(char const*) {} +} +#endif + struct ssl_pem_decode_state { std::vector* vect; size_t index = 0; @@ -7,23 +14,18 @@ struct ssl_pem_decode_state { static void ssl_pem_decode(void *dest_ctx, const void *src, size_t len) { ssl_pem_decode_state* ctx = static_cast(dest_ctx); - // copy the recieved bytes into the vector, resizing if needed - if (ctx->vect->size() < len + ctx->index) { - Serial.println("Overflow!"); - return; - } - for (size_t i = 0; i < len; i++) (*(ctx->vect))[i + ctx->index] = static_cast(src)[i]; + for (size_t i = 0; i < len; i++) ctx->vect->emplace_back(static_cast(src)[i]); // update index ctx->index += len; } const std::vector SSLObj::make_vector_pem(const char* data, const size_t len) { - if (data == nullptr || len == 0) return { 0 }; + if (data == nullptr || len < 80) return {}; // initialize the bearssl PEM context br_pem_decoder_context pctx; br_pem_decoder_init(&pctx); // create a temporary vector - std::vector temp(len * 3 / 4 + 5); + std::vector temp; // initialize the DER storage context ssl_pem_decode_state state; state.vect = &temp; @@ -36,22 +38,28 @@ const std::vector SSLObj::make_vector_pem(const char* data, const do { index += br_pem_decoder_push(&pctx, static_cast(&data[index]), len - index); br_state = br_pem_decoder_event(&pctx); - } while (br_state != BR_PEM_ERROR && br_state != BR_PEM_END_OBJ); + // if we found the begining object, reserve the vector based on the remaining relavent bytes + if (br_state == BR_PEM_BEGIN_OBJ) { + // 22 = five dashes for header and footer + four newlines - character difference between `BEGIN` and `END` + const size_t relavant_bytes_base64 = len - (2*strlen(br_pem_decoder_name(&pctx)) + 22); + temp.reserve(relavant_bytes_base64 * 3 / 4); + } + } while (br_state != BR_PEM_ERROR && br_state != BR_PEM_END_OBJ && len != index); // error check if (br_state == BR_PEM_ERROR) { // set data to error temp.clear(); } // else we're good! - return { temp }; + return temp; } const std::vector SSLObj::make_vector_der(const char* data, const size_t len) { - if (data == nullptr || len == 0) return { 0 }; + if (data == nullptr || len == 0) return {}; // create a temporary vector std::vector temp(len); // copy the elements over for (size_t i = 0; i < len; i++) temp[i] = data[i]; // return the new SSLObj - return { temp }; + return temp; } \ No newline at end of file diff --git a/src/SSLObj.h b/src/SSLObj.h index 25e8827..8d5ecaf 100644 --- a/src/SSLObj.h +++ b/src/SSLObj.h @@ -24,14 +24,16 @@ * This file contains a utility class to take PEM input and store it as a DER object * for later use by BearSSL. */ - -#include +#include #include "bearssl_pem.h" -#include "Arduino.h" #ifndef SSLObj_H_ #define SSLObj_H_ +#undef min +#undef max +#include + /** * \brief This namespace works with raw DER byte arrays for use later with TLS mutual auth. * From c6ac76be2754e4da951c1250b39b88d374ce2b1d Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 14 Aug 2019 11:00:19 -0700 Subject: [PATCH 077/205] small bugfix with flushing behavior --- src/SSLClientImpl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index eaa94aa..a9cf890 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -219,10 +219,8 @@ int SSLClientImpl::peek_impl() { /* see SSLClientImpl.h */ void SSLClientImpl::flush_impl() { - // trigger a flush, incase there's any leftover data - br_ssl_engine_flush(&m_sslctx.eng, 0); - // run until application data is ready for pickup - if(m_run_until(BR_SSL_RECVAPP) < 0) m_error("Could not flush write buffer!", __func__); + if (m_write_idx > 0) + if(m_run_until(BR_SSL_RECVAPP) < 0) m_error("Could not flush write buffer!", __func__); } /* see SSLClientImpl.h */ @@ -524,6 +522,8 @@ unsigned SSLClientImpl::m_update_engine() { // data has been written to the io buffer, something is wrong if (!(state & BR_SSL_SENDAPP)) { m_error("Error m_write_idx > 0 but the ssl engine is not ready for data", func_name); + m_error(br_ssl_engine_current_state(&m_sslctx.eng), func_name); + m_error(br_ssl_engine_last_error(&m_sslctx.eng), func_name); setWriteError(SSL_BR_WRITE_ERROR); stop_impl(); return 0; From c832294902f3e5d8723046accfa67debefc63fdc Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 14 Aug 2019 11:12:06 -0700 Subject: [PATCH 078/205] Remove unnessecary functions in SSLObj, add comments to SSLObj and update docs --- docs/html/_s_s_l_client_8h.html | 1 + docs/html/_s_s_l_client_8h_source.html | 80 ++--- docs/html/_s_s_l_client_impl_8h_source.html | 35 +- docs/html/_s_s_l_obj_8cpp.html | 115 +++++++ docs/html/_s_s_l_obj_8cpp.js | 4 + docs/html/_s_s_l_obj_8h.html | 127 +++++++ docs/html/_s_s_l_obj_8h.js | 4 + docs/html/_s_s_l_obj_8h_source.html | 108 ++++++ docs/html/annotated.html | 9 +- docs/html/annotated_dup.js | 1 + docs/html/class_s_s_l_client-members.html | 17 +- docs/html/class_s_s_l_client.html | 103 +++--- docs/html/class_s_s_l_client.js | 2 +- .../html/class_s_s_l_client_impl-members.html | 9 +- docs/html/class_s_s_l_client_impl.html | 21 ++ docs/html/class_s_s_l_client_impl.js | 1 + docs/html/classes.html | 8 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 4 + .../dir_68267d1309a1af8e8297ef4c3efbcdba.js | 2 + docs/html/files.html | 10 +- docs/html/functions.html | 22 +- docs/html/functions_func.html | 6 + docs/html/functions_vars.html | 6 + docs/html/hierarchy.html | 3 +- docs/html/hierarchy.js | 1 + docs/html/menudata.js | 6 + docs/html/namespace_s_s_l_obj.html | 159 +++++++++ docs/html/namespacemembers.html | 106 ++++++ docs/html/namespacemembers_func.html | 106 ++++++ docs/html/namespaces.html | 110 ++++++ docs/html/namespaces_dup.js | 4 + docs/html/navtreedata.js | 7 + docs/html/navtreeindex0.js | 314 +++++++++--------- docs/html/search/all_11.js | 3 +- docs/html/search/all_12.html | 30 ++ docs/html/search/all_12.js | 5 + docs/html/search/all_8.js | 1 + docs/html/search/all_a.js | 3 +- docs/html/search/all_e.js | 8 +- docs/html/search/classes_0.js | 1 + docs/html/search/files_3.js | 2 + docs/html/search/functions_7.js | 3 +- docs/html/search/functions_b.js | 4 +- docs/html/search/namespaces_0.html | 30 ++ docs/html/search/namespaces_0.js | 4 + docs/html/search/searchdata.js | 47 +-- docs/html/search/variables_4.html | 30 ++ docs/html/search/variables_4.js | 4 + docs/html/search/variables_5.html | 30 ++ docs/html/search/variables_5.js | 4 + ...structssl__pem__decode__state-members.html | 110 ++++++ docs/html/structssl__pem__decode__state.html | 149 +++++++++ docs/html/structssl__pem__decode__state.js | 5 + src/SSLObj.cpp | 14 +- src/SSLObj.h | 16 +- 55 files changed, 1669 insertions(+), 345 deletions(-) create mode 100644 docs/html/_s_s_l_obj_8cpp.html create mode 100644 docs/html/_s_s_l_obj_8cpp.js create mode 100644 docs/html/_s_s_l_obj_8h.html create mode 100644 docs/html/_s_s_l_obj_8h.js create mode 100644 docs/html/_s_s_l_obj_8h_source.html create mode 100644 docs/html/namespace_s_s_l_obj.html create mode 100644 docs/html/namespacemembers.html create mode 100644 docs/html/namespacemembers_func.html create mode 100644 docs/html/namespaces.html create mode 100644 docs/html/namespaces_dup.js create mode 100644 docs/html/search/all_12.html create mode 100644 docs/html/search/all_12.js create mode 100644 docs/html/search/namespaces_0.html create mode 100644 docs/html/search/namespaces_0.js create mode 100644 docs/html/search/variables_4.html create mode 100644 docs/html/search/variables_4.js create mode 100644 docs/html/search/variables_5.html create mode 100644 docs/html/search/variables_5.js create mode 100644 docs/html/structssl__pem__decode__state-members.html create mode 100644 docs/html/structssl__pem__decode__state.html create mode 100644 docs/html/structssl__pem__decode__state.js diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index 945261d..df7d798 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -98,6 +98,7 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h.html','');}); #include "SSLClientImpl.h"
    #include "SSLSession.h"
    #include "SSLClientParameters.h"
    +#include "SSLObj.h"

    Go to the source code of this file.

    diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index 090a4ef..69d4620 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -91,53 +91,55 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
    SSLClient.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLClientImpl.h"
    23 #include "SSLSession.h"
    24 #include "SSLClientParameters.h"
    25 
    26 #ifndef SSLClient_H_
    27 #define SSLClient_H_
    28 
    34 template <class C, size_t SessionCache = 1>
    35 class SSLClient : public SSLClientImpl {
    36 /*
    37  * static checks
    38  * I'm a java developer, so I want to ensure that my inheritance is safe.
    39  * These checks ensure that all the functions we use on class C are
    40  * actually present on class C. It does this by checking that the
    41  * class inherits from Client.
    42  *
    43  * Additionally, I ran into a lot of memory issues with large sessions caches.
    44  * Since each session contains at max 352 bytes of memory, they eat of the
    45  * stack quite quickly and can cause overflows. As a result, I have added a
    46  * warning here to discourage the use of more than 3 sessions at a time. Any
    47  * amount past that will require special modification of this library, and
    48  * assumes you know what you are doing.
    49  */
    50 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
    51 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
    52 
    53 public:
    71  explicit SSLClient( const C& client,
    72  const br_x509_trust_anchor *trust_anchors,
    73  const size_t trust_anchors_num,
    74  const int analog_pin,
    75  const DebugLevel debug = SSL_WARN)
    76  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
    77  , m_client(client)
    78  , m_sessions{}
    79  {
    80  // set the timeout to a reasonable number (it can always be changes later)
    81  // SSL Connections take a really long time so we don't want to time out a legitimate thing
    82  setTimeout(30 * 1000);
    83  }
    84 
    89  explicit SSLClient( const C& client,
    90  const br_x509_trust_anchor *trust_anchors,
    91  const size_t trust_anchors_num,
    92  const int analog_pin,
    93  const DebugLevel debug,
    94  const SSLClientParameters* mutual_auth_params)
    95  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug, mutual_auth_params)
    96  , m_client(client)
    97  , m_sessions{}
    98  {
    99  // set the timeout to a reasonable number (it can always be changes later)
    100  // SSL Connections take a really long time so we don't want to time out a legitimate thing
    101  setTimeout(30 * 1000);
    102  }
    103 
    104  //========================================
    105  //= Functions implemented in SSLClientImpl
    106  //========================================
    107 
    147  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
    148 
    185  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
    186 
    188  size_t write(uint8_t b) override { return write_impl(&b, 1); }
    212  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
    213 
    232  int available() override { return available_impl(); }
    233 
    238  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    260  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
    261 
    270  int peek() override { return peek_impl(); }
    271 
    279  void flush() override { return flush_impl(); }
    280 
    289  void stop() override { return stop_impl(); }
    290 
    304  uint8_t connected() override { return connected_impl(); }
    305 
    306  //========================================
    307  //= Functions Not in the Client Interface
    308  //========================================
    309 
    324  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
    325 
    334  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
    335 
    341  size_t getSessionCount() const override { return SessionCache; }
    342 
    348  operator bool() { return connected() > 0; }
    350  bool operator==(const bool value) { return bool() == value; }
    352  bool operator!=(const bool value) { return bool() != value; }
    354  bool operator==(const C& rhs) { return m_client == rhs; }
    356  bool operator!=(const C& rhs) { return m_client != rhs; }
    358  uint16_t localPort() override { return m_client.localPort(); }
    360  IPAddress remoteIP() override { return m_client.remoteIP(); }
    362  uint16_t remotePort() override { return m_client.remotePort(); }
    363 
    365  C& getClient() { return m_client; }
    366 
    367 protected:
    369  Client& get_arduino_client() override { return m_client; }
    370  const Client& get_arduino_client() const override { return m_client; }
    372  SSLSession* get_session_array() override { return m_sessions; }
    373  const SSLSession* get_session_array() const override { return m_sessions; }
    374 
    375 private:
    376  // create a copy of the client
    377  C m_client;
    378  // also store an array of SSLSessions, so we can resume communication with multiple websites
    379  SSLSession m_sessions[SessionCache];
    380 };
    381 
    382 #endif
    size_t write_impl(const uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:147
    -
    const SSLSession * get_session_array() const override
    Definition: SSLClient.h:373
    -
    IPAddress remoteIP() override
    Returns the remote IP, if C::remoteIP exists.
    Definition: SSLClient.h:360
    -
    size_t write(uint8_t b) override
    Definition: SSLClient.h:188
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLClientImpl.h"
    23 #include "SSLSession.h"
    24 #include "SSLClientParameters.h"
    25 #include "SSLObj.h"
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 template <class C, size_t SessionCache = 1>
    36 class SSLClient : public SSLClientImpl {
    37 /*
    38  * static checks
    39  * I'm a java developer, so I want to ensure that my inheritance is safe.
    40  * These checks ensure that all the functions we use on class C are
    41  * actually present on class C. It does this by checking that the
    42  * class inherits from Client.
    43  *
    44  * Additionally, I ran into a lot of memory issues with large sessions caches.
    45  * Since each session contains at max 352 bytes of memory, they eat of the
    46  * stack quite quickly and can cause overflows. As a result, I have added a
    47  * warning here to discourage the use of more than 3 sessions at a time. Any
    48  * amount past that will require special modification of this library, and
    49  * assumes you know what you are doing.
    50  */
    51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
    52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
    53 
    54 public:
    72  explicit SSLClient( const C& client,
    73  const br_x509_trust_anchor *trust_anchors,
    74  const size_t trust_anchors_num,
    75  const int analog_pin,
    76  const DebugLevel debug = SSL_WARN)
    77  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
    78  , m_client(client)
    79  , m_sessions{}
    80  {
    81  // set the timeout to a reasonable number (it can always be changes later)
    82  // SSL Connections take a really long time so we don't want to time out a legitimate thing
    83  setTimeout(30 * 1000);
    84  }
    85 
    86  //========================================
    87  //= Functions implemented in SSLClientImpl
    88  //========================================
    89 
    129  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
    130 
    167  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
    168 
    170  size_t write(uint8_t b) override { return write_impl(&b, 1); }
    194  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
    195 
    214  int available() override { return available_impl(); }
    215 
    220  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    242  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
    243 
    252  int peek() override { return peek_impl(); }
    253 
    261  void flush() override { return flush_impl(); }
    262 
    271  void stop() override { return stop_impl(); }
    272 
    286  uint8_t connected() override { return connected_impl(); }
    287 
    288  //========================================
    289  //= Functions Not in the Client Interface
    290  //========================================
    291 
    297  void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); }
    298 
    313  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
    314 
    323  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
    324 
    330  size_t getSessionCount() const override { return SessionCache; }
    331 
    337  operator bool() { return connected() > 0; }
    339  bool operator==(const bool value) { return bool() == value; }
    341  bool operator!=(const bool value) { return bool() != value; }
    343  bool operator==(const C& rhs) { return m_client == rhs; }
    345  bool operator!=(const C& rhs) { return m_client != rhs; }
    347  uint16_t localPort() override { return m_client.localPort(); }
    349  IPAddress remoteIP() override { return m_client.remoteIP(); }
    351  uint16_t remotePort() override { return m_client.remotePort(); }
    352 
    354  C& getClient() { return m_client; }
    355 
    356 protected:
    358  Client& get_arduino_client() override { return m_client; }
    359  const Client& get_arduino_client() const override { return m_client; }
    361  SSLSession* get_session_array() override { return m_sessions; }
    362  const SSLSession* get_session_array() const override { return m_sessions; }
    363 
    364 private:
    365  // create a copy of the client
    366  C m_client;
    367  // also store an array of SSLSessions, so we can resume communication with multiple websites
    368  SSLSession m_sessions[SessionCache];
    369 };
    370 
    371 #endif
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.h:297
    +
    size_t write_impl(const uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:130
    +
    const SSLSession * get_session_array() const override
    Definition: SSLClient.h:362
    +
    IPAddress remoteIP() override
    Returns the remote IP, if C::remoteIP exists.
    Definition: SSLClient.h:349
    +
    size_t write(uint8_t b) override
    Definition: SSLClient.h:170
    Definition: SSLClientImpl.h:66
    -
    SSLSession & get_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:305
    +
    SSLSession & get_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:286
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:52
    -
    SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)
    Definition: SSLClient.h:89
    -
    bool operator!=(const C &rhs)
    Returns whether or not two SSLClient objects do not have the same underlying client object.
    Definition: SSLClient.h:356
    -
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.h:232
    -
    C & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:365
    -
    int peek_impl()
    Definition: SSLClientImpl.cpp:226
    +
    bool operator!=(const C &rhs)
    Returns whether or not two SSLClient objects do not have the same underlying client object.
    Definition: SSLClient.h:345
    +
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.h:214
    +
    C & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:354
    +
    int peek_impl()
    Definition: SSLClientImpl.cpp:209
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    -
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.h:279
    -
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    -
    bool operator!=(const bool value)
    Definition: SSLClient.h:352
    -
    void stop() override
    Close the connection.
    Definition: SSLClient.h:289
    -
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.h:212
    -
    SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.h:71
    -
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.h:270
    -
    int available_impl()
    Definition: SSLClientImpl.cpp:190
    -
    bool operator==(const C &rhs)
    Returns whether or not two SSLClient objects have the same underlying client object.
    Definition: SSLClient.h:354
    -
    int read_impl(uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:211
    -
    SSLSession * get_session_array() override
    Returns an instance of the session array that is on the stack.
    Definition: SSLClient.h:372
    -
    void remove_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:324
    -
    Client & get_arduino_client() override
    Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
    Definition: SSLClient.h:369
    -
    uint16_t localPort() override
    Returns the local port, if C::localPort exists.
    Definition: SSLClient.h:358
    +
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.h:261
    +
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:36
    +
    bool operator!=(const bool value)
    Definition: SSLClient.h:341
    +
    void stop() override
    Close the connection.
    Definition: SSLClient.h:271
    +
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.h:194
    +
    SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.h:72
    +
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.h:252
    +
    int available_impl()
    Definition: SSLClientImpl.cpp:173
    +
    bool operator==(const C &rhs)
    Returns whether or not two SSLClient objects have the same underlying client object.
    Definition: SSLClient.h:343
    +
    int read_impl(uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:194
    +
    SSLSession * get_session_array() override
    Returns an instance of the session array that is on the stack.
    Definition: SSLClient.h:361
    +
    void remove_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:305
    +
    Client & get_arduino_client() override
    Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
    Definition: SSLClient.h:358
    +
    uint16_t localPort() override
    Returns the local port, if C::localPort exists.
    Definition: SSLClient.h:347
    -
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:238
    +
    void set_mutual_impl(const SSLClientParameters *params)
    Definition: SSLClientImpl.cpp:316
    +
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:220
    -
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.h:304
    +
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.h:286
    -
    const Client & get_arduino_client() const override
    Definition: SSLClient.h:370
    -
    int connect(const char *host, uint16_t port) override
    Connect over SSL to a host specified by a hostname.
    Definition: SSLClient.h:185
    -
    bool operator==(const bool value)
    Definition: SSLClient.h:350
    -
    uint16_t remotePort() override
    Returns the remote port, if C::remotePort exists. Else return 0.
    Definition: SSLClient.h:362
    -
    int connect_impl(IPAddress ip, uint16_t port)
    Definition: SSLClientImpl.cpp:90
    -
    size_t getSessionCount() const override
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:341
    -
    void stop_impl()
    Definition: SSLClientImpl.cpp:246
    -
    void flush_impl()
    Definition: SSLClientImpl.cpp:238
    +
    const Client & get_arduino_client() const override
    Definition: SSLClient.h:359
    +
    int connect(const char *host, uint16_t port) override
    Connect over SSL to a host specified by a hostname.
    Definition: SSLClient.h:167
    +
    bool operator==(const bool value)
    Definition: SSLClient.h:339
    +
    uint16_t remotePort() override
    Returns the remote port, if C::remotePort exists. Else return 0.
    Definition: SSLClient.h:351
    +
    int connect_impl(IPAddress ip, uint16_t port)
    Definition: SSLClientImpl.cpp:73
    +
    size_t getSessionCount() const override
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:330
    +
    void stop_impl()
    Definition: SSLClientImpl.cpp:227
    +
    void flush_impl()
    Definition: SSLClientImpl.cpp:221
    +
    Implementation code to be inherited by SSLClient.
    Definition: SSLClientImpl.h:72
    -
    void removeSession(const char *host, const IPAddress &addr)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.h:334
    -
    uint8_t connected_impl()
    Definition: SSLClientImpl.cpp:274
    -
    SSLSession & getSession(const char *host, const IPAddress &addr)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.h:324
    +
    void removeSession(const char *host, const IPAddress &addr)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.h:323
    +
    uint8_t connected_impl()
    Definition: SSLClientImpl.cpp:255
    +
    SSLSession & getSession(const char *host, const IPAddress &addr)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.h:313
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClientImpl.h:60
    -
    int read(uint8_t *buf, size_t size) override
    Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
    Definition: SSLClient.h:260
    -
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.h:147
    +
    int read(uint8_t *buf, size_t size) override
    Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
    Definition: SSLClient.h:242
    +
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.h:129
    diff --git a/docs/html/_s_s_l_client_impl_8h_source.html b/docs/html/_s_s_l_client_impl_8h_source.html index 6e50fd6..b7ff5ee 100644 --- a/docs/html/_s_s_l_client_impl_8h_source.html +++ b/docs/html/_s_s_l_client_impl_8h_source.html @@ -91,17 +91,17 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h_source.html','')
    SSLClientImpl.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "bearssl.h"
    22 #include "Arduino.h"
    23 #include "Client.h"
    24 #include "SSLSession.h"
    25 #include "SSLClientParameters.h"
    26 
    27 #ifndef SSLClientImpl_H_
    28 #define SSLClientImpl_H_
    29 
    38 enum Error {
    39  SSL_OK = 0,
    52 };
    53 
    60 enum DebugLevel {
    62  SSL_NONE = 0,
    64  SSL_ERROR = 1,
    66  SSL_WARN = 2,
    68  SSL_INFO = 3,
    69 };
    70 
    72 class SSLClientImpl : public Client {
    73 public:
    75  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
    76  const size_t trust_anchors_num, const int analog_pin,
    77  const DebugLevel debug);
    78 
    80  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
    81  const size_t trust_anchors_num, const int analog_pin,
    82  const DebugLevel debug, const SSLClientParameters* mutual_auth_params);
    83 
    84  //============================================
    85  //= Functions implemented in SSLClientImpl.cpp
    86  //============================================
    87 
    89  int connect_impl(IPAddress ip, uint16_t port);
    91  int connect_impl(const char *host, uint16_t port);
    93  size_t write_impl(const uint8_t *buf, size_t size);
    95  int available_impl();
    97  int read_impl(uint8_t *buf, size_t size);
    99  int peek_impl();
    101  void flush_impl();
    103  void stop_impl();
    105  uint8_t connected_impl();
    107  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
    109  void remove_session_impl(const char* host, const IPAddress& addr);
    110 
    111  //============================================
    112  //= Functions implemented in SSLClient.h
    113  //============================================
    115  virtual uint16_t localPort() = 0;
    117  virtual IPAddress remoteIP() = 0;
    119  virtual uint16_t remotePort() = 0;
    121  virtual size_t getSessionCount() const = 0;
    122 
    123 protected:
    125  virtual Client& get_arduino_client() = 0;
    126  virtual const Client& get_arduino_client() const = 0;
    128  virtual SSLSession* get_session_array() = 0;
    129  virtual const SSLSession* get_session_array() const = 0;
    130 
    131  //============================================
    132  //= Functions implemented in SSLClientImpl.cpp
    133  //============================================
    134 
    136  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    137 
    139  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    140 
    142  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    143 
    145  template<typename T>
    146  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    147  // check the current debug level and serial status
    148  if (level > m_debug || !Serial) return;
    149  // print prefix
    150  m_print_prefix(func_name, level);
    151  // print the message
    152  Serial.println(str);
    153  }
    154 
    156  template<typename T>
    157  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    158 
    159  template<typename T>
    160  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    161 
    162  template<typename T>
    163  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    164 
    165 private:
    167  bool m_soft_connected(const char* func_name);
    169  int m_start_ssl(const char* host, SSLSession& ssl_ses);
    171  int m_run_until(const unsigned target);
    173  unsigned m_update_engine();
    175  int m_get_session_index(const char* host, const IPAddress& addr) const;
    176 
    177  //============================================
    178  //= Data Members
    179  //============================================
    180 
    181  // store the pin to fetch an RNG see from
    182  const int m_analog_pin;
    183  // store an index of where a new session can be placed if we don't have any corresponding sessions
    184  size_t m_session_index;
    185  // store whether to enable debug logging
    186  const DebugLevel m_debug;
    187  // store if we are connected in bearssl or not
    188  bool m_is_connected;
    189  // store the context values required for SSL
    190  br_ssl_client_context m_sslctx;
    191  br_x509_minimal_context m_x509ctx;
    192  // use a mono-directional buffer by default to cut memory in half
    193  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    194  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    195  // simply edit this value to change the buffer size to the desired value
    196  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    197  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    205  unsigned char m_iobuf[2048];
    206  // store the index of where we are writing in the buffer
    207  // so we can send our records all at once to prevent
    208  // weird timing issues
    209  size_t m_write_idx;
    210 };
    211 
    212 #endif /* SSLClientImpl_H_ */
    size_t write_impl(const uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:147
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "bearssl.h"
    22 #include "Arduino.h"
    23 #include "Client.h"
    24 #include "SSLSession.h"
    25 #include "SSLClientParameters.h"
    26 
    27 #ifndef SSLClientImpl_H_
    28 #define SSLClientImpl_H_
    29 
    38 enum Error {
    39  SSL_OK = 0,
    52 };
    53 
    60 enum DebugLevel {
    62  SSL_NONE = 0,
    64  SSL_ERROR = 1,
    66  SSL_WARN = 2,
    68  SSL_INFO = 3,
    69 };
    70 
    72 class SSLClientImpl : public Client {
    73 public:
    75  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
    76  const size_t trust_anchors_num, const int analog_pin,
    77  const DebugLevel debug);
    78 
    80  explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors,
    81  const size_t trust_anchors_num, const int analog_pin,
    82  const DebugLevel debug, const SSLClientParameters* mutual_auth_params);
    83 
    84  //============================================
    85  //= Functions implemented in SSLClientImpl.cpp
    86  //============================================
    87 
    89  int connect_impl(IPAddress ip, uint16_t port);
    91  int connect_impl(const char *host, uint16_t port);
    93  size_t write_impl(const uint8_t *buf, size_t size);
    95  int available_impl();
    97  int read_impl(uint8_t *buf, size_t size);
    99  int peek_impl();
    101  void flush_impl();
    103  void stop_impl();
    105  uint8_t connected_impl();
    107  SSLSession& get_session_impl(const char* host, const IPAddress& addr);
    109  void remove_session_impl(const char* host, const IPAddress& addr);
    111  void set_mutual_impl(const SSLClientParameters* params);
    112  //============================================
    113  //= Functions implemented in SSLClient.h
    114  //============================================
    116  virtual uint16_t localPort() = 0;
    118  virtual IPAddress remoteIP() = 0;
    120  virtual uint16_t remotePort() = 0;
    122  virtual size_t getSessionCount() const = 0;
    123 
    124 protected:
    126  virtual Client& get_arduino_client() = 0;
    127  virtual const Client& get_arduino_client() const = 0;
    129  virtual SSLSession* get_session_array() = 0;
    130  virtual const SSLSession* get_session_array() const = 0;
    131 
    132  //============================================
    133  //= Functions implemented in SSLClientImpl.cpp
    134  //============================================
    135 
    137  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    138 
    140  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    141 
    143  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    144 
    146  template<typename T>
    147  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    148  // check the current debug level and serial status
    149  if (level > m_debug || !Serial) return;
    150  // print prefix
    151  m_print_prefix(func_name, level);
    152  // print the message
    153  Serial.println(str);
    154  }
    155 
    157  template<typename T>
    158  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    159 
    160  template<typename T>
    161  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    162 
    163  template<typename T>
    164  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    165 
    166 private:
    168  bool m_soft_connected(const char* func_name);
    170  int m_start_ssl(const char* host, SSLSession& ssl_ses);
    172  int m_run_until(const unsigned target);
    174  unsigned m_update_engine();
    176  int m_get_session_index(const char* host, const IPAddress& addr) const;
    177 
    178  //============================================
    179  //= Data Members
    180  //============================================
    181 
    182  // store the pin to fetch an RNG see from
    183  const int m_analog_pin;
    184  // store an index of where a new session can be placed if we don't have any corresponding sessions
    185  size_t m_session_index;
    186  // store whether to enable debug logging
    187  const DebugLevel m_debug;
    188  // store if we are connected in bearssl or not
    189  bool m_is_connected;
    190  // store the context values required for SSL
    191  br_ssl_client_context m_sslctx;
    192  br_x509_minimal_context m_x509ctx;
    193  // use a mono-directional buffer by default to cut memory in half
    194  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    195  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    196  // simply edit this value to change the buffer size to the desired value
    197  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    198  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    206  unsigned char m_iobuf[2048];
    207  // store the index of where we are writing in the buffer
    208  // so we can send our records all at once to prevent
    209  // weird timing issues
    210  size_t m_write_idx;
    211 };
    212 
    213 #endif /* SSLClientImpl_H_ */
    size_t write_impl(const uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:130
    virtual uint16_t remotePort()=0
    -
    void m_print(const T str, const char *func_name, const DebugLevel level) const
    debugging print function, only prints if m_debug is true
    Definition: SSLClientImpl.h:146
    +
    void m_print(const T str, const char *func_name, const DebugLevel level) const
    debugging print function, only prints if m_debug is true
    Definition: SSLClientImpl.h:147
    Definition: SSLClientImpl.h:66
    virtual IPAddress remoteIP()=0
    -
    SSLSession & get_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:305
    +
    SSLSession & get_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:286
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:52
    -
    void m_info(const T str, const char *func_name) const
    Prints a info message to serial, if info messages are enabled.
    Definition: SSLClientImpl.h:157
    +
    void m_info(const T str, const char *func_name) const
    Prints a info message to serial, if info messages are enabled.
    Definition: SSLClientImpl.h:158
    SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
    Definition: SSLClientImpl.cpp:53
    -
    void m_error(const T str, const char *func_name) const
    Definition: SSLClientImpl.h:163
    -
    int peek_impl()
    Definition: SSLClientImpl.cpp:226
    +
    void m_error(const T str, const char *func_name) const
    Definition: SSLClientImpl.h:164
    +
    int peek_impl()
    Definition: SSLClientImpl.cpp:209
    Definition: SSLClientImpl.h:68
    Definition: SSLClientImpl.h:64
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    @@ -110,28 +110,29 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8h_source.html','')
    virtual SSLSession * get_session_array()=0
    Definition: SSLClientImpl.h:47
    Definition: SSLClientImpl.h:39
    -
    void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
    Prints the string associated with a write error.
    Definition: SSLClientImpl.cpp:671
    -
    int available_impl()
    Definition: SSLClientImpl.cpp:190
    +
    void m_print_ssl_error(const int ssl_error, const DebugLevel level) const
    Prints the string associated with a write error.
    Definition: SSLClientImpl.cpp:668
    +
    int available_impl()
    Definition: SSLClientImpl.cpp:173
    Error
    Static constants defining the possible errors encountered.
    Definition: SSLClientImpl.h:38
    Definition: SSLClientImpl.h:43
    -
    int read_impl(uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:211
    -
    void remove_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:324
    +
    int read_impl(uint8_t *buf, size_t size)
    Definition: SSLClientImpl.cpp:194
    +
    void remove_session_impl(const char *host, const IPAddress &addr)
    Definition: SSLClientImpl.cpp:305
    Definition: SSLClientImpl.h:45
    virtual Client & get_arduino_client()=0
    Definition: SSLClientImpl.h:41
    -
    void m_print_prefix(const char *func_name, const DebugLevel level) const
    Prints a debugging prefix to all logs, so we can attatch them to useful information.
    Definition: SSLClientImpl.cpp:653
    +
    void m_print_prefix(const char *func_name, const DebugLevel level) const
    Prints a debugging prefix to all logs, so we can attatch them to useful information.
    Definition: SSLClientImpl.cpp:650
    +
    void set_mutual_impl(const SSLClientParameters *params)
    Definition: SSLClientImpl.cpp:316
    Definition: SSLClientImpl.h:62
    -
    void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
    Print the text string associated with a BearSSL error code.
    Definition: SSLClientImpl.cpp:686
    -
    void m_warn(const T str, const char *func_name) const
    Definition: SSLClientImpl.h:160
    +
    void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const
    Print the text string associated with a BearSSL error code.
    Definition: SSLClientImpl.cpp:683
    +
    void m_warn(const T str, const char *func_name) const
    Definition: SSLClientImpl.h:161
    -
    int connect_impl(IPAddress ip, uint16_t port)
    Definition: SSLClientImpl.cpp:90
    +
    int connect_impl(IPAddress ip, uint16_t port)
    Definition: SSLClientImpl.cpp:73
    Definition: SSLClientImpl.h:51
    -
    void stop_impl()
    Definition: SSLClientImpl.cpp:246
    -
    void flush_impl()
    Definition: SSLClientImpl.cpp:238
    +
    void stop_impl()
    Definition: SSLClientImpl.cpp:227
    +
    void flush_impl()
    Definition: SSLClientImpl.cpp:221
    Implementation code to be inherited by SSLClient.
    Definition: SSLClientImpl.h:72
    virtual uint16_t localPort()=0
    -
    uint8_t connected_impl()
    Definition: SSLClientImpl.cpp:274
    +
    uint8_t connected_impl()
    Definition: SSLClientImpl.cpp:255
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClientImpl.h:60
    diff --git a/docs/html/_s_s_l_obj_8cpp.html b/docs/html/_s_s_l_obj_8cpp.html new file mode 100644 index 0000000..b720439 --- /dev/null +++ b/docs/html/_s_s_l_obj_8cpp.html @@ -0,0 +1,115 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLObj.cpp File Reference + + + + + + + + + + + + + + +
    +
    +
    + + + + + +
    +
    SSLClient +  v1.1.1 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    + + + + + + + + + +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    SSLObj.cpp File Reference
    +
    +
    +
    #include "SSLObj.h"
    +
    + + + +

    +Classes

    struct  ssl_pem_decode_state
     
    +
    +
    + + + + diff --git a/docs/html/_s_s_l_obj_8cpp.js b/docs/html/_s_s_l_obj_8cpp.js new file mode 100644 index 0000000..41eb738 --- /dev/null +++ b/docs/html/_s_s_l_obj_8cpp.js @@ -0,0 +1,4 @@ +var _s_s_l_obj_8cpp = +[ + [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", "structssl__pem__decode__state" ] +]; \ No newline at end of file diff --git a/docs/html/_s_s_l_obj_8h.html b/docs/html/_s_s_l_obj_8h.html new file mode 100644 index 0000000..c50d212 --- /dev/null +++ b/docs/html/_s_s_l_obj_8h.html @@ -0,0 +1,127 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLObj.h File Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.1.1 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    SSLObj.h File Reference
    +
    +
    +
    #include <cstring>
    +#include "bearssl_pem.h"
    +#include <vector>
    +
    +

    Go to the source code of this file.

    + + + + + +

    +Namespaces

     SSLObj
     This namespace works with raw DER byte arrays for use later with TLS mutual auth.
     
    + + + + +

    +Functions

    const std::vector< unsigned char > SSLObj::make_vector_pem (const char *data, const size_t len)
     Convert a PEM buffer into a vector of raw DER bytes. More...
     
    +
    +
    + + + + diff --git a/docs/html/_s_s_l_obj_8h.js b/docs/html/_s_s_l_obj_8h.js new file mode 100644 index 0000000..815a655 --- /dev/null +++ b/docs/html/_s_s_l_obj_8h.js @@ -0,0 +1,4 @@ +var _s_s_l_obj_8h = +[ + [ "make_vector_pem", "_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d", null ] +]; \ No newline at end of file diff --git a/docs/html/_s_s_l_obj_8h_source.html b/docs/html/_s_s_l_obj_8h_source.html new file mode 100644 index 0000000..d32ef25 --- /dev/null +++ b/docs/html/_s_s_l_obj_8h_source.html @@ -0,0 +1,108 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLObj.h Source File + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.1.1 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    SSLObj.h
    +
    +
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    27 #include <cstring>
    28 #include "bearssl_pem.h"
    29 
    30 #ifndef SSLObj_H_
    31 #define SSLObj_H_
    32 
    33 #undef min
    34 #undef max
    35 #include <vector>
    36 
    47 namespace SSLObj {
    60  const std::vector<unsigned char> make_vector_pem(const char* data, const size_t len);
    61 }
    62 
    63 #endif
    This namespace works with raw DER byte arrays for use later with TLS mutual auth.
    Definition: SSLObj.h:47
    +
    const std::vector< unsigned char > make_vector_pem(const char *data, const size_t len)
    Convert a PEM buffer into a vector of raw DER bytes.
    Definition: SSLObj.cpp:22
    +
    +
    + + + + diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 2f4d32a..c49db68 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -93,10 +93,11 @@ $(document).ready(function(){initNavTree('annotated.html','');});
    Here are the classes, structs, unions and interfaces with brief descriptions:
    - - - - + + + + +
     CSSLClientThe main SSLClient class. Check out README.md for more info
     CSSLClientImplImplementation code to be inherited by SSLClient
     CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
     CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
     Cssl_pem_decode_state
     CSSLClientThe main SSLClient class. Check out README.md for more info
     CSSLClientImplImplementation code to be inherited by SSLClient
     CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
     CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
    diff --git a/docs/html/annotated_dup.js b/docs/html/annotated_dup.js index 1a3e527..72e17b0 100644 --- a/docs/html/annotated_dup.js +++ b/docs/html/annotated_dup.js @@ -1,5 +1,6 @@ var annotated_dup = [ + [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", "structssl__pem__decode__state" ], [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ], [ "SSLClientImpl", "class_s_s_l_client_impl.html", "class_s_s_l_client_impl" ], [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ], diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 2685ca5..24a725e 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -134,15 +134,16 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');}); remotePort() overrideSSLClient< C, SessionCache >inlinevirtual remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl removeSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inline + set_mutual_impl(const SSLClientParameters *params)SSLClientImpl + setMutualAuthParams(const SSLClientParameters *params)SSLClient< C, SessionCache >inline SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)SSLClient< C, SessionCache >inlineexplicit - SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClient< C, SessionCache >inlineexplicit - SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit - SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClientImplexplicit - stop() overrideSSLClient< C, SessionCache >inline - stop_impl()SSLClientImpl - write(uint8_t b) overrideSSLClient< C, SessionCache >inline - write(const uint8_t *buf, size_t size) overrideSSLClient< C, SessionCache >inline - write_impl(const uint8_t *buf, size_t size)SSLClientImpl + SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit + SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClientImplexplicit + stop() overrideSSLClient< C, SessionCache >inline + stop_impl()SSLClientImpl + write(uint8_t b) overrideSSLClient< C, SessionCache >inline + write(const uint8_t *buf, size_t size) overrideSSLClient< C, SessionCache >inline + write_impl(const uint8_t *buf, size_t size)SSLClientImpl diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index b9d4812..d8df6fe 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -115,8 +115,6 @@ Public Member Functions  SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)  Initialize SSLClient with all of the prerequisites needed. More...
      - SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params) -  int connect (IPAddress ip, uint16_t port) override  Connect over SSL to a host specified by an IP address. More...
      @@ -149,6 +147,9 @@ Public Member Functions uint8_t connected () override  Check if the device is connected. More...
      +void setMutualAuthParams (const SSLClientParameters *params) + Add a client certificate and enable support for mutual auth. More...
    SSLSessiongetSession (const char *host, const IPAddress &addr)  Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
      @@ -210,6 +211,8 @@ Public Member Functions   void remove_session_impl (const char *host, const IPAddress &addr)   +void set_mutual_impl (const SSLClientParameters *params) +  @@ -255,7 +258,7 @@ class SSLClient< C, SessionCache >

    The main SSLClient class. Check out README.md for more info.

    Constructor & Destructor Documentation

    -

    ◆ SSLClient() [1/2]

    +

    ◆ SSLClient()

    @@ -324,69 +327,6 @@ The analog_pin should be set to input. -
    -
    - -

    ◆ SSLClient() [2/2]

    - -
    -
    -
    -template<class C , size_t SessionCache = 1>
    -

    Protected Member Functions

    - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SSLClient< C, SessionCache >::SSLClient (const C & client,
    const br_x509_trust_anchor * trust_anchors,
    const size_t trust_anchors_num,
    const int analog_pin,
    const DebugLevel debug,
    const SSLClientParametersmutual_auth_params 
    )
    -
    -inlineexplicit
    -

    Member Function Documentation

    @@ -1234,6 +1174,37 @@ template<class C , size_t SessionCache = 1> + + + +

    ◆ setMutualAuthParams()

    + +
    +
    +
    +template<class C , size_t SessionCache = 1>
    + + + + + +
    + + + + + + + + +
    void SSLClient< C, SessionCache >::setMutualAuthParams (const SSLClientParametersparams)
    +
    +inline
    +
    + +

    Add a client certificate and enable support for mutual auth.

    +

    This function must be called BEFORE making an SSL connection.

    +
    diff --git a/docs/html/class_s_s_l_client.js b/docs/html/class_s_s_l_client.js index 814f6b3..029693f 100644 --- a/docs/html/class_s_s_l_client.js +++ b/docs/html/class_s_s_l_client.js @@ -1,7 +1,6 @@ var class_s_s_l_client = [ [ "SSLClient", "class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0", null ], - [ "SSLClient", "class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d", null ], [ "available", "class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e", null ], [ "connect", "class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630", null ], [ "connect", "class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf", null ], @@ -26,6 +25,7 @@ var class_s_s_l_client = [ "remoteIP", "class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174", null ], [ "remotePort", "class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22", null ], [ "removeSession", "class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c", null ], + [ "setMutualAuthParams", "class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f", null ], [ "stop", "class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529", null ], [ "write", "class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb", null ], [ "write", "class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9", null ] diff --git a/docs/html/class_s_s_l_client_impl-members.html b/docs/html/class_s_s_l_client_impl-members.html index a54731c..d522108 100644 --- a/docs/html/class_s_s_l_client_impl-members.html +++ b/docs/html/class_s_s_l_client_impl-members.html @@ -118,10 +118,11 @@ $(document).ready(function(){initNavTree('class_s_s_l_client_impl.html','');}); remoteIP()=0SSLClientImplpure virtual remotePort()=0SSLClientImplpure virtual remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl - SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit - SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClientImplexplicit - stop_impl()SSLClientImpl - write_impl(const uint8_t *buf, size_t size)SSLClientImpl + set_mutual_impl(const SSLClientParameters *params)SSLClientImpl + SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit + SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClientImplexplicit + stop_impl()SSLClientImpl + write_impl(const uint8_t *buf, size_t size)SSLClientImpl diff --git a/docs/html/class_s_s_l_client_impl.html b/docs/html/class_s_s_l_client_impl.html index bd14620..ce4a622 100644 --- a/docs/html/class_s_s_l_client_impl.html +++ b/docs/html/class_s_s_l_client_impl.html @@ -138,6 +138,8 @@ Public Member Functions   void remove_session_impl (const char *host, const IPAddress &addr)   +void set_mutual_impl (const SSLClientParameters *params) +  virtual uint16_t localPort ()=0   virtual IPAddress remoteIP ()=0 @@ -1002,6 +1004,25 @@ template<typename T > + + +

    ◆ set_mutual_impl()

    + +
    +
    + + + + + + + + +
    void SSLClientImpl::set_mutual_impl (const SSLClientParametersparams)
    +
    diff --git a/docs/html/class_s_s_l_client_impl.js b/docs/html/class_s_s_l_client_impl.js index a423c6a..d862475 100644 --- a/docs/html/class_s_s_l_client_impl.js +++ b/docs/html/class_s_s_l_client_impl.js @@ -26,6 +26,7 @@ var class_s_s_l_client_impl = [ "remoteIP", "class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387", null ], [ "remotePort", "class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5", null ], [ "remove_session_impl", "class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1", null ], + [ "set_mutual_impl", "class_s_s_l_client_impl.html#a9dd694f8e0e65624b103dc781a7744af", null ], [ "stop_impl", "class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6", null ], [ "write_impl", "class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d", null ] ]; \ No newline at end of file diff --git a/docs/html/classes.html b/docs/html/classes.html index e47714d..c18aed9 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -94,10 +94,10 @@ $(document).ready(function(){initNavTree('classes.html','');}); - - - + + + +
      s  
    -
    SSLClientImpl   SSLSession   
    SSLClientParameters   
    SSLClient   
    SSLClient   SSLClientParameters   
    SSLClientImpl   SSLSession   
    ssl_pem_decode_state   
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 8c0fd50..b4482c9 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -104,6 +104,10 @@ Files   file  SSLClientParameters.h [code]   +file  SSLObj.cpp +  +file  SSLObj.h [code] +  file  SSLSession.cpp   file  SSLSession.h [code] diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js index 703b1e3..6b5c86a 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js @@ -7,6 +7,8 @@ var dir_68267d1309a1af8e8297ef4c3efbcdba = [ "SSLClientParameters.h", "_s_s_l_client_parameters_8h.html", [ [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ] ] ], + [ "SSLObj.cpp", "_s_s_l_obj_8cpp.html", "_s_s_l_obj_8cpp" ], + [ "SSLObj.h", "_s_s_l_obj_8h.html", "_s_s_l_obj_8h" ], [ "SSLSession.cpp", "_s_s_l_session_8cpp.html", null ], [ "SSLSession.h", "_s_s_l_session_8h.html", [ [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] diff --git a/docs/html/files.html b/docs/html/files.html index 40e5214..6f99fdf 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -106,10 +106,12 @@ $(document).ready(function(){initNavTree('files.html','');});  SSLClientImpl.cpp  SSLClientImpl.h  SSLClientParameters.h - SSLSession.cpp - SSLSession.h - time_macros.h - TLS12_only_profile.c + SSLObj.cpp + SSLObj.h + SSLSession.cpp + SSLSession.h + time_macros.h + TLS12_only_profile.c diff --git a/docs/html/functions.html b/docs/html/functions.html index b78e046..549139d 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -113,7 +113,7 @@ $(document).ready(function(){initNavTree('functions.html','');}); : SSLClient< C, SessionCache >
  • connect_impl() -: SSLClientImpl +: SSLClientImpl
  • connected() : SSLClient< C, SessionCache > @@ -144,7 +144,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

    - g -

    • get_arduino_client() : SSLClient< C, SessionCache > -, SSLClientImpl +, SSLClientImpl
    • get_hostname() : SSLSession @@ -153,7 +153,7 @@ $(document).ready(function(){initNavTree('functions.html','');}); : SSLSession
    • get_session_array() -: SSLClient< C, SessionCache > +: SSLClient< C, SessionCache > , SSLClientImpl
    • get_session_impl() @@ -173,6 +173,9 @@ $(document).ready(function(){initNavTree('functions.html','');});

      - i -

        +
      • index +: ssl_pem_decode_state +
      • is_valid_session() : SSLSession
      • @@ -263,9 +266,15 @@ $(document).ready(function(){initNavTree('functions.html','');});

        - s -

        +

        - v -

        + +

        - w -

        • write() : SSLClient< C, SessionCache > diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index 9d99958..f610a78 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -250,9 +250,15 @@ $(document).ready(function(){initNavTree('functions_func.html','');});

          - s -

          diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index bee8ccf..50cd42e 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -98,7 +98,8 @@ $(document).ready(function(){initNavTree('hierarchy.html','');});  CClient  CSSLClientImplImplementation code to be inherited by SSLClient  CSSLClient< C, SessionCache >The main SSLClient class. Check out README.md for more info - CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication + Cssl_pem_decode_state + CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication diff --git a/docs/html/hierarchy.js b/docs/html/hierarchy.js index c7642c5..bfd3475 100644 --- a/docs/html/hierarchy.js +++ b/docs/html/hierarchy.js @@ -8,5 +8,6 @@ var hierarchy = [ "SSLClient< C, SessionCache >", "class_s_s_l_client.html", null ] ] ] ] ], + [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", null ], [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", null ] ]; \ No newline at end of file diff --git a/docs/html/menudata.js b/docs/html/menudata.js index 6d24172..d7d7efc 100644 --- a/docs/html/menudata.js +++ b/docs/html/menudata.js @@ -24,6 +24,11 @@ for the JavaScript code in this file var menudata={children:[ {text:"Main Page",url:"index.html"}, {text:"Related Pages",url:"pages.html"}, +{text:"Namespaces",url:"namespaces.html",children:[ +{text:"Namespace List",url:"namespaces.html"}, +{text:"Namespace Members",url:"namespacemembers.html",children:[ +{text:"All",url:"namespacemembers.html"}, +{text:"Functions",url:"namespacemembers_func.html"}]}]}, {text:"Classes",url:"annotated.html",children:[ {text:"Class List",url:"annotated.html"}, {text:"Class Index",url:"classes.html"}, @@ -43,6 +48,7 @@ var menudata={children:[ {text:"r",url:"functions.html#index_r"}, {text:"s",url:"functions.html#index_s"}, {text:"t",url:"functions.html#index_t"}, +{text:"v",url:"functions.html#index_v"}, {text:"w",url:"functions.html#index_w"}]}, {text:"Functions",url:"functions_func.html",children:[ {text:"a",url:"functions_func.html#index_a"}, diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/html/namespace_s_s_l_obj.html new file mode 100644 index 0000000..f347e91 --- /dev/null +++ b/docs/html/namespace_s_s_l_obj.html @@ -0,0 +1,159 @@ + + + + + + + +SSLClient: SSLObj Namespace Reference + + + + + + + + + + + + + + +
          +
          + + + + + + +
          +
          SSLClient +  v1.1.1 +
          +
          Add TLS 1.2 functionality to any network library.
          +
          +
          + + + + + + + +
          +
          + +
          +
          +
          + +
          + +
          +
          + + +
          + +
          + +
          + +
          +
          SSLObj Namespace Reference
          +
          +
          + +

          This namespace works with raw DER byte arrays for use later with TLS mutual auth. +More...

          + + + + + +

          +Functions

          const std::vector< unsigned char > make_vector_pem (const char *data, const size_t len)
           Convert a PEM buffer into a vector of raw DER bytes. More...
           
          +

          Detailed Description

          +

          This namespace works with raw DER byte arrays for use later with TLS mutual auth.

          +

          SSLObj.h

          +

          This file contains a utility class to take PEM input and store it as a DER object for later use by BearSSL.This namespace was created to store some of the values stored in SSLClientParameters, which allow BearSSL use client certificates when creating a TLS connection. Since most certificates are transmitted over the internet in PEM format, a certificate can be provided in PEM or DER format, and will be converted internally to DER format for later use.

          +

          Function Documentation

          + +

          ◆ make_vector_pem()

          + +
          +
          + + + + + + + + + + + + + + + + + + +
          const std::vector< unsigned char > SSLObj::make_vector_pem (const char * data,
          const size_t len 
          )
          +
          + +

          Convert a PEM buffer into a vector of raw DER bytes.

          +

          This function takes a PEM buffer (e.g. ----BEGIN CERTIFICATE...) and converts it into a vector of raw bytes. The bytes given to this function must:

            +
          • Contain both the -----BEGIN XXX----- and -----END XXX----- strings. These are removed during processing.
          • +
          • Have a base64 encoded body
          • +
          • Only contain a single object (certificate, private key, etc.).
          • +
          +
          Returns
          The raw bytes decoded from the PEM file.
          + +
          +
          +
          +
          + + + + diff --git a/docs/html/namespacemembers.html b/docs/html/namespacemembers.html new file mode 100644 index 0000000..5b0684e --- /dev/null +++ b/docs/html/namespacemembers.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: Namespace Members + + + + + + + + + + + + + + +
          +
          + + + + + + +
          +
          SSLClient +  v1.1.1 +
          +
          Add TLS 1.2 functionality to any network library.
          +
          +
          + + + + + + + +
          +
          + +
          +
          +
          + +
          + +
          +
          + + +
          + +
          + +
          +
          Here is a list of all namespace members with links to the namespace documentation for each member:
            +
          • make_vector_pem() +: SSLObj +
          • +
          +
          +
          + + + + diff --git a/docs/html/namespacemembers_func.html b/docs/html/namespacemembers_func.html new file mode 100644 index 0000000..3b56928 --- /dev/null +++ b/docs/html/namespacemembers_func.html @@ -0,0 +1,106 @@ + + + + + + + +SSLClient: Namespace Members + + + + + + + + + + + + + + +
          +
          + + + + + + +
          +
          SSLClient +  v1.1.1 +
          +
          Add TLS 1.2 functionality to any network library.
          +
          +
          + + + + + + + +
          +
          + +
          +
          +
          + +
          + +
          +
          + + +
          + +
          + +
            +
          • make_vector_pem() +: SSLObj +
          • +
          +
          +
          + + + + diff --git a/docs/html/namespaces.html b/docs/html/namespaces.html new file mode 100644 index 0000000..5dde767 --- /dev/null +++ b/docs/html/namespaces.html @@ -0,0 +1,110 @@ + + + + + + + +SSLClient: Namespace List + + + + + + + + + + + + + + +
          +
          + + + + + + +
          +
          SSLClient +  v1.1.1 +
          +
          Add TLS 1.2 functionality to any network library.
          +
          +
          + + + + + + + +
          +
          + +
          +
          +
          + +
          + +
          +
          + + +
          + +
          + +
          +
          +
          Namespace List
          +
          +
          +
          Here is a list of all namespaces with brief descriptions:
          + + +
           NSSLObjThis namespace works with raw DER byte arrays for use later with TLS mutual auth
          +
          +
          +
          + + + + diff --git a/docs/html/namespaces_dup.js b/docs/html/namespaces_dup.js new file mode 100644 index 0000000..edcae9b --- /dev/null +++ b/docs/html/namespaces_dup.js @@ -0,0 +1,4 @@ +var namespaces_dup = +[ + [ "SSLObj", "namespace_s_s_l_obj.html", null ] +]; \ No newline at end of file diff --git a/docs/html/navtreedata.js b/docs/html/navtreedata.js index 14992b6..c0fedb9 100644 --- a/docs/html/navtreedata.js +++ b/docs/html/navtreedata.js @@ -26,6 +26,13 @@ var NAVTREE = [ "SSLClient", "index.html", [ [ "SSLClient - Arduino Library For SSL", "index.html", null ], [ "Trust Anchors", "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html", null ], + [ "Namespaces", "namespaces.html", [ + [ "Namespace List", "namespaces.html", "namespaces_dup" ], + [ "Namespace Members", "namespacemembers.html", [ + [ "All", "namespacemembers.html", null ], + [ "Functions", "namespacemembers_func.html", null ] + ] ] + ] ], [ "Classes", "annotated.html", [ [ "Class List", "annotated.html", "annotated_dup" ], [ "Class Index", "classes.html", null ], diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index dbc5b10..e9bd31d 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -1,158 +1,170 @@ var NAVTREEINDEX0 = { -"_s_s_l_client_8h.html":[3,0,2,1], -"_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569":[3,0,2,1,1], -"_s_s_l_client_8h_source.html":[3,0,2,1], -"_s_s_l_client_impl_8cpp.html":[3,0,2,2], -"_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[3,0,2,2,0], -"_s_s_l_client_impl_8h.html":[3,0,2,3], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5":[3,0,2,3,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c":[3,0,2,3,2,0], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b":[3,0,2,3,2,3], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9":[3,0,2,3,2,4], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b":[3,0,2,3,2,1], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6":[3,0,2,3,2,6], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3":[3,0,2,3,2,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc":[3,0,2,3,2,5], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395":[3,0,2,3,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d":[3,0,2,3,1,2], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91":[3,0,2,3,1,3], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec":[3,0,2,3,1,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f":[3,0,2,3,1,0], -"_s_s_l_client_impl_8h_source.html":[3,0,2,3], -"_s_s_l_client_parameters_8h.html":[3,0,2,4], -"_s_s_l_client_parameters_8h_source.html":[3,0,2,4], -"_s_s_l_session_8cpp.html":[3,0,2,5], -"_s_s_l_session_8h.html":[3,0,2,6], -"_s_s_l_session_8h_source.html":[3,0,2,6], -"_t_l_s12__only__profile_8c.html":[3,0,2,8], -"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[3,0,2,8,0], -"annotated.html":[2,0], -"cert_8h.html":[3,0,1,0], -"cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,1,0,0], -"cert_8h_source.html":[3,0,1,0], -"class_s_s_l_client.html":[2,0,0], -"class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd":[2,0,0,10], -"class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc":[2,0,0,5], -"class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1":[2,0,0,15], -"class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd":[2,0,0,13], -"class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086":[2,0,0,12], -"class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44":[2,0,0,6], -"class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd":[2,0,0,20], -"class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52":[2,0,0,8], -"class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630":[2,0,0,3], -"class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc":[2,0,0,18], -"class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73":[2,0,0,14], -"class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22":[2,0,0,24], -"class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c":[2,0,0,25], -"class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e":[2,0,0,2], -"class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9":[2,0,0,19], -"class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb":[2,0,0,27], -"class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9":[2,0,0,28], -"class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1":[2,0,0,16], -"class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf":[2,0,0,4], -"class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a":[2,0,0,7], -"class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9":[2,0,0,9], -"class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529":[2,0,0,26], -"class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d":[2,0,0,1], -"class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b":[2,0,0,17], -"class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0":[2,0,0,0], -"class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e":[2,0,0,21], -"class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174":[2,0,0,23], -"class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41":[2,0,0,11], -"class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795":[2,0,0,22], -"class_s_s_l_client_impl.html":[2,0,1], -"class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d":[2,0,1,21], -"class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3":[2,0,1,7], -"class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788":[2,0,1,6], -"class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe":[2,0,1,22], -"class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b":[2,0,1,0], -"class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f":[2,0,1,20], -"class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed":[2,0,1,17], -"class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c":[2,0,1,15], -"class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b":[2,0,1,9], -"class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117":[2,0,1,16], -"class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5":[2,0,1,13], -"class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1":[2,0,1,25], -"class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075":[2,0,1,19], -"class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d":[2,0,1,27], -"class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6":[2,0,1,26], -"class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea":[2,0,1,1], -"class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b":[2,0,1,12], -"class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5":[2,0,1,24], -"class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb":[2,0,1,5], -"class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f":[2,0,1,18], -"class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b":[2,0,1,3], -"class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336":[2,0,1,8], -"class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e":[2,0,1,11], -"class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b":[2,0,1,2], -"class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4":[2,0,1,10], -"class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83":[2,0,1,14], -"class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba":[2,0,1,4], -"class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387":[2,0,1,23], -"class_s_s_l_session.html":[2,0,3], -"class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076":[2,0,3,4], -"class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e":[2,0,3,6], -"class_s_s_l_session.html#a3305941fa615f7134526b718917716ee":[2,0,3,1], -"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[2,0,3,2], -"class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0":[2,0,3,3], -"class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f":[2,0,3,5], -"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[2,0,3,7], -"class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb":[2,0,3,0], -"classes.html":[2,1], -"dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[3,0,0,1], -"dir_68267d1309a1af8e8297ef4c3efbcdba.html":[3,0,2], -"dir_9c42dc81377249a918256dbb9cfb2167.html":[3,0,0,0], -"dir_d28a4824dc47e487b107a5db32ef43c4.html":[3,0,0], -"dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[3,0,1], -"ec__prime__fast__256_8c.html":[3,0,2,0], -"ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab":[3,0,2,0,0], -"files.html":[3,0], -"functions.html":[2,3,0], -"functions_func.html":[2,3,1], -"functions_vars.html":[2,3,2], -"globals.html":[3,1,0], -"globals_defs.html":[3,1,5], -"globals_enum.html":[3,1,3], -"globals_eval.html":[3,1,4], -"globals_func.html":[3,1,1], -"globals_vars.html":[3,1,2], -"hierarchy.html":[2,2], +"_s_s_l_client_8h.html":[4,0,2,1], +"_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569":[4,0,2,1,1], +"_s_s_l_client_8h_source.html":[4,0,2,1], +"_s_s_l_client_impl_8cpp.html":[4,0,2,2], +"_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[4,0,2,2,0], +"_s_s_l_client_impl_8h.html":[4,0,2,3], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5":[4,0,2,3,2], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c":[4,0,2,3,2,0], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b":[4,0,2,3,2,3], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9":[4,0,2,3,2,4], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b":[4,0,2,3,2,1], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6":[4,0,2,3,2,6], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3":[4,0,2,3,2,2], +"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc":[4,0,2,3,2,5], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395":[4,0,2,3,1], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d":[4,0,2,3,1,2], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91":[4,0,2,3,1,3], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec":[4,0,2,3,1,1], +"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f":[4,0,2,3,1,0], +"_s_s_l_client_impl_8h_source.html":[4,0,2,3], +"_s_s_l_client_parameters_8h.html":[4,0,2,4], +"_s_s_l_client_parameters_8h_source.html":[4,0,2,4], +"_s_s_l_obj_8cpp.html":[4,0,2,5], +"_s_s_l_obj_8h.html":[4,0,2,6], +"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[4,0,2,6,0], +"_s_s_l_obj_8h_source.html":[4,0,2,6], +"_s_s_l_session_8cpp.html":[4,0,2,7], +"_s_s_l_session_8h.html":[4,0,2,8], +"_s_s_l_session_8h_source.html":[4,0,2,8], +"_t_l_s12__only__profile_8c.html":[4,0,2,10], +"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[4,0,2,10,0], +"annotated.html":[3,0], +"cert_8h.html":[4,0,1,0], +"cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,1,0,0], +"cert_8h_source.html":[4,0,1,0], +"class_s_s_l_client.html":[3,0,1], +"class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f":[3,0,1,25], +"class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd":[3,0,1,9], +"class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc":[3,0,1,4], +"class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1":[3,0,1,14], +"class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd":[3,0,1,12], +"class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086":[3,0,1,11], +"class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44":[3,0,1,5], +"class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd":[3,0,1,19], +"class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52":[3,0,1,7], +"class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630":[3,0,1,2], +"class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc":[3,0,1,17], +"class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73":[3,0,1,13], +"class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22":[3,0,1,23], +"class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c":[3,0,1,24], +"class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e":[3,0,1,1], +"class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9":[3,0,1,18], +"class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb":[3,0,1,27], +"class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9":[3,0,1,28], +"class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1":[3,0,1,15], +"class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf":[3,0,1,3], +"class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a":[3,0,1,6], +"class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9":[3,0,1,8], +"class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529":[3,0,1,26], +"class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b":[3,0,1,16], +"class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0":[3,0,1,0], +"class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e":[3,0,1,20], +"class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174":[3,0,1,22], +"class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41":[3,0,1,10], +"class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795":[3,0,1,21], +"class_s_s_l_client_impl.html":[3,0,2], +"class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d":[3,0,2,21], +"class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3":[3,0,2,7], +"class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788":[3,0,2,6], +"class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe":[3,0,2,22], +"class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b":[3,0,2,0], +"class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f":[3,0,2,20], +"class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed":[3,0,2,17], +"class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c":[3,0,2,15], +"class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b":[3,0,2,9], +"class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117":[3,0,2,16], +"class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5":[3,0,2,13], +"class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1":[3,0,2,25], +"class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075":[3,0,2,19], +"class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d":[3,0,2,28], +"class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6":[3,0,2,27], +"class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea":[3,0,2,1], +"class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b":[3,0,2,12], +"class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5":[3,0,2,24], +"class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb":[3,0,2,5], +"class_s_s_l_client_impl.html#a9dd694f8e0e65624b103dc781a7744af":[3,0,2,26], +"class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f":[3,0,2,18], +"class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b":[3,0,2,3], +"class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336":[3,0,2,8], +"class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e":[3,0,2,11], +"class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b":[3,0,2,2], +"class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4":[3,0,2,10], +"class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83":[3,0,2,14], +"class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba":[3,0,2,4], +"class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387":[3,0,2,23], +"class_s_s_l_session.html":[3,0,4], +"class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076":[3,0,4,4], +"class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e":[3,0,4,6], +"class_s_s_l_session.html#a3305941fa615f7134526b718917716ee":[3,0,4,1], +"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[3,0,4,2], +"class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0":[3,0,4,3], +"class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f":[3,0,4,5], +"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[3,0,4,7], +"class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb":[3,0,4,0], +"classes.html":[3,1], +"dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[4,0,0,1], +"dir_68267d1309a1af8e8297ef4c3efbcdba.html":[4,0,2], +"dir_9c42dc81377249a918256dbb9cfb2167.html":[4,0,0,0], +"dir_d28a4824dc47e487b107a5db32ef43c4.html":[4,0,0], +"dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[4,0,1], +"ec__prime__fast__256_8c.html":[4,0,2,0], +"ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab":[4,0,2,0,0], +"files.html":[4,0], +"functions.html":[3,3,0], +"functions_func.html":[3,3,1], +"functions_vars.html":[3,3,2], +"globals.html":[4,1,0], +"globals_defs.html":[4,1,5], +"globals_enum.html":[4,1,3], +"globals_eval.html":[4,1,4], +"globals_func.html":[4,1,1], +"globals_vars.html":[4,1,2], +"hierarchy.html":[3,2], "index.html":[], "index.html":[0], "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[1], +"namespace_s_s_l_obj.html":[2,0,0], +"namespacemembers.html":[2,1,0], +"namespacemembers_func.html":[2,1,1], +"namespaces.html":[2,0], "pages.html":[], -"struct_s_s_l_client_parameters.html":[2,0,2], -"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[2,0,2,1], -"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[2,0,2,0], -"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[2,0,2,2], -"time__macros_8h.html":[3,0,2,7], -"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,2,7,19], -"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,2,7,14], -"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,2,7,1], -"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,2,7,20], -"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,2,7,16], -"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,2,7,4], -"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,2,7,15], -"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,2,7,13], -"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,2,7,5], -"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,2,7,8], -"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,2,7,0], -"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,2,7,6], -"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,2,7,18], -"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,2,7,12], -"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,2,7,11], -"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,2,7,2], -"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,2,7,7], -"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,2,7,17], -"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,2,7,3], -"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,2,7,9], -"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,2,7,10], -"time__macros_8h_source.html":[3,0,2,7], -"trust__anchors_8h.html":[3,0,0,0,0], -"trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,0,0,0], -"trust__anchors_8h_source.html":[3,0,0,0,0], -"trustanchors_8h.html":[3,0,0,1,0], -"trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,1,0,0], -"trustanchors_8h_source.html":[3,0,0,1,0] +"struct_s_s_l_client_parameters.html":[3,0,3], +"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[3,0,3,1], +"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[3,0,3,0], +"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[3,0,3,2], +"structssl__pem__decode__state.html":[3,0,0], +"structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3":[3,0,0,0], +"structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9":[3,0,0,1], +"time__macros_8h.html":[4,0,2,9], +"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[4,0,2,9,19], +"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[4,0,2,9,14], +"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[4,0,2,9,1], +"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[4,0,2,9,20], +"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[4,0,2,9,16], +"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[4,0,2,9,4], +"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[4,0,2,9,15], +"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[4,0,2,9,13], +"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[4,0,2,9,5], +"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[4,0,2,9,8], +"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[4,0,2,9,0], +"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[4,0,2,9,6], +"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[4,0,2,9,18], +"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[4,0,2,9,12], +"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[4,0,2,9,11], +"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[4,0,2,9,2], +"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[4,0,2,9,7], +"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[4,0,2,9,17], +"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[4,0,2,9,3], +"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[4,0,2,9,9], +"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[4,0,2,9,10], +"time__macros_8h_source.html":[4,0,2,9], +"trust__anchors_8h.html":[4,0,0,0,0], +"trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,0,0,0,0], +"trust__anchors_8h_source.html":[4,0,0,0,0], +"trustanchors_8h.html":[4,0,0,1,0], +"trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,0,1,0,0], +"trustanchors_8h_source.html":[4,0,0,1,0] }; diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js index b1b7f3c..a18bd2a 100644 --- a/docs/html/search/all_11.js +++ b/docs/html/search/all_11.js @@ -1,5 +1,4 @@ var searchData= [ - ['write',['write',['../class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb',1,'SSLClient::write(uint8_t b) override'],['../class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9',1,'SSLClient::write(const uint8_t *buf, size_t size) override']]], - ['write_5fimpl',['write_impl',['../class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d',1,'SSLClientImpl']]] + ['vect',['vect',['../structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/html/search/all_12.html b/docs/html/search/all_12.html new file mode 100644 index 0000000..0876adf --- /dev/null +++ b/docs/html/search/all_12.html @@ -0,0 +1,30 @@ + + + + + + + + + +
          +
          Loading...
          +
          + +
          Searching...
          +
          No Matches
          + +
          + + diff --git a/docs/html/search/all_12.js b/docs/html/search/all_12.js new file mode 100644 index 0000000..b1b7f3c --- /dev/null +++ b/docs/html/search/all_12.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['write',['write',['../class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb',1,'SSLClient::write(uint8_t b) override'],['../class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9',1,'SSLClient::write(const uint8_t *buf, size_t size) override']]], + ['write_5fimpl',['write_impl',['../class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d',1,'SSLClientImpl']]] +]; diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js index 7fdc7da..c29a2f2 100644 --- a/docs/html/search/all_8.js +++ b/docs/html/search/all_8.js @@ -1,4 +1,5 @@ var searchData= [ + ['index',['index',['../structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3',1,'ssl_pem_decode_state']]], ['is_5fvalid_5fsession',['is_valid_session',['../class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076',1,'SSLSession']]] ]; diff --git a/docs/html/search/all_a.js b/docs/html/search/all_a.js index e250434..f9c2b25 100644 --- a/docs/html/search/all_a.js +++ b/docs/html/search/all_a.js @@ -6,5 +6,6 @@ var searchData= ['m_5fprint_5fbr_5ferror',['m_print_br_error',['../class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed',1,'SSLClientImpl']]], ['m_5fprint_5fprefix',['m_print_prefix',['../class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f',1,'SSLClientImpl']]], ['m_5fprint_5fssl_5ferror',['m_print_ssl_error',['../class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075',1,'SSLClientImpl']]], - ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]] + ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]], + ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] ]; diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js index 5c98031..0383728 100644 --- a/docs/html/search/all_e.js +++ b/docs/html/search/all_e.js @@ -5,7 +5,9 @@ var searchData= ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], + ['set_5fmutual_5fimpl',['set_mutual_impl',['../class_s_s_l_client_impl.html#a9dd694f8e0e65624b103dc781a7744af',1,'SSLClientImpl']]], ['set_5fparameters',['set_parameters',['../class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e',1,'SSLSession']]], + ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f',1,'SSLClient']]], ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3',1,'SSLClientImpl.h']]], ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9',1,'SSLClientImpl.h']]], ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b',1,'SSLClientImpl.h']]], @@ -16,8 +18,9 @@ var searchData= ['ssl_5fnone',['SSL_NONE',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f',1,'SSLClientImpl.h']]], ['ssl_5fok',['SSL_OK',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c',1,'SSLClientImpl.h']]], ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6',1,'SSLClientImpl.h']]], + ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], ['ssl_5fwarn',['SSL_WARN',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d',1,'SSLClientImpl.h']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient< C, SessionCache >'],['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)'],['../class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient< C, SessionCache >'],['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient()']]], ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], ['sslclient_5fh_5f',['SSLClient_H_',['../_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569',1,'SSLClient.h']]], ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'SSLClientImpl'],['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)'],['../class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], @@ -25,6 +28,9 @@ var searchData= ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], + ['sslobj',['SSLObj',['../namespace_s_s_l_obj.html',1,'']]], + ['sslobj_2ecpp',['SSLObj.cpp',['../_s_s_l_obj_8cpp.html',1,'']]], + ['sslobj_2eh',['SSLObj.h',['../_s_s_l_obj_8h.html',1,'']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession::SSLSession()']]], ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js index e9cbbc6..f951cf3 100644 --- a/docs/html/search/classes_0.js +++ b/docs/html/search/classes_0.js @@ -1,5 +1,6 @@ var searchData= [ + ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'']]], ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'']]], ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], diff --git a/docs/html/search/files_3.js b/docs/html/search/files_3.js index 1b3b062..4b15112 100644 --- a/docs/html/search/files_3.js +++ b/docs/html/search/files_3.js @@ -4,6 +4,8 @@ var searchData= ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], + ['sslobj_2ecpp',['SSLObj.cpp',['../_s_s_l_obj_8cpp.html',1,'']]], + ['sslobj_2eh',['SSLObj.h',['../_s_s_l_obj_8h.html',1,'']]], ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]] ]; diff --git a/docs/html/search/functions_7.js b/docs/html/search/functions_7.js index e250434..f9c2b25 100644 --- a/docs/html/search/functions_7.js +++ b/docs/html/search/functions_7.js @@ -6,5 +6,6 @@ var searchData= ['m_5fprint_5fbr_5ferror',['m_print_br_error',['../class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed',1,'SSLClientImpl']]], ['m_5fprint_5fprefix',['m_print_prefix',['../class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f',1,'SSLClientImpl']]], ['m_5fprint_5fssl_5ferror',['m_print_ssl_error',['../class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075',1,'SSLClientImpl']]], - ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]] + ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]], + ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] ]; diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js index 60bd456..750a591 100644 --- a/docs/html/search/functions_b.js +++ b/docs/html/search/functions_b.js @@ -1,7 +1,9 @@ var searchData= [ + ['set_5fmutual_5fimpl',['set_mutual_impl',['../class_s_s_l_client_impl.html#a9dd694f8e0e65624b103dc781a7744af',1,'SSLClientImpl']]], ['set_5fparameters',['set_parameters',['../class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e',1,'SSLSession']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)'],['../class_s_s_l_client.html#ad7b20a2ac220d346a8047db77d97723d',1,'SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], + ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f',1,'SSLClient']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient']]], ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)'],['../class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession']]], ['stop',['stop',['../class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529',1,'SSLClient']]], diff --git a/docs/html/search/namespaces_0.html b/docs/html/search/namespaces_0.html new file mode 100644 index 0000000..c534537 --- /dev/null +++ b/docs/html/search/namespaces_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
          +
          Loading...
          +
          + +
          Searching...
          +
          No Matches
          + +
          + + diff --git a/docs/html/search/namespaces_0.js b/docs/html/search/namespaces_0.js new file mode 100644 index 0000000..923d09a --- /dev/null +++ b/docs/html/search/namespaces_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['sslobj',['SSLObj',['../namespace_s_s_l_obj.html',1,'']]] +]; diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js index 903807c..5109317 100644 --- a/docs/html/search/searchdata.js +++ b/docs/html/search/searchdata.js @@ -1,39 +1,42 @@ var indexSectionsWithContent = { - 0: "_abcdefgilmoprstuw", + 0: "_abcdefgilmoprstuvw", 1: "s", - 2: "cerst", - 3: "abcfgilmoprstw", - 4: "_bce", - 5: "de", - 6: "s", - 7: "_cgpstu", - 8: "st" + 2: "s", + 3: "cerst", + 4: "abcfgilmoprstw", + 5: "_bceiv", + 6: "de", + 7: "s", + 8: "_cgpstu", + 9: "st" }; var indexSectionNames = { 0: "all", 1: "classes", - 2: "files", - 3: "functions", - 4: "variables", - 5: "enums", - 6: "enumvalues", - 7: "defines", - 8: "pages" + 2: "namespaces", + 3: "files", + 4: "functions", + 5: "variables", + 6: "enums", + 7: "enumvalues", + 8: "defines", + 9: "pages" }; var indexSectionLabels = { 0: "All", 1: "Classes", - 2: "Files", - 3: "Functions", - 4: "Variables", - 5: "Enumerations", - 6: "Enumerator", - 7: "Macros", - 8: "Pages" + 2: "Namespaces", + 3: "Files", + 4: "Functions", + 5: "Variables", + 6: "Enumerations", + 7: "Enumerator", + 8: "Macros", + 9: "Pages" }; diff --git a/docs/html/search/variables_4.html b/docs/html/search/variables_4.html new file mode 100644 index 0000000..39883bd --- /dev/null +++ b/docs/html/search/variables_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
          +
          Loading...
          +
          + +
          Searching...
          +
          No Matches
          + +
          + + diff --git a/docs/html/search/variables_4.js b/docs/html/search/variables_4.js new file mode 100644 index 0000000..2d07945 --- /dev/null +++ b/docs/html/search/variables_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['index',['index',['../structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3',1,'ssl_pem_decode_state']]] +]; diff --git a/docs/html/search/variables_5.html b/docs/html/search/variables_5.html new file mode 100644 index 0000000..f25879c --- /dev/null +++ b/docs/html/search/variables_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
          +
          Loading...
          +
          + +
          Searching...
          +
          No Matches
          + +
          + + diff --git a/docs/html/search/variables_5.js b/docs/html/search/variables_5.js new file mode 100644 index 0000000..a18bd2a --- /dev/null +++ b/docs/html/search/variables_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['vect',['vect',['../structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9',1,'ssl_pem_decode_state']]] +]; diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/html/structssl__pem__decode__state-members.html new file mode 100644 index 0000000..3c72623 --- /dev/null +++ b/docs/html/structssl__pem__decode__state-members.html @@ -0,0 +1,110 @@ + + + + + + + +SSLClient: Member List + + + + + + + + + + + + + + +
          +
          + + + + + + +
          +
          SSLClient +  v1.1.1 +
          +
          Add TLS 1.2 functionality to any network library.
          +
          +
          + + + + + + + +
          +
          + +
          +
          +
          + +
          + +
          +
          + + +
          + +
          + +
          +
          +
          ssl_pem_decode_state Member List
          +
          +
          + +

          This is the complete list of members for ssl_pem_decode_state, including all inherited members.

          + + + +
          indexssl_pem_decode_state
          vectssl_pem_decode_state
          +
          + + + + diff --git a/docs/html/structssl__pem__decode__state.html b/docs/html/structssl__pem__decode__state.html new file mode 100644 index 0000000..8698fd3 --- /dev/null +++ b/docs/html/structssl__pem__decode__state.html @@ -0,0 +1,149 @@ + + + + + + + +SSLClient: ssl_pem_decode_state Struct Reference + + + + + + + + + + + + + + +
          +
          + + + + + + +
          +
          SSLClient +  v1.1.1 +
          +
          Add TLS 1.2 functionality to any network library.
          +
          +
          + + + + + + + +
          +
          + +
          +
          +
          + +
          + +
          +
          + + +
          + +
          + +
          + +
          +
          ssl_pem_decode_state Struct Reference
          +
          +
          + + + + + + +

          +Public Attributes

          std::vector< unsigned char > * vect
           
          size_t index = 0
           
          +

          Member Data Documentation

          + +

          ◆ index

          + +
          +
          + + + + +
          size_t ssl_pem_decode_state::index = 0
          +
          + +
          +
          + +

          ◆ vect

          + +
          +
          + + + + +
          std::vector<unsigned char>* ssl_pem_decode_state::vect
          +
          + +
          +
          +
          The documentation for this struct was generated from the following file:
            +
          • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLObj.cpp
          • +
          +
          +
          + + + + diff --git a/docs/html/structssl__pem__decode__state.js b/docs/html/structssl__pem__decode__state.js new file mode 100644 index 0000000..fe8cbfc --- /dev/null +++ b/docs/html/structssl__pem__decode__state.js @@ -0,0 +1,5 @@ +var structssl__pem__decode__state = +[ + [ "index", "structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3", null ], + [ "vect", "structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9", null ] +]; \ No newline at end of file diff --git a/src/SSLObj.cpp b/src/SSLObj.cpp index 73ead13..05fee81 100644 --- a/src/SSLObj.cpp +++ b/src/SSLObj.cpp @@ -12,7 +12,7 @@ struct ssl_pem_decode_state { size_t index = 0; }; -static void ssl_pem_decode(void *dest_ctx, const void *src, size_t len) { +static void ssl_pem_decode_callback(void *dest_ctx, const void *src, size_t len) { ssl_pem_decode_state* ctx = static_cast(dest_ctx); for (size_t i = 0; i < len; i++) ctx->vect->emplace_back(static_cast(src)[i]); // update index @@ -31,7 +31,7 @@ const std::vector SSLObj::make_vector_pem(const char* data, const state.vect = &temp; state.index = 0; // set the byte reciever - br_pem_decoder_setdest(&pctx, &ssl_pem_decode, &state); + br_pem_decoder_setdest(&pctx, &ssl_pem_decode_callback, &state); // start decoding! int br_state = 0; size_t index = 0; @@ -52,14 +52,4 @@ const std::vector SSLObj::make_vector_pem(const char* data, const } // else we're good! return temp; -} - -const std::vector SSLObj::make_vector_der(const char* data, const size_t len) { - if (data == nullptr || len == 0) return {}; - // create a temporary vector - std::vector temp(len); - // copy the elements over - for (size_t i = 0; i < len; i++) temp[i] = data[i]; - // return the new SSLObj - return temp; } \ No newline at end of file diff --git a/src/SSLObj.h b/src/SSLObj.h index 8d5ecaf..8f70ac8 100644 --- a/src/SSLObj.h +++ b/src/SSLObj.h @@ -41,13 +41,23 @@ * which allow BearSSL use client certificates when creating a TLS connection. Since * most certificates are transmitted over the internet in PEM format, a certificate can * be provided in PEM or DER format, and will be converted internally to DER format for - * later use. A PEM file provided to this class MUST CONTAIN the `----BEGIN ... -----` - * header in order to be parsed correctly. + * later use. */ namespace SSLObj { + /** + * @brief Convert a PEM buffer into a vector of raw DER bytes + * + * This function takes a PEM buffer (e.g. `----BEGIN CERTIFICATE...`) and converts + * it into a vector of raw bytes. The bytes given to this function must: + * * Contain both the `-----BEGIN XXX-----` and `-----END XXX-----` strings. These are + * removed during processing. + * * Have a base64 encoded body + * * Only contain a single object (certificate, private key, etc.). + * + * @returns The raw bytes decoded from the PEM file. + */ const std::vector make_vector_pem(const char* data, const size_t len); - const std::vector make_vector_der(const char* data, const size_t len); } #endif \ No newline at end of file From 26e054bd76ea711149136e8939d425dfbcaf78e0 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 14 Aug 2019 11:14:13 -0700 Subject: [PATCH 079/205] bump version --- docs/html/_r_e_a_d_m_e_8md.html | 2 +- docs/html/_s_s_l_client_8h.html | 2 +- docs/html/_s_s_l_client_8h_source.html | 2 +- docs/html/_s_s_l_client_impl_8cpp.html | 2 +- docs/html/_s_s_l_client_impl_8h.html | 2 +- docs/html/_s_s_l_client_impl_8h_source.html | 2 +- docs/html/_s_s_l_client_parameters_8h.html | 2 +- docs/html/_s_s_l_client_parameters_8h_source.html | 2 +- docs/html/_s_s_l_obj_8cpp.html | 2 +- docs/html/_s_s_l_obj_8h.html | 2 +- docs/html/_s_s_l_obj_8h_source.html | 2 +- docs/html/_s_s_l_session_8cpp.html | 2 +- docs/html/_s_s_l_session_8h.html | 2 +- docs/html/_s_s_l_session_8h_source.html | 2 +- docs/html/_t_l_s12__only__profile_8c.html | 2 +- docs/html/_trust_anchors_8md.html | 2 +- docs/html/annotated.html | 2 +- docs/html/cert_8h.html | 2 +- docs/html/cert_8h_source.html | 2 +- docs/html/class_s_s_l_client-members.html | 2 +- docs/html/class_s_s_l_client.html | 2 +- docs/html/class_s_s_l_client_impl-members.html | 2 +- docs/html/class_s_s_l_client_impl.html | 2 +- docs/html/class_s_s_l_session-members.html | 2 +- docs/html/class_s_s_l_session.html | 2 +- docs/html/classes.html | 2 +- docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html | 2 +- docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html | 2 +- docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html | 2 +- docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html | 2 +- docs/html/ec__prime__fast__256_8c.html | 2 +- docs/html/files.html | 2 +- docs/html/functions.html | 2 +- docs/html/functions_func.html | 2 +- docs/html/functions_vars.html | 2 +- docs/html/globals.html | 2 +- docs/html/globals_defs.html | 2 +- docs/html/globals_enum.html | 2 +- docs/html/globals_eval.html | 2 +- docs/html/globals_func.html | 2 +- docs/html/globals_vars.html | 2 +- docs/html/hierarchy.html | 2 +- docs/html/index.html | 2 +- ...cuments__arduino_libraries__s_s_l_client__trust_anchors.html | 2 +- docs/html/namespace_s_s_l_obj.html | 2 +- docs/html/namespacemembers.html | 2 +- docs/html/namespacemembers_func.html | 2 +- docs/html/namespaces.html | 2 +- docs/html/pages.html | 2 +- docs/html/struct_s_s_l_client_parameters-members.html | 2 +- docs/html/struct_s_s_l_client_parameters.html | 2 +- docs/html/structssl__pem__decode__state-members.html | 2 +- docs/html/structssl__pem__decode__state.html | 2 +- docs/html/time__macros_8h.html | 2 +- docs/html/time__macros_8h_source.html | 2 +- docs/html/trust__anchors_8h.html | 2 +- docs/html/trust__anchors_8h_source.html | 2 +- docs/html/trustanchors_8h.html | 2 +- docs/html/trustanchors_8h_source.html | 2 +- library.properties | 2 +- 61 files changed, 61 insertions(+), 61 deletions(-) diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/html/_r_e_a_d_m_e_8md.html index 159a65b..301d463 100644 --- a/docs/html/_r_e_a_d_m_e_8md.html +++ b/docs/html/_r_e_a_d_m_e_8md.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index df7d798..e4a92cf 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index 69d4620..f30fb5d 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_client_impl_8cpp.html b/docs/html/_s_s_l_client_impl_8cpp.html index 07e3d3b..7a0a456 100644 --- a/docs/html/_s_s_l_client_impl_8cpp.html +++ b/docs/html/_s_s_l_client_impl_8cpp.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_client_impl_8h.html b/docs/html/_s_s_l_client_impl_8h.html index 6e9ba5d..cef1ffa 100644 --- a/docs/html/_s_s_l_client_impl_8h.html +++ b/docs/html/_s_s_l_client_impl_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_client_impl_8h_source.html b/docs/html/_s_s_l_client_impl_8h_source.html index b7ff5ee..a762cc8 100644 --- a/docs/html/_s_s_l_client_impl_8h_source.html +++ b/docs/html/_s_s_l_client_impl_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_client_parameters_8h.html b/docs/html/_s_s_l_client_parameters_8h.html index 408fb5b..a7c5050 100644 --- a/docs/html/_s_s_l_client_parameters_8h.html +++ b/docs/html/_s_s_l_client_parameters_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_client_parameters_8h_source.html b/docs/html/_s_s_l_client_parameters_8h_source.html index f1aed41..262cf99 100644 --- a/docs/html/_s_s_l_client_parameters_8h_source.html +++ b/docs/html/_s_s_l_client_parameters_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_obj_8cpp.html b/docs/html/_s_s_l_obj_8cpp.html index b720439..6a97a5e 100644 --- a/docs/html/_s_s_l_obj_8cpp.html +++ b/docs/html/_s_s_l_obj_8cpp.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_obj_8h.html b/docs/html/_s_s_l_obj_8h.html index c50d212..9024aa9 100644 --- a/docs/html/_s_s_l_obj_8h.html +++ b/docs/html/_s_s_l_obj_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_obj_8h_source.html b/docs/html/_s_s_l_obj_8h_source.html index d32ef25..b4a8442 100644 --- a/docs/html/_s_s_l_obj_8h_source.html +++ b/docs/html/_s_s_l_obj_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_session_8cpp.html b/docs/html/_s_s_l_session_8cpp.html index 458ced1..21494ea 100644 --- a/docs/html/_s_s_l_session_8cpp.html +++ b/docs/html/_s_s_l_session_8cpp.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index 7f71f53..e0dbc53 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index 9623d0b..1a0730f 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html index 0562e86..0e42728 100644 --- a/docs/html/_t_l_s12__only__profile_8c.html +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html index e73745c..a64bd86 100644 --- a/docs/html/_trust_anchors_8md.html +++ b/docs/html/_trust_anchors_8md.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/annotated.html b/docs/html/annotated.html index c49db68..3ddfa8e 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/cert_8h.html b/docs/html/cert_8h.html index 9bb5578..88192ea 100644 --- a/docs/html/cert_8h.html +++ b/docs/html/cert_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html index e1db8ed..6f4239c 100644 --- a/docs/html/cert_8h_source.html +++ b/docs/html/cert_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 24a725e..0981301 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index d8df6fe..66fcc3a 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/class_s_s_l_client_impl-members.html b/docs/html/class_s_s_l_client_impl-members.html index d522108..0d3412e 100644 --- a/docs/html/class_s_s_l_client_impl-members.html +++ b/docs/html/class_s_s_l_client_impl-members.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/class_s_s_l_client_impl.html b/docs/html/class_s_s_l_client_impl.html index ce4a622..34f8e64 100644 --- a/docs/html/class_s_s_l_client_impl.html +++ b/docs/html/class_s_s_l_client_impl.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index 8512fbe..94cb202 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index bf83f7e..b5d0811 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/classes.html b/docs/html/classes.html index c18aed9..8a44185 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html index e1f45cd..ad459b7 100644 --- a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index b4482c9..213ba14 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html index 0f6fe49..fdd7d17 100644 --- a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html index d7796f8..98fae67 100644 --- a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html index e955a0c..544df56 100644 --- a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/ec__prime__fast__256_8c.html b/docs/html/ec__prime__fast__256_8c.html index e2edbfe..1dbbfeb 100644 --- a/docs/html/ec__prime__fast__256_8c.html +++ b/docs/html/ec__prime__fast__256_8c.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/files.html b/docs/html/files.html index 6f99fdf..6672f57 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/functions.html b/docs/html/functions.html index 549139d..de3bd8b 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index f610a78..7ff72b8 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/functions_vars.html b/docs/html/functions_vars.html index 5a57c5b..5cc8e91 100644 --- a/docs/html/functions_vars.html +++ b/docs/html/functions_vars.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/globals.html b/docs/html/globals.html index 991b825..a3bb937 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index 110a147..6b52f8f 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/globals_enum.html b/docs/html/globals_enum.html index 44a509d..6161561 100644 --- a/docs/html/globals_enum.html +++ b/docs/html/globals_enum.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/globals_eval.html b/docs/html/globals_eval.html index ea1f9be..2494fd1 100644 --- a/docs/html/globals_eval.html +++ b/docs/html/globals_eval.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index bb7f1cb..f23d91b 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index de931f5..3ac6bb8 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 50cd42e..a11880c 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/index.html b/docs/html/index.html index 9411517..ed54c66 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index 8ea9d13..b719965 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/html/namespace_s_s_l_obj.html index f347e91..ea568a5 100644 --- a/docs/html/namespace_s_s_l_obj.html +++ b/docs/html/namespace_s_s_l_obj.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespacemembers.html b/docs/html/namespacemembers.html index 5b0684e..193a83c 100644 --- a/docs/html/namespacemembers.html +++ b/docs/html/namespacemembers.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespacemembers_func.html b/docs/html/namespacemembers_func.html index 3b56928..f0b8146 100644 --- a/docs/html/namespacemembers_func.html +++ b/docs/html/namespacemembers_func.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespaces.html b/docs/html/namespaces.html index 5dde767..2f1ddb6 100644 --- a/docs/html/namespaces.html +++ b/docs/html/namespaces.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/pages.html b/docs/html/pages.html index 40f7260..356a0fd 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/html/struct_s_s_l_client_parameters-members.html index 3a9f4b6..7171d9f 100644 --- a/docs/html/struct_s_s_l_client_parameters-members.html +++ b/docs/html/struct_s_s_l_client_parameters-members.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html index df4ab25..e5f31db 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/html/structssl__pem__decode__state-members.html index 3c72623..4ee8da1 100644 --- a/docs/html/structssl__pem__decode__state-members.html +++ b/docs/html/structssl__pem__decode__state-members.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/structssl__pem__decode__state.html b/docs/html/structssl__pem__decode__state.html index 8698fd3..c314b41 100644 --- a/docs/html/structssl__pem__decode__state.html +++ b/docs/html/structssl__pem__decode__state.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html index e7f6961..e22bf32 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/html/time__macros_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html index 38aa464..677a444 100644 --- a/docs/html/time__macros_8h_source.html +++ b/docs/html/time__macros_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html index 9256c2b..ef2751e 100644 --- a/docs/html/trust__anchors_8h.html +++ b/docs/html/trust__anchors_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index 05a0dbe..e3690bc 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html index 72d7454..729f06c 100644 --- a/docs/html/trustanchors_8h.html +++ b/docs/html/trustanchors_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html index c21f425..7d967ea 100644 --- a/docs/html/trustanchors_8h_source.html +++ b/docs/html/trustanchors_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.1.1 +  v1.3.0
          Add TLS 1.2 functionality to any network library.
          diff --git a/library.properties b/library.properties index db0cf09..17f6405 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.2.3 +version=1.3.0 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From c157c00f691b376f71f72590ca0f5c5e5128c806 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 14 Aug 2019 11:19:56 -0700 Subject: [PATCH 080/205] final update to documentation before version release --- docs/html/_s_s_l_client_8h_source.html | 32 +++++++++++++------------- docs/html/class_s_s_l_client.html | 3 ++- src/SSLClient.h | 5 +++- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index f30fb5d..ca4b889 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -91,52 +91,52 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
          SSLClient.h
          -Go to the documentation of this file.
          1 /* Copyright 2019 OSU OPEnS Lab
          2  *
          3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
          4  * software and associated documentation files (the "Software"), to deal in the Software
          5  * without restriction, including without limitation the rights to use, copy, modify,
          6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
          7  * permit persons to whom the Software is furnished to do so, subject to the following
          8  * conditions:
          9  *
          10  * The above copyright notice and this permission notice shall be included in all
          11  * copies or substantial portions of the Software.
          12  *
          13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
          14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
          15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
          16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
          17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
          18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
          19  */
          20 
          21 #include "Client.h"
          22 #include "SSLClientImpl.h"
          23 #include "SSLSession.h"
          24 #include "SSLClientParameters.h"
          25 #include "SSLObj.h"
          26 
          27 #ifndef SSLClient_H_
          28 #define SSLClient_H_
          29 
          35 template <class C, size_t SessionCache = 1>
          36 class SSLClient : public SSLClientImpl {
          37 /*
          38  * static checks
          39  * I'm a java developer, so I want to ensure that my inheritance is safe.
          40  * These checks ensure that all the functions we use on class C are
          41  * actually present on class C. It does this by checking that the
          42  * class inherits from Client.
          43  *
          44  * Additionally, I ran into a lot of memory issues with large sessions caches.
          45  * Since each session contains at max 352 bytes of memory, they eat of the
          46  * stack quite quickly and can cause overflows. As a result, I have added a
          47  * warning here to discourage the use of more than 3 sessions at a time. Any
          48  * amount past that will require special modification of this library, and
          49  * assumes you know what you are doing.
          50  */
          51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
          52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
          53 
          54 public:
          72  explicit SSLClient( const C& client,
          73  const br_x509_trust_anchor *trust_anchors,
          74  const size_t trust_anchors_num,
          75  const int analog_pin,
          76  const DebugLevel debug = SSL_WARN)
          77  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
          78  , m_client(client)
          79  , m_sessions{}
          80  {
          81  // set the timeout to a reasonable number (it can always be changes later)
          82  // SSL Connections take a really long time so we don't want to time out a legitimate thing
          83  setTimeout(30 * 1000);
          84  }
          85 
          86  //========================================
          87  //= Functions implemented in SSLClientImpl
          88  //========================================
          89 
          129  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
          130 
          167  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
          168 
          170  size_t write(uint8_t b) override { return write_impl(&b, 1); }
          194  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
          195 
          214  int available() override { return available_impl(); }
          215 
          220  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
          242  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
          243 
          252  int peek() override { return peek_impl(); }
          253 
          261  void flush() override { return flush_impl(); }
          262 
          271  void stop() override { return stop_impl(); }
          272 
          286  uint8_t connected() override { return connected_impl(); }
          287 
          288  //========================================
          289  //= Functions Not in the Client Interface
          290  //========================================
          291 
          297  void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); }
          298 
          313  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
          314 
          323  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
          324 
          330  size_t getSessionCount() const override { return SessionCache; }
          331 
          337  operator bool() { return connected() > 0; }
          339  bool operator==(const bool value) { return bool() == value; }
          341  bool operator!=(const bool value) { return bool() != value; }
          343  bool operator==(const C& rhs) { return m_client == rhs; }
          345  bool operator!=(const C& rhs) { return m_client != rhs; }
          347  uint16_t localPort() override { return m_client.localPort(); }
          349  IPAddress remoteIP() override { return m_client.remoteIP(); }
          351  uint16_t remotePort() override { return m_client.remotePort(); }
          352 
          354  C& getClient() { return m_client; }
          355 
          356 protected:
          358  Client& get_arduino_client() override { return m_client; }
          359  const Client& get_arduino_client() const override { return m_client; }
          361  SSLSession* get_session_array() override { return m_sessions; }
          362  const SSLSession* get_session_array() const override { return m_sessions; }
          363 
          364 private:
          365  // create a copy of the client
          366  C m_client;
          367  // also store an array of SSLSessions, so we can resume communication with multiple websites
          368  SSLSession m_sessions[SessionCache];
          369 };
          370 
          371 #endif
          void setMutualAuthParams(const SSLClientParameters *params)
          Add a client certificate and enable support for mutual auth.
          Definition: SSLClient.h:297
          +Go to the documentation of this file.
          1 /* Copyright 2019 OSU OPEnS Lab
          2  *
          3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
          4  * software and associated documentation files (the "Software"), to deal in the Software
          5  * without restriction, including without limitation the rights to use, copy, modify,
          6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
          7  * permit persons to whom the Software is furnished to do so, subject to the following
          8  * conditions:
          9  *
          10  * The above copyright notice and this permission notice shall be included in all
          11  * copies or substantial portions of the Software.
          12  *
          13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
          14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
          15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
          16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
          17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
          18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
          19  */
          20 
          21 #include "Client.h"
          22 #include "SSLClientImpl.h"
          23 #include "SSLSession.h"
          24 #include "SSLClientParameters.h"
          25 #include "SSLObj.h"
          26 
          27 #ifndef SSLClient_H_
          28 #define SSLClient_H_
          29 
          35 template <class C, size_t SessionCache = 1>
          36 class SSLClient : public SSLClientImpl {
          37 /*
          38  * static checks
          39  * I'm a java developer, so I want to ensure that my inheritance is safe.
          40  * These checks ensure that all the functions we use on class C are
          41  * actually present on class C. It does this by checking that the
          42  * class inherits from Client.
          43  *
          44  * Additionally, I ran into a lot of memory issues with large sessions caches.
          45  * Since each session contains at max 352 bytes of memory, they eat of the
          46  * stack quite quickly and can cause overflows. As a result, I have added a
          47  * warning here to discourage the use of more than 3 sessions at a time. Any
          48  * amount past that will require special modification of this library, and
          49  * assumes you know what you are doing.
          50  */
          51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
          52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
          53 
          54 public:
          72  explicit SSLClient( const C& client,
          73  const br_x509_trust_anchor *trust_anchors,
          74  const size_t trust_anchors_num,
          75  const int analog_pin,
          76  const DebugLevel debug = SSL_WARN)
          77  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
          78  , m_client(client)
          79  , m_sessions{}
          80  {
          81  // set the timeout to a reasonable number (it can always be changes later)
          82  // SSL Connections take a really long time so we don't want to time out a legitimate thing
          83  setTimeout(30 * 1000);
          84  }
          85 
          86  //========================================
          87  //= Functions implemented in SSLClientImpl
          88  //========================================
          89 
          129  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
          130 
          167  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
          168 
          170  size_t write(uint8_t b) override { return write_impl(&b, 1); }
          194  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
          195 
          214  int available() override { return available_impl(); }
          215 
          220  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
          242  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
          243 
          252  int peek() override { return peek_impl(); }
          253 
          261  void flush() override { return flush_impl(); }
          262 
          271  void stop() override { return stop_impl(); }
          272 
          286  uint8_t connected() override { return connected_impl(); }
          287 
          288  //========================================
          289  //= Functions Not in the Client Interface
          290  //========================================
          291 
          300  void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); }
          301 
          316  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
          317 
          326  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
          327 
          333  size_t getSessionCount() const override { return SessionCache; }
          334 
          340  operator bool() { return connected() > 0; }
          342  bool operator==(const bool value) { return bool() == value; }
          344  bool operator!=(const bool value) { return bool() != value; }
          346  bool operator==(const C& rhs) { return m_client == rhs; }
          348  bool operator!=(const C& rhs) { return m_client != rhs; }
          350  uint16_t localPort() override { return m_client.localPort(); }
          352  IPAddress remoteIP() override { return m_client.remoteIP(); }
          354  uint16_t remotePort() override { return m_client.remotePort(); }
          355 
          357  C& getClient() { return m_client; }
          358 
          359 protected:
          361  Client& get_arduino_client() override { return m_client; }
          362  const Client& get_arduino_client() const override { return m_client; }
          364  SSLSession* get_session_array() override { return m_sessions; }
          365  const SSLSession* get_session_array() const override { return m_sessions; }
          366 
          367 private:
          368  // create a copy of the client
          369  C m_client;
          370  // also store an array of SSLSessions, so we can resume communication with multiple websites
          371  SSLSession m_sessions[SessionCache];
          372 };
          373 
          374 #endif
          void setMutualAuthParams(const SSLClientParameters *params)
          Add a client certificate and enable support for mutual auth.
          Definition: SSLClient.h:300
          size_t write_impl(const uint8_t *buf, size_t size)
          Definition: SSLClientImpl.cpp:130
          -
          const SSLSession * get_session_array() const override
          Definition: SSLClient.h:362
          -
          IPAddress remoteIP() override
          Returns the remote IP, if C::remoteIP exists.
          Definition: SSLClient.h:349
          +
          const SSLSession * get_session_array() const override
          Definition: SSLClient.h:365
          +
          IPAddress remoteIP() override
          Returns the remote IP, if C::remoteIP exists.
          Definition: SSLClient.h:352
          size_t write(uint8_t b) override
          Definition: SSLClient.h:170
          Definition: SSLClientImpl.h:66
          SSLSession & get_session_impl(const char *host, const IPAddress &addr)
          Definition: SSLClientImpl.cpp:286
          This class stores values which allow SSLClient to save and resume SSL sessions.
          Definition: SSLSession.h:52
          -
          bool operator!=(const C &rhs)
          Returns whether or not two SSLClient objects do not have the same underlying client object.
          Definition: SSLClient.h:345
          +
          bool operator!=(const C &rhs)
          Returns whether or not two SSLClient objects do not have the same underlying client object.
          Definition: SSLClient.h:348
          int available() override
          Returns the number of bytes available to read from the data that has been received and decrypted.
          Definition: SSLClient.h:214
          -
          C & getClient()
          Returns a reference to the client object stored in this class. Take care not to break it.
          Definition: SSLClient.h:354
          +
          C & getClient()
          Returns a reference to the client object stored in this class. Take care not to break it.
          Definition: SSLClient.h:357
          int peek_impl()
          Definition: SSLClientImpl.cpp:209
          This struct stores data required for SSLClient to use mutual authentication.
          Definition: SSLClientParameters.h:52
          void flush() override
          Force writing the buffered bytes from SSLClient::write to the network.
          Definition: SSLClient.h:261
          The main SSLClient class. Check out README.md for more info.
          Definition: SSLClient.h:36
          -
          bool operator!=(const bool value)
          Definition: SSLClient.h:341
          +
          bool operator!=(const bool value)
          Definition: SSLClient.h:344
          void stop() override
          Close the connection.
          Definition: SSLClient.h:271
          size_t write(const uint8_t *buf, size_t size) override
          Write some bytes to the SSL connection.
          Definition: SSLClient.h:194
          SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
          Initialize SSLClient with all of the prerequisites needed.
          Definition: SSLClient.h:72
          int peek() override
          View the first byte of the buffer, without removing it from the SSLClient Buffer.
          Definition: SSLClient.h:252
          int available_impl()
          Definition: SSLClientImpl.cpp:173
          -
          bool operator==(const C &rhs)
          Returns whether or not two SSLClient objects have the same underlying client object.
          Definition: SSLClient.h:343
          +
          bool operator==(const C &rhs)
          Returns whether or not two SSLClient objects have the same underlying client object.
          Definition: SSLClient.h:346
          int read_impl(uint8_t *buf, size_t size)
          Definition: SSLClientImpl.cpp:194
          -
          SSLSession * get_session_array() override
          Returns an instance of the session array that is on the stack.
          Definition: SSLClient.h:361
          +
          SSLSession * get_session_array() override
          Returns an instance of the session array that is on the stack.
          Definition: SSLClient.h:364
          void remove_session_impl(const char *host, const IPAddress &addr)
          Definition: SSLClientImpl.cpp:305
          -
          Client & get_arduino_client() override
          Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
          Definition: SSLClient.h:358
          -
          uint16_t localPort() override
          Returns the local port, if C::localPort exists.
          Definition: SSLClient.h:347
          +
          Client & get_arduino_client() override
          Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
          Definition: SSLClient.h:361
          +
          uint16_t localPort() override
          Returns the local port, if C::localPort exists.
          Definition: SSLClient.h:350
          void set_mutual_impl(const SSLClientParameters *params)
          Definition: SSLClientImpl.cpp:316
          int read() override
          Read a single byte, or -1 if none is available.
          Definition: SSLClient.h:220
          uint8_t connected() override
          Check if the device is connected.
          Definition: SSLClient.h:286
          -
          const Client & get_arduino_client() const override
          Definition: SSLClient.h:359
          +
          const Client & get_arduino_client() const override
          Definition: SSLClient.h:362
          int connect(const char *host, uint16_t port) override
          Connect over SSL to a host specified by a hostname.
          Definition: SSLClient.h:167
          -
          bool operator==(const bool value)
          Definition: SSLClient.h:339
          -
          uint16_t remotePort() override
          Returns the remote port, if C::remotePort exists. Else return 0.
          Definition: SSLClient.h:351
          +
          bool operator==(const bool value)
          Definition: SSLClient.h:342
          +
          uint16_t remotePort() override
          Returns the remote port, if C::remotePort exists. Else return 0.
          Definition: SSLClient.h:354
          int connect_impl(IPAddress ip, uint16_t port)
          Definition: SSLClientImpl.cpp:73
          -
          size_t getSessionCount() const override
          Get the maximum number of SSL sessions that can be stored at once.
          Definition: SSLClient.h:330
          +
          size_t getSessionCount() const override
          Get the maximum number of SSL sessions that can be stored at once.
          Definition: SSLClient.h:333
          void stop_impl()
          Definition: SSLClientImpl.cpp:227
          void flush_impl()
          Definition: SSLClientImpl.cpp:221
          Implementation code to be inherited by SSLClient.
          Definition: SSLClientImpl.h:72
          -
          void removeSession(const char *host, const IPAddress &addr)
          Clear the session corresponding to a host and IP.
          Definition: SSLClient.h:323
          +
          void removeSession(const char *host, const IPAddress &addr)
          Clear the session corresponding to a host and IP.
          Definition: SSLClient.h:326
          uint8_t connected_impl()
          Definition: SSLClientImpl.cpp:255
          -
          SSLSession & getSession(const char *host, const IPAddress &addr)
          Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
          Definition: SSLClient.h:313
          +
          SSLSession & getSession(const char *host, const IPAddress &addr)
          Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
          Definition: SSLClient.h:316
          DebugLevel
          Level of verbosity used in logging for SSLClient.
          Definition: SSLClientImpl.h:60
          int read(uint8_t *buf, size_t size) override
          Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
          Definition: SSLClient.h:242
          int connect(IPAddress ip, uint16_t port) override
          Connect over SSL to a host specified by an IP address.
          Definition: SSLClient.h:129
          diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 66fcc3a..44b769d 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -1203,7 +1203,8 @@ template<class C , size_t SessionCache = 1>

          Add a client certificate and enable support for mutual auth.

          -

          This function must be called BEFORE making an SSL connection.

          +

          Please ensure that the values in params are valid for the lifetime of SSLClient. You may want to make them global constants.

          +
          Precondition
          SSLClient has not already started an SSL connection.
          diff --git a/src/SSLClient.h b/src/SSLClient.h index 6116d61..6c635e1 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -292,7 +292,10 @@ public: /** * @brief Add a client certificate and enable support for mutual auth * - * This function must be called BEFORE making an SSL connection. + * Please ensure that the values in `params` are valid for the lifetime + * of SSLClient. You may want to make them global constants. + * + * @pre SSLClient has not already started an SSL connection. */ void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); } From 6012a3e5ba79198909a168e5a8151a40f07e513b Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 6 Nov 2019 16:04:09 -0800 Subject: [PATCH 081/205] Updated travis to use latest version of ArduinoCLI --- .travis.yml | 47 +++++++++++++++++++++++++++++++++++----------- library.properties | 3 ++- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6eac9e6..57f01e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,44 @@ language: c -sudo: false -cache: - directories: - - ~/arduino_ide - - ~/.arduino15/packages/ -git: - depth: false - quiet: true env: global: # You can uncomment this to explicitly choose an (old) version of the Arduino IDE #- ARDUINO_IDE_VERSION="1.8.7" + - ADDITIONAL_URLS="https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" +cache: + directories: + - ~/arduino_ide + - ~/.arduino15/packages/ +jobs: + include: + - env: + - ARCH="cortex-m0plus" + - CORE="adafruit:samd" + - BOARD="adafruit:samd:adafruit_feather_m0" + - DEPLOY=1 + - env: + - ARCH="cortex-m0plus" + - CORE="arduino:samd" + - BOARD="arduino:samd:mzero_bl" + - DEPLOY=0 + before_install: - - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) + - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/bin sudo sh + - arduino-cli core update-index --additional-urls $ADDITIONAL_URLS + - arduino-cli core install arduino:samd -v + - arduino-cli core install adafruit:samd -v --additional-urls $ADDITIONAL_URLS + - mkdir -p $HOME/Arduino/libraries + - git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/Arduino/libraries/EthernetLarge install: - - if [ ! -d "$HOME/arduino_ide/libraries/EthernetLarge" ]; then git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/arduino_ide/libraries/EthernetLarge; fi + - ln -s $PWD $HOME/Arduino/libraries/. script: - - build_platform zero \ No newline at end of file + - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetHTTPS + - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetMultiHTTPS +deploy: + - provider: script + script: bash .travis/upload_precompiled.sh + skip_cleanup: true + on: + tags: true + branch: develop + condition: $DEPLOY = 1 + \ No newline at end of file diff --git a/library.properties b/library.properties index 17f6405..3f10399 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,5 @@ paragraph=including the Arduino EthernetClient and WiFiClient classes (though it category=Communication url=https://github.com/OPEnSLab-OSU/SSLClient architectures=samd -includes=SSLClient.h \ No newline at end of file +includes=SSLClient.h +dot_a_linkage=true \ No newline at end of file From a0f74b19a3a6116f3142411a965b8aabf808d2ad Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 6 Nov 2019 16:36:07 -0800 Subject: [PATCH 082/205] attempted to add autocompile and deploy feature --- .travis.yml | 22 +++++++++++++++------- .travis/library.properties | 12 ++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 .travis/library.properties diff --git a/.travis.yml b/.travis.yml index 57f01e6..e604c7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,12 +33,20 @@ install: script: - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetHTTPS - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetMultiHTTPS +before_deploy: + - mkdir src/$ARCH + - cp $(find /tmp/ -maxdepth 1 -type d -name "arduino-sketch*" -print)/libraries/SSLClient/SSLClient.a src/$ARCH/SSLClient.a + - cp .travis/library.properties library.properties + - find src/ -iname "*.c" -delete + - find src/ -iname "*.cpp" -delete + - zip -r SSLClient.zip . deploy: - - provider: script - script: bash .travis/upload_precompiled.sh - skip_cleanup: true - on: - tags: true - branch: develop - condition: $DEPLOY = 1 + provider: releases + api_key: "$GITHUB_TOKEN" + file: "SSLClient.zip" + skip_cleanup: true + on: + tags: true + branch: master + condition: $DEPLOY = 1 \ No newline at end of file diff --git a/.travis/library.properties b/.travis/library.properties new file mode 100644 index 0000000..3111be0 --- /dev/null +++ b/.travis/library.properties @@ -0,0 +1,12 @@ +name=SSLClient +version=1.3.0 +author=Noah Koontz +maintainer=OPEnS Lab +sentence=Arduino library to add SSL functionality to any Client class +paragraph=including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. +category=Communication +url=https://github.com/OPEnSLab-OSU/SSLClient +architectures=samd +includes=SSLClient.h +precompiled=true +ldflags=-lSSLClient \ No newline at end of file From 0ca631c62752b3acfe7bb837ccdf224eed07e691 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Nov 2019 09:41:27 -0800 Subject: [PATCH 083/205] update travis for autodeploy --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e604c7a..5084d9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,9 @@ script: - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetMultiHTTPS before_deploy: - mkdir src/$ARCH - - cp $(find /tmp/ -maxdepth 1 -type d -name "arduino-sketch*" -print)/libraries/SSLClient/SSLClient.a src/$ARCH/SSLClient.a - - cp .travis/library.properties library.properties + - cp "$(find /tmp/ -maxdepth 1 -type d -name "arduino-sketch*" -print | head -n 1)/libraries/SSLClient/SSLClient.a" src/$ARCH/ + - cp .travis/library.properties . + - rm -rf .git - find src/ -iname "*.c" -delete - find src/ -iname "*.cpp" -delete - zip -r SSLClient.zip . From 00f78f18e868e8380d163d711e00308694fed355 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Nov 2019 12:08:39 -0800 Subject: [PATCH 084/205] refactored SSLClient to use a reference to a client as opposed to an instance. --- README.md | 26 +- TrustAnchors.md | 2 +- examples/EthernetHTTPS/EthernetHTTPS.ino | 5 +- .../EthernetMultiHTTPS/EthernetMultiHTTPS.ino | 5 +- src/{SSLClientImpl.cpp => SSLClient.cpp} | 222 ++++++++--------- src/SSLClient.h | 229 ++++++++++++------ src/SSLClientImpl.h | 213 ---------------- src/SSLSession.cpp | 24 -- src/SSLSession.h | 55 +---- src/config.h | 5 +- 10 files changed, 281 insertions(+), 505 deletions(-) rename src/{SSLClientImpl.cpp => SSLClient.cpp} (85%) delete mode 100644 src/SSLClientImpl.h delete mode 100644 src/SSLSession.cpp diff --git a/README.md b/README.md index f37a77a..8231abc 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,20 @@ Using SSLClient should be similar to using any other Arduino-based Client class, Once all those are ready, you can create a simple SSLClient object like this: ```C++ -SSLClient client(BaseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin); +BaseClientType baseClientInstance; +SSLClient client(baseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin); ``` Where: -* BaseClientType - The type of BaseClientInstance -* BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3) +* BaseClientType - The type of baseClientInstance +* BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3). It is important that this instance be stored *outside* the SSLClient declaration (for instance, `SSLClient(BaseClientType() ...)` wouldn't work). * TAs - The name of the trust anchor array created in step 2. If you generated a header using the tutorial this will probably be `TAs`. * TAs_NUM - The number of trust anchors in TAs. If you generated a header using the tutorial this will probably be `TAs_NUM`. * AnalogPin - The analog pin to pull random data from (step 4). For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using: ```C++ -SSLClient client(EthernetClient(), TAs, 2, A7); +EthernetClient baseClient; +SSLClient client(baseClient, TAs, 2, A7); ``` Once that is setup, simply use SSLClient as you would the base client class: ```C++ @@ -62,7 +64,8 @@ Additionally, the bulk of SSLClient is split into two components: a template cla ### Logging SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor: ```C++ -SSLClient client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO); +EthernetClient baseClient; +SSLClient client(baseClient, TAs, (size_t)2, A7, 1, SSLClient::SSL_INFO); ``` Logging is always outputted through the [Arduino Serial interface](https://www.arduino.cc/reference/en/language/functions/communication/serial/), so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in ::DebugLevel. The log level is set to `SSL_WARN` by default. @@ -90,7 +93,8 @@ while (!client.available()) { /* ... */ } Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below: ```C++ -SSLClient client(EthernetClient(), TAs, 2, A7); +EthernetClient baseClient; +SSLClient client(baseClient, TAs, (size_t)2, A7); // ... // connect to ardiuino.cc over ssl (port 443 for websites) client.connect("www.arduino.cc", 443); @@ -114,17 +118,19 @@ In order to use SSL session resumption: * You must reuse the same SSLClient object (SSL Sessions are stored in the object itself). * You must reconnect to the exact same server. -SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with `"www.google.com"`. However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection. +SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use the SSL session with that hostname. However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection. You can test whether or not a website can resume SSL Sessions using the [Session Example](./examples/Session_Example/Session_Example.ino) included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume. SSL sessions take a lot of memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration: ```C++ -SSLClient client(EthernetClient(), TAs, 2, A7); +EthernetClient baseClient; +SSLClient client(baseClient, TAs, (size_t)2, A7, SomeNumber); ``` Where `SomeNumber` is the number of sessions you would like to store. For example this declaration can store 3 sessions: ```C++ -SSLClient client(EthernetClient(), TAs, 2, A7); +EthernetClient baseClient; +SSLClient client(baseClient, TAs, (size_t)2, A7, 3); ``` Sessions are managed internally using the SSLSession::getSession function. This function will cycle through sessions in a rotating order, allowing the session cache to continually overwrite old sessions. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to. @@ -181,7 +187,7 @@ With this: ``` You may need to use `sudo` or administrator permissions to make this modification. We change `MAX_SOCK_NUM` and `ETHERNET_LARGE_BUFFERS` so the Ethernet hardware can allocate a larger space for SSLClient, however a downside of this modification is we are now only able to have two sockets concurrently. As most microprocessors barely have enough memory for one SSL connection, this limitation will rarely be encountered in practice. -### Random Data +### Seeding Random Data The SSL protocol requires that SSLClient generate some random bits before connecting with a server. BearSSL provides a random number generator but requires a [some entropy for a seed](https://bearssl.org/apidoc/bearssl__ssl_8h.html#a7d8e8de2afd49d6794eae02f56f81152). Normally this seed is generated by taking the microsecond time using the internal clock, however since most microcontrollers are not build with this feature another source must be found. As a simple solution, SSLClient uses a floating analog pin as an external source of random data, passed through to the constructor in the `analog_pin` argument. Before every connection, SSLClient will take the bottom byte from 16 analog reads on `analog_pin`, and combine these bytes into a 16 byte random number, which is used as a seed for BearSSL. To ensure the most random data, it is recommended that this analog pin be either floating or connected to a location not modifiable by the microcontroller (i.e. a battery voltage readout). ### Certificate Verification diff --git a/TrustAnchors.md b/TrustAnchors.md index a04e4cb..05cfa30 100644 --- a/TrustAnchors.md +++ b/TrustAnchors.md @@ -55,7 +55,7 @@ Once you've generated a trust anchor array, add it to your Arduino sketch using ```C++ #include "yourtrustanchorfile.h" // ... -SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin); +SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin); // ... ``` Where `yourtrustanchorfile.h` contains a generated trust anchor array names `TAs`, with length `TAs_NUM`. BearSSL will now automatically use these trust anchors when `SSLClient::connect` is called. \ No newline at end of file diff --git a/examples/EthernetHTTPS/EthernetHTTPS.ino b/examples/EthernetHTTPS/EthernetHTTPS.ino index 4ab030c..9250ced 100644 --- a/examples/EthernetHTTPS/EthernetHTTPS.ino +++ b/examples/EthernetHTTPS/EthernetHTTPS.ino @@ -42,7 +42,8 @@ const int rand_pin = A5; // Initialize the SSL client library // We input an EthernetClient, our trust anchors, and the analog pin -SSLClient client(EthernetClient(), TAs, (size_t)TAs_NUM, rand_pin); +EthernetClient base_client; +SSLClient client(base_client, TAs, (size_t)TAs_NUM, rand_pin); // Variables to measure the speed unsigned long beginMicros, endMicros; unsigned long byteCount = 0; @@ -95,8 +96,6 @@ void setup() { // specify the server and port, 443 is the standard port for HTTPS if (client.connect(server, 443)) { auto time = millis() - start; - Serial.print("connected to "); - Serial.println(client.remoteIP()); Serial.print("Took: "); Serial.println(time); // Make a HTTP request: diff --git a/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino index 08d919d..3c1d5a2 100644 --- a/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino +++ b/examples/EthernetMultiHTTPS/EthernetMultiHTTPS.ino @@ -44,7 +44,8 @@ const int rand_pin = A5; // Initialize the SSL client library // We input an EthernetClient, our trust anchors, and the analog pin // Additionally specify that we want to store 2 sessions since we are connecting to 2 domains -SSLClient client(EthernetClient(), TAs, (size_t)TAs_NUM, rand_pin); +EthernetClient base_client; +SSLClient client(base_client, TAs, (size_t)TAs_NUM, rand_pin); // Variables to measure the speed unsigned long beginMicros, endMicros; unsigned long byteCount = 0; @@ -146,8 +147,6 @@ void connectSSL() { auto start = millis(); if (client.connect(server, 443)) { auto time = millis() - start; - Serial.print("connected to "); - Serial.println(client.remoteIP()); Serial.print("Took: "); Serial.println(time); // Make a HTTP request: diff --git a/src/SSLClientImpl.cpp b/src/SSLClient.cpp similarity index 85% rename from src/SSLClientImpl.cpp rename to src/SSLClient.cpp index a9cf890..783609a 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClient.cpp @@ -20,6 +20,7 @@ #include "SSLClient.h" +#if defined(ARDUINO_ARCH_SAMD) // system reset definitions static constexpr auto SYSRESETREQ = (1<<2); static constexpr auto VECTKEY = (0x05fa0000UL); @@ -29,6 +30,7 @@ static constexpr auto VECTKEY_MASK = (0x0000ffffUL); (*(uint32_t*)0xe000ed0cUL)=((*(uint32_t*)0xe000ed0cUL)&VECTKEY_MASK)|VECTKEY|SYSRESETREQ; while(1) { } } +#endif #ifdef __arm__ // should use uinstd.h to define sbrk but Due causes a conflict @@ -49,15 +51,22 @@ static int freeMemory() { #endif // __arm__ } -/* see SSLClientImpl.h */ -SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug) - : m_analog_pin(analog_pin) - , m_session_index(0) +/* see SSLClient.h */ +SSLClient::SSLClient( Client& client, + const br_x509_trust_anchor *trust_anchors, + const size_t trust_anchors_num, + const int analog_pin, + const size_t max_sessions, + const DebugLevel debug) + : m_client(client) + , m_sessions() + , m_max_sessions(max_sessions) + , m_analog_pin(analog_pin) , m_debug(debug) , m_is_connected(false) , m_write_idx(0) { - + + setTimeout(30*1000); // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); // initlalize the various bearssl libraries so they're ready to go when we connect @@ -69,8 +78,8 @@ SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); } -/* see SSLClientImpl.h*/ -int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { +/* see SSLClient.h*/ +int SSLClient::connect(IPAddress ip, uint16_t port) { const char* func_name = __func__; // connection check if (get_arduino_client().connected()) { @@ -89,11 +98,11 @@ int SSLClientImpl::connect_impl(IPAddress ip, uint16_t port) { return 0; } m_info("Base client connected!", func_name); - return m_start_ssl(NULL, get_session_impl(NULL, ip)); + return m_start_ssl(nullptr); } -/* see SSLClientImpl.h*/ -int SSLClientImpl::connect_impl(const char *host, uint16_t port) { +/* see SSLClient.h*/ +int SSLClient::connect(const char *host, uint16_t port) { const char* func_name = __func__; // connection check if (get_arduino_client().connected()) { @@ -105,15 +114,7 @@ int SSLClientImpl::connect_impl(const char *host, uint16_t port) { m_write_idx = 0; // first, if we have a session, check if we're trying to resolve the same host // as before - bool connect_ok; - SSLSession& ses = get_session_impl(host, INADDR_NONE); - if (ses.is_valid_session()) { - // if so, then connect using the stored session - m_info("Connecting using a cached IP", func_name); - connect_ok = get_arduino_client().connect(ses.get_ip(), port); - } - // else connect with the provided hostname - else connect_ok = get_arduino_client().connect(host, port); + const bool connect_ok = get_arduino_client().connect(host, port); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!connect_ok) { @@ -123,11 +124,11 @@ int SSLClientImpl::connect_impl(const char *host, uint16_t port) { } m_info("Base client connected!", func_name); // start ssl! - return m_start_ssl(host, ses); + return m_start_ssl(host, getSession(host)); } -/* see SSLClientImpl.h*/ -size_t SSLClientImpl::write_impl(const uint8_t *buf, size_t size) { +/* see SSLClient.h*/ +size_t SSLClient::write(const uint8_t *buf, size_t size) { const char* func_name = __func__; // check if the socket is still open and such if (!m_soft_connected(func_name) || !buf || !size) return 0; @@ -169,8 +170,8 @@ size_t SSLClientImpl::write_impl(const uint8_t *buf, size_t size) { return size; } -/* see SSLClientImpl.h*/ -int SSLClientImpl::available_impl() { +/* see SSLClient.h*/ +int SSLClient::available() { const char* func_name = __func__; // connection check if (!m_soft_connected(func_name)) return 0; @@ -190,10 +191,10 @@ int SSLClientImpl::available_impl() { return 0; } -/* see SSLClientImpl.h */ -int SSLClientImpl::read_impl(uint8_t *buf, size_t size) { +/* see SSLClient.h */ +int SSLClient::read(uint8_t *buf, size_t size) { // check that the engine is ready to read - if (available_impl() <= 0 || !size) return -1; + if (available() <= 0 || !size) return -1; // read the buffer, send the ack, and return the bytes read size_t alen; unsigned char* br_buf = br_ssl_engine_recvapp_buf(&m_sslctx.eng, &alen); @@ -205,10 +206,10 @@ int SSLClientImpl::read_impl(uint8_t *buf, size_t size) { return read_amount; } -/* see SSLClientImpl.h */ -int SSLClientImpl::peek_impl() { +/* see SSLClient.h */ +int SSLClient::peek() { // check that the engine is ready to read - if (available_impl() <= 0) return -1; + if (available() <= 0) return -1; // read the buffer, send the ack, and return the bytes read size_t alen; uint8_t read_num; @@ -217,15 +218,14 @@ int SSLClientImpl::peek_impl() { return (int)read_num; } -/* see SSLClientImpl.h */ -void SSLClientImpl::flush_impl() { +/* see SSLClient.h */ +void SSLClient::flush() { if (m_write_idx > 0) if(m_run_until(BR_SSL_RECVAPP) < 0) m_error("Could not flush write buffer!", __func__); } -/* see SSLClientImpl.h */ -void SSLClientImpl::stop_impl() { - const char* func_name = __func__; +/* see SSLClient.h */ +void SSLClient::stop() { // tell the SSL connection to gracefully close br_ssl_engine_close(&m_sslctx.eng); // if the engine isn't closed, and the socket is still open @@ -240,7 +240,7 @@ void SSLClientImpl::stop_impl() { */ size_t len; - if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != NULL) { + if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != nullptr) { br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); } } @@ -251,8 +251,8 @@ void SSLClientImpl::stop_impl() { m_is_connected = false; } -/* see SSLClientImpl.h */ -uint8_t SSLClientImpl::connected_impl() { +/* see SSLClient.h */ +uint8_t SSLClient::connected() { const char* func_name = __func__; // check all of the error cases const auto c_con = get_arduino_client().connected(); @@ -273,7 +273,7 @@ uint8_t SSLClientImpl::connected_impl() { // we are not connected m_is_connected = false; // set the write error so the engine doesn't try to close the connection - stop_impl(); + stop(); } else if (!wr_ok) { m_error("Not connected because write error is set", func_name); @@ -282,38 +282,32 @@ uint8_t SSLClientImpl::connected_impl() { return c_con && br_con; } -/* see SSLClientImpl.h */ -SSLSession& SSLClientImpl::get_session_impl(const char* host, const IPAddress& addr) { +/* see SSLClient.h */ +SSLSession* SSLClient::getSession(const char* host) { const char* func_name = __func__; // search for a matching session with the IP - int temp_index = m_get_session_index(host, addr); + int temp_index = m_get_session_index(host); // if none are availible, use m_session_index - if (temp_index == -1) { - temp_index = m_session_index; - // reset the session so we don't try to send one sites session to another - get_session_array()[temp_index].clear_parameters(); - } - // increment m_session_index so the session cache is a circular buffer - if (temp_index == m_session_index && ++m_session_index >= getSessionCount()) m_session_index = 0; + if (temp_index < 0) return nullptr; // return the pointed to value m_info("Using session index: ", func_name); m_info(temp_index, func_name); - return get_session_array()[temp_index]; + return &(m_sessions[temp_index]); } -/* see SSLClientImpl.h */ -void SSLClientImpl::remove_session_impl(const char* host, const IPAddress& addr) { +/* see SSLClient.h */ +void SSLClient::removeSession(const char* host) { const char* func_name = __func__; - int temp_index = m_get_session_index(host, addr); - if (temp_index != -1) { + int temp_index = m_get_session_index(host); + if (temp_index >= 0) { m_info(" Deleted session ", func_name); m_info(temp_index, func_name); - get_session_array()[temp_index].clear_parameters(); + m_sessions.erase(m_sessions.begin() + static_cast(temp_index)); } } -/* see SSLClientImpl.h */ -void SSLClientImpl::set_mutual_impl(const SSLClientParameters* params) { +/* see SSLClient.h */ +void SSLClient::setMutualAuthParams(const SSLClientParameters* params) { // if mutual authentication if needed, configure bearssl to support it. if (params != nullptr) br_ssl_client_set_single_ec( &m_sslctx, @@ -326,7 +320,7 @@ void SSLClientImpl::set_mutual_impl(const SSLClientParameters* params) { &br_ecdsa_i15_sign_asn1); } -bool SSLClientImpl::m_soft_connected(const char* func_name) { +bool SSLClient::m_soft_connected(const char* func_name) { // check if the socket is still open and such if (getWriteError()) { m_error("Cannot operate if the write error is not reset: ", func_name); @@ -343,8 +337,8 @@ bool SSLClientImpl::m_soft_connected(const char* func_name) { return true; } -/* see SSLClientImpl.h */ -int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { +/* see SSLClient.h */ +int SSLClient::m_start_ssl(const char* host, SSLSession* ssl_ses) { const char* func_name = __func__; // clear the write error setWriteError(SSL_OK); @@ -352,11 +346,12 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { // we want 128 bits to be safe, as recommended by the bearssl docs uint8_t rng_seeds[16]; // take the bottom 8 bits of the analog read - for (uint8_t i = 0; i < sizeof rng_seeds; i++) rng_seeds[i] = static_cast(analogRead(m_analog_pin)); + for (uint8_t i = 0; i < sizeof rng_seeds; i++) + rng_seeds[i] = static_cast(analogRead(m_analog_pin)); br_ssl_engine_inject_entropy(&m_sslctx.eng, rng_seeds, sizeof rng_seeds); // inject session parameters for faster reconnection, if we have any - if(ssl_ses.is_valid_session()) { - br_ssl_engine_set_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); + if(ssl_ses != nullptr) { + br_ssl_engine_set_session_parameters(&m_sslctx.eng, ssl_ses->to_br_session()); m_info("Set SSL session!", func_name); } // reset the engine, but make sure that it reset successfully @@ -379,24 +374,27 @@ int SSLClientImpl::m_start_ssl(const char* host, SSLSession& ssl_ses) { m_is_connected = true; // all good to go! the SSL socket should be up and running // overwrite the session we got with new parameters - br_ssl_engine_get_session_parameters(&m_sslctx.eng, ssl_ses.to_br_session()); - // print the cipher suite - m_info("Used cipher suite: ", func_name); - m_info(ssl_ses.cipher_suite, func_name); - // set the hostname and ip in the session as well - ssl_ses.set_parameters(remoteIP(), host); + if (ssl_ses != nullptr) + br_ssl_engine_get_session_parameters(&m_sslctx.eng, ssl_ses->to_br_session()); + else if (host != nullptr) { + if (m_sessions.size() >= m_max_sessions) + m_sessions.erase(m_sessions.begin()); + SSLSession session(host); + br_ssl_engine_get_session_parameters(&m_sslctx.eng, session.to_br_session()); + m_sessions.push_back(session); + } return 1; } -/* see SSLClientImpl.h*/ -int SSLClientImpl::m_run_until(const unsigned target) { +/* see SSLClient.h */ +int SSLClient::m_run_until(const unsigned target) { const char* func_name = __func__; unsigned lastState = 0; size_t lastLen = 0; const unsigned long start = millis(); for (;;) { unsigned state = m_update_engine(); - // error check + // error check if (state == BR_SSL_CLOSED || getWriteError() != SSL_OK) { return -1; } @@ -404,7 +402,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { if (millis() - start > getTimeout()) { m_error("SSL internals timed out! This could be an internal error, bad data sent from the server, or data being discarded due to a buffer overflow. If you are using Ethernet, did you modify the library properly (see README)?", func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop_impl(); + stop(); return -1; } // debug @@ -448,7 +446,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { */ if (state & BR_SSL_RECVAPP && target & BR_SSL_SENDAPP) { size_t len; - if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != NULL) { + if (br_ssl_engine_recvapp_buf(&m_sslctx.eng, &len) != nullptr) { m_write_idx = 0; m_warn("Discarded unread data to favor a write operation", func_name); br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); @@ -457,7 +455,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { else { m_error("SSL engine state is RECVAPP, however the buffer was null! (This is a problem with BearSSL internals)", func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop_impl(); + stop(); return -1; } } @@ -473,8 +471,8 @@ int SSLClientImpl::m_run_until(const unsigned target) { } } -/* see SSLClientImpl.h*/ -unsigned SSLClientImpl::m_update_engine() { +/* see SSLClient.h*/ +unsigned SSLClient::m_update_engine() { const char* func_name = __func__; for(;;) { // get the state @@ -491,26 +489,21 @@ unsigned SSLClientImpl::m_update_engine() { buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); wlen = get_arduino_client().write(buf, len); - // let the chip recover - if (wlen < 0) { - m_error("Error writing to m_client", func_name); - m_error(get_arduino_client().getWriteError(), func_name); - setWriteError(SSL_CLIENT_WRTIE_ERROR); - /* - * If we received a close_notify and we - * still send something, then we have our - * own response close_notify to send, and - * the peer is allowed by RFC 5246 not to - * wait for it. - */ - if (!&m_sslctx.eng.shutdown_recv) return 0; - stop_impl(); + if (wlen <= 0) { + // if the arduino client encountered an error + if (get_arduino_client().getWriteError() || !get_arduino_client().connected()) { + m_error("Error writing to m_client", func_name); + m_error(get_arduino_client().getWriteError(), func_name); + setWriteError(SSL_CLIENT_WRTIE_ERROR); + } + // else presumably the socket just closed itself, so just stop the engine + stop(); return 0; } if (wlen > 0) { br_ssl_engine_sendrec_ack(&m_sslctx.eng, wlen); } - continue; + continue; } /* @@ -525,7 +518,7 @@ unsigned SSLClientImpl::m_update_engine() { m_error(br_ssl_engine_current_state(&m_sslctx.eng), func_name); m_error(br_ssl_engine_last_error(&m_sslctx.eng), func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop_impl(); + stop(); return 0; } // else time to send the application data @@ -533,17 +526,17 @@ unsigned SSLClientImpl::m_update_engine() { size_t alen; unsigned char *buf = br_ssl_engine_sendapp_buf(&m_sslctx.eng, &alen); // engine check - if (alen == 0 || buf == NULL) { + if (alen == 0 || buf == nullptr) { m_error("Engine set write flag but returned null buffer", func_name); setWriteError(SSL_BR_WRITE_ERROR); - stop_impl(); + stop(); return 0; } // sanity check if (alen < m_write_idx) { m_error("Alen is less than m_write_idx", func_name); setWriteError(SSL_INTERNAL_ERROR); - stop_impl(); + stop(); return 0; } // all good? lets send the data @@ -570,8 +563,9 @@ unsigned SSLClientImpl::m_update_engine() { unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? const auto avail = get_arduino_client().available(); - if (avail > 0 && avail >= len) { + if (avail > 0 && static_cast(avail) >= len) { int mem = freeMemory(); +#if defined(ARDUINO_ARCH_SAMD) // check for a stack overflow // if the stack overflows we basically have to crash, and // hope the user is ok with that @@ -581,6 +575,7 @@ unsigned SSLClientImpl::m_update_engine() { // software reset RESET(); } +#endif // debug info m_info("Memory: ", func_name); m_info(mem, func_name); @@ -591,7 +586,7 @@ unsigned SSLClientImpl::m_update_engine() { if(mem < 7000) { m_error("Out of memory! Decrease the number of sessions or the size of m_iobuf", func_name); setWriteError(SSL_OUT_OF_MEMORY); - stop_impl(); + stop(); return 0; } // I suppose so! @@ -600,7 +595,7 @@ unsigned SSLClientImpl::m_update_engine() { m_error("Error reading bytes from m_client. Write Error: ", func_name); m_error(get_arduino_client().getWriteError(), func_name); setWriteError(SSL_CLIENT_WRTIE_ERROR); - stop_impl(); + stop(); return 0; } if (rlen > 0) { @@ -626,19 +621,14 @@ unsigned SSLClientImpl::m_update_engine() { } /* see SSLClientImpl.h */ -int SSLClientImpl::m_get_session_index(const char* host, const IPAddress& addr) const { +int SSLClient::m_get_session_index(const char* host) const { const char* func_name = __func__; + if(host == nullptr) return -1; // search for a matching session with the IP for (uint8_t i = 0; i < getSessionCount(); i++) { // if we're looking at a real session - if (get_session_array()[i].is_valid_session() - && ( - // and the hostname matches, or - (host != NULL && get_session_array()[i].get_hostname().equals(host)) - // there is no hostname and the IP address matches - || (host == NULL && addr == get_session_array()[i].get_ip()) - )) { - m_info(get_session_array()[i].get_hostname(), func_name); + if (m_sessions[i].get_hostname().equals(host)) { + m_info(m_sessions[i].get_hostname(), func_name); return i; } } @@ -646,8 +636,8 @@ int SSLClientImpl::m_get_session_index(const char* host, const IPAddress& addr) return -1; } -/* See SSLClientImpl.h */ -void SSLClientImpl::m_print_prefix(const char* func_name, const DebugLevel level) const +/* See SSLClient.h */ +void SSLClient::m_print_prefix(const char* func_name, const DebugLevel level) const { // print the sslclient prefix Serial.print("(SSLClient)"); @@ -664,8 +654,8 @@ void SSLClientImpl::m_print_prefix(const char* func_name, const DebugLevel level Serial.print("): "); } -/* See SSLClientImpl.h */ -void SSLClientImpl::m_print_ssl_error(const int ssl_error, const DebugLevel level) const { +/* See SSLClient.h */ +void SSLClient::m_print_ssl_error(const int ssl_error, const DebugLevel level) const { if (level > m_debug) return; m_print_prefix(__func__, level); switch(ssl_error) { @@ -679,8 +669,8 @@ void SSLClientImpl::m_print_ssl_error(const int ssl_error, const DebugLevel leve } } -/* See SSLClientImpl.h */ -void SSLClientImpl::m_print_br_error(const unsigned br_error_code, const DebugLevel level) const { +/* See SSLClient.h */ +void SSLClient::m_print_br_error(const unsigned br_error_code, const DebugLevel level) const { if (level > m_debug) return; m_print_prefix(__func__, level); switch (br_error_code) { @@ -744,4 +734,4 @@ void SSLClientImpl::m_print_br_error(const unsigned br_error_code, const DebugLe case BR_ERR_X509_NOT_TRUSTED: Serial.println("Chain could not be linked to a trust anchor."); break; default: Serial.println("Unknown error code."); break; } -} \ No newline at end of file +} diff --git a/src/SSLClient.h b/src/SSLClient.h index 6c635e1..89954cb 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -19,10 +19,10 @@ */ #include "Client.h" -#include "SSLClientImpl.h" #include "SSLSession.h" #include "SSLClientParameters.h" #include "SSLObj.h" +#include #ifndef SSLClient_H_ #define SSLClient_H_ @@ -32,26 +32,49 @@ * Check out README.md for more info. */ -template -class SSLClient : public SSLClientImpl { -/* - * static checks - * I'm a java developer, so I want to ensure that my inheritance is safe. - * These checks ensure that all the functions we use on class C are - * actually present on class C. It does this by checking that the - * class inherits from Client. - * - * Additionally, I ran into a lot of memory issues with large sessions caches. - * Since each session contains at max 352 bytes of memory, they eat of the - * stack quite quickly and can cause overflows. As a result, I have added a - * warning here to discourage the use of more than 3 sessions at a time. Any - * amount past that will require special modification of this library, and - * assumes you know what you are doing. - */ -static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!"); -static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur."); - +class SSLClient : public Client { public: + /** + * @brief Static constants defining the possible errors encountered. + * + * If SSLClient encounters an error, it will generally output + * logs into the serial monitor. If you need a way of programmatically + * checking the errors, you can do so with SSLClient::getWriteError(), + * which will return one of these values. + */ + enum Error { + SSL_OK = 0, + /** The underlying client failed to connect, probably not an issue with SSL */ + SSL_CLIENT_CONNECT_FAIL, + /** BearSSL failed to complete the SSL handshake, check logs for bear ssl error output */ + SSL_BR_CONNECT_FAIL, + /** The underlying client failed to write a payload, probably not an issue with SSL */ + SSL_CLIENT_WRTIE_ERROR, + /** An internal error occurred with BearSSL, check logs for diagnosis. */ + SSL_BR_WRITE_ERROR, + /** An internal error occurred with SSLClient, and you probably need to submit an issue on Github. */ + SSL_INTERNAL_ERROR, + /** SSLClient detected that there was not enough memory (>8000 bytes) to continue. */ + SSL_OUT_OF_MEMORY + }; + + /** + * @brief Level of verbosity used in logging for SSLClient. + * + * Use these values when initializing SSLClient to set how many logs you + * would like to see in the Serial monitor. + */ + enum DebugLevel { + /** No logging output */ + SSL_NONE = 0, + /** Only output errors that result in connection failure */ + SSL_ERROR = 1, + /** Output errors and warnings (useful when just starting to develop) */ + SSL_WARN = 2, + /** Output errors, warnings, and internal information (very verbose) */ + SSL_INFO = 3, + }; + /** * @brief Initialize SSLClient with all of the prerequisites needed. * @@ -66,25 +89,18 @@ public: * of the SSL server certificate. Check out TrustAnchors.md for more info. * @param trust_anchors_num The number of objects in the trust_anchors array. * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG. + * @param max_sessions The maximum number of SSL sessions to store connection information from. * @param debug The level of debug logging (use the ::DebugLevel enum). - * @param mutual_auth_params Configuration to use for mutual authentication, nullptr to disable mutual auth. (see ::SSLClientParameters). */ - explicit SSLClient( const C& client, + explicit SSLClient( Client& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, - const DebugLevel debug = SSL_WARN) - : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug) - , m_client(client) - , m_sessions{} - { - // set the timeout to a reasonable number (it can always be changes later) - // SSL Connections take a really long time so we don't want to time out a legitimate thing - setTimeout(30 * 1000); - } + const size_t max_sessions = 1, + const DebugLevel debug = SSL_WARN); //======================================== - //= Functions implemented in SSLClientImpl + //= Functions implemented in SSLClient.cpp //======================================== /** @@ -126,7 +142,7 @@ public: * @param port the port to connect to * @returns 1 if success, 0 if failure */ - int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); } + int connect(IPAddress ip, uint16_t port) override; /** * @brief Connect over SSL to a host specified by a hostname. @@ -164,10 +180,8 @@ public: * @param port The port to connect to on the host (443 for HTTPS) * @returns 1 of success, 0 if failure */ - int connect(const char *host, uint16_t port) override { return connect_impl(host, port); } + int connect(const char *host, uint16_t port) override; - /** @see SSLClient::write(uint8_t*, size_t) */ - size_t write(uint8_t b) override { return write_impl(&b, 1); } /** * @brief Write some bytes to the SSL connection * @@ -191,7 +205,9 @@ public: * @returns The number of bytes copied to the buffer (size), or zero if the BearSSL engine * fails to become ready for writing data. */ - size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); } + size_t write(const uint8_t *buf, size_t size) override; + /** @see SSLClient::write(uint8_t*, size_t) */ + size_t write(uint8_t b) override { return write(&b, 1); } /** * @brief Returns the number of bytes available to read from the data that has been received and decrypted. @@ -211,13 +227,8 @@ public: * @returns The number of bytes available (can be zero), or zero if any of the pre * conditions aren't satisfied. */ - int available() override { return available_impl(); } + int available() override; - /** - * @brief Read a single byte, or -1 if none is available. - * @see SSLClient::read(uint8_t*, size_t) - */ - int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; }; /** * @brief Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. * @@ -239,7 +250,12 @@ public: * * @returns The number of bytes copied (<= size), or -1 if the preconditions are not satisfied. */ - int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); } + int read(uint8_t *buf, size_t size) override; + /** + * @brief Read a single byte, or -1 if none is available. + * @see SSLClient::read(uint8_t*, size_t) + */ + int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; }; /** * @brief View the first byte of the buffer, without removing it from the SSLClient Buffer @@ -249,7 +265,7 @@ public: * @returns The first byte received, or -1 if the preconditions are not satisfied (warning: * do not use if your data may be -1, as the return value is ambiguous) */ - int peek() override { return peek_impl(); } + int peek() override; /** * @brief Force writing the buffered bytes from SSLClient::write to the network. @@ -258,7 +274,7 @@ public: * an explanation of how writing with SSLClient works, please see SSLClient::write. * The implementation for this function can be found in SSLClientImpl::flush. */ - void flush() override { return flush_impl(); } + void flush() override; /** * @brief Close the connection @@ -268,7 +284,7 @@ public: * error was encountered previously, this function will simply call m_client::stop. * The implementation for this function can be found in SSLClientImpl::peek. */ - void stop() override { return stop_impl(); } + void stop() override; /** * @brief Check if the device is connected. @@ -283,7 +299,7 @@ public: * * @returns 1 if connected, 0 if not */ - uint8_t connected() override { return connected_impl(); } + uint8_t connected() override; //======================================== //= Functions Not in the Client Interface @@ -297,7 +313,7 @@ public: * * @pre SSLClient has not already started an SSL connection. */ - void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); } + void setMutualAuthParams(const SSLClientParameters* params); /** * @brief Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist @@ -311,26 +327,26 @@ public: * * @param host A hostname c string, or NULL if one is not available * @param addr An IP address - * @returns A reference to an SSLSession object + * @returns A pointer to the SSLSession, or NULL of none matched the criteria available */ - SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); } + SSLSession* getSession(const char* host); /** * @brief Clear the session corresponding to a host and IP * * The implementation for this function can be found at SSLClientImpl::remove_session_impl. * - * @param host A hostname c string, or NULL if one is not available + * @param host A hostname c string, or nullptr if one is not available * @param addr An IP address */ - void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); } + void removeSession(const char* host); /** * @brief Get the maximum number of SSL sessions that can be stored at once * * @returns The SessionCache template parameter. */ - size_t getSessionCount() const override { return SessionCache; } + size_t getSessionCount() const { return m_sessions.size(); } /** * @brief Equivalent to SSLClient::connected() > 0 @@ -338,37 +354,92 @@ public: * @returns true if connected, false if not */ operator bool() { return connected() > 0; } - /** @see SSLClient::operator bool */ - bool operator==(const bool value) { return bool() == value; } - /** @see SSLClient::operator bool */ - bool operator!=(const bool value) { return bool() != value; } - /** @brief Returns whether or not two SSLClient objects have the same underlying client object */ - bool operator==(const C& rhs) { return m_client == rhs; } - /** @brief Returns whether or not two SSLClient objects do not have the same underlying client object */ - bool operator!=(const C& rhs) { return m_client != rhs; } - /** @brief Returns the local port, if C::localPort exists */ - uint16_t localPort() override { return m_client.localPort(); } - /** @brief Returns the remote IP, if C::remoteIP exists. */ - IPAddress remoteIP() override { return m_client.remoteIP(); } - /** @brief Returns the remote port, if C::remotePort exists. Else return 0. */ - uint16_t remotePort() override { return m_client.remotePort(); } /** @brief Returns a reference to the client object stored in this class. Take care not to break it. */ - C& getClient() { return m_client; } - -protected: - /** @brief Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl */ - Client& get_arduino_client() override { return m_client; } - const Client& get_arduino_client() const override { return m_client; } - /** @brief Returns an instance of the session array that is on the stack */ - SSLSession* get_session_array() override { return m_sessions; } - const SSLSession* get_session_array() const override { return m_sessions; } + Client& getClient() { return m_client; } private: + /** @brief Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl */ + Client& get_arduino_client() { return m_client; } + const Client& get_arduino_client() const { return m_client; } + + /** Returns whether or not the engine is connected, without polling the client over SPI or other (as opposed to connected()) */ + bool m_soft_connected(const char* func_name); + /** start the ssl engine on the connected client */ + int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr); + /** run the bearssl engine until a certain state */ + int m_run_until(const unsigned target); + /** proxy for available that returns the state */ + unsigned m_update_engine(); + /** utility function to find a session index based off of a host and IP */ + int m_get_session_index(const char* host) const; + + /** @brief Prints a debugging prefix to all logs, so we can attatch them to useful information */ + void m_print_prefix(const char* func_name, const DebugLevel level) const; + + /** @brief Prints the string associated with a write error */ + void m_print_ssl_error(const int ssl_error, const DebugLevel level) const; + + /** @brief Print the text string associated with a BearSSL error code */ + void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const; + + /** @brief debugging print function, only prints if m_debug is true */ + template + void m_print(const T str, const char* func_name, const DebugLevel level) const { + // check the current debug level and serial status + if (level > m_debug || !Serial) return; + // print prefix + m_print_prefix(func_name, level); + // print the message + Serial.println(str); + } + + /** @brief Prints a info message to serial, if info messages are enabled */ + template + void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); } + + template + void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); } + + template + void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); } + + //============================================ + //= Data Members + //============================================ // create a copy of the client - C m_client; + Client& m_client; // also store an array of SSLSessions, so we can resume communication with multiple websites - SSLSession m_sessions[SessionCache]; + std::vector m_sessions; + // as well as the maximmum number of sessions we can store + const size_t m_max_sessions; + // store the pin to fetch an RNG see from + const int m_analog_pin; + // store whether to enable debug logging + const DebugLevel m_debug; + // store if we are connected in bearssl or not + bool m_is_connected; + // store the context values required for SSL + br_ssl_client_context m_sslctx; + br_x509_minimal_context m_x509ctx; + // use a mono-directional buffer by default to cut memory in half + // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI + // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically + // simply edit this value to change the buffer size to the desired value + // additionally, we need to correct buffer size based off of how many sessions we decide to cache + // since SSL takes so much memory if we don't it will cause the stack and heap to collide + /** + * @brief The internal buffer to use with BearSSL. + * This buffer controls how much data BearSSL can encrypt/decrypt at a given time. It can be expanded + * or shrunk to [255, BR_SSL_BUFSIZE_BIDI], depending on the memory and speed needs of your application. + * As a rule of thumb SSLClient will fail if it does not have at least 8000 bytes when starting a + * connection. + */ + unsigned char m_iobuf[2048]; + // store the index of where we are writing in the buffer + // so we can send our records all at once to prevent + // weird timing issues + size_t m_write_idx; }; #endif /** SSLClient_H_ */ \ No newline at end of file diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h deleted file mode 100644 index 931ad77..0000000 --- a/src/SSLClientImpl.h +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright 2019 OSU OPEnS Lab - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the "Software"), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "bearssl.h" -#include "Arduino.h" -#include "Client.h" -#include "SSLSession.h" -#include "SSLClientParameters.h" - -#ifndef SSLClientImpl_H_ -#define SSLClientImpl_H_ - -/** - * @brief Static constants defining the possible errors encountered. - * - * If SSLClient encounters an error, it will generally output - * logs into the serial monitor. If you need a way of programmatically - * checking the errors, you can do so with SSLClient::getWriteError(), - * which will return one of these values. - */ -enum Error { - SSL_OK = 0, - /** The underlying client failed to connect, probably not an issue with SSL */ - SSL_CLIENT_CONNECT_FAIL, - /** BearSSL failed to complete the SSL handshake, check logs for bear ssl error output */ - SSL_BR_CONNECT_FAIL, - /** The underlying client failed to write a payload, probably not an issue with SSL */ - SSL_CLIENT_WRTIE_ERROR, - /** An internal error occurred with BearSSL, check logs for diagnosis. */ - SSL_BR_WRITE_ERROR, - /** An internal error occurred with SSLClient, and you probably need to submit an issue on Github. */ - SSL_INTERNAL_ERROR, - /** SSLClient detected that there was not enough memory (>8000 bytes) to continue. */ - SSL_OUT_OF_MEMORY -}; - -/** - * @brief Level of verbosity used in logging for SSLClient. - * - * Use these values when initializing SSLClient to set how many logs you - * would like to see in the Serial monitor. - */ -enum DebugLevel { - /** No logging output */ - SSL_NONE = 0, - /** Only output errors that result in connection failure */ - SSL_ERROR = 1, - /** Output errors and warnings (useful when just starting to develop) */ - SSL_WARN = 2, - /** Output errors, warnings, and internal information (very verbose) */ - SSL_INFO = 3, -}; - -/** @brief Implementation code to be inherited by SSLClient */ -class SSLClientImpl : public Client { -public: - /** @see SSLClient::SSLClient */ - explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, - const DebugLevel debug); - - /** @see SSLClient::SSLClient */ - explicit SSLClientImpl(const br_x509_trust_anchor *trust_anchors, - const size_t trust_anchors_num, const int analog_pin, - const DebugLevel debug, const SSLClientParameters* mutual_auth_params); - - //============================================ - //= Functions implemented in SSLClientImpl.cpp - //============================================ - - /** @see SSLClient::connect(IPAddress, uint16_t) */ - int connect_impl(IPAddress ip, uint16_t port); - /** @see SSLClient::connect(const char*, uint16_t) */ - int connect_impl(const char *host, uint16_t port); - /** @see SSLClient::write(const uint8_t*, size_t) */ - size_t write_impl(const uint8_t *buf, size_t size); - /** @see SSLClient::available */ - int available_impl(); - /** @see SSLClient::read(uint8_t*, size_t) */ - int read_impl(uint8_t *buf, size_t size); - /** @see SSLClient::peek */ - int peek_impl(); - /** @see SSLClient::flush */ - void flush_impl(); - /** @see SSLClient::stop */ - void stop_impl(); - /** @see SSLClient::connected */ - uint8_t connected_impl(); - /** @see SSLClient::getSession */ - SSLSession& get_session_impl(const char* host, const IPAddress& addr); - /** @see SSLClient::removeSession */ - void remove_session_impl(const char* host, const IPAddress& addr); - /** @see SSLClient::setMutualAuthParams */ - void set_mutual_impl(const SSLClientParameters* params); - //============================================ - //= Functions implemented in SSLClient.h - //============================================ - /** @see SSLClient::localPort */ - virtual uint16_t localPort() = 0; - /** @see SSLClient::remoteIP */ - virtual IPAddress remoteIP() = 0; - /** @see SSLClient::localPort */ - virtual uint16_t remotePort() = 0; - /** @see SSLClient::getSessionCount */ - virtual size_t getSessionCount() const = 0; - -protected: - /** @see SSLClient::get_arduino_client */ - virtual Client& get_arduino_client() = 0; - virtual const Client& get_arduino_client() const = 0; - /** @see SSLClient::get_session_array */ - virtual SSLSession* get_session_array() = 0; - virtual const SSLSession* get_session_array() const = 0; - - //============================================ - //= Functions implemented in SSLClientImpl.cpp - //============================================ - - /** @brief Prints a debugging prefix to all logs, so we can attatch them to useful information */ - void m_print_prefix(const char* func_name, const DebugLevel level) const; - - /** @brief Prints the string associated with a write error */ - void m_print_ssl_error(const int ssl_error, const DebugLevel level) const; - - /** @brief Print the text string associated with a BearSSL error code */ - void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const; - - /** @brief debugging print function, only prints if m_debug is true */ - template - void m_print(const T str, const char* func_name, const DebugLevel level) const { - // check the current debug level and serial status - if (level > m_debug || !Serial) return; - // print prefix - m_print_prefix(func_name, level); - // print the message - Serial.println(str); - } - - /** @brief Prints a info message to serial, if info messages are enabled */ - template - void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); } - - template - void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); } - - template - void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); } - -private: - /** Returns whether or not the engine is connected, without polling the client over SPI or other (as opposed to connected()) */ - bool m_soft_connected(const char* func_name); - /** start the ssl engine on the connected client */ - int m_start_ssl(const char* host, SSLSession& ssl_ses); - /** run the bearssl engine until a certain state */ - int m_run_until(const unsigned target); - /** proxy for available that returns the state */ - unsigned m_update_engine(); - /** utility function to find a session index based off of a host and IP */ - int m_get_session_index(const char* host, const IPAddress& addr) const; - - //============================================ - //= Data Members - //============================================ - - // store the pin to fetch an RNG see from - const int m_analog_pin; - // store an index of where a new session can be placed if we don't have any corresponding sessions - size_t m_session_index; - // store whether to enable debug logging - const DebugLevel m_debug; - // store if we are connected in bearssl or not - bool m_is_connected; - // store the context values required for SSL - br_ssl_client_context m_sslctx; - br_x509_minimal_context m_x509ctx; - // use a mono-directional buffer by default to cut memory in half - // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI - // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically - // simply edit this value to change the buffer size to the desired value - // additionally, we need to correct buffer size based off of how many sessions we decide to cache - // since SSL takes so much memory if we don't it will cause the stack and heap to collide - /** - * @brief The internal buffer to use with BearSSL. - * This buffer controls how much data BearSSL can encrypt/decrypt at a given time. It can be expanded - * or shrunk to [255, BR_SSL_BUFSIZE_BIDI], depending on the memory and speed needs of your application. - * As a rule of thumb SSLClient will fail if it does not have at least 8000 bytes when starting a - * connection. - */ - unsigned char m_iobuf[2048]; - // store the index of where we are writing in the buffer - // so we can send our records all at once to prevent - // weird timing issues - size_t m_write_idx; -}; - -#endif /* SSLClientImpl_H_ */ \ No newline at end of file diff --git a/src/SSLSession.cpp b/src/SSLSession.cpp deleted file mode 100644 index 6338ad3..0000000 --- a/src/SSLSession.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "SSLSession.h" - -/* See SSLSession.h */ -void SSLSession::set_parameters(const IPAddress& ip, const char* hostname) { - // copy the hostname - if (hostname != NULL) m_hostname = hostname; - // or if there's no hostname, clear the string - else m_hostname = ""; - // and the IP address - m_ip = ip; - // check if both values are valid, and if so set valid to true - if (m_ip != INADDR_NONE && session_id_len > 0 - && (hostname == NULL || m_hostname)) m_valid_session = true; - // else clear - else clear_parameters(); -} - -/* see SSLSession.h */ -void SSLSession::clear_parameters() { - // clear the hostname , ip, and valid session flags - m_hostname = ""; - m_ip = INADDR_NONE; - m_valid_session = false; -} \ No newline at end of file diff --git a/src/SSLSession.h b/src/SSLSession.h index ef6e997..aa413b1 100644 --- a/src/SSLSession.h +++ b/src/SSLSession.h @@ -27,7 +27,6 @@ #include "bearssl.h" #include "Arduino.h" -#include "IPAddress.h" #ifndef SSLSession_H_ #define SSLSession_H_ @@ -57,13 +56,8 @@ public: * * Sets all parameters to zero, and invalidates the session */ - SSLSession() - : m_valid_session(false) - , m_hostname() - , m_ip(INADDR_NONE) {} - - /** @brief use clear_parameters or set_parameters instead */ - SSLSession& operator=(const SSLSession&) = delete; + SSLSession(const char* hostname) + : m_hostname(hostname) {} /** * @brief Get the hostname string associated with this session @@ -75,57 +69,12 @@ public: */ const String& get_hostname() const { return m_hostname; } - /** - * @brief Get ::IPAddress associated with this session - * - * @returns A ::IPAddress object, #INADDR_NONE if there is no IP - * @pre must check isValidSession before getting this value, - * as if this session in invalid this value is not guarenteed - * to be reset to #INADDR_NONE. - */ - const IPAddress& get_ip() const { return m_ip; } - - bool is_valid_session() const { return m_valid_session; } - - /** - * @brief Set the ip address and hostname of the session. - * - * This function stores the ip Address object and hostname object into - * the session object. If hostname is not null or ip address is - * not blank, and the ::br_ssl_session_parameters values are non-zero - * it then validates the session. - * - * @pre You must call - * ::br_ssl_engine_get_session_parameters - * with this session before calling this function. This is because - * there is no way to completely validate the ::br_ssl_session_parameters - * and the session may end up in a corrupted state if this is not observed. - * - * @param ip The IP address of the host associated with the session - * @param hostname The string hostname ("www.google.com") associated with the session. - * Take care that this value is corrent, SSLSession performs no validation - * of the hostname. - */ - void set_parameters(const IPAddress& ip, const char* hostname = NULL); - - /** - * @brief Delete the parameters and invalidate the session. - * - * Roughly equivalent to this_session = SSLSession(), however - * this function preserves the String object, allowing it - * to better handle the dynamic memory needed. - */ - void clear_parameters(); - /** @brief Returns a pointer to the ::br_ssl_session_parameters component of this class. */ br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; } private: - bool m_valid_session; // aparently a hostname has a max length of 256 chars. Go figure. String m_hostname; - // store the IP Address we connected to - IPAddress m_ip; }; diff --git a/src/config.h b/src/config.h index ad4969f..d7c2e19 100644 --- a/src/config.h +++ b/src/config.h @@ -133,8 +133,8 @@ * returned value (a 'time_t') is an integer that counts time in seconds * since the Unix Epoch (Jan 1st, 1970, 00:00 UTC). * -#define BR_USE_UNIX_TIME 1 */ +#define BR_USE_UNIX_TIME 0 /* * When BR_USE_WIN32_TIME is enabled, the X.509 validation engine obtains @@ -143,9 +143,8 @@ * * Note: if both BR_USE_UNIX_TIME and BR_USE_WIN32_TIME are defined, the * former takes precedence. - * -#define BR_USE_WIN32_TIME 1 */ +#define BR_USE_WIN32_TIME 0 /* * When BR_ARMEL_CORTEXM_GCC is enabled, some operations are replaced with From ab9a195124af6ab309784f6055acff4a90a9ff6b Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 7 Nov 2019 12:10:00 -0800 Subject: [PATCH 085/205] updated doxygen --- docs/html/_s_s_l_client_8cpp.html | 130 ++ docs/html/_s_s_l_client_8cpp.js | 4 + docs/html/_s_s_l_client_8h.html | 27 +- docs/html/_s_s_l_client_8h_source.html | 75 +- docs/html/_s_s_l_session_8h.html | 1 - docs/html/_s_s_l_session_8h_source.html | 13 +- docs/html/annotated.html | 5 +- docs/html/annotated_dup.js | 1 - docs/html/class_s_s_l_client-members.html | 85 +- docs/html/class_s_s_l_client.html | 1080 +++++------------ docs/html/class_s_s_l_client.js | 62 +- docs/html/class_s_s_l_client.png | Bin 861 -> 380 bytes docs/html/class_s_s_l_session-members.html | 11 +- docs/html/class_s_s_l_session.html | 171 +-- docs/html/class_s_s_l_session.js | 7 +- docs/html/classes.html | 8 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 8 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.js | 8 +- docs/html/files.html | 18 +- docs/html/functions.html | 180 +-- docs/html/functions_enum.html | 109 ++ docs/html/functions_eval.html | 136 +++ docs/html/functions_func.html | 183 +-- docs/html/globals.html | 84 +- docs/html/globals_defs.html | 3 - docs/html/globals_vars.html | 2 +- docs/html/hierarchy.html | 9 +- docs/html/hierarchy.js | 4 +- docs/html/index.html | 28 +- ...ibraries__s_s_l_client__trust_anchors.html | 4 +- docs/html/menudata.js | 36 +- docs/html/navtreedata.js | 8 +- docs/html/navtreeindex0.js | 208 ++-- docs/html/search/all_0.js | 2 +- docs/html/search/all_1.js | 3 +- docs/html/search/all_10.js | 3 +- docs/html/search/all_11.js | 2 +- docs/html/search/all_3.js | 7 +- docs/html/search/all_4.js | 2 +- docs/html/search/all_5.js | 2 +- docs/html/search/all_6.js | 3 +- docs/html/search/all_7.js | 10 +- docs/html/search/all_8.js | 3 +- docs/html/search/all_9.js | 2 +- docs/html/search/all_a.js | 9 +- docs/html/search/all_b.js | 6 +- docs/html/search/all_c.js | 6 +- docs/html/search/all_d.js | 36 +- docs/html/search/all_e.js | 44 +- docs/html/search/all_f.js | 10 +- docs/html/search/classes_0.js | 1 - docs/html/search/defines_4.js | 3 +- docs/html/search/enums_0.js | 2 +- docs/html/search/enums_1.js | 2 +- docs/html/search/enumvalues_0.js | 22 +- docs/html/search/files_3.js | 4 +- docs/html/search/functions_0.js | 3 +- docs/html/search/functions_2.js | 7 +- docs/html/search/functions_3.js | 3 +- docs/html/search/functions_4.js | 10 +- docs/html/search/functions_5.js | 2 +- docs/html/search/functions_6.js | 2 +- docs/html/search/functions_7.js | 9 +- docs/html/search/functions_8.js | 6 +- docs/html/search/functions_9.js | 6 +- docs/html/search/functions_a.js | 7 +- docs/html/search/functions_b.js | 9 +- docs/html/search/searchdata.js | 4 +- docs/html/search/variables_0.js | 2 +- docs/html/struct_s_s_l_client_parameters.html | 2 +- 70 files changed, 1131 insertions(+), 1833 deletions(-) create mode 100644 docs/html/_s_s_l_client_8cpp.html create mode 100644 docs/html/_s_s_l_client_8cpp.js create mode 100644 docs/html/functions_enum.html create mode 100644 docs/html/functions_eval.html diff --git a/docs/html/_s_s_l_client_8cpp.html b/docs/html/_s_s_l_client_8cpp.html new file mode 100644 index 0000000..2717c69 --- /dev/null +++ b/docs/html/_s_s_l_client_8cpp.html @@ -0,0 +1,130 @@ + + + + + + + +SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClient.cpp File Reference + + + + + + + + + + + + + + +
          +
          + + + + + + +
          +
          SSLClient +  v1.3.0 +
          +
          Add TLS 1.2 functionality to any network library.
          +
          +
          + + + + + + + +
          +
          + +
          +
          +
          + +
          + +
          +
          + + +
          + +
          + +
          + +
          +
          SSLClient.cpp File Reference
          +
          +
          +
          #include "SSLClient.h"
          +
          + + + +

          +Variables

          char * __brkval
           
          +

          Variable Documentation

          + +

          ◆ __brkval

          + +
          +
          + + + + +
          char* __brkval
          +
          + +
          +
          +
          +
          + + + + diff --git a/docs/html/_s_s_l_client_8cpp.js b/docs/html/_s_s_l_client_8cpp.js new file mode 100644 index 0000000..b150c92 --- /dev/null +++ b/docs/html/_s_s_l_client_8cpp.js @@ -0,0 +1,4 @@ +var _s_s_l_client_8cpp = +[ + [ "__brkval", "_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56", null ] +]; \ No newline at end of file diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index e4a92cf..dc0f248 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -88,46 +88,25 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h.html','');});
          SSLClient.h File Reference
          #include "Client.h"
          -#include "SSLClientImpl.h"
          #include "SSLSession.h"
          #include "SSLClientParameters.h"
          #include "SSLObj.h"
          +#include <vector>

          Go to the source code of this file.

          - + -

          Classes

          class  SSLClient< C, SessionCache >
          class  SSLClient
           The main SSLClient class. Check out README.md for more info. More...
           
          - - -

          -Macros

          #define SSLClient_H_
           
          -

          Macro Definition Documentation

          - -

          ◆ SSLClient_H_

          - -
          -
          - - - - -
          #define SSLClient_H_
          -
          - -
          -
          diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index ca4b889..a4e47ee 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -91,55 +91,40 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
          SSLClient.h
          -Go to the documentation of this file.
          1 /* Copyright 2019 OSU OPEnS Lab
          2  *
          3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
          4  * software and associated documentation files (the "Software"), to deal in the Software
          5  * without restriction, including without limitation the rights to use, copy, modify,
          6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
          7  * permit persons to whom the Software is furnished to do so, subject to the following
          8  * conditions:
          9  *
          10  * The above copyright notice and this permission notice shall be included in all
          11  * copies or substantial portions of the Software.
          12  *
          13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
          14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
          15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
          16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
          17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
          18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
          19  */
          20 
          21 #include "Client.h"
          22 #include "SSLClientImpl.h"
          23 #include "SSLSession.h"
          24 #include "SSLClientParameters.h"
          25 #include "SSLObj.h"
          26 
          27 #ifndef SSLClient_H_
          28 #define SSLClient_H_
          29 
          35 template <class C, size_t SessionCache = 1>
          36 class SSLClient : public SSLClientImpl {
          37 /*
          38  * static checks
          39  * I'm a java developer, so I want to ensure that my inheritance is safe.
          40  * These checks ensure that all the functions we use on class C are
          41  * actually present on class C. It does this by checking that the
          42  * class inherits from Client.
          43  *
          44  * Additionally, I ran into a lot of memory issues with large sessions caches.
          45  * Since each session contains at max 352 bytes of memory, they eat of the
          46  * stack quite quickly and can cause overflows. As a result, I have added a
          47  * warning here to discourage the use of more than 3 sessions at a time. Any
          48  * amount past that will require special modification of this library, and
          49  * assumes you know what you are doing.
          50  */
          51 static_assert(SessionCache > 0 && SessionCache < 255, "There can be no less than one and no more than 255 sessions in the cache!");
          52 static_assert(SessionCache <= 3, "You need to decrease the size of m_iobuf in order to have more than 3 sessions at once, otherwise memory issues will occur.");
          53 
          54 public:
          72  explicit SSLClient( const C& client,
          73  const br_x509_trust_anchor *trust_anchors,
          74  const size_t trust_anchors_num,
          75  const int analog_pin,
          76  const DebugLevel debug = SSL_WARN)
          77  : SSLClientImpl(trust_anchors, trust_anchors_num, analog_pin, debug)
          78  , m_client(client)
          79  , m_sessions{}
          80  {
          81  // set the timeout to a reasonable number (it can always be changes later)
          82  // SSL Connections take a really long time so we don't want to time out a legitimate thing
          83  setTimeout(30 * 1000);
          84  }
          85 
          86  //========================================
          87  //= Functions implemented in SSLClientImpl
          88  //========================================
          89 
          129  int connect(IPAddress ip, uint16_t port) override { return connect_impl(ip, port); }
          130 
          167  int connect(const char *host, uint16_t port) override { return connect_impl(host, port); }
          168 
          170  size_t write(uint8_t b) override { return write_impl(&b, 1); }
          194  size_t write(const uint8_t *buf, size_t size) override { return write_impl(buf, size); }
          195 
          214  int available() override { return available_impl(); }
          215 
          220  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
          242  int read(uint8_t *buf, size_t size) override { return read_impl(buf, size); }
          243 
          252  int peek() override { return peek_impl(); }
          253 
          261  void flush() override { return flush_impl(); }
          262 
          271  void stop() override { return stop_impl(); }
          272 
          286  uint8_t connected() override { return connected_impl(); }
          287 
          288  //========================================
          289  //= Functions Not in the Client Interface
          290  //========================================
          291 
          300  void setMutualAuthParams(const SSLClientParameters* params) { return set_mutual_impl(params); }
          301 
          316  SSLSession& getSession(const char* host, const IPAddress& addr) { return get_session_impl(host, addr); }
          317 
          326  void removeSession(const char* host, const IPAddress& addr) { return remove_session_impl(host, addr); }
          327 
          333  size_t getSessionCount() const override { return SessionCache; }
          334 
          340  operator bool() { return connected() > 0; }
          342  bool operator==(const bool value) { return bool() == value; }
          344  bool operator!=(const bool value) { return bool() != value; }
          346  bool operator==(const C& rhs) { return m_client == rhs; }
          348  bool operator!=(const C& rhs) { return m_client != rhs; }
          350  uint16_t localPort() override { return m_client.localPort(); }
          352  IPAddress remoteIP() override { return m_client.remoteIP(); }
          354  uint16_t remotePort() override { return m_client.remotePort(); }
          355 
          357  C& getClient() { return m_client; }
          358 
          359 protected:
          361  Client& get_arduino_client() override { return m_client; }
          362  const Client& get_arduino_client() const override { return m_client; }
          364  SSLSession* get_session_array() override { return m_sessions; }
          365  const SSLSession* get_session_array() const override { return m_sessions; }
          366 
          367 private:
          368  // create a copy of the client
          369  C m_client;
          370  // also store an array of SSLSessions, so we can resume communication with multiple websites
          371  SSLSession m_sessions[SessionCache];
          372 };
          373 
          374 #endif
          void setMutualAuthParams(const SSLClientParameters *params)
          Add a client certificate and enable support for mutual auth.
          Definition: SSLClient.h:300
          -
          size_t write_impl(const uint8_t *buf, size_t size)
          Definition: SSLClientImpl.cpp:130
          -
          const SSLSession * get_session_array() const override
          Definition: SSLClient.h:365
          -
          IPAddress remoteIP() override
          Returns the remote IP, if C::remoteIP exists.
          Definition: SSLClient.h:352
          -
          size_t write(uint8_t b) override
          Definition: SSLClient.h:170
          -
          Definition: SSLClientImpl.h:66
          -
          SSLSession & get_session_impl(const char *host, const IPAddress &addr)
          Definition: SSLClientImpl.cpp:286
          -
          This class stores values which allow SSLClient to save and resume SSL sessions.
          Definition: SSLSession.h:52
          -
          bool operator!=(const C &rhs)
          Returns whether or not two SSLClient objects do not have the same underlying client object.
          Definition: SSLClient.h:348
          -
          int available() override
          Returns the number of bytes available to read from the data that has been received and decrypted.
          Definition: SSLClient.h:214
          -
          C & getClient()
          Returns a reference to the client object stored in this class. Take care not to break it.
          Definition: SSLClient.h:357
          -
          int peek_impl()
          Definition: SSLClientImpl.cpp:209
          +Go to the documentation of this file.
          1 /* Copyright 2019 OSU OPEnS Lab
          2  *
          3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
          4  * software and associated documentation files (the "Software"), to deal in the Software
          5  * without restriction, including without limitation the rights to use, copy, modify,
          6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
          7  * permit persons to whom the Software is furnished to do so, subject to the following
          8  * conditions:
          9  *
          10  * The above copyright notice and this permission notice shall be included in all
          11  * copies or substantial portions of the Software.
          12  *
          13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
          14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
          15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
          16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
          17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
          18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
          19  */
          20 
          21 #include "Client.h"
          22 #include "SSLSession.h"
          23 #include "SSLClientParameters.h"
          24 #include "SSLObj.h"
          25 #include <vector>
          26 
          27 #ifndef SSLClient_H_
          28 #define SSLClient_H_
          29 
          35 class SSLClient : public Client {
          36 public:
          45  enum Error {
          46  SSL_OK = 0,
          59  };
          60 
          67  enum DebugLevel {
          69  SSL_NONE = 0,
          71  SSL_ERROR = 1,
          73  SSL_WARN = 2,
          75  SSL_INFO = 3,
          76  };
          77 
          95  explicit SSLClient( Client& client,
          96  const br_x509_trust_anchor *trust_anchors,
          97  const size_t trust_anchors_num,
          98  const int analog_pin,
          99  const size_t max_sessions = 1,
          100  const DebugLevel debug = SSL_WARN);
          101 
          102  //========================================
          103  //= Functions implemented in SSLClient.cpp
          104  //========================================
          105 
          145  int connect(IPAddress ip, uint16_t port) override;
          146 
          183  int connect(const char *host, uint16_t port) override;
          184 
          208  size_t write(const uint8_t *buf, size_t size) override;
          210  size_t write(uint8_t b) override { return write(&b, 1); }
          211 
          230  int available() override;
          231 
          253  int read(uint8_t *buf, size_t size) override;
          258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
          259 
          268  int peek() override;
          269 
          277  void flush() override;
          278 
          287  void stop() override;
          288 
          302  uint8_t connected() override;
          303 
          304  //========================================
          305  //= Functions Not in the Client Interface
          306  //========================================
          307 
          316  void setMutualAuthParams(const SSLClientParameters* params);
          317 
          332  SSLSession* getSession(const char* host);
          333 
          342  void removeSession(const char* host);
          343 
          349  size_t getSessionCount() const { return m_sessions.size(); }
          350 
          356  operator bool() { return connected() > 0; }
          357 
          359  Client& getClient() { return m_client; }
          360 
          361 private:
          363  Client& get_arduino_client() { return m_client; }
          364  const Client& get_arduino_client() const { return m_client; }
          365 
          367  bool m_soft_connected(const char* func_name);
          369  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
          371  int m_run_until(const unsigned target);
          373  unsigned m_update_engine();
          375  int m_get_session_index(const char* host) const;
          376 
          378  void m_print_prefix(const char* func_name, const DebugLevel level) const;
          379 
          381  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
          382 
          384  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
          385 
          387  template<typename T>
          388  void m_print(const T str, const char* func_name, const DebugLevel level) const {
          389  // check the current debug level and serial status
          390  if (level > m_debug || !Serial) return;
          391  // print prefix
          392  m_print_prefix(func_name, level);
          393  // print the message
          394  Serial.println(str);
          395  }
          396 
          398  template<typename T>
          399  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
          400 
          401  template<typename T>
          402  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
          403 
          404  template<typename T>
          405  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
          406 
          407  //============================================
          408  //= Data Members
          409  //============================================
          410  // create a copy of the client
          411  Client& m_client;
          412  // also store an array of SSLSessions, so we can resume communication with multiple websites
          413  std::vector<SSLSession> m_sessions;
          414  // as well as the maximmum number of sessions we can store
          415  const size_t m_max_sessions;
          416  // store the pin to fetch an RNG see from
          417  const int m_analog_pin;
          418  // store whether to enable debug logging
          419  const DebugLevel m_debug;
          420  // store if we are connected in bearssl or not
          421  bool m_is_connected;
          422  // store the context values required for SSL
          423  br_ssl_client_context m_sslctx;
          424  br_x509_minimal_context m_x509ctx;
          425  // use a mono-directional buffer by default to cut memory in half
          426  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
          427  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
          428  // simply edit this value to change the buffer size to the desired value
          429  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
          430  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
          438  unsigned char m_iobuf[2048];
          439  // store the index of where we are writing in the buffer
          440  // so we can send our records all at once to prevent
          441  // weird timing issues
          442  size_t m_write_idx;
          443 };
          444 
          445 #endif
          uint8_t connected() override
          Check if the device is connected.
          Definition: SSLClient.cpp:255
          +
          Definition: SSLClient.h:58
          +
          This class stores values which allow SSLClient to save and resume SSL sessions.
          Definition: SSLSession.h:51
          +
          Definition: SSLClient.h:48
          +
          Definition: SSLClient.h:75
          +
          Definition: SSLClient.h:54
          +
          SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
          Initialize SSLClient with all of the prerequisites needed.
          Definition: SSLClient.cpp:55
          +
          void flush() override
          Force writing the buffered bytes from SSLClient::write to the network.
          Definition: SSLClient.cpp:222
          +
          SSLSession * getSession(const char *host)
          Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
          Definition: SSLClient.cpp:286
          This struct stores data required for SSLClient to use mutual authentication.
          Definition: SSLClientParameters.h:52
          -
          void flush() override
          Force writing the buffered bytes from SSLClient::write to the network.
          Definition: SSLClient.h:261
          -
          The main SSLClient class. Check out README.md for more info.
          Definition: SSLClient.h:36
          -
          bool operator!=(const bool value)
          Definition: SSLClient.h:344
          -
          void stop() override
          Close the connection.
          Definition: SSLClient.h:271
          -
          size_t write(const uint8_t *buf, size_t size) override
          Write some bytes to the SSL connection.
          Definition: SSLClient.h:194
          -
          SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
          Initialize SSLClient with all of the prerequisites needed.
          Definition: SSLClient.h:72
          -
          int peek() override
          View the first byte of the buffer, without removing it from the SSLClient Buffer.
          Definition: SSLClient.h:252
          -
          int available_impl()
          Definition: SSLClientImpl.cpp:173
          -
          bool operator==(const C &rhs)
          Returns whether or not two SSLClient objects have the same underlying client object.
          Definition: SSLClient.h:346
          -
          int read_impl(uint8_t *buf, size_t size)
          Definition: SSLClientImpl.cpp:194
          -
          SSLSession * get_session_array() override
          Returns an instance of the session array that is on the stack.
          Definition: SSLClient.h:364
          -
          void remove_session_impl(const char *host, const IPAddress &addr)
          Definition: SSLClientImpl.cpp:305
          -
          Client & get_arduino_client() override
          Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.
          Definition: SSLClient.h:361
          -
          uint16_t localPort() override
          Returns the local port, if C::localPort exists.
          Definition: SSLClient.h:350
          - -
          void set_mutual_impl(const SSLClientParameters *params)
          Definition: SSLClientImpl.cpp:316
          -
          int read() override
          Read a single byte, or -1 if none is available.
          Definition: SSLClient.h:220
          +
          void setMutualAuthParams(const SSLClientParameters *params)
          Add a client certificate and enable support for mutual auth.
          Definition: SSLClient.cpp:310
          +
          int available() override
          Returns the number of bytes available to read from the data that has been received and decrypted.
          Definition: SSLClient.cpp:174
          +
          The main SSLClient class. Check out README.md for more info.
          Definition: SSLClient.h:35
          +
          Definition: SSLClient.h:73
          +
          void stop() override
          Close the connection.
          Definition: SSLClient.cpp:228
          +
          Definition: SSLClient.h:71
          +
          int connect(IPAddress ip, uint16_t port) override
          Connect over SSL to a host specified by an IP address.
          Definition: SSLClient.cpp:82
          +
          size_t write(const uint8_t *buf, size_t size) override
          Write some bytes to the SSL connection.
          Definition: SSLClient.cpp:131
          +
          int read() override
          Read a single byte, or -1 if none is available.
          Definition: SSLClient.h:258
          +
          Error
          Static constants defining the possible errors encountered.
          Definition: SSLClient.h:45
          +
          Definition: SSLClient.h:52
          +
          DebugLevel
          Level of verbosity used in logging for SSLClient.
          Definition: SSLClient.h:67
          +
          size_t getSessionCount() const
          Get the maximum number of SSL sessions that can be stored at once.
          Definition: SSLClient.h:349
          +
          int peek() override
          View the first byte of the buffer, without removing it from the SSLClient Buffer.
          Definition: SSLClient.cpp:210
          -
          uint8_t connected() override
          Check if the device is connected.
          Definition: SSLClient.h:286
          +
          Definition: SSLClient.h:50
          -
          const Client & get_arduino_client() const override
          Definition: SSLClient.h:362
          -
          int connect(const char *host, uint16_t port) override
          Connect over SSL to a host specified by a hostname.
          Definition: SSLClient.h:167
          -
          bool operator==(const bool value)
          Definition: SSLClient.h:342
          -
          uint16_t remotePort() override
          Returns the remote port, if C::remotePort exists. Else return 0.
          Definition: SSLClient.h:354
          -
          int connect_impl(IPAddress ip, uint16_t port)
          Definition: SSLClientImpl.cpp:73
          -
          size_t getSessionCount() const override
          Get the maximum number of SSL sessions that can be stored at once.
          Definition: SSLClient.h:333
          -
          void stop_impl()
          Definition: SSLClientImpl.cpp:227
          -
          void flush_impl()
          Definition: SSLClientImpl.cpp:221
          +
          size_t write(uint8_t b) override
          Definition: SSLClient.h:210
          +
          Client & getClient()
          Returns a reference to the client object stored in this class. Take care not to break it.
          Definition: SSLClient.h:359
          +
          void removeSession(const char *host)
          Clear the session corresponding to a host and IP.
          Definition: SSLClient.cpp:299
          -
          Implementation code to be inherited by SSLClient.
          Definition: SSLClientImpl.h:72
          -
          void removeSession(const char *host, const IPAddress &addr)
          Clear the session corresponding to a host and IP.
          Definition: SSLClient.h:326
          -
          uint8_t connected_impl()
          Definition: SSLClientImpl.cpp:255
          -
          SSLSession & getSession(const char *host, const IPAddress &addr)
          Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
          Definition: SSLClient.h:316
          -
          DebugLevel
          Level of verbosity used in logging for SSLClient.
          Definition: SSLClientImpl.h:60
          -
          int read(uint8_t *buf, size_t size) override
          Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes re...
          Definition: SSLClient.h:242
          -
          int connect(IPAddress ip, uint16_t port) override
          Connect over SSL to a host specified by an IP address.
          Definition: SSLClient.h:129
          +
          Definition: SSLClient.h:69
          +
          Definition: SSLClient.h:46
          +
          Definition: SSLClient.h:56
          diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index e0dbc53..086efc4 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -95,7 +95,6 @@ $(document).ready(function(){initNavTree('_s_s_l_session_8h.html','');});
          #include "bearssl.h"
          #include "Arduino.h"
          -#include "IPAddress.h"

          Go to the source code of this file.

          diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index 1a0730f..d70c2ba 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -91,15 +91,10 @@ $(document).ready(function(){initNavTree('_s_s_l_session_8h_source.html','');});
          SSLSession.h
          -Go to the documentation of this file.
          1 /* Copyright 2019 OSU OPEnS Lab
          2  *
          3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
          4  * software and associated documentation files (the "Software"), to deal in the Software
          5  * without restriction, including without limitation the rights to use, copy, modify,
          6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
          7  * permit persons to whom the Software is furnished to do so, subject to the following
          8  * conditions:
          9  *
          10  * The above copyright notice and this permission notice shall be included in all
          11  * copies or substantial portions of the Software.
          12  *
          13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
          14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
          15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
          16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
          17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
          18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
          19  */
          20 
          28 #include "bearssl.h"
          29 #include "Arduino.h"
          30 #include "IPAddress.h"
          31 
          32 #ifndef SSLSession_H_
          33 #define SSLSession_H_
          34 
          52 class SSLSession : public br_ssl_session_parameters {
          53 
          54 public:
          61  : m_valid_session(false)
          62  , m_hostname()
          63  , m_ip(INADDR_NONE) {}
          64 
          66  SSLSession& operator=(const SSLSession&) = delete;
          67 
          76  const String& get_hostname() const { return m_hostname; }
          77 
          86  const IPAddress& get_ip() const { return m_ip; }
          87 
          88  bool is_valid_session() const { return m_valid_session; }
          89 
          109  void set_parameters(const IPAddress& ip, const char* hostname = NULL);
          110 
          118  void clear_parameters();
          119 
          121  br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; }
          122 
          123 private:
          124  bool m_valid_session;
          125  // aparently a hostname has a max length of 256 chars. Go figure.
          126  String m_hostname;
          127  // store the IP Address we connected to
          128  IPAddress m_ip;
          129 };
          130 
          131 
          132 
          133 #endif /* SSLSession_H_ */
          This class stores values which allow SSLClient to save and resume SSL sessions.
          Definition: SSLSession.h:52
          -
          br_ssl_session_parameters * to_br_session()
          Returns a pointer to the ::br_ssl_session_parameters component of this class.
          Definition: SSLSession.h:121
          -
          void set_parameters(const IPAddress &ip, const char *hostname=NULL)
          Set the ip address and hostname of the session.
          Definition: SSLSession.cpp:4
          -
          void clear_parameters()
          Delete the parameters and invalidate the session.
          Definition: SSLSession.cpp:19
          -
          bool is_valid_session() const
          Definition: SSLSession.h:88
          -
          SSLSession & operator=(const SSLSession &)=delete
          use clear_parameters or set_parameters instead
          -
          const IPAddress & get_ip() const
          Get ::IPAddress associated with this session.
          Definition: SSLSession.h:86
          -
          SSLSession()
          SSLSession constructor.
          Definition: SSLSession.h:60
          -
          const String & get_hostname() const
          Get the hostname string associated with this session.
          Definition: SSLSession.h:76
          +Go to the documentation of this file.
          1 /* Copyright 2019 OSU OPEnS Lab
          2  *
          3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
          4  * software and associated documentation files (the "Software"), to deal in the Software
          5  * without restriction, including without limitation the rights to use, copy, modify,
          6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
          7  * permit persons to whom the Software is furnished to do so, subject to the following
          8  * conditions:
          9  *
          10  * The above copyright notice and this permission notice shall be included in all
          11  * copies or substantial portions of the Software.
          12  *
          13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
          14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
          15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
          16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
          17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
          18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
          19  */
          20 
          28 #include "bearssl.h"
          29 #include "Arduino.h"
          30 
          31 #ifndef SSLSession_H_
          32 #define SSLSession_H_
          33 
          51 class SSLSession : public br_ssl_session_parameters {
          52 
          53 public:
          59  SSLSession(const char* hostname)
          60  : m_hostname(hostname) {}
          61 
          70  const String& get_hostname() const { return m_hostname; }
          71 
          73  br_ssl_session_parameters* to_br_session() { return (br_ssl_session_parameters *)this; }
          74 
          75 private:
          76  // aparently a hostname has a max length of 256 chars. Go figure.
          77  String m_hostname;
          78 };
          79 
          80 
          81 
          82 #endif /* SSLSession_H_ */
          This class stores values which allow SSLClient to save and resume SSL sessions.
          Definition: SSLSession.h:51
          +
          br_ssl_session_parameters * to_br_session()
          Returns a pointer to the ::br_ssl_session_parameters component of this class.
          Definition: SSLSession.h:73
          +
          SSLSession(const char *hostname)
          SSLSession constructor.
          Definition: SSLSession.h:59
          +
          const String & get_hostname() const
          Get the hostname string associated with this session.
          Definition: SSLSession.h:70
          diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 3ddfa8e..cfc7655 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -95,9 +95,8 @@ $(document).ready(function(){initNavTree('annotated.html','');});
          - - - + +
           Cssl_pem_decode_state
           CSSLClientThe main SSLClient class. Check out README.md for more info
           CSSLClientImplImplementation code to be inherited by SSLClient
           CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
           CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
           CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
           CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
          diff --git a/docs/html/annotated_dup.js b/docs/html/annotated_dup.js index 72e17b0..997b666 100644 --- a/docs/html/annotated_dup.js +++ b/docs/html/annotated_dup.js @@ -2,7 +2,6 @@ var annotated_dup = [ [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", "structssl__pem__decode__state" ], [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ], - [ "SSLClientImpl", "class_s_s_l_client_impl.html", "class_s_s_l_client_impl" ], [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ], [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] ]; \ No newline at end of file diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 0981301..2927210 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -88,62 +88,43 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');});
          -
          SSLClient< C, SessionCache > Member List
          +
          SSLClient Member List
          -

          This is the complete list of members for SSLClient< C, SessionCache >, including all inherited members.

          +

          This is the complete list of members for SSLClient, including all inherited members.

          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          available() overrideSSLClient< C, SessionCache >inline
          available_impl()SSLClientImpl
          connect(IPAddress ip, uint16_t port) overrideSSLClient< C, SessionCache >inline
          connect(const char *host, uint16_t port) overrideSSLClient< C, SessionCache >inline
          connect_impl(IPAddress ip, uint16_t port)SSLClientImpl
          connect_impl(const char *host, uint16_t port)SSLClientImpl
          connected() overrideSSLClient< C, SessionCache >inline
          connected_impl()SSLClientImpl
          flush() overrideSSLClient< C, SessionCache >inline
          flush_impl()SSLClientImpl
          get_arduino_client() overrideSSLClient< C, SessionCache >inlineprotectedvirtual
          get_arduino_client() const overrideSSLClient< C, SessionCache >inlineprotectedvirtual
          get_session_array() overrideSSLClient< C, SessionCache >inlineprotectedvirtual
          get_session_array() const overrideSSLClient< C, SessionCache >inlineprotectedvirtual
          get_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
          getClient()SSLClient< C, SessionCache >inline
          getSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inline
          getSessionCount() const overrideSSLClient< C, SessionCache >inlinevirtual
          localPort() overrideSSLClient< C, SessionCache >inlinevirtual
          m_error(const T str, const char *func_name) constSSLClientImplinlineprotected
          m_info(const T str, const char *func_name) constSSLClientImplinlineprotected
          m_print(const T str, const char *func_name, const DebugLevel level) constSSLClientImplinlineprotected
          m_print_br_error(const unsigned br_error_code, const DebugLevel level) constSSLClientImplprotected
          m_print_prefix(const char *func_name, const DebugLevel level) constSSLClientImplprotected
          m_print_ssl_error(const int ssl_error, const DebugLevel level) constSSLClientImplprotected
          m_warn(const T str, const char *func_name) constSSLClientImplinlineprotected
          operator bool()SSLClient< C, SessionCache >inline
          operator!=(const bool value)SSLClient< C, SessionCache >inline
          operator!=(const C &rhs)SSLClient< C, SessionCache >inline
          operator==(const bool value)SSLClient< C, SessionCache >inline
          operator==(const C &rhs)SSLClient< C, SessionCache >inline
          peek() overrideSSLClient< C, SessionCache >inline
          peek_impl()SSLClientImpl
          read() overrideSSLClient< C, SessionCache >inline
          read(uint8_t *buf, size_t size) overrideSSLClient< C, SessionCache >inline
          read_impl(uint8_t *buf, size_t size)SSLClientImpl
          remoteIP() overrideSSLClient< C, SessionCache >inlinevirtual
          remotePort() overrideSSLClient< C, SessionCache >inlinevirtual
          remove_session_impl(const char *host, const IPAddress &addr)SSLClientImpl
          removeSession(const char *host, const IPAddress &addr)SSLClient< C, SessionCache >inline
          set_mutual_impl(const SSLClientParameters *params)SSLClientImpl
          setMutualAuthParams(const SSLClientParameters *params)SSLClient< C, SessionCache >inline
          SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)SSLClient< C, SessionCache >inlineexplicit
          SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)SSLClientImplexplicit
          SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)SSLClientImplexplicit
          stop() overrideSSLClient< C, SessionCache >inline
          stop_impl()SSLClientImpl
          write(uint8_t b) overrideSSLClient< C, SessionCache >inline
          write(const uint8_t *buf, size_t size) overrideSSLClient< C, SessionCache >inline
          write_impl(const uint8_t *buf, size_t size)SSLClientImpl
          available() overrideSSLClient
          connect(IPAddress ip, uint16_t port) overrideSSLClient
          connect(const char *host, uint16_t port) overrideSSLClient
          connected() overrideSSLClient
          DebugLevel enum nameSSLClient
          Error enum nameSSLClient
          flush() overrideSSLClient
          getClient()SSLClientinline
          getSession(const char *host)SSLClient
          getSessionCount() constSSLClientinline
          operator bool()SSLClientinline
          peek() overrideSSLClient
          read(uint8_t *buf, size_t size) overrideSSLClient
          read() overrideSSLClientinline
          removeSession(const char *host)SSLClient
          setMutualAuthParams(const SSLClientParameters *params)SSLClient
          SSL_BR_CONNECT_FAIL enum valueSSLClient
          SSL_BR_WRITE_ERROR enum valueSSLClient
          SSL_CLIENT_CONNECT_FAIL enum valueSSLClient
          SSL_CLIENT_WRTIE_ERROR enum valueSSLClient
          SSL_ERROR enum valueSSLClient
          SSL_INFO enum valueSSLClient
          SSL_INTERNAL_ERROR enum valueSSLClient
          SSL_NONE enum valueSSLClient
          SSL_OK enum valueSSLClient
          SSL_OUT_OF_MEMORY enum valueSSLClient
          SSL_WARN enum valueSSLClient
          SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)SSLClientexplicit
          stop() overrideSSLClient
          write(const uint8_t *buf, size_t size) overrideSSLClient
          write(uint8_t b) overrideSSLClientinline
          diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 44b769d..1e4fddb 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -5,7 +5,7 @@ -SSLClient: SSLClient< C, SessionCache > Class Template Reference +SSLClient: SSLClient Class Reference @@ -88,11 +88,11 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');});
          -
          SSLClient< C, SessionCache > Class Template Reference
          +
          SSLClient Class Reference
          @@ -101,177 +101,167 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');});

          #include <SSLClient.h>

          -Inheritance diagram for SSLClient< C, SessionCache >:
          +Inheritance diagram for SSLClient:
          - - -SSLClientImpl - -
          + + + + + + + + + +

          +Public Types

          enum  Error {
          +  SSL_OK = 0, +SSL_CLIENT_CONNECT_FAIL, +SSL_BR_CONNECT_FAIL, +SSL_CLIENT_WRTIE_ERROR, +
          +  SSL_BR_WRITE_ERROR, +SSL_INTERNAL_ERROR, +SSL_OUT_OF_MEMORY +
          + }
           Static constants defining the possible errors encountered. More...
           
          enum  DebugLevel { SSL_NONE = 0, +SSL_ERROR = 1, +SSL_WARN = 2, +SSL_INFO = 3 + }
           Level of verbosity used in logging for SSLClient. More...
           
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

          Public Member Functions

           SSLClient (const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug=SSL_WARN)
           Initialize SSLClient with all of the prerequisites needed. More...
           
          int connect (IPAddress ip, uint16_t port) override
           Connect over SSL to a host specified by an IP address. More...
           
          int connect (const char *host, uint16_t port) override
           Connect over SSL to a host specified by a hostname. More...
           
          size_t write (uint8_t b) override
           
          size_t write (const uint8_t *buf, size_t size) override
           Write some bytes to the SSL connection. More...
           
          int available () override
           Returns the number of bytes available to read from the data that has been received and decrypted. More...
           
          int read () override
           Read a single byte, or -1 if none is available. More...
           
          int read (uint8_t *buf, size_t size) override
           Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. More...
           
          int peek () override
           View the first byte of the buffer, without removing it from the SSLClient Buffer. More...
           
          void flush () override
           Force writing the buffered bytes from SSLClient::write to the network. More...
           
          void stop () override
           Close the connection. More...
           
          uint8_t connected () override
           Check if the device is connected. More...
           
          void setMutualAuthParams (const SSLClientParameters *params)
           Add a client certificate and enable support for mutual auth. More...
           
          SSLSessiongetSession (const char *host, const IPAddress &addr)
           Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
           
          void removeSession (const char *host, const IPAddress &addr)
           Clear the session corresponding to a host and IP. More...
           
          size_t getSessionCount () const override
           Get the maximum number of SSL sessions that can be stored at once. More...
           
           operator bool ()
           Equivalent to SSLClient::connected() > 0. More...
           
          bool operator== (const bool value)
           
          bool operator!= (const bool value)
           
          bool operator== (const C &rhs)
           Returns whether or not two SSLClient objects have the same underlying client object. More...
           
          bool operator!= (const C &rhs)
           Returns whether or not two SSLClient objects do not have the same underlying client object. More...
           
          uint16_t localPort () override
           Returns the local port, if C::localPort exists. More...
           
          IPAddress remoteIP () override
           Returns the remote IP, if C::remoteIP exists. More...
           
          uint16_t remotePort () override
           Returns the remote port, if C::remotePort exists. Else return 0. More...
           
          C & getClient ()
           Returns a reference to the client object stored in this class. Take care not to break it. More...
           
          - Public Member Functions inherited from SSLClientImpl
           SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)
           
           SSLClientImpl (const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)
           
          int connect_impl (IPAddress ip, uint16_t port)
           
          int connect_impl (const char *host, uint16_t port)
           
          size_t write_impl (const uint8_t *buf, size_t size)
           
          int available_impl ()
           
          int read_impl (uint8_t *buf, size_t size)
           
          int peek_impl ()
           
          void flush_impl ()
           
          void stop_impl ()
           
          uint8_t connected_impl ()
           
          SSLSessionget_session_impl (const char *host, const IPAddress &addr)
           
          void remove_session_impl (const char *host, const IPAddress &addr)
           
          void set_mutual_impl (const SSLClientParameters *params)
           
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

          -Protected Member Functions

          Client & get_arduino_client () override
           Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl. More...
           
          const Client & get_arduino_client () const override
           
          SSLSessionget_session_array () override
           Returns an instance of the session array that is on the stack. More...
           
          const SSLSessionget_session_array () const override
           
          - Protected Member Functions inherited from SSLClientImpl
          void m_print_prefix (const char *func_name, const DebugLevel level) const
           Prints a debugging prefix to all logs, so we can attatch them to useful information. More...
           
          void m_print_ssl_error (const int ssl_error, const DebugLevel level) const
           Prints the string associated with a write error. More...
           
          void m_print_br_error (const unsigned br_error_code, const DebugLevel level) const
           Print the text string associated with a BearSSL error code. More...
           
          template<typename T >
          void m_print (const T str, const char *func_name, const DebugLevel level) const
           debugging print function, only prints if m_debug is true More...
           
          template<typename T >
          void m_info (const T str, const char *func_name) const
           Prints a info message to serial, if info messages are enabled. More...
           
          template<typename T >
          void m_warn (const T str, const char *func_name) const
           
          template<typename T >
          void m_error (const T str, const char *func_name) const
           
           SSLClient (Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
           Initialize SSLClient with all of the prerequisites needed. More...
           
          int connect (IPAddress ip, uint16_t port) override
           Connect over SSL to a host specified by an IP address. More...
           
          int connect (const char *host, uint16_t port) override
           Connect over SSL to a host specified by a hostname. More...
           
          size_t write (const uint8_t *buf, size_t size) override
           Write some bytes to the SSL connection. More...
           
          size_t write (uint8_t b) override
           
          int available () override
           Returns the number of bytes available to read from the data that has been received and decrypted. More...
           
          int read (uint8_t *buf, size_t size) override
           Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read. More...
           
          int read () override
           Read a single byte, or -1 if none is available. More...
           
          int peek () override
           View the first byte of the buffer, without removing it from the SSLClient Buffer. More...
           
          void flush () override
           Force writing the buffered bytes from SSLClient::write to the network. More...
           
          void stop () override
           Close the connection. More...
           
          uint8_t connected () override
           Check if the device is connected. More...
           
          void setMutualAuthParams (const SSLClientParameters *params)
           Add a client certificate and enable support for mutual auth. More...
           
          SSLSessiongetSession (const char *host)
           Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
           
          void removeSession (const char *host)
           Clear the session corresponding to a host and IP. More...
           
          size_t getSessionCount () const
           Get the maximum number of SSL sessions that can be stored at once. More...
           
           operator bool ()
           Equivalent to SSLClient::connected() > 0. More...
           
          Client & getClient ()
           Returns a reference to the client object stored in this class. Take care not to break it. More...
           

          Detailed Description

          -

          template<class C, size_t SessionCache = 1>
          -class SSLClient< C, SessionCache >

          - -

          The main SSLClient class. Check out README.md for more info.

          -

          Constructor & Destructor Documentation

          - -

          ◆ SSLClient()

          +

          The main SSLClient class. Check out README.md for more info.

          +

          Member Enumeration Documentation

          + +

          ◆ DebugLevel

          + +
          +
          + + + + +
          enum SSLClient::DebugLevel
          +
          + +

          Level of verbosity used in logging for SSLClient.

          +

          Use these values when initializing SSLClient to set how many logs you would like to see in the Serial monitor.

          + + + + + +
          Enumerator
          SSL_NONE 

          No logging output

          +
          SSL_ERROR 

          Only output errors that result in connection failure

          +
          SSL_WARN 

          Output errors and warnings (useful when just starting to develop)

          +
          SSL_INFO 

          Output errors, warnings, and internal information (very verbose)

          +
          + +
          +
          + +

          ◆ Error

          + +
          +
          + + + + +
          enum SSLClient::Error
          +
          + +

          Static constants defining the possible errors encountered.

          +

          If SSLClient encounters an error, it will generally output logs into the serial monitor. If you need a way of programmatically checking the errors, you can do so with SSLClient::getWriteError(), which will return one of these values.

          + + + + + + + + +
          Enumerator
          SSL_OK 
          SSL_CLIENT_CONNECT_FAIL 

          The underlying client failed to connect, probably not an issue with SSL

          +
          SSL_BR_CONNECT_FAIL 

          BearSSL failed to complete the SSL handshake, check logs for bear ssl error output

          +
          SSL_CLIENT_WRTIE_ERROR 

          The underlying client failed to write a payload, probably not an issue with SSL

          +
          SSL_BR_WRITE_ERROR 

          An internal error occurred with BearSSL, check logs for diagnosis.

          +
          SSL_INTERNAL_ERROR 

          An internal error occurred with SSLClient, and you probably need to submit an issue on Github.

          +
          SSL_OUT_OF_MEMORY 

          SSLClient detected that there was not enough memory (>8000 bytes) to continue.

          +
          + +
          +
          +

          Constructor & Destructor Documentation

          + +

          ◆ SSLClient()

          -
          -template<class C , size_t SessionCache = 1>
          +explicit
          - + - + @@ -295,8 +285,14 @@ template<class C , size_t SessionCache = 1> - - + + + + + + + + @@ -306,7 +302,7 @@ template<class C , size_t SessionCache = 1>
          SSLClient< C, SessionCache >::SSLClient SSLClient::SSLClient (const C & Client &  client,
          const DebugLevel debug = SSL_WARN const size_t max_sessions = 1,
          const DebugLevel debug = SSL_WARN 
          -inlineexplicit
          @@ -321,8 +317,8 @@ The analog_pin should be set to input. trust_anchorsTrust anchors used in the verification of the SSL server certificate. Check out TrustAnchors.md for more info. trust_anchors_numThe number of objects in the trust_anchors array. analog_pinAn analog pin to pull random bytes from, used in seeding the RNG. - debugThe level of debug logging (use the DebugLevel enum). - mutual_auth_paramsConfiguration to use for mutual authentication, nullptr to disable mutual auth. (see SSLClientParameters). + max_sessionsThe maximum number of SSL sessions to store connection information from. + debugThe level of debug logging (use the ::DebugLevel enum). @@ -330,19 +326,17 @@ The analog_pin should be set to input.

          Member Function Documentation

          - -

          ◆ available()

          + +

          ◆ available()

          -
          -template<class C , size_t SessionCache = 1>
          +override
          - + @@ -350,32 +344,30 @@ template<class C , size_t SessionCache = 1>
          int SSLClient< C, SessionCache >::available int SSLClient::available ( )
          -inlineoverride

          Returns the number of bytes available to read from the data that has been received and decrypted.

          -

          This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

          +

          This function updates the state of the SSL engine (including writing any data, see SSLClient::write) and as a result should be called periodically when expecting data. Additionally, since if there are no bytes and if SSLClient::connected is false this function returns zero (this same behavior is found in EthernetClient), it is prudent to ensure in your own code that the preconditions are met before checking this function to prevent an ambiguous result.

          The implementation for this function can be found in SSLClientImpl::available

          -
          Precondition
          SSLClient::connected must be true. (Call SSLClient::connected before this function)
          +
          Precondition
          SSLClient::connected must be true. (Call SSLClient::connected before this function)
          Returns
          The number of bytes available (can be zero), or zero if any of the pre conditions aren't satisfied.
          - -

          ◆ connect() [1/2]

          + +

          ◆ connect() [1/2]

          -
          -template<class C , size_t SessionCache = 1>
          +override
          - + @@ -394,7 +386,7 @@ template<class C , size_t SessionCache = 1>
          int SSLClient< C, SessionCache >::connect int SSLClient::connect ( IPAddress  ip,
          -inlineoverride
          @@ -403,7 +395,7 @@ template<class C , size_t SessionCache = 1>

          SSLClient::connect(host, port) should be preferred over this function, as verifying the domain name is a step in ensuring the certificate is legitimate, which is important to the security of the device. Additionally, SSL sessions cannot be resumed when using this function, which can drastically increase initial connect time.

          This function initializes the socket by calling m_client::connect(IPAddress, uint16_t) with the parameters supplied, then once the socket is open, uses BearSSL to to complete a SSL handshake. Due to the design of the SSL standard, this function will probably take an extended period (1-4sec) to negotiate the handshake and finish the connection. This function runs until the SSL handshake succeeds or fails.

          SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

          -

          The implementation for this function can be found in SSLClientImpl::connect_impl(IPAddress, uint16_t).

          +

          The implementation for this function can be found in SSLClientImpl::connect_impl(IPAddress, uint16_t).

          Precondition
          The underlying client object (passed in through the constructor) is in a non- error state, and must be able to access the IP.
          SSLClient can only have one connection at a time, so the client object must not already be connected.
          @@ -422,19 +414,17 @@ There must be a trust anchor given to the constructor that corresponds to the ce
          - -

          ◆ connect() [2/2]

          + +

          ◆ connect() [2/2]

          -
          -template<class C , size_t SessionCache = 1>
          +override
          - + @@ -453,7 +443,7 @@ template<class C , size_t SessionCache = 1>
          int SSLClient< C, SessionCache >::connect int SSLClient::connect ( const char *  host,
          -inlineoverride
          @@ -462,7 +452,7 @@ template<class C , size_t SessionCache = 1>

          This function initializes the socket by calling m_client::connect(const char*, uint16_t) with the parameters supplied, then once the socket is open, uses BearSSL to complete a SSL handshake. This function runs until the SSL handshake succeeds or fails.

          SSL requires the client to generate some random bits (to be later combined with some random bits from the server), so SSLClient uses the least significant bits from the analog pin supplied in the constructor. The random bits are generated from 16 consecutive analogReads, and given to BearSSL before the handshake starts.

          This function will usually take around 4-10 seconds. If possible, this function also attempts to resume the SSL session if one is present matching the hostname string, which will reduce connection time to 100-500ms. To read more about this functionality, check out Session Caching in the README.

          -

          The implementation for this function can be found in SSLClientImpl::connect_impl(const char*, uint16_t)

          +

          The implementation for this function can be found in SSLClientImpl::connect_impl(const char*, uint16_t)

          Precondition
          The underlying client object (passed in through the constructor) is in a non- error state, and must be able to access the IP.
          SSLClient can only have one connection at a time, so the client object must not already be connected.
          @@ -481,19 +471,17 @@ There must be a trust anchor given to the constructor that corresponds to the ce
          - -

          ◆ connected()

          + +

          ◆ connected()

          -
          -template<class C , size_t SessionCache = 1>
          +override
          - + @@ -501,31 +489,29 @@ template<class C , size_t SessionCache = 1>
          uint8_t SSLClient< C, SessionCache >::connected uint8_t SSLClient::connected ( )
          -inlineoverride

          Check if the device is connected.

          -

          Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that this function should be called before SSLClient::available– both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently, and SSLClient::connected contains logic to ensure that if the socket is dropped SSLClient will react accordingly.

          -

          The implementation for this function can be found in SSLClientImpl::connected_impl.

          +

          Use this function to determine if SSLClient is still connected and a SSL connection is active. It should be noted that this function should be called before SSLClient::available– both functions send and receive data with the SSLClient::m_client device, however SSLClient::available has some delays built in to protect SSLClient::m_client from being polled too frequently, and SSLClient::connected contains logic to ensure that if the socket is dropped SSLClient will react accordingly.

          +

          The implementation for this function can be found in SSLClientImpl::connected_impl.

          Returns
          1 if connected, 0 if not
          - -

          ◆ flush()

          + +

          ◆ flush()

          -
          -template<class C , size_t SessionCache = 1>
          +override
          - + @@ -533,149 +519,27 @@ template<class C , size_t SessionCache = 1>
          void SSLClient< C, SessionCache >::flush void SSLClient::flush ( )
          -inlineoverride
          -

          Force writing the buffered bytes from SSLClient::write to the network.

          -

          This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush.

          +

          Force writing the buffered bytes from SSLClient::write to the network.

          +

          This function is blocking until all bytes from the buffer are written. For an explanation of how writing with SSLClient works, please see SSLClient::write. The implementation for this function can be found in SSLClientImpl::flush.

          - -

          ◆ get_arduino_client() [1/2]

          + +

          ◆ getClient()

          -
          -template<class C , size_t SessionCache = 1>
          - - -
          - - - - - -
          Client& SSLClient< C, SessionCache >::get_arduino_client ()
          -
          -inlineoverrideprotectedvirtual
          -
          - -

          Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl.

          - -

          Implements SSLClientImpl.

          - -
          -
          - -

          ◆ get_arduino_client() [2/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - -
          const Client& SSLClient< C, SessionCache >::get_arduino_client () const
          -
          -inlineoverrideprotectedvirtual
          -
          - -

          Implements SSLClientImpl.

          - -
          -
          - -

          ◆ get_session_array() [1/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - -
          SSLSession* SSLClient< C, SessionCache >::get_session_array ()
          -
          -inlineoverrideprotectedvirtual
          -
          - -

          Returns an instance of the session array that is on the stack.

          - -

          Implements SSLClientImpl.

          - -
          -
          - -

          ◆ get_session_array() [2/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - -
          const SSLSession* SSLClient< C, SessionCache >::get_session_array () const
          -
          -inlineoverrideprotectedvirtual
          -
          - -

          Implements SSLClientImpl.

          - -
          -
          - -

          ◆ getClient()

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - -
          The documentation for this class was generated from the following files:
            +
            The documentation for this class was generated from the following file:
            • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLSession.h
            • -
            • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLSession.cpp
            diff --git a/docs/html/class_s_s_l_session.js b/docs/html/class_s_s_l_session.js index c5d362a..6f58817 100644 --- a/docs/html/class_s_s_l_session.js +++ b/docs/html/class_s_s_l_session.js @@ -1,11 +1,6 @@ var class_s_s_l_session = [ - [ "SSLSession", "class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb", null ], - [ "clear_parameters", "class_s_s_l_session.html#a3305941fa615f7134526b718917716ee", null ], + [ "SSLSession", "class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74", null ], [ "get_hostname", "class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820", null ], - [ "get_ip", "class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0", null ], - [ "is_valid_session", "class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076", null ], - [ "operator=", "class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f", null ], - [ "set_parameters", "class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e", null ], [ "to_br_session", "class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc", null ] ]; \ No newline at end of file diff --git a/docs/html/classes.html b/docs/html/classes.html index 8a44185..b944012 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -94,10 +94,10 @@ $(document).ready(function(){initNavTree('classes.html','');});
          - - - + @@ -692,45 +556,25 @@ template<class C , size_t SessionCache = 1> - -

          ◆ getSession()

          + +

          ◆ getSession()

          -
          -template<class C , size_t SessionCache = 1>
          -
          C& SSLClient< C, SessionCache >::getClient Client& SSLClient::getClient ( )
          - - - - -
          - + - - - - + - - - - - - -
          SSLSession& SSLClient< C, SessionCache >::getSession SSLSession * SSLClient::getSession ( const char * host,
          host) const IPAddress & addr 
          )
          -
          -inline

          Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist.

          If no session corresponding to the host and IP exist, then this function will cycle through sessions in a rotating order. This allows the session cache to continually store sessions, however it will also result in old sessions being cleared and returned. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

          -

          The implementation for this function can be found at SSLClientImpl::get_session_impl.

          +

          The implementation for this function can be found at SSLClientImpl::get_session_impl.

          Parameters
          @@ -738,23 +582,21 @@ template<class C , size_t SessionCache = 1>
          hostA hostname c string, or NULL if one is not available
          -
          Returns
          A reference to an SSLSession object
          +
          Returns
          A pointer to the SSLSession, or NULL of none matched the criteria available
          - -

          ◆ getSessionCount()

          + +

          ◆ getSessionCount()

          -
          -template<class C , size_t SessionCache = 1>
          +inline
          - + @@ -762,7 +604,7 @@ template<class C , size_t SessionCache = 1>
          size_t SSLClient< C, SessionCache >::getSessionCount size_t SSLClient::getSessionCount ( ) const
          -inlineoverridevirtual
          @@ -770,54 +612,19 @@ template<class C , size_t SessionCache = 1>

          Get the maximum number of SSL sessions that can be stored at once.

          Returns
          The SessionCache template parameter.
          -

          Implements SSLClientImpl.

          -
          - -

          ◆ localPort()

          + +

          ◆ operator bool()

          -
          -template<class C , size_t SessionCache = 1>
          - - -
          - - - - - -
          uint16_t SSLClient< C, SessionCache >::localPort ()
          -
          -inlineoverridevirtual
          -
          - -

          Returns the local port, if C::localPort exists.

          - -

          Implements SSLClientImpl.

          - -
          -
          - -

          ◆ operator bool()

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - -
          Returns
          A String object or "" if there is no hostname
          Precondition
          must check isValidSession before getting this value, as if this session in invalid this value is not guarenteed to be reset to "".
          - - - -

          ◆ get_ip()

          - -
          -
          -
          - - - + @@ -830,142 +637,22 @@ template<class C , size_t SessionCache = 1>
          SSLClient< C, SessionCache >::operator bool SSLClient::operator bool ( )
          -

          Equivalent to SSLClient::connected() > 0.

          +

          Equivalent to SSLClient::connected() > 0.

          Returns
          true if connected, false if not
          - -

          ◆ operator!=() [1/2]

          + +

          ◆ peek()

          -
          -template<class C , size_t SessionCache = 1>
          - - -
          - - - - - - -
          bool SSLClient< C, SessionCache >::operator!= (const bool value)
          -
          -inline
          -
          -
          See also
          SSLClient::operator bool
          - -
          -
          - -

          ◆ operator!=() [2/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - - -
          bool SSLClient< C, SessionCache >::operator!= (const C & rhs)
          -
          -inline
          -
          - -

          Returns whether or not two SSLClient objects do not have the same underlying client object.

          - -
          -
          - -

          ◆ operator==() [1/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - - -
          bool SSLClient< C, SessionCache >::operator== (const bool value)
          -
          -inline
          -
          -
          See also
          SSLClient::operator bool
          - -
          -
          - -

          ◆ operator==() [2/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - - -
          bool SSLClient< C, SessionCache >::operator== (const C & rhs)
          -
          -inline
          -
          - -

          Returns whether or not two SSLClient objects have the same underlying client object.

          - -
          -
          - -

          ◆ peek()

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - +override
          - - - + @@ -973,60 +660,28 @@ template<class C , size_t SessionCache = 1>
          int SSLClient< C, SessionCache >::peek int SSLClient::peek ( )
          -inlineoverride

          View the first byte of the buffer, without removing it from the SSLClient Buffer.

          -

          The implementation for this function can be found in SSLClientImpl::peek

          Precondition
          SSLClient::available must be >0
          +

          The implementation for this function can be found in SSLClientImpl::peek

          Precondition
          SSLClient::available must be >0
          Returns
          The first byte received, or -1 if the preconditions are not satisfied (warning: do not use if your data may be -1, as the return value is ambiguous)
          - -

          ◆ read() [1/2]

          + +

          ◆ read() [1/2]

          -
          -template<class C , size_t SessionCache = 1>
          - - -
          - - - - - -
          int SSLClient< C, SessionCache >::read ()
          -
          -inlineoverride
          -
          - -

          Read a single byte, or -1 if none is available.

          -
          See also
          SSLClient::read(uint8_t*, size_t)
          - -
          -
          - -

          ◆ read() [2/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - +override
          - - - + @@ -1045,16 +700,16 @@ template<class C , size_t SessionCache = 1>
          int SSLClient< C, SessionCache >::read int SSLClient::read ( uint8_t *  buf,
          -inlineoverride

          Read size bytes from the SSL client buffer, copying them into *buf, and return the number of bytes read.

          -

          This function checks if bytes are ready to be read by calling SSLClient::available, and if so copies size number of bytes from the IO buffer into the buf pointer. Data read using this function will not include any SSL or socket commands, as the Client and BearSSL will capture those and process them separately.

          +

          This function checks if bytes are ready to be read by calling SSLClient::available, and if so copies size number of bytes from the IO buffer into the buf pointer. Data read using this function will not include any SSL or socket commands, as the Client and BearSSL will capture those and process them separately.

          If you find that you are having a lot of timeout errors, SSLClient may be experiencing a buffer overflow. Checkout README.md for more information.

          -

          The implementation for this function can be found in SSLClientImpl::read_impl(uint8_t*, size_t)

          -
          Precondition
          SSLClient::available must be >0
          +

          The implementation for this function can be found in SSLClientImpl::read_impl(uint8_t*, size_t)

          +
          Precondition
          SSLClient::available must be >0
          Parameters
          @@ -1066,161 +721,17 @@ template<class C , size_t SessionCache = 1> - -

          ◆ remoteIP()

          + +

          ◆ read() [2/2]

          -
          -template<class C , size_t SessionCache = 1>
          bufThe pointer to the buffer to put SSL application data into
          - - -
          - - - - - -
          IPAddress SSLClient< C, SessionCache >::remoteIP ()
          -
          -inlineoverridevirtual
          -
          - -

          Returns the remote IP, if C::remoteIP exists.

          - -

          Implements SSLClientImpl.

          - -
          -
          - -

          ◆ remotePort()

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - -
          uint16_t SSLClient< C, SessionCache >::remotePort ()
          -
          -inlineoverridevirtual
          -
          - -

          Returns the remote port, if C::remotePort exists. Else return 0.

          - -

          Implements SSLClientImpl.

          - -
          -
          - -

          ◆ removeSession()

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - - - - - - - - - - - - -
          void SSLClient< C, SessionCache >::removeSession (const char * host,
          const IPAddress & addr 
          )
          -
          -inline
          -
          - -

          Clear the session corresponding to a host and IP.

          -

          The implementation for this function can be found at SSLClientImpl::remove_session_impl.

          -
          Parameters
          - - - -
          hostA hostname c string, or NULL if one is not available
          addrAn IP address
          -
          -
          - -
          -
          - -

          ◆ setMutualAuthParams()

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - - - -
          - - - - - - - - -
          void SSLClient< C, SessionCache >::setMutualAuthParams (const SSLClientParametersparams)
          -
          -inline
          -
          - -

          Add a client certificate and enable support for mutual auth.

          -

          Please ensure that the values in params are valid for the lifetime of SSLClient. You may want to make them global constants.

          -
          Precondition
          SSLClient has not already started an SSL connection.
          - -
          -
          - -

          ◆ stop()

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - -

          Member Function Documentation

          - -

          ◆ clear_parameters()

          - -
          -
          -
          - - - + @@ -1233,53 +744,100 @@ template<class C , size_t SessionCache = 1>
          void SSLClient< C, SessionCache >::stop int SSLClient::read ( )
          +

          Read a single byte, or -1 if none is available.

          +
          See also
          SSLClient::read(uint8_t*, size_t)
          + +
          + + +

          ◆ removeSession()

          + +
          +
          + + + + + + + + +
          void SSLClient::removeSession (const char * host)
          +
          + +

          Clear the session corresponding to a host and IP.

          +

          The implementation for this function can be found at SSLClientImpl::remove_session_impl.

          +
          Parameters
          + + + +
          hostA hostname c string, or nullptr if one is not available
          addrAn IP address
          +
          +
          + +
          +
          + +

          ◆ setMutualAuthParams()

          + +
          +
          + + + + + + + + +
          void SSLClient::setMutualAuthParams (const SSLClientParametersparams)
          +
          + +

          Add a client certificate and enable support for mutual auth.

          +

          Please ensure that the values in params are valid for the lifetime of SSLClient. You may want to make them global constants.

          +
          Precondition
          SSLClient has not already started an SSL connection.
          + +
          +
          + +

          ◆ stop()

          + +
          +
          + + + + + +
          + + + + + + + +
          void SSLClient::stop ()
          +
          +override
          +
          +

          Close the connection.

          If the SSL session is still active, all incoming data is discarded and BearSSL will attempt to close the session gracefully (will write to the network), and then call m_client::stop. If the session is not active or an error was encountered previously, this function will simply call m_client::stop. The implementation for this function can be found in SSLClientImpl::peek.

          - -

          ◆ write() [1/2]

          + +

          ◆ write() [1/2]

          -
          -template<class C , size_t SessionCache = 1>
          - - -
          - - - - - - -
          size_t SSLClient< C, SessionCache >::write (uint8_t b)
          -
          -inlineoverride
          -
          -
          See also
          SSLClient::write(uint8_t*, size_t)
          - -
          -
          - -

          ◆ write() [2/2]

          - -
          -
          -
          -template<class C , size_t SessionCache = 1>
          - - - +override
          - - - + @@ -1298,15 +856,15 @@ template<class C , size_t SessionCache = 1>
          size_t SSLClient< C, SessionCache >::write size_t SSLClient::write ( const uint8_t *  buf,
          -inlineoverride

          Write some bytes to the SSL connection.

          -

          Assuming all preconditions are met, this function writes data to the BearSSL IO buffer, BUT does not initially send the data. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready for writing, and will write the data to the network. Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until all the data in buf is sent–attempting to keep all writes to the network grouped together. For information on why this is the case check out README.md .

          -

          The implementation for this function can be found in SSLClientImpl::write_impl(const uint8_t*, size_t)

          -
          Precondition
          The socket and SSL layer must be connected, meaning SSLClient::connected must be true.
          +

          Assuming all preconditions are met, this function writes data to the BearSSL IO buffer, BUT does not initially send the data. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready for writing, and will write the data to the network. Alternatively, if this function is requested to write a larger amount of data than SSLClientImpl::m_iobuf can handle, data will be written to the network in pages the size of SSLClientImpl::m_iobuf until all the data in buf is sent–attempting to keep all writes to the network grouped together. For information on why this is the case check out README.md .

          +

          The implementation for this function can be found in SSLClientImpl::write_impl(const uint8_t*, size_t)

          +
          Precondition
          The socket and SSL layer must be connected, meaning SSLClient::connected must be true.
          BearSSL must not be waiting for the recipt of user data (if it is, there is probably an error with how the protocol in implemented in your code).
          Parameters
          @@ -1320,8 +878,36 @@ BearSSL must not be waiting for the recipt of user data (if it is, there is prob
          -
          The documentation for this class was generated from the following file:
            + +

            ◆ write() [2/2]

            + +
            +
            + + + + + +
            + + + + + + + + +
            size_t SSLClient::write (uint8_t b)
            +
            +inlineoverride
            +
            +
            See also
            SSLClient::write(uint8_t*, size_t)
            + +
            +
            +
            The documentation for this class was generated from the following files:
            • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClient.h
            • +
            • C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClient.cpp
            diff --git a/docs/html/class_s_s_l_client.js b/docs/html/class_s_s_l_client.js index 029693f..8b45e37 100644 --- a/docs/html/class_s_s_l_client.js +++ b/docs/html/class_s_s_l_client.js @@ -1,32 +1,36 @@ var class_s_s_l_client = [ - [ "SSLClient", "class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0", null ], - [ "available", "class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e", null ], - [ "connect", "class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630", null ], - [ "connect", "class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf", null ], - [ "connected", "class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc", null ], - [ "flush", "class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44", null ], - [ "get_arduino_client", "class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a", null ], - [ "get_arduino_client", "class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52", null ], - [ "get_session_array", "class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9", null ], - [ "get_session_array", "class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd", null ], - [ "getClient", "class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41", null ], - [ "getSession", "class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086", null ], - [ "getSessionCount", "class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd", null ], - [ "localPort", "class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73", null ], - [ "operator bool", "class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1", null ], - [ "operator!=", "class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1", null ], - [ "operator!=", "class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b", null ], - [ "operator==", "class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc", null ], - [ "operator==", "class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9", null ], - [ "peek", "class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd", null ], - [ "read", "class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e", null ], - [ "read", "class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795", null ], - [ "remoteIP", "class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174", null ], - [ "remotePort", "class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22", null ], - [ "removeSession", "class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c", null ], - [ "setMutualAuthParams", "class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f", null ], - [ "stop", "class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529", null ], - [ "write", "class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb", null ], - [ "write", "class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9", null ] + [ "DebugLevel", "class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1", [ + [ "SSL_NONE", "class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75", null ], + [ "SSL_ERROR", "class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5", null ], + [ "SSL_WARN", "class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97", null ], + [ "SSL_INFO", "class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2", null ] + ] ], + [ "Error", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea", [ + [ "SSL_OK", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94", null ], + [ "SSL_CLIENT_CONNECT_FAIL", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd", null ], + [ "SSL_BR_CONNECT_FAIL", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5", null ], + [ "SSL_CLIENT_WRTIE_ERROR", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8", null ], + [ "SSL_BR_WRITE_ERROR", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016", null ], + [ "SSL_INTERNAL_ERROR", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84", null ], + [ "SSL_OUT_OF_MEMORY", "class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08", null ] + ] ], + [ "SSLClient", "class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376", null ], + [ "available", "class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78", null ], + [ "connect", "class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3", null ], + [ "connect", "class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90", null ], + [ "connected", "class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae", null ], + [ "flush", "class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c", null ], + [ "getClient", "class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21", null ], + [ "getSession", "class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3", null ], + [ "getSessionCount", "class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22", null ], + [ "operator bool", "class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b", null ], + [ "peek", "class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86", null ], + [ "read", "class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95", null ], + [ "read", "class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb", null ], + [ "removeSession", "class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4", null ], + [ "setMutualAuthParams", "class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29", null ], + [ "stop", "class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe", null ], + [ "write", "class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86", null ], + [ "write", "class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d", null ] ]; \ No newline at end of file diff --git a/docs/html/class_s_s_l_client.png b/docs/html/class_s_s_l_client.png index 0519c9e396e13e9d09044f374bcda247c9e4d98d..181cd65589bc4519aef334438686659647f5eb6f 100644 GIT binary patch delta 333 zcmV-T0kZzx2K)jciBL{Q4GJ0x0000DNk~Le0000(0000`2m=5B0CiS4bde!Ce*p_g zL_t(|0qvd3ZiFxlMUOY!|NrAofDi}5G_6^TG?uPqY{9{gWRICy&@f2~Su!L!jTvRw z#jTR$GmncOC0h5u$G}Qn700000NkvXXu0mjf_z#y7 literal 861 zcmeAS@N?(olHy`uVBq!ia0vp^`+&HEgBeKXbuN?#QW60^A+G=b{|7Q(y!l$%e`o@b z1;z&s9ANFd15(3L666=m08|75S5Ji)F)%Q_@pN$vsbG9N_jTW9D;@@Qw^jH5_xf|I zh9A1QUbj@Ya_Y^7oh6ejp6P2YeIh<-)v9o(_|U6e7s5lgKH~c8?pjfj9ej0F?XTl{ z7vke9p1gCi-~ZmSsa8|&ZrPeuzZCVZ-@m+K&dODFUF%<-7xoJM8oKWKeX~u`e}zgH z#)r$bpS*niZ_TFn387d01><8wL$%?iD}4zKUAyD;@+p&|8P+{vdmw)Q*Y?@j_4j|3 zSD*iP?(5=D3^xRSF@&|)HHa?cPjG#~9D$eX6FDvQBX@U42hja4N4hSE3vPTQ`?uu( z>R(@X*q&cl^HQNqLP+o@bN-9`SF!hxyDrJwzs&wys^GTAAiq4W;C+An+KS$P-!3n; zzjpt!M(31mS>}O)6U8g?Uz;&oTwl*zy7@}JQTn3&xlit2o}Y8K`DVS_53T0ude=YdY!{cn>_ zH+B5%sj0eu0>d65XgImn-#xzc{9>)=haHX|_$>SRz@M8Z&pzKg`>Xlab?+ZL-2HW< z?!66z!Q&s#>MzRw-o$bH<35r8yct;yZB?Ax_5Qz)53`NEv>-;dF2`ryGEgwAm@}2V z|FdGer@^*|sb|mLy?SrU?OkUX&V7CT)FS@5(bdWwXS2%0Z*P@jyUf2}t<6;%zc1V0 zPQ8C~&5N4JcJi+$r7w%GTYTyLx6-(4pVw9!{JuM7&e?xE-oIWs|Hby_?V zRQJ35&;BNU*6u(!M=gW4ll%d$|G$8#ciMl3_GPnL-A&t00rLWbr>mdKI;Vst092>5 AfB*mh diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index 94cb202..ca1bf32 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -94,14 +94,9 @@ $(document).ready(function(){initNavTree('class_s_s_l_session.html','');});

            This is the complete list of members for SSLSession, including all inherited members.

            - - - - - - - - + + +
            clear_parameters()SSLSession
            get_hostname() constSSLSessioninline
            get_ip() constSSLSessioninline
            is_valid_session() constSSLSessioninline
            operator=(const SSLSession &)=deleteSSLSession
            set_parameters(const IPAddress &ip, const char *hostname=NULL)SSLSession
            SSLSession()SSLSessioninline
            to_br_session()SSLSessioninline
            get_hostname() constSSLSessioninline
            SSLSession(const char *hostname)SSLSessioninline
            to_br_session()SSLSessioninline
            diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index b5d0811..79e8cca 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -108,26 +108,12 @@ Inheritance diagram for SSLSession: - - - - - - + + + - - - - - - - - - - - @@ -138,8 +124,8 @@ Public Member Functions

            This file contains a simple utility class to store parameters about an SSL Session for reuse later.This class was created to extend the values stored in br_ssl_session_parameters, which allow BearSSL to resume an SSL session. When testing BearSSL's session resumption feature, it was observed that BearSSL can only resume a session that was was started with the same server. This becomes an issue when using repeated requests to a domain name which can resolve to multiple IP addresses ("api.github.com"), as the device will switch between two or three servers. Since BearSSL only stores one session at a time, this results in session resumption being few and far between.

            To remedy this problem, an SSLSession stores the IPAddress and hostname, along with the parameters in br_ssl_session_parameters struct. Using this data, SSLClient is able to remember which IPAddress is associated with which session, allowing it to reconnect to the last IPAddress, as opposed to any associated with the domain.

            Constructor & Destructor Documentation

            - -

            ◆ SSLSession()

            + +

            ◆ SSLSession()

            @@ -150,7 +136,8 @@ Public Member Functions
            - + +

            Public Member Functions

             SSLSession ()
             SSLSession constructor. More...
             
            SSLSessionoperator= (const SSLSession &)=delete
             use clear_parameters or set_parameters instead More...
             
             SSLSession (const char *hostname)
             SSLSession constructor. More...
             
            const String & get_hostname () const
             Get the hostname string associated with this session. More...
             
            const IPAddress & get_ip () const
             Get ::IPAddress associated with this session. More...
             
            bool is_valid_session () const
             
            void set_parameters (const IPAddress &ip, const char *hostname=NULL)
             Set the ip address and hostname of the session. More...
             
            void clear_parameters ()
             Delete the parameters and invalidate the session. More...
             
            br_ssl_session_parameters * to_br_session ()
             Returns a pointer to the ::br_ssl_session_parameters component of this class. More...
             
            SSLSession::SSLSession ()const char * hostname)
            @@ -167,26 +154,6 @@ Public Member Functions
          - - - - - - -
          void SSLSession::clear_parameters ()
          -
          - -

          Delete the parameters and invalidate the session.

          -

          Roughly equivalent to this_session = SSLSession(), however this function preserves the String object, allowing it to better handle the dynamic memory needed.

          - -
          -

          ◆ get_hostname()

          @@ -214,127 +181,6 @@ Public Member Functions
          - - - - -
          - - - - - - - -
          const IPAddress& SSLSession::get_ip () const
          -
          -inline
          -
          - -

          Get ::IPAddress associated with this session.

          -
          Returns
          A ::IPAddress object, #INADDR_NONE if there is no IP
          -
          Precondition
          must check isValidSession before getting this value, as if this session in invalid this value is not guarenteed to be reset to #INADDR_NONE.
          - -
          -
          - -

          ◆ is_valid_session()

          - -
          -
          - - - - - -
          - - - - - - - -
          bool SSLSession::is_valid_session () const
          -
          -inline
          -
          - -
          -
          - -

          ◆ operator=()

          - -
          -
          - - - - - -
          - - - - - - - - -
          SSLSession& SSLSession::operator= (const SSLSession)
          -
          -delete
          -
          - -

          use clear_parameters or set_parameters instead

          - -
          -
          - -

          ◆ set_parameters()

          - -
          -
          - - - - - - - - - - - - - - - - - - -
          void SSLSession::set_parameters (const IPAddress & ip,
          const char * hostname = NULL 
          )
          -
          - -

          Set the ip address and hostname of the session.

          -

          This function stores the ip Address object and hostname object into the session object. If hostname is not null or ip address is not blank, and the ::br_ssl_session_parameters values are non-zero it then validates the session.

          -
          Precondition
          You must call ::br_ssl_engine_get_session_parameters with this session before calling this function. This is because there is no way to completely validate the ::br_ssl_session_parameters and the session may end up in a corrupted state if this is not observed.
          -
          Parameters
          - - - -
          ipThe IP address of the host associated with the session
          hostnameThe string hostname ("www.google.com") associated with the session. Take care that this value is corrent, SSLSession performs no validation of the hostname.
          -
          -
          -
          @@ -364,9 +210,8 @@ Public Member Functions
          - - - + + + +
            s  
          -
          SSLClient   SSLClientParameters   
          SSLClientImpl   SSLSession   
          ssl_pem_decode_state   
          SSLClient   SSLSession   
          SSLClientParameters   
          ssl_pem_decode_state   
          diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 213ba14..97c64ed 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -96,20 +96,16 @@ $(document).ready(function(){initNavTree('dir_68267d1309a1af8e8297ef4c3efbcdba.h Files file  ec_prime_fast_256.c   +file  SSLClient.cpp +  file  SSLClient.h [code]   -file  SSLClientImpl.cpp -  -file  SSLClientImpl.h [code] -  file  SSLClientParameters.h [code]   file  SSLObj.cpp   file  SSLObj.h [code]   -file  SSLSession.cpp -  file  SSLSession.h [code]   file  time_macros.h [code] diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js index 6b5c86a..a47c04c 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js @@ -1,15 +1,15 @@ var dir_68267d1309a1af8e8297ef4c3efbcdba = [ [ "ec_prime_fast_256.c", "ec__prime__fast__256_8c.html", "ec__prime__fast__256_8c" ], - [ "SSLClient.h", "_s_s_l_client_8h.html", "_s_s_l_client_8h" ], - [ "SSLClientImpl.cpp", "_s_s_l_client_impl_8cpp.html", "_s_s_l_client_impl_8cpp" ], - [ "SSLClientImpl.h", "_s_s_l_client_impl_8h.html", "_s_s_l_client_impl_8h" ], + [ "SSLClient.cpp", "_s_s_l_client_8cpp.html", "_s_s_l_client_8cpp" ], + [ "SSLClient.h", "_s_s_l_client_8h.html", [ + [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ] + ] ], [ "SSLClientParameters.h", "_s_s_l_client_parameters_8h.html", [ [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ] ] ], [ "SSLObj.cpp", "_s_s_l_obj_8cpp.html", "_s_s_l_obj_8cpp" ], [ "SSLObj.h", "_s_s_l_obj_8h.html", "_s_s_l_obj_8h" ], - [ "SSLSession.cpp", "_s_s_l_session_8cpp.html", null ], [ "SSLSession.h", "_s_s_l_session_8h.html", [ [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] ] ], diff --git a/docs/html/files.html b/docs/html/files.html index 6672f57..95ada10 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -102,16 +102,14 @@ $(document).ready(function(){initNavTree('files.html','');});  cert.h   src  ec_prime_fast_256.c - SSLClient.h - SSLClientImpl.cpp - SSLClientImpl.h - SSLClientParameters.h - SSLObj.cpp - SSLObj.h - SSLSession.cpp - SSLSession.h - time_macros.h - TLS12_only_profile.c + SSLClient.cpp + SSLClient.h + SSLClientParameters.h + SSLObj.cpp + SSLObj.h + SSLSession.h + time_macros.h + TLS12_only_profile.c
          diff --git a/docs/html/functions.html b/docs/html/functions.html index de3bd8b..cc1ba07 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -91,10 +91,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

          - a -

          @@ -103,23 +100,21 @@ $(document).ready(function(){initNavTree('functions.html','');});
        • chain_len : SSLClientParameters
        • -
        • clear_parameters() -: SSLSession -
        • client_cert_chain : SSLClientParameters
        • connect() -: SSLClient< C, SessionCache > -
        • -
        • connect_impl() -: SSLClientImpl +: SSLClient
        • connected() -: SSLClient< C, SessionCache > +: SSLClient
        • -
        • connected_impl() -: SSLClientImpl +
        + + +

        - d -

        @@ -128,46 +123,31 @@ $(document).ready(function(){initNavTree('functions.html','');});
      • ec_key : SSLClientParameters
      • +
      • Error +: SSLClient +

      - f -

      - g -

      @@ -176,119 +156,78 @@ $(document).ready(function(){initNavTree('functions.html','');});
    • index : ssl_pem_decode_state
    • -
    • is_valid_session() -: SSLSession -
    • -
    - - -

    - l -

    - - -

    - m -

    - o -

    - p -

    - r -

    - s -

    @@ -309,10 +248,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

    - w -

    diff --git a/docs/html/functions_enum.html b/docs/html/functions_enum.html new file mode 100644 index 0000000..d14bd09 --- /dev/null +++ b/docs/html/functions_enum.html @@ -0,0 +1,109 @@ + + + + + + + +SSLClient: Class Members - Enumerations + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.3.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    + + + + diff --git a/docs/html/functions_eval.html b/docs/html/functions_eval.html new file mode 100644 index 0000000..0ff75bc --- /dev/null +++ b/docs/html/functions_eval.html @@ -0,0 +1,136 @@ + + + + + + + +SSLClient: Class Members - Enumerator + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.3.0 +
    +
    Add TLS 1.2 functionality to any network library.
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    + + + + diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index 7ff72b8..799ae11 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -87,209 +87,60 @@ $(document).ready(function(){initNavTree('functions_func.html','');});
    -  - -

    - a -

    diff --git a/docs/html/globals.html b/docs/html/globals.html index a3bb937..b704556 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -87,11 +87,9 @@ $(document).ready(function(){initNavTree('globals.html','');});
    -
    Here is a list of all file members with links to the files they belong to:
    - -

    - _ -

      +
      Here is a list of all file members with links to the files they belong to:
      - - -

      - b -

      - - -

      - c -

      • CONV_STR2DEC_1 : time_macros.h
      • @@ -146,38 +136,12 @@ $(document).ready(function(){initNavTree('globals.html','');});
      • CONV_STR2DEC_4 : time_macros.h
      • -
      - - -

      - d -

      - - -

      - e -

      - - -

      - g -

      - - -

      - p -

      - - -

      - s -

      - - -

      - t -

      - - -

      - u -

      • UNIX_TIMESTAMP : time_macros.h
      • diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index 6b52f8f..fef2962 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -145,9 +145,6 @@ $(document).ready(function(){initNavTree('globals_defs.html','');});
      • SEC_PER_YEAR : time_macros.h
      • -
      • SSLClient_H_ -: SSLClient.h -
      • TAs_NUM : trust_anchors.h , cert.h diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index 3ac6bb8..34445a7 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('globals_vars.html','');});
         
        • __brkval -: SSLClientImpl.cpp +: SSLClient.cpp
        • br_ec_prime_fast_256 : ec_prime_fast_256.c diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index a11880c..f525e14 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -92,14 +92,13 @@ $(document).ready(function(){initNavTree('hierarchy.html','');});
        This inheritance list is sorted roughly, but not completely, alphabetically:
        -
        [detail level 123]
        +
        [detail level 12]
        - - - - + + +
         Cbr_ssl_session_parameters
         CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
         CClient
         CSSLClientImplImplementation code to be inherited by SSLClient
         CSSLClient< C, SessionCache >The main SSLClient class. Check out README.md for more info
         Cssl_pem_decode_state
         CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
         CSSLClientThe main SSLClient class. Check out README.md for more info
         Cssl_pem_decode_state
         CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
        diff --git a/docs/html/hierarchy.js b/docs/html/hierarchy.js index bfd3475..5a0d7ae 100644 --- a/docs/html/hierarchy.js +++ b/docs/html/hierarchy.js @@ -4,9 +4,7 @@ var hierarchy = [ "SSLSession", "class_s_s_l_session.html", null ] ] ], [ "Client", null, [ - [ "SSLClientImpl", "class_s_s_l_client_impl.html", [ - [ "SSLClient< C, SessionCache >", "class_s_s_l_client.html", null ] - ] ] + [ "SSLClient", "class_s_s_l_client.html", null ] ] ], [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", null ], [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", null ] diff --git a/docs/html/index.html b/docs/html/index.html index ed54c66..2f790ee 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -104,13 +104,13 @@ $(document).ready(function(){initNavTree('index.html','');});
      • A Client class associated with a network interface. We tested this library using EthernetClient, however in theory it will work for any class implementing Client.
      • An analog pin, used for generating random data at the start of the connection (see the Implementation Gotchas).
      • -

        Once all those are ready, you can create a simple SSLClient object like this:

        {C++}
        SSLClient<BaseClientType> client(BaseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin);

        Where:

          -
        • BaseClientType - The type of BaseClientInstance
        • -
        • BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3)
        • +

          Once all those are ready, you can create a simple SSLClient object like this:

          {C++}
          BaseClientType baseClientInstance;
          SSLClient client(baseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin);

          Where:

            +
          • BaseClientType - The type of baseClientInstance
          • +
          • BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3). It is important that this instance be stored outside the SSLClient declaration (for instance, SSLClient(BaseClientType() ...) wouldn't work).
          • TAs - The name of the trust anchor array created in step 2. If you generated a header using the tutorial this will probably be TAs.
          • TAs_NUM - The number of trust anchors in TAs. If you generated a header using the tutorial this will probably be TAs_NUM.
          • AnalogPin - The analog pin to pull random data from (step 4).

            -

            For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using:

            {C++}
            SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);

            Once that is setup, simply use SSLClient as you would the base client class:

            {C++}
            // connect to ardiuino.cc over ssl (port 443 for websites)
            client.connect("www.arduino.cc", 443);
            // Make a HTTP request
            client.println("GET /asciilogo.txt HTTP/1.1");
            client.println("User-Agent: AdafruitFeatherM0WiFi");
            client.print("Host: ");
            client.println(server);
            client.println("Connection: close");
            client.println();
            client.flush();
            // read and print the data
            ...

            Note: client.connect("www.arduino.cc", 443) can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in Implementation Notes.

            +

            For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using:

            {C++}
            EthernetClient baseClient;
            SSLClient client(baseClient, TAs, 2, A7);

            Once that is setup, simply use SSLClient as you would the base client class:

            {C++}
            // connect to ardiuino.cc over ssl (port 443 for websites)
            client.connect("www.arduino.cc", 443);
            // Make a HTTP request
            client.println("GET /asciilogo.txt HTTP/1.1");
            client.println("User-Agent: AdafruitFeatherM0WiFi");
            client.print("Host: ");
            client.println(server);
            client.println("Connection: close");
            client.println();
            client.flush();
            // read and print the data
            ...

            Note: client.connect("www.arduino.cc", 443) can take 5-15 seconds to finish. This an unavoidable consequence of the SSL protocol, and is detailed in Implementation Notes.

          For more information on SSLClient, check out the examples, API documentation, or the rest of this README.

          @@ -119,13 +119,13 @@ $(document).ready(function(){initNavTree('index.html','');});

          Additionally, the bulk of SSLClient is split into two components: a template class SSLClient, and an implementation class SSLClientImpl. The template class serves to abstract some functions not implemented in the Arduino Client interface (such as EthernetClient::remoteIP), and the implementation class is the rest of the SSLClient library.

          Other Features

          Logging

          -

          SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor:

          {C++}
          SSLClient<EthernetClient> client(EthernetClient(), TAs, (size_t)2, A7, SSL_INFO);

          Logging is always outputted through the Arduino Serial interface, so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in DebugLevel. The log level is set to SSL_WARN by default.

          +

          SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor:

          {C++}
          EthernetClient baseClient;
          SSLClient client(baseClient, TAs, (size_t)2, A7, 1, SSLClient::SSL_INFO);

          Logging is always outputted through the Arduino Serial interface, so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in ::DebugLevel. The log level is set to SSL_WARN by default.

          Errors

          -

          When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from SSLClient::getWriteError(), which will return a value from the Error enum. For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at SSL_ERROR or lower.

          +

          When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from SSLClient::getWriteError(), which will return a value from the ::Error enum. For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at SSL_ERROR or lower.

          Write Buffering

          -

          As you may have noticed in the documentation for SSLClient::write, calling this function does not actually write to the network. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready and write to the network (see SSLClient::write for details).

          -

          This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so:

          {C++}
          EthernetClient client;
          // ...
          // connect to ardiuino.cc over ssl (port 443 for websites)
          client.connect("www.arduino.cc", 443);
          // ...
          // write an http request to the network
          client.write("GET /asciilogo.txt HTTP/1.1\r\n");
          client.write("Host: arduino.cc\r\n");
          client.write("Connection: close\r\n");
          // wait for response
          while (!client.available()) { /* ... */ }
          // ...

          Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

          -
          {C++}
          SSLClient<EthernetClient> client(EthernetClient(), TAs, 2, A7);
          // ...
          // connect to ardiuino.cc over ssl (port 443 for websites)
          client.connect("www.arduino.cc", 443);
          // ...
          // add http request to the buffer
          client.write("GET /asciilogo.txt HTTP/1.1\r\n");
          client.write("Host: arduino.cc\r\n");
          client.write("Connection: close\r\n");
          // write the bytes to the network, then wait for response
          while (!client.available()) { /* ... */ }
          // ...

          If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

          +

          As you may have noticed in the documentation for SSLClient::write, calling this function does not actually write to the network. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready and write to the network (see SSLClient::write for details).

          +

          This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so:

          {C++}
          EthernetClient client;
          // ...
          // connect to ardiuino.cc over ssl (port 443 for websites)
          client.connect("www.arduino.cc", 443);
          // ...
          // write an http request to the network
          client.write("GET /asciilogo.txt HTTP/1.1\r\n");
          client.write("Host: arduino.cc\r\n");
          client.write("Connection: close\r\n");
          // wait for response
          while (!client.available()) { /* ... */ }
          // ...

          Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

          +
          {C++}
          EthernetClient baseClient;
          SSLClient client(baseClient, TAs, (size_t)2, A7);
          // ...
          // connect to ardiuino.cc over ssl (port 443 for websites)
          client.connect("www.arduino.cc", 443);
          // ...
          // add http request to the buffer
          client.write("GET /asciilogo.txt HTTP/1.1\r\n");
          client.write("Host: arduino.cc\r\n");
          client.write("Connection: close\r\n");
          // write the bytes to the network, then wait for response
          while (!client.available()) { /* ... */ }
          // ...

          If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

          Session Caching

          As detailed in the resources section, SSL handshakes take an extended period (1-4sec) to negotiate. To remedy this problem, BearSSL is able to keep a SSL session cache of the clients it has connected to. If BearSSL successfully resumes an SSL session, it can reduce connection time to 100-500ms.

          In order to use SSL session resumption:

            @@ -133,9 +133,9 @@ $(document).ready(function(){initNavTree('index.html','');});
          • You must reuse the same SSLClient object (SSL Sessions are stored in the object itself).
          • You must reconnect to the exact same server.
          -

          SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call connect("www.google.com") SSLClient will use a IP address that recognizes the SSL session instead of another IP address associated with "www.google.com". However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection.

          +

          SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call connect("www.google.com") SSLClient will use the SSL session with that hostname. However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection.

          You can test whether or not a website can resume SSL Sessions using the Session Example included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume.

          -

          SSL sessions take a lot of memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration:

          {C++}
          SSLClient<EthernetClient, SomeNumber> client(EthernetClient(), TAs, 2, A7);

          Where SomeNumber is the number of sessions you would like to store. For example this declaration can store 3 sessions:

          {C++}
          SSLClient<EthernetClient, 3> client(EthernetClient(), TAs, 2, A7);

          Sessions are managed internally using the SSLSession::getSession function. This function will cycle through sessions in a rotating order, allowing the session cache to continually overwrite old sessions. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

          +

          SSL sessions take a lot of memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration:

          {C++}
          EthernetClient baseClient;
          SSLClient client(baseClient, TAs, (size_t)2, A7, SomeNumber);

          Where SomeNumber is the number of sessions you would like to store. For example this declaration can store 3 sessions:

          {C++}
          EthernetClient baseClient;
          SSLClient client(baseClient, TAs, (size_t)2, A7, 3);

          Sessions are managed internally using the SSLSession::getSession function. This function will cycle through sessions in a rotating order, allowing the session cache to continually overwrite old sessions. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

          If you need to clear a session, you can do so using the SSLSession::removeSession function.

          Implementation Gotchas

          Some ideas that didn't quite fit in the API documentation.

          @@ -143,7 +143,7 @@ $(document).ready(function(){initNavTree('index.html','');});

          If you are using the Arduino Ethernet library, you will need to modify the library to support the large buffer sizes required by SSL (detailed in resources). You can either modify the library yourself, or use this fork of the Ethernet library with the modification. To use the fork, simply install the library using the "add a .zip library" button in Arduino, and replace #include "Ethernet.h" with #include "EthernetLarge.h" in your sketch. Alternatively if for some reason this solution does not work, you can apply the modification using the instructions below.

          Manual Modification

          First find the location of the library in the directory where Arduino is installed (C:\Program Files (x86)\Arduino on Windows). Inside of this directory, navigate to libraries\Ethernet\src (C:\Program Files (x86)\Arduino\libraries\Ethernet\src on Windows). Modify Ethernet.h to replace these lines:

          {C++}
          ...
          // Configure the maximum number of sockets to support. W5100 chips can have
          // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
          // of RAM are used for each socket. Reducing the maximum can save RAM, but
          // you are limited to fewer simultaneous connections.
          #if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048)
          #define MAX_SOCK_NUM 4
          #else
          #define MAX_SOCK_NUM 8
          #endif
          // By default, each socket uses 2K buffers inside the Wiznet chip. If
          // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
          // this will use larger buffers within the Wiznet chip. Large buffers
          // can really help with UDP protocols like Artnet. In theory larger
          // buffers should allow faster TCP over high-latency links, but this
          // does not always seem to work in practice (maybe Wiznet bugs?)
          //#define ETHERNET_LARGE_BUFFERS
          ...

          With this:

          {C++}
          ...
          // Configure the maximum number of sockets to support. W5100 chips can have
          // up to 4 sockets. W5200 & W5500 can have up to 8 sockets. Several bytes
          // of RAM are used for each socket. Reducing the maximum can save RAM, but
          // you are limited to fewer simultaneous connections.
          #define MAX_SOCK_NUM 2
          // By default, each socket uses 2K buffers inside the Wiznet chip. If
          // MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
          // this will use larger buffers within the Wiznet chip. Large buffers
          // can really help with UDP protocols like Artnet. In theory larger
          // buffers should allow faster TCP over high-latency links, but this
          // does not always seem to work in practice (maybe Wiznet bugs?)
          #define ETHERNET_LARGE_BUFFERS
          ...

          You may need to use sudo or administrator permissions to make this modification. We change MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS so the Ethernet hardware can allocate a larger space for SSLClient, however a downside of this modification is we are now only able to have two sockets concurrently. As most microprocessors barely have enough memory for one SSL connection, this limitation will rarely be encountered in practice.

          -

          Random Data

          +

          Seeding Random Data

          The SSL protocol requires that SSLClient generate some random bits before connecting with a server. BearSSL provides a random number generator but requires a some entropy for a seed. Normally this seed is generated by taking the microsecond time using the internal clock, however since most microcontrollers are not build with this feature another source must be found. As a simple solution, SSLClient uses a floating analog pin as an external source of random data, passed through to the constructor in the analog_pin argument. Before every connection, SSLClient will take the bottom byte from 16 analog reads on analog_pin, and combine these bytes into a 16 byte random number, which is used as a seed for BearSSL. To ensure the most random data, it is recommended that this analog pin be either floating or connected to a location not modifiable by the microcontroller (i.e. a battery voltage readout).

          Certificate Verification

          SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. Check out this document for more details on this component of SSLClient.

          @@ -151,7 +151,7 @@ $(document).ready(function(){initNavTree('index.html','');});

          Resources

          The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive.

          To illustrate this, I will run some tests on various domains below. I haven't yet, but I will.

          -

          If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from SSLClient.h, SSLClientImpl.h, and SSLClientImpl.cpp. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself.

          +

          If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from SSLClient.h, SSLClientImpl.h, and SSLClientImpl.cpp. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself.

          Read Buffer Overflow

          SSL is a buffered protocol, and since most microcontrollers have limited resources (see Resources), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow, caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received, forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems, this could be the reason why.

          In order to remedy this problem, the device must be able to read the data faster than it is being received, or alternatively have a cache large enough to store the entire payload. Since SSL's encryption forces the device to read slowly, this means we must increase the cache size. Depending on your platform, there are a number of ways this can be done:

            @@ -161,7 +161,7 @@ $(document).ready(function(){initNavTree('index.html','');});
          • If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM.

          Cipher Support

          -

          By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

          {C++}
          br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
          // comment the above line and uncomment the line below if you're having trouble connecting over SSL
          // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

          to this:

          {C++}
          // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
          // comment the above line and uncomment the line below if you're having trouble connecting over SSL
          br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

          If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the BearSSL profiles documentation and I wish you the best of luck.

          +

          By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

          {C++}
          br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
          // comment the above line and uncomment the line below if you're having trouble connecting over SSL
          // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

          to this:

          {C++}
          // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
          // comment the above line and uncomment the line below if you're having trouble connecting over SSL
          br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

          If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the BearSSL profiles documentation and I wish you the best of luck.

    diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index b719965..d307879 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -92,7 +92,7 @@ $(document).ready(function(){initNavTree('md__c_1__users__noah__documents__ardui

    SSLClient uses BearSSL's minimal x509 verification engine to verify the certificate of an SSL connection. This engine requires the developer create a trust anchor array using values stored in trusted root certificates. In short, these trust anchor arrays allow BearSSL to verify that the server being connected to is who they say they are, and not someone malicious. You can read more about certificates and why they are important here.

    -

    SSLClient stores trust anchors in hardcoded constant variables, passed into SSLClient::SSLClient during setup. These constants are generally stored in their own header file as found in the BearSSL docs. This header file will look something like:

    {C++}
    #define TAs_NUM 1
    static const unsigned char TA_DN0[] = {
    // lots of raw bytes here
    // ...
    };
    static const unsigned char TA_RSA_N0[] = {
    // lots of raw bytes here
    //...
    };
    static const unsigned char TA_RSA_E0[] = {
    // 1-3 bytes here
    };
    static const br_x509_trust_anchor TAs[] = {
    {
    { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    BR_X509_TA_CA,
    {
    BR_KEYTYPE_RSA,
    { .rsa = {
    (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
    (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
    } }
    }
    },
    };

    A full example of a trust anchor header can be found in this file. Full documentation for the format of these variables can be found in the BearSSL documentation for br_x509_trust_anchor.

    +

    SSLClient stores trust anchors in hardcoded constant variables, passed into SSLClient::SSLClient during setup. These constants are generally stored in their own header file as found in the BearSSL docs. This header file will look something like:

    {C++}
    #define TAs_NUM 1
    static const unsigned char TA_DN0[] = {
    // lots of raw bytes here
    // ...
    };
    static const unsigned char TA_RSA_N0[] = {
    // lots of raw bytes here
    //...
    };
    static const unsigned char TA_RSA_E0[] = {
    // 1-3 bytes here
    };
    static const br_x509_trust_anchor TAs[] = {
    {
    { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    BR_X509_TA_CA,
    {
    BR_KEYTYPE_RSA,
    { .rsa = {
    (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
    (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
    } }
    }
    },
    };

    A full example of a trust anchor header can be found in this file. Full documentation for the format of these variables can be found in the BearSSL documentation for br_x509_trust_anchor.

    Generating Trust Anchors

    HTTPS

    For HTTPS, there a couple of tools you can use. Ordered from easiest to hardest:

      @@ -103,7 +103,7 @@ $(document).ready(function(){initNavTree('md__c_1__users__noah__documents__ardui

      Other Connections

      For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convert command to convert the certificate into a trust anchor header.

      Using Trust Anchors

      -

      Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

      {C++}
      #include "yourtrustanchorfile.h"
      // ...
      SSLClient<SomeClientType> client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
      // ...

      Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

      +

      Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

      {C++}
      #include "yourtrustanchorfile.h"
      // ...
      SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
      // ...

      Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

    diff --git a/docs/html/menudata.js b/docs/html/menudata.js index d7d7efc..529ffec 100644 --- a/docs/html/menudata.js +++ b/docs/html/menudata.js @@ -37,12 +37,11 @@ var menudata={children:[ {text:"All",url:"functions.html",children:[ {text:"a",url:"functions.html#index_a"}, {text:"c",url:"functions.html#index_c"}, +{text:"d",url:"functions.html#index_d"}, {text:"e",url:"functions.html#index_e"}, {text:"f",url:"functions.html#index_f"}, {text:"g",url:"functions.html#index_g"}, {text:"i",url:"functions.html#index_i"}, -{text:"l",url:"functions.html#index_l"}, -{text:"m",url:"functions.html#index_m"}, {text:"o",url:"functions.html#index_o"}, {text:"p",url:"functions.html#index_p"}, {text:"r",url:"functions.html#index_r"}, @@ -50,37 +49,14 @@ var menudata={children:[ {text:"t",url:"functions.html#index_t"}, {text:"v",url:"functions.html#index_v"}, {text:"w",url:"functions.html#index_w"}]}, -{text:"Functions",url:"functions_func.html",children:[ -{text:"a",url:"functions_func.html#index_a"}, -{text:"c",url:"functions_func.html#index_c"}, -{text:"f",url:"functions_func.html#index_f"}, -{text:"g",url:"functions_func.html#index_g"}, -{text:"i",url:"functions_func.html#index_i"}, -{text:"l",url:"functions_func.html#index_l"}, -{text:"m",url:"functions_func.html#index_m"}, -{text:"o",url:"functions_func.html#index_o"}, -{text:"p",url:"functions_func.html#index_p"}, -{text:"r",url:"functions_func.html#index_r"}, -{text:"s",url:"functions_func.html#index_s"}, -{text:"t",url:"functions_func.html#index_t"}, -{text:"w",url:"functions_func.html#index_w"}]}, -{text:"Variables",url:"functions_vars.html"}]}]}, +{text:"Functions",url:"functions_func.html"}, +{text:"Variables",url:"functions_vars.html"}, +{text:"Enumerations",url:"functions_enum.html"}, +{text:"Enumerator",url:"functions_eval.html"}]}]}, {text:"Files",url:"files.html",children:[ {text:"File List",url:"files.html"}, {text:"File Members",url:"globals.html",children:[ -{text:"All",url:"globals.html",children:[ -{text:"_",url:"globals.html#index__5F"}, -{text:"b",url:"globals.html#index_b"}, -{text:"c",url:"globals.html#index_c"}, -{text:"d",url:"globals.html#index_d"}, -{text:"e",url:"globals.html#index_e"}, -{text:"g",url:"globals.html#index_g"}, -{text:"p",url:"globals.html#index_p"}, -{text:"s",url:"globals.html#index_s"}, -{text:"t",url:"globals.html#index_t"}, -{text:"u",url:"globals.html#index_u"}]}, +{text:"All",url:"globals.html"}, {text:"Functions",url:"globals_func.html"}, {text:"Variables",url:"globals_vars.html"}, -{text:"Enumerations",url:"globals_enum.html"}, -{text:"Enumerator",url:"globals_eval.html"}, {text:"Macros",url:"globals_defs.html"}]}]}]} diff --git a/docs/html/navtreedata.js b/docs/html/navtreedata.js index c0fedb9..10bfff6 100644 --- a/docs/html/navtreedata.js +++ b/docs/html/navtreedata.js @@ -40,7 +40,9 @@ var NAVTREE = [ "Class Members", "functions.html", [ [ "All", "functions.html", null ], [ "Functions", "functions_func.html", null ], - [ "Variables", "functions_vars.html", null ] + [ "Variables", "functions_vars.html", null ], + [ "Enumerations", "functions_enum.html", null ], + [ "Enumerator", "functions_eval.html", null ] ] ] ] ], [ "Files", "files.html", [ @@ -49,8 +51,6 @@ var NAVTREE = [ "All", "globals.html", null ], [ "Functions", "globals_func.html", null ], [ "Variables", "globals_vars.html", null ], - [ "Enumerations", "globals_enum.html", null ], - [ "Enumerator", "globals_eval.html", null ], [ "Macros", "globals_defs.html", null ] ] ] ] ] @@ -59,7 +59,7 @@ var NAVTREE = var NAVTREEINDEX = [ -"_s_s_l_client_8h.html" +"_s_s_l_client_8cpp.html" ]; var SYNCONMSG = 'click to disable panel synchronisation'; diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index e9bd31d..5640f49 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -1,109 +1,59 @@ var NAVTREEINDEX0 = { -"_s_s_l_client_8h.html":[4,0,2,1], -"_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569":[4,0,2,1,1], -"_s_s_l_client_8h_source.html":[4,0,2,1], -"_s_s_l_client_impl_8cpp.html":[4,0,2,2], -"_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[4,0,2,2,0], -"_s_s_l_client_impl_8h.html":[4,0,2,3], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5":[4,0,2,3,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c":[4,0,2,3,2,0], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b":[4,0,2,3,2,3], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9":[4,0,2,3,2,4], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b":[4,0,2,3,2,1], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6":[4,0,2,3,2,6], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3":[4,0,2,3,2,2], -"_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc":[4,0,2,3,2,5], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395":[4,0,2,3,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d":[4,0,2,3,1,2], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91":[4,0,2,3,1,3], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec":[4,0,2,3,1,1], -"_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f":[4,0,2,3,1,0], -"_s_s_l_client_impl_8h_source.html":[4,0,2,3], -"_s_s_l_client_parameters_8h.html":[4,0,2,4], -"_s_s_l_client_parameters_8h_source.html":[4,0,2,4], -"_s_s_l_obj_8cpp.html":[4,0,2,5], -"_s_s_l_obj_8h.html":[4,0,2,6], -"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[4,0,2,6,0], -"_s_s_l_obj_8h_source.html":[4,0,2,6], -"_s_s_l_session_8cpp.html":[4,0,2,7], -"_s_s_l_session_8h.html":[4,0,2,8], -"_s_s_l_session_8h_source.html":[4,0,2,8], -"_t_l_s12__only__profile_8c.html":[4,0,2,10], -"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[4,0,2,10,0], +"_s_s_l_client_8cpp.html":[4,0,2,1], +"_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[4,0,2,1,0], +"_s_s_l_client_8h.html":[4,0,2,2], +"_s_s_l_client_8h_source.html":[4,0,2,2], +"_s_s_l_client_parameters_8h.html":[4,0,2,3], +"_s_s_l_client_parameters_8h_source.html":[4,0,2,3], +"_s_s_l_obj_8cpp.html":[4,0,2,4], +"_s_s_l_obj_8h.html":[4,0,2,5], +"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[4,0,2,5,0], +"_s_s_l_obj_8h_source.html":[4,0,2,5], +"_s_s_l_session_8h.html":[4,0,2,6], +"_s_s_l_session_8h_source.html":[4,0,2,6], +"_t_l_s12__only__profile_8c.html":[4,0,2,8], +"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[4,0,2,8,0], "annotated.html":[3,0], "cert_8h.html":[4,0,1,0], "cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,1,0,0], "cert_8h_source.html":[4,0,1,0], "class_s_s_l_client.html":[3,0,1], -"class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f":[3,0,1,25], -"class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd":[3,0,1,9], -"class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc":[3,0,1,4], -"class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1":[3,0,1,14], -"class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd":[3,0,1,12], -"class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086":[3,0,1,11], -"class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44":[3,0,1,5], -"class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd":[3,0,1,19], -"class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52":[3,0,1,7], -"class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630":[3,0,1,2], -"class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc":[3,0,1,17], -"class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73":[3,0,1,13], -"class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22":[3,0,1,23], -"class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c":[3,0,1,24], -"class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e":[3,0,1,1], -"class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9":[3,0,1,18], -"class_s_s_l_client.html#a6b8ff53c10fe34aab1dc2561410f70bb":[3,0,1,27], -"class_s_s_l_client.html#a6bcb7579ebc051c097acb794b95771a9":[3,0,1,28], -"class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1":[3,0,1,15], -"class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf":[3,0,1,3], -"class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a":[3,0,1,6], -"class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9":[3,0,1,8], -"class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529":[3,0,1,26], -"class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b":[3,0,1,16], -"class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0":[3,0,1,0], -"class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e":[3,0,1,20], -"class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174":[3,0,1,22], -"class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41":[3,0,1,10], -"class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795":[3,0,1,21], -"class_s_s_l_client_impl.html":[3,0,2], -"class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d":[3,0,2,21], -"class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3":[3,0,2,7], -"class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788":[3,0,2,6], -"class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe":[3,0,2,22], -"class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b":[3,0,2,0], -"class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f":[3,0,2,20], -"class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed":[3,0,2,17], -"class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c":[3,0,2,15], -"class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b":[3,0,2,9], -"class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117":[3,0,2,16], -"class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5":[3,0,2,13], -"class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1":[3,0,2,25], -"class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075":[3,0,2,19], -"class_s_s_l_client_impl.html#a807656f814f24cf6cd711e429b716c4d":[3,0,2,28], -"class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6":[3,0,2,27], -"class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea":[3,0,2,1], -"class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b":[3,0,2,12], -"class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5":[3,0,2,24], -"class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb":[3,0,2,5], -"class_s_s_l_client_impl.html#a9dd694f8e0e65624b103dc781a7744af":[3,0,2,26], -"class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f":[3,0,2,18], -"class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b":[3,0,2,3], -"class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336":[3,0,2,8], -"class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e":[3,0,2,11], -"class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b":[3,0,2,2], -"class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4":[3,0,2,10], -"class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83":[3,0,2,14], -"class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba":[3,0,2,4], -"class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387":[3,0,2,23], -"class_s_s_l_session.html":[3,0,4], -"class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076":[3,0,4,4], -"class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e":[3,0,4,6], -"class_s_s_l_session.html#a3305941fa615f7134526b718917716ee":[3,0,4,1], -"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[3,0,4,2], -"class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0":[3,0,4,3], -"class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f":[3,0,4,5], -"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[3,0,4,7], -"class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb":[3,0,4,0], +"class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86":[3,0,1,18], +"class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86":[3,0,1,12], +"class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78":[3,0,1,3], +"class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90":[3,0,1,5], +"class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3":[3,0,1,9], +"class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b":[3,0,1,11], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea":[3,0,1,1], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08":[3,0,1,1,6], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94":[3,0,1,1,0], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016":[3,0,1,1,4], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5":[3,0,1,1,2], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd":[3,0,1,1,1], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8":[3,0,1,1,3], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84":[3,0,1,1,5], +"class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95":[3,0,1,13], +"class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae":[3,0,1,6], +"class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376":[3,0,1,2], +"class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d":[3,0,1,19], +"class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21":[3,0,1,8], +"class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29":[3,0,1,16], +"class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c":[3,0,1,7], +"class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3":[3,0,1,4], +"class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4":[3,0,1,15], +"class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe":[3,0,1,17], +"class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22":[3,0,1,10], +"class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb":[3,0,1,14], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1":[3,0,1,0], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5":[3,0,1,0,1], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75":[3,0,1,0,0], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97":[3,0,1,0,2], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2":[3,0,1,0,3], +"class_s_s_l_session.html":[3,0,3], +"class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74":[3,0,3,0], +"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[3,0,3,1], +"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[3,0,3,2], "classes.html":[3,1], "dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[4,0,0,1], "dir_68267d1309a1af8e8297ef4c3efbcdba.html":[4,0,2], @@ -114,12 +64,12 @@ var NAVTREEINDEX0 = "ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab":[4,0,2,0,0], "files.html":[4,0], "functions.html":[3,3,0], +"functions_enum.html":[3,3,3], +"functions_eval.html":[3,3,4], "functions_func.html":[3,3,1], "functions_vars.html":[3,3,2], "globals.html":[4,1,0], -"globals_defs.html":[4,1,5], -"globals_enum.html":[4,1,3], -"globals_eval.html":[4,1,4], +"globals_defs.html":[4,1,3], "globals_func.html":[4,1,1], "globals_vars.html":[4,1,2], "hierarchy.html":[3,2], @@ -131,36 +81,36 @@ var NAVTREEINDEX0 = "namespacemembers_func.html":[2,1,1], "namespaces.html":[2,0], "pages.html":[], -"struct_s_s_l_client_parameters.html":[3,0,3], -"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[3,0,3,1], -"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[3,0,3,0], -"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[3,0,3,2], +"struct_s_s_l_client_parameters.html":[3,0,2], +"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[3,0,2,1], +"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[3,0,2,0], +"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[3,0,2,2], "structssl__pem__decode__state.html":[3,0,0], "structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3":[3,0,0,0], "structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9":[3,0,0,1], -"time__macros_8h.html":[4,0,2,9], -"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[4,0,2,9,19], -"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[4,0,2,9,14], -"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[4,0,2,9,1], -"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[4,0,2,9,20], -"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[4,0,2,9,16], -"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[4,0,2,9,4], -"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[4,0,2,9,15], -"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[4,0,2,9,13], -"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[4,0,2,9,5], -"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[4,0,2,9,8], -"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[4,0,2,9,0], -"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[4,0,2,9,6], -"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[4,0,2,9,18], -"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[4,0,2,9,12], -"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[4,0,2,9,11], -"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[4,0,2,9,2], -"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[4,0,2,9,7], -"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[4,0,2,9,17], -"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[4,0,2,9,3], -"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[4,0,2,9,9], -"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[4,0,2,9,10], -"time__macros_8h_source.html":[4,0,2,9], +"time__macros_8h.html":[4,0,2,7], +"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[4,0,2,7,19], +"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[4,0,2,7,14], +"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[4,0,2,7,1], +"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[4,0,2,7,20], +"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[4,0,2,7,16], +"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[4,0,2,7,4], +"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[4,0,2,7,15], +"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[4,0,2,7,13], +"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[4,0,2,7,5], +"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[4,0,2,7,8], +"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[4,0,2,7,0], +"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[4,0,2,7,6], +"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[4,0,2,7,18], +"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[4,0,2,7,12], +"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[4,0,2,7,11], +"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[4,0,2,7,2], +"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[4,0,2,7,7], +"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[4,0,2,7,17], +"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[4,0,2,7,3], +"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[4,0,2,7,9], +"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[4,0,2,7,10], +"time__macros_8h_source.html":[4,0,2,7], "trust__anchors_8h.html":[4,0,0,0,0], "trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,0,0,0,0], "trust__anchors_8h_source.html":[4,0,0,0,0], diff --git a/docs/html/search/all_0.js b/docs/html/search/all_0.js index e3a632e..312f869 100644 --- a/docs/html/search/all_0.js +++ b/docs/html/search/all_0.js @@ -1,6 +1,6 @@ var searchData= [ - ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClientImpl.cpp']]], + ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClient.cpp']]], ['_5f_5ftime_5fdays_5f_5f',['__TIME_DAYS__',['../time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf',1,'time_macros.h']]], ['_5f_5ftime_5fhours_5f_5f',['__TIME_HOURS__',['../time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4',1,'time_macros.h']]], ['_5f_5ftime_5fminutes_5f_5f',['__TIME_MINUTES__',['../time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8',1,'time_macros.h']]], diff --git a/docs/html/search/all_1.js b/docs/html/search/all_1.js index 6e54ada..0728bc1 100644 --- a/docs/html/search/all_1.js +++ b/docs/html/search/all_1.js @@ -1,5 +1,4 @@ var searchData= [ - ['available',['available',['../class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e',1,'SSLClient']]], - ['available_5fimpl',['available_impl',['../class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b',1,'SSLClientImpl']]] + ['available',['available',['../class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_10.js b/docs/html/search/all_10.js index a658122..a18bd2a 100644 --- a/docs/html/search/all_10.js +++ b/docs/html/search/all_10.js @@ -1,5 +1,4 @@ var searchData= [ - ['unix_5ftimestamp',['UNIX_TIMESTAMP',['../time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487',1,'time_macros.h']]], - ['unix_5ftimestamp_5futc',['UNIX_TIMESTAMP_UTC',['../time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3',1,'time_macros.h']]] + ['vect',['vect',['../structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js index a18bd2a..451bfc6 100644 --- a/docs/html/search/all_11.js +++ b/docs/html/search/all_11.js @@ -1,4 +1,4 @@ var searchData= [ - ['vect',['vect',['../structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9',1,'ssl_pem_decode_state']]] + ['write',['write',['../class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86',1,'SSLClient::write(const uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d',1,'SSLClient::write(uint8_t b) override']]] ]; diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js index e6f18e0..13385d1 100644 --- a/docs/html/search/all_3.js +++ b/docs/html/search/all_3.js @@ -2,12 +2,9 @@ var searchData= [ ['cert_2eh',['cert.h',['../cert_8h.html',1,'']]], ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], - ['clear_5fparameters',['clear_parameters',['../class_s_s_l_session.html#a3305941fa615f7134526b718917716ee',1,'SSLSession']]], ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]], - ['connect',['connect',['../class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf',1,'SSLClient::connect(const char *host, uint16_t port) override']]], - ['connect_5fimpl',['connect_impl',['../class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b',1,'SSLClientImpl::connect_impl(IPAddress ip, uint16_t port)'],['../class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba',1,'SSLClientImpl::connect_impl(const char *host, uint16_t port)']]], - ['connected',['connected',['../class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc',1,'SSLClient']]], - ['connected_5fimpl',['connected_impl',['../class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb',1,'SSLClientImpl']]], + ['connect',['connect',['../class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90',1,'SSLClient::connect(const char *host, uint16_t port) override']]], + ['connected',['connected',['../class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae',1,'SSLClient']]], ['conv_5fstr2dec_5f1',['CONV_STR2DEC_1',['../time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a',1,'time_macros.h']]], ['conv_5fstr2dec_5f2',['CONV_STR2DEC_2',['../time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3',1,'time_macros.h']]], ['conv_5fstr2dec_5f3',['CONV_STR2DEC_3',['../time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4',1,'time_macros.h']]], diff --git a/docs/html/search/all_4.js b/docs/html/search/all_4.js index a3cc239..1630eb3 100644 --- a/docs/html/search/all_4.js +++ b/docs/html/search/all_4.js @@ -1,4 +1,4 @@ var searchData= [ - ['debuglevel',['DebugLevel',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395',1,'SSLClientImpl.h']]] + ['debuglevel',['DebugLevel',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_5.js b/docs/html/search/all_5.js index e49278d..143336e 100644 --- a/docs/html/search/all_5.js +++ b/docs/html/search/all_5.js @@ -2,5 +2,5 @@ var searchData= [ ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]], ['ec_5fprime_5ffast_5f256_2ec',['ec_prime_fast_256.c',['../ec__prime__fast__256_8c.html',1,'']]], - ['error',['Error',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5',1,'SSLClientImpl.h']]] + ['error',['Error',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js index 3dc70e4..47e3882 100644 --- a/docs/html/search/all_6.js +++ b/docs/html/search/all_6.js @@ -1,5 +1,4 @@ var searchData= [ - ['flush',['flush',['../class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44',1,'SSLClient']]], - ['flush_5fimpl',['flush_impl',['../class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788',1,'SSLClientImpl']]] + ['flush',['flush',['../class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js index fcf2600..48ec004 100644 --- a/docs/html/search/all_7.js +++ b/docs/html/search/all_7.js @@ -1,12 +1,8 @@ var searchData= [ - ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a',1,'SSLClient::get_arduino_client() override'],['../class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52',1,'SSLClient::get_arduino_client() const override'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], - ['get_5fip',['get_ip',['../class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0',1,'SSLSession']]], ['get_5fmonth',['GET_MONTH',['../time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994',1,'time_macros.h']]], - ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9',1,'SSLClient::get_session_array() override'],['../class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd',1,'SSLClient::get_session_array() const override'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], - ['get_5fsession_5fimpl',['get_session_impl',['../class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e',1,'SSLClientImpl']]], - ['getclient',['getClient',['../class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41',1,'SSLClient']]], - ['getsession',['getSession',['../class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086',1,'SSLClient']]], - ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] + ['getclient',['getClient',['../class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21',1,'SSLClient']]], + ['getsession',['getSession',['../class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3',1,'SSLClient']]], + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js index c29a2f2..2d07945 100644 --- a/docs/html/search/all_8.js +++ b/docs/html/search/all_8.js @@ -1,5 +1,4 @@ var searchData= [ - ['index',['index',['../structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3',1,'ssl_pem_decode_state']]], - ['is_5fvalid_5fsession',['is_valid_session',['../class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076',1,'SSLSession']]] + ['index',['index',['../structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/html/search/all_9.js b/docs/html/search/all_9.js index 0773563..e4f8b0f 100644 --- a/docs/html/search/all_9.js +++ b/docs/html/search/all_9.js @@ -1,4 +1,4 @@ var searchData= [ - ['localport',['localPort',['../class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] + ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] ]; diff --git a/docs/html/search/all_a.js b/docs/html/search/all_a.js index f9c2b25..0aecf24 100644 --- a/docs/html/search/all_a.js +++ b/docs/html/search/all_a.js @@ -1,11 +1,4 @@ var searchData= [ - ['m_5ferror',['m_error',['../class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83',1,'SSLClientImpl']]], - ['m_5finfo',['m_info',['../class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c',1,'SSLClientImpl']]], - ['m_5fprint',['m_print',['../class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117',1,'SSLClientImpl']]], - ['m_5fprint_5fbr_5ferror',['m_print_br_error',['../class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed',1,'SSLClientImpl']]], - ['m_5fprint_5fprefix',['m_print_prefix',['../class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f',1,'SSLClientImpl']]], - ['m_5fprint_5fssl_5ferror',['m_print_ssl_error',['../class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075',1,'SSLClientImpl']]], - ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]], - ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_b.js b/docs/html/search/all_b.js index d7f8a71..95f21a7 100644 --- a/docs/html/search/all_b.js +++ b/docs/html/search/all_b.js @@ -1,7 +1,5 @@ var searchData= [ - ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1',1,'SSLClient']]], - ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b',1,'SSLClient::operator!=(const C &rhs)']]], - ['operator_3d',['operator=',['../class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f',1,'SSLSession']]], - ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9',1,'SSLClient::operator==(const C &rhs)']]] + ['peek',['peek',['../class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86',1,'SSLClient']]], + ['pst_5foffset',['PST_OFFSET',['../time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb',1,'time_macros.h']]] ]; diff --git a/docs/html/search/all_c.js b/docs/html/search/all_c.js index 6de2fa7..3e07012 100644 --- a/docs/html/search/all_c.js +++ b/docs/html/search/all_c.js @@ -1,6 +1,6 @@ var searchData= [ - ['peek',['peek',['../class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd',1,'SSLClient']]], - ['peek_5fimpl',['peek_impl',['../class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d',1,'SSLClientImpl']]], - ['pst_5foffset',['PST_OFFSET',['../time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb',1,'time_macros.h']]] + ['read',['read',['../class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95',1,'SSLClient::read(uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb',1,'SSLClient::read() override']]], + ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]], + ['removesession',['removeSession',['../class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_d.js b/docs/html/search/all_d.js index 6283be9..cf50882 100644 --- a/docs/html/search/all_d.js +++ b/docs/html/search/all_d.js @@ -1,10 +1,32 @@ var searchData= [ - ['read',['read',['../class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e',1,'SSLClient::read() override'],['../class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795',1,'SSLClient::read(uint8_t *buf, size_t size) override']]], - ['read_5fimpl',['read_impl',['../class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe',1,'SSLClientImpl']]], - ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]], - ['remoteip',['remoteIP',['../class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], - ['remoteport',['remotePort',['../class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], - ['remove_5fsession_5fimpl',['remove_session_impl',['../class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1',1,'SSLClientImpl']]], - ['removesession',['removeSession',['../class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c',1,'SSLClient']]] + ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../index.html',1,'']]], + ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], + ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], + ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], + ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], + ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29',1,'SSLClient']]], + ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5',1,'SSLClient']]], + ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016',1,'SSLClient']]], + ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd',1,'SSLClient']]], + ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8',1,'SSLClient']]], + ['ssl_5ferror',['SSL_ERROR',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5',1,'SSLClient']]], + ['ssl_5finfo',['SSL_INFO',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2',1,'SSLClient']]], + ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84',1,'SSLClient']]], + ['ssl_5fnone',['SSL_NONE',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75',1,'SSLClient']]], + ['ssl_5fok',['SSL_OK',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94',1,'SSLClient']]], + ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08',1,'SSLClient']]], + ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], + ['ssl_5fwarn',['SSL_WARN',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97',1,'SSLClient']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient'],['../class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376',1,'SSLClient::SSLClient()']]], + ['sslclient_2ecpp',['SSLClient.cpp',['../_s_s_l_client_8cpp.html',1,'']]], + ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], + ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], + ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], + ['sslobj',['SSLObj',['../namespace_s_s_l_obj.html',1,'']]], + ['sslobj_2ecpp',['SSLObj.cpp',['../_s_s_l_obj_8cpp.html',1,'']]], + ['sslobj_2eh',['SSLObj.h',['../_s_s_l_obj_8h.html',1,'']]], + ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74',1,'SSLSession::SSLSession()']]], + ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], + ['stop',['stop',['../class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js index 0383728..45a40de 100644 --- a/docs/html/search/all_e.js +++ b/docs/html/search/all_e.js @@ -1,39 +1,11 @@ var searchData= [ - ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../index.html',1,'']]], - ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], - ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], - ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], - ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], - ['set_5fmutual_5fimpl',['set_mutual_impl',['../class_s_s_l_client_impl.html#a9dd694f8e0e65624b103dc781a7744af',1,'SSLClientImpl']]], - ['set_5fparameters',['set_parameters',['../class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e',1,'SSLSession']]], - ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f',1,'SSLClient']]], - ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3',1,'SSLClientImpl.h']]], - ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9',1,'SSLClientImpl.h']]], - ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b',1,'SSLClientImpl.h']]], - ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b',1,'SSLClientImpl.h']]], - ['ssl_5ferror',['SSL_ERROR',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec',1,'SSLClientImpl.h']]], - ['ssl_5finfo',['SSL_INFO',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91',1,'SSLClientImpl.h']]], - ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc',1,'SSLClientImpl.h']]], - ['ssl_5fnone',['SSL_NONE',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f',1,'SSLClientImpl.h']]], - ['ssl_5fok',['SSL_OK',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c',1,'SSLClientImpl.h']]], - ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6',1,'SSLClientImpl.h']]], - ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], - ['ssl_5fwarn',['SSL_WARN',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d',1,'SSLClientImpl.h']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient< C, SessionCache >'],['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient::SSLClient()']]], - ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], - ['sslclient_5fh_5f',['SSLClient_H_',['../_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569',1,'SSLClient.h']]], - ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'SSLClientImpl'],['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)'],['../class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], - ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], - ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], - ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], - ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], - ['sslobj',['SSLObj',['../namespace_s_s_l_obj.html',1,'']]], - ['sslobj_2ecpp',['SSLObj.cpp',['../_s_s_l_obj_8cpp.html',1,'']]], - ['sslobj_2eh',['SSLObj.h',['../_s_s_l_obj_8h.html',1,'']]], - ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession::SSLSession()']]], - ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], - ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], - ['stop',['stop',['../class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529',1,'SSLClient']]], - ['stop_5fimpl',['stop_impl',['../class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6',1,'SSLClientImpl']]] + ['trust_20anchors',['Trust Anchors',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]], + ['tas_5fnum',['TAs_NUM',['../trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trust_anchors.h'],['../trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trustanchors.h'],['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): cert.h']]], + ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], + ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], + ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]], + ['trust_5fanchors_2eh',['trust_anchors.h',['../trust__anchors_8h.html',1,'']]], + ['trustanchors_2eh',['trustanchors.h',['../trustanchors_8h.html',1,'']]], + ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] ]; diff --git a/docs/html/search/all_f.js b/docs/html/search/all_f.js index 45a40de..a658122 100644 --- a/docs/html/search/all_f.js +++ b/docs/html/search/all_f.js @@ -1,11 +1,5 @@ var searchData= [ - ['trust_20anchors',['Trust Anchors',['../md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]], - ['tas_5fnum',['TAs_NUM',['../trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trust_anchors.h'],['../trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): trustanchors.h'],['../cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948',1,'TAs_NUM(): cert.h']]], - ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], - ['tls12_5fonly_5fprofile_2ec',['TLS12_only_profile.c',['../_t_l_s12__only__profile_8c.html',1,'']]], - ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]], - ['trust_5fanchors_2eh',['trust_anchors.h',['../trust__anchors_8h.html',1,'']]], - ['trustanchors_2eh',['trustanchors.h',['../trustanchors_8h.html',1,'']]], - ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] + ['unix_5ftimestamp',['UNIX_TIMESTAMP',['../time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487',1,'time_macros.h']]], + ['unix_5ftimestamp_5futc',['UNIX_TIMESTAMP_UTC',['../time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3',1,'time_macros.h']]] ]; diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js index f951cf3..81431f8 100644 --- a/docs/html/search/classes_0.js +++ b/docs/html/search/classes_0.js @@ -2,7 +2,6 @@ var searchData= [ ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'']]], - ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html',1,'']]], ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'']]] ]; diff --git a/docs/html/search/defines_4.js b/docs/html/search/defines_4.js index 2572f0d..1c7ae85 100644 --- a/docs/html/search/defines_4.js +++ b/docs/html/search/defines_4.js @@ -3,6 +3,5 @@ var searchData= ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], - ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], - ['sslclient_5fh_5f',['SSLClient_H_',['../_s_s_l_client_8h.html#a0e14869de8f634ff2fb63826ae583569',1,'SSLClient.h']]] + ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]] ]; diff --git a/docs/html/search/enums_0.js b/docs/html/search/enums_0.js index a3cc239..1630eb3 100644 --- a/docs/html/search/enums_0.js +++ b/docs/html/search/enums_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['debuglevel',['DebugLevel',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395',1,'SSLClientImpl.h']]] + ['debuglevel',['DebugLevel',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1',1,'SSLClient']]] ]; diff --git a/docs/html/search/enums_1.js b/docs/html/search/enums_1.js index 212a9a9..2f4b1da 100644 --- a/docs/html/search/enums_1.js +++ b/docs/html/search/enums_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['error',['Error',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5',1,'SSLClientImpl.h']]] + ['error',['Error',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea',1,'SSLClient']]] ]; diff --git a/docs/html/search/enumvalues_0.js b/docs/html/search/enumvalues_0.js index 0dc67d2..0455a1a 100644 --- a/docs/html/search/enumvalues_0.js +++ b/docs/html/search/enumvalues_0.js @@ -1,14 +1,14 @@ var searchData= [ - ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afb90a695332a7c96044dc97c577ee3c3',1,'SSLClientImpl.h']]], - ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d9afd51e0012e791f099657797c9aa9',1,'SSLClientImpl.h']]], - ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5aaa79045423a355885738cd239dff6c2b',1,'SSLClientImpl.h']]], - ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1d5f8248fac85f56b05d49c7cb53494b',1,'SSLClientImpl.h']]], - ['ssl_5ferror',['SSL_ERROR',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395ad3f9f0591dcabc4fac1222c462bf17ec',1,'SSLClientImpl.h']]], - ['ssl_5finfo',['SSL_INFO',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a8c0bb62be3d0e6bfe5ed2f7ebbed3d91',1,'SSLClientImpl.h']]], - ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5afd588a56dcccf4f6943defa7ab699afc',1,'SSLClientImpl.h']]], - ['ssl_5fnone',['SSL_NONE',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395af16e73d8cce9a2c987bde5afe5524d7f',1,'SSLClientImpl.h']]], - ['ssl_5fok',['SSL_OK',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5a1218c16a5bf50589e0c498983851612c',1,'SSLClientImpl.h']]], - ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../_s_s_l_client_impl_8h.html#a2c3e4bb40f36b262a5214e2da2bca9c5adec799caf92b4fe2b6d2b362136f6ef6',1,'SSLClientImpl.h']]], - ['ssl_5fwarn',['SSL_WARN',['../_s_s_l_client_impl_8h.html#ab658e6d84759440dbf3c890446075395a86c8fdfc38831619d5ed73dff5b0911d',1,'SSLClientImpl.h']]] + ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5',1,'SSLClient']]], + ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016',1,'SSLClient']]], + ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd',1,'SSLClient']]], + ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8',1,'SSLClient']]], + ['ssl_5ferror',['SSL_ERROR',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5',1,'SSLClient']]], + ['ssl_5finfo',['SSL_INFO',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2',1,'SSLClient']]], + ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84',1,'SSLClient']]], + ['ssl_5fnone',['SSL_NONE',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75',1,'SSLClient']]], + ['ssl_5fok',['SSL_OK',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94',1,'SSLClient']]], + ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08',1,'SSLClient']]], + ['ssl_5fwarn',['SSL_WARN',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97',1,'SSLClient']]] ]; diff --git a/docs/html/search/files_3.js b/docs/html/search/files_3.js index 4b15112..212b513 100644 --- a/docs/html/search/files_3.js +++ b/docs/html/search/files_3.js @@ -1,11 +1,9 @@ var searchData= [ + ['sslclient_2ecpp',['SSLClient.cpp',['../_s_s_l_client_8cpp.html',1,'']]], ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], - ['sslclientimpl_2ecpp',['SSLClientImpl.cpp',['../_s_s_l_client_impl_8cpp.html',1,'']]], - ['sslclientimpl_2eh',['SSLClientImpl.h',['../_s_s_l_client_impl_8h.html',1,'']]], ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], ['sslobj_2ecpp',['SSLObj.cpp',['../_s_s_l_obj_8cpp.html',1,'']]], ['sslobj_2eh',['SSLObj.h',['../_s_s_l_obj_8h.html',1,'']]], - ['sslsession_2ecpp',['SSLSession.cpp',['../_s_s_l_session_8cpp.html',1,'']]], ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]] ]; diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js index 6e54ada..0728bc1 100644 --- a/docs/html/search/functions_0.js +++ b/docs/html/search/functions_0.js @@ -1,5 +1,4 @@ var searchData= [ - ['available',['available',['../class_s_s_l_client.html#a5d13fd2f32ee2ea65a1f3820f758e77e',1,'SSLClient']]], - ['available_5fimpl',['available_impl',['../class_s_s_l_client_impl.html#abe33c793ec37f11087651cf4e586569b',1,'SSLClientImpl']]] + ['available',['available',['../class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_2.js b/docs/html/search/functions_2.js index 47de2ad..171bc1c 100644 --- a/docs/html/search/functions_2.js +++ b/docs/html/search/functions_2.js @@ -1,8 +1,5 @@ var searchData= [ - ['clear_5fparameters',['clear_parameters',['../class_s_s_l_session.html#a3305941fa615f7134526b718917716ee',1,'SSLSession']]], - ['connect',['connect',['../class_s_s_l_client.html#a4a2172aedfcc483ba2a256ad12148630',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a91c63e35f31652c20faa5b9be95984bf',1,'SSLClient::connect(const char *host, uint16_t port) override']]], - ['connect_5fimpl',['connect_impl',['../class_s_s_l_client_impl.html#aa5c14ecf301c268306946c85825e565b',1,'SSLClientImpl::connect_impl(IPAddress ip, uint16_t port)'],['../class_s_s_l_client_impl.html#ae6c947ad92979ab99364428004abbeba',1,'SSLClientImpl::connect_impl(const char *host, uint16_t port)']]], - ['connected',['connected',['../class_s_s_l_client.html#a25e4414ab0c9424d09592f9567a678dc',1,'SSLClient']]], - ['connected_5fimpl',['connected_impl',['../class_s_s_l_client_impl.html#a957984fa392550a7df86f758e9b14bfb',1,'SSLClientImpl']]] + ['connect',['connect',['../class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90',1,'SSLClient::connect(const char *host, uint16_t port) override']]], + ['connected',['connected',['../class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_3.js b/docs/html/search/functions_3.js index 3dc70e4..47e3882 100644 --- a/docs/html/search/functions_3.js +++ b/docs/html/search/functions_3.js @@ -1,5 +1,4 @@ var searchData= [ - ['flush',['flush',['../class_s_s_l_client.html#a2ee6a3134d07ca09cf61ee04d32c3d44',1,'SSLClient']]], - ['flush_5fimpl',['flush_impl',['../class_s_s_l_client_impl.html#a21ab78a0917f74ae5383d688e1548788',1,'SSLClientImpl']]] + ['flush',['flush',['../class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_4.js b/docs/html/search/functions_4.js index 18508ae..d68b4de 100644 --- a/docs/html/search/functions_4.js +++ b/docs/html/search/functions_4.js @@ -1,11 +1,7 @@ var searchData= [ - ['get_5farduino_5fclient',['get_arduino_client',['../class_s_s_l_client.html#a9c5001bdfa75ccc0d93cc60dd872b38a',1,'SSLClient::get_arduino_client() override'],['../class_s_s_l_client.html#a353c875d17a85dbb7bfe10de155f3b52',1,'SSLClient::get_arduino_client() const override'],['../class_s_s_l_client_impl.html#a20dd9a9794b95719e6f3df8cb39126e3',1,'SSLClientImpl::get_arduino_client()=0'],['../class_s_s_l_client_impl.html#ab1c8f30bd3669c15e07fa1522ede4336',1,'SSLClientImpl::get_arduino_client() const =0']]], ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], - ['get_5fip',['get_ip',['../class_s_s_l_session.html#a878e1e8788634c5c42778369fbf7bab0',1,'SSLSession']]], - ['get_5fsession_5farray',['get_session_array',['../class_s_s_l_client.html#a9e7769fed78825cf4723778f4b5aa3e9',1,'SSLClient::get_session_array() override'],['../class_s_s_l_client.html#a18adfc074d6b8e996819d4beb4689cbd',1,'SSLClient::get_session_array() const override'],['../class_s_s_l_client_impl.html#a44cfafd6f5cdcaa5dbac22961ab3a58b',1,'SSLClientImpl::get_session_array()=0'],['../class_s_s_l_client_impl.html#ace6652307ba028d67c7ddbc4103fa9b4',1,'SSLClientImpl::get_session_array() const =0']]], - ['get_5fsession_5fimpl',['get_session_impl',['../class_s_s_l_client_impl.html#ab4e38d4319ec504395d67d2ab21a639e',1,'SSLClientImpl']]], - ['getclient',['getClient',['../class_s_s_l_client.html#afd0d4d2c98433d60897d8828d8047d41',1,'SSLClient']]], - ['getsession',['getSession',['../class_s_s_l_client.html#a2d8bf9b891151bc5b0b865d70cf9c086',1,'SSLClient']]], - ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#a2d71f00d6634092f50c5262ad25cdacd',1,'SSLClient::getSessionCount()'],['../class_s_s_l_client_impl.html#a8e2385522ec04b1ce70871d4de23db6b',1,'SSLClientImpl::getSessionCount()']]] + ['getclient',['getClient',['../class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21',1,'SSLClient']]], + ['getsession',['getSession',['../class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3',1,'SSLClient']]], + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_5.js b/docs/html/search/functions_5.js index 7fdc7da..e4f8b0f 100644 --- a/docs/html/search/functions_5.js +++ b/docs/html/search/functions_5.js @@ -1,4 +1,4 @@ var searchData= [ - ['is_5fvalid_5fsession',['is_valid_session',['../class_s_s_l_session.html#a0c36cee72cfa862b7d4b2f5c112d5076',1,'SSLSession']]] + ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] ]; diff --git a/docs/html/search/functions_6.js b/docs/html/search/functions_6.js index 0773563..0aecf24 100644 --- a/docs/html/search/functions_6.js +++ b/docs/html/search/functions_6.js @@ -1,4 +1,4 @@ var searchData= [ - ['localport',['localPort',['../class_s_s_l_client.html#a563c5f9829757075bf16742cffa4cf73',1,'SSLClient::localPort()'],['../class_s_s_l_client_impl.html#a45f26385ee1975b12265943efb1ff0d5',1,'SSLClientImpl::localPort()']]] + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_7.js b/docs/html/search/functions_7.js index f9c2b25..53b8b47 100644 --- a/docs/html/search/functions_7.js +++ b/docs/html/search/functions_7.js @@ -1,11 +1,4 @@ var searchData= [ - ['m_5ferror',['m_error',['../class_s_s_l_client_impl.html#ada595ed8f11673a9180ef0b762949c83',1,'SSLClientImpl']]], - ['m_5finfo',['m_info',['../class_s_s_l_client_impl.html#a3b4cb1e9e510955078b83c9f84c0e18c',1,'SSLClientImpl']]], - ['m_5fprint',['m_print',['../class_s_s_l_client_impl.html#a45a1967029784a2f0f3edc7f75a00117',1,'SSLClientImpl']]], - ['m_5fprint_5fbr_5ferror',['m_print_br_error',['../class_s_s_l_client_impl.html#a2cf492a714cf787e54a17bb47cda43ed',1,'SSLClientImpl']]], - ['m_5fprint_5fprefix',['m_print_prefix',['../class_s_s_l_client_impl.html#a9ee82ad492f2297bd7cd0835c0d4556f',1,'SSLClientImpl']]], - ['m_5fprint_5fssl_5ferror',['m_print_ssl_error',['../class_s_s_l_client_impl.html#a6e701597178b81f10d0db671b81ab075',1,'SSLClientImpl']]], - ['m_5fwarn',['m_warn',['../class_s_s_l_client_impl.html#a2bfb55bcde46d8d77a46bfe0f577bf3f',1,'SSLClientImpl']]], - ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] + ['peek',['peek',['../class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_8.js b/docs/html/search/functions_8.js index d7f8a71..c66bc46 100644 --- a/docs/html/search/functions_8.js +++ b/docs/html/search/functions_8.js @@ -1,7 +1,5 @@ var searchData= [ - ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a2d378fbb7b8f15a1691746572f9d95b1',1,'SSLClient']]], - ['operator_21_3d',['operator!=',['../class_s_s_l_client.html#a824b599264f893e1b206a9100bc52ee1',1,'SSLClient::operator!=(const bool value)'],['../class_s_s_l_client.html#adab82ba09345fa070712d3124af30e1b',1,'SSLClient::operator!=(const C &rhs)']]], - ['operator_3d',['operator=',['../class_s_s_l_session.html#abb3f7bbe70e3a59f9ce492c55507f36f',1,'SSLSession']]], - ['operator_3d_3d',['operator==',['../class_s_s_l_client.html#a505bfb6831a45aebf58d84e3b89d4cfc',1,'SSLClient::operator==(const bool value)'],['../class_s_s_l_client.html#a5f40f8f4d26d21e14276c3e8162b62b9',1,'SSLClient::operator==(const C &rhs)']]] + ['read',['read',['../class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95',1,'SSLClient::read(uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb',1,'SSLClient::read() override']]], + ['removesession',['removeSession',['../class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_9.js b/docs/html/search/functions_9.js index ceddcf3..5e05068 100644 --- a/docs/html/search/functions_9.js +++ b/docs/html/search/functions_9.js @@ -1,5 +1,7 @@ var searchData= [ - ['peek',['peek',['../class_s_s_l_client.html#a31742867b00bd8d130637af0935bacbd',1,'SSLClient']]], - ['peek_5fimpl',['peek_impl',['../class_s_s_l_client_impl.html#a1b90e7df3a77eea5efb955cc15a17f7d',1,'SSLClientImpl']]] + ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29',1,'SSLClient']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376',1,'SSLClient']]], + ['sslsession',['SSLSession',['../class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74',1,'SSLSession']]], + ['stop',['stop',['../class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_a.js b/docs/html/search/functions_a.js index 6e82845..96d95c1 100644 --- a/docs/html/search/functions_a.js +++ b/docs/html/search/functions_a.js @@ -1,9 +1,4 @@ var searchData= [ - ['read',['read',['../class_s_s_l_client.html#aedf2746cc35da596faf8322776c2118e',1,'SSLClient::read() override'],['../class_s_s_l_client.html#afd6d7ae798c05cf566b2eb5651dba795',1,'SSLClient::read(uint8_t *buf, size_t size) override']]], - ['read_5fimpl',['read_impl',['../class_s_s_l_client_impl.html#a231b7b1bb2182cda1ed6e9d5ebf66afe',1,'SSLClientImpl']]], - ['remoteip',['remoteIP',['../class_s_s_l_client.html#af76a0df76834e0d0999dbf44c7c0a174',1,'SSLClient::remoteIP()'],['../class_s_s_l_client_impl.html#ae97adc55212c1aa96880aac28dd71387',1,'SSLClientImpl::remoteIP()']]], - ['remoteport',['remotePort',['../class_s_s_l_client.html#a5974a5f8722a752f121af4fac498bb22',1,'SSLClient::remotePort()'],['../class_s_s_l_client_impl.html#a93cdb32491fc08b035e40f840ff2e8f5',1,'SSLClientImpl::remotePort()']]], - ['remove_5fsession_5fimpl',['remove_session_impl',['../class_s_s_l_client_impl.html#a6baed094969874fb9d2bea3a00ecbee1',1,'SSLClientImpl']]], - ['removesession',['removeSession',['../class_s_s_l_client.html#a5b626703a24089dbb0480a9b6ddf348c',1,'SSLClient']]] + ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]] ]; diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js index 750a591..451bfc6 100644 --- a/docs/html/search/functions_b.js +++ b/docs/html/search/functions_b.js @@ -1,11 +1,4 @@ var searchData= [ - ['set_5fmutual_5fimpl',['set_mutual_impl',['../class_s_s_l_client_impl.html#a9dd694f8e0e65624b103dc781a7744af',1,'SSLClientImpl']]], - ['set_5fparameters',['set_parameters',['../class_s_s_l_session.html#a2fa15ce0b7caae25dfb567954175257e',1,'SSLSession']]], - ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a16aa9765bd450dcbba21c598456f464f',1,'SSLClient']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html#ae9a7509bc8a18f67e286547c19deb3c0',1,'SSLClient']]], - ['sslclientimpl',['SSLClientImpl',['../class_s_s_l_client_impl.html#a2b0b9043c8252871272bf6ba199ab67b',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug)'],['../class_s_s_l_client_impl.html#a8314c7dab1d923db5624f8075a53e6ea',1,'SSLClientImpl::SSLClientImpl(const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const DebugLevel debug, const SSLClientParameters *mutual_auth_params)']]], - ['sslsession',['SSLSession',['../class_s_s_l_session.html#ae05648200cea66577f024d5d09a6fcbb',1,'SSLSession']]], - ['stop',['stop',['../class_s_s_l_client.html#ad30db47248d78df7c12dedfb27f06529',1,'SSLClient']]], - ['stop_5fimpl',['stop_impl',['../class_s_s_l_client_impl.html#a81eb5ede3a894f281ae586d463b624e6',1,'SSLClientImpl']]] + ['write',['write',['../class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86',1,'SSLClient::write(const uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d',1,'SSLClient::write(uint8_t b) override']]] ]; diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js index 5109317..cec0612 100644 --- a/docs/html/search/searchdata.js +++ b/docs/html/search/searchdata.js @@ -1,10 +1,10 @@ var indexSectionsWithContent = { - 0: "_abcdefgilmoprstuvw", + 0: "_abcdefgimoprstuvw", 1: "s", 2: "s", 3: "cerst", - 4: "abcfgilmoprstw", + 4: "abcfgmoprstw", 5: "_bceiv", 6: "de", 7: "s", diff --git a/docs/html/search/variables_0.js b/docs/html/search/variables_0.js index 3adb20a..631745b 100644 --- a/docs/html/search/variables_0.js +++ b/docs/html/search/variables_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_impl_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClientImpl.cpp']]] + ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClient.cpp']]] ]; diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html index e5f31db..47d8224 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -113,7 +113,7 @@ Public Attributes

    Detailed Description

    This struct stores data required for SSLClient to use mutual authentication.

    SSLClientParameters.h

    -

    This file contains a simple utility class to store parameters about an SSL Session for reuse later.This file contains a simple struct to package together all the data required to use client certificate authentication with SSLClient.TLS mutual authentication is a process in which both the server and client perform cryptographic operations to verify the authenticity of eachother, for more information check out this article: https://medium.com/sitewards/the-magic-of-tls-x509-and-mutual-authentication-explained-b2162dec4401 . If this struct is provided to SSLClient::SSLClient, SSLClient will automatically send a client certificate if one is requested by the server. This will happen for all SSLClient connections, and may cause issues for websites that do not need mutual authentication— as a result, please only turn on mutual authentication if you are sure it is neccesary.

    +

    This file contains a simple utility class to store parameters about an SSL Session for reuse later.This file contains a simple struct to package together all the data required to use client certificate authentication with SSLClient.TLS mutual authentication is a process in which both the server and client perform cryptographic operations to verify the authenticity of eachother, for more information check out this article: https://medium.com/sitewards/the-magic-of-tls-x509-and-mutual-authentication-explained-b2162dec4401 . If this struct is provided to SSLClient::SSLClient, SSLClient will automatically send a client certificate if one is requested by the server. This will happen for all SSLClient connections, and may cause issues for websites that do not need mutual authentication— as a result, please only turn on mutual authentication if you are sure it is neccesary.

    At the moment SSLClient only supports mutual authentication using ECC client certificates.

    Member Data Documentation

    From 26b175844e7534fc8dfaaf54fac77703c686ec41 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 11 Nov 2019 12:18:58 -0800 Subject: [PATCH 086/205] Fixed a bug causing a buffer overflow in the WiFi101 library --- src/SSLClient.cpp | 4 ++-- src/SSLClient.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 783609a..87c4ea5 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -563,7 +563,7 @@ unsigned SSLClient::m_update_engine() { unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? const auto avail = get_arduino_client().available(); - if (avail > 0 && static_cast(avail) >= len) { + if (avail > 0) { int mem = freeMemory(); #if defined(ARDUINO_ARCH_SAMD) // check for a stack overflow @@ -590,7 +590,7 @@ unsigned SSLClient::m_update_engine() { return 0; } // I suppose so! - int rlen = get_arduino_client().read(buf, len); + int rlen = get_arduino_client().read(buf, avail < len ? avail : len); if (rlen <= 0) { m_error("Error reading bytes from m_client. Write Error: ", func_name); m_error(get_arduino_client().getWriteError(), func_name); diff --git a/src/SSLClient.h b/src/SSLClient.h index 89954cb..1891f4f 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -407,7 +407,7 @@ private: //============================================ //= Data Members //============================================ - // create a copy of the client + // create a reference the client Client& m_client; // also store an array of SSLSessions, so we can resume communication with multiple websites std::vector m_sessions; From 957e09c3d3024e0b4d85fdffdc51849db90e7d9c Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 11 Nov 2019 12:26:24 -0800 Subject: [PATCH 087/205] remove quotes from API key --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5084d9a..a3f3154 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ before_deploy: - zip -r SSLClient.zip . deploy: provider: releases - api_key: "$GITHUB_TOKEN" + api_key: $GITHUB_TOKEN file: "SSLClient.zip" skip_cleanup: true on: From 58a551aa385234b731a3f6f4c3d3bd645dbce2ac Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 11 Nov 2019 15:02:37 -0800 Subject: [PATCH 088/205] prevent conflict with SSLClient errors and common other client write errors --- src/SSLClient.cpp | 1 - src/SSLClient.h | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 87c4ea5..428e275 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -109,7 +109,6 @@ int SSLClient::connect(const char *host, uint16_t port) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); return -1; } - m_info("Client not connected, continuing...", func_name); // reset indexs for saftey m_write_idx = 0; // first, if we have a session, check if we're trying to resolve the same host diff --git a/src/SSLClient.h b/src/SSLClient.h index 1891f4f..17c91d4 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -45,17 +45,17 @@ public: enum Error { SSL_OK = 0, /** The underlying client failed to connect, probably not an issue with SSL */ - SSL_CLIENT_CONNECT_FAIL, + SSL_CLIENT_CONNECT_FAIL = 2, /** BearSSL failed to complete the SSL handshake, check logs for bear ssl error output */ - SSL_BR_CONNECT_FAIL, + SSL_BR_CONNECT_FAIL = 3, /** The underlying client failed to write a payload, probably not an issue with SSL */ - SSL_CLIENT_WRTIE_ERROR, + SSL_CLIENT_WRTIE_ERROR = 4, /** An internal error occurred with BearSSL, check logs for diagnosis. */ - SSL_BR_WRITE_ERROR, + SSL_BR_WRITE_ERROR = 5, /** An internal error occurred with SSLClient, and you probably need to submit an issue on Github. */ - SSL_INTERNAL_ERROR, + SSL_INTERNAL_ERROR = 6, /** SSLClient detected that there was not enough memory (>8000 bytes) to continue. */ - SSL_OUT_OF_MEMORY + SSL_OUT_OF_MEMORY = 7 }; /** From 42a39222ef7cd7d48de1e9d03dbcbeba2fcab193 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 12 Nov 2019 11:46:23 -0800 Subject: [PATCH 089/205] bump version --- docs/html/_r_e_a_d_m_e_8md.html | 2 +- docs/html/_s_s_l_client_8cpp.html | 2 +- docs/html/_s_s_l_client_8h.html | 2 +- docs/html/_s_s_l_client_8h_source.html | 20 +++++++++---------- docs/html/_s_s_l_client_parameters_8h.html | 2 +- .../_s_s_l_client_parameters_8h_source.html | 2 +- docs/html/_s_s_l_obj_8cpp.html | 2 +- docs/html/_s_s_l_obj_8h.html | 2 +- docs/html/_s_s_l_obj_8h_source.html | 2 +- docs/html/_s_s_l_session_8h.html | 2 +- docs/html/_s_s_l_session_8h_source.html | 2 +- docs/html/_t_l_s12__only__profile_8c.html | 2 +- docs/html/_trust_anchors_8md.html | 2 +- docs/html/annotated.html | 2 +- docs/html/cert_8h.html | 2 +- docs/html/cert_8h_source.html | 2 +- docs/html/class_s_s_l_client-members.html | 2 +- docs/html/class_s_s_l_client.html | 14 ++++++------- docs/html/class_s_s_l_session-members.html | 2 +- docs/html/class_s_s_l_session.html | 2 +- docs/html/classes.html | 2 +- .../dir_386349f6a9bc1e2cd0767d257d5e5b91.html | 2 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- .../dir_9c42dc81377249a918256dbb9cfb2167.html | 2 +- .../dir_d28a4824dc47e487b107a5db32ef43c4.html | 2 +- .../dir_dfc5a9f91fbfb9426c406a3f10131a54.html | 2 +- docs/html/ec__prime__fast__256_8c.html | 2 +- docs/html/files.html | 2 +- docs/html/functions.html | 2 +- docs/html/functions_enum.html | 2 +- docs/html/functions_eval.html | 2 +- docs/html/functions_func.html | 2 +- docs/html/functions_vars.html | 2 +- docs/html/globals.html | 2 +- docs/html/globals_defs.html | 2 +- docs/html/globals_func.html | 2 +- docs/html/globals_vars.html | 2 +- docs/html/hierarchy.html | 2 +- docs/html/index.html | 2 +- ...ibraries__s_s_l_client__trust_anchors.html | 2 +- docs/html/namespace_s_s_l_obj.html | 2 +- docs/html/namespacemembers.html | 2 +- docs/html/namespacemembers_func.html | 2 +- docs/html/namespaces.html | 2 +- docs/html/pages.html | 2 +- ...truct_s_s_l_client_parameters-members.html | 2 +- docs/html/struct_s_s_l_client_parameters.html | 2 +- ...structssl__pem__decode__state-members.html | 2 +- docs/html/structssl__pem__decode__state.html | 2 +- docs/html/time__macros_8h.html | 2 +- docs/html/time__macros_8h_source.html | 2 +- docs/html/trust__anchors_8h.html | 2 +- docs/html/trust__anchors_8h_source.html | 2 +- docs/html/trustanchors_8h.html | 2 +- docs/html/trustanchors_8h_source.html | 2 +- library.properties | 2 +- 56 files changed, 71 insertions(+), 71 deletions(-) diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/html/_r_e_a_d_m_e_8md.html index 301d463..c78e9c5 100644 --- a/docs/html/_r_e_a_d_m_e_8md.html +++ b/docs/html/_r_e_a_d_m_e_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8cpp.html b/docs/html/_s_s_l_client_8cpp.html index 2717c69..c25e9a1 100644 --- a/docs/html/_s_s_l_client_8cpp.html +++ b/docs/html/_s_s_l_client_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index dc0f248..0292567 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index a4e47ee..f7a521c 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    @@ -91,36 +91,36 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
    SSLClient.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    361 private:
    363  Client& get_arduino_client() { return m_client; }
    364  const Client& get_arduino_client() const { return m_client; }
    365 
    367  bool m_soft_connected(const char* func_name);
    369  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    371  int m_run_until(const unsigned target);
    373  unsigned m_update_engine();
    375  int m_get_session_index(const char* host) const;
    376 
    378  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    379 
    381  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    382 
    384  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    385 
    387  template<typename T>
    388  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    389  // check the current debug level and serial status
    390  if (level > m_debug || !Serial) return;
    391  // print prefix
    392  m_print_prefix(func_name, level);
    393  // print the message
    394  Serial.println(str);
    395  }
    396 
    398  template<typename T>
    399  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    400 
    401  template<typename T>
    402  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    403 
    404  template<typename T>
    405  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    406 
    407  //============================================
    408  //= Data Members
    409  //============================================
    410  // create a copy of the client
    411  Client& m_client;
    412  // also store an array of SSLSessions, so we can resume communication with multiple websites
    413  std::vector<SSLSession> m_sessions;
    414  // as well as the maximmum number of sessions we can store
    415  const size_t m_max_sessions;
    416  // store the pin to fetch an RNG see from
    417  const int m_analog_pin;
    418  // store whether to enable debug logging
    419  const DebugLevel m_debug;
    420  // store if we are connected in bearssl or not
    421  bool m_is_connected;
    422  // store the context values required for SSL
    423  br_ssl_client_context m_sslctx;
    424  br_x509_minimal_context m_x509ctx;
    425  // use a mono-directional buffer by default to cut memory in half
    426  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    427  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    428  // simply edit this value to change the buffer size to the desired value
    429  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    430  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    438  unsigned char m_iobuf[2048];
    439  // store the index of where we are writing in the buffer
    440  // so we can send our records all at once to prevent
    441  // weird timing issues
    442  size_t m_write_idx;
    443 };
    444 
    445 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:255
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    361 private:
    363  Client& get_arduino_client() { return m_client; }
    364  const Client& get_arduino_client() const { return m_client; }
    365 
    367  bool m_soft_connected(const char* func_name);
    369  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    371  int m_run_until(const unsigned target);
    373  unsigned m_update_engine();
    375  int m_get_session_index(const char* host) const;
    376 
    378  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    379 
    381  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    382 
    384  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    385 
    387  template<typename T>
    388  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    389  // check the current debug level and serial status
    390  if (level > m_debug || !Serial) return;
    391  // print prefix
    392  m_print_prefix(func_name, level);
    393  // print the message
    394  Serial.println(str);
    395  }
    396 
    398  template<typename T>
    399  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    400 
    401  template<typename T>
    402  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    403 
    404  template<typename T>
    405  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    406 
    407  //============================================
    408  //= Data Members
    409  //============================================
    410  // create a reference the client
    411  Client& m_client;
    412  // also store an array of SSLSessions, so we can resume communication with multiple websites
    413  std::vector<SSLSession> m_sessions;
    414  // as well as the maximmum number of sessions we can store
    415  const size_t m_max_sessions;
    416  // store the pin to fetch an RNG see from
    417  const int m_analog_pin;
    418  // store whether to enable debug logging
    419  const DebugLevel m_debug;
    420  // store if we are connected in bearssl or not
    421  bool m_is_connected;
    422  // store the context values required for SSL
    423  br_ssl_client_context m_sslctx;
    424  br_x509_minimal_context m_x509ctx;
    425  // use a mono-directional buffer by default to cut memory in half
    426  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    427  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    428  // simply edit this value to change the buffer size to the desired value
    429  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    430  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    438  unsigned char m_iobuf[2048];
    439  // store the index of where we are writing in the buffer
    440  // so we can send our records all at once to prevent
    441  // weird timing issues
    442  size_t m_write_idx;
    443 };
    444 
    445 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:254
    Definition: SSLClient.h:58
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:51
    Definition: SSLClient.h:48
    Definition: SSLClient.h:75
    Definition: SSLClient.h:54
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:55
    -
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:222
    -
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:286
    +
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:221
    +
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:285
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    -
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:310
    -
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:174
    +
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:309
    +
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:173
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    Definition: SSLClient.h:73
    -
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:228
    +
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:227
    Definition: SSLClient.h:71
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:82
    -
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:131
    +
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:130
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:258
    Error
    Static constants defining the possible errors encountered.
    Definition: SSLClient.h:45
    Definition: SSLClient.h:52
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClient.h:67
    size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:349
    -
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:210
    +
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:209
    Definition: SSLClient.h:50
    size_t write(uint8_t b) override
    Definition: SSLClient.h:210
    Client & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:359
    -
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:299
    +
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:298
    Definition: SSLClient.h:69
    Definition: SSLClient.h:46
    diff --git a/docs/html/_s_s_l_client_parameters_8h.html b/docs/html/_s_s_l_client_parameters_8h.html index a7c5050..47a5896 100644 --- a/docs/html/_s_s_l_client_parameters_8h.html +++ b/docs/html/_s_s_l_client_parameters_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_parameters_8h_source.html b/docs/html/_s_s_l_client_parameters_8h_source.html index 262cf99..6dedaae 100644 --- a/docs/html/_s_s_l_client_parameters_8h_source.html +++ b/docs/html/_s_s_l_client_parameters_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8cpp.html b/docs/html/_s_s_l_obj_8cpp.html index 6a97a5e..87fdb40 100644 --- a/docs/html/_s_s_l_obj_8cpp.html +++ b/docs/html/_s_s_l_obj_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h.html b/docs/html/_s_s_l_obj_8h.html index 9024aa9..c788182 100644 --- a/docs/html/_s_s_l_obj_8h.html +++ b/docs/html/_s_s_l_obj_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h_source.html b/docs/html/_s_s_l_obj_8h_source.html index b4a8442..b7f9b53 100644 --- a/docs/html/_s_s_l_obj_8h_source.html +++ b/docs/html/_s_s_l_obj_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index 086efc4..17d678f 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index d70c2ba..32ea911 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html index 0e42728..176afce 100644 --- a/docs/html/_t_l_s12__only__profile_8c.html +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html index a64bd86..3f11130 100644 --- a/docs/html/_trust_anchors_8md.html +++ b/docs/html/_trust_anchors_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/annotated.html b/docs/html/annotated.html index cfc7655..04e5b27 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h.html b/docs/html/cert_8h.html index 88192ea..cb19e45 100644 --- a/docs/html/cert_8h.html +++ b/docs/html/cert_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html index 6f4239c..caac9ef 100644 --- a/docs/html/cert_8h_source.html +++ b/docs/html/cert_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 2927210..02df105 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 1e4fddb..62f1993 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    @@ -111,13 +111,13 @@ Inheritance diagram for SSLClient:
    Public Types enum  Error {
      SSL_OK = 0, -SSL_CLIENT_CONNECT_FAIL, -SSL_BR_CONNECT_FAIL, -SSL_CLIENT_WRTIE_ERROR, +SSL_CLIENT_CONNECT_FAIL = 2, +SSL_BR_CONNECT_FAIL = 3, +SSL_CLIENT_WRTIE_ERROR = 4,
    -  SSL_BR_WRITE_ERROR, -SSL_INTERNAL_ERROR, -SSL_OUT_OF_MEMORY +  SSL_BR_WRITE_ERROR = 5, +SSL_INTERNAL_ERROR = 6, +SSL_OUT_OF_MEMORY = 7
    }  Static constants defining the possible errors encountered. More...
    diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index ca1bf32..1e878f3 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index 79e8cca..454052a 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/classes.html b/docs/html/classes.html index b944012..28e3204 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html index ad459b7..0a0a250 100644 --- a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 97c64ed..b1509c0 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html index fdd7d17..9cc7f6a 100644 --- a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html index 98fae67..a201518 100644 --- a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html index 544df56..f42bc8d 100644 --- a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/ec__prime__fast__256_8c.html b/docs/html/ec__prime__fast__256_8c.html index 1dbbfeb..bb4d6f9 100644 --- a/docs/html/ec__prime__fast__256_8c.html +++ b/docs/html/ec__prime__fast__256_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/files.html b/docs/html/files.html index 95ada10..d51797c 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions.html b/docs/html/functions.html index cc1ba07..4e11d63 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_enum.html b/docs/html/functions_enum.html index d14bd09..a59822a 100644 --- a/docs/html/functions_enum.html +++ b/docs/html/functions_enum.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_eval.html b/docs/html/functions_eval.html index 0ff75bc..77c9361 100644 --- a/docs/html/functions_eval.html +++ b/docs/html/functions_eval.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index 799ae11..d277946 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_vars.html b/docs/html/functions_vars.html index 5cc8e91..55e1d11 100644 --- a/docs/html/functions_vars.html +++ b/docs/html/functions_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals.html b/docs/html/globals.html index b704556..fd21b44 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index fef2962..bbdd3d3 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index f23d91b..57f26c1 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index 34445a7..e2e73c4 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index f525e14..59aaf82 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/index.html b/docs/html/index.html index 2f790ee..6a02e39 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index d307879..71718cb 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/html/namespace_s_s_l_obj.html index ea568a5..236cda0 100644 --- a/docs/html/namespace_s_s_l_obj.html +++ b/docs/html/namespace_s_s_l_obj.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers.html b/docs/html/namespacemembers.html index 193a83c..361e57e 100644 --- a/docs/html/namespacemembers.html +++ b/docs/html/namespacemembers.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers_func.html b/docs/html/namespacemembers_func.html index f0b8146..ba602f5 100644 --- a/docs/html/namespacemembers_func.html +++ b/docs/html/namespacemembers_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespaces.html b/docs/html/namespaces.html index 2f1ddb6..f7b1ebe 100644 --- a/docs/html/namespaces.html +++ b/docs/html/namespaces.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/pages.html b/docs/html/pages.html index 356a0fd..64f2340 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/html/struct_s_s_l_client_parameters-members.html index 7171d9f..1c4cb0f 100644 --- a/docs/html/struct_s_s_l_client_parameters-members.html +++ b/docs/html/struct_s_s_l_client_parameters-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html index 47d8224..024c050 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/html/structssl__pem__decode__state-members.html index 4ee8da1..108d3ce 100644 --- a/docs/html/structssl__pem__decode__state-members.html +++ b/docs/html/structssl__pem__decode__state-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state.html b/docs/html/structssl__pem__decode__state.html index c314b41..9c58cb1 100644 --- a/docs/html/structssl__pem__decode__state.html +++ b/docs/html/structssl__pem__decode__state.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html index e22bf32..68dcb80 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/html/time__macros_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html index 677a444..a5e2fa7 100644 --- a/docs/html/time__macros_8h_source.html +++ b/docs/html/time__macros_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html index ef2751e..0df213d 100644 --- a/docs/html/trust__anchors_8h.html +++ b/docs/html/trust__anchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index e3690bc..2998bfc 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html index 729f06c..958a976 100644 --- a/docs/html/trustanchors_8h.html +++ b/docs/html/trustanchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html index 7d967ea..964016b 100644 --- a/docs/html/trustanchors_8h_source.html +++ b/docs/html/trustanchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.3.0 +  v1.4.2
    Add TLS 1.2 functionality to any network library.
    diff --git a/library.properties b/library.properties index 3f10399..90907dd 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.3.0 +version=1.4.2 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From e8c7cc2f11ef779f7c06793d143d500887a58dfc Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 20 Nov 2019 19:47:59 -0800 Subject: [PATCH 090/205] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8231abc..9d9ae7d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SSLClient - Arduino Library For SSL +# SSLClient [![Build Status](https://travis-ci.org/OPEnSLab-OSU/SSLClient.svg?branch=master)](https://travis-ci.org/OPEnSLab-OSU/SSLClient) From 106c124c58c690365ecee5fa21e28ceda9d9289a Mon Sep 17 00:00:00 2001 From: Noah Date: Wed, 20 Nov 2019 19:49:54 -0800 Subject: [PATCH 091/205] Update readme to remove old template implementation --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 9d9ae7d..1917370 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,7 @@ For more information on SSLClient, check out the [examples](./examples), [API do ## How It Works -SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](https://bearssl.org/) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, making debugging a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint. - -Additionally, the bulk of SSLClient is split into two components: a template class [SSLClient](./src/SSLClient.h), and an implementation class [SSLClientImpl](./src/SSLClientImpl.h). The template class serves to abstract some functions not implemented in the Arduino Client interface (such as EthernetClient::remoteIP), and the implementation class is the rest of the SSLClient library. +SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant [BearSSL](https://bearssl.org/) as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of SSLClient's code adds those programming checks back in, making debugging a fast and simple process. ## Other Features From 539b088e82aa08457c1d90e800791b10782a32a3 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 26 Dec 2019 17:50:34 -0500 Subject: [PATCH 092/205] fix support for the esp8266 --- src/SSLClient.cpp | 5 +++++ src/SSLClient.h | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 428e275..3529144 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -35,6 +35,8 @@ static constexpr auto VECTKEY_MASK = (0x0000ffffUL); #ifdef __arm__ // should use uinstd.h to define sbrk but Due causes a conflict extern "C" char* sbrk(int incr); +#elif defined(ESP8266) // esp8266 +#define SYSTEM_STACK_END_ADDRESS 0x3FFFC000 #else // __ARM__ extern char *__brkval; #endif // __arm__ @@ -44,6 +46,9 @@ static int freeMemory() { char top; #ifdef __arm__ return &top - reinterpret_cast(sbrk(0)); +#elif defined(ESP8266) // ESP8266 + register volatile uint32_t stackAddress asm("a1"); + return stackAddress-SYSTEM_STACK_END_ADDRESS; #elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) return &top - __brkval; #else // __arm__ diff --git a/src/SSLClient.h b/src/SSLClient.h index 17c91d4..79d6827 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -358,6 +358,18 @@ public: /** @brief Returns a reference to the client object stored in this class. Take care not to break it. */ Client& getClient() { return m_client; } + /** + * @brief Set the timeout when waiting for an SSL response. + * @param t The timeout value, in milliseconds (defaults to 30 seconds if not set). Do not set to zero. + */ + void setTimeout(unsigned int t) { m_timeout = t; } + + /** + * @brief Get the timeout when waiting for an SSL response. + * @returns The timeout value in milliseconds. + */ + unsigned int getTimeout() const { return m_timeout; } + private: /** @brief Returns an instance of m_client that is polymorphic and can be used by SSLClientImpl */ Client& get_arduino_client() { return m_client; } @@ -419,6 +431,8 @@ private: const DebugLevel m_debug; // store if we are connected in bearssl or not bool m_is_connected; + // store the timeout for SSL internals + unsigned int m_timeout; // store the context values required for SSL br_ssl_client_context m_sslctx; br_x509_minimal_context m_x509ctx; From c2eca312f4e04c400baf4567b3a7820eddd9c222 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 26 Dec 2019 17:59:50 -0500 Subject: [PATCH 093/205] bump version in doxygen --- docs/html/_r_e_a_d_m_e_8md.html | 2 +- docs/html/_s_s_l_client_8cpp.html | 2 +- docs/html/_s_s_l_client_8h.html | 2 +- docs/html/_s_s_l_client_8h_source.html | 26 +- docs/html/_s_s_l_client_parameters_8h.html | 2 +- .../_s_s_l_client_parameters_8h_source.html | 2 +- docs/html/_s_s_l_obj_8cpp.html | 2 +- docs/html/_s_s_l_obj_8h.html | 2 +- docs/html/_s_s_l_obj_8h_source.html | 2 +- docs/html/_s_s_l_session_8h.html | 2 +- docs/html/_s_s_l_session_8h_source.html | 2 +- docs/html/_t_l_s12__only__profile_8c.html | 2 +- docs/html/_trust_anchors_8md.html | 2 +- docs/html/annotated.html | 2 +- docs/html/cert_8h.html | 2 +- docs/html/cert_8h_source.html | 2 +- docs/html/class_s_s_l_client-members.html | 16 +- docs/html/class_s_s_l_client.html | 70 +++++- docs/html/class_s_s_l_client.js | 2 + docs/html/class_s_s_l_session-members.html | 2 +- docs/html/class_s_s_l_session.html | 2 +- docs/html/classes.html | 2 +- .../dir_386349f6a9bc1e2cd0767d257d5e5b91.html | 2 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- .../dir_9c42dc81377249a918256dbb9cfb2167.html | 2 +- .../dir_d28a4824dc47e487b107a5db32ef43c4.html | 2 +- .../dir_dfc5a9f91fbfb9426c406a3f10131a54.html | 2 +- docs/html/ec__prime__fast__256_8c.html | 2 +- docs/html/files.html | 2 +- docs/html/functions.html | 8 +- docs/html/functions_enum.html | 2 +- docs/html/functions_eval.html | 2 +- docs/html/functions_func.html | 8 +- docs/html/functions_vars.html | 2 +- docs/html/globals.html | 2 +- docs/html/globals_defs.html | 2 +- docs/html/globals_func.html | 2 +- docs/html/globals_vars.html | 2 +- docs/html/hierarchy.html | 2 +- docs/html/index.html | 9 +- ...ibraries__s_s_l_client__trust_anchors.html | 2 +- docs/html/namespace_s_s_l_obj.html | 2 +- docs/html/namespacemembers.html | 2 +- docs/html/namespacemembers_func.html | 2 +- docs/html/namespaces.html | 2 +- docs/html/navtreedata.js | 1 - docs/html/navtreeindex0.js | 231 +++++++++--------- docs/html/pages.html | 2 +- docs/html/search/all_7.js | 3 +- docs/html/search/all_d.js | 3 +- docs/html/search/functions_4.js | 3 +- docs/html/search/functions_9.js | 1 + docs/html/search/pages_0.js | 2 +- ...truct_s_s_l_client_parameters-members.html | 2 +- docs/html/struct_s_s_l_client_parameters.html | 2 +- ...structssl__pem__decode__state-members.html | 2 +- docs/html/structssl__pem__decode__state.html | 2 +- docs/html/time__macros_8h.html | 2 +- docs/html/time__macros_8h_source.html | 2 +- docs/html/trust__anchors_8h.html | 2 +- docs/html/trust__anchors_8h_source.html | 2 +- docs/html/trustanchors_8h.html | 2 +- docs/html/trustanchors_8h_source.html | 2 +- library.properties | 2 +- 64 files changed, 286 insertions(+), 197 deletions(-) diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/html/_r_e_a_d_m_e_8md.html index c78e9c5..ebee020 100644 --- a/docs/html/_r_e_a_d_m_e_8md.html +++ b/docs/html/_r_e_a_d_m_e_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8cpp.html b/docs/html/_s_s_l_client_8cpp.html index c25e9a1..4c6ce71 100644 --- a/docs/html/_s_s_l_client_8cpp.html +++ b/docs/html/_s_s_l_client_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index 0292567..c9700ea 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index f7a521c..804eb3b 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    @@ -91,36 +91,38 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
    SSLClient.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    361 private:
    363  Client& get_arduino_client() { return m_client; }
    364  const Client& get_arduino_client() const { return m_client; }
    365 
    367  bool m_soft_connected(const char* func_name);
    369  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    371  int m_run_until(const unsigned target);
    373  unsigned m_update_engine();
    375  int m_get_session_index(const char* host) const;
    376 
    378  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    379 
    381  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    382 
    384  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    385 
    387  template<typename T>
    388  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    389  // check the current debug level and serial status
    390  if (level > m_debug || !Serial) return;
    391  // print prefix
    392  m_print_prefix(func_name, level);
    393  // print the message
    394  Serial.println(str);
    395  }
    396 
    398  template<typename T>
    399  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    400 
    401  template<typename T>
    402  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    403 
    404  template<typename T>
    405  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    406 
    407  //============================================
    408  //= Data Members
    409  //============================================
    410  // create a reference the client
    411  Client& m_client;
    412  // also store an array of SSLSessions, so we can resume communication with multiple websites
    413  std::vector<SSLSession> m_sessions;
    414  // as well as the maximmum number of sessions we can store
    415  const size_t m_max_sessions;
    416  // store the pin to fetch an RNG see from
    417  const int m_analog_pin;
    418  // store whether to enable debug logging
    419  const DebugLevel m_debug;
    420  // store if we are connected in bearssl or not
    421  bool m_is_connected;
    422  // store the context values required for SSL
    423  br_ssl_client_context m_sslctx;
    424  br_x509_minimal_context m_x509ctx;
    425  // use a mono-directional buffer by default to cut memory in half
    426  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    427  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    428  // simply edit this value to change the buffer size to the desired value
    429  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    430  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    438  unsigned char m_iobuf[2048];
    439  // store the index of where we are writing in the buffer
    440  // so we can send our records all at once to prevent
    441  // weird timing issues
    442  size_t m_write_idx;
    443 };
    444 
    445 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:254
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    365  void setTimeout(unsigned int t) { m_timeout = t; }
    366 
    371  unsigned int getTimeout() const { return m_timeout; }
    372 
    373 private:
    375  Client& get_arduino_client() { return m_client; }
    376  const Client& get_arduino_client() const { return m_client; }
    377 
    379  bool m_soft_connected(const char* func_name);
    381  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    383  int m_run_until(const unsigned target);
    385  unsigned m_update_engine();
    387  int m_get_session_index(const char* host) const;
    388 
    390  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    391 
    393  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    394 
    396  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    397 
    399  template<typename T>
    400  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    401  // check the current debug level and serial status
    402  if (level > m_debug || !Serial) return;
    403  // print prefix
    404  m_print_prefix(func_name, level);
    405  // print the message
    406  Serial.println(str);
    407  }
    408 
    410  template<typename T>
    411  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    412 
    413  template<typename T>
    414  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    415 
    416  template<typename T>
    417  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    418 
    419  //============================================
    420  //= Data Members
    421  //============================================
    422  // create a reference the client
    423  Client& m_client;
    424  // also store an array of SSLSessions, so we can resume communication with multiple websites
    425  std::vector<SSLSession> m_sessions;
    426  // as well as the maximmum number of sessions we can store
    427  const size_t m_max_sessions;
    428  // store the pin to fetch an RNG see from
    429  const int m_analog_pin;
    430  // store whether to enable debug logging
    431  const DebugLevel m_debug;
    432  // store if we are connected in bearssl or not
    433  bool m_is_connected;
    434  // store the timeout for SSL internals
    435  unsigned int m_timeout;
    436  // store the context values required for SSL
    437  br_ssl_client_context m_sslctx;
    438  br_x509_minimal_context m_x509ctx;
    439  // use a mono-directional buffer by default to cut memory in half
    440  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    441  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    442  // simply edit this value to change the buffer size to the desired value
    443  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    444  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    452  unsigned char m_iobuf[2048];
    453  // store the index of where we are writing in the buffer
    454  // so we can send our records all at once to prevent
    455  // weird timing issues
    456  size_t m_write_idx;
    457 };
    458 
    459 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:259
    Definition: SSLClient.h:58
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:51
    +
    void setTimeout(unsigned int t)
    Set the timeout when waiting for an SSL response.
    Definition: SSLClient.h:365
    Definition: SSLClient.h:48
    Definition: SSLClient.h:75
    Definition: SSLClient.h:54
    -
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:55
    -
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:221
    -
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:285
    +
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:60
    +
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:226
    +
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:290
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    -
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:309
    -
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:173
    +
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:314
    +
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:178
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    Definition: SSLClient.h:73
    -
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:227
    +
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:232
    Definition: SSLClient.h:71
    -
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:82
    -
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:130
    +
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:87
    +
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:135
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:258
    Error
    Static constants defining the possible errors encountered.
    Definition: SSLClient.h:45
    Definition: SSLClient.h:52
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClient.h:67
    size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:349
    -
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:209
    +
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:214
    Definition: SSLClient.h:50
    size_t write(uint8_t b) override
    Definition: SSLClient.h:210
    Client & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:359
    -
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:298
    +
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:303
    +
    unsigned int getTimeout() const
    Get the timeout when waiting for an SSL response.
    Definition: SSLClient.h:371
    Definition: SSLClient.h:69
    Definition: SSLClient.h:46
    diff --git a/docs/html/_s_s_l_client_parameters_8h.html b/docs/html/_s_s_l_client_parameters_8h.html index 47a5896..2647c40 100644 --- a/docs/html/_s_s_l_client_parameters_8h.html +++ b/docs/html/_s_s_l_client_parameters_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_parameters_8h_source.html b/docs/html/_s_s_l_client_parameters_8h_source.html index 6dedaae..7d928bd 100644 --- a/docs/html/_s_s_l_client_parameters_8h_source.html +++ b/docs/html/_s_s_l_client_parameters_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8cpp.html b/docs/html/_s_s_l_obj_8cpp.html index 87fdb40..0a2fc2f 100644 --- a/docs/html/_s_s_l_obj_8cpp.html +++ b/docs/html/_s_s_l_obj_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h.html b/docs/html/_s_s_l_obj_8h.html index c788182..c027151 100644 --- a/docs/html/_s_s_l_obj_8h.html +++ b/docs/html/_s_s_l_obj_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h_source.html b/docs/html/_s_s_l_obj_8h_source.html index b7f9b53..31eaa8d 100644 --- a/docs/html/_s_s_l_obj_8h_source.html +++ b/docs/html/_s_s_l_obj_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index 17d678f..e6b2880 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index 32ea911..11dbedc 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html index 176afce..c10b9ff 100644 --- a/docs/html/_t_l_s12__only__profile_8c.html +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html index 3f11130..2224d5f 100644 --- a/docs/html/_trust_anchors_8md.html +++ b/docs/html/_trust_anchors_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 04e5b27..d9cbd2e 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h.html b/docs/html/cert_8h.html index cb19e45..7119de4 100644 --- a/docs/html/cert_8h.html +++ b/docs/html/cert_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html index caac9ef..98ce4e3 100644 --- a/docs/html/cert_8h_source.html +++ b/docs/html/cert_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 02df105..9bd680d 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    @@ -104,12 +104,14 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');}); getClient()SSLClientinline getSession(const char *host)SSLClient getSessionCount() constSSLClientinline - operator bool()SSLClientinline - peek() overrideSSLClient - read(uint8_t *buf, size_t size) overrideSSLClient - read() overrideSSLClientinline - removeSession(const char *host)SSLClient - setMutualAuthParams(const SSLClientParameters *params)SSLClient + getTimeout() constSSLClientinline + operator bool()SSLClientinline + peek() overrideSSLClient + read(uint8_t *buf, size_t size) overrideSSLClient + read() overrideSSLClientinline + removeSession(const char *host)SSLClient + setMutualAuthParams(const SSLClientParameters *params)SSLClient + setTimeout(unsigned int t)SSLClientinline SSL_BR_CONNECT_FAIL enum valueSSLClient SSL_BR_WRITE_ERROR enum valueSSLClient SSL_CLIENT_CONNECT_FAIL enum valueSSLClient diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 62f1993..8c54357 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    @@ -185,6 +185,12 @@ Public Member Functions Client & getClient ()  Returns a reference to the client object stored in this class. Take care not to break it. More...
      +void setTimeout (unsigned int t) + Set the timeout when waiting for an SSL response. More...
    +  +unsigned int getTimeout () const + Get the timeout when waiting for an SSL response. More...

    Detailed Description

    The main SSLClient class. Check out README.md for more info.

    @@ -612,6 +618,34 @@ There must be a trust anchor given to the constructor that corresponds to the ce

    Get the maximum number of SSL sessions that can be stored at once.

    Returns
    The SessionCache template parameter.
    +
    +
    + +

    ◆ getTimeout()

    + +
    +
    + + + + + +
    + + + + + + + +
    unsigned int SSLClient::getTimeout () const
    +
    +inline
    +
    + +

    Get the timeout when waiting for an SSL response.

    +
    Returns
    The timeout value in milliseconds.
    +
    @@ -797,6 +831,40 @@ There must be a trust anchor given to the constructor that corresponds to the ce

    Please ensure that the values in params are valid for the lifetime of SSLClient. You may want to make them global constants.

    Precondition
    SSLClient has not already started an SSL connection.
    +
    +
    + +

    ◆ setTimeout()

    + +
    +
    + + + + + +
    + + + + + + + + +
    void SSLClient::setTimeout (unsigned int t)
    +
    +inline
    +
    + +

    Set the timeout when waiting for an SSL response.

    +
    Parameters
    + + +
    tThe timeout value, in milliseconds (defaults to 30 seconds if not set). Do not set to zero.
    +
    +
    +
    diff --git a/docs/html/class_s_s_l_client.js b/docs/html/class_s_s_l_client.js index 8b45e37..d2eadc2 100644 --- a/docs/html/class_s_s_l_client.js +++ b/docs/html/class_s_s_l_client.js @@ -24,12 +24,14 @@ var class_s_s_l_client = [ "getClient", "class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21", null ], [ "getSession", "class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3", null ], [ "getSessionCount", "class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22", null ], + [ "getTimeout", "class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498", null ], [ "operator bool", "class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b", null ], [ "peek", "class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86", null ], [ "read", "class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95", null ], [ "read", "class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb", null ], [ "removeSession", "class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4", null ], [ "setMutualAuthParams", "class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29", null ], + [ "setTimeout", "class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae", null ], [ "stop", "class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe", null ], [ "write", "class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86", null ], [ "write", "class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d", null ] diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index 1e878f3..f3b1d0e 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index 454052a..917abdc 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/classes.html b/docs/html/classes.html index 28e3204..b6041e9 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html index 0a0a250..825ca7b 100644 --- a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index b1509c0..456518e 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html index 9cc7f6a..d5e0dd3 100644 --- a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html index a201518..5d8ba54 100644 --- a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html index f42bc8d..16f74f7 100644 --- a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/ec__prime__fast__256_8c.html b/docs/html/ec__prime__fast__256_8c.html index bb4d6f9..7699c72 100644 --- a/docs/html/ec__prime__fast__256_8c.html +++ b/docs/html/ec__prime__fast__256_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/files.html b/docs/html/files.html index d51797c..cf9a5ac 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions.html b/docs/html/functions.html index 4e11d63..85678f0 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    @@ -149,6 +149,9 @@ $(document).ready(function(){initNavTree('functions.html','');});
  • getSessionCount() : SSLClient
  • +
  • getTimeout() +: SSLClient +
  • @@ -187,6 +190,9 @@ $(document).ready(function(){initNavTree('functions.html','');});
  • setMutualAuthParams() : SSLClient
  • +
  • setTimeout() +: SSLClient +
  • SSL_BR_CONNECT_FAIL : SSLClient
  • diff --git a/docs/html/functions_enum.html b/docs/html/functions_enum.html index a59822a..37cf15a 100644 --- a/docs/html/functions_enum.html +++ b/docs/html/functions_enum.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_eval.html b/docs/html/functions_eval.html index 77c9361..2e9b13d 100644 --- a/docs/html/functions_eval.html +++ b/docs/html/functions_eval.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index d277946..581a9bf 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    @@ -112,6 +112,9 @@ $(document).ready(function(){initNavTree('functions_func.html','');});
  • getSessionCount() : SSLClient
  • +
  • getTimeout() +: SSLClient +
  • operator bool() : SSLClient
  • @@ -127,6 +130,9 @@ $(document).ready(function(){initNavTree('functions_func.html','');});
  • setMutualAuthParams() : SSLClient
  • +
  • setTimeout() +: SSLClient +
  • SSLClient() : SSLClient
  • diff --git a/docs/html/functions_vars.html b/docs/html/functions_vars.html index 55e1d11..a8687fc 100644 --- a/docs/html/functions_vars.html +++ b/docs/html/functions_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals.html b/docs/html/globals.html index fd21b44..c2e3cd5 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index bbdd3d3..0b0d8dc 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index 57f26c1..739b50a 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index e2e73c4..66a165d 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 59aaf82..35e7bf0 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/index.html b/docs/html/index.html index 6a02e39..ebde966 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -5,7 +5,7 @@ -SSLClient: SSLClient - Arduino Library For SSL +SSLClient: SSLClient @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('index.html','');});
    -
    SSLClient - Arduino Library For SSL
    +

    Build Status @@ -115,8 +115,7 @@ $(document).ready(function(){initNavTree('index.html','');});

    For more information on SSLClient, check out the examples, API documentation, or the rest of this README.

    How It Works

    -

    SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant BearSSL as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of the code adds those programming checks back in, making debugging a fast and simple process. The rest manages the state of BearSSL, and ensures a manageable memory footprint.

    -

    Additionally, the bulk of SSLClient is split into two components: a template class SSLClient, and an implementation class SSLClientImpl. The template class serves to abstract some functions not implemented in the Arduino Client interface (such as EthernetClient::remoteIP), and the implementation class is the rest of the SSLClient library.

    +

    SSLClient was created to integrate SSL seamlessly with the Arduino infrastructure, and so it does just that: implementing the brilliant BearSSL as a proxy in front of any Arduino socket library. BearSSL is designed with low flash footprint in mind, and as a result does little verification of improper programming, relying on the developer to ensure the code is correct. Since SSLClient is built specifically for the Arduino ecosystem, most of SSLClient's code adds those programming checks back in, making debugging a fast and simple process.

    Other Features

    Logging

    SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor:

    {C++}
    EthernetClient baseClient;
    SSLClient client(baseClient, TAs, (size_t)2, A7, 1, SSLClient::SSL_INFO);

    Logging is always outputted through the Arduino Serial interface, so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in ::DebugLevel. The log level is set to SSL_WARN by default.

    diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index 71718cb..e5b45f8 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/html/namespace_s_s_l_obj.html index 236cda0..057d37a 100644 --- a/docs/html/namespace_s_s_l_obj.html +++ b/docs/html/namespace_s_s_l_obj.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers.html b/docs/html/namespacemembers.html index 361e57e..2f32e3b 100644 --- a/docs/html/namespacemembers.html +++ b/docs/html/namespacemembers.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers_func.html b/docs/html/namespacemembers_func.html index ba602f5..59c906e 100644 --- a/docs/html/namespacemembers_func.html +++ b/docs/html/namespacemembers_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespaces.html b/docs/html/namespaces.html index f7b1ebe..3f434c7 100644 --- a/docs/html/namespaces.html +++ b/docs/html/namespaces.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/navtreedata.js b/docs/html/navtreedata.js index 10bfff6..8d74ad1 100644 --- a/docs/html/navtreedata.js +++ b/docs/html/navtreedata.js @@ -24,7 +24,6 @@ for the JavaScript code in this file var NAVTREE = [ [ "SSLClient", "index.html", [ - [ "SSLClient - Arduino Library For SSL", "index.html", null ], [ "Trust Anchors", "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html", null ], [ "Namespaces", "namespaces.html", [ [ "Namespace List", "namespaces.html", "namespaces_dup" ], diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index 5640f49..55158e2 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -1,120 +1,121 @@ var NAVTREEINDEX0 = { -"_s_s_l_client_8cpp.html":[4,0,2,1], -"_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[4,0,2,1,0], -"_s_s_l_client_8h.html":[4,0,2,2], -"_s_s_l_client_8h_source.html":[4,0,2,2], -"_s_s_l_client_parameters_8h.html":[4,0,2,3], -"_s_s_l_client_parameters_8h_source.html":[4,0,2,3], -"_s_s_l_obj_8cpp.html":[4,0,2,4], -"_s_s_l_obj_8h.html":[4,0,2,5], -"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[4,0,2,5,0], -"_s_s_l_obj_8h_source.html":[4,0,2,5], -"_s_s_l_session_8h.html":[4,0,2,6], -"_s_s_l_session_8h_source.html":[4,0,2,6], -"_t_l_s12__only__profile_8c.html":[4,0,2,8], -"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[4,0,2,8,0], -"annotated.html":[3,0], -"cert_8h.html":[4,0,1,0], -"cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,1,0,0], -"cert_8h_source.html":[4,0,1,0], -"class_s_s_l_client.html":[3,0,1], -"class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86":[3,0,1,18], -"class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86":[3,0,1,12], -"class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78":[3,0,1,3], -"class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90":[3,0,1,5], -"class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3":[3,0,1,9], -"class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b":[3,0,1,11], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea":[3,0,1,1], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08":[3,0,1,1,6], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94":[3,0,1,1,0], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016":[3,0,1,1,4], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5":[3,0,1,1,2], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd":[3,0,1,1,1], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8":[3,0,1,1,3], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84":[3,0,1,1,5], -"class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95":[3,0,1,13], -"class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae":[3,0,1,6], -"class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376":[3,0,1,2], -"class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d":[3,0,1,19], -"class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21":[3,0,1,8], -"class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29":[3,0,1,16], -"class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c":[3,0,1,7], -"class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3":[3,0,1,4], -"class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4":[3,0,1,15], -"class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe":[3,0,1,17], -"class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22":[3,0,1,10], -"class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb":[3,0,1,14], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1":[3,0,1,0], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5":[3,0,1,0,1], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75":[3,0,1,0,0], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97":[3,0,1,0,2], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2":[3,0,1,0,3], -"class_s_s_l_session.html":[3,0,3], -"class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74":[3,0,3,0], -"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[3,0,3,1], -"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[3,0,3,2], -"classes.html":[3,1], -"dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[4,0,0,1], -"dir_68267d1309a1af8e8297ef4c3efbcdba.html":[4,0,2], -"dir_9c42dc81377249a918256dbb9cfb2167.html":[4,0,0,0], -"dir_d28a4824dc47e487b107a5db32ef43c4.html":[4,0,0], -"dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[4,0,1], -"ec__prime__fast__256_8c.html":[4,0,2,0], -"ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab":[4,0,2,0,0], -"files.html":[4,0], -"functions.html":[3,3,0], -"functions_enum.html":[3,3,3], -"functions_eval.html":[3,3,4], -"functions_func.html":[3,3,1], -"functions_vars.html":[3,3,2], -"globals.html":[4,1,0], -"globals_defs.html":[4,1,3], -"globals_func.html":[4,1,1], -"globals_vars.html":[4,1,2], -"hierarchy.html":[3,2], +"_s_s_l_client_8cpp.html":[3,0,2,1], +"_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[3,0,2,1,0], +"_s_s_l_client_8h.html":[3,0,2,2], +"_s_s_l_client_8h_source.html":[3,0,2,2], +"_s_s_l_client_parameters_8h.html":[3,0,2,3], +"_s_s_l_client_parameters_8h_source.html":[3,0,2,3], +"_s_s_l_obj_8cpp.html":[3,0,2,4], +"_s_s_l_obj_8h.html":[3,0,2,5], +"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[3,0,2,5,0], +"_s_s_l_obj_8h_source.html":[3,0,2,5], +"_s_s_l_session_8h.html":[3,0,2,6], +"_s_s_l_session_8h_source.html":[3,0,2,6], +"_t_l_s12__only__profile_8c.html":[3,0,2,8], +"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[3,0,2,8,0], +"annotated.html":[2,0], +"cert_8h.html":[3,0,1,0], +"cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,1,0,0], +"cert_8h_source.html":[3,0,1,0], +"class_s_s_l_client.html":[2,0,1], +"class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86":[2,0,1,20], +"class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86":[2,0,1,13], +"class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78":[2,0,1,3], +"class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90":[2,0,1,5], +"class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498":[2,0,1,11], +"class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3":[2,0,1,9], +"class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b":[2,0,1,12], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea":[2,0,1,1], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08":[2,0,1,1,6], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94":[2,0,1,1,0], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016":[2,0,1,1,4], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5":[2,0,1,1,2], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd":[2,0,1,1,1], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8":[2,0,1,1,3], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84":[2,0,1,1,5], +"class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95":[2,0,1,14], +"class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae":[2,0,1,6], +"class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376":[2,0,1,2], +"class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d":[2,0,1,21], +"class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae":[2,0,1,18], +"class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21":[2,0,1,8], +"class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29":[2,0,1,17], +"class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c":[2,0,1,7], +"class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3":[2,0,1,4], +"class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4":[2,0,1,16], +"class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe":[2,0,1,19], +"class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22":[2,0,1,10], +"class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb":[2,0,1,15], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1":[2,0,1,0], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5":[2,0,1,0,1], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75":[2,0,1,0,0], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97":[2,0,1,0,2], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2":[2,0,1,0,3], +"class_s_s_l_session.html":[2,0,3], +"class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74":[2,0,3,0], +"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[2,0,3,1], +"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[2,0,3,2], +"classes.html":[2,1], +"dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[3,0,0,1], +"dir_68267d1309a1af8e8297ef4c3efbcdba.html":[3,0,2], +"dir_9c42dc81377249a918256dbb9cfb2167.html":[3,0,0,0], +"dir_d28a4824dc47e487b107a5db32ef43c4.html":[3,0,0], +"dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[3,0,1], +"ec__prime__fast__256_8c.html":[3,0,2,0], +"ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab":[3,0,2,0,0], +"files.html":[3,0], +"functions.html":[2,3,0], +"functions_enum.html":[2,3,3], +"functions_eval.html":[2,3,4], +"functions_func.html":[2,3,1], +"functions_vars.html":[2,3,2], +"globals.html":[3,1,0], +"globals_defs.html":[3,1,3], +"globals_func.html":[3,1,1], +"globals_vars.html":[3,1,2], +"hierarchy.html":[2,2], "index.html":[], -"index.html":[0], -"md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[1], -"namespace_s_s_l_obj.html":[2,0,0], -"namespacemembers.html":[2,1,0], -"namespacemembers_func.html":[2,1,1], -"namespaces.html":[2,0], +"md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[0], +"namespace_s_s_l_obj.html":[1,0,0], +"namespacemembers.html":[1,1,0], +"namespacemembers_func.html":[1,1,1], +"namespaces.html":[1,0], "pages.html":[], -"struct_s_s_l_client_parameters.html":[3,0,2], -"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[3,0,2,1], -"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[3,0,2,0], -"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[3,0,2,2], -"structssl__pem__decode__state.html":[3,0,0], -"structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3":[3,0,0,0], -"structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9":[3,0,0,1], -"time__macros_8h.html":[4,0,2,7], -"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[4,0,2,7,19], -"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[4,0,2,7,14], -"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[4,0,2,7,1], -"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[4,0,2,7,20], -"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[4,0,2,7,16], -"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[4,0,2,7,4], -"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[4,0,2,7,15], -"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[4,0,2,7,13], -"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[4,0,2,7,5], -"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[4,0,2,7,8], -"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[4,0,2,7,0], -"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[4,0,2,7,6], -"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[4,0,2,7,18], -"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[4,0,2,7,12], -"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[4,0,2,7,11], -"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[4,0,2,7,2], -"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[4,0,2,7,7], -"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[4,0,2,7,17], -"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[4,0,2,7,3], -"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[4,0,2,7,9], -"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[4,0,2,7,10], -"time__macros_8h_source.html":[4,0,2,7], -"trust__anchors_8h.html":[4,0,0,0,0], -"trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,0,0,0,0], -"trust__anchors_8h_source.html":[4,0,0,0,0], -"trustanchors_8h.html":[4,0,0,1,0], -"trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[4,0,0,1,0,0], -"trustanchors_8h_source.html":[4,0,0,1,0] +"struct_s_s_l_client_parameters.html":[2,0,2], +"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[2,0,2,1], +"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[2,0,2,0], +"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[2,0,2,2], +"structssl__pem__decode__state.html":[2,0,0], +"structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3":[2,0,0,0], +"structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9":[2,0,0,1], +"time__macros_8h.html":[3,0,2,7], +"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,2,7,19], +"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,2,7,14], +"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,2,7,1], +"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,2,7,20], +"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,2,7,16], +"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,2,7,4], +"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,2,7,15], +"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,2,7,13], +"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,2,7,5], +"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,2,7,8], +"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,2,7,0], +"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,2,7,6], +"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,2,7,18], +"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,2,7,12], +"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,2,7,11], +"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,2,7,2], +"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,2,7,7], +"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,2,7,17], +"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,2,7,3], +"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,2,7,9], +"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,2,7,10], +"time__macros_8h_source.html":[3,0,2,7], +"trust__anchors_8h.html":[3,0,0,0,0], +"trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,0,0,0], +"trust__anchors_8h_source.html":[3,0,0,0,0], +"trustanchors_8h.html":[3,0,0,1,0], +"trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,1,0,0], +"trustanchors_8h_source.html":[3,0,0,1,0] }; diff --git a/docs/html/pages.html b/docs/html/pages.html index 64f2340..6e99f9f 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js index 48ec004..e8142e4 100644 --- a/docs/html/search/all_7.js +++ b/docs/html/search/all_7.js @@ -4,5 +4,6 @@ var searchData= ['get_5fmonth',['GET_MONTH',['../time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994',1,'time_macros.h']]], ['getclient',['getClient',['../class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21',1,'SSLClient']]], ['getsession',['getSession',['../class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3',1,'SSLClient']]], - ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]] + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]], + ['gettimeout',['getTimeout',['../class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_d.js b/docs/html/search/all_d.js index cf50882..1b4cde8 100644 --- a/docs/html/search/all_d.js +++ b/docs/html/search/all_d.js @@ -1,11 +1,12 @@ var searchData= [ - ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../index.html',1,'']]], + ['sslclient',['SSLClient',['../index.html',1,'']]], ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29',1,'SSLClient']]], + ['settimeout',['setTimeout',['../class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae',1,'SSLClient']]], ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5',1,'SSLClient']]], ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016',1,'SSLClient']]], ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd',1,'SSLClient']]], diff --git a/docs/html/search/functions_4.js b/docs/html/search/functions_4.js index d68b4de..7554e48 100644 --- a/docs/html/search/functions_4.js +++ b/docs/html/search/functions_4.js @@ -3,5 +3,6 @@ var searchData= ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], ['getclient',['getClient',['../class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21',1,'SSLClient']]], ['getsession',['getSession',['../class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3',1,'SSLClient']]], - ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]] + ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]], + ['gettimeout',['getTimeout',['../class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498',1,'SSLClient']]] ]; diff --git a/docs/html/search/functions_9.js b/docs/html/search/functions_9.js index 5e05068..d2a5842 100644 --- a/docs/html/search/functions_9.js +++ b/docs/html/search/functions_9.js @@ -1,6 +1,7 @@ var searchData= [ ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29',1,'SSLClient']]], + ['settimeout',['setTimeout',['../class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae',1,'SSLClient']]], ['sslclient',['SSLClient',['../class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376',1,'SSLClient']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74',1,'SSLSession']]], ['stop',['stop',['../class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe',1,'SSLClient']]] diff --git a/docs/html/search/pages_0.js b/docs/html/search/pages_0.js index 54d5ef5..11688e5 100644 --- a/docs/html/search/pages_0.js +++ b/docs/html/search/pages_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['sslclient_20_2d_20arduino_20library_20for_20ssl',['SSLClient - Arduino Library For SSL',['../index.html',1,'']]] + ['sslclient',['SSLClient',['../index.html',1,'']]] ]; diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/html/struct_s_s_l_client_parameters-members.html index 1c4cb0f..a4011c1 100644 --- a/docs/html/struct_s_s_l_client_parameters-members.html +++ b/docs/html/struct_s_s_l_client_parameters-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html index 024c050..8ea35ed 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/html/structssl__pem__decode__state-members.html index 108d3ce..46edec2 100644 --- a/docs/html/structssl__pem__decode__state-members.html +++ b/docs/html/structssl__pem__decode__state-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state.html b/docs/html/structssl__pem__decode__state.html index 9c58cb1..d2eb9fc 100644 --- a/docs/html/structssl__pem__decode__state.html +++ b/docs/html/structssl__pem__decode__state.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html index 68dcb80..9afa61a 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/html/time__macros_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html index a5e2fa7..6bb9fff 100644 --- a/docs/html/time__macros_8h_source.html +++ b/docs/html/time__macros_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html index 0df213d..bca7bac 100644 --- a/docs/html/trust__anchors_8h.html +++ b/docs/html/trust__anchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index 2998bfc..50718a5 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html index 958a976..8d88809 100644 --- a/docs/html/trustanchors_8h.html +++ b/docs/html/trustanchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html index 964016b..4217857 100644 --- a/docs/html/trustanchors_8h_source.html +++ b/docs/html/trustanchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.2 +  v1.4.4
    Add TLS 1.2 functionality to any network library.
    diff --git a/library.properties b/library.properties index 90907dd..b0f5f66 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.4.2 +version=1.4.4 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From f9e4d2574c1293edca4bffadedf267f35f5443cb Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 30 Dec 2019 08:00:00 -0800 Subject: [PATCH 094/205] fix incorrect cast from bool to int, and an invalid return value --- src/SSLClient.cpp | 9 +++------ src/SSLClient.h | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 3529144..0b09baa 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -89,7 +89,7 @@ int SSLClient::connect(IPAddress ip, uint16_t port) { // connection check if (get_arduino_client().connected()) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); - return -1; + return 0; } // reset indexs for saftey m_write_idx = 0; @@ -112,16 +112,13 @@ int SSLClient::connect(const char *host, uint16_t port) { // connection check if (get_arduino_client().connected()) { m_error("Cannot have two connections at the same time! Please create another SSLClient instance.", func_name); - return -1; + return 0; } // reset indexs for saftey m_write_idx = 0; - // first, if we have a session, check if we're trying to resolve the same host - // as before - const bool connect_ok = get_arduino_client().connect(host, port); // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. - if (!connect_ok) { + if (!get_arduino_client().connect(host, port)) { m_error("Failed to connect using m_client. Are you connected to the internet?", func_name); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; diff --git a/src/SSLClient.h b/src/SSLClient.h index 79d6827..28fc932 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -165,7 +165,7 @@ public: * * The implementation for this function can be found in SSLClientImpl::connect_impl(const char*, uint16_t) * - * @pre The underlying client object (passed in through the constructor) is in a non- + * @pre The underlying client object (passed in through the constructor) is in a non- * error state, and must be able to access the IP. * @pre SSLClient can only have one connection at a time, so the client * object must not already be connected. From 7f7deb5e658857f70a94578751f0e7cd797875d4 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 30 Dec 2019 08:02:36 -0800 Subject: [PATCH 095/205] bump version to v1.4.5 --- .travis/library.properties | 2 +- docs/html/_r_e_a_d_m_e_8md.html | 2 +- docs/html/_s_s_l_client_8cpp.html | 2 +- docs/html/_s_s_l_client_8h.html | 2 +- docs/html/_s_s_l_client_8h_source.html | 20 +++++++++---------- docs/html/_s_s_l_client_parameters_8h.html | 2 +- .../_s_s_l_client_parameters_8h_source.html | 2 +- docs/html/_s_s_l_obj_8cpp.html | 2 +- docs/html/_s_s_l_obj_8h.html | 2 +- docs/html/_s_s_l_obj_8h_source.html | 2 +- docs/html/_s_s_l_session_8h.html | 2 +- docs/html/_s_s_l_session_8h_source.html | 2 +- docs/html/_t_l_s12__only__profile_8c.html | 2 +- docs/html/_trust_anchors_8md.html | 2 +- docs/html/annotated.html | 2 +- docs/html/cert_8h.html | 2 +- docs/html/cert_8h_source.html | 2 +- docs/html/class_s_s_l_client-members.html | 2 +- docs/html/class_s_s_l_client.html | 2 +- docs/html/class_s_s_l_session-members.html | 2 +- docs/html/class_s_s_l_session.html | 2 +- docs/html/classes.html | 2 +- .../dir_386349f6a9bc1e2cd0767d257d5e5b91.html | 2 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- .../dir_9c42dc81377249a918256dbb9cfb2167.html | 2 +- .../dir_d28a4824dc47e487b107a5db32ef43c4.html | 2 +- .../dir_dfc5a9f91fbfb9426c406a3f10131a54.html | 2 +- docs/html/ec__prime__fast__256_8c.html | 2 +- docs/html/files.html | 2 +- docs/html/functions.html | 2 +- docs/html/functions_enum.html | 2 +- docs/html/functions_eval.html | 2 +- docs/html/functions_func.html | 2 +- docs/html/functions_vars.html | 2 +- docs/html/globals.html | 2 +- docs/html/globals_defs.html | 2 +- docs/html/globals_func.html | 2 +- docs/html/globals_vars.html | 2 +- docs/html/hierarchy.html | 2 +- docs/html/index.html | 2 +- ...ibraries__s_s_l_client__trust_anchors.html | 2 +- docs/html/namespace_s_s_l_obj.html | 2 +- docs/html/namespacemembers.html | 2 +- docs/html/namespacemembers_func.html | 2 +- docs/html/namespaces.html | 2 +- docs/html/pages.html | 2 +- ...truct_s_s_l_client_parameters-members.html | 2 +- docs/html/struct_s_s_l_client_parameters.html | 2 +- ...structssl__pem__decode__state-members.html | 2 +- docs/html/structssl__pem__decode__state.html | 2 +- docs/html/time__macros_8h.html | 2 +- docs/html/time__macros_8h_source.html | 2 +- docs/html/trust__anchors_8h.html | 2 +- docs/html/trust__anchors_8h_source.html | 2 +- docs/html/trustanchors_8h.html | 2 +- docs/html/trustanchors_8h_source.html | 2 +- library.properties | 2 +- 57 files changed, 66 insertions(+), 66 deletions(-) diff --git a/.travis/library.properties b/.travis/library.properties index 3111be0..f9a3cbf 100644 --- a/.travis/library.properties +++ b/.travis/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.3.0 +version=1.4.5 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/html/_r_e_a_d_m_e_8md.html index ebee020..fae2ace 100644 --- a/docs/html/_r_e_a_d_m_e_8md.html +++ b/docs/html/_r_e_a_d_m_e_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8cpp.html b/docs/html/_s_s_l_client_8cpp.html index 4c6ce71..fb00945 100644 --- a/docs/html/_s_s_l_client_8cpp.html +++ b/docs/html/_s_s_l_client_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index c9700ea..419fe33 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index 804eb3b..d512294 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
    SSLClient.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    365  void setTimeout(unsigned int t) { m_timeout = t; }
    366 
    371  unsigned int getTimeout() const { return m_timeout; }
    372 
    373 private:
    375  Client& get_arduino_client() { return m_client; }
    376  const Client& get_arduino_client() const { return m_client; }
    377 
    379  bool m_soft_connected(const char* func_name);
    381  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    383  int m_run_until(const unsigned target);
    385  unsigned m_update_engine();
    387  int m_get_session_index(const char* host) const;
    388 
    390  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    391 
    393  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    394 
    396  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    397 
    399  template<typename T>
    400  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    401  // check the current debug level and serial status
    402  if (level > m_debug || !Serial) return;
    403  // print prefix
    404  m_print_prefix(func_name, level);
    405  // print the message
    406  Serial.println(str);
    407  }
    408 
    410  template<typename T>
    411  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    412 
    413  template<typename T>
    414  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    415 
    416  template<typename T>
    417  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    418 
    419  //============================================
    420  //= Data Members
    421  //============================================
    422  // create a reference the client
    423  Client& m_client;
    424  // also store an array of SSLSessions, so we can resume communication with multiple websites
    425  std::vector<SSLSession> m_sessions;
    426  // as well as the maximmum number of sessions we can store
    427  const size_t m_max_sessions;
    428  // store the pin to fetch an RNG see from
    429  const int m_analog_pin;
    430  // store whether to enable debug logging
    431  const DebugLevel m_debug;
    432  // store if we are connected in bearssl or not
    433  bool m_is_connected;
    434  // store the timeout for SSL internals
    435  unsigned int m_timeout;
    436  // store the context values required for SSL
    437  br_ssl_client_context m_sslctx;
    438  br_x509_minimal_context m_x509ctx;
    439  // use a mono-directional buffer by default to cut memory in half
    440  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    441  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    442  // simply edit this value to change the buffer size to the desired value
    443  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    444  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    452  unsigned char m_iobuf[2048];
    453  // store the index of where we are writing in the buffer
    454  // so we can send our records all at once to prevent
    455  // weird timing issues
    456  size_t m_write_idx;
    457 };
    458 
    459 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:259
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    365  void setTimeout(unsigned int t) { m_timeout = t; }
    366 
    371  unsigned int getTimeout() const { return m_timeout; }
    372 
    373 private:
    375  Client& get_arduino_client() { return m_client; }
    376  const Client& get_arduino_client() const { return m_client; }
    377 
    379  bool m_soft_connected(const char* func_name);
    381  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    383  int m_run_until(const unsigned target);
    385  unsigned m_update_engine();
    387  int m_get_session_index(const char* host) const;
    388 
    390  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    391 
    393  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    394 
    396  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    397 
    399  template<typename T>
    400  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    401  // check the current debug level and serial status
    402  if (level > m_debug || !Serial) return;
    403  // print prefix
    404  m_print_prefix(func_name, level);
    405  // print the message
    406  Serial.println(str);
    407  }
    408 
    410  template<typename T>
    411  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    412 
    413  template<typename T>
    414  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    415 
    416  template<typename T>
    417  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    418 
    419  //============================================
    420  //= Data Members
    421  //============================================
    422  // create a reference the client
    423  Client& m_client;
    424  // also store an array of SSLSessions, so we can resume communication with multiple websites
    425  std::vector<SSLSession> m_sessions;
    426  // as well as the maximmum number of sessions we can store
    427  const size_t m_max_sessions;
    428  // store the pin to fetch an RNG see from
    429  const int m_analog_pin;
    430  // store whether to enable debug logging
    431  const DebugLevel m_debug;
    432  // store if we are connected in bearssl or not
    433  bool m_is_connected;
    434  // store the timeout for SSL internals
    435  unsigned int m_timeout;
    436  // store the context values required for SSL
    437  br_ssl_client_context m_sslctx;
    438  br_x509_minimal_context m_x509ctx;
    439  // use a mono-directional buffer by default to cut memory in half
    440  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    441  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    442  // simply edit this value to change the buffer size to the desired value
    443  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    444  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    452  unsigned char m_iobuf[2048];
    453  // store the index of where we are writing in the buffer
    454  // so we can send our records all at once to prevent
    455  // weird timing issues
    456  size_t m_write_idx;
    457 };
    458 
    459 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:256
    Definition: SSLClient.h:58
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:51
    void setTimeout(unsigned int t)
    Set the timeout when waiting for an SSL response.
    Definition: SSLClient.h:365
    @@ -99,29 +99,29 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8h_source.html','');});
    Definition: SSLClient.h:75
    Definition: SSLClient.h:54
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:60
    -
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:226
    -
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:290
    +
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:223
    +
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:287
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    -
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:314
    -
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:178
    +
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:311
    +
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:175
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    Definition: SSLClient.h:73
    -
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:232
    +
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:229
    Definition: SSLClient.h:71
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:87
    -
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:135
    +
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:132
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:258
    Error
    Static constants defining the possible errors encountered.
    Definition: SSLClient.h:45
    Definition: SSLClient.h:52
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClient.h:67
    size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:349
    -
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:214
    +
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:211
    Definition: SSLClient.h:50
    size_t write(uint8_t b) override
    Definition: SSLClient.h:210
    Client & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:359
    -
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:303
    +
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:300
    unsigned int getTimeout() const
    Get the timeout when waiting for an SSL response.
    Definition: SSLClient.h:371
    Definition: SSLClient.h:69
    diff --git a/docs/html/_s_s_l_client_parameters_8h.html b/docs/html/_s_s_l_client_parameters_8h.html index 2647c40..5f949e2 100644 --- a/docs/html/_s_s_l_client_parameters_8h.html +++ b/docs/html/_s_s_l_client_parameters_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_parameters_8h_source.html b/docs/html/_s_s_l_client_parameters_8h_source.html index 7d928bd..12859e2 100644 --- a/docs/html/_s_s_l_client_parameters_8h_source.html +++ b/docs/html/_s_s_l_client_parameters_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8cpp.html b/docs/html/_s_s_l_obj_8cpp.html index 0a2fc2f..c386639 100644 --- a/docs/html/_s_s_l_obj_8cpp.html +++ b/docs/html/_s_s_l_obj_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h.html b/docs/html/_s_s_l_obj_8h.html index c027151..c77e4bb 100644 --- a/docs/html/_s_s_l_obj_8h.html +++ b/docs/html/_s_s_l_obj_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h_source.html b/docs/html/_s_s_l_obj_8h_source.html index 31eaa8d..36d79e8 100644 --- a/docs/html/_s_s_l_obj_8h_source.html +++ b/docs/html/_s_s_l_obj_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index e6b2880..654ceb4 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index 11dbedc..bab8f33 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html index c10b9ff..f691a67 100644 --- a/docs/html/_t_l_s12__only__profile_8c.html +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html index 2224d5f..043deb4 100644 --- a/docs/html/_trust_anchors_8md.html +++ b/docs/html/_trust_anchors_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/annotated.html b/docs/html/annotated.html index d9cbd2e..344e56b 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h.html b/docs/html/cert_8h.html index 7119de4..2b064e2 100644 --- a/docs/html/cert_8h.html +++ b/docs/html/cert_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html index 98ce4e3..2b2e4d0 100644 --- a/docs/html/cert_8h_source.html +++ b/docs/html/cert_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 9bd680d..77a9bdc 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 8c54357..dc4755c 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index f3b1d0e..3dbefa9 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index 917abdc..dd8f652 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/classes.html b/docs/html/classes.html index b6041e9..674145d 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html index 825ca7b..b0f91e2 100644 --- a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 456518e..949ebde 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html index d5e0dd3..8c7286b 100644 --- a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html index 5d8ba54..e4c5a38 100644 --- a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html index 16f74f7..d8380fc 100644 --- a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/ec__prime__fast__256_8c.html b/docs/html/ec__prime__fast__256_8c.html index 7699c72..8ed139f 100644 --- a/docs/html/ec__prime__fast__256_8c.html +++ b/docs/html/ec__prime__fast__256_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/files.html b/docs/html/files.html index cf9a5ac..f9a5fa2 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions.html b/docs/html/functions.html index 85678f0..353df3b 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_enum.html b/docs/html/functions_enum.html index 37cf15a..005750c 100644 --- a/docs/html/functions_enum.html +++ b/docs/html/functions_enum.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_eval.html b/docs/html/functions_eval.html index 2e9b13d..d283e2e 100644 --- a/docs/html/functions_eval.html +++ b/docs/html/functions_eval.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index 581a9bf..6fd009a 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_vars.html b/docs/html/functions_vars.html index a8687fc..de9b743 100644 --- a/docs/html/functions_vars.html +++ b/docs/html/functions_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals.html b/docs/html/globals.html index c2e3cd5..d237227 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index 0b0d8dc..ad42bfd 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index 739b50a..c99467d 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index 66a165d..8998ead 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 35e7bf0..4533ba4 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/index.html b/docs/html/index.html index ebde966..9ceb7fd 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index e5b45f8..20dd978 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/html/namespace_s_s_l_obj.html index 057d37a..1b9f603 100644 --- a/docs/html/namespace_s_s_l_obj.html +++ b/docs/html/namespace_s_s_l_obj.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers.html b/docs/html/namespacemembers.html index 2f32e3b..4fe7911 100644 --- a/docs/html/namespacemembers.html +++ b/docs/html/namespacemembers.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers_func.html b/docs/html/namespacemembers_func.html index 59c906e..4a04138 100644 --- a/docs/html/namespacemembers_func.html +++ b/docs/html/namespacemembers_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespaces.html b/docs/html/namespaces.html index 3f434c7..b210ae9 100644 --- a/docs/html/namespaces.html +++ b/docs/html/namespaces.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/pages.html b/docs/html/pages.html index 6e99f9f..06ad112 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/html/struct_s_s_l_client_parameters-members.html index a4011c1..5d6d7d6 100644 --- a/docs/html/struct_s_s_l_client_parameters-members.html +++ b/docs/html/struct_s_s_l_client_parameters-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html index 8ea35ed..e9f54fb 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/html/structssl__pem__decode__state-members.html index 46edec2..990bfa5 100644 --- a/docs/html/structssl__pem__decode__state-members.html +++ b/docs/html/structssl__pem__decode__state-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state.html b/docs/html/structssl__pem__decode__state.html index d2eb9fc..5305782 100644 --- a/docs/html/structssl__pem__decode__state.html +++ b/docs/html/structssl__pem__decode__state.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html index 9afa61a..e6feab8 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/html/time__macros_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html index 6bb9fff..6076167 100644 --- a/docs/html/time__macros_8h_source.html +++ b/docs/html/time__macros_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html index bca7bac..2fea34b 100644 --- a/docs/html/trust__anchors_8h.html +++ b/docs/html/trust__anchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index 50718a5..ee59654 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html index 8d88809..7970dba 100644 --- a/docs/html/trustanchors_8h.html +++ b/docs/html/trustanchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html index 4217857..8cee1b9 100644 --- a/docs/html/trustanchors_8h_source.html +++ b/docs/html/trustanchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.4 +  v1.4.5
    Add TLS 1.2 functionality to any network library.
    diff --git a/library.properties b/library.properties index b0f5f66..4069e7e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.4.4 +version=1.4.5 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From 6d014c5f0a3a4abed1cab461099a453dd25489b1 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 30 Dec 2019 08:21:19 -0800 Subject: [PATCH 096/205] Fix the adafruit SAMD core version used by travis --- .travis.yml | 3 +-- .travis/library.properties | 2 +- docs/html/_r_e_a_d_m_e_8md.html | 2 +- docs/html/_s_s_l_client_8cpp.html | 2 +- docs/html/_s_s_l_client_8h.html | 2 +- docs/html/_s_s_l_client_8h_source.html | 2 +- docs/html/_s_s_l_client_parameters_8h.html | 2 +- docs/html/_s_s_l_client_parameters_8h_source.html | 2 +- docs/html/_s_s_l_obj_8cpp.html | 2 +- docs/html/_s_s_l_obj_8h.html | 2 +- docs/html/_s_s_l_obj_8h_source.html | 2 +- docs/html/_s_s_l_session_8h.html | 2 +- docs/html/_s_s_l_session_8h_source.html | 2 +- docs/html/_t_l_s12__only__profile_8c.html | 2 +- docs/html/_trust_anchors_8md.html | 2 +- docs/html/annotated.html | 2 +- docs/html/cert_8h.html | 2 +- docs/html/cert_8h_source.html | 2 +- docs/html/class_s_s_l_client-members.html | 2 +- docs/html/class_s_s_l_client.html | 2 +- docs/html/class_s_s_l_session-members.html | 2 +- docs/html/class_s_s_l_session.html | 2 +- docs/html/classes.html | 2 +- docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html | 2 +- docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html | 2 +- docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html | 2 +- docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html | 2 +- docs/html/ec__prime__fast__256_8c.html | 2 +- docs/html/files.html | 2 +- docs/html/functions.html | 2 +- docs/html/functions_enum.html | 2 +- docs/html/functions_eval.html | 2 +- docs/html/functions_func.html | 2 +- docs/html/functions_vars.html | 2 +- docs/html/globals.html | 2 +- docs/html/globals_defs.html | 2 +- docs/html/globals_func.html | 2 +- docs/html/globals_vars.html | 2 +- docs/html/hierarchy.html | 2 +- docs/html/index.html | 2 +- ...uments__arduino_libraries__s_s_l_client__trust_anchors.html | 2 +- docs/html/namespace_s_s_l_obj.html | 2 +- docs/html/namespacemembers.html | 2 +- docs/html/namespacemembers_func.html | 2 +- docs/html/namespaces.html | 2 +- docs/html/pages.html | 2 +- docs/html/struct_s_s_l_client_parameters-members.html | 2 +- docs/html/struct_s_s_l_client_parameters.html | 2 +- docs/html/structssl__pem__decode__state-members.html | 2 +- docs/html/structssl__pem__decode__state.html | 2 +- docs/html/time__macros_8h.html | 2 +- docs/html/time__macros_8h_source.html | 2 +- docs/html/trust__anchors_8h.html | 2 +- docs/html/trust__anchors_8h_source.html | 2 +- docs/html/trustanchors_8h.html | 2 +- docs/html/trustanchors_8h_source.html | 2 +- library.properties | 2 +- 58 files changed, 58 insertions(+), 59 deletions(-) diff --git a/.travis.yml b/.travis.yml index a3f3154..fc5ffb6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ before_install: - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/bin sudo sh - arduino-cli core update-index --additional-urls $ADDITIONAL_URLS - arduino-cli core install arduino:samd -v - - arduino-cli core install adafruit:samd -v --additional-urls $ADDITIONAL_URLS + - arduino-cli core install adafruit:samd@1.5.6 -v --additional-urls $ADDITIONAL_URLS - mkdir -p $HOME/Arduino/libraries - git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/Arduino/libraries/EthernetLarge install: @@ -50,4 +50,3 @@ deploy: tags: true branch: master condition: $DEPLOY = 1 - \ No newline at end of file diff --git a/.travis/library.properties b/.travis/library.properties index f9a3cbf..2cd6ee3 100644 --- a/.travis/library.properties +++ b/.travis/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.4.5 +version=1.4.6 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/html/_r_e_a_d_m_e_8md.html index fae2ace..fd61056 100644 --- a/docs/html/_r_e_a_d_m_e_8md.html +++ b/docs/html/_r_e_a_d_m_e_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8cpp.html b/docs/html/_s_s_l_client_8cpp.html index fb00945..d000e4c 100644 --- a/docs/html/_s_s_l_client_8cpp.html +++ b/docs/html/_s_s_l_client_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h.html b/docs/html/_s_s_l_client_8h.html index 419fe33..42b94a3 100644 --- a/docs/html/_s_s_l_client_8h.html +++ b/docs/html/_s_s_l_client_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8h_source.html b/docs/html/_s_s_l_client_8h_source.html index d512294..43e3f0e 100644 --- a/docs/html/_s_s_l_client_8h_source.html +++ b/docs/html/_s_s_l_client_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_parameters_8h.html b/docs/html/_s_s_l_client_parameters_8h.html index 5f949e2..dcf4562 100644 --- a/docs/html/_s_s_l_client_parameters_8h.html +++ b/docs/html/_s_s_l_client_parameters_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_parameters_8h_source.html b/docs/html/_s_s_l_client_parameters_8h_source.html index 12859e2..7782ab4 100644 --- a/docs/html/_s_s_l_client_parameters_8h_source.html +++ b/docs/html/_s_s_l_client_parameters_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8cpp.html b/docs/html/_s_s_l_obj_8cpp.html index c386639..dd949ae 100644 --- a/docs/html/_s_s_l_obj_8cpp.html +++ b/docs/html/_s_s_l_obj_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h.html b/docs/html/_s_s_l_obj_8h.html index c77e4bb..7a3fa88 100644 --- a/docs/html/_s_s_l_obj_8h.html +++ b/docs/html/_s_s_l_obj_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h_source.html b/docs/html/_s_s_l_obj_8h_source.html index 36d79e8..5224fe6 100644 --- a/docs/html/_s_s_l_obj_8h_source.html +++ b/docs/html/_s_s_l_obj_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index 654ceb4..4017c51 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index bab8f33..f86c947 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html index f691a67..74153aa 100644 --- a/docs/html/_t_l_s12__only__profile_8c.html +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html index 043deb4..da6e691 100644 --- a/docs/html/_trust_anchors_8md.html +++ b/docs/html/_trust_anchors_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 344e56b..018732e 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h.html b/docs/html/cert_8h.html index 2b064e2..ced538b 100644 --- a/docs/html/cert_8h.html +++ b/docs/html/cert_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html index 2b2e4d0..de6ff00 100644 --- a/docs/html/cert_8h_source.html +++ b/docs/html/cert_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 77a9bdc..136231e 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index dc4755c..0a9e1da 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index 3dbefa9..d035c58 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index dd8f652..1a1574a 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/classes.html b/docs/html/classes.html index 674145d..59bf48a 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html index b0f91e2..c9720d1 100644 --- a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 949ebde..24f9953 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html index 8c7286b..6c302ee 100644 --- a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html index e4c5a38..b81fe87 100644 --- a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html index d8380fc..d5742ed 100644 --- a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/ec__prime__fast__256_8c.html b/docs/html/ec__prime__fast__256_8c.html index 8ed139f..a3cc4e7 100644 --- a/docs/html/ec__prime__fast__256_8c.html +++ b/docs/html/ec__prime__fast__256_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/files.html b/docs/html/files.html index f9a5fa2..f7dae12 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions.html b/docs/html/functions.html index 353df3b..8ecc386 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_enum.html b/docs/html/functions_enum.html index 005750c..20b6fd0 100644 --- a/docs/html/functions_enum.html +++ b/docs/html/functions_enum.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_eval.html b/docs/html/functions_eval.html index d283e2e..8bd2041 100644 --- a/docs/html/functions_eval.html +++ b/docs/html/functions_eval.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index 6fd009a..d2ff505 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_vars.html b/docs/html/functions_vars.html index de9b743..f6b963a 100644 --- a/docs/html/functions_vars.html +++ b/docs/html/functions_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals.html b/docs/html/globals.html index d237227..0ed24c6 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index ad42bfd..303137a 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index c99467d..3631b47 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index 8998ead..272494e 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 4533ba4..20f90ea 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/index.html b/docs/html/index.html index 9ceb7fd..9b90264 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index 20dd978..cf764ef 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/html/namespace_s_s_l_obj.html index 1b9f603..ecb8ff8 100644 --- a/docs/html/namespace_s_s_l_obj.html +++ b/docs/html/namespace_s_s_l_obj.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers.html b/docs/html/namespacemembers.html index 4fe7911..ce98c51 100644 --- a/docs/html/namespacemembers.html +++ b/docs/html/namespacemembers.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers_func.html b/docs/html/namespacemembers_func.html index 4a04138..f1b956c 100644 --- a/docs/html/namespacemembers_func.html +++ b/docs/html/namespacemembers_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespaces.html b/docs/html/namespaces.html index b210ae9..04490c1 100644 --- a/docs/html/namespaces.html +++ b/docs/html/namespaces.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/pages.html b/docs/html/pages.html index 06ad112..c0a2370 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/html/struct_s_s_l_client_parameters-members.html index 5d6d7d6..17b2d29 100644 --- a/docs/html/struct_s_s_l_client_parameters-members.html +++ b/docs/html/struct_s_s_l_client_parameters-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html index e9f54fb..378f2f4 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/html/structssl__pem__decode__state-members.html index 990bfa5..aa97d7a 100644 --- a/docs/html/structssl__pem__decode__state-members.html +++ b/docs/html/structssl__pem__decode__state-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state.html b/docs/html/structssl__pem__decode__state.html index 5305782..d83b13e 100644 --- a/docs/html/structssl__pem__decode__state.html +++ b/docs/html/structssl__pem__decode__state.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html index e6feab8..e83dae8 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/html/time__macros_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html index 6076167..3438408 100644 --- a/docs/html/time__macros_8h_source.html +++ b/docs/html/time__macros_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html index 2fea34b..051c11e 100644 --- a/docs/html/trust__anchors_8h.html +++ b/docs/html/trust__anchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index ee59654..2d6add6 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html index 7970dba..0602f16 100644 --- a/docs/html/trustanchors_8h.html +++ b/docs/html/trustanchors_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html index 8cee1b9..c5088dd 100644 --- a/docs/html/trustanchors_8h_source.html +++ b/docs/html/trustanchors_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.5 +  v1.4.6
    Add TLS 1.2 functionality to any network library.
    diff --git a/library.properties b/library.properties index 4069e7e..bc8cd08 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.4.5 +version=1.4.6 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class From 90572ac065d546a384072e09a0b65214d5f86e87 Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 31 Dec 2019 10:16:27 -0800 Subject: [PATCH 097/205] Update README to specify non-compatibility with the ESP family --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1917370..29fb769 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ You can also view this README in [doxygen](https://openslab-osu.github.io/SSLCli SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. +SSLClient has been tested on the SAMD21 and STM32 (in progress). SSClient does not currently support the ESP8266/ESP32 family (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5)). + ## Overview Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few extra things, however, that you will need to get started: From 231da377627a9ad67f215d7df9d19c7421ed8557 Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 31 Dec 2019 10:18:12 -0800 Subject: [PATCH 098/205] Update issue link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29fb769..52c882c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ You can also view this README in [doxygen](https://openslab-osu.github.io/SSLCli SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. -SSLClient has been tested on the SAMD21 and STM32 (in progress). SSClient does not currently support the ESP8266/ESP32 family (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5)). +SSLClient has been tested on the SAMD21 and STM32 (in progress). SSClient does not currently support the ESP8266/ESP32 family (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)). ## Overview From 576e34487ea563512c6a35cb27a183274f59a445 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 6 Jan 2020 09:38:39 -0800 Subject: [PATCH 099/205] Fix memory checker for ESP32 compatibility --- .travis.yml | 2 +- .travis/library.properties | 2 +- README.md | 2 +- docs/html/_r_e_a_d_m_e_8md.html | 2 +- docs/html/_s_s_l_client_8cpp.html | 27 ++----------------- docs/html/_s_s_l_client_8h.html | 2 +- docs/html/_s_s_l_client_8h_source.html | 24 ++++++++--------- docs/html/_s_s_l_client_parameters_8h.html | 2 +- .../_s_s_l_client_parameters_8h_source.html | 2 +- docs/html/_s_s_l_obj_8cpp.html | 2 +- docs/html/_s_s_l_obj_8h.html | 2 +- docs/html/_s_s_l_obj_8h_source.html | 2 +- docs/html/_s_s_l_session_8h.html | 2 +- docs/html/_s_s_l_session_8h_source.html | 2 +- docs/html/_t_l_s12__only__profile_8c.html | 2 +- docs/html/_trust_anchors_8md.html | 2 +- docs/html/annotated.html | 2 +- docs/html/cert_8h.html | 2 +- docs/html/cert_8h_source.html | 2 +- docs/html/class_s_s_l_client-members.html | 2 +- docs/html/class_s_s_l_client.html | 2 +- docs/html/class_s_s_l_session-members.html | 2 +- docs/html/class_s_s_l_session.html | 2 +- docs/html/classes.html | 2 +- .../dir_386349f6a9bc1e2cd0767d257d5e5b91.html | 2 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.js | 2 +- .../dir_9c42dc81377249a918256dbb9cfb2167.html | 2 +- .../dir_d28a4824dc47e487b107a5db32ef43c4.html | 2 +- .../dir_dfc5a9f91fbfb9426c406a3f10131a54.html | 2 +- docs/html/ec__prime__fast__256_8c.html | 2 +- docs/html/files.html | 2 +- docs/html/functions.html | 2 +- docs/html/functions_enum.html | 2 +- docs/html/functions_eval.html | 2 +- docs/html/functions_func.html | 2 +- docs/html/functions_vars.html | 2 +- docs/html/globals.html | 5 +--- docs/html/globals_defs.html | 2 +- docs/html/globals_func.html | 2 +- docs/html/globals_vars.html | 5 +--- docs/html/hierarchy.html | 2 +- docs/html/index.html | 3 ++- ...ibraries__s_s_l_client__trust_anchors.html | 2 +- docs/html/namespace_s_s_l_obj.html | 2 +- docs/html/namespacemembers.html | 2 +- docs/html/namespacemembers_func.html | 2 +- docs/html/namespaces.html | 2 +- docs/html/navtreeindex0.js | 1 - docs/html/pages.html | 2 +- docs/html/search/all_0.js | 1 - docs/html/search/searchdata.js | 2 +- docs/html/search/variables_0.js | 2 +- docs/html/search/variables_1.js | 3 ++- docs/html/search/variables_2.js | 3 +-- docs/html/search/variables_3.js | 2 +- docs/html/search/variables_4.js | 2 +- ...truct_s_s_l_client_parameters-members.html | 2 +- docs/html/struct_s_s_l_client_parameters.html | 2 +- ...structssl__pem__decode__state-members.html | 2 +- docs/html/structssl__pem__decode__state.html | 2 +- docs/html/time__macros_8h.html | 2 +- docs/html/time__macros_8h_source.html | 2 +- docs/html/trust__anchors_8h.html | 2 +- docs/html/trust__anchors_8h_source.html | 2 +- docs/html/trustanchors_8h.html | 2 +- docs/html/trustanchors_8h_source.html | 2 +- library.properties | 2 +- src/SSLClient.cpp | 11 +++----- 69 files changed, 83 insertions(+), 118 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc5ffb6..cf23d60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ before_install: - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/bin sudo sh - arduino-cli core update-index --additional-urls $ADDITIONAL_URLS - arduino-cli core install arduino:samd -v - - arduino-cli core install adafruit:samd@1.5.6 -v --additional-urls $ADDITIONAL_URLS + - arduino-cli core install adafruit:samd -v --additional-urls $ADDITIONAL_URLS - mkdir -p $HOME/Arduino/libraries - git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/Arduino/libraries/EthernetLarge install: diff --git a/.travis/library.properties b/.travis/library.properties index 2cd6ee3..3bc0cad 100644 --- a/.travis/library.properties +++ b/.travis/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.4.6 +version=1.4.7 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/README.md b/README.md index 52c882c..027f60f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ You can also view this README in [doxygen](https://openslab-osu.github.io/SSLCli SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. -SSLClient has been tested on the SAMD21 and STM32 (in progress). SSClient does not currently support the ESP8266/ESP32 family (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)). +SSLClient has been tested on the SAMD21, ESP32, and STM32 (in progress). SSClient does not currently support the ESP8266 (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)). ## Overview diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/html/_r_e_a_d_m_e_8md.html index fd61056..af50fef 100644 --- a/docs/html/_r_e_a_d_m_e_8md.html +++ b/docs/html/_r_e_a_d_m_e_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_8cpp.html b/docs/html/_s_s_l_client_8cpp.html index d000e4c..25e3925 100644 --- a/docs/html/_s_s_l_client_8cpp.html +++ b/docs/html/_s_s_l_client_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    @@ -87,35 +87,12 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8cpp.html','');});
    -
    SSLClient.cpp File Reference
    #include "SSLClient.h"
    -
    - - - -

    -Variables

    char * __brkval
     
    -

    Variable Documentation

    - -

    ◆ __brkval

    - -
    -
    - - - - -
    char* __brkval
    -
    - -
    -
    -
    +
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    365  void setTimeout(unsigned int t) { m_timeout = t; }
    366 
    371  unsigned int getTimeout() const { return m_timeout; }
    372 
    373 private:
    375  Client& get_arduino_client() { return m_client; }
    376  const Client& get_arduino_client() const { return m_client; }
    377 
    379  bool m_soft_connected(const char* func_name);
    381  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    383  int m_run_until(const unsigned target);
    385  unsigned m_update_engine();
    387  int m_get_session_index(const char* host) const;
    388 
    390  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    391 
    393  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    394 
    396  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    397 
    399  template<typename T>
    400  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    401  // check the current debug level and serial status
    402  if (level > m_debug || !Serial) return;
    403  // print prefix
    404  m_print_prefix(func_name, level);
    405  // print the message
    406  Serial.println(str);
    407  }
    408 
    410  template<typename T>
    411  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    412 
    413  template<typename T>
    414  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    415 
    416  template<typename T>
    417  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    418 
    419  //============================================
    420  //= Data Members
    421  //============================================
    422  // create a reference the client
    423  Client& m_client;
    424  // also store an array of SSLSessions, so we can resume communication with multiple websites
    425  std::vector<SSLSession> m_sessions;
    426  // as well as the maximmum number of sessions we can store
    427  const size_t m_max_sessions;
    428  // store the pin to fetch an RNG see from
    429  const int m_analog_pin;
    430  // store whether to enable debug logging
    431  const DebugLevel m_debug;
    432  // store if we are connected in bearssl or not
    433  bool m_is_connected;
    434  // store the timeout for SSL internals
    435  unsigned int m_timeout;
    436  // store the context values required for SSL
    437  br_ssl_client_context m_sslctx;
    438  br_x509_minimal_context m_x509ctx;
    439  // use a mono-directional buffer by default to cut memory in half
    440  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    441  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    442  // simply edit this value to change the buffer size to the desired value
    443  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    444  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    452  unsigned char m_iobuf[2048];
    453  // store the index of where we are writing in the buffer
    454  // so we can send our records all at once to prevent
    455  // weird timing issues
    456  size_t m_write_idx;
    457 };
    458 
    459 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:256
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    365  void setTimeout(unsigned int t) { m_timeout = t; }
    366 
    371  unsigned int getTimeout() const { return m_timeout; }
    372 
    373 private:
    375  Client& get_arduino_client() { return m_client; }
    376  const Client& get_arduino_client() const { return m_client; }
    377 
    379  bool m_soft_connected(const char* func_name);
    381  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    383  int m_run_until(const unsigned target);
    385  unsigned m_update_engine();
    387  int m_get_session_index(const char* host) const;
    388 
    390  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    391 
    393  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    394 
    396  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    397 
    399  template<typename T>
    400  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    401  // check the current debug level and serial status
    402  if (level > m_debug || !Serial) return;
    403  // print prefix
    404  m_print_prefix(func_name, level);
    405  // print the message
    406  Serial.println(str);
    407  }
    408 
    410  template<typename T>
    411  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    412 
    413  template<typename T>
    414  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    415 
    416  template<typename T>
    417  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    418 
    419  //============================================
    420  //= Data Members
    421  //============================================
    422  // create a reference the client
    423  Client& m_client;
    424  // also store an array of SSLSessions, so we can resume communication with multiple websites
    425  std::vector<SSLSession> m_sessions;
    426  // as well as the maximmum number of sessions we can store
    427  const size_t m_max_sessions;
    428  // store the pin to fetch an RNG see from
    429  const int m_analog_pin;
    430  // store whether to enable debug logging
    431  const DebugLevel m_debug;
    432  // store if we are connected in bearssl or not
    433  bool m_is_connected;
    434  // store the timeout for SSL internals
    435  unsigned int m_timeout;
    436  // store the context values required for SSL
    437  br_ssl_client_context m_sslctx;
    438  br_x509_minimal_context m_x509ctx;
    439  // use a mono-directional buffer by default to cut memory in half
    440  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    441  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    442  // simply edit this value to change the buffer size to the desired value
    443  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    444  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    452  unsigned char m_iobuf[2048];
    453  // store the index of where we are writing in the buffer
    454  // so we can send our records all at once to prevent
    455  // weird timing issues
    456  size_t m_write_idx;
    457 };
    458 
    459 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:251
    Definition: SSLClient.h:58
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:51
    void setTimeout(unsigned int t)
    Set the timeout when waiting for an SSL response.
    Definition: SSLClient.h:365
    Definition: SSLClient.h:48
    Definition: SSLClient.h:75
    Definition: SSLClient.h:54
    -
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:60
    -
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:223
    -
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:287
    +
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:55
    +
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:218
    +
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:282
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    -
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:311
    -
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:175
    +
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:306
    +
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:170
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    Definition: SSLClient.h:73
    -
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:229
    +
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:224
    Definition: SSLClient.h:71
    -
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:87
    -
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:132
    +
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:82
    +
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:127
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:258
    Error
    Static constants defining the possible errors encountered.
    Definition: SSLClient.h:45
    Definition: SSLClient.h:52
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClient.h:67
    size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:349
    -
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:211
    +
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:206
    Definition: SSLClient.h:50
    size_t write(uint8_t b) override
    Definition: SSLClient.h:210
    Client & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:359
    -
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:300
    +
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:295
    unsigned int getTimeout() const
    Get the timeout when waiting for an SSL response.
    Definition: SSLClient.h:371
    Definition: SSLClient.h:69
    diff --git a/docs/html/_s_s_l_client_parameters_8h.html b/docs/html/_s_s_l_client_parameters_8h.html index dcf4562..5a55ac2 100644 --- a/docs/html/_s_s_l_client_parameters_8h.html +++ b/docs/html/_s_s_l_client_parameters_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_client_parameters_8h_source.html b/docs/html/_s_s_l_client_parameters_8h_source.html index 7782ab4..af183a5 100644 --- a/docs/html/_s_s_l_client_parameters_8h_source.html +++ b/docs/html/_s_s_l_client_parameters_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8cpp.html b/docs/html/_s_s_l_obj_8cpp.html index dd949ae..c8534c5 100644 --- a/docs/html/_s_s_l_obj_8cpp.html +++ b/docs/html/_s_s_l_obj_8cpp.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h.html b/docs/html/_s_s_l_obj_8h.html index 7a3fa88..a6251c2 100644 --- a/docs/html/_s_s_l_obj_8h.html +++ b/docs/html/_s_s_l_obj_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_obj_8h_source.html b/docs/html/_s_s_l_obj_8h_source.html index 5224fe6..91e6b8c 100644 --- a/docs/html/_s_s_l_obj_8h_source.html +++ b/docs/html/_s_s_l_obj_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h.html b/docs/html/_s_s_l_session_8h.html index 4017c51..74704ae 100644 --- a/docs/html/_s_s_l_session_8h.html +++ b/docs/html/_s_s_l_session_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_s_s_l_session_8h_source.html b/docs/html/_s_s_l_session_8h_source.html index f86c947..f0f131f 100644 --- a/docs/html/_s_s_l_session_8h_source.html +++ b/docs/html/_s_s_l_session_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_t_l_s12__only__profile_8c.html b/docs/html/_t_l_s12__only__profile_8c.html index 74153aa..b3dbb37 100644 --- a/docs/html/_t_l_s12__only__profile_8c.html +++ b/docs/html/_t_l_s12__only__profile_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/_trust_anchors_8md.html b/docs/html/_trust_anchors_8md.html index da6e691..4b062a2 100644 --- a/docs/html/_trust_anchors_8md.html +++ b/docs/html/_trust_anchors_8md.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 018732e..a3d9322 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h.html b/docs/html/cert_8h.html index ced538b..08da610 100644 --- a/docs/html/cert_8h.html +++ b/docs/html/cert_8h.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/cert_8h_source.html b/docs/html/cert_8h_source.html index de6ff00..42ec87d 100644 --- a/docs/html/cert_8h_source.html +++ b/docs/html/cert_8h_source.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client-members.html b/docs/html/class_s_s_l_client-members.html index 136231e..e5da38e 100644 --- a/docs/html/class_s_s_l_client-members.html +++ b/docs/html/class_s_s_l_client-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_client.html b/docs/html/class_s_s_l_client.html index 0a9e1da..079f3f6 100644 --- a/docs/html/class_s_s_l_client.html +++ b/docs/html/class_s_s_l_client.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session-members.html b/docs/html/class_s_s_l_session-members.html index d035c58..ec7afaa 100644 --- a/docs/html/class_s_s_l_session-members.html +++ b/docs/html/class_s_s_l_session-members.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/class_s_s_l_session.html b/docs/html/class_s_s_l_session.html index 1a1574a..57c9ffb 100644 --- a/docs/html/class_s_s_l_session.html +++ b/docs/html/class_s_s_l_session.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/classes.html b/docs/html/classes.html index 59bf48a..18a590c 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html index c9720d1..9b24b34 100644 --- a/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html +++ b/docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 24f9953..f375e51 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js index a47c04c..55154a2 100644 --- a/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js +++ b/docs/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js @@ -1,7 +1,7 @@ var dir_68267d1309a1af8e8297ef4c3efbcdba = [ [ "ec_prime_fast_256.c", "ec__prime__fast__256_8c.html", "ec__prime__fast__256_8c" ], - [ "SSLClient.cpp", "_s_s_l_client_8cpp.html", "_s_s_l_client_8cpp" ], + [ "SSLClient.cpp", "_s_s_l_client_8cpp.html", null ], [ "SSLClient.h", "_s_s_l_client_8h.html", [ [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ] ] ], diff --git a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html index 6c302ee..3cb8b1e 100644 --- a/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html +++ b/docs/html/dir_9c42dc81377249a918256dbb9cfb2167.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html index b81fe87..38f25f1 100644 --- a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html index d5742ed..29b244d 100644 --- a/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html +++ b/docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/ec__prime__fast__256_8c.html b/docs/html/ec__prime__fast__256_8c.html index a3cc4e7..8767b85 100644 --- a/docs/html/ec__prime__fast__256_8c.html +++ b/docs/html/ec__prime__fast__256_8c.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/files.html b/docs/html/files.html index f7dae12..2058c75 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions.html b/docs/html/functions.html index 8ecc386..665c985 100644 --- a/docs/html/functions.html +++ b/docs/html/functions.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_enum.html b/docs/html/functions_enum.html index 20b6fd0..f10ee4c 100644 --- a/docs/html/functions_enum.html +++ b/docs/html/functions_enum.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_eval.html b/docs/html/functions_eval.html index 8bd2041..3ebca65 100644 --- a/docs/html/functions_eval.html +++ b/docs/html/functions_eval.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html index d2ff505..4cd56f5 100644 --- a/docs/html/functions_func.html +++ b/docs/html/functions_func.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/functions_vars.html b/docs/html/functions_vars.html index f6b963a..77e1787 100644 --- a/docs/html/functions_vars.html +++ b/docs/html/functions_vars.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/globals.html b/docs/html/globals.html index 0ed24c6..4dd9ecb 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -30,7 +30,7 @@
    SSLClient -  v1.4.6 +  v1.4.7
    Add TLS 1.2 functionality to any network library.
    @@ -88,9 +88,6 @@ $(document).ready(function(){initNavTree('globals.html','');});
    Here is a list of all file members with links to the files they belong to:
      -
    • __brkval -: SSLClient.cpp -
    • __TIME_DAYS__ : time_macros.h
    • diff --git a/docs/html/globals_defs.html b/docs/html/globals_defs.html index 303137a..6e00765 100644 --- a/docs/html/globals_defs.html +++ b/docs/html/globals_defs.html @@ -30,7 +30,7 @@
      SSLClient -  v1.4.6 +  v1.4.7
      Add TLS 1.2 functionality to any network library.
      diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index 3631b47..c559d52 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -30,7 +30,7 @@
      SSLClient -  v1.4.6 +  v1.4.7
      Add TLS 1.2 functionality to any network library.
      diff --git a/docs/html/globals_vars.html b/docs/html/globals_vars.html index 272494e..9cbe008 100644 --- a/docs/html/globals_vars.html +++ b/docs/html/globals_vars.html @@ -30,7 +30,7 @@
      SSLClient -  v1.4.6 +  v1.4.7
      Add TLS 1.2 functionality to any network library.
      @@ -88,9 +88,6 @@ $(document).ready(function(){initNavTree('globals_vars.html','');});
       
        -
      • __brkval -: SSLClient.cpp -
      • br_ec_prime_fast_256 : ec_prime_fast_256.c
      • diff --git a/docs/html/hierarchy.html b/docs/html/hierarchy.html index 20f90ea..b123abe 100644 --- a/docs/html/hierarchy.html +++ b/docs/html/hierarchy.html @@ -30,7 +30,7 @@
        SSLClient -  v1.4.6 +  v1.4.7
        Add TLS 1.2 functionality to any network library.
        diff --git a/docs/html/index.html b/docs/html/index.html index 9b90264..9e50380 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -30,7 +30,7 @@
        SSLClient -  v1.4.6 +  v1.4.7
        Add TLS 1.2 functionality to any network library.
        @@ -96,6 +96,7 @@ $(document).ready(function(){initNavTree('index.html','');});

        SSLClient requires at least 110kb flash and 7kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.

        You can also view this README in doxygen.

        SSLClient is a simple library to add TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it.

        +

        SSLClient has been tested on the SAMD21, ESP32, and STM32 (in progress). SSClient does not currently support the ESP8266 (see this issue).

        Overview

        Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with EthernetClient. There are a few extra things, however, that you will need to get started:

          diff --git a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index cf764ef..36fb4df 100644 --- a/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/html/namespace_s_s_l_obj.html index ecb8ff8..5d3af7a 100644 --- a/docs/html/namespace_s_s_l_obj.html +++ b/docs/html/namespace_s_s_l_obj.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespacemembers.html b/docs/html/namespacemembers.html index ce98c51..53d7762 100644 --- a/docs/html/namespacemembers.html +++ b/docs/html/namespacemembers.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespacemembers_func.html b/docs/html/namespacemembers_func.html index f1b956c..46f8a15 100644 --- a/docs/html/namespacemembers_func.html +++ b/docs/html/namespacemembers_func.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/namespaces.html b/docs/html/namespaces.html index 04490c1..edad91b 100644 --- a/docs/html/namespaces.html +++ b/docs/html/namespaces.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index 55158e2..0dde6b3 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -1,7 +1,6 @@ var NAVTREEINDEX0 = { "_s_s_l_client_8cpp.html":[3,0,2,1], -"_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56":[3,0,2,1,0], "_s_s_l_client_8h.html":[3,0,2,2], "_s_s_l_client_8h_source.html":[3,0,2,2], "_s_s_l_client_parameters_8h.html":[3,0,2,3], diff --git a/docs/html/pages.html b/docs/html/pages.html index c0a2370..73a881b 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/search/all_0.js b/docs/html/search/all_0.js index 312f869..7708a75 100644 --- a/docs/html/search/all_0.js +++ b/docs/html/search/all_0.js @@ -1,6 +1,5 @@ var searchData= [ - ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClient.cpp']]], ['_5f_5ftime_5fdays_5f_5f',['__TIME_DAYS__',['../time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf',1,'time_macros.h']]], ['_5f_5ftime_5fhours_5f_5f',['__TIME_HOURS__',['../time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4',1,'time_macros.h']]], ['_5f_5ftime_5fminutes_5f_5f',['__TIME_MINUTES__',['../time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8',1,'time_macros.h']]], diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js index cec0612..a1efc7e 100644 --- a/docs/html/search/searchdata.js +++ b/docs/html/search/searchdata.js @@ -5,7 +5,7 @@ var indexSectionsWithContent = 2: "s", 3: "cerst", 4: "abcfgmoprstw", - 5: "_bceiv", + 5: "bceiv", 6: "de", 7: "s", 8: "_cgpstu", diff --git a/docs/html/search/variables_0.js b/docs/html/search/variables_0.js index 631745b..814f51b 100644 --- a/docs/html/search/variables_0.js +++ b/docs/html/search/variables_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['_5f_5fbrkval',['__brkval',['../_s_s_l_client_8cpp.html#ad193a2cc121e0d4614a1c21eb463fb56',1,'SSLClient.cpp']]] + ['br_5fec_5fprime_5ffast_5f256',['br_ec_prime_fast_256',['../ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab',1,'ec_prime_fast_256.c']]] ]; diff --git a/docs/html/search/variables_1.js b/docs/html/search/variables_1.js index 814f51b..faff15d 100644 --- a/docs/html/search/variables_1.js +++ b/docs/html/search/variables_1.js @@ -1,4 +1,5 @@ var searchData= [ - ['br_5fec_5fprime_5ffast_5f256',['br_ec_prime_fast_256',['../ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab',1,'ec_prime_fast_256.c']]] + ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], + ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]] ]; diff --git a/docs/html/search/variables_2.js b/docs/html/search/variables_2.js index faff15d..eb3b769 100644 --- a/docs/html/search/variables_2.js +++ b/docs/html/search/variables_2.js @@ -1,5 +1,4 @@ var searchData= [ - ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], - ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]] + ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]] ]; diff --git a/docs/html/search/variables_3.js b/docs/html/search/variables_3.js index eb3b769..2d07945 100644 --- a/docs/html/search/variables_3.js +++ b/docs/html/search/variables_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]] + ['index',['index',['../structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/html/search/variables_4.js b/docs/html/search/variables_4.js index 2d07945..a18bd2a 100644 --- a/docs/html/search/variables_4.js +++ b/docs/html/search/variables_4.js @@ -1,4 +1,4 @@ var searchData= [ - ['index',['index',['../structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3',1,'ssl_pem_decode_state']]] + ['vect',['vect',['../structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/html/struct_s_s_l_client_parameters-members.html index 17b2d29..b326fb4 100644 --- a/docs/html/struct_s_s_l_client_parameters-members.html +++ b/docs/html/struct_s_s_l_client_parameters-members.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/html/struct_s_s_l_client_parameters.html index 378f2f4..c889f7c 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/html/struct_s_s_l_client_parameters.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/html/structssl__pem__decode__state-members.html index aa97d7a..de3d26c 100644 --- a/docs/html/structssl__pem__decode__state-members.html +++ b/docs/html/structssl__pem__decode__state-members.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/structssl__pem__decode__state.html b/docs/html/structssl__pem__decode__state.html index d83b13e..df3c8e2 100644 --- a/docs/html/structssl__pem__decode__state.html +++ b/docs/html/structssl__pem__decode__state.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/time__macros_8h.html b/docs/html/time__macros_8h.html index e83dae8..7709738 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/html/time__macros_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/time__macros_8h_source.html b/docs/html/time__macros_8h_source.html index 3438408..aca40e9 100644 --- a/docs/html/time__macros_8h_source.html +++ b/docs/html/time__macros_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trust__anchors_8h.html b/docs/html/trust__anchors_8h.html index 051c11e..421a2de 100644 --- a/docs/html/trust__anchors_8h.html +++ b/docs/html/trust__anchors_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trust__anchors_8h_source.html b/docs/html/trust__anchors_8h_source.html index 2d6add6..fb9291f 100644 --- a/docs/html/trust__anchors_8h_source.html +++ b/docs/html/trust__anchors_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trustanchors_8h.html b/docs/html/trustanchors_8h.html index 0602f16..63a48c3 100644 --- a/docs/html/trustanchors_8h.html +++ b/docs/html/trustanchors_8h.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/docs/html/trustanchors_8h_source.html b/docs/html/trustanchors_8h_source.html index c5088dd..b4cd9a0 100644 --- a/docs/html/trustanchors_8h_source.html +++ b/docs/html/trustanchors_8h_source.html @@ -30,7 +30,7 @@
          SSLClient -  v1.4.6 +  v1.4.7
          Add TLS 1.2 functionality to any network library.
          diff --git a/library.properties b/library.properties index bc8cd08..e345065 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.4.6 +version=1.4.7 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 0b09baa..1d62fea 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -30,13 +30,10 @@ static constexpr auto VECTKEY_MASK = (0x0000ffffUL); (*(uint32_t*)0xe000ed0cUL)=((*(uint32_t*)0xe000ed0cUL)&VECTKEY_MASK)|VECTKEY|SYSRESETREQ; while(1) { } } -#endif #ifdef __arm__ // should use uinstd.h to define sbrk but Due causes a conflict extern "C" char* sbrk(int incr); -#elif defined(ESP8266) // esp8266 -#define SYSTEM_STACK_END_ADDRESS 0x3FFFC000 #else // __ARM__ extern char *__brkval; #endif // __arm__ @@ -46,15 +43,13 @@ static int freeMemory() { char top; #ifdef __arm__ return &top - reinterpret_cast(sbrk(0)); -#elif defined(ESP8266) // ESP8266 - register volatile uint32_t stackAddress asm("a1"); - return stackAddress-SYSTEM_STACK_END_ADDRESS; #elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) return &top - __brkval; #else // __arm__ return __brkval ? &top - __brkval : &top - __malloc_heap_start; #endif // __arm__ } +#endif // ARDUINO_ARCH_SAMD /* see SSLClient.h */ SSLClient::SSLClient( Client& client, @@ -565,8 +560,8 @@ unsigned SSLClient::m_update_engine() { // do we have the record you're looking for? const auto avail = get_arduino_client().available(); if (avail > 0) { - int mem = freeMemory(); #if defined(ARDUINO_ARCH_SAMD) + int mem = freeMemory(); // check for a stack overflow // if the stack overflows we basically have to crash, and // hope the user is ok with that @@ -576,7 +571,6 @@ unsigned SSLClient::m_update_engine() { // software reset RESET(); } -#endif // debug info m_info("Memory: ", func_name); m_info(mem, func_name); @@ -590,6 +584,7 @@ unsigned SSLClient::m_update_engine() { stop(); return 0; } +#endif // I suppose so! int rlen = get_arduino_client().read(buf, avail < len ? avail : len); if (rlen <= 0) { From c045607b39219fe3b71d1cc80a2bd85b2af5666d Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Fri, 10 Jan 2020 17:04:37 -0800 Subject: [PATCH 100/205] Clarification edits for trust anchor generation --- TrustAnchors.md | 6 +++--- tools/pycert_bearssl/pycert_bearssl.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/TrustAnchors.md b/TrustAnchors.md index 05cfa30..f9b7eb6 100644 --- a/TrustAnchors.md +++ b/TrustAnchors.md @@ -43,11 +43,11 @@ A full example of a trust anchor header can be found in [this file](./readme/cer For HTTPS, there a couple of tools you can use. Ordered from easiest to hardest: * [This website, written to simplify the creation of trust anchor headers](https://openslab-osu.github.io/bearssl-certificate-utility/). Simply plug and play. * [pycert_bearssl](./tools/pycert_bearssl/pycert_bearssl.py), a command line utility based on a [pycert](https://learn.adafruit.com/introducing-the-adafruit-wiced-feather-wifi/pycert-dot-py). You will need to install Python 3, and follow the instructions in the [pycert_bearssl.py file](./tools/pycert_bearssl/pycert_bearssl.py). You'll want to use the `pycert_bearssl.py download` command once the utility is set up. -* The brssl command line utility, included in the [BearSSL source](https://bearssl.org/gitweb/?p=BearSSL;a=blob_plain;f=tools/brssl.h;hb=HEAD). You will need to compile this file yourself. +* The `brssl` command line utility, included in the [BearSSL source](https://bearssl.org/gitweb/?p=BearSSL;a=blob_plain;f=tools/brssl.h;hb=HEAD). You will need to compile this file yourself. ### Other Connections -For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out [this StackExchange post](https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file) for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use [this website](https://www.sslshopper.com/ssl-converter.html)), and use the `pycert_bearssl.py convert` command to convert the certificate into a trust anchor header. +For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out [this StackExchange post](https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file) for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use [this website](https://www.sslshopper.com/ssl-converter.html)), and use the `pycert_bearssl.py convet --no-search` command to convert the certificate into a trust anchor header. ## Using Trust Anchors @@ -55,7 +55,7 @@ Once you've generated a trust anchor array, add it to your Arduino sketch using ```C++ #include "yourtrustanchorfile.h" // ... -SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin); +SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin); // ... ``` Where `yourtrustanchorfile.h` contains a generated trust anchor array names `TAs`, with length `TAs_NUM`. BearSSL will now automatically use these trust anchors when `SSLClient::connect` is called. \ No newline at end of file diff --git a/tools/pycert_bearssl/pycert_bearssl.py b/tools/pycert_bearssl/pycert_bearssl.py index 392838e..475c59c 100644 --- a/tools/pycert_bearssl/pycert_bearssl.py +++ b/tools/pycert_bearssl/pycert_bearssl.py @@ -69,7 +69,7 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom Note that the certificates will be validated before they are downloaded! """ # if array is emptey, exit - if len(domain) is 0: + if len(domain) == 0: return # prepare the root certificate store cert_obj_store = cert_util.parse_root_certificate_store(use_store) @@ -100,8 +100,8 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom help='the location of the .pem file containing a list of trusted root certificates (default: use certifi.where())') @click.option('--keep-dupes', '-d', is_flag=True, default=False, help='write all certs including any duplicates (default: remove duplicates)') -@click.option('--no-verify', '-n', is_flag=True, default=False, - help='Do not attempt to match a root certificate to the provided PEM files') +@click.option('--no-search', '-n', is_flag=True, default=False, + help='Do not attempt to search for a root certificate to the provided PEM files, instead treat the PEM files as the root certificates') @click.argument('cert', type=click.File('r'), nargs=-1) def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_verify, cert): """Convert PEM certificates into a C header that can be imported into a @@ -117,7 +117,7 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_verify, pycert convert foo.pem bar.pem """ # if array is emptey, exit - if len(cert) is 0: + if len(cert) == 0: return # prepare root certificate store cert_obj_store = cert_util.parse_root_certificate_store(use_store) From c8030dfe4e7436a9694cece3c1a9f1bc98610e93 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Fri, 10 Jan 2020 17:05:29 -0800 Subject: [PATCH 101/205] remove old template reference in trustanchors guide --- TrustAnchors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustAnchors.md b/TrustAnchors.md index f9b7eb6..539b696 100644 --- a/TrustAnchors.md +++ b/TrustAnchors.md @@ -55,7 +55,7 @@ Once you've generated a trust anchor array, add it to your Arduino sketch using ```C++ #include "yourtrustanchorfile.h" // ... -SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin); +SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin); // ... ``` Where `yourtrustanchorfile.h` contains a generated trust anchor array names `TAs`, with length `TAs_NUM`. BearSSL will now automatically use these trust anchors when `SSLClient::connect` is called. \ No newline at end of file From 32eec1d4294826cfa2a70a1cc7ebf40bf67ec205 Mon Sep 17 00:00:00 2001 From: Alberto Panu Date: Fri, 7 Feb 2020 00:50:32 +0100 Subject: [PATCH 102/205] Tested the library with TI Tiva C TM4C1294 I have tested the lib on EK-TM4C1294XL Tiva C evaluation board and it works. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 027f60f..1576632 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ You can also view this README in [doxygen](https://openslab-osu.github.io/SSLCli SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. -SSLClient has been tested on the SAMD21, ESP32, and STM32 (in progress). SSClient does not currently support the ESP8266 (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)). +SSLClient has been tested on the SAMD21, ESP32, TIVA C, and STM32 (in progress). SSClient does not currently support the ESP8266 (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)). ## Overview From eeeb385e33b0d20096a9728cad37e9ba1a4f0145 Mon Sep 17 00:00:00 2001 From: Alberto Panu Date: Fri, 7 Feb 2020 01:08:21 +0100 Subject: [PATCH 103/205] Added tivac architecture --- .travis/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis/library.properties b/.travis/library.properties index 3bc0cad..a69a9fe 100644 --- a/.travis/library.properties +++ b/.travis/library.properties @@ -6,7 +6,7 @@ sentence=Arduino library to add SSL functionality to any Client class paragraph=including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. category=Communication url=https://github.com/OPEnSLab-OSU/SSLClient -architectures=samd +architectures=samd,tivac includes=SSLClient.h precompiled=true -ldflags=-lSSLClient \ No newline at end of file +ldflags=-lSSLClient From 8b554f21451f961e79f3e2ebd2b2bb48e9d0d03f Mon Sep 17 00:00:00 2001 From: Alberto Panu Date: Fri, 7 Feb 2020 01:09:08 +0100 Subject: [PATCH 104/205] Added tivac architecture --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index e345065..abaccf9 100644 --- a/library.properties +++ b/library.properties @@ -6,6 +6,6 @@ sentence=Arduino library to add SSL functionality to any Client class paragraph=including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. category=Communication url=https://github.com/OPEnSLab-OSU/SSLClient -architectures=samd +architectures=samd,tivac includes=SSLClient.h -dot_a_linkage=true \ No newline at end of file +dot_a_linkage=true From 65eb61d27c9cda8b90f430b4301ca99c8fb23628 Mon Sep 17 00:00:00 2001 From: Alberto Panu Date: Fri, 7 Feb 2020 01:15:34 +0100 Subject: [PATCH 105/205] Added sample for Texas Instruments Tiva C TM4C1294 Tested on EK-TM4C1294XL board with Energia 1.8.11E23 --- .../EthernetHTTPStivac/EthernetHTTPStivac.ino | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 examples/EthernetHTTPStivac/EthernetHTTPStivac.ino diff --git a/examples/EthernetHTTPStivac/EthernetHTTPStivac.ino b/examples/EthernetHTTPStivac/EthernetHTTPStivac.ino new file mode 100644 index 0000000..b1f52da --- /dev/null +++ b/examples/EthernetHTTPStivac/EthernetHTTPStivac.ino @@ -0,0 +1,161 @@ +/* + Web client + + This sketch connects to a website (http://www.arduino.cc/asciilogo.txt) + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Noah Koontz, based on work by Adrian McEwen and Tom Igoe + + */ + + // NOTE: This example REQUIRES the EthernetLarge library. + // You can get it here: https://github.com/OPEnSLab-OSU/EthernetLarge + +#include +//#include +#include "Ethernet.h" +#include +#include "trust_anchors.h" + +#define BUFFLEN 80 + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +// byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +// With Tiva C the mac address could be changed with LM Flash Programmer + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(54,85,55,79); // numeric IP for Google (no DNS) +const char server[] = "www.arduino.cc"; // name address for Arduino (using DNS) +const char server_host[] = "www.arduino.cc"; // leave this alone, change only above two + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192,168,2,177); +IPAddress myDns(8, 8, 8, 8); +IPAddress gw = IPAddress(192,168,2,1); +IPAddress mask = IPAddress(255,255,255,0); + +// Choose the analog pin to get semi-random data from for SSL +// Pick a pin that's not connected or attached to a randomish voltage source +const int rand_pin = A5; + +// Initialize the SSL client library +// We input an EthernetClient, our trust anchors, and the analog pin +EthernetClient base_client; +SSLClient client(base_client, TAs, (size_t)TAs_NUM, rand_pin); +// Variables to measure the speed +unsigned long beginMicros, endMicros; +unsigned long byteCount = 0; +bool printWebData = true; // set to false for better speed measurement + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + //Ethernet.init(10); // Most Arduino shields + //Ethernet.init(5); // MKR ETH shield + //Ethernet.init(0); // Teensy 2.0 + //Ethernet.init(20); // Teensy++ 2.0 + //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet connection: + Serial.println(F("Initialize Ethernet with DHCP:")); + //if (Ethernet.begin(mac) == 0) { + if (Ethernet.begin(0) == 0) { + Serial.println(F("Failed to configure Ethernet using DHCP")); + // Check for Ethernet hardware present +/* if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + }*/ +/* if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + }*/ + // try to configure using IP address instead of DHCP: + //Ethernet.begin(mac, ip, myDns); + Ethernet.begin(0, ip, myDns, gw, mask); + } else { + Serial.print(F(" DHCP assigned IP ")); + Serial.println(Ethernet.localIP()); + } + // give the Ethernet shield a second to initialize: + delay(2000); + + Serial.print(F("connecting to ")); + Serial.print(server); + Serial.println(F("...")); + + // if you get a connection, report back via serial: + auto start = millis(); + // specify the server and port, 443 is the standard port for HTTPS + if (client.connect(server, 443)) { + auto time = millis() - start; + Serial.print(F("Took: ")); + Serial.println(time); + // Make a HTTP request: + client.println(F("GET /asciilogo.txt HTTP/1.1")); + client.println(F("User-Agent: SSLClientOverEthernet")); + client.print(F("Host: ")); + client.println(server_host); + client.println(F("Connection: close")); + client.println(); + } else { + // if you didn't get a connection to the server: + Serial.println(F("connection failed")); + } + beginMicros = micros(); +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + int len = client.available(); + while (len > 0) { + //if (len > 0) { + byte buffer[BUFFLEN]; + if (len > BUFFLEN) len = BUFFLEN; + client.read(buffer, len); + if (printWebData) { + Serial.write(buffer, len); // show in the serial monitor (slows some boards) + } + byteCount = byteCount + len; + len = client.available(); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + endMicros = micros(); + Serial.println(); + Serial.println(F("disconnecting.")); + client.stop(); + Serial.print(F("Received ")); + Serial.print(byteCount); + Serial.print(F(" bytes in ")); + float seconds = (float)(endMicros - beginMicros) / 1000000.0; + Serial.print(seconds, 4); + float rate = (float)byteCount / seconds / 1000.0; + Serial.print(F(", rate = ")); + Serial.print(rate); + Serial.print(F(" kbytes/second")); + Serial.println(); + + // do nothing forevermore: + while (true) { + delay(1); + } + } +} From 39e5211178cdf20717e20a66363b95038e7a055f Mon Sep 17 00:00:00 2001 From: Alberto Panu Date: Fri, 7 Feb 2020 01:16:08 +0100 Subject: [PATCH 106/205] Create trust_anchors.h --- examples/EthernetHTTPStivac/trust_anchors.h | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 examples/EthernetHTTPStivac/trust_anchors.h diff --git a/examples/EthernetHTTPStivac/trust_anchors.h b/examples/EthernetHTTPStivac/trust_anchors.h new file mode 100644 index 0000000..c456e9b --- /dev/null +++ b/examples/EthernetHTTPStivac/trust_anchors.h @@ -0,0 +1,80 @@ +#ifndef _CERTIFICATES_H_ +#define _CERTIFICATES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. + * Certificates are BearSSL br_x509_trust_anchor format. Included certs: + * + * Index: 0 + * Label: AddTrust External CA Root + * Subject: C=SE,O=AddTrust AB,OU=AddTrust External TTP Network,CN=AddTrust External CA Root + * Domain(s): www.arduino.cc + */ + +#define TAs_NUM 1 + +static const unsigned char TA_DN0[] = { + 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, + 0x42, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, + 0x20, 0x52, 0x6f, 0x6f, 0x74, +}; + +static const unsigned char TA_RSA_N0[] = { + 0xb7, 0xf7, 0x1a, 0x33, 0xe6, 0xf2, 0x00, 0x04, 0x2d, 0x39, 0xe0, 0x4e, + 0x5b, 0xed, 0x1f, 0xbc, 0x6c, 0x0f, 0xcd, 0xb5, 0xfa, 0x23, 0xb6, 0xce, + 0xde, 0x9b, 0x11, 0x33, 0x97, 0xa4, 0x29, 0x4c, 0x7d, 0x93, 0x9f, 0xbd, + 0x4a, 0xbc, 0x93, 0xed, 0x03, 0x1a, 0xe3, 0x8f, 0xcf, 0xe5, 0x6d, 0x50, + 0x5a, 0xd6, 0x97, 0x29, 0x94, 0x5a, 0x80, 0xb0, 0x49, 0x7a, 0xdb, 0x2e, + 0x95, 0xfd, 0xb8, 0xca, 0xbf, 0x37, 0x38, 0x2d, 0x1e, 0x3e, 0x91, 0x41, + 0xad, 0x70, 0x56, 0xc7, 0xf0, 0x4f, 0x3f, 0xe8, 0x32, 0x9e, 0x74, 0xca, + 0xc8, 0x90, 0x54, 0xe9, 0xc6, 0x5f, 0x0f, 0x78, 0x9d, 0x9a, 0x40, 0x3c, + 0x0e, 0xac, 0x61, 0xaa, 0x5e, 0x14, 0x8f, 0x9e, 0x87, 0xa1, 0x6a, 0x50, + 0xdc, 0xd7, 0x9a, 0x4e, 0xaf, 0x05, 0xb3, 0xa6, 0x71, 0x94, 0x9c, 0x71, + 0xb3, 0x50, 0x60, 0x0a, 0xc7, 0x13, 0x9d, 0x38, 0x07, 0x86, 0x02, 0xa8, + 0xe9, 0xa8, 0x69, 0x26, 0x18, 0x90, 0xab, 0x4c, 0xb0, 0x4f, 0x23, 0xab, + 0x3a, 0x4f, 0x84, 0xd8, 0xdf, 0xce, 0x9f, 0xe1, 0x69, 0x6f, 0xbb, 0xd7, + 0x42, 0xd7, 0x6b, 0x44, 0xe4, 0xc7, 0xad, 0xee, 0x6d, 0x41, 0x5f, 0x72, + 0x5a, 0x71, 0x08, 0x37, 0xb3, 0x79, 0x65, 0xa4, 0x59, 0xa0, 0x94, 0x37, + 0xf7, 0x00, 0x2f, 0x0d, 0xc2, 0x92, 0x72, 0xda, 0xd0, 0x38, 0x72, 0xdb, + 0x14, 0xa8, 0x45, 0xc4, 0x5d, 0x2a, 0x7d, 0xb7, 0xb4, 0xd6, 0xc4, 0xee, + 0xac, 0xcd, 0x13, 0x44, 0xb7, 0xc9, 0x2b, 0xdd, 0x43, 0x00, 0x25, 0xfa, + 0x61, 0xb9, 0x69, 0x6a, 0x58, 0x23, 0x11, 0xb7, 0xa7, 0x33, 0x8f, 0x56, + 0x75, 0x59, 0xf5, 0xcd, 0x29, 0xd7, 0x46, 0xb7, 0x0a, 0x2b, 0x65, 0xb6, + 0xd3, 0x42, 0x6f, 0x15, 0xb2, 0xb8, 0x7b, 0xfb, 0xef, 0xe9, 0x5d, 0x53, + 0xd5, 0x34, 0x5a, 0x27, +}; + +static const unsigned char TA_RSA_E0[] = { + 0x01, 0x00, 0x01, +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef _CERTIFICATES_H_ */ From 089f842558678e03edb2a549ae92f2a2864ecd8b Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Fri, 7 Feb 2020 12:30:46 -0800 Subject: [PATCH 107/205] Upgrade bearssl to acc70b1be60a6f321e2da618cd35d901b1a598a4 --- src/SSLClient.cpp | 11 +- src/bearssl/src/ec/ec_all_m31.c | 50 + src/bearssl/src/ec/ec_c25519_i15.c | 12 +- src/bearssl/src/ec/ec_c25519_i31.c | 17 +- src/bearssl/src/ec/ec_c25519_m15.c | 12 +- src/bearssl/src/ec/ec_c25519_m31.c | 105 +- src/bearssl/src/ec/ec_c25519_m62.c | 605 +++++++ src/bearssl/src/ec/ec_c25519_m64.c | 831 +++++++++ src/bearssl/src/ec/ec_p256_m15.c | 2 +- src/bearssl/src/ec/ec_p256_m31.c | 2 +- src/bearssl/src/ec/ec_p256_m62.c | 1765 ++++++++++++++++++++ src/bearssl/src/ec/ec_p256_m64.c | 1730 +++++++++++++++++++ src/bearssl/src/int/i31_montmul.c | 44 +- src/bearssl/src/int/i31_mulacc.c | 13 + src/bearssl/src/int/i32_mulacc.c | 4 + src/bearssl/src/kdf/shake.c | 590 +++++++ src/bearssl/src/rand/sysrng.c | 91 +- src/bearssl/src/rsa/rsa_default_pss_sign.c | 38 + src/bearssl/src/rsa/rsa_default_pss_vrfy.c | 38 + src/bearssl/src/rsa/rsa_i15_keygen.c | 6 +- src/bearssl/src/rsa/rsa_i15_modulus.c | 2 +- src/bearssl/src/rsa/rsa_i15_pss_sign.c | 40 + src/bearssl/src/rsa/rsa_i15_pss_vrfy.c | 44 + src/bearssl/src/rsa/rsa_i31_keygen_inner.c | 6 +- src/bearssl/src/rsa/rsa_i31_modulus.c | 2 +- src/bearssl/src/rsa/rsa_i31_pss_sign.c | 40 + src/bearssl/src/rsa/rsa_i31_pss_vrfy.c | 44 + src/bearssl/src/rsa/rsa_i32_pss_sign.c | 40 + src/bearssl/src/rsa/rsa_i32_pss_vrfy.c | 44 + src/bearssl/src/rsa/rsa_i62_pss_sign.c | 60 + src/bearssl/src/rsa/rsa_i62_pss_vrfy.c | 64 + src/bearssl/src/rsa/rsa_pss_sig_pad.c | 106 ++ src/bearssl/src/rsa/rsa_pss_sig_unpad.c | 121 ++ src/bearssl/src/ssl/ssl_client_full.c | 1 - src/bearssl/src/ssl/ssl_engine.c | 15 + src/bearssl/src/ssl/ssl_io.c | 12 +- src/bearssl/src/x509/asn1.t0 | 2 +- src/bearssl/src/x509/skey_decoder.c | 2 +- src/bearssl/src/x509/skey_decoder.t0 | 2 +- src/bearssl/src/x509/x509_minimal.c | 2 +- src/bearssl/src/x509/x509_minimal.t0 | 2 +- src/bearssl_ec.h | 86 +- src/bearssl_hash.h | 4 +- src/bearssl_kdf.h | 99 ++ src/bearssl_rsa.h | 313 +++- src/bearssl_ssl.h | 22 +- src/config.h | 29 +- src/inner.h | 53 +- 48 files changed, 7091 insertions(+), 132 deletions(-) create mode 100644 src/bearssl/src/ec/ec_c25519_m62.c create mode 100644 src/bearssl/src/ec/ec_c25519_m64.c create mode 100644 src/bearssl/src/ec/ec_p256_m62.c create mode 100644 src/bearssl/src/ec/ec_p256_m64.c create mode 100644 src/bearssl/src/kdf/shake.c create mode 100644 src/bearssl/src/rsa/rsa_default_pss_sign.c create mode 100644 src/bearssl/src/rsa/rsa_default_pss_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i15_pss_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i15_pss_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i31_pss_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i31_pss_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i32_pss_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i32_pss_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_i62_pss_sign.c create mode 100644 src/bearssl/src/rsa/rsa_i62_pss_vrfy.c create mode 100644 src/bearssl/src/rsa/rsa_pss_sig_pad.c create mode 100644 src/bearssl/src/rsa/rsa_pss_sig_unpad.c diff --git a/src/SSLClient.cpp b/src/SSLClient.cpp index 1d62fea..d1314be 100644 --- a/src/SSLClient.cpp +++ b/src/SSLClient.cpp @@ -392,6 +392,13 @@ int SSLClient::m_run_until(const unsigned target) { unsigned state = m_update_engine(); // error check if (state == BR_SSL_CLOSED || getWriteError() != SSL_OK) { + if (state == BR_SSL_CLOSED) { + m_warn("Terminating because the ssl engine closed", func_name); + } + else { + m_warn("Terminating with write error: ", func_name); + m_warn(getWriteError(), func_name); + } return -1; } // timeout check @@ -406,7 +413,7 @@ int SSLClient::m_run_until(const unsigned target) { lastState = state; m_info("m_run changed state:", func_name); if(m_debug == DebugLevel::SSL_INFO) { - m_info("State: ", __func__); + m_info("State: ", func_name); if(state == 0) Serial.println(" Invalid"); else if (state & BR_SSL_CLOSED) Serial.println(" Connection closed"); else { @@ -728,6 +735,6 @@ void SSLClient::m_print_br_error(const unsigned br_error_code, const DebugLevel case BR_ERR_X509_FORBIDDEN_KEY_USAGE: Serial.println("Key Usage extension prohibits intended usage."); break; case BR_ERR_X509_WEAK_PUBLIC_KEY: Serial.println("Public key found in certificate is too small."); break; case BR_ERR_X509_NOT_TRUSTED: Serial.println("Chain could not be linked to a trust anchor."); break; - default: Serial.println("Unknown error code."); break; + default: Serial.print("Unknown error code: "); Serial.println(br_error_code); break; } } diff --git a/src/bearssl/src/ec/ec_all_m31.c b/src/bearssl/src/ec/ec_all_m31.c index 0552c4b..8fd8c3c 100644 --- a/src/bearssl/src/ec/ec_all_m31.c +++ b/src/bearssl/src/ec/ec_all_m31.c @@ -29,9 +29,17 @@ api_generator(int curve, size_t *len) { switch (curve) { case BR_EC_secp256r1: +#if BR_INT128 || BR_UMUL128 + return br_ec_p256_m64.generator(curve, len); +#else return br_ec_p256_m31.generator(curve, len); +#endif case BR_EC_curve25519: +#if BR_INT128 || BR_UMUL128 + return br_ec_c25519_m64.generator(curve, len); +#else return br_ec_c25519_m31.generator(curve, len); +#endif default: return br_ec_prime_i31.generator(curve, len); } @@ -42,9 +50,17 @@ api_order(int curve, size_t *len) { switch (curve) { case BR_EC_secp256r1: +#if BR_INT128 || BR_UMUL128 + return br_ec_p256_m64.order(curve, len); +#else return br_ec_p256_m31.order(curve, len); +#endif case BR_EC_curve25519: +#if BR_INT128 || BR_UMUL128 + return br_ec_c25519_m64.order(curve, len); +#else return br_ec_c25519_m31.order(curve, len); +#endif default: return br_ec_prime_i31.order(curve, len); } @@ -55,9 +71,17 @@ api_xoff(int curve, size_t *len) { switch (curve) { case BR_EC_secp256r1: +#if BR_INT128 || BR_UMUL128 + return br_ec_p256_m64.xoff(curve, len); +#else return br_ec_p256_m31.xoff(curve, len); +#endif case BR_EC_curve25519: +#if BR_INT128 || BR_UMUL128 + return br_ec_c25519_m64.xoff(curve, len); +#else return br_ec_c25519_m31.xoff(curve, len); +#endif default: return br_ec_prime_i31.xoff(curve, len); } @@ -69,9 +93,17 @@ api_mul(unsigned char *G, size_t Glen, { switch (curve) { case BR_EC_secp256r1: +#if BR_INT128 || BR_UMUL128 + return br_ec_p256_m64.mul(G, Glen, kb, kblen, curve); +#else return br_ec_p256_m31.mul(G, Glen, kb, kblen, curve); +#endif case BR_EC_curve25519: +#if BR_INT128 || BR_UMUL128 + return br_ec_c25519_m64.mul(G, Glen, kb, kblen, curve); +#else return br_ec_c25519_m31.mul(G, Glen, kb, kblen, curve); +#endif default: return br_ec_prime_i31.mul(G, Glen, kb, kblen, curve); } @@ -83,9 +115,17 @@ api_mulgen(unsigned char *R, { switch (curve) { case BR_EC_secp256r1: +#if BR_INT128 || BR_UMUL128 + return br_ec_p256_m64.mulgen(R, x, xlen, curve); +#else return br_ec_p256_m31.mulgen(R, x, xlen, curve); +#endif case BR_EC_curve25519: +#if BR_INT128 || BR_UMUL128 + return br_ec_c25519_m64.mulgen(R, x, xlen, curve); +#else return br_ec_c25519_m31.mulgen(R, x, xlen, curve); +#endif default: return br_ec_prime_i31.mulgen(R, x, xlen, curve); } @@ -98,11 +138,21 @@ api_muladd(unsigned char *A, const unsigned char *B, size_t len, { switch (curve) { case BR_EC_secp256r1: +#if BR_INT128 || BR_UMUL128 + return br_ec_p256_m64.muladd(A, B, len, + x, xlen, y, ylen, curve); +#else return br_ec_p256_m31.muladd(A, B, len, x, xlen, y, ylen, curve); +#endif case BR_EC_curve25519: +#if BR_INT128 || BR_UMUL128 + return br_ec_c25519_m64.muladd(A, B, len, + x, xlen, y, ylen, curve); +#else return br_ec_c25519_m31.muladd(A, B, len, x, xlen, y, ylen, curve); +#endif default: return br_ec_prime_i31.muladd(A, B, len, x, xlen, y, ylen, curve); diff --git a/src/bearssl/src/ec/ec_c25519_i15.c b/src/bearssl/src/ec/ec_c25519_i15.c index 361e75f..8fadcf4 100644 --- a/src/bearssl/src/ec/ec_c25519_i15.c +++ b/src/bearssl/src/ec/ec_c25519_i15.c @@ -239,11 +239,11 @@ api_mul(unsigned char *G, size_t Glen, x2[1] = 19; memcpy(z3, x2, ILEN); - memcpy(k, kb, kblen); - memset(k + kblen, 0, (sizeof k) - kblen); - k[0] &= 0xF8; - k[31] &= 0x7F; - k[31] |= 0x40; + memset(k, 0, (sizeof k) - kblen); + memcpy(k + (sizeof k) - kblen, kb, kblen); + k[31] &= 0xF8; + k[0] &= 0x7F; + k[0] |= 0x40; /* obsolete print_int_mont("x1", x1); @@ -253,7 +253,7 @@ api_mul(unsigned char *G, size_t Glen, for (i = 254; i >= 0; i --) { uint32_t kt; - kt = (k[i >> 3] >> (i & 7)) & 1; + kt = (k[31 - (i >> 3)] >> (i & 7)) & 1; swap ^= kt; cswap(x2, x3, swap); cswap(z2, z3, swap); diff --git a/src/bearssl/src/ec/ec_c25519_i31.c b/src/bearssl/src/ec/ec_c25519_i31.c index aa88dd6..f8ffc2c 100644 --- a/src/bearssl/src/ec/ec_c25519_i31.c +++ b/src/bearssl/src/ec/ec_c25519_i31.c @@ -214,7 +214,7 @@ api_mul(unsigned char *G, size_t Glen, * br_i31_decode_reduce(a, G, 32, C255_P); */ br_i31_zero(b, 0x108); - b[9] = 0x0100; + b[9] = 0x0080; br_i31_decode_mod(a, G, 32, b); a[0] = 0x107; br_i31_sub(a, C255_P, NOT(br_i31_sub(a, C255_P, 0))); @@ -230,11 +230,14 @@ api_mul(unsigned char *G, size_t Glen, x2[1] = 0x13000000; memcpy(z3, x2, sizeof x2); - memcpy(k, kb, kblen); - memset(k + kblen, 0, (sizeof k) - kblen); - k[0] &= 0xF8; - k[31] &= 0x7F; - k[31] |= 0x40; + /* + * kb[] is in big-endian notation, but possibly shorter than k[]. + */ + memset(k, 0, (sizeof k) - kblen); + memcpy(k + (sizeof k) - kblen, kb, kblen); + k[31] &= 0xF8; + k[0] &= 0x7F; + k[0] |= 0x40; /* obsolete print_int_mont("x1", x1); @@ -244,7 +247,7 @@ api_mul(unsigned char *G, size_t Glen, for (i = 254; i >= 0; i --) { uint32_t kt; - kt = (k[i >> 3] >> (i & 7)) & 1; + kt = (k[31 - (i >> 3)] >> (i & 7)) & 1; swap ^= kt; cswap(x2, x3, swap); cswap(z2, z3, swap); diff --git a/src/bearssl/src/ec/ec_c25519_m15.c b/src/bearssl/src/ec/ec_c25519_m15.c index 0373197..deff55b 100644 --- a/src/bearssl/src/ec/ec_c25519_m15.c +++ b/src/bearssl/src/ec/ec_c25519_m15.c @@ -1332,11 +1332,11 @@ api_mul(unsigned char *G, size_t Glen, memset(z3, 0, sizeof z3); z3[0] = 1; - memcpy(k, kb, kblen); - memset(k + kblen, 0, (sizeof k) - kblen); - k[0] &= 0xF8; - k[31] &= 0x7F; - k[31] |= 0x40; + memset(k, 0, (sizeof k) - kblen); + memcpy(k + (sizeof k) - kblen, kb, kblen); + k[31] &= 0xF8; + k[0] &= 0x7F; + k[0] |= 0x40; /* obsolete print_int("x1", x1); @@ -1346,7 +1346,7 @@ api_mul(unsigned char *G, size_t Glen, for (i = 254; i >= 0; i --) { uint32_t kt; - kt = (k[i >> 3] >> (i & 7)) & 1; + kt = (k[31 - (i >> 3)] >> (i & 7)) & 1; swap ^= kt; cswap(x2, x3, swap); cswap(z2, z3, swap); diff --git a/src/bearssl/src/ec/ec_c25519_m31.c b/src/bearssl/src/ec/ec_c25519_m31.c index b249634..1dd6d51 100644 --- a/src/bearssl/src/ec/ec_c25519_m31.c +++ b/src/bearssl/src/ec/ec_c25519_m31.c @@ -372,8 +372,7 @@ reduce_final_f255(uint32_t *d) static void f255_mul(uint32_t *d, const uint32_t *a, const uint32_t *b) { - uint32_t t[18]; - uint64_t cc, w; + uint32_t t[18], cc; int i; /* @@ -389,21 +388,42 @@ f255_mul(uint32_t *d, const uint32_t *a, const uint32_t *b) * offset 9*30 = 270, word 9+k must be added to word k with * a factor of 19*2^15 = 622592. The extra bits in word 8 are also * added that way. + * + * Keeping the carry on 32 bits helps with 32-bit architectures, + * and does not noticeably impact performance on 64-bit systems. */ - cc = MUL31(t[8] >> 15, 19); + cc = MUL15(t[8] >> 15, 19); /* at most 19*(2^15-1) = 622573 */ t[8] &= 0x7FFF; for (i = 0; i < 9; i ++) { - w = (uint64_t)t[i] + cc + MUL31(t[i + 9], 622592); + uint64_t w; + + w = (uint64_t)t[i] + (uint64_t)cc + MUL31(t[i + 9], 622592); t[i] = (uint32_t)w & 0x3FFFFFFF; - cc = w >> 30; + cc = (uint32_t)(w >> 30); /* at most 622592 */ } - cc = MUL31(w >> 15, 19); + + /* + * Original product was up to (2^256-1)^2, i.e. a 512-bit integer. + * This was split into two parts (upper of 257 bits, lower of 255 + * bits), and the upper was added to the lower with a factor 19, + * which means that the intermediate value is less than 77*2^255 + * (19*2^257 + 2^255). Therefore, the extra bits "t[8] >> 15" are + * less than 77, and the initial carry cc is at most 76*19 = 1444. + */ + cc = MUL15(t[8] >> 15, 19); t[8] &= 0x7FFF; for (i = 0; i < 9; i ++) { - w = t[i] + cc; - d[i] = (uint32_t)w & 0x3FFFFFFF; - cc = w >> 30; + uint32_t z; + + z = t[i] + cc; + d[i] = z & 0x3FFFFFFF; + cc = z >> 30; } + + /* + * Final result is at most 2^255 + 1443. In particular, the last + * carry is necessarily 0, since t[8] was truncated to 15 bits. + */ } /* @@ -415,8 +435,7 @@ f255_mul(uint32_t *d, const uint32_t *a, const uint32_t *b) static void f255_square(uint32_t *d, const uint32_t *a) { - uint32_t t[18]; - uint64_t cc, w; + uint32_t t[18], cc; int i; /* @@ -428,24 +447,25 @@ f255_square(uint32_t *d, const uint32_t *a) /* * Modular reduction: each high word is added where necessary. - * Since the modulus is 2^255-19 and word 9 corresponds to - * offset 9*30 = 270, word 9+k must be added to word k with - * a factor of 19*2^15 = 622592. The extra bits in word 8 are also - * added that way. + * See f255_mul() for details on the reduction and carry limits. */ - cc = MUL31(t[8] >> 15, 19); + cc = MUL15(t[8] >> 15, 19); t[8] &= 0x7FFF; for (i = 0; i < 9; i ++) { - w = (uint64_t)t[i] + cc + MUL31(t[i + 9], 622592); + uint64_t w; + + w = (uint64_t)t[i] + (uint64_t)cc + MUL31(t[i + 9], 622592); t[i] = (uint32_t)w & 0x3FFFFFFF; - cc = w >> 30; + cc = (uint32_t)(w >> 30); } - cc = MUL31(w >> 15, 19); + cc = MUL15(t[8] >> 15, 19); t[8] &= 0x7FFF; for (i = 0; i < 9; i ++) { - w = t[i] + cc; - d[i] = (uint32_t)w & 0x3FFFFFFF; - cc = w >> 30; + uint32_t z; + + z = t[i] + cc; + d[i] = z & 0x3FFFFFFF; + cc = z >> 30; } } @@ -515,20 +535,31 @@ static void f255_mul_a24(uint32_t *d, const uint32_t *a) { int i; - uint64_t cc, w; + uint64_t w; + uint32_t cc; + /* + * a[] is over 256 bits, thus a[8] has length at most 16 bits. + * We single out the processing of the last word: intermediate + * value w is up to 121665*2^16, yielding a carry for the next + * loop of at most 19*(121665*2^16/2^15) = 4623289. + */ cc = 0; - for (i = 0; i < 9; i ++) { - w = MUL31(a[i], 121665) + cc; + for (i = 0; i < 8; i ++) { + w = MUL31(a[i], 121665) + (uint64_t)cc; d[i] = (uint32_t)w & 0x3FFFFFFF; - cc = w >> 30; + cc = (uint32_t)(w >> 30); } - cc = MUL31((uint32_t)(w >> 15), 19); - d[8] &= 0x7FFF; + w = MUL31(a[8], 121665) + (uint64_t)cc; + d[8] = (uint32_t)w & 0x7FFF; + cc = MUL15((uint32_t)(w >> 15), 19); + for (i = 0; i < 9; i ++) { - w = (uint64_t)d[i] + cc; - d[i] = w & 0x3FFFFFFF; - cc = w >> 30; + uint32_t z; + + z = d[i] + cc; + d[i] = z & 0x3FFFFFFF; + cc = z >> 30; } } @@ -623,11 +654,11 @@ api_mul(unsigned char *G, size_t Glen, memset(z3, 0, sizeof z3); z3[0] = 1; - memcpy(k, kb, kblen); - memset(k + kblen, 0, (sizeof k) - kblen); - k[0] &= 0xF8; - k[31] &= 0x7F; - k[31] |= 0x40; + memset(k, 0, (sizeof k) - kblen); + memcpy(k + (sizeof k) - kblen, kb, kblen); + k[31] &= 0xF8; + k[0] &= 0x7F; + k[0] |= 0x40; /* obsolete print_int("x1", x1); @@ -637,7 +668,7 @@ api_mul(unsigned char *G, size_t Glen, for (i = 254; i >= 0; i --) { uint32_t kt; - kt = (k[i >> 3] >> (i & 7)) & 1; + kt = (k[31 - (i >> 3)] >> (i & 7)) & 1; swap ^= kt; cswap(x2, x3, swap); cswap(z2, z3, swap); diff --git a/src/bearssl/src/ec/ec_c25519_m62.c b/src/bearssl/src/ec/ec_c25519_m62.c new file mode 100644 index 0000000..6b058eb --- /dev/null +++ b/src/bearssl/src/ec/ec_c25519_m62.c @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +#if BR_UMUL128 +#include +#endif + +static const unsigned char GEN[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ORDER[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return GEN; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return ORDER; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 0; +} + +/* + * A field element is encoded as five 64-bit integers, in basis 2^51. + * Limbs may be occasionally larger than 2^51, to save on carry + * propagation costs. + */ + +#define MASK51 (((uint64_t)1 << 51) - (uint64_t)1) + +/* + * Swap two field elements, conditionally on a flag. + */ +static inline void +f255_cswap(uint64_t *a, uint64_t *b, uint32_t ctl) +{ + uint64_t m, w; + + m = -(uint64_t)ctl; + w = m & (a[0] ^ b[0]); a[0] ^= w; b[0] ^= w; + w = m & (a[1] ^ b[1]); a[1] ^= w; b[1] ^= w; + w = m & (a[2] ^ b[2]); a[2] ^= w; b[2] ^= w; + w = m & (a[3] ^ b[3]); a[3] ^= w; b[3] ^= w; + w = m & (a[4] ^ b[4]); a[4] ^= w; b[4] ^= w; +} + +/* + * Addition with no carry propagation. Limbs double in size. + */ +static inline void +f255_add(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ + d[0] = a[0] + b[0]; + d[1] = a[1] + b[1]; + d[2] = a[2] + b[2]; + d[3] = a[3] + b[3]; + d[4] = a[4] + b[4]; +} + +/* + * Subtraction. + * On input, limbs must fit on 60 bits each. On output, result is + * partially reduced, with max value 2^255+19456; moreover, all + * limbs will fit on 51 bits, except the low limb, which may have + * value up to 2^51+19455. + */ +static inline void +f255_sub(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ + uint64_t cc, w; + + /* + * We compute d = (2^255-19)*1024 + a - b. Since the limbs + * fit on 60 bits, the maximum value of operands are slightly + * more than 2^264, but much less than 2^265-19456. This + * ensures that the result is positive. + */ + + /* + * Initial carry is 19456, since we add 2^265-19456. Each + * individual subtraction may yield a carry up to 513. + */ + w = a[0] - b[0] - 19456; + d[0] = w & MASK51; + cc = -(w >> 51) & 0x3FF; + w = a[1] - b[1] - cc; + d[1] = w & MASK51; + cc = -(w >> 51) & 0x3FF; + w = a[2] - b[2] - cc; + d[2] = w & MASK51; + cc = -(w >> 51) & 0x3FF; + w = a[3] - b[3] - cc; + d[3] = w & MASK51; + cc = -(w >> 51) & 0x3FF; + d[4] = ((uint64_t)1 << 61) + a[4] - b[4] - cc; + + /* + * Partial reduction. The intermediate result may be up to + * slightly above 2^265, but less than 2^265+2^255. When we + * truncate to 255 bits, the upper bits will be at most 1024. + */ + d[0] += 19 * (d[4] >> 51); + d[4] &= MASK51; +} + +/* + * UMUL51(hi, lo, x, y) computes: + * + * hi = floor((x * y) / (2^51)) + * lo = x * y mod 2^51 + * + * Note that lo < 2^51, but "hi" may be larger, if the input operands are + * larger. + */ +#if BR_INT128 + +#define UMUL51(hi, lo, x, y) do { \ + unsigned __int128 umul_tmp; \ + umul_tmp = (unsigned __int128)(x) * (unsigned __int128)(y); \ + (hi) = (uint64_t)(umul_tmp >> 51); \ + (lo) = (uint64_t)umul_tmp & MASK51; \ + } while (0) + +#elif BR_UMUL128 + +#define UMUL51(hi, lo, x, y) do { \ + uint64_t umul_hi, umul_lo; \ + umul_lo = _umul128((x), (y), &umul_hi); \ + (hi) = (umul_hi << 13) | (umul_lo >> 51); \ + (lo) = umul_lo & MASK51; \ + } while (0) + +#endif + +/* + * Multiplication. + * On input, limbs must fit on 54 bits each. + * On output, limb 0 is at most 2^51 + 155647, and other limbs fit + * on 51 bits each. + */ +static inline void +f255_mul(uint64_t *d, uint64_t *a, uint64_t *b) +{ + uint64_t t[10], hi, lo, w, cc; + + /* + * Perform cross products, accumulating values without carry + * propagation. + * + * Since input limbs fit on 54 bits each, each individual + * UMUL51 will produce a "hi" of less than 2^57. The maximum + * sum will be at most 5*(2^57-1) + 4*(2^51-1) (for t[5]), + * i.e. less than 324*2^51. + */ + + UMUL51(t[1], t[0], a[0], b[0]); + + UMUL51(t[2], lo, a[1], b[0]); t[1] += lo; + UMUL51(hi, lo, a[0], b[1]); t[1] += lo; t[2] += hi; + + UMUL51(t[3], lo, a[2], b[0]); t[2] += lo; + UMUL51(hi, lo, a[1], b[1]); t[2] += lo; t[3] += hi; + UMUL51(hi, lo, a[0], b[2]); t[2] += lo; t[3] += hi; + + UMUL51(t[4], lo, a[3], b[0]); t[3] += lo; + UMUL51(hi, lo, a[2], b[1]); t[3] += lo; t[4] += hi; + UMUL51(hi, lo, a[1], b[2]); t[3] += lo; t[4] += hi; + UMUL51(hi, lo, a[0], b[3]); t[3] += lo; t[4] += hi; + + UMUL51(t[5], lo, a[4], b[0]); t[4] += lo; + UMUL51(hi, lo, a[3], b[1]); t[4] += lo; t[5] += hi; + UMUL51(hi, lo, a[2], b[2]); t[4] += lo; t[5] += hi; + UMUL51(hi, lo, a[1], b[3]); t[4] += lo; t[5] += hi; + UMUL51(hi, lo, a[0], b[4]); t[4] += lo; t[5] += hi; + + UMUL51(t[6], lo, a[4], b[1]); t[5] += lo; + UMUL51(hi, lo, a[3], b[2]); t[5] += lo; t[6] += hi; + UMUL51(hi, lo, a[2], b[3]); t[5] += lo; t[6] += hi; + UMUL51(hi, lo, a[1], b[4]); t[5] += lo; t[6] += hi; + + UMUL51(t[7], lo, a[4], b[2]); t[6] += lo; + UMUL51(hi, lo, a[3], b[3]); t[6] += lo; t[7] += hi; + UMUL51(hi, lo, a[2], b[4]); t[6] += lo; t[7] += hi; + + UMUL51(t[8], lo, a[4], b[3]); t[7] += lo; + UMUL51(hi, lo, a[3], b[4]); t[7] += lo; t[8] += hi; + + UMUL51(t[9], lo, a[4], b[4]); t[8] += lo; + + /* + * The upper words t[5]..t[9] are folded back into the lower + * words, using the rule that 2^255 = 19 in the field. + * + * Since each t[i] is less than 324*2^51, the additions below + * will yield less than 6480*2^51 in each limb; this fits in + * 64 bits (6480*2^51 < 8192*2^51 = 2^64), hence there is + * no overflow. + */ + t[0] += 19 * t[5]; + t[1] += 19 * t[6]; + t[2] += 19 * t[7]; + t[3] += 19 * t[8]; + t[4] += 19 * t[9]; + + /* + * Propagate carries. + */ + w = t[0]; + d[0] = w & MASK51; + cc = w >> 51; + w = t[1] + cc; + d[1] = w & MASK51; + cc = w >> 51; + w = t[2] + cc; + d[2] = w & MASK51; + cc = w >> 51; + w = t[3] + cc; + d[3] = w & MASK51; + cc = w >> 51; + w = t[4] + cc; + d[4] = w & MASK51; + cc = w >> 51; + + /* + * Since the limbs were 64-bit values, the top carry is at + * most 8192 (in practice, that cannot be reached). We simply + * performed a partial reduction. + */ + d[0] += 19 * cc; +} + +/* + * Multiplication by A24 = 121665. + * Input must have limbs of 60 bits at most. + */ +static inline void +f255_mul_a24(uint64_t *d, const uint64_t *a) +{ + uint64_t t[5], cc, w; + + /* + * 121665 = 15 * 8111. We first multiply by 15, with carry + * propagation and partial reduction. + */ + w = a[0] * 15; + t[0] = w & MASK51; + cc = w >> 51; + w = a[1] * 15 + cc; + t[1] = w & MASK51; + cc = w >> 51; + w = a[2] * 15 + cc; + t[2] = w & MASK51; + cc = w >> 51; + w = a[3] * 15 + cc; + t[3] = w & MASK51; + cc = w >> 51; + w = a[4] * 15 + cc; + t[4] = w & MASK51; + t[0] += 19 * (w >> 51); + + /* + * Then multiplication by 8111. At that point, we known that + * t[0] is less than 2^51 + 19*8192, and other limbs are less + * than 2^51; thus, there will be no overflow. + */ + w = t[0] * 8111; + d[0] = w & MASK51; + cc = w >> 51; + w = t[1] * 8111 + cc; + d[1] = w & MASK51; + cc = w >> 51; + w = t[2] * 8111 + cc; + d[2] = w & MASK51; + cc = w >> 51; + w = t[3] * 8111 + cc; + d[3] = w & MASK51; + cc = w >> 51; + w = t[4] * 8111 + cc; + d[4] = w & MASK51; + d[0] += 19 * (w >> 51); +} + +/* + * Finalize reduction. + * On input, limbs must fit on 51 bits, except possibly the low limb, + * which may be slightly above 2^51. + */ +static inline void +f255_final_reduce(uint64_t *a) +{ + uint64_t t[5], cc, w; + + /* + * We add 19. If the result (in t[]) is below 2^255, then a[] + * is already less than 2^255-19, thus already reduced. + * Otherwise, we subtract 2^255 from t[], in which case we + * have t = a - (2^255-19), and that's our result. + */ + w = a[0] + 19; + t[0] = w & MASK51; + cc = w >> 51; + w = a[1] + cc; + t[1] = w & MASK51; + cc = w >> 51; + w = a[2] + cc; + t[2] = w & MASK51; + cc = w >> 51; + w = a[3] + cc; + t[3] = w & MASK51; + cc = w >> 51; + w = a[4] + cc; + t[4] = w & MASK51; + cc = w >> 51; + + /* + * The bit 255 of t is in cc. If that bit is 0, when a[] must + * be unchanged; otherwise, it must be replaced with t[]. + */ + cc = -cc; + a[0] ^= cc & (a[0] ^ t[0]); + a[1] ^= cc & (a[1] ^ t[1]); + a[2] ^= cc & (a[2] ^ t[2]); + a[3] ^= cc & (a[3] ^ t[3]); + a[4] ^= cc & (a[4] ^ t[4]); +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + unsigned char k[32]; + uint64_t x1[5], x2[5], z2[5], x3[5], z3[5]; + uint32_t swap; + int i; + + (void)curve; + + /* + * Points are encoded over exactly 32 bytes. Multipliers must fit + * in 32 bytes as well. + */ + if (Glen != 32 || kblen > 32) { + return 0; + } + + /* + * RFC 7748 mandates that the high bit of the last point byte must + * be ignored/cleared; the "& MASK51" in the initialization for + * x1[4] clears that bit. + */ + x1[0] = br_dec64le(&G[0]) & MASK51; + x1[1] = (br_dec64le(&G[6]) >> 3) & MASK51; + x1[2] = (br_dec64le(&G[12]) >> 6) & MASK51; + x1[3] = (br_dec64le(&G[19]) >> 1) & MASK51; + x1[4] = (br_dec64le(&G[24]) >> 12) & MASK51; + + /* + * We can use memset() to clear values, because exact-width types + * like uint64_t are guaranteed to have no padding bits or + * trap representations. + */ + memset(x2, 0, sizeof x2); + x2[0] = 1; + memset(z2, 0, sizeof z2); + memcpy(x3, x1, sizeof x1); + memcpy(z3, x2, sizeof x2); + + /* + * The multiplier is provided in big-endian notation, and + * possibly shorter than 32 bytes. + */ + memset(k, 0, (sizeof k) - kblen); + memcpy(k + (sizeof k) - kblen, kb, kblen); + k[31] &= 0xF8; + k[0] &= 0x7F; + k[0] |= 0x40; + + swap = 0; + + for (i = 254; i >= 0; i --) { + uint64_t a[5], aa[5], b[5], bb[5], e[5]; + uint64_t c[5], d[5], da[5], cb[5]; + uint32_t kt; + + kt = (k[31 - (i >> 3)] >> (i & 7)) & 1; + swap ^= kt; + f255_cswap(x2, x3, swap); + f255_cswap(z2, z3, swap); + swap = kt; + + /* + * At that point, limbs of x_2 and z_2 are assumed to fit + * on at most 52 bits each. + * + * Each f255_add() adds one bit to the maximum range of + * the values, but f255_sub() and f255_mul() bring back + * the limbs into 52 bits. All f255_add() outputs are + * used only as inputs for f255_mul(), which ensures + * that limbs remain in the proper range. + */ + + /* A = x_2 + z_2 -- limbs fit on 53 bits each */ + f255_add(a, x2, z2); + + /* AA = A^2 */ + f255_mul(aa, a, a); + + /* B = x_2 - z_2 */ + f255_sub(b, x2, z2); + + /* BB = B^2 */ + f255_mul(bb, b, b); + + /* E = AA - BB */ + f255_sub(e, aa, bb); + + /* C = x_3 + z_3 -- limbs fit on 53 bits each */ + f255_add(c, x3, z3); + + /* D = x_3 - z_3 */ + f255_sub(d, x3, z3); + + /* DA = D * A */ + f255_mul(da, d, a); + + /* CB = C * B */ + f255_mul(cb, c, b); + + /* x_3 = (DA + CB)^2 */ + f255_add(x3, da, cb); + f255_mul(x3, x3, x3); + + /* z_3 = x_1 * (DA - CB)^2 */ + f255_sub(z3, da, cb); + f255_mul(z3, z3, z3); + f255_mul(z3, x1, z3); + + /* x_2 = AA * BB */ + f255_mul(x2, aa, bb); + + /* z_2 = E * (AA + a24 * E) */ + f255_mul_a24(z2, e); + f255_add(z2, aa, z2); + f255_mul(z2, e, z2); + } + + f255_cswap(x2, x3, swap); + f255_cswap(z2, z3, swap); + + /* + * Compute 1/z2 = z2^(p-2). Since p = 2^255-19, we can mutualize + * most non-squarings. We use x1 and x3, now useless, as temporaries. + */ + memcpy(x1, z2, sizeof z2); + for (i = 0; i < 15; i ++) { + f255_mul(x1, x1, x1); + f255_mul(x1, x1, z2); + } + memcpy(x3, x1, sizeof x1); + for (i = 0; i < 14; i ++) { + int j; + + for (j = 0; j < 16; j ++) { + f255_mul(x3, x3, x3); + } + f255_mul(x3, x3, x1); + } + for (i = 14; i >= 0; i --) { + f255_mul(x3, x3, x3); + if ((0xFFEB >> i) & 1) { + f255_mul(x3, z2, x3); + } + } + + /* + * Compute x2/z2. We have 1/z2 in x3. + */ + f255_mul(x2, x2, x3); + f255_final_reduce(x2); + + /* + * Encode the final x2 value in little-endian. We first assemble + * the limbs into 64-bit values. + */ + x2[0] |= x2[1] << 51; + x2[1] = (x2[1] >> 13) | (x2[2] << 38); + x2[2] = (x2[2] >> 26) | (x2[3] << 25); + x2[3] = (x2[3] >> 39) | (x2[4] << 12); + br_enc64le(G, x2[0]); + br_enc64le(G + 8, x2[1]); + br_enc64le(G + 16, x2[2]); + br_enc64le(G + 24, x2[3]); + return 1; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We don't implement this method, since it is used for ECDSA + * only, and there is no ECDSA over Curve25519 (which instead + * uses EdDSA). + */ + (void)A; + (void)B; + (void)len; + (void)x; + (void)xlen; + (void)y; + (void)ylen; + (void)curve; + return 0; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_c25519_m62 = { + (uint32_t)0x20000000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_c25519_m62_get(void) +{ + return &br_ec_c25519_m62; +} + +#else + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_c25519_m62_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/ec/ec_c25519_m64.c b/src/bearssl/src/ec/ec_c25519_m64.c new file mode 100644 index 0000000..df48834 --- /dev/null +++ b/src/bearssl/src/ec/ec_c25519_m64.c @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +#if BR_UMUL128 +#include +#endif + +static const unsigned char GEN[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ORDER[] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return GEN; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return ORDER; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 0; +} + +/* + * A field element is encoded as four 64-bit integers, in basis 2^63. + * Operations return partially reduced values, which may range up to + * 2^255+37. + */ + +#define MASK63 (((uint64_t)1 << 63) - (uint64_t)1) + +/* + * Swap two field elements, conditionally on a flag. + */ +static inline void +f255_cswap(uint64_t *a, uint64_t *b, uint32_t ctl) +{ + uint64_t m, w; + + m = -(uint64_t)ctl; + w = m & (a[0] ^ b[0]); a[0] ^= w; b[0] ^= w; + w = m & (a[1] ^ b[1]); a[1] ^= w; b[1] ^= w; + w = m & (a[2] ^ b[2]); a[2] ^= w; b[2] ^= w; + w = m & (a[3] ^ b[3]); a[3] ^= w; b[3] ^= w; +} + +/* + * Addition in the field. + */ +static inline void +f255_add(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ +#if BR_INT128 + + uint64_t t0, t1, t2, t3, cc; + unsigned __int128 z; + + z = (unsigned __int128)a[0] + (unsigned __int128)b[0]; + t0 = (uint64_t)z; + z = (unsigned __int128)a[1] + (unsigned __int128)b[1] + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)a[2] + (unsigned __int128)b[2] + (z >> 64); + t2 = (uint64_t)z; + z = (unsigned __int128)a[3] + (unsigned __int128)b[3] + (z >> 64); + t3 = (uint64_t)z & MASK63; + cc = (uint64_t)(z >> 63); + + /* + * Since operands are at most 2^255+37, the sum is at most + * 2^256+74; thus, the carry cc is equal to 0, 1 or 2. + * + * We use: 2^255 = 19 mod p. + * Since we add 0, 19 or 38 to a value that fits on 255 bits, + * the result is at most 2^255+37. + */ + z = (unsigned __int128)t0 + (unsigned __int128)(19 * cc); + d[0] = (uint64_t)z; + z = (unsigned __int128)t1 + (z >> 64); + d[1] = (uint64_t)z; + z = (unsigned __int128)t2 + (z >> 64); + d[2] = (uint64_t)z; + d[3] = t3 + (uint64_t)(z >> 64); + +#elif BR_UMUL128 + + uint64_t t0, t1, t2, t3, cc; + unsigned char k; + + k = _addcarry_u64(0, a[0], b[0], &t0); + k = _addcarry_u64(k, a[1], b[1], &t1); + k = _addcarry_u64(k, a[2], b[2], &t2); + k = _addcarry_u64(k, a[3], b[3], &t3); + cc = (k << 1) + (t3 >> 63); + t3 &= MASK63; + + /* + * Since operands are at most 2^255+37, the sum is at most + * 2^256+74; thus, the carry cc is equal to 0, 1 or 2. + * + * We use: 2^255 = 19 mod p. + * Since we add 0, 19 or 38 to a value that fits on 255 bits, + * the result is at most 2^255+37. + */ + k = _addcarry_u64(0, t0, 19 * cc, &d[0]); + k = _addcarry_u64(k, t1, 0, &d[1]); + k = _addcarry_u64(k, t2, 0, &d[2]); + (void)_addcarry_u64(k, t3, 0, &d[3]); + +#endif +} + +/* + * Subtraction. + */ +static inline void +f255_sub(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ +#if BR_INT128 + + /* + * We compute t = 2^256 - 38 + a - b, which is necessarily + * positive but lower than 2^256 + 2^255, since a <= 2^255 + 37 + * and b <= 2^255 + 37. We then subtract 0, p or 2*p, depending + * on the two upper bits of t (bits 255 and 256). + */ + + uint64_t t0, t1, t2, t3, t4, cc; + unsigned __int128 z; + + z = (unsigned __int128)a[0] - (unsigned __int128)b[0] - 38; + t0 = (uint64_t)z; + cc = -(uint64_t)(z >> 64); + z = (unsigned __int128)a[1] - (unsigned __int128)b[1] + - (unsigned __int128)cc; + t1 = (uint64_t)z; + cc = -(uint64_t)(z >> 64); + z = (unsigned __int128)a[2] - (unsigned __int128)b[2] + - (unsigned __int128)cc; + t2 = (uint64_t)z; + cc = -(uint64_t)(z >> 64); + z = (unsigned __int128)a[3] - (unsigned __int128)b[3] + - (unsigned __int128)cc; + t3 = (uint64_t)z; + t4 = 1 + (uint64_t)(z >> 64); + + /* + * We have a 257-bit result. The two top bits can be 00, 01 or 10, + * but not 11 (value t <= 2^256 - 38 + 2^255 + 37 = 2^256 + 2^255 - 1). + * Therefore, we can truncate to 255 bits, and add 0, 19 or 38. + * This guarantees that the result is at most 2^255+37. + */ + cc = (38 & -t4) + (19 & -(t3 >> 63)); + t3 &= MASK63; + z = (unsigned __int128)t0 + (unsigned __int128)cc; + d[0] = (uint64_t)z; + z = (unsigned __int128)t1 + (z >> 64); + d[1] = (uint64_t)z; + z = (unsigned __int128)t2 + (z >> 64); + d[2] = (uint64_t)z; + d[3] = t3 + (uint64_t)(z >> 64); + +#elif BR_UMUL128 + + /* + * We compute t = 2^256 - 38 + a - b, which is necessarily + * positive but lower than 2^256 + 2^255, since a <= 2^255 + 37 + * and b <= 2^255 + 37. We then subtract 0, p or 2*p, depending + * on the two upper bits of t (bits 255 and 256). + */ + + uint64_t t0, t1, t2, t3, t4; + unsigned char k; + + k = _subborrow_u64(0, a[0], b[0], &t0); + k = _subborrow_u64(k, a[1], b[1], &t1); + k = _subborrow_u64(k, a[2], b[2], &t2); + k = _subborrow_u64(k, a[3], b[3], &t3); + (void)_subborrow_u64(k, 1, 0, &t4); + + k = _subborrow_u64(0, t0, 38, &t0); + k = _subborrow_u64(k, t1, 0, &t1); + k = _subborrow_u64(k, t2, 0, &t2); + k = _subborrow_u64(k, t3, 0, &t3); + (void)_subborrow_u64(k, t4, 0, &t4); + + /* + * We have a 257-bit result. The two top bits can be 00, 01 or 10, + * but not 11 (value t <= 2^256 - 38 + 2^255 + 37 = 2^256 + 2^255 - 1). + * Therefore, we can truncate to 255 bits, and add 0, 19 or 38. + * This guarantees that the result is at most 2^255+37. + */ + t4 = (38 & -t4) + (19 & -(t3 >> 63)); + t3 &= MASK63; + k = _addcarry_u64(0, t0, t4, &d[0]); + k = _addcarry_u64(k, t1, 0, &d[1]); + k = _addcarry_u64(k, t2, 0, &d[2]); + (void)_addcarry_u64(k, t3, 0, &d[3]); + +#endif +} + +/* + * Multiplication. + */ +static inline void +f255_mul(uint64_t *d, uint64_t *a, uint64_t *b) +{ +#if BR_INT128 + + unsigned __int128 z; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, th; + + /* + * Compute the product a*b over plain integers. + */ + z = (unsigned __int128)a[0] * (unsigned __int128)b[0]; + t0 = (uint64_t)z; + z = (unsigned __int128)a[0] * (unsigned __int128)b[1] + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)a[0] * (unsigned __int128)b[2] + (z >> 64); + t2 = (uint64_t)z; + z = (unsigned __int128)a[0] * (unsigned __int128)b[3] + (z >> 64); + t3 = (uint64_t)z; + t4 = (uint64_t)(z >> 64); + + z = (unsigned __int128)a[1] * (unsigned __int128)b[0] + + (unsigned __int128)t1; + t1 = (uint64_t)z; + z = (unsigned __int128)a[1] * (unsigned __int128)b[1] + + (unsigned __int128)t2 + (z >> 64); + t2 = (uint64_t)z; + z = (unsigned __int128)a[1] * (unsigned __int128)b[2] + + (unsigned __int128)t3 + (z >> 64); + t3 = (uint64_t)z; + z = (unsigned __int128)a[1] * (unsigned __int128)b[3] + + (unsigned __int128)t4 + (z >> 64); + t4 = (uint64_t)z; + t5 = (uint64_t)(z >> 64); + + z = (unsigned __int128)a[2] * (unsigned __int128)b[0] + + (unsigned __int128)t2; + t2 = (uint64_t)z; + z = (unsigned __int128)a[2] * (unsigned __int128)b[1] + + (unsigned __int128)t3 + (z >> 64); + t3 = (uint64_t)z; + z = (unsigned __int128)a[2] * (unsigned __int128)b[2] + + (unsigned __int128)t4 + (z >> 64); + t4 = (uint64_t)z; + z = (unsigned __int128)a[2] * (unsigned __int128)b[3] + + (unsigned __int128)t5 + (z >> 64); + t5 = (uint64_t)z; + t6 = (uint64_t)(z >> 64); + + z = (unsigned __int128)a[3] * (unsigned __int128)b[0] + + (unsigned __int128)t3; + t3 = (uint64_t)z; + z = (unsigned __int128)a[3] * (unsigned __int128)b[1] + + (unsigned __int128)t4 + (z >> 64); + t4 = (uint64_t)z; + z = (unsigned __int128)a[3] * (unsigned __int128)b[2] + + (unsigned __int128)t5 + (z >> 64); + t5 = (uint64_t)z; + z = (unsigned __int128)a[3] * (unsigned __int128)b[3] + + (unsigned __int128)t6 + (z >> 64); + t6 = (uint64_t)z; + t7 = (uint64_t)(z >> 64); + + /* + * Modulo p, we have: + * + * 2^255 = 19 + * 2^510 = 19*19 = 361 + * + * We split the intermediate t into three parts, in basis + * 2^255. The low one will be in t0..t3; the middle one in t4..t7. + * The upper one can only be a single bit (th), since the + * multiplication operands are at most 2^255+37 each. + */ + th = t7 >> 62; + t7 = ((t7 << 1) | (t6 >> 63)) & MASK63; + t6 = (t6 << 1) | (t5 >> 63); + t5 = (t5 << 1) | (t4 >> 63); + t4 = (t4 << 1) | (t3 >> 63); + t3 &= MASK63; + + /* + * Multiply the middle part (t4..t7) by 19. We truncate it to + * 255 bits; the extra bits will go along with th. + */ + z = (unsigned __int128)t4 * 19; + t4 = (uint64_t)z; + z = (unsigned __int128)t5 * 19 + (z >> 64); + t5 = (uint64_t)z; + z = (unsigned __int128)t6 * 19 + (z >> 64); + t6 = (uint64_t)z; + z = (unsigned __int128)t7 * 19 + (z >> 64); + t7 = (uint64_t)z & MASK63; + + th = (361 & -th) + (19 * (uint64_t)(z >> 63)); + + /* + * Add elements together. + * At this point: + * t0..t3 fits on 255 bits. + * t4..t7 fits on 255 bits. + * th <= 361 + 342 = 703. + */ + z = (unsigned __int128)t0 + (unsigned __int128)t4 + + (unsigned __int128)th; + t0 = (uint64_t)z; + z = (unsigned __int128)t1 + (unsigned __int128)t5 + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)t2 + (unsigned __int128)t6 + (z >> 64); + t2 = (uint64_t)z; + z = (unsigned __int128)t3 + (unsigned __int128)t7 + (z >> 64); + t3 = (uint64_t)z & MASK63; + th = (uint64_t)(z >> 63); + + /* + * Since the sum is at most 2^256 + 703, the two upper bits, in th, + * can only have value 0, 1 or 2. We just add th*19, which + * guarantees a result of at most 2^255+37. + */ + z = (unsigned __int128)t0 + (19 * th); + d[0] = (uint64_t)z; + z = (unsigned __int128)t1 + (z >> 64); + d[1] = (uint64_t)z; + z = (unsigned __int128)t2 + (z >> 64); + d[2] = (uint64_t)z; + d[3] = t3 + (uint64_t)(z >> 64); + +#elif BR_UMUL128 + + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, th; + uint64_t h0, h1, h2, h3; + unsigned char k; + + /* + * Compute the product a*b over plain integers. + */ + t0 = _umul128(a[0], b[0], &h0); + t1 = _umul128(a[0], b[1], &h1); + k = _addcarry_u64(0, t1, h0, &t1); + t2 = _umul128(a[0], b[2], &h2); + k = _addcarry_u64(k, t2, h1, &t2); + t3 = _umul128(a[0], b[3], &h3); + k = _addcarry_u64(k, t3, h2, &t3); + (void)_addcarry_u64(k, h3, 0, &t4); + + k = _addcarry_u64(0, _umul128(a[1], b[0], &h0), t1, &t1); + k = _addcarry_u64(k, _umul128(a[1], b[1], &h1), t2, &t2); + k = _addcarry_u64(k, _umul128(a[1], b[2], &h2), t3, &t3); + k = _addcarry_u64(k, _umul128(a[1], b[3], &h3), t4, &t4); + t5 = k; + k = _addcarry_u64(0, t2, h0, &t2); + k = _addcarry_u64(k, t3, h1, &t3); + k = _addcarry_u64(k, t4, h2, &t4); + (void)_addcarry_u64(k, t5, h3, &t5); + + k = _addcarry_u64(0, _umul128(a[2], b[0], &h0), t2, &t2); + k = _addcarry_u64(k, _umul128(a[2], b[1], &h1), t3, &t3); + k = _addcarry_u64(k, _umul128(a[2], b[2], &h2), t4, &t4); + k = _addcarry_u64(k, _umul128(a[2], b[3], &h3), t5, &t5); + t6 = k; + k = _addcarry_u64(0, t3, h0, &t3); + k = _addcarry_u64(k, t4, h1, &t4); + k = _addcarry_u64(k, t5, h2, &t5); + (void)_addcarry_u64(k, t6, h3, &t6); + + k = _addcarry_u64(0, _umul128(a[3], b[0], &h0), t3, &t3); + k = _addcarry_u64(k, _umul128(a[3], b[1], &h1), t4, &t4); + k = _addcarry_u64(k, _umul128(a[3], b[2], &h2), t5, &t5); + k = _addcarry_u64(k, _umul128(a[3], b[3], &h3), t6, &t6); + t7 = k; + k = _addcarry_u64(0, t4, h0, &t4); + k = _addcarry_u64(k, t5, h1, &t5); + k = _addcarry_u64(k, t6, h2, &t6); + (void)_addcarry_u64(k, t7, h3, &t7); + + /* + * Modulo p, we have: + * + * 2^255 = 19 + * 2^510 = 19*19 = 361 + * + * We split the intermediate t into three parts, in basis + * 2^255. The low one will be in t0..t3; the middle one in t4..t7. + * The upper one can only be a single bit (th), since the + * multiplication operands are at most 2^255+37 each. + */ + th = t7 >> 62; + t7 = ((t7 << 1) | (t6 >> 63)) & MASK63; + t6 = (t6 << 1) | (t5 >> 63); + t5 = (t5 << 1) | (t4 >> 63); + t4 = (t4 << 1) | (t3 >> 63); + t3 &= MASK63; + + /* + * Multiply the middle part (t4..t7) by 19. We truncate it to + * 255 bits; the extra bits will go along with th. + */ + t4 = _umul128(t4, 19, &h0); + t5 = _umul128(t5, 19, &h1); + t6 = _umul128(t6, 19, &h2); + t7 = _umul128(t7, 19, &h3); + k = _addcarry_u64(0, t5, h0, &t5); + k = _addcarry_u64(k, t6, h1, &t6); + k = _addcarry_u64(k, t7, h2, &t7); + (void)_addcarry_u64(k, h3, 0, &h3); + th = (361 & -th) + (19 * ((h3 << 1) + (t7 >> 63))); + t7 &= MASK63; + + /* + * Add elements together. + * At this point: + * t0..t3 fits on 255 bits. + * t4..t7 fits on 255 bits. + * th <= 361 + 342 = 703. + */ + k = _addcarry_u64(0, t0, t4, &t0); + k = _addcarry_u64(k, t1, t5, &t1); + k = _addcarry_u64(k, t2, t6, &t2); + k = _addcarry_u64(k, t3, t7, &t3); + t4 = k; + k = _addcarry_u64(0, t0, th, &t0); + k = _addcarry_u64(k, t1, 0, &t1); + k = _addcarry_u64(k, t2, 0, &t2); + k = _addcarry_u64(k, t3, 0, &t3); + (void)_addcarry_u64(k, t4, 0, &t4); + + th = (t4 << 1) + (t3 >> 63); + t3 &= MASK63; + + /* + * Since the sum is at most 2^256 + 703, the two upper bits, in th, + * can only have value 0, 1 or 2. We just add th*19, which + * guarantees a result of at most 2^255+37. + */ + k = _addcarry_u64(0, t0, 19 * th, &d[0]); + k = _addcarry_u64(k, t1, 0, &d[1]); + k = _addcarry_u64(k, t2, 0, &d[2]); + (void)_addcarry_u64(k, t3, 0, &d[3]); + +#endif +} + +/* + * Multiplication by A24 = 121665. + */ +static inline void +f255_mul_a24(uint64_t *d, const uint64_t *a) +{ +#if BR_INT128 + + uint64_t t0, t1, t2, t3; + unsigned __int128 z; + + z = (unsigned __int128)a[0] * 121665; + t0 = (uint64_t)z; + z = (unsigned __int128)a[1] * 121665 + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)a[2] * 121665 + (z >> 64); + t2 = (uint64_t)z; + z = (unsigned __int128)a[3] * 121665 + (z >> 64); + t3 = (uint64_t)z & MASK63; + + z = (unsigned __int128)t0 + (19 * (uint64_t)(z >> 63)); + t0 = (uint64_t)z; + z = (unsigned __int128)t1 + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)t2 + (z >> 64); + t2 = (uint64_t)z; + t3 = t3 + (uint64_t)(z >> 64); + + z = (unsigned __int128)t0 + (19 & -(t3 >> 63)); + d[0] = (uint64_t)z; + z = (unsigned __int128)t1 + (z >> 64); + d[1] = (uint64_t)z; + z = (unsigned __int128)t2 + (z >> 64); + d[2] = (uint64_t)z; + d[3] = (t3 & MASK63) + (uint64_t)(z >> 64); + +#elif BR_UMUL128 + + uint64_t t0, t1, t2, t3, t4, h0, h1, h2, h3; + unsigned char k; + + t0 = _umul128(a[0], 121665, &h0); + t1 = _umul128(a[1], 121665, &h1); + k = _addcarry_u64(0, t1, h0, &t1); + t2 = _umul128(a[2], 121665, &h2); + k = _addcarry_u64(k, t2, h1, &t2); + t3 = _umul128(a[3], 121665, &h3); + k = _addcarry_u64(k, t3, h2, &t3); + (void)_addcarry_u64(k, h3, 0, &t4); + + t4 = (t4 << 1) + (t3 >> 63); + t3 &= MASK63; + k = _addcarry_u64(0, t0, 19 * t4, &t0); + k = _addcarry_u64(k, t1, 0, &t1); + k = _addcarry_u64(k, t2, 0, &t2); + (void)_addcarry_u64(k, t3, 0, &t3); + + t4 = 19 & -(t3 >> 63); + t3 &= MASK63; + k = _addcarry_u64(0, t0, t4, &d[0]); + k = _addcarry_u64(k, t1, 0, &d[1]); + k = _addcarry_u64(k, t2, 0, &d[2]); + (void)_addcarry_u64(k, t3, 0, &d[3]); + +#endif +} + +/* + * Finalize reduction. + */ +static inline void +f255_final_reduce(uint64_t *a) +{ +#if BR_INT128 + + uint64_t t0, t1, t2, t3, m; + unsigned __int128 z; + + /* + * We add 19. If the result (in t) is below 2^255, then a[] + * is already less than 2^255-19, thus already reduced. + * Otherwise, we subtract 2^255 from t[], in which case we + * have t = a - (2^255-19), and that's our result. + */ + z = (unsigned __int128)a[0] + 19; + t0 = (uint64_t)z; + z = (unsigned __int128)a[1] + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)a[2] + (z >> 64); + t2 = (uint64_t)z; + t3 = a[3] + (uint64_t)(z >> 64); + + m = -(t3 >> 63); + t3 &= MASK63; + a[0] ^= m & (a[0] ^ t0); + a[1] ^= m & (a[1] ^ t1); + a[2] ^= m & (a[2] ^ t2); + a[3] ^= m & (a[3] ^ t3); + +#elif BR_UMUL128 + + uint64_t t0, t1, t2, t3, m; + unsigned char k; + + /* + * We add 19. If the result (in t) is below 2^255, then a[] + * is already less than 2^255-19, thus already reduced. + * Otherwise, we subtract 2^255 from t[], in which case we + * have t = a - (2^255-19), and that's our result. + */ + k = _addcarry_u64(0, a[0], 19, &t0); + k = _addcarry_u64(k, a[1], 0, &t1); + k = _addcarry_u64(k, a[2], 0, &t2); + (void)_addcarry_u64(k, a[3], 0, &t3); + + m = -(t3 >> 63); + t3 &= MASK63; + a[0] ^= m & (a[0] ^ t0); + a[1] ^= m & (a[1] ^ t1); + a[2] ^= m & (a[2] ^ t2); + a[3] ^= m & (a[3] ^ t3); + +#endif +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *kb, size_t kblen, int curve) +{ + unsigned char k[32]; + uint64_t x1[4], x2[4], z2[4], x3[4], z3[4]; + uint32_t swap; + int i; + + (void)curve; + + /* + * Points are encoded over exactly 32 bytes. Multipliers must fit + * in 32 bytes as well. + */ + if (Glen != 32 || kblen > 32) { + return 0; + } + + /* + * RFC 7748 mandates that the high bit of the last point byte must + * be ignored/cleared. + */ + x1[0] = br_dec64le(&G[ 0]); + x1[1] = br_dec64le(&G[ 8]); + x1[2] = br_dec64le(&G[16]); + x1[3] = br_dec64le(&G[24]) & MASK63; + + /* + * We can use memset() to clear values, because exact-width types + * like uint64_t are guaranteed to have no padding bits or + * trap representations. + */ + memset(x2, 0, sizeof x2); + x2[0] = 1; + memset(z2, 0, sizeof z2); + memcpy(x3, x1, sizeof x1); + memcpy(z3, x2, sizeof x2); + + /* + * The multiplier is provided in big-endian notation, and + * possibly shorter than 32 bytes. + */ + memset(k, 0, (sizeof k) - kblen); + memcpy(k + (sizeof k) - kblen, kb, kblen); + k[31] &= 0xF8; + k[0] &= 0x7F; + k[0] |= 0x40; + + swap = 0; + + for (i = 254; i >= 0; i --) { + uint64_t a[4], aa[4], b[4], bb[4], e[4]; + uint64_t c[4], d[4], da[4], cb[4]; + uint32_t kt; + + kt = (k[31 - (i >> 3)] >> (i & 7)) & 1; + swap ^= kt; + f255_cswap(x2, x3, swap); + f255_cswap(z2, z3, swap); + swap = kt; + + /* A = x_2 + z_2 */ + f255_add(a, x2, z2); + + /* AA = A^2 */ + f255_mul(aa, a, a); + + /* B = x_2 - z_2 */ + f255_sub(b, x2, z2); + + /* BB = B^2 */ + f255_mul(bb, b, b); + + /* E = AA - BB */ + f255_sub(e, aa, bb); + + /* C = x_3 + z_3 */ + f255_add(c, x3, z3); + + /* D = x_3 - z_3 */ + f255_sub(d, x3, z3); + + /* DA = D * A */ + f255_mul(da, d, a); + + /* CB = C * B */ + f255_mul(cb, c, b); + + /* x_3 = (DA + CB)^2 */ + f255_add(x3, da, cb); + f255_mul(x3, x3, x3); + + /* z_3 = x_1 * (DA - CB)^2 */ + f255_sub(z3, da, cb); + f255_mul(z3, z3, z3); + f255_mul(z3, x1, z3); + + /* x_2 = AA * BB */ + f255_mul(x2, aa, bb); + + /* z_2 = E * (AA + a24 * E) */ + f255_mul_a24(z2, e); + f255_add(z2, aa, z2); + f255_mul(z2, e, z2); + } + + f255_cswap(x2, x3, swap); + f255_cswap(z2, z3, swap); + + /* + * Compute 1/z2 = z2^(p-2). Since p = 2^255-19, we can mutualize + * most non-squarings. We use x1 and x3, now useless, as temporaries. + */ + memcpy(x1, z2, sizeof z2); + for (i = 0; i < 15; i ++) { + f255_mul(x1, x1, x1); + f255_mul(x1, x1, z2); + } + memcpy(x3, x1, sizeof x1); + for (i = 0; i < 14; i ++) { + int j; + + for (j = 0; j < 16; j ++) { + f255_mul(x3, x3, x3); + } + f255_mul(x3, x3, x1); + } + for (i = 14; i >= 0; i --) { + f255_mul(x3, x3, x3); + if ((0xFFEB >> i) & 1) { + f255_mul(x3, z2, x3); + } + } + + /* + * Compute x2/z2. We have 1/z2 in x3. + */ + f255_mul(x2, x2, x3); + f255_final_reduce(x2); + + /* + * Encode the final x2 value in little-endian. + */ + br_enc64le(G, x2[0]); + br_enc64le(G + 8, x2[1]); + br_enc64le(G + 16, x2[2]); + br_enc64le(G + 24, x2[3]); + return 1; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *x, size_t xlen, int curve) +{ + const unsigned char *G; + size_t Glen; + + G = api_generator(curve, &Glen); + memcpy(R, G, Glen); + api_mul(R, Glen, x, xlen, curve); + return Glen; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We don't implement this method, since it is used for ECDSA + * only, and there is no ECDSA over Curve25519 (which instead + * uses EdDSA). + */ + (void)A; + (void)B; + (void)len; + (void)x; + (void)xlen; + (void)y; + (void)ylen; + (void)curve; + return 0; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_c25519_m64 = { + (uint32_t)0x20000000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_c25519_m64_get(void) +{ + return &br_ec_c25519_m64; +} + +#else + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_c25519_m64_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/ec/ec_p256_m15.c b/src/bearssl/src/ec/ec_p256_m15.c index 6ce57e0..8d68d1d 100644 --- a/src/bearssl/src/ec/ec_p256_m15.c +++ b/src/bearssl/src/ec/ec_p256_m15.c @@ -1739,7 +1739,7 @@ p256_decode(p256_jacobian *P, const void *src, size_t len) memcpy(P->y, ty, sizeof ty); memset(P->z, 0, sizeof P->z); P->z[0] = 1; - return NEQ(bad, 0) ^ 1; + return EQ(bad, 0); } /* diff --git a/src/bearssl/src/ec/ec_p256_m31.c b/src/bearssl/src/ec/ec_p256_m31.c index ec22c3e..d57ef7b 100644 --- a/src/bearssl/src/ec/ec_p256_m31.c +++ b/src/bearssl/src/ec/ec_p256_m31.c @@ -1089,7 +1089,7 @@ p256_decode(p256_jacobian *P, const void *src, size_t len) memcpy(P->y, ty, sizeof ty); memset(P->z, 0, sizeof P->z); P->z[0] = 1; - return NEQ(bad, 0) ^ 1; + return EQ(bad, 0); } /* diff --git a/src/bearssl/src/ec/ec_p256_m62.c b/src/bearssl/src/ec/ec_p256_m62.c new file mode 100644 index 0000000..a431790 --- /dev/null +++ b/src/bearssl/src/ec/ec_p256_m62.c @@ -0,0 +1,1765 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +#if BR_UMUL128 +#include +#endif + +static const unsigned char P256_G[] = { + 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, + 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, + 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, + 0x98, 0xC2, 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, + 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, + 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, + 0x68, 0x37, 0xBF, 0x51, 0xF5 +}; + +static const unsigned char P256_N[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, + 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, + 0x25, 0x51 +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_G; + return P256_G; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_N; + return P256_N; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 1; +} + +/* + * A field element is encoded as five 64-bit integers, in basis 2^52. + * Limbs may occasionally exceed 2^52. + * + * A _partially reduced_ value is such that the following hold: + * - top limb is less than 2^48 + 2^30 + * - the other limbs fit on 53 bits each + * In particular, such a value is less than twice the modulus p. + */ + +#define BIT(n) ((uint64_t)1 << (n)) +#define MASK48 (BIT(48) - BIT(0)) +#define MASK52 (BIT(52) - BIT(0)) + +/* R = 2^260 mod p */ +static const uint64_t F256_R[] = { + 0x0000000000010, 0xF000000000000, 0xFFFFFFFFFFFFF, + 0xFFEFFFFFFFFFF, 0x00000000FFFFF +}; + +/* Curve equation is y^2 = x^3 - 3*x + B. This constant is B*R mod p + (Montgomery representation of B). */ +static const uint64_t P256_B_MONTY[] = { + 0xDF6229C4BDDFD, 0xCA8843090D89C, 0x212ED6ACF005C, + 0x83415A220ABF7, 0x0C30061DD4874 +}; + +/* + * Addition in the field. Carry propagation is not performed. + * On input, limbs may be up to 63 bits each; on output, they will + * be up to one bit more than on input. + */ +static inline void +f256_add(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ + d[0] = a[0] + b[0]; + d[1] = a[1] + b[1]; + d[2] = a[2] + b[2]; + d[3] = a[3] + b[3]; + d[4] = a[4] + b[4]; +} + +/* + * Partially reduce the provided value. + * Input: limbs can go up to 61 bits each. + * Output: partially reduced. + */ +static inline void +f256_partial_reduce(uint64_t *a) +{ + uint64_t w, cc, s; + + /* + * Propagate carries. + */ + w = a[0]; + a[0] = w & MASK52; + cc = w >> 52; + w = a[1] + cc; + a[1] = w & MASK52; + cc = w >> 52; + w = a[2] + cc; + a[2] = w & MASK52; + cc = w >> 52; + w = a[3] + cc; + a[3] = w & MASK52; + cc = w >> 52; + a[4] += cc; + + s = a[4] >> 48; /* s < 2^14 */ + a[0] += s; /* a[0] < 2^52 + 2^14 */ + w = a[1] - (s << 44); + a[1] = w & MASK52; /* a[1] < 2^52 */ + cc = -(w >> 52) & 0xFFF; /* cc < 16 */ + w = a[2] - cc; + a[2] = w & MASK52; /* a[2] < 2^52 */ + cc = w >> 63; /* cc = 0 or 1 */ + w = a[3] - cc - (s << 36); + a[3] = w & MASK52; /* a[3] < 2^52 */ + cc = w >> 63; /* cc = 0 or 1 */ + w = a[4] & MASK48; + a[4] = w + (s << 16) - cc; /* a[4] < 2^48 + 2^30 */ +} + +/* + * Subtraction in the field. + * Input: limbs must fit on 60 bits each; in particular, the complete + * integer will be less than 2^268 + 2^217. + * Output: partially reduced. + */ +static inline void +f256_sub(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ + uint64_t t[5], w, s, cc; + + /* + * We compute d = 2^13*p + a - b; this ensures a positive + * intermediate value. + * + * Each individual addition/subtraction may yield a positive or + * negative result; thus, we need to handle a signed carry, thus + * with sign extension. We prefer not to use signed types (int64_t) + * because conversion from unsigned to signed is cumbersome (a + * direct cast with the top bit set is undefined behavior; instead, + * we have to use pointer aliasing, using the guaranteed properties + * of exact-width types, but this requires the compiler to optimize + * away the writes and reads from RAM), and right-shifting a + * signed negative value is implementation-defined. Therefore, + * we use a custom sign extension. + */ + + w = a[0] - b[0] - BIT(13); + t[0] = w & MASK52; + cc = w >> 52; + cc |= -(cc & BIT(11)); + w = a[1] - b[1] + cc; + t[1] = w & MASK52; + cc = w >> 52; + cc |= -(cc & BIT(11)); + w = a[2] - b[2] + cc; + t[2] = (w & MASK52) + BIT(5); + cc = w >> 52; + cc |= -(cc & BIT(11)); + w = a[3] - b[3] + cc; + t[3] = (w & MASK52) + BIT(49); + cc = w >> 52; + cc |= -(cc & BIT(11)); + t[4] = (BIT(61) - BIT(29)) + a[4] - b[4] + cc; + + /* + * Perform partial reduction. Rule is: + * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p + * + * At that point: + * 0 <= t[0] <= 2^52 - 1 + * 0 <= t[1] <= 2^52 - 1 + * 2^5 <= t[2] <= 2^52 + 2^5 - 1 + * 2^49 <= t[3] <= 2^52 + 2^49 - 1 + * 2^59 < t[4] <= 2^61 + 2^60 - 2^29 + * + * Thus, the value 's' (t[4] / 2^48) will be necessarily + * greater than 2048, and less than 12288. + */ + s = t[4] >> 48; + + d[0] = t[0] + s; /* d[0] <= 2^52 + 12287 */ + w = t[1] - (s << 44); + d[1] = w & MASK52; /* d[1] <= 2^52 - 1 */ + cc = -(w >> 52) & 0xFFF; /* cc <= 48 */ + w = t[2] - cc; + cc = w >> 63; /* cc = 0 or 1 */ + d[2] = w + (cc << 52); /* d[2] <= 2^52 + 31 */ + w = t[3] - cc - (s << 36); + cc = w >> 63; /* cc = 0 or 1 */ + d[3] = w + (cc << 52); /* t[3] <= 2^52 + 2^49 - 1 */ + d[4] = (t[4] & MASK48) + (s << 16) - cc; /* d[4] < 2^48 + 2^30 */ + + /* + * If s = 0, then none of the limbs is modified, and there cannot + * be an overflow; if s != 0, then (s << 16) > cc, and there is + * no overflow either. + */ +} + +/* + * Montgomery multiplication in the field. + * Input: limbs must fit on 56 bits each. + * Output: partially reduced. + */ +static void +f256_montymul(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ +#if BR_INT128 + + int i; + uint64_t t[5]; + + t[0] = 0; + t[1] = 0; + t[2] = 0; + t[3] = 0; + t[4] = 0; + for (i = 0; i < 5; i ++) { + uint64_t x, f, cc, w, s; + unsigned __int128 z; + + /* + * Since limbs of a[] and b[] fit on 56 bits each, + * each individual product fits on 112 bits. Also, + * the factor f fits on 52 bits, so f<<48 fits on + * 112 bits too. This guarantees that carries (cc) + * will fit on 62 bits, thus no overflow. + * + * The operations below compute: + * t <- (t + x*b + f*p) / 2^64 + */ + x = a[i]; + z = (unsigned __int128)b[0] * (unsigned __int128)x + + (unsigned __int128)t[0]; + f = (uint64_t)z & MASK52; + cc = (uint64_t)(z >> 52); + z = (unsigned __int128)b[1] * (unsigned __int128)x + + (unsigned __int128)t[1] + cc + + ((unsigned __int128)f << 44); + t[0] = (uint64_t)z & MASK52; + cc = (uint64_t)(z >> 52); + z = (unsigned __int128)b[2] * (unsigned __int128)x + + (unsigned __int128)t[2] + cc; + t[1] = (uint64_t)z & MASK52; + cc = (uint64_t)(z >> 52); + z = (unsigned __int128)b[3] * (unsigned __int128)x + + (unsigned __int128)t[3] + cc + + ((unsigned __int128)f << 36); + t[2] = (uint64_t)z & MASK52; + cc = (uint64_t)(z >> 52); + z = (unsigned __int128)b[4] * (unsigned __int128)x + + (unsigned __int128)t[4] + cc + + ((unsigned __int128)f << 48) + - ((unsigned __int128)f << 16); + t[3] = (uint64_t)z & MASK52; + t[4] = (uint64_t)(z >> 52); + + /* + * t[4] may be up to 62 bits here; we need to do a + * partial reduction. Note that limbs t[0] to t[3] + * fit on 52 bits each. + */ + s = t[4] >> 48; /* s < 2^14 */ + t[0] += s; /* t[0] < 2^52 + 2^14 */ + w = t[1] - (s << 44); + t[1] = w & MASK52; /* t[1] < 2^52 */ + cc = -(w >> 52) & 0xFFF; /* cc < 16 */ + w = t[2] - cc; + t[2] = w & MASK52; /* t[2] < 2^52 */ + cc = w >> 63; /* cc = 0 or 1 */ + w = t[3] - cc - (s << 36); + t[3] = w & MASK52; /* t[3] < 2^52 */ + cc = w >> 63; /* cc = 0 or 1 */ + w = t[4] & MASK48; + t[4] = w + (s << 16) - cc; /* t[4] < 2^48 + 2^30 */ + + /* + * The final t[4] cannot overflow because cc is 0 or 1, + * and cc can be 1 only if s != 0. + */ + } + + d[0] = t[0]; + d[1] = t[1]; + d[2] = t[2]; + d[3] = t[3]; + d[4] = t[4]; + +#elif BR_UMUL128 + + int i; + uint64_t t[5]; + + t[0] = 0; + t[1] = 0; + t[2] = 0; + t[3] = 0; + t[4] = 0; + for (i = 0; i < 5; i ++) { + uint64_t x, f, cc, w, s, zh, zl; + unsigned char k; + + /* + * Since limbs of a[] and b[] fit on 56 bits each, + * each individual product fits on 112 bits. Also, + * the factor f fits on 52 bits, so f<<48 fits on + * 112 bits too. This guarantees that carries (cc) + * will fit on 62 bits, thus no overflow. + * + * The operations below compute: + * t <- (t + x*b + f*p) / 2^64 + */ + x = a[i]; + zl = _umul128(b[0], x, &zh); + k = _addcarry_u64(0, t[0], zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + f = zl & MASK52; + cc = (zl >> 52) | (zh << 12); + + zl = _umul128(b[1], x, &zh); + k = _addcarry_u64(0, t[1], zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + k = _addcarry_u64(0, cc, zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + k = _addcarry_u64(0, f << 44, zl, &zl); + (void)_addcarry_u64(k, f >> 20, zh, &zh); + t[0] = zl & MASK52; + cc = (zl >> 52) | (zh << 12); + + zl = _umul128(b[2], x, &zh); + k = _addcarry_u64(0, t[2], zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + k = _addcarry_u64(0, cc, zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + t[1] = zl & MASK52; + cc = (zl >> 52) | (zh << 12); + + zl = _umul128(b[3], x, &zh); + k = _addcarry_u64(0, t[3], zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + k = _addcarry_u64(0, cc, zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + k = _addcarry_u64(0, f << 36, zl, &zl); + (void)_addcarry_u64(k, f >> 28, zh, &zh); + t[2] = zl & MASK52; + cc = (zl >> 52) | (zh << 12); + + zl = _umul128(b[4], x, &zh); + k = _addcarry_u64(0, t[4], zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + k = _addcarry_u64(0, cc, zl, &zl); + (void)_addcarry_u64(k, 0, zh, &zh); + k = _addcarry_u64(0, f << 48, zl, &zl); + (void)_addcarry_u64(k, f >> 16, zh, &zh); + k = _subborrow_u64(0, zl, f << 16, &zl); + (void)_subborrow_u64(k, zh, f >> 48, &zh); + t[3] = zl & MASK52; + t[4] = (zl >> 52) | (zh << 12); + + /* + * t[4] may be up to 62 bits here; we need to do a + * partial reduction. Note that limbs t[0] to t[3] + * fit on 52 bits each. + */ + s = t[4] >> 48; /* s < 2^14 */ + t[0] += s; /* t[0] < 2^52 + 2^14 */ + w = t[1] - (s << 44); + t[1] = w & MASK52; /* t[1] < 2^52 */ + cc = -(w >> 52) & 0xFFF; /* cc < 16 */ + w = t[2] - cc; + t[2] = w & MASK52; /* t[2] < 2^52 */ + cc = w >> 63; /* cc = 0 or 1 */ + w = t[3] - cc - (s << 36); + t[3] = w & MASK52; /* t[3] < 2^52 */ + cc = w >> 63; /* cc = 0 or 1 */ + w = t[4] & MASK48; + t[4] = w + (s << 16) - cc; /* t[4] < 2^48 + 2^30 */ + + /* + * The final t[4] cannot overflow because cc is 0 or 1, + * and cc can be 1 only if s != 0. + */ + } + + d[0] = t[0]; + d[1] = t[1]; + d[2] = t[2]; + d[3] = t[3]; + d[4] = t[4]; + +#endif +} + +/* + * Montgomery squaring in the field; currently a basic wrapper around + * multiplication (inline, should be optimized away). + * TODO: see if some extra speed can be gained here. + */ +static inline void +f256_montysquare(uint64_t *d, const uint64_t *a) +{ + f256_montymul(d, a, a); +} + +/* + * Convert to Montgomery representation. + */ +static void +f256_tomonty(uint64_t *d, const uint64_t *a) +{ + /* + * R2 = 2^520 mod p. + * If R = 2^260 mod p, then R2 = R^2 mod p; and the Montgomery + * multiplication of a by R2 is: a*R2/R = a*R mod p, i.e. the + * conversion to Montgomery representation. + */ + static const uint64_t R2[] = { + 0x0000000000300, 0xFFFFFFFF00000, 0xFFFFEFFFFFFFB, + 0xFDFFFFFFFFFFF, 0x0000004FFFFFF + }; + + f256_montymul(d, a, R2); +} + +/* + * Convert from Montgomery representation. + */ +static void +f256_frommonty(uint64_t *d, const uint64_t *a) +{ + /* + * Montgomery multiplication by 1 is division by 2^260 modulo p. + */ + static const uint64_t one[] = { 1, 0, 0, 0, 0 }; + + f256_montymul(d, a, one); +} + +/* + * Inversion in the field. If the source value is 0 modulo p, then this + * returns 0 or p. This function uses Montgomery representation. + */ +static void +f256_invert(uint64_t *d, const uint64_t *a) +{ + /* + * We compute a^(p-2) mod p. The exponent pattern (from high to + * low) is: + * - 32 bits of value 1 + * - 31 bits of value 0 + * - 1 bit of value 1 + * - 96 bits of value 0 + * - 94 bits of value 1 + * - 1 bit of value 0 + * - 1 bit of value 1 + * To speed up the square-and-multiply algorithm, we precompute + * a^(2^31-1). + */ + + uint64_t r[5], t[5]; + int i; + + memcpy(t, a, sizeof t); + for (i = 0; i < 30; i ++) { + f256_montysquare(t, t); + f256_montymul(t, t, a); + } + + memcpy(r, t, sizeof t); + for (i = 224; i >= 0; i --) { + f256_montysquare(r, r); + switch (i) { + case 0: + case 2: + case 192: + case 224: + f256_montymul(r, r, a); + break; + case 3: + case 34: + case 65: + f256_montymul(r, r, t); + break; + } + } + memcpy(d, r, sizeof r); +} + +/* + * Finalize reduction. + * Input value should be partially reduced. + * On output, limbs a[0] to a[3] fit on 52 bits each, limb a[4] fits + * on 48 bits, and the integer is less than p. + */ +static inline void +f256_final_reduce(uint64_t *a) +{ + uint64_t r[5], t[5], w, cc; + int i; + + /* + * Propagate carries to ensure that limbs 0 to 3 fit on 52 bits. + */ + cc = 0; + for (i = 0; i < 5; i ++) { + w = a[i] + cc; + r[i] = w & MASK52; + cc = w >> 52; + } + + /* + * We compute t = r + (2^256 - p) = r + 2^224 - 2^192 - 2^96 + 1. + * If t < 2^256, then r < p, and we return r. Otherwise, we + * want to return r - p = t - 2^256. + */ + + /* + * Add 2^224 + 1, and propagate carries to ensure that limbs + * t[0] to t[3] fit in 52 bits each. + */ + w = r[0] + 1; + t[0] = w & MASK52; + cc = w >> 52; + w = r[1] + cc; + t[1] = w & MASK52; + cc = w >> 52; + w = r[2] + cc; + t[2] = w & MASK52; + cc = w >> 52; + w = r[3] + cc; + t[3] = w & MASK52; + cc = w >> 52; + t[4] = r[4] + cc + BIT(16); + + /* + * Subtract 2^192 + 2^96. Since we just added 2^224 + 1, the + * result cannot be negative. + */ + w = t[1] - BIT(44); + t[1] = w & MASK52; + cc = w >> 63; + w = t[2] - cc; + t[2] = w & MASK52; + cc = w >> 63; + w = t[3] - BIT(36) - cc; + t[3] = w & MASK52; + cc = w >> 63; + t[4] -= cc; + + /* + * If the top limb t[4] fits on 48 bits, then r[] is already + * in the proper range. Otherwise, t[] is the value to return + * (truncated to 256 bits). + */ + cc = -(t[4] >> 48); + t[4] &= MASK48; + for (i = 0; i < 5; i ++) { + a[i] = r[i] ^ (cc & (r[i] ^ t[i])); + } +} + +/* + * Points in affine and Jacobian coordinates. + * + * - In affine coordinates, the point-at-infinity cannot be encoded. + * - Jacobian coordinates (X,Y,Z) correspond to affine (X/Z^2,Y/Z^3); + * if Z = 0 then this is the point-at-infinity. + */ +typedef struct { + uint64_t x[5]; + uint64_t y[5]; +} p256_affine; + +typedef struct { + uint64_t x[5]; + uint64_t y[5]; + uint64_t z[5]; +} p256_jacobian; + +/* + * Decode a field element (unsigned big endian notation). + */ +static void +f256_decode(uint64_t *a, const unsigned char *buf) +{ + uint64_t w0, w1, w2, w3; + + w3 = br_dec64be(buf + 0); + w2 = br_dec64be(buf + 8); + w1 = br_dec64be(buf + 16); + w0 = br_dec64be(buf + 24); + a[0] = w0 & MASK52; + a[1] = ((w0 >> 52) | (w1 << 12)) & MASK52; + a[2] = ((w1 >> 40) | (w2 << 24)) & MASK52; + a[3] = ((w2 >> 28) | (w3 << 36)) & MASK52; + a[4] = w3 >> 16; +} + +/* + * Encode a field element (unsigned big endian notation). The field + * element MUST be fully reduced. + */ +static void +f256_encode(unsigned char *buf, const uint64_t *a) +{ + uint64_t w0, w1, w2, w3; + + w0 = a[0] | (a[1] << 52); + w1 = (a[1] >> 12) | (a[2] << 40); + w2 = (a[2] >> 24) | (a[3] << 28); + w3 = (a[3] >> 36) | (a[4] << 16); + br_enc64be(buf + 0, w3); + br_enc64be(buf + 8, w2); + br_enc64be(buf + 16, w1); + br_enc64be(buf + 24, w0); +} + +/* + * Decode a point. The returned point is in Jacobian coordinates, but + * with z = 1. If the encoding is invalid, or encodes a point which is + * not on the curve, or encodes the point at infinity, then this function + * returns 0. Otherwise, 1 is returned. + * + * The buffer is assumed to have length exactly 65 bytes. + */ +static uint32_t +point_decode(p256_jacobian *P, const unsigned char *buf) +{ + uint64_t x[5], y[5], t[5], x3[5], tt; + uint32_t r; + + /* + * Header byte shall be 0x04. + */ + r = EQ(buf[0], 0x04); + + /* + * Decode X and Y coordinates, and convert them into + * Montgomery representation. + */ + f256_decode(x, buf + 1); + f256_decode(y, buf + 33); + f256_tomonty(x, x); + f256_tomonty(y, y); + + /* + * Verify y^2 = x^3 + A*x + B. In curve P-256, A = -3. + * Note that the Montgomery representation of 0 is 0. We must + * take care to apply the final reduction to make sure we have + * 0 and not p. + */ + f256_montysquare(t, y); + f256_montysquare(x3, x); + f256_montymul(x3, x3, x); + f256_sub(t, t, x3); + f256_add(t, t, x); + f256_add(t, t, x); + f256_add(t, t, x); + f256_sub(t, t, P256_B_MONTY); + f256_final_reduce(t); + tt = t[0] | t[1] | t[2] | t[3] | t[4]; + r &= EQ((uint32_t)(tt | (tt >> 32)), 0); + + /* + * Return the point in Jacobian coordinates (and Montgomery + * representation). + */ + memcpy(P->x, x, sizeof x); + memcpy(P->y, y, sizeof y); + memcpy(P->z, F256_R, sizeof F256_R); + return r; +} + +/* + * Final conversion for a point: + * - The point is converted back to affine coordinates. + * - Final reduction is performed. + * - The point is encoded into the provided buffer. + * + * If the point is the point-at-infinity, all operations are performed, + * but the buffer contents are indeterminate, and 0 is returned. Otherwise, + * the encoded point is written in the buffer, and 1 is returned. + */ +static uint32_t +point_encode(unsigned char *buf, const p256_jacobian *P) +{ + uint64_t t1[5], t2[5], z; + + /* Set t1 = 1/z^2 and t2 = 1/z^3. */ + f256_invert(t2, P->z); + f256_montysquare(t1, t2); + f256_montymul(t2, t2, t1); + + /* Compute affine coordinates x (in t1) and y (in t2). */ + f256_montymul(t1, P->x, t1); + f256_montymul(t2, P->y, t2); + + /* Convert back from Montgomery representation, and finalize + reductions. */ + f256_frommonty(t1, t1); + f256_frommonty(t2, t2); + f256_final_reduce(t1); + f256_final_reduce(t2); + + /* Encode. */ + buf[0] = 0x04; + f256_encode(buf + 1, t1); + f256_encode(buf + 33, t2); + + /* Return success if and only if P->z != 0. */ + z = P->z[0] | P->z[1] | P->z[2] | P->z[3] | P->z[4]; + return NEQ((uint32_t)(z | z >> 32), 0); +} + +/* + * Point doubling in Jacobian coordinates: point P is doubled. + * Note: if the source point is the point-at-infinity, then the result is + * still the point-at-infinity, which is correct. Moreover, if the three + * coordinates were zero, then they still are zero in the returned value. + */ +static void +p256_double(p256_jacobian *P) +{ + /* + * Doubling formulas are: + * + * s = 4*x*y^2 + * m = 3*(x + z^2)*(x - z^2) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y^4 + * z' = 2*y*z + * + * These formulas work for all points, including points of order 2 + * and points at infinity: + * - If y = 0 then z' = 0. But there is no such point in P-256 + * anyway. + * - If z = 0 then z' = 0. + */ + uint64_t t1[5], t2[5], t3[5], t4[5]; + + /* + * Compute z^2 in t1. + */ + f256_montysquare(t1, P->z); + + /* + * Compute x-z^2 in t2 and x+z^2 in t1. + */ + f256_add(t2, P->x, t1); + f256_sub(t1, P->x, t1); + + /* + * Compute 3*(x+z^2)*(x-z^2) in t1. + */ + f256_montymul(t3, t1, t2); + f256_add(t1, t3, t3); + f256_add(t1, t3, t1); + + /* + * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3). + */ + f256_montysquare(t3, P->y); + f256_add(t3, t3, t3); + f256_montymul(t2, P->x, t3); + f256_add(t2, t2, t2); + + /* + * Compute x' = m^2 - 2*s. + */ + f256_montysquare(P->x, t1); + f256_sub(P->x, P->x, t2); + f256_sub(P->x, P->x, t2); + + /* + * Compute z' = 2*y*z. + */ + f256_montymul(t4, P->y, P->z); + f256_add(P->z, t4, t4); + f256_partial_reduce(P->z); + + /* + * Compute y' = m*(s - x') - 8*y^4. Note that we already have + * 2*y^2 in t3. + */ + f256_sub(t2, t2, P->x); + f256_montymul(P->y, t1, t2); + f256_montysquare(t4, t3); + f256_add(t4, t4, t4); + f256_sub(P->y, P->y, t4); +} + +/* + * Point addition (Jacobian coordinates): P1 is replaced with P1+P2. + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 but P2 != 0 + * - If P1 != 0 but P2 == 0 + * - If P1 == P2 + * + * In all three cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y coordinate. + * - P1 == 0 and P2 == 0. + * - The Y coordinate of one of the points is 0 and the other point is + * the point at infinity. + * + * The third case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + * + * Note that you can get a returned value of 0 with a correct result, + * e.g. if P1 and P2 have the same Y coordinate, but distinct X coordinates. + */ +static uint32_t +p256_add(p256_jacobian *P1, const p256_jacobian *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 * z2^2 + * u2 = x2 * z1^2 + * s1 = y1 * z2^3 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 * z2 + */ + uint64_t t1[5], t2[5], t3[5], t4[5], t5[5], t6[5], t7[5], tt; + uint32_t ret; + + /* + * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). + */ + f256_montysquare(t3, P2->z); + f256_montymul(t1, P1->x, t3); + f256_montymul(t4, P2->z, t3); + f256_montymul(t3, P1->y, t4); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + f256_montysquare(t4, P1->z); + f256_montymul(t2, P2->x, t4); + f256_montymul(t5, P1->z, t4); + f256_montymul(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + f256_sub(t2, t2, t1); + f256_sub(t4, t4, t3); + f256_final_reduce(t4); + tt = t4[0] | t4[1] | t4[2] | t4[3] | t4[4]; + ret = (uint32_t)(tt | (tt >> 32)); + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + f256_montysquare(t7, t2); + f256_montymul(t6, t1, t7); + f256_montymul(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + f256_montysquare(P1->x, t4); + f256_sub(P1->x, P1->x, t5); + f256_sub(P1->x, P1->x, t6); + f256_sub(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + f256_sub(t6, t6, P1->x); + f256_montymul(P1->y, t4, t6); + f256_montymul(t1, t5, t3); + f256_sub(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1*z2. + */ + f256_montymul(t1, P1->z, P2->z); + f256_montymul(P1->z, t1, t2); + + return ret; +} + +/* + * Point addition (mixed coordinates): P1 is replaced with P1+P2. + * This is a specialised function for the case when P2 is a non-zero point + * in affine coordinates. + * + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 + * - If P1 == P2 + * + * In both cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y (affine) coordinate. + * - The Y coordinate of P2 is 0 and P1 is the point at infinity. + * + * The second case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + * + * Again, a value of 0 may be returned in some cases where the addition + * result is correct. + */ +static uint32_t +p256_add_mixed(p256_jacobian *P1, const p256_affine *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 + * u2 = x2 * z1^2 + * s1 = y1 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 + */ + uint64_t t1[5], t2[5], t3[5], t4[5], t5[5], t6[5], t7[5], tt; + uint32_t ret; + + /* + * Compute u1 = x1 (in t1) and s1 = y1 (in t3). + */ + memcpy(t1, P1->x, sizeof t1); + memcpy(t3, P1->y, sizeof t3); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + f256_montysquare(t4, P1->z); + f256_montymul(t2, P2->x, t4); + f256_montymul(t5, P1->z, t4); + f256_montymul(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + f256_sub(t2, t2, t1); + f256_sub(t4, t4, t3); + f256_final_reduce(t4); + tt = t4[0] | t4[1] | t4[2] | t4[3] | t4[4]; + ret = (uint32_t)(tt | (tt >> 32)); + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + f256_montysquare(t7, t2); + f256_montymul(t6, t1, t7); + f256_montymul(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + f256_montysquare(P1->x, t4); + f256_sub(P1->x, P1->x, t5); + f256_sub(P1->x, P1->x, t6); + f256_sub(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + f256_sub(t6, t6, P1->x); + f256_montymul(P1->y, t4, t6); + f256_montymul(t1, t5, t3); + f256_sub(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1*z2. + */ + f256_montymul(P1->z, P1->z, t2); + + return ret; +} + +#if 0 +/* unused */ +/* + * Point addition (mixed coordinates, complete): P1 is replaced with P1+P2. + * This is a specialised function for the case when P2 is a non-zero point + * in affine coordinates. + * + * This function returns the correct result in all cases. + */ +static uint32_t +p256_add_complete_mixed(p256_jacobian *P1, const p256_affine *P2) +{ + /* + * Addtions formulas, in the general case, are: + * + * u1 = x1 + * u2 = x2 * z1^2 + * s1 = y1 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 + * + * These formulas mishandle the two following cases: + * + * - If P1 is the point-at-infinity (z1 = 0), then z3 is + * incorrectly set to 0. + * + * - If P1 = P2, then u1 = u2 and s1 = s2, and x3, y3 and z3 + * are all set to 0. + * + * However, if P1 + P2 = 0, then u1 = u2 but s1 != s2, and then + * we correctly get z3 = 0 (the point-at-infinity). + * + * To fix the case P1 = 0, we perform at the end a copy of P2 + * over P1, conditional to z1 = 0. + * + * For P1 = P2: in that case, both h and r are set to 0, and + * we get x3, y3 and z3 equal to 0. We can test for that + * occurrence to make a mask which will be all-one if P1 = P2, + * or all-zero otherwise; then we can compute the double of P2 + * and add it, combined with the mask, to (x3,y3,z3). + * + * Using the doubling formulas in p256_double() on (x2,y2), + * simplifying since P2 is affine (i.e. z2 = 1, implicitly), + * we get: + * s = 4*x2*y2^2 + * m = 3*(x2 + 1)*(x2 - 1) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y2^4 + * z' = 2*y2 + * which requires only 6 multiplications. Added to the 11 + * multiplications of the normal mixed addition in Jacobian + * coordinates, we get a cost of 17 multiplications in total. + */ + uint64_t t1[5], t2[5], t3[5], t4[5], t5[5], t6[5], t7[5], tt, zz; + int i; + + /* + * Set zz to -1 if P1 is the point at infinity, 0 otherwise. + */ + zz = P1->z[0] | P1->z[1] | P1->z[2] | P1->z[3] | P1->z[4]; + zz = ((zz | -zz) >> 63) - (uint64_t)1; + + /* + * Compute u1 = x1 (in t1) and s1 = y1 (in t3). + */ + memcpy(t1, P1->x, sizeof t1); + memcpy(t3, P1->y, sizeof t3); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + f256_montysquare(t4, P1->z); + f256_montymul(t2, P2->x, t4); + f256_montymul(t5, P1->z, t4); + f256_montymul(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * reduce. + */ + f256_sub(t2, t2, t1); + f256_sub(t4, t4, t3); + + /* + * If both h = 0 and r = 0, then P1 = P2, and we want to set + * the mask tt to -1; otherwise, the mask will be 0. + */ + f256_final_reduce(t2); + f256_final_reduce(t4); + tt = t2[0] | t2[1] | t2[2] | t2[3] | t2[4] + | t4[0] | t4[1] | t4[2] | t4[3] | t4[4]; + tt = ((tt | -tt) >> 63) - (uint64_t)1; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + f256_montysquare(t7, t2); + f256_montymul(t6, t1, t7); + f256_montymul(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + f256_montysquare(P1->x, t4); + f256_sub(P1->x, P1->x, t5); + f256_sub(P1->x, P1->x, t6); + f256_sub(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + f256_sub(t6, t6, P1->x); + f256_montymul(P1->y, t4, t6); + f256_montymul(t1, t5, t3); + f256_sub(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1. + */ + f256_montymul(P1->z, P1->z, t2); + + /* + * The "double" result, in case P1 = P2. + */ + + /* + * Compute z' = 2*y2 (in t1). + */ + f256_add(t1, P2->y, P2->y); + f256_partial_reduce(t1); + + /* + * Compute 2*(y2^2) (in t2) and s = 4*x2*(y2^2) (in t3). + */ + f256_montysquare(t2, P2->y); + f256_add(t2, t2, t2); + f256_add(t3, t2, t2); + f256_montymul(t3, P2->x, t3); + + /* + * Compute m = 3*(x2^2 - 1) (in t4). + */ + f256_montysquare(t4, P2->x); + f256_sub(t4, t4, F256_R); + f256_add(t5, t4, t4); + f256_add(t4, t4, t5); + + /* + * Compute x' = m^2 - 2*s (in t5). + */ + f256_montysquare(t5, t4); + f256_sub(t5, t3); + f256_sub(t5, t3); + + /* + * Compute y' = m*(s - x') - 8*y2^4 (in t6). + */ + f256_sub(t6, t3, t5); + f256_montymul(t6, t6, t4); + f256_montysquare(t7, t2); + f256_sub(t6, t6, t7); + f256_sub(t6, t6, t7); + + /* + * We now have the alternate (doubling) coordinates in (t5,t6,t1). + * We combine them with (x3,y3,z3). + */ + for (i = 0; i < 5; i ++) { + P1->x[i] |= tt & t5[i]; + P1->y[i] |= tt & t6[i]; + P1->z[i] |= tt & t1[i]; + } + + /* + * If P1 = 0, then we get z3 = 0 (which is invalid); if z1 is 0, + * then we want to replace the result with a copy of P2. The + * test on z1 was done at the start, in the zz mask. + */ + for (i = 0; i < 5; i ++) { + P1->x[i] ^= zz & (P1->x[i] ^ P2->x[i]); + P1->y[i] ^= zz & (P1->y[i] ^ P2->y[i]); + P1->z[i] ^= zz & (P1->z[i] ^ F256_R[i]); + } +} +#endif + +/* + * Inner function for computing a point multiplication. A window is + * provided, with points 1*P to 15*P in affine coordinates. + * + * Assumptions: + * - All provided points are valid points on the curve. + * - Multiplier is non-zero, and smaller than the curve order. + * - Everything is in Montgomery representation. + */ +static void +point_mul_inner(p256_jacobian *R, const p256_affine *W, + const unsigned char *k, size_t klen) +{ + p256_jacobian Q; + uint32_t qz; + + memset(&Q, 0, sizeof Q); + qz = 1; + while (klen -- > 0) { + int i; + unsigned bk; + + bk = *k ++; + for (i = 0; i < 2; i ++) { + uint32_t bits; + uint32_t bnz; + p256_affine T; + p256_jacobian U; + uint32_t n; + int j; + uint64_t m; + + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + bits = (bk >> 4) & 0x0F; + bnz = NEQ(bits, 0); + + /* + * Lookup point in window. If the bits are 0, + * we get something invalid, which is not a + * problem because we will use it only if the + * bits are non-zero. + */ + memset(&T, 0, sizeof T); + for (n = 0; n < 15; n ++) { + m = -(uint64_t)EQ(bits, n + 1); + T.x[0] |= m & W[n].x[0]; + T.x[1] |= m & W[n].x[1]; + T.x[2] |= m & W[n].x[2]; + T.x[3] |= m & W[n].x[3]; + T.x[4] |= m & W[n].x[4]; + T.y[0] |= m & W[n].y[0]; + T.y[1] |= m & W[n].y[1]; + T.y[2] |= m & W[n].y[2]; + T.y[3] |= m & W[n].y[3]; + T.y[4] |= m & W[n].y[4]; + } + + U = Q; + p256_add_mixed(&U, &T); + + /* + * If qz is still 1, then Q was all-zeros, and this + * is conserved through p256_double(). + */ + m = -(uint64_t)(bnz & qz); + for (j = 0; j < 5; j ++) { + Q.x[j] ^= m & (Q.x[j] ^ T.x[j]); + Q.y[j] ^= m & (Q.y[j] ^ T.y[j]); + Q.z[j] ^= m & (Q.z[j] ^ F256_R[j]); + } + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + bk <<= 4; + } + } + *R = Q; +} + +/* + * Convert a window from Jacobian to affine coordinates. A single + * field inversion is used. This function works for windows up to + * 32 elements. + * + * The destination array (aff[]) and the source array (jac[]) may + * overlap, provided that the start of aff[] is not after the start of + * jac[]. Even if the arrays do _not_ overlap, the source array is + * modified. + */ +static void +window_to_affine(p256_affine *aff, p256_jacobian *jac, int num) +{ + /* + * Convert the window points to affine coordinates. We use the + * following trick to mutualize the inversion computation: if + * we have z1, z2, z3, and z4, and want to invert all of them, + * we compute u = 1/(z1*z2*z3*z4), and then we have: + * 1/z1 = u*z2*z3*z4 + * 1/z2 = u*z1*z3*z4 + * 1/z3 = u*z1*z2*z4 + * 1/z4 = u*z1*z2*z3 + * + * The partial products are computed recursively: + * + * - on input (z_1,z_2), return (z_2,z_1) and z_1*z_2 + * - on input (z_1,z_2,... z_n): + * recurse on (z_1,z_2,... z_(n/2)) -> r1 and m1 + * recurse on (z_(n/2+1),z_(n/2+2)... z_n) -> r2 and m2 + * multiply elements of r1 by m2 -> s1 + * multiply elements of r2 by m1 -> s2 + * return r1||r2 and m1*m2 + * + * In the example below, we suppose that we have 14 elements. + * Let z1, z2,... zE be the 14 values to invert (index noted in + * hexadecimal, starting at 1). + * + * - Depth 1: + * swap(z1, z2); z12 = z1*z2 + * swap(z3, z4); z34 = z3*z4 + * swap(z5, z6); z56 = z5*z6 + * swap(z7, z8); z78 = z7*z8 + * swap(z9, zA); z9A = z9*zA + * swap(zB, zC); zBC = zB*zC + * swap(zD, zE); zDE = zD*zE + * + * - Depth 2: + * z1 <- z1*z34, z2 <- z2*z34, z3 <- z3*z12, z4 <- z4*z12 + * z1234 = z12*z34 + * z5 <- z5*z78, z6 <- z6*z78, z7 <- z7*z56, z8 <- z8*z56 + * z5678 = z56*z78 + * z9 <- z9*zBC, zA <- zA*zBC, zB <- zB*z9A, zC <- zC*z9A + * z9ABC = z9A*zBC + * + * - Depth 3: + * z1 <- z1*z5678, z2 <- z2*z5678, z3 <- z3*z5678, z4 <- z4*z5678 + * z5 <- z5*z1234, z6 <- z6*z1234, z7 <- z7*z1234, z8 <- z8*z1234 + * z12345678 = z1234*z5678 + * z9 <- z9*zDE, zA <- zA*zDE, zB <- zB*zDE, zC <- zC*zDE + * zD <- zD*z9ABC, zE*z9ABC + * z9ABCDE = z9ABC*zDE + * + * - Depth 4: + * multiply z1..z8 by z9ABCDE + * multiply z9..zE by z12345678 + * final z = z12345678*z9ABCDE + */ + + uint64_t z[16][5]; + int i, k, s; +#define zt (z[15]) +#define zu (z[14]) +#define zv (z[13]) + + /* + * First recursion step (pairwise swapping and multiplication). + * If there is an odd number of elements, then we "invent" an + * extra one with coordinate Z = 1 (in Montgomery representation). + */ + for (i = 0; (i + 1) < num; i += 2) { + memcpy(zt, jac[i].z, sizeof zt); + memcpy(jac[i].z, jac[i + 1].z, sizeof zt); + memcpy(jac[i + 1].z, zt, sizeof zt); + f256_montymul(z[i >> 1], jac[i].z, jac[i + 1].z); + } + if ((num & 1) != 0) { + memcpy(z[num >> 1], jac[num - 1].z, sizeof zt); + memcpy(jac[num - 1].z, F256_R, sizeof F256_R); + } + + /* + * Perform further recursion steps. At the entry of each step, + * the process has been done for groups of 's' points. The + * integer k is the log2 of s. + */ + for (k = 1, s = 2; s < num; k ++, s <<= 1) { + int n; + + for (i = 0; i < num; i ++) { + f256_montymul(jac[i].z, jac[i].z, z[(i >> k) ^ 1]); + } + n = (num + s - 1) >> k; + for (i = 0; i < (n >> 1); i ++) { + f256_montymul(z[i], z[i << 1], z[(i << 1) + 1]); + } + if ((n & 1) != 0) { + memmove(z[n >> 1], z[n], sizeof zt); + } + } + + /* + * Invert the final result, and convert all points. + */ + f256_invert(zt, z[0]); + for (i = 0; i < num; i ++) { + f256_montymul(zv, jac[i].z, zt); + f256_montysquare(zu, zv); + f256_montymul(zv, zv, zu); + f256_montymul(aff[i].x, jac[i].x, zu); + f256_montymul(aff[i].y, jac[i].y, zv); + } +} + +/* + * Multiply the provided point by an integer. + * Assumptions: + * - Source point is a valid curve point. + * - Source point is not the point-at-infinity. + * - Integer is not 0, and is lower than the curve order. + * If these conditions are not met, then the result is indeterminate + * (but the process is still constant-time). + */ +static void +p256_mul(p256_jacobian *P, const unsigned char *k, size_t klen) +{ + union { + p256_affine aff[15]; + p256_jacobian jac[15]; + } window; + int i; + + /* + * Compute window, in Jacobian coordinates. + */ + window.jac[0] = *P; + for (i = 2; i < 16; i ++) { + window.jac[i - 1] = window.jac[(i >> 1) - 1]; + if ((i & 1) == 0) { + p256_double(&window.jac[i - 1]); + } else { + p256_add(&window.jac[i - 1], &window.jac[i >> 1]); + } + } + + /* + * Convert the window points to affine coordinates. Point + * window[0] is the source point, already in affine coordinates. + */ + window_to_affine(window.aff, window.jac, 15); + + /* + * Perform point multiplication. + */ + point_mul_inner(P, window.aff, k, klen); +} + +/* + * Precomputed window for the conventional generator: P256_Gwin[n] + * contains (n+1)*G (affine coordinates, in Montgomery representation). + */ +static const p256_affine P256_Gwin[] = { + { + { 0x30D418A9143C1, 0xC4FEDB60179E7, 0x62251075BA95F, + 0x5C669FB732B77, 0x08905F76B5375 }, + { 0x5357CE95560A8, 0x43A19E45CDDF2, 0x21F3258B4AB8E, + 0xD8552E88688DD, 0x0571FF18A5885 } + }, + { + { 0x46D410DDD64DF, 0x0B433827D8500, 0x1490D9AA6AE3C, + 0xA3A832205038D, 0x06BB32E52DCF3 }, + { 0x48D361BEE1A57, 0xB7B236FF82F36, 0x042DBE152CD7C, + 0xA3AA9A8FB0E92, 0x08C577517A5B8 } + }, + { + { 0x3F904EEBC1272, 0x9E87D81FBFFAC, 0xCBBC98B027F84, + 0x47E46AD77DD87, 0x06936A3FD6FF7 }, + { 0x5C1FC983A7EBD, 0xC3861FE1AB04C, 0x2EE98E583E47A, + 0xC06A88208311A, 0x05F06A2AB587C } + }, + { + { 0xB50D46918DCC5, 0xD7623C17374B0, 0x100AF24650A6E, + 0x76ABCDAACACE8, 0x077362F591B01 }, + { 0xF24CE4CBABA68, 0x17AD6F4472D96, 0xDDD22E1762847, + 0x862EB6C36DEE5, 0x04B14C39CC5AB } + }, + { + { 0x8AAEC45C61F5C, 0x9D4B9537DBE1B, 0x76C20C90EC649, + 0x3C7D41CB5AAD0, 0x0907960649052 }, + { 0x9B4AE7BA4F107, 0xF75EB882BEB30, 0x7A1F6873C568E, + 0x915C540A9877E, 0x03A076BB9DD1E } + }, + { + { 0x47373E77664A1, 0xF246CEE3E4039, 0x17A3AD55AE744, + 0x673C50A961A5B, 0x03074B5964213 }, + { 0x6220D377E44BA, 0x30DFF14B593D3, 0x639F11299C2B5, + 0x75F5424D44CEF, 0x04C9916DEA07F } + }, + { + { 0x354EA0173B4F1, 0x3C23C00F70746, 0x23BB082BD2021, + 0xE03E43EAAB50C, 0x03BA5119D3123 }, + { 0xD0303F5B9D4DE, 0x17DA67BDD2847, 0xC941956742F2F, + 0x8670F933BDC77, 0x0AEDD9164E240 } + }, + { + { 0x4CD19499A78FB, 0x4BF9B345527F1, 0x2CFC6B462AB5C, + 0x30CDF90F02AF0, 0x0763891F62652 }, + { 0xA3A9532D49775, 0xD7F9EBA15F59D, 0x60BBF021E3327, + 0xF75C23C7B84BE, 0x06EC12F2C706D } + }, + { + { 0x6E8F264E20E8E, 0xC79A7A84175C9, 0xC8EB00ABE6BFE, + 0x16A4CC09C0444, 0x005B3081D0C4E }, + { 0x777AA45F33140, 0xDCE5D45E31EB7, 0xB12F1A56AF7BE, + 0xF9B2B6E019A88, 0x086659CDFD835 } + }, + { + { 0xDBD19DC21EC8C, 0x94FCF81392C18, 0x250B4998F9868, + 0x28EB37D2CD648, 0x0C61C947E4B34 }, + { 0x407880DD9E767, 0x0C83FBE080C2B, 0x9BE5D2C43A899, + 0xAB4EF7D2D6577, 0x08719A555B3B4 } + }, + { + { 0x260A6245E4043, 0x53E7FDFE0EA7D, 0xAC1AB59DE4079, + 0x072EFF3A4158D, 0x0E7090F1949C9 }, + { 0x85612B944E886, 0xE857F61C81A76, 0xAD643D250F939, + 0x88DAC0DAA891E, 0x089300244125B } + }, + { + { 0x1AA7D26977684, 0x58A345A3304B7, 0x37385EABDEDEF, + 0x155E409D29DEE, 0x0EE1DF780B83E }, + { 0x12D91CBB5B437, 0x65A8956370CAC, 0xDE6D66170ED2F, + 0xAC9B8228CFA8A, 0x0FF57C95C3238 } + }, + { + { 0x25634B2ED7097, 0x9156FD30DCCC4, 0x9E98110E35676, + 0x7594CBCD43F55, 0x038477ACC395B }, + { 0x2B90C00EE17FF, 0xF842ED2E33575, 0x1F5BC16874838, + 0x7968CD06422BD, 0x0BC0876AB9E7B } + }, + { + { 0xA35BB0CF664AF, 0x68F9707E3A242, 0x832660126E48F, + 0x72D2717BF54C6, 0x0AAE7333ED12C }, + { 0x2DB7995D586B1, 0xE732237C227B5, 0x65E7DBBE29569, + 0xBBBD8E4193E2A, 0x052706DC3EAA1 } + }, + { + { 0xD8B7BC60055BE, 0xD76E27E4B72BC, 0x81937003CC23E, + 0xA090E337424E4, 0x02AA0E43EAD3D }, + { 0x524F6383C45D2, 0x422A41B2540B8, 0x8A4797D766355, + 0xDF444EFA6DE77, 0x0042170A9079A } + }, +}; + +/* + * Multiply the conventional generator of the curve by the provided + * integer. Return is written in *P. + * + * Assumptions: + * - Integer is not 0, and is lower than the curve order. + * If this conditions is not met, then the result is indeterminate + * (but the process is still constant-time). + */ +static void +p256_mulgen(p256_jacobian *P, const unsigned char *k, size_t klen) +{ + point_mul_inner(P, P256_Gwin, k, klen); +} + +/* + * Return 1 if all of the following hold: + * - klen <= 32 + * - k != 0 + * - k is lower than the curve order + * Otherwise, return 0. + * + * Constant-time behaviour: only klen may be observable. + */ +static uint32_t +check_scalar(const unsigned char *k, size_t klen) +{ + uint32_t z; + int32_t c; + size_t u; + + if (klen > 32) { + return 0; + } + z = 0; + for (u = 0; u < klen; u ++) { + z |= k[u]; + } + if (klen == 32) { + c = 0; + for (u = 0; u < klen; u ++) { + c |= -(int32_t)EQ0(c) & CMP(k[u], P256_N[u]); + } + } else { + c = -1; + } + return NEQ(z, 0) & LT0(c); +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *k, size_t klen, int curve) +{ + uint32_t r; + p256_jacobian P; + + (void)curve; + if (Glen != 65) { + return 0; + } + r = check_scalar(k, klen); + r &= point_decode(&P, G); + p256_mul(&P, k, klen); + r &= point_encode(G, &P); + return r; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *k, size_t klen, int curve) +{ + p256_jacobian P; + + (void)curve; + p256_mulgen(&P, k, klen); + point_encode(R, &P); + return 65; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We might want to use Shamir's trick here: make a composite + * window of u*P+v*Q points, to merge the two doubling-ladders + * into one. This, however, has some complications: + * + * - During the computation, we may hit the point-at-infinity. + * Thus, we would need p256_add_complete_mixed() (complete + * formulas for point addition), with a higher cost (17 muls + * instead of 11). + * + * - A 4-bit window would be too large, since it would involve + * 16*16-1 = 255 points. For the same window size as in the + * p256_mul() case, we would need to reduce the window size + * to 2 bits, and thus perform twice as many non-doubling + * point additions. + * + * - The window may itself contain the point-at-infinity, and + * thus cannot be in all generality be made of affine points. + * Instead, we would need to make it a window of points in + * Jacobian coordinates. Even p256_add_complete_mixed() would + * be inappropriate. + * + * For these reasons, the code below performs two separate + * point multiplications, then computes the final point addition + * (which is both a "normal" addition, and a doubling, to handle + * all cases). + */ + + p256_jacobian P, Q; + uint32_t r, t, s; + uint64_t z; + + (void)curve; + if (len != 65) { + return 0; + } + r = point_decode(&P, A); + p256_mul(&P, x, xlen); + if (B == NULL) { + p256_mulgen(&Q, y, ylen); + } else { + r &= point_decode(&Q, B); + p256_mul(&Q, y, ylen); + } + + /* + * The final addition may fail in case both points are equal. + */ + t = p256_add(&P, &Q); + f256_final_reduce(P.z); + z = P.z[0] | P.z[1] | P.z[2] | P.z[3] | P.z[4]; + s = EQ((uint32_t)(z | (z >> 32)), 0); + p256_double(&Q); + + /* + * If s is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we + * have the following: + * + * s = 0, t = 0 return P (normal addition) + * s = 0, t = 1 return P (normal addition) + * s = 1, t = 0 return Q (a 'double' case) + * s = 1, t = 1 report an error (P+Q = 0) + */ + CCOPY(s & ~t, &P, &Q, sizeof Q); + point_encode(A, &P); + r &= ~(s & t); + return r; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_p256_m62 = { + (uint32_t)0x00800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_p256_m62_get(void) +{ + return &br_ec_p256_m62; +} + +#else + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_p256_m62_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/ec/ec_p256_m64.c b/src/bearssl/src/ec/ec_p256_m64.c new file mode 100644 index 0000000..5a7ea17 --- /dev/null +++ b/src/bearssl/src/ec/ec_p256_m64.c @@ -0,0 +1,1730 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +#if BR_UMUL128 +#include +#endif + +static const unsigned char P256_G[] = { + 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, + 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, + 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, + 0x98, 0xC2, 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, + 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, + 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, + 0x68, 0x37, 0xBF, 0x51, 0xF5 +}; + +static const unsigned char P256_N[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, + 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, + 0x25, 0x51 +}; + +static const unsigned char * +api_generator(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_G; + return P256_G; +} + +static const unsigned char * +api_order(int curve, size_t *len) +{ + (void)curve; + *len = sizeof P256_N; + return P256_N; +} + +static size_t +api_xoff(int curve, size_t *len) +{ + (void)curve; + *len = 32; + return 1; +} + +/* + * A field element is encoded as four 64-bit integers, in basis 2^64. + * Values may reach up to 2^256-1. Montgomery multiplication is used. + */ + +/* R = 2^256 mod p */ +static const uint64_t F256_R[] = { + 0x0000000000000001, 0xFFFFFFFF00000000, + 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFE +}; + +/* Curve equation is y^2 = x^3 - 3*x + B. This constant is B*R mod p + (Montgomery representation of B). */ +static const uint64_t P256_B_MONTY[] = { + 0xD89CDF6229C4BDDF, 0xACF005CD78843090, + 0xE5A220ABF7212ED6, 0xDC30061D04874834 +}; + +/* + * Addition in the field. + */ +static inline void +f256_add(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ +#if BR_INT128 + unsigned __int128 w; + uint64_t t; + + w = (unsigned __int128)a[0] + b[0]; + d[0] = (uint64_t)w; + w = (unsigned __int128)a[1] + b[1] + (w >> 64); + d[1] = (uint64_t)w; + w = (unsigned __int128)a[2] + b[2] + (w >> 64); + d[2] = (uint64_t)w; + w = (unsigned __int128)a[3] + b[3] + (w >> 64); + d[3] = (uint64_t)w; + t = (uint64_t)(w >> 64); + + /* + * 2^256 = 2^224 - 2^192 - 2^96 + 1 in the field. + */ + w = (unsigned __int128)d[0] + t; + d[0] = (uint64_t)w; + w = (unsigned __int128)d[1] + (w >> 64) - (t << 32); + d[1] = (uint64_t)w; + /* Here, carry "w >> 64" can only be 0 or -1 */ + w = (unsigned __int128)d[2] - ((w >> 64) & 1); + d[2] = (uint64_t)w; + /* Again, carry is 0 or -1 */ + d[3] += (uint64_t)(w >> 64) + (t << 32) - t; + +#elif BR_UMUL128 + + unsigned char cc; + uint64_t t; + + cc = _addcarry_u64(0, a[0], b[0], &d[0]); + cc = _addcarry_u64(cc, a[1], b[1], &d[1]); + cc = _addcarry_u64(cc, a[2], b[2], &d[2]); + cc = _addcarry_u64(cc, a[3], b[3], &d[3]); + + /* + * If there is a carry, then we want to subtract p, which we + * do by adding 2^256 - p. + */ + t = cc; + cc = _addcarry_u64(cc, d[0], 0, &d[0]); + cc = _addcarry_u64(cc, d[1], -(t << 32), &d[1]); + cc = _addcarry_u64(cc, d[2], -t, &d[2]); + (void)_addcarry_u64(cc, d[3], (t << 32) - (t << 1), &d[3]); + +#endif +} + +/* + * Subtraction in the field. + */ +static inline void +f256_sub(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ +#if BR_INT128 + + unsigned __int128 w; + uint64_t t; + + w = (unsigned __int128)a[0] - b[0]; + d[0] = (uint64_t)w; + w = (unsigned __int128)a[1] - b[1] - ((w >> 64) & 1); + d[1] = (uint64_t)w; + w = (unsigned __int128)a[2] - b[2] - ((w >> 64) & 1); + d[2] = (uint64_t)w; + w = (unsigned __int128)a[3] - b[3] - ((w >> 64) & 1); + d[3] = (uint64_t)w; + t = (uint64_t)(w >> 64) & 1; + + /* + * p = 2^256 - 2^224 + 2^192 + 2^96 - 1. + */ + w = (unsigned __int128)d[0] - t; + d[0] = (uint64_t)w; + w = (unsigned __int128)d[1] + (t << 32) - ((w >> 64) & 1); + d[1] = (uint64_t)w; + /* Here, carry "w >> 64" can only be 0 or +1 */ + w = (unsigned __int128)d[2] + (w >> 64); + d[2] = (uint64_t)w; + /* Again, carry is 0 or +1 */ + d[3] += (uint64_t)(w >> 64) - (t << 32) + t; + +#elif BR_UMUL128 + + unsigned char cc; + uint64_t t; + + cc = _subborrow_u64(0, a[0], b[0], &d[0]); + cc = _subborrow_u64(cc, a[1], b[1], &d[1]); + cc = _subborrow_u64(cc, a[2], b[2], &d[2]); + cc = _subborrow_u64(cc, a[3], b[3], &d[3]); + + /* + * If there is a carry, then we need to add p. + */ + t = cc; + cc = _addcarry_u64(0, d[0], -t, &d[0]); + cc = _addcarry_u64(cc, d[1], (-t) >> 32, &d[1]); + cc = _addcarry_u64(cc, d[2], 0, &d[2]); + (void)_addcarry_u64(cc, d[3], t - (t << 32), &d[3]); + +#endif +} + +/* + * Montgomery multiplication in the field. + */ +static void +f256_montymul(uint64_t *d, const uint64_t *a, const uint64_t *b) +{ +#if BR_INT128 + + uint64_t x, f, t0, t1, t2, t3, t4; + unsigned __int128 z, ff; + int i; + + /* + * When computing d <- d + a[u]*b, we also add f*p such + * that d + a[u]*b + f*p is a multiple of 2^64. Since + * p = -1 mod 2^64, we can compute f = d[0] + a[u]*b[0] mod 2^64. + */ + + /* + * Step 1: t <- (a[0]*b + f*p) / 2^64 + * We have f = a[0]*b[0] mod 2^64. Since p = -1 mod 2^64, this + * ensures that (a[0]*b + f*p) is a multiple of 2^64. + * + * We also have: f*p = f*2^256 - f*2^224 + f*2^192 + f*2^96 - f. + */ + x = a[0]; + z = (unsigned __int128)b[0] * x; + f = (uint64_t)z; + z = (unsigned __int128)b[1] * x + (z >> 64) + (uint64_t)(f << 32); + t0 = (uint64_t)z; + z = (unsigned __int128)b[2] * x + (z >> 64) + (uint64_t)(f >> 32); + t1 = (uint64_t)z; + z = (unsigned __int128)b[3] * x + (z >> 64) + f; + t2 = (uint64_t)z; + t3 = (uint64_t)(z >> 64); + ff = ((unsigned __int128)f << 64) - ((unsigned __int128)f << 32); + z = (unsigned __int128)t2 + (uint64_t)ff; + t2 = (uint64_t)z; + z = (unsigned __int128)t3 + (z >> 64) + (ff >> 64); + t3 = (uint64_t)z; + t4 = (uint64_t)(z >> 64); + + /* + * Steps 2 to 4: t <- (t + a[i]*b + f*p) / 2^64 + */ + for (i = 1; i < 4; i ++) { + x = a[i]; + + /* t <- (t + x*b - f) / 2^64 */ + z = (unsigned __int128)b[0] * x + t0; + f = (uint64_t)z; + z = (unsigned __int128)b[1] * x + t1 + (z >> 64); + t0 = (uint64_t)z; + z = (unsigned __int128)b[2] * x + t2 + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)b[3] * x + t3 + (z >> 64); + t2 = (uint64_t)z; + z = t4 + (z >> 64); + t3 = (uint64_t)z; + t4 = (uint64_t)(z >> 64); + + /* t <- t + f*2^32, carry in the upper half of z */ + z = (unsigned __int128)t0 + (uint64_t)(f << 32); + t0 = (uint64_t)z; + z = (z >> 64) + (unsigned __int128)t1 + (uint64_t)(f >> 32); + t1 = (uint64_t)z; + + /* t <- t + f*2^192 - f*2^160 + f*2^128 */ + ff = ((unsigned __int128)f << 64) + - ((unsigned __int128)f << 32) + f; + z = (z >> 64) + (unsigned __int128)t2 + (uint64_t)ff; + t2 = (uint64_t)z; + z = (unsigned __int128)t3 + (z >> 64) + (ff >> 64); + t3 = (uint64_t)z; + t4 += (uint64_t)(z >> 64); + } + + /* + * At that point, we have computed t = (a*b + F*p) / 2^256, where + * F is a 256-bit integer whose limbs are the "f" coefficients + * in the steps above. We have: + * a <= 2^256-1 + * b <= 2^256-1 + * F <= 2^256-1 + * Hence: + * a*b + F*p <= (2^256-1)*(2^256-1) + p*(2^256-1) + * a*b + F*p <= 2^256*(2^256 - 2 + p) + 1 - p + * Therefore: + * t < 2^256 + p - 2 + * Since p < 2^256, it follows that: + * t4 can be only 0 or 1 + * t - p < 2^256 + * We can therefore subtract p from t, conditionally on t4, to + * get a nonnegative result that fits on 256 bits. + */ + z = (unsigned __int128)t0 + t4; + t0 = (uint64_t)z; + z = (unsigned __int128)t1 - (t4 << 32) + (z >> 64); + t1 = (uint64_t)z; + z = (unsigned __int128)t2 - (z >> 127); + t2 = (uint64_t)z; + t3 = t3 - (uint64_t)(z >> 127) - t4 + (t4 << 32); + + d[0] = t0; + d[1] = t1; + d[2] = t2; + d[3] = t3; + +#elif BR_UMUL128 + + uint64_t x, f, t0, t1, t2, t3, t4; + uint64_t zl, zh, ffl, ffh; + unsigned char k, m; + int i; + + /* + * When computing d <- d + a[u]*b, we also add f*p such + * that d + a[u]*b + f*p is a multiple of 2^64. Since + * p = -1 mod 2^64, we can compute f = d[0] + a[u]*b[0] mod 2^64. + */ + + /* + * Step 1: t <- (a[0]*b + f*p) / 2^64 + * We have f = a[0]*b[0] mod 2^64. Since p = -1 mod 2^64, this + * ensures that (a[0]*b + f*p) is a multiple of 2^64. + * + * We also have: f*p = f*2^256 - f*2^224 + f*2^192 + f*2^96 - f. + */ + x = a[0]; + + zl = _umul128(b[0], x, &zh); + f = zl; + t0 = zh; + + zl = _umul128(b[1], x, &zh); + k = _addcarry_u64(0, zl, t0, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + k = _addcarry_u64(0, zl, f << 32, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + t0 = zl; + t1 = zh; + + zl = _umul128(b[2], x, &zh); + k = _addcarry_u64(0, zl, t1, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + k = _addcarry_u64(0, zl, f >> 32, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + t1 = zl; + t2 = zh; + + zl = _umul128(b[3], x, &zh); + k = _addcarry_u64(0, zl, t2, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + k = _addcarry_u64(0, zl, f, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + t2 = zl; + t3 = zh; + + t4 = _addcarry_u64(0, t3, f, &t3); + k = _subborrow_u64(0, t2, f << 32, &t2); + k = _subborrow_u64(k, t3, f >> 32, &t3); + (void)_subborrow_u64(k, t4, 0, &t4); + + /* + * Steps 2 to 4: t <- (t + a[i]*b + f*p) / 2^64 + */ + for (i = 1; i < 4; i ++) { + x = a[i]; + /* f = t0 + x * b[0]; -- computed below */ + + /* t <- (t + x*b - f) / 2^64 */ + zl = _umul128(b[0], x, &zh); + k = _addcarry_u64(0, zl, t0, &f); + (void)_addcarry_u64(k, zh, 0, &t0); + + zl = _umul128(b[1], x, &zh); + k = _addcarry_u64(0, zl, t0, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + k = _addcarry_u64(0, zl, t1, &t0); + (void)_addcarry_u64(k, zh, 0, &t1); + + zl = _umul128(b[2], x, &zh); + k = _addcarry_u64(0, zl, t1, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + k = _addcarry_u64(0, zl, t2, &t1); + (void)_addcarry_u64(k, zh, 0, &t2); + + zl = _umul128(b[3], x, &zh); + k = _addcarry_u64(0, zl, t2, &zl); + (void)_addcarry_u64(k, zh, 0, &zh); + k = _addcarry_u64(0, zl, t3, &t2); + (void)_addcarry_u64(k, zh, 0, &t3); + + t4 = _addcarry_u64(0, t3, t4, &t3); + + /* t <- t + f*2^32, carry in k */ + k = _addcarry_u64(0, t0, f << 32, &t0); + k = _addcarry_u64(k, t1, f >> 32, &t1); + + /* t <- t + f*2^192 - f*2^160 + f*2^128 */ + m = _subborrow_u64(0, f, f << 32, &ffl); + (void)_subborrow_u64(m, f, f >> 32, &ffh); + k = _addcarry_u64(k, t2, ffl, &t2); + k = _addcarry_u64(k, t3, ffh, &t3); + (void)_addcarry_u64(k, t4, 0, &t4); + } + + /* + * At that point, we have computed t = (a*b + F*p) / 2^256, where + * F is a 256-bit integer whose limbs are the "f" coefficients + * in the steps above. We have: + * a <= 2^256-1 + * b <= 2^256-1 + * F <= 2^256-1 + * Hence: + * a*b + F*p <= (2^256-1)*(2^256-1) + p*(2^256-1) + * a*b + F*p <= 2^256*(2^256 - 2 + p) + 1 - p + * Therefore: + * t < 2^256 + p - 2 + * Since p < 2^256, it follows that: + * t4 can be only 0 or 1 + * t - p < 2^256 + * We can therefore subtract p from t, conditionally on t4, to + * get a nonnegative result that fits on 256 bits. + */ + k = _addcarry_u64(0, t0, t4, &t0); + k = _addcarry_u64(k, t1, -(t4 << 32), &t1); + k = _addcarry_u64(k, t2, -t4, &t2); + (void)_addcarry_u64(k, t3, (t4 << 32) - (t4 << 1), &t3); + + d[0] = t0; + d[1] = t1; + d[2] = t2; + d[3] = t3; + +#endif +} + +/* + * Montgomery squaring in the field; currently a basic wrapper around + * multiplication (inline, should be optimized away). + * TODO: see if some extra speed can be gained here. + */ +static inline void +f256_montysquare(uint64_t *d, const uint64_t *a) +{ + f256_montymul(d, a, a); +} + +/* + * Convert to Montgomery representation. + */ +static void +f256_tomonty(uint64_t *d, const uint64_t *a) +{ + /* + * R2 = 2^512 mod p. + * If R = 2^256 mod p, then R2 = R^2 mod p; and the Montgomery + * multiplication of a by R2 is: a*R2/R = a*R mod p, i.e. the + * conversion to Montgomery representation. + */ + static const uint64_t R2[] = { + 0x0000000000000003, + 0xFFFFFFFBFFFFFFFF, + 0xFFFFFFFFFFFFFFFE, + 0x00000004FFFFFFFD + }; + + f256_montymul(d, a, R2); +} + +/* + * Convert from Montgomery representation. + */ +static void +f256_frommonty(uint64_t *d, const uint64_t *a) +{ + /* + * Montgomery multiplication by 1 is division by 2^256 modulo p. + */ + static const uint64_t one[] = { 1, 0, 0, 0 }; + + f256_montymul(d, a, one); +} + +/* + * Inversion in the field. If the source value is 0 modulo p, then this + * returns 0 or p. This function uses Montgomery representation. + */ +static void +f256_invert(uint64_t *d, const uint64_t *a) +{ + /* + * We compute a^(p-2) mod p. The exponent pattern (from high to + * low) is: + * - 32 bits of value 1 + * - 31 bits of value 0 + * - 1 bit of value 1 + * - 96 bits of value 0 + * - 94 bits of value 1 + * - 1 bit of value 0 + * - 1 bit of value 1 + * To speed up the square-and-multiply algorithm, we precompute + * a^(2^31-1). + */ + + uint64_t r[4], t[4]; + int i; + + memcpy(t, a, sizeof t); + for (i = 0; i < 30; i ++) { + f256_montysquare(t, t); + f256_montymul(t, t, a); + } + + memcpy(r, t, sizeof t); + for (i = 224; i >= 0; i --) { + f256_montysquare(r, r); + switch (i) { + case 0: + case 2: + case 192: + case 224: + f256_montymul(r, r, a); + break; + case 3: + case 34: + case 65: + f256_montymul(r, r, t); + break; + } + } + memcpy(d, r, sizeof r); +} + +/* + * Finalize reduction. + * Input value fits on 256 bits. This function subtracts p if and only + * if the input is greater than or equal to p. + */ +static inline void +f256_final_reduce(uint64_t *a) +{ +#if BR_INT128 + + uint64_t t0, t1, t2, t3, cc; + unsigned __int128 z; + + /* + * We add 2^224 - 2^192 - 2^96 + 1 to a. If there is no carry, + * then a < p; otherwise, the addition result we computed is + * the value we must return. + */ + z = (unsigned __int128)a[0] + 1; + t0 = (uint64_t)z; + z = (unsigned __int128)a[1] + (z >> 64) - ((uint64_t)1 << 32); + t1 = (uint64_t)z; + z = (unsigned __int128)a[2] - (z >> 127); + t2 = (uint64_t)z; + z = (unsigned __int128)a[3] - (z >> 127) + 0xFFFFFFFF; + t3 = (uint64_t)z; + cc = -(uint64_t)(z >> 64); + + a[0] ^= cc & (a[0] ^ t0); + a[1] ^= cc & (a[1] ^ t1); + a[2] ^= cc & (a[2] ^ t2); + a[3] ^= cc & (a[3] ^ t3); + +#elif BR_UMUL128 + + uint64_t t0, t1, t2, t3, m; + unsigned char k; + + k = _addcarry_u64(0, a[0], (uint64_t)1, &t0); + k = _addcarry_u64(k, a[1], -((uint64_t)1 << 32), &t1); + k = _addcarry_u64(k, a[2], -(uint64_t)1, &t2); + k = _addcarry_u64(k, a[3], ((uint64_t)1 << 32) - 2, &t3); + m = -(uint64_t)k; + + a[0] ^= m & (a[0] ^ t0); + a[1] ^= m & (a[1] ^ t1); + a[2] ^= m & (a[2] ^ t2); + a[3] ^= m & (a[3] ^ t3); + +#endif +} + +/* + * Points in affine and Jacobian coordinates. + * + * - In affine coordinates, the point-at-infinity cannot be encoded. + * - Jacobian coordinates (X,Y,Z) correspond to affine (X/Z^2,Y/Z^3); + * if Z = 0 then this is the point-at-infinity. + */ +typedef struct { + uint64_t x[4]; + uint64_t y[4]; +} p256_affine; + +typedef struct { + uint64_t x[4]; + uint64_t y[4]; + uint64_t z[4]; +} p256_jacobian; + +/* + * Decode a point. The returned point is in Jacobian coordinates, but + * with z = 1. If the encoding is invalid, or encodes a point which is + * not on the curve, or encodes the point at infinity, then this function + * returns 0. Otherwise, 1 is returned. + * + * The buffer is assumed to have length exactly 65 bytes. + */ +static uint32_t +point_decode(p256_jacobian *P, const unsigned char *buf) +{ + uint64_t x[4], y[4], t[4], x3[4], tt; + uint32_t r; + + /* + * Header byte shall be 0x04. + */ + r = EQ(buf[0], 0x04); + + /* + * Decode X and Y coordinates, and convert them into + * Montgomery representation. + */ + x[3] = br_dec64be(buf + 1); + x[2] = br_dec64be(buf + 9); + x[1] = br_dec64be(buf + 17); + x[0] = br_dec64be(buf + 25); + y[3] = br_dec64be(buf + 33); + y[2] = br_dec64be(buf + 41); + y[1] = br_dec64be(buf + 49); + y[0] = br_dec64be(buf + 57); + f256_tomonty(x, x); + f256_tomonty(y, y); + + /* + * Verify y^2 = x^3 + A*x + B. In curve P-256, A = -3. + * Note that the Montgomery representation of 0 is 0. We must + * take care to apply the final reduction to make sure we have + * 0 and not p. + */ + f256_montysquare(t, y); + f256_montysquare(x3, x); + f256_montymul(x3, x3, x); + f256_sub(t, t, x3); + f256_add(t, t, x); + f256_add(t, t, x); + f256_add(t, t, x); + f256_sub(t, t, P256_B_MONTY); + f256_final_reduce(t); + tt = t[0] | t[1] | t[2] | t[3]; + r &= EQ((uint32_t)(tt | (tt >> 32)), 0); + + /* + * Return the point in Jacobian coordinates (and Montgomery + * representation). + */ + memcpy(P->x, x, sizeof x); + memcpy(P->y, y, sizeof y); + memcpy(P->z, F256_R, sizeof F256_R); + return r; +} + +/* + * Final conversion for a point: + * - The point is converted back to affine coordinates. + * - Final reduction is performed. + * - The point is encoded into the provided buffer. + * + * If the point is the point-at-infinity, all operations are performed, + * but the buffer contents are indeterminate, and 0 is returned. Otherwise, + * the encoded point is written in the buffer, and 1 is returned. + */ +static uint32_t +point_encode(unsigned char *buf, const p256_jacobian *P) +{ + uint64_t t1[4], t2[4], z; + + /* Set t1 = 1/z^2 and t2 = 1/z^3. */ + f256_invert(t2, P->z); + f256_montysquare(t1, t2); + f256_montymul(t2, t2, t1); + + /* Compute affine coordinates x (in t1) and y (in t2). */ + f256_montymul(t1, P->x, t1); + f256_montymul(t2, P->y, t2); + + /* Convert back from Montgomery representation, and finalize + reductions. */ + f256_frommonty(t1, t1); + f256_frommonty(t2, t2); + f256_final_reduce(t1); + f256_final_reduce(t2); + + /* Encode. */ + buf[0] = 0x04; + br_enc64be(buf + 1, t1[3]); + br_enc64be(buf + 9, t1[2]); + br_enc64be(buf + 17, t1[1]); + br_enc64be(buf + 25, t1[0]); + br_enc64be(buf + 33, t2[3]); + br_enc64be(buf + 41, t2[2]); + br_enc64be(buf + 49, t2[1]); + br_enc64be(buf + 57, t2[0]); + + /* Return success if and only if P->z != 0. */ + z = P->z[0] | P->z[1] | P->z[2] | P->z[3]; + return NEQ((uint32_t)(z | z >> 32), 0); +} + +/* + * Point doubling in Jacobian coordinates: point P is doubled. + * Note: if the source point is the point-at-infinity, then the result is + * still the point-at-infinity, which is correct. Moreover, if the three + * coordinates were zero, then they still are zero in the returned value. + * + * (Note: this is true even without the final reduction: if the three + * coordinates are encoded as four words of value zero each, then the + * result will also have all-zero coordinate encodings, not the alternate + * encoding as the integer p.) + */ +static void +p256_double(p256_jacobian *P) +{ + /* + * Doubling formulas are: + * + * s = 4*x*y^2 + * m = 3*(x + z^2)*(x - z^2) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y^4 + * z' = 2*y*z + * + * These formulas work for all points, including points of order 2 + * and points at infinity: + * - If y = 0 then z' = 0. But there is no such point in P-256 + * anyway. + * - If z = 0 then z' = 0. + */ + uint64_t t1[4], t2[4], t3[4], t4[4]; + + /* + * Compute z^2 in t1. + */ + f256_montysquare(t1, P->z); + + /* + * Compute x-z^2 in t2 and x+z^2 in t1. + */ + f256_add(t2, P->x, t1); + f256_sub(t1, P->x, t1); + + /* + * Compute 3*(x+z^2)*(x-z^2) in t1. + */ + f256_montymul(t3, t1, t2); + f256_add(t1, t3, t3); + f256_add(t1, t3, t1); + + /* + * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3). + */ + f256_montysquare(t3, P->y); + f256_add(t3, t3, t3); + f256_montymul(t2, P->x, t3); + f256_add(t2, t2, t2); + + /* + * Compute x' = m^2 - 2*s. + */ + f256_montysquare(P->x, t1); + f256_sub(P->x, P->x, t2); + f256_sub(P->x, P->x, t2); + + /* + * Compute z' = 2*y*z. + */ + f256_montymul(t4, P->y, P->z); + f256_add(P->z, t4, t4); + + /* + * Compute y' = m*(s - x') - 8*y^4. Note that we already have + * 2*y^2 in t3. + */ + f256_sub(t2, t2, P->x); + f256_montymul(P->y, t1, t2); + f256_montysquare(t4, t3); + f256_add(t4, t4, t4); + f256_sub(P->y, P->y, t4); +} + +/* + * Point addition (Jacobian coordinates): P1 is replaced with P1+P2. + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 but P2 != 0 + * - If P1 != 0 but P2 == 0 + * - If P1 == P2 + * + * In all three cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y coordinate. + * - P1 == 0 and P2 == 0. + * - The Y coordinate of one of the points is 0 and the other point is + * the point at infinity. + * + * The third case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + * + * Note that you can get a returned value of 0 with a correct result, + * e.g. if P1 and P2 have the same Y coordinate, but distinct X coordinates. + */ +static uint32_t +p256_add(p256_jacobian *P1, const p256_jacobian *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 * z2^2 + * u2 = x2 * z1^2 + * s1 = y1 * z2^3 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 * z2 + */ + uint64_t t1[4], t2[4], t3[4], t4[4], t5[4], t6[4], t7[4], tt; + uint32_t ret; + + /* + * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). + */ + f256_montysquare(t3, P2->z); + f256_montymul(t1, P1->x, t3); + f256_montymul(t4, P2->z, t3); + f256_montymul(t3, P1->y, t4); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + f256_montysquare(t4, P1->z); + f256_montymul(t2, P2->x, t4); + f256_montymul(t5, P1->z, t4); + f256_montymul(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + f256_sub(t2, t2, t1); + f256_sub(t4, t4, t3); + f256_final_reduce(t4); + tt = t4[0] | t4[1] | t4[2] | t4[3]; + ret = (uint32_t)(tt | (tt >> 32)); + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + f256_montysquare(t7, t2); + f256_montymul(t6, t1, t7); + f256_montymul(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + f256_montysquare(P1->x, t4); + f256_sub(P1->x, P1->x, t5); + f256_sub(P1->x, P1->x, t6); + f256_sub(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + f256_sub(t6, t6, P1->x); + f256_montymul(P1->y, t4, t6); + f256_montymul(t1, t5, t3); + f256_sub(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1*z2. + */ + f256_montymul(t1, P1->z, P2->z); + f256_montymul(P1->z, t1, t2); + + return ret; +} + +/* + * Point addition (mixed coordinates): P1 is replaced with P1+P2. + * This is a specialised function for the case when P2 is a non-zero point + * in affine coordinates. + * + * This function computes the wrong result in the following cases: + * + * - If P1 == 0 + * - If P1 == P2 + * + * In both cases, P1 is set to the point at infinity. + * + * Returned value is 0 if one of the following occurs: + * + * - P1 and P2 have the same Y (affine) coordinate. + * - The Y coordinate of P2 is 0 and P1 is the point at infinity. + * + * The second case cannot actually happen with valid points, since a point + * with Y == 0 is a point of order 2, and there is no point of order 2 on + * curve P-256. + * + * Therefore, assuming that P1 != 0 on input, then the caller + * can apply the following: + * + * - If the result is not the point at infinity, then it is correct. + * - Otherwise, if the returned value is 1, then this is a case of + * P1+P2 == 0, so the result is indeed the point at infinity. + * - Otherwise, P1 == P2, so a "double" operation should have been + * performed. + * + * Again, a value of 0 may be returned in some cases where the addition + * result is correct. + */ +static uint32_t +p256_add_mixed(p256_jacobian *P1, const p256_affine *P2) +{ + /* + * Addtions formulas are: + * + * u1 = x1 + * u2 = x2 * z1^2 + * s1 = y1 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 + */ + uint64_t t1[4], t2[4], t3[4], t4[4], t5[4], t6[4], t7[4], tt; + uint32_t ret; + + /* + * Compute u1 = x1 (in t1) and s1 = y1 (in t3). + */ + memcpy(t1, P1->x, sizeof t1); + memcpy(t3, P1->y, sizeof t3); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + f256_montysquare(t4, P1->z); + f256_montymul(t2, P2->x, t4); + f256_montymul(t5, P1->z, t4); + f256_montymul(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * We need to test whether r is zero, so we will do some extra + * reduce. + */ + f256_sub(t2, t2, t1); + f256_sub(t4, t4, t3); + f256_final_reduce(t4); + tt = t4[0] | t4[1] | t4[2] | t4[3]; + ret = (uint32_t)(tt | (tt >> 32)); + ret = (ret | -ret) >> 31; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + f256_montysquare(t7, t2); + f256_montymul(t6, t1, t7); + f256_montymul(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + f256_montysquare(P1->x, t4); + f256_sub(P1->x, P1->x, t5); + f256_sub(P1->x, P1->x, t6); + f256_sub(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + f256_sub(t6, t6, P1->x); + f256_montymul(P1->y, t4, t6); + f256_montymul(t1, t5, t3); + f256_sub(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1*z2. + */ + f256_montymul(P1->z, P1->z, t2); + + return ret; +} + +#if 0 +/* unused */ +/* + * Point addition (mixed coordinates, complete): P1 is replaced with P1+P2. + * This is a specialised function for the case when P2 is a non-zero point + * in affine coordinates. + * + * This function returns the correct result in all cases. + */ +static uint32_t +p256_add_complete_mixed(p256_jacobian *P1, const p256_affine *P2) +{ + /* + * Addtions formulas, in the general case, are: + * + * u1 = x1 + * u2 = x2 * z1^2 + * s1 = y1 + * s2 = y2 * z1^3 + * h = u2 - u1 + * r = s2 - s1 + * x3 = r^2 - h^3 - 2 * u1 * h^2 + * y3 = r * (u1 * h^2 - x3) - s1 * h^3 + * z3 = h * z1 + * + * These formulas mishandle the two following cases: + * + * - If P1 is the point-at-infinity (z1 = 0), then z3 is + * incorrectly set to 0. + * + * - If P1 = P2, then u1 = u2 and s1 = s2, and x3, y3 and z3 + * are all set to 0. + * + * However, if P1 + P2 = 0, then u1 = u2 but s1 != s2, and then + * we correctly get z3 = 0 (the point-at-infinity). + * + * To fix the case P1 = 0, we perform at the end a copy of P2 + * over P1, conditional to z1 = 0. + * + * For P1 = P2: in that case, both h and r are set to 0, and + * we get x3, y3 and z3 equal to 0. We can test for that + * occurrence to make a mask which will be all-one if P1 = P2, + * or all-zero otherwise; then we can compute the double of P2 + * and add it, combined with the mask, to (x3,y3,z3). + * + * Using the doubling formulas in p256_double() on (x2,y2), + * simplifying since P2 is affine (i.e. z2 = 1, implicitly), + * we get: + * s = 4*x2*y2^2 + * m = 3*(x2 + 1)*(x2 - 1) + * x' = m^2 - 2*s + * y' = m*(s - x') - 8*y2^4 + * z' = 2*y2 + * which requires only 6 multiplications. Added to the 11 + * multiplications of the normal mixed addition in Jacobian + * coordinates, we get a cost of 17 multiplications in total. + */ + uint64_t t1[4], t2[4], t3[4], t4[4], t5[4], t6[4], t7[4], tt, zz; + int i; + + /* + * Set zz to -1 if P1 is the point at infinity, 0 otherwise. + */ + zz = P1->z[0] | P1->z[1] | P1->z[2] | P1->z[3]; + zz = ((zz | -zz) >> 63) - (uint64_t)1; + + /* + * Compute u1 = x1 (in t1) and s1 = y1 (in t3). + */ + memcpy(t1, P1->x, sizeof t1); + memcpy(t3, P1->y, sizeof t3); + + /* + * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). + */ + f256_montysquare(t4, P1->z); + f256_montymul(t2, P2->x, t4); + f256_montymul(t5, P1->z, t4); + f256_montymul(t4, P2->y, t5); + + /* + * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). + * reduce. + */ + f256_sub(t2, t2, t1); + f256_sub(t4, t4, t3); + + /* + * If both h = 0 and r = 0, then P1 = P2, and we want to set + * the mask tt to -1; otherwise, the mask will be 0. + */ + f256_final_reduce(t2); + f256_final_reduce(t4); + tt = t2[0] | t2[1] | t2[2] | t2[3] | t4[0] | t4[1] | t4[2] | t4[3]; + tt = ((tt | -tt) >> 63) - (uint64_t)1; + + /* + * Compute u1*h^2 (in t6) and h^3 (in t5); + */ + f256_montysquare(t7, t2); + f256_montymul(t6, t1, t7); + f256_montymul(t5, t7, t2); + + /* + * Compute x3 = r^2 - h^3 - 2*u1*h^2. + */ + f256_montysquare(P1->x, t4); + f256_sub(P1->x, P1->x, t5); + f256_sub(P1->x, P1->x, t6); + f256_sub(P1->x, P1->x, t6); + + /* + * Compute y3 = r*(u1*h^2 - x3) - s1*h^3. + */ + f256_sub(t6, t6, P1->x); + f256_montymul(P1->y, t4, t6); + f256_montymul(t1, t5, t3); + f256_sub(P1->y, P1->y, t1); + + /* + * Compute z3 = h*z1. + */ + f256_montymul(P1->z, P1->z, t2); + + /* + * The "double" result, in case P1 = P2. + */ + + /* + * Compute z' = 2*y2 (in t1). + */ + f256_add(t1, P2->y, P2->y); + + /* + * Compute 2*(y2^2) (in t2) and s = 4*x2*(y2^2) (in t3). + */ + f256_montysquare(t2, P2->y); + f256_add(t2, t2, t2); + f256_add(t3, t2, t2); + f256_montymul(t3, P2->x, t3); + + /* + * Compute m = 3*(x2^2 - 1) (in t4). + */ + f256_montysquare(t4, P2->x); + f256_sub(t4, t4, F256_R); + f256_add(t5, t4, t4); + f256_add(t4, t4, t5); + + /* + * Compute x' = m^2 - 2*s (in t5). + */ + f256_montysquare(t5, t4); + f256_sub(t5, t3); + f256_sub(t5, t3); + + /* + * Compute y' = m*(s - x') - 8*y2^4 (in t6). + */ + f256_sub(t6, t3, t5); + f256_montymul(t6, t6, t4); + f256_montysquare(t7, t2); + f256_sub(t6, t6, t7); + f256_sub(t6, t6, t7); + + /* + * We now have the alternate (doubling) coordinates in (t5,t6,t1). + * We combine them with (x3,y3,z3). + */ + for (i = 0; i < 4; i ++) { + P1->x[i] |= tt & t5[i]; + P1->y[i] |= tt & t6[i]; + P1->z[i] |= tt & t1[i]; + } + + /* + * If P1 = 0, then we get z3 = 0 (which is invalid); if z1 is 0, + * then we want to replace the result with a copy of P2. The + * test on z1 was done at the start, in the zz mask. + */ + for (i = 0; i < 4; i ++) { + P1->x[i] ^= zz & (P1->x[i] ^ P2->x[i]); + P1->y[i] ^= zz & (P1->y[i] ^ P2->y[i]); + P1->z[i] ^= zz & (P1->z[i] ^ F256_R[i]); + } +} +#endif + +/* + * Inner function for computing a point multiplication. A window is + * provided, with points 1*P to 15*P in affine coordinates. + * + * Assumptions: + * - All provided points are valid points on the curve. + * - Multiplier is non-zero, and smaller than the curve order. + * - Everything is in Montgomery representation. + */ +static void +point_mul_inner(p256_jacobian *R, const p256_affine *W, + const unsigned char *k, size_t klen) +{ + p256_jacobian Q; + uint32_t qz; + + memset(&Q, 0, sizeof Q); + qz = 1; + while (klen -- > 0) { + int i; + unsigned bk; + + bk = *k ++; + for (i = 0; i < 2; i ++) { + uint32_t bits; + uint32_t bnz; + p256_affine T; + p256_jacobian U; + uint32_t n; + int j; + uint64_t m; + + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + p256_double(&Q); + bits = (bk >> 4) & 0x0F; + bnz = NEQ(bits, 0); + + /* + * Lookup point in window. If the bits are 0, + * we get something invalid, which is not a + * problem because we will use it only if the + * bits are non-zero. + */ + memset(&T, 0, sizeof T); + for (n = 0; n < 15; n ++) { + m = -(uint64_t)EQ(bits, n + 1); + T.x[0] |= m & W[n].x[0]; + T.x[1] |= m & W[n].x[1]; + T.x[2] |= m & W[n].x[2]; + T.x[3] |= m & W[n].x[3]; + T.y[0] |= m & W[n].y[0]; + T.y[1] |= m & W[n].y[1]; + T.y[2] |= m & W[n].y[2]; + T.y[3] |= m & W[n].y[3]; + } + + U = Q; + p256_add_mixed(&U, &T); + + /* + * If qz is still 1, then Q was all-zeros, and this + * is conserved through p256_double(). + */ + m = -(uint64_t)(bnz & qz); + for (j = 0; j < 4; j ++) { + Q.x[j] |= m & T.x[j]; + Q.y[j] |= m & T.y[j]; + Q.z[j] |= m & F256_R[j]; + } + CCOPY(bnz & ~qz, &Q, &U, sizeof Q); + qz &= ~bnz; + bk <<= 4; + } + } + *R = Q; +} + +/* + * Convert a window from Jacobian to affine coordinates. A single + * field inversion is used. This function works for windows up to + * 32 elements. + * + * The destination array (aff[]) and the source array (jac[]) may + * overlap, provided that the start of aff[] is not after the start of + * jac[]. Even if the arrays do _not_ overlap, the source array is + * modified. + */ +static void +window_to_affine(p256_affine *aff, p256_jacobian *jac, int num) +{ + /* + * Convert the window points to affine coordinates. We use the + * following trick to mutualize the inversion computation: if + * we have z1, z2, z3, and z4, and want to inverse all of them, + * we compute u = 1/(z1*z2*z3*z4), and then we have: + * 1/z1 = u*z2*z3*z4 + * 1/z2 = u*z1*z3*z4 + * 1/z3 = u*z1*z2*z4 + * 1/z4 = u*z1*z2*z3 + * + * The partial products are computed recursively: + * + * - on input (z_1,z_2), return (z_2,z_1) and z_1*z_2 + * - on input (z_1,z_2,... z_n): + * recurse on (z_1,z_2,... z_(n/2)) -> r1 and m1 + * recurse on (z_(n/2+1),z_(n/2+2)... z_n) -> r2 and m2 + * multiply elements of r1 by m2 -> s1 + * multiply elements of r2 by m1 -> s2 + * return r1||r2 and m1*m2 + * + * In the example below, we suppose that we have 14 elements. + * Let z1, z2,... zE be the 14 values to invert (index noted in + * hexadecimal, starting at 1). + * + * - Depth 1: + * swap(z1, z2); z12 = z1*z2 + * swap(z3, z4); z34 = z3*z4 + * swap(z5, z6); z56 = z5*z6 + * swap(z7, z8); z78 = z7*z8 + * swap(z9, zA); z9A = z9*zA + * swap(zB, zC); zBC = zB*zC + * swap(zD, zE); zDE = zD*zE + * + * - Depth 2: + * z1 <- z1*z34, z2 <- z2*z34, z3 <- z3*z12, z4 <- z4*z12 + * z1234 = z12*z34 + * z5 <- z5*z78, z6 <- z6*z78, z7 <- z7*z56, z8 <- z8*z56 + * z5678 = z56*z78 + * z9 <- z9*zBC, zA <- zA*zBC, zB <- zB*z9A, zC <- zC*z9A + * z9ABC = z9A*zBC + * + * - Depth 3: + * z1 <- z1*z5678, z2 <- z2*z5678, z3 <- z3*z5678, z4 <- z4*z5678 + * z5 <- z5*z1234, z6 <- z6*z1234, z7 <- z7*z1234, z8 <- z8*z1234 + * z12345678 = z1234*z5678 + * z9 <- z9*zDE, zA <- zA*zDE, zB <- zB*zDE, zC <- zC*zDE + * zD <- zD*z9ABC, zE*z9ABC + * z9ABCDE = z9ABC*zDE + * + * - Depth 4: + * multiply z1..z8 by z9ABCDE + * multiply z9..zE by z12345678 + * final z = z12345678*z9ABCDE + */ + + uint64_t z[16][4]; + int i, k, s; +#define zt (z[15]) +#define zu (z[14]) +#define zv (z[13]) + + /* + * First recursion step (pairwise swapping and multiplication). + * If there is an odd number of elements, then we "invent" an + * extra one with coordinate Z = 1 (in Montgomery representation). + */ + for (i = 0; (i + 1) < num; i += 2) { + memcpy(zt, jac[i].z, sizeof zt); + memcpy(jac[i].z, jac[i + 1].z, sizeof zt); + memcpy(jac[i + 1].z, zt, sizeof zt); + f256_montymul(z[i >> 1], jac[i].z, jac[i + 1].z); + } + if ((num & 1) != 0) { + memcpy(z[num >> 1], jac[num - 1].z, sizeof zt); + memcpy(jac[num - 1].z, F256_R, sizeof F256_R); + } + + /* + * Perform further recursion steps. At the entry of each step, + * the process has been done for groups of 's' points. The + * integer k is the log2 of s. + */ + for (k = 1, s = 2; s < num; k ++, s <<= 1) { + int n; + + for (i = 0; i < num; i ++) { + f256_montymul(jac[i].z, jac[i].z, z[(i >> k) ^ 1]); + } + n = (num + s - 1) >> k; + for (i = 0; i < (n >> 1); i ++) { + f256_montymul(z[i], z[i << 1], z[(i << 1) + 1]); + } + if ((n & 1) != 0) { + memmove(z[n >> 1], z[n], sizeof zt); + } + } + + /* + * Invert the final result, and convert all points. + */ + f256_invert(zt, z[0]); + for (i = 0; i < num; i ++) { + f256_montymul(zv, jac[i].z, zt); + f256_montysquare(zu, zv); + f256_montymul(zv, zv, zu); + f256_montymul(aff[i].x, jac[i].x, zu); + f256_montymul(aff[i].y, jac[i].y, zv); + } +} + +/* + * Multiply the provided point by an integer. + * Assumptions: + * - Source point is a valid curve point. + * - Source point is not the point-at-infinity. + * - Integer is not 0, and is lower than the curve order. + * If these conditions are not met, then the result is indeterminate + * (but the process is still constant-time). + */ +static void +p256_mul(p256_jacobian *P, const unsigned char *k, size_t klen) +{ + union { + p256_affine aff[15]; + p256_jacobian jac[15]; + } window; + int i; + + /* + * Compute window, in Jacobian coordinates. + */ + window.jac[0] = *P; + for (i = 2; i < 16; i ++) { + window.jac[i - 1] = window.jac[(i >> 1) - 1]; + if ((i & 1) == 0) { + p256_double(&window.jac[i - 1]); + } else { + p256_add(&window.jac[i - 1], &window.jac[i >> 1]); + } + } + + /* + * Convert the window points to affine coordinates. Point + * window[0] is the source point, already in affine coordinates. + */ + window_to_affine(window.aff, window.jac, 15); + + /* + * Perform point multiplication. + */ + point_mul_inner(P, window.aff, k, klen); +} + +/* + * Precomputed window for the conventional generator: P256_Gwin[n] + * contains (n+1)*G (affine coordinates, in Montgomery representation). + */ +static const p256_affine P256_Gwin[] = { + { + { 0x79E730D418A9143C, 0x75BA95FC5FEDB601, + 0x79FB732B77622510, 0x18905F76A53755C6 }, + { 0xDDF25357CE95560A, 0x8B4AB8E4BA19E45C, + 0xD2E88688DD21F325, 0x8571FF1825885D85 } + }, + { + { 0x850046D410DDD64D, 0xAA6AE3C1A433827D, + 0x732205038D1490D9, 0xF6BB32E43DCF3A3B }, + { 0x2F3648D361BEE1A5, 0x152CD7CBEB236FF8, + 0x19A8FB0E92042DBE, 0x78C577510A5B8A3B } + }, + { + { 0xFFAC3F904EEBC127, 0xB027F84A087D81FB, + 0x66AD77DD87CBBC98, 0x26936A3FB6FF747E }, + { 0xB04C5C1FC983A7EB, 0x583E47AD0861FE1A, + 0x788208311A2EE98E, 0xD5F06A29E587CC07 } + }, + { + { 0x74B0B50D46918DCC, 0x4650A6EDC623C173, + 0x0CDAACACE8100AF2, 0x577362F541B0176B }, + { 0x2D96F24CE4CBABA6, 0x17628471FAD6F447, + 0x6B6C36DEE5DDD22E, 0x84B14C394C5AB863 } + }, + { + { 0xBE1B8AAEC45C61F5, 0x90EC649A94B9537D, + 0x941CB5AAD076C20C, 0xC9079605890523C8 }, + { 0xEB309B4AE7BA4F10, 0x73C568EFE5EB882B, + 0x3540A9877E7A1F68, 0x73A076BB2DD1E916 } + }, + { + { 0x403947373E77664A, 0x55AE744F346CEE3E, + 0xD50A961A5B17A3AD, 0x13074B5954213673 }, + { 0x93D36220D377E44B, 0x299C2B53ADFF14B5, + 0xF424D44CEF639F11, 0xA4C9916D4A07F75F } + }, + { + { 0x0746354EA0173B4F, 0x2BD20213D23C00F7, + 0xF43EAAB50C23BB08, 0x13BA5119C3123E03 }, + { 0x2847D0303F5B9D4D, 0x6742F2F25DA67BDD, + 0xEF933BDC77C94195, 0xEAEDD9156E240867 } + }, + { + { 0x27F14CD19499A78F, 0x462AB5C56F9B3455, + 0x8F90F02AF02CFC6B, 0xB763891EB265230D }, + { 0xF59DA3A9532D4977, 0x21E3327DCF9EBA15, + 0x123C7B84BE60BBF0, 0x56EC12F27706DF76 } + }, + { + { 0x75C96E8F264E20E8, 0xABE6BFED59A7A841, + 0x2CC09C0444C8EB00, 0xE05B3080F0C4E16B }, + { 0x1EB7777AA45F3314, 0x56AF7BEDCE5D45E3, + 0x2B6E019A88B12F1A, 0x086659CDFD835F9B } + }, + { + { 0x2C18DBD19DC21EC8, 0x98F9868A0FCF8139, + 0x737D2CD648250B49, 0xCC61C94724B3428F }, + { 0x0C2B407880DD9E76, 0xC43A8991383FBE08, + 0x5F7D2D65779BE5D2, 0x78719A54EB3B4AB5 } + }, + { + { 0xEA7D260A6245E404, 0x9DE407956E7FDFE0, + 0x1FF3A4158DAC1AB5, 0x3E7090F1649C9073 }, + { 0x1A7685612B944E88, 0x250F939EE57F61C8, + 0x0C0DAA891EAD643D, 0x68930023E125B88E } + }, + { + { 0x04B71AA7D2697768, 0xABDEDEF5CA345A33, + 0x2409D29DEE37385E, 0x4EE1DF77CB83E156 }, + { 0x0CAC12D91CBB5B43, 0x170ED2F6CA895637, + 0x28228CFA8ADE6D66, 0x7FF57C9553238ACA } + }, + { + { 0xCCC425634B2ED709, 0x0E356769856FD30D, + 0xBCBCD43F559E9811, 0x738477AC5395B759 }, + { 0x35752B90C00EE17F, 0x68748390742ED2E3, + 0x7CD06422BD1F5BC1, 0xFBC08769C9E7B797 } + }, + { + { 0xA242A35BB0CF664A, 0x126E48F77F9707E3, + 0x1717BF54C6832660, 0xFAAE7332FD12C72E }, + { 0x27B52DB7995D586B, 0xBE29569E832237C2, + 0xE8E4193E2A65E7DB, 0x152706DC2EAA1BBB } + }, + { + { 0x72BCD8B7BC60055B, 0x03CC23EE56E27E4B, + 0xEE337424E4819370, 0xE2AA0E430AD3DA09 }, + { 0x40B8524F6383C45D, 0xD766355442A41B25, + 0x64EFA6DE778A4797, 0x2042170A7079ADF4 } + } +}; + +/* + * Multiply the conventional generator of the curve by the provided + * integer. Return is written in *P. + * + * Assumptions: + * - Integer is not 0, and is lower than the curve order. + * If this conditions is not met, then the result is indeterminate + * (but the process is still constant-time). + */ +static void +p256_mulgen(p256_jacobian *P, const unsigned char *k, size_t klen) +{ + point_mul_inner(P, P256_Gwin, k, klen); +} + +/* + * Return 1 if all of the following hold: + * - klen <= 32 + * - k != 0 + * - k is lower than the curve order + * Otherwise, return 0. + * + * Constant-time behaviour: only klen may be observable. + */ +static uint32_t +check_scalar(const unsigned char *k, size_t klen) +{ + uint32_t z; + int32_t c; + size_t u; + + if (klen > 32) { + return 0; + } + z = 0; + for (u = 0; u < klen; u ++) { + z |= k[u]; + } + if (klen == 32) { + c = 0; + for (u = 0; u < klen; u ++) { + c |= -(int32_t)EQ0(c) & CMP(k[u], P256_N[u]); + } + } else { + c = -1; + } + return NEQ(z, 0) & LT0(c); +} + +static uint32_t +api_mul(unsigned char *G, size_t Glen, + const unsigned char *k, size_t klen, int curve) +{ + uint32_t r; + p256_jacobian P; + + (void)curve; + if (Glen != 65) { + return 0; + } + r = check_scalar(k, klen); + r &= point_decode(&P, G); + p256_mul(&P, k, klen); + r &= point_encode(G, &P); + return r; +} + +static size_t +api_mulgen(unsigned char *R, + const unsigned char *k, size_t klen, int curve) +{ + p256_jacobian P; + + (void)curve; + p256_mulgen(&P, k, klen); + point_encode(R, &P); + return 65; +} + +static uint32_t +api_muladd(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve) +{ + /* + * We might want to use Shamir's trick here: make a composite + * window of u*P+v*Q points, to merge the two doubling-ladders + * into one. This, however, has some complications: + * + * - During the computation, we may hit the point-at-infinity. + * Thus, we would need p256_add_complete_mixed() (complete + * formulas for point addition), with a higher cost (17 muls + * instead of 11). + * + * - A 4-bit window would be too large, since it would involve + * 16*16-1 = 255 points. For the same window size as in the + * p256_mul() case, we would need to reduce the window size + * to 2 bits, and thus perform twice as many non-doubling + * point additions. + * + * - The window may itself contain the point-at-infinity, and + * thus cannot be in all generality be made of affine points. + * Instead, we would need to make it a window of points in + * Jacobian coordinates. Even p256_add_complete_mixed() would + * be inappropriate. + * + * For these reasons, the code below performs two separate + * point multiplications, then computes the final point addition + * (which is both a "normal" addition, and a doubling, to handle + * all cases). + */ + + p256_jacobian P, Q; + uint32_t r, t, s; + uint64_t z; + + (void)curve; + if (len != 65) { + return 0; + } + r = point_decode(&P, A); + p256_mul(&P, x, xlen); + if (B == NULL) { + p256_mulgen(&Q, y, ylen); + } else { + r &= point_decode(&Q, B); + p256_mul(&Q, y, ylen); + } + + /* + * The final addition may fail in case both points are equal. + */ + t = p256_add(&P, &Q); + f256_final_reduce(P.z); + z = P.z[0] | P.z[1] | P.z[2] | P.z[3]; + s = EQ((uint32_t)(z | (z >> 32)), 0); + p256_double(&Q); + + /* + * If s is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we + * have the following: + * + * s = 0, t = 0 return P (normal addition) + * s = 0, t = 1 return P (normal addition) + * s = 1, t = 0 return Q (a 'double' case) + * s = 1, t = 1 report an error (P+Q = 0) + */ + CCOPY(s & ~t, &P, &Q, sizeof Q); + point_encode(A, &P); + r &= ~(s & t); + return r; +} + +/* see bearssl_ec.h */ +const br_ec_impl br_ec_p256_m64 = { + (uint32_t)0x00800000, + &api_generator, + &api_order, + &api_xoff, + &api_mul, + &api_mulgen, + &api_muladd +}; + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_p256_m64_get(void) +{ + return &br_ec_p256_m64; +} + +#else + +/* see bearssl_ec.h */ +const br_ec_impl * +br_ec_p256_m64_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/int/i31_montmul.c b/src/bearssl/src/int/i31_montmul.c index 8066808..758f8f4 100644 --- a/src/bearssl/src/int/i31_montmul.c +++ b/src/bearssl/src/int/i31_montmul.c @@ -29,16 +29,45 @@ void br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, const uint32_t *m, uint32_t m0i) { + /* + * Each outer loop iteration computes: + * d <- (d + xu*y + f*m) / 2^31 + * We have xu <= 2^31-1 and f <= 2^31-1. + * Thus, if d <= 2*m-1 on input, then: + * 2*m-1 + 2*(2^31-1)*m <= (2^32)*m-1 + * and the new d value is less than 2*m. + * + * We represent d over 31-bit words, with an extra word 'dh' + * which can thus be only 0 or 1. + */ size_t len, len4, u, v; - uint64_t dh; + uint32_t dh; len = (m[0] + 31) >> 5; len4 = len & ~(size_t)3; br_i31_zero(d, m[0]); dh = 0; for (u = 0; u < len; u ++) { + /* + * The carry for each operation fits on 32 bits: + * d[v+1] <= 2^31-1 + * xu*y[v+1] <= (2^31-1)*(2^31-1) + * f*m[v+1] <= (2^31-1)*(2^31-1) + * r <= 2^32-1 + * (2^31-1) + 2*(2^31-1)*(2^31-1) + (2^32-1) = 2^63 - 2^31 + * After division by 2^31, the new r is then at most 2^32-1 + * + * Using a 32-bit carry has performance benefits on 32-bit + * systems; however, on 64-bit architectures, we prefer to + * keep the carry (r) in a 64-bit register, thus avoiding some + * "clear high bits" operations. + */ uint32_t f, xu; - uint64_t r, zh; +#if BR_64 + uint64_t r; +#else + uint32_t r; +#endif xu = x[u + 1]; f = MUL31_lo((d[1] + MUL31_lo(x[u + 1], y[1])), m0i); @@ -73,9 +102,14 @@ br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, d[v] = (uint32_t)z & 0x7FFFFFFF; } - zh = dh + r; - d[len] = (uint32_t)zh & 0x7FFFFFFF; - dh = zh >> 31; + /* + * Since the new dh can only be 0 or 1, the addition of + * the old dh with the carry MUST fit on 32 bits, and + * thus can be done into dh itself. + */ + dh += r; + d[len] = dh & 0x7FFFFFFF; + dh >>= 31; } /* diff --git a/src/bearssl/src/int/i31_mulacc.c b/src/bearssl/src/int/i31_mulacc.c index 024d095..7410e54 100644 --- a/src/bearssl/src/int/i31_mulacc.c +++ b/src/bearssl/src/int/i31_mulacc.c @@ -45,7 +45,20 @@ br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b) for (u = 0; u < blen; u ++) { uint32_t f; size_t v; + + /* + * Carry always fits on 31 bits; we want to keep it in a + * 32-bit register on 32-bit architectures (on a 64-bit + * architecture, cast down from 64 to 32 bits means + * clearing the high bits, which is not free; on a 32-bit + * architecture, the same operation really means ignoring + * the top register, which has negative or zero cost). + */ +#if BR_64 uint64_t cc; +#else + uint32_t cc; +#endif f = b[1 + u]; cc = 0; diff --git a/src/bearssl/src/int/i32_mulacc.c b/src/bearssl/src/int/i32_mulacc.c index f62c782..55da385 100644 --- a/src/bearssl/src/int/i32_mulacc.c +++ b/src/bearssl/src/int/i32_mulacc.c @@ -36,7 +36,11 @@ br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b) for (u = 0; u < blen; u ++) { uint32_t f; size_t v; +#if BR_64 uint64_t cc; +#else + uint32_t cc; +#endif f = b[1 + u]; cc = 0; diff --git a/src/bearssl/src/kdf/shake.c b/src/bearssl/src/kdf/shake.c new file mode 100644 index 0000000..80d7176 --- /dev/null +++ b/src/bearssl/src/kdf/shake.c @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Round constants. + */ +static const uint64_t RC[] = { + 0x0000000000000001, 0x0000000000008082, + 0x800000000000808A, 0x8000000080008000, + 0x000000000000808B, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, + 0x000000000000008A, 0x0000000000000088, + 0x0000000080008009, 0x000000008000000A, + 0x000000008000808B, 0x800000000000008B, + 0x8000000000008089, 0x8000000000008003, + 0x8000000000008002, 0x8000000000000080, + 0x000000000000800A, 0x800000008000000A, + 0x8000000080008081, 0x8000000000008080, + 0x0000000080000001, 0x8000000080008008 +}; + +/* + * XOR a block of data into the provided state. This supports only + * blocks whose length is a multiple of 64 bits. + */ +static void +xor_block(uint64_t *A, const void *data, size_t rate) +{ + size_t u; + + for (u = 0; u < rate; u += 8) { + A[u >> 3] ^= br_dec64le((const unsigned char *)data + u); + } +} + +/* + * Process a block with the provided data. The data length must be a + * multiple of 8 (in bytes); normally, this is the "rate". + */ +static void +process_block(uint64_t *A) +{ + uint64_t t0, t1, t2, t3, t4; + uint64_t tt0, tt1, tt2, tt3; + uint64_t t, kt; + uint64_t c0, c1, c2, c3, c4, bnn; + int j; + + /* + * Compute the 24 rounds. This loop is partially unrolled (each + * iteration computes two rounds). + */ + for (j = 0; j < 24; j += 2) { + + tt0 = A[ 1] ^ A[ 6]; + tt1 = A[11] ^ A[16]; + tt0 ^= A[21] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[ 4] ^ A[ 9]; + tt3 = A[14] ^ A[19]; + tt0 ^= A[24]; + tt2 ^= tt3; + t0 = tt0 ^ tt2; + + tt0 = A[ 2] ^ A[ 7]; + tt1 = A[12] ^ A[17]; + tt0 ^= A[22] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[ 0] ^ A[ 5]; + tt3 = A[10] ^ A[15]; + tt0 ^= A[20]; + tt2 ^= tt3; + t1 = tt0 ^ tt2; + + tt0 = A[ 3] ^ A[ 8]; + tt1 = A[13] ^ A[18]; + tt0 ^= A[23] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[ 1] ^ A[ 6]; + tt3 = A[11] ^ A[16]; + tt0 ^= A[21]; + tt2 ^= tt3; + t2 = tt0 ^ tt2; + + tt0 = A[ 4] ^ A[ 9]; + tt1 = A[14] ^ A[19]; + tt0 ^= A[24] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[ 2] ^ A[ 7]; + tt3 = A[12] ^ A[17]; + tt0 ^= A[22]; + tt2 ^= tt3; + t3 = tt0 ^ tt2; + + tt0 = A[ 0] ^ A[ 5]; + tt1 = A[10] ^ A[15]; + tt0 ^= A[20] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[ 3] ^ A[ 8]; + tt3 = A[13] ^ A[18]; + tt0 ^= A[23]; + tt2 ^= tt3; + t4 = tt0 ^ tt2; + + A[ 0] = A[ 0] ^ t0; + A[ 5] = A[ 5] ^ t0; + A[10] = A[10] ^ t0; + A[15] = A[15] ^ t0; + A[20] = A[20] ^ t0; + A[ 1] = A[ 1] ^ t1; + A[ 6] = A[ 6] ^ t1; + A[11] = A[11] ^ t1; + A[16] = A[16] ^ t1; + A[21] = A[21] ^ t1; + A[ 2] = A[ 2] ^ t2; + A[ 7] = A[ 7] ^ t2; + A[12] = A[12] ^ t2; + A[17] = A[17] ^ t2; + A[22] = A[22] ^ t2; + A[ 3] = A[ 3] ^ t3; + A[ 8] = A[ 8] ^ t3; + A[13] = A[13] ^ t3; + A[18] = A[18] ^ t3; + A[23] = A[23] ^ t3; + A[ 4] = A[ 4] ^ t4; + A[ 9] = A[ 9] ^ t4; + A[14] = A[14] ^ t4; + A[19] = A[19] ^ t4; + A[24] = A[24] ^ t4; + A[ 5] = (A[ 5] << 36) | (A[ 5] >> (64 - 36)); + A[10] = (A[10] << 3) | (A[10] >> (64 - 3)); + A[15] = (A[15] << 41) | (A[15] >> (64 - 41)); + A[20] = (A[20] << 18) | (A[20] >> (64 - 18)); + A[ 1] = (A[ 1] << 1) | (A[ 1] >> (64 - 1)); + A[ 6] = (A[ 6] << 44) | (A[ 6] >> (64 - 44)); + A[11] = (A[11] << 10) | (A[11] >> (64 - 10)); + A[16] = (A[16] << 45) | (A[16] >> (64 - 45)); + A[21] = (A[21] << 2) | (A[21] >> (64 - 2)); + A[ 2] = (A[ 2] << 62) | (A[ 2] >> (64 - 62)); + A[ 7] = (A[ 7] << 6) | (A[ 7] >> (64 - 6)); + A[12] = (A[12] << 43) | (A[12] >> (64 - 43)); + A[17] = (A[17] << 15) | (A[17] >> (64 - 15)); + A[22] = (A[22] << 61) | (A[22] >> (64 - 61)); + A[ 3] = (A[ 3] << 28) | (A[ 3] >> (64 - 28)); + A[ 8] = (A[ 8] << 55) | (A[ 8] >> (64 - 55)); + A[13] = (A[13] << 25) | (A[13] >> (64 - 25)); + A[18] = (A[18] << 21) | (A[18] >> (64 - 21)); + A[23] = (A[23] << 56) | (A[23] >> (64 - 56)); + A[ 4] = (A[ 4] << 27) | (A[ 4] >> (64 - 27)); + A[ 9] = (A[ 9] << 20) | (A[ 9] >> (64 - 20)); + A[14] = (A[14] << 39) | (A[14] >> (64 - 39)); + A[19] = (A[19] << 8) | (A[19] >> (64 - 8)); + A[24] = (A[24] << 14) | (A[24] >> (64 - 14)); + bnn = ~A[12]; + kt = A[ 6] | A[12]; + c0 = A[ 0] ^ kt; + kt = bnn | A[18]; + c1 = A[ 6] ^ kt; + kt = A[18] & A[24]; + c2 = A[12] ^ kt; + kt = A[24] | A[ 0]; + c3 = A[18] ^ kt; + kt = A[ 0] & A[ 6]; + c4 = A[24] ^ kt; + A[ 0] = c0; + A[ 6] = c1; + A[12] = c2; + A[18] = c3; + A[24] = c4; + bnn = ~A[22]; + kt = A[ 9] | A[10]; + c0 = A[ 3] ^ kt; + kt = A[10] & A[16]; + c1 = A[ 9] ^ kt; + kt = A[16] | bnn; + c2 = A[10] ^ kt; + kt = A[22] | A[ 3]; + c3 = A[16] ^ kt; + kt = A[ 3] & A[ 9]; + c4 = A[22] ^ kt; + A[ 3] = c0; + A[ 9] = c1; + A[10] = c2; + A[16] = c3; + A[22] = c4; + bnn = ~A[19]; + kt = A[ 7] | A[13]; + c0 = A[ 1] ^ kt; + kt = A[13] & A[19]; + c1 = A[ 7] ^ kt; + kt = bnn & A[20]; + c2 = A[13] ^ kt; + kt = A[20] | A[ 1]; + c3 = bnn ^ kt; + kt = A[ 1] & A[ 7]; + c4 = A[20] ^ kt; + A[ 1] = c0; + A[ 7] = c1; + A[13] = c2; + A[19] = c3; + A[20] = c4; + bnn = ~A[17]; + kt = A[ 5] & A[11]; + c0 = A[ 4] ^ kt; + kt = A[11] | A[17]; + c1 = A[ 5] ^ kt; + kt = bnn | A[23]; + c2 = A[11] ^ kt; + kt = A[23] & A[ 4]; + c3 = bnn ^ kt; + kt = A[ 4] | A[ 5]; + c4 = A[23] ^ kt; + A[ 4] = c0; + A[ 5] = c1; + A[11] = c2; + A[17] = c3; + A[23] = c4; + bnn = ~A[ 8]; + kt = bnn & A[14]; + c0 = A[ 2] ^ kt; + kt = A[14] | A[15]; + c1 = bnn ^ kt; + kt = A[15] & A[21]; + c2 = A[14] ^ kt; + kt = A[21] | A[ 2]; + c3 = A[15] ^ kt; + kt = A[ 2] & A[ 8]; + c4 = A[21] ^ kt; + A[ 2] = c0; + A[ 8] = c1; + A[14] = c2; + A[15] = c3; + A[21] = c4; + A[ 0] = A[ 0] ^ RC[j + 0]; + + tt0 = A[ 6] ^ A[ 9]; + tt1 = A[ 7] ^ A[ 5]; + tt0 ^= A[ 8] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[24] ^ A[22]; + tt3 = A[20] ^ A[23]; + tt0 ^= A[21]; + tt2 ^= tt3; + t0 = tt0 ^ tt2; + + tt0 = A[12] ^ A[10]; + tt1 = A[13] ^ A[11]; + tt0 ^= A[14] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[ 0] ^ A[ 3]; + tt3 = A[ 1] ^ A[ 4]; + tt0 ^= A[ 2]; + tt2 ^= tt3; + t1 = tt0 ^ tt2; + + tt0 = A[18] ^ A[16]; + tt1 = A[19] ^ A[17]; + tt0 ^= A[15] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[ 6] ^ A[ 9]; + tt3 = A[ 7] ^ A[ 5]; + tt0 ^= A[ 8]; + tt2 ^= tt3; + t2 = tt0 ^ tt2; + + tt0 = A[24] ^ A[22]; + tt1 = A[20] ^ A[23]; + tt0 ^= A[21] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[12] ^ A[10]; + tt3 = A[13] ^ A[11]; + tt0 ^= A[14]; + tt2 ^= tt3; + t3 = tt0 ^ tt2; + + tt0 = A[ 0] ^ A[ 3]; + tt1 = A[ 1] ^ A[ 4]; + tt0 ^= A[ 2] ^ tt1; + tt0 = (tt0 << 1) | (tt0 >> 63); + tt2 = A[18] ^ A[16]; + tt3 = A[19] ^ A[17]; + tt0 ^= A[15]; + tt2 ^= tt3; + t4 = tt0 ^ tt2; + + A[ 0] = A[ 0] ^ t0; + A[ 3] = A[ 3] ^ t0; + A[ 1] = A[ 1] ^ t0; + A[ 4] = A[ 4] ^ t0; + A[ 2] = A[ 2] ^ t0; + A[ 6] = A[ 6] ^ t1; + A[ 9] = A[ 9] ^ t1; + A[ 7] = A[ 7] ^ t1; + A[ 5] = A[ 5] ^ t1; + A[ 8] = A[ 8] ^ t1; + A[12] = A[12] ^ t2; + A[10] = A[10] ^ t2; + A[13] = A[13] ^ t2; + A[11] = A[11] ^ t2; + A[14] = A[14] ^ t2; + A[18] = A[18] ^ t3; + A[16] = A[16] ^ t3; + A[19] = A[19] ^ t3; + A[17] = A[17] ^ t3; + A[15] = A[15] ^ t3; + A[24] = A[24] ^ t4; + A[22] = A[22] ^ t4; + A[20] = A[20] ^ t4; + A[23] = A[23] ^ t4; + A[21] = A[21] ^ t4; + A[ 3] = (A[ 3] << 36) | (A[ 3] >> (64 - 36)); + A[ 1] = (A[ 1] << 3) | (A[ 1] >> (64 - 3)); + A[ 4] = (A[ 4] << 41) | (A[ 4] >> (64 - 41)); + A[ 2] = (A[ 2] << 18) | (A[ 2] >> (64 - 18)); + A[ 6] = (A[ 6] << 1) | (A[ 6] >> (64 - 1)); + A[ 9] = (A[ 9] << 44) | (A[ 9] >> (64 - 44)); + A[ 7] = (A[ 7] << 10) | (A[ 7] >> (64 - 10)); + A[ 5] = (A[ 5] << 45) | (A[ 5] >> (64 - 45)); + A[ 8] = (A[ 8] << 2) | (A[ 8] >> (64 - 2)); + A[12] = (A[12] << 62) | (A[12] >> (64 - 62)); + A[10] = (A[10] << 6) | (A[10] >> (64 - 6)); + A[13] = (A[13] << 43) | (A[13] >> (64 - 43)); + A[11] = (A[11] << 15) | (A[11] >> (64 - 15)); + A[14] = (A[14] << 61) | (A[14] >> (64 - 61)); + A[18] = (A[18] << 28) | (A[18] >> (64 - 28)); + A[16] = (A[16] << 55) | (A[16] >> (64 - 55)); + A[19] = (A[19] << 25) | (A[19] >> (64 - 25)); + A[17] = (A[17] << 21) | (A[17] >> (64 - 21)); + A[15] = (A[15] << 56) | (A[15] >> (64 - 56)); + A[24] = (A[24] << 27) | (A[24] >> (64 - 27)); + A[22] = (A[22] << 20) | (A[22] >> (64 - 20)); + A[20] = (A[20] << 39) | (A[20] >> (64 - 39)); + A[23] = (A[23] << 8) | (A[23] >> (64 - 8)); + A[21] = (A[21] << 14) | (A[21] >> (64 - 14)); + bnn = ~A[13]; + kt = A[ 9] | A[13]; + c0 = A[ 0] ^ kt; + kt = bnn | A[17]; + c1 = A[ 9] ^ kt; + kt = A[17] & A[21]; + c2 = A[13] ^ kt; + kt = A[21] | A[ 0]; + c3 = A[17] ^ kt; + kt = A[ 0] & A[ 9]; + c4 = A[21] ^ kt; + A[ 0] = c0; + A[ 9] = c1; + A[13] = c2; + A[17] = c3; + A[21] = c4; + bnn = ~A[14]; + kt = A[22] | A[ 1]; + c0 = A[18] ^ kt; + kt = A[ 1] & A[ 5]; + c1 = A[22] ^ kt; + kt = A[ 5] | bnn; + c2 = A[ 1] ^ kt; + kt = A[14] | A[18]; + c3 = A[ 5] ^ kt; + kt = A[18] & A[22]; + c4 = A[14] ^ kt; + A[18] = c0; + A[22] = c1; + A[ 1] = c2; + A[ 5] = c3; + A[14] = c4; + bnn = ~A[23]; + kt = A[10] | A[19]; + c0 = A[ 6] ^ kt; + kt = A[19] & A[23]; + c1 = A[10] ^ kt; + kt = bnn & A[ 2]; + c2 = A[19] ^ kt; + kt = A[ 2] | A[ 6]; + c3 = bnn ^ kt; + kt = A[ 6] & A[10]; + c4 = A[ 2] ^ kt; + A[ 6] = c0; + A[10] = c1; + A[19] = c2; + A[23] = c3; + A[ 2] = c4; + bnn = ~A[11]; + kt = A[ 3] & A[ 7]; + c0 = A[24] ^ kt; + kt = A[ 7] | A[11]; + c1 = A[ 3] ^ kt; + kt = bnn | A[15]; + c2 = A[ 7] ^ kt; + kt = A[15] & A[24]; + c3 = bnn ^ kt; + kt = A[24] | A[ 3]; + c4 = A[15] ^ kt; + A[24] = c0; + A[ 3] = c1; + A[ 7] = c2; + A[11] = c3; + A[15] = c4; + bnn = ~A[16]; + kt = bnn & A[20]; + c0 = A[12] ^ kt; + kt = A[20] | A[ 4]; + c1 = bnn ^ kt; + kt = A[ 4] & A[ 8]; + c2 = A[20] ^ kt; + kt = A[ 8] | A[12]; + c3 = A[ 4] ^ kt; + kt = A[12] & A[16]; + c4 = A[ 8] ^ kt; + A[12] = c0; + A[16] = c1; + A[20] = c2; + A[ 4] = c3; + A[ 8] = c4; + A[ 0] = A[ 0] ^ RC[j + 1]; + t = A[ 5]; + A[ 5] = A[18]; + A[18] = A[11]; + A[11] = A[10]; + A[10] = A[ 6]; + A[ 6] = A[22]; + A[22] = A[20]; + A[20] = A[12]; + A[12] = A[19]; + A[19] = A[15]; + A[15] = A[24]; + A[24] = A[ 8]; + A[ 8] = t; + t = A[ 1]; + A[ 1] = A[ 9]; + A[ 9] = A[14]; + A[14] = A[ 2]; + A[ 2] = A[13]; + A[13] = A[23]; + A[23] = A[ 4]; + A[ 4] = A[21]; + A[21] = A[16]; + A[16] = A[ 3]; + A[ 3] = A[17]; + A[17] = A[ 7]; + A[ 7] = t; + } +} + +/* see bearssl_kdf.h */ +void +br_shake_init(br_shake_context *sc, int security_level) +{ + sc->rate = 200 - (size_t)(security_level >> 2); + sc->dptr = 0; + memset(sc->A, 0, sizeof sc->A); + sc->A[ 1] = ~(uint64_t)0; + sc->A[ 2] = ~(uint64_t)0; + sc->A[ 8] = ~(uint64_t)0; + sc->A[12] = ~(uint64_t)0; + sc->A[17] = ~(uint64_t)0; + sc->A[20] = ~(uint64_t)0; +} + +/* see bearssl_kdf.h */ +void +br_shake_inject(br_shake_context *sc, const void *data, size_t len) +{ + const unsigned char *buf; + size_t rate, dptr; + + buf = data; + rate = sc->rate; + dptr = sc->dptr; + while (len > 0) { + size_t clen; + + clen = rate - dptr; + if (clen > len) { + clen = len; + } + memcpy(sc->dbuf + dptr, buf, clen); + dptr += clen; + buf += clen; + len -= clen; + if (dptr == rate) { + xor_block(sc->A, sc->dbuf, rate); + process_block(sc->A); + dptr = 0; + } + } + sc->dptr = dptr; +} + +/* see bearssl_kdf.h */ +void +br_shake_flip(br_shake_context *sc) +{ + /* + * We apply padding and pre-XOR the value into the state. We + * set dptr to the end of the buffer, so that first call to + * shake_extract() will process the block. + */ + if ((sc->dptr + 1) == sc->rate) { + sc->dbuf[sc->dptr ++] = 0x9F; + } else { + sc->dbuf[sc->dptr ++] = 0x1F; + memset(sc->dbuf + sc->dptr, 0x00, sc->rate - sc->dptr - 1); + sc->dbuf[sc->rate - 1] = 0x80; + sc->dptr = sc->rate; + } + xor_block(sc->A, sc->dbuf, sc->rate); +} + +/* see bearssl_kdf.h */ +void +br_shake_produce(br_shake_context *sc, void *out, size_t len) +{ + unsigned char *buf; + size_t dptr, rate; + + buf = out; + dptr = sc->dptr; + rate = sc->rate; + while (len > 0) { + size_t clen; + + if (dptr == rate) { + unsigned char *dbuf; + uint64_t *A; + + A = sc->A; + dbuf = sc->dbuf; + process_block(A); + br_enc64le(dbuf + 0, A[ 0]); + br_enc64le(dbuf + 8, ~A[ 1]); + br_enc64le(dbuf + 16, ~A[ 2]); + br_enc64le(dbuf + 24, A[ 3]); + br_enc64le(dbuf + 32, A[ 4]); + br_enc64le(dbuf + 40, A[ 5]); + br_enc64le(dbuf + 48, A[ 6]); + br_enc64le(dbuf + 56, A[ 7]); + br_enc64le(dbuf + 64, ~A[ 8]); + br_enc64le(dbuf + 72, A[ 9]); + br_enc64le(dbuf + 80, A[10]); + br_enc64le(dbuf + 88, A[11]); + br_enc64le(dbuf + 96, ~A[12]); + br_enc64le(dbuf + 104, A[13]); + br_enc64le(dbuf + 112, A[14]); + br_enc64le(dbuf + 120, A[15]); + br_enc64le(dbuf + 128, A[16]); + br_enc64le(dbuf + 136, ~A[17]); + br_enc64le(dbuf + 144, A[18]); + br_enc64le(dbuf + 152, A[19]); + br_enc64le(dbuf + 160, ~A[20]); + br_enc64le(dbuf + 168, A[21]); + br_enc64le(dbuf + 176, A[22]); + br_enc64le(dbuf + 184, A[23]); + br_enc64le(dbuf + 192, A[24]); + dptr = 0; + } + clen = rate - dptr; + if (clen > len) { + clen = len; + } + memcpy(buf, sc->dbuf + dptr, clen); + dptr += clen; + buf += clen; + len -= clen; + } + sc->dptr = dptr; +} diff --git a/src/bearssl/src/rand/sysrng.c b/src/bearssl/src/rand/sysrng.c index bec06be..5a92114 100644 --- a/src/bearssl/src/rand/sysrng.c +++ b/src/bearssl/src/rand/sysrng.c @@ -25,6 +25,10 @@ #define BR_ENABLE_INTRINSICS 1 #include "inner.h" +#if BR_USE_GETENTROPY +#include +#endif + #if BR_USE_URANDOM #include #include @@ -38,6 +42,9 @@ #pragma comment(lib, "advapi32") #endif +/* + * Seeder that uses the RDRAND opcodes (on x86 CPU). + */ #if BR_RDRAND BR_TARGETS_X86_UP BR_TARGET("rdrnd") @@ -57,9 +64,24 @@ seeder_rdrand(const br_prng_class **ctx) * * Intel recommends trying at least 10 times in case of * failure. + * + * AMD bug: there are reports that some AMD processors + * have a bug that makes them fail silently after a + * suspend/resume cycle, in which case RDRAND will report + * a success but always return 0xFFFFFFFF. + * see: https://bugzilla.kernel.org/show_bug.cgi?id=85911 + * + * As a mitigation, if the 32-bit value is 0 or -1, then + * it is considered a failure and tried again. This should + * reliably detect the buggy case, at least. This also + * implies that the selected seed values can never be + * 0x00000000 or 0xFFFFFFFF, which is not a problem since + * we are generating a seed for a PRNG, and we overdo it + * a bit (we generate 32 bytes of randomness, and 256 bits + * of entropy are really overkill). */ for (j = 0; j < 10; j ++) { - if (_rdrand32_step(&x)) { + if (_rdrand32_step(&x) && x != 0 && x != (uint32_t)-1) { goto next_word; } } @@ -80,9 +102,11 @@ rdrand_supported(void) */ return br_cpuid(0, 0, 0x40000000, 0); } - #endif +/* + * Seeder that uses /dev/urandom (on Unix-like systems). + */ #if BR_USE_URANDOM static int seeder_urandom(const br_prng_class **ctx) @@ -116,6 +140,32 @@ seeder_urandom(const br_prng_class **ctx) } #endif +/* + * Seeder that uses getentropy() (backed by getrandom() on some systems, + * e.g. Linux). On failure, it will use the /dev/urandom seeder (if + * enabled). + */ +#if BR_USE_GETENTROPY +static int +seeder_getentropy(const br_prng_class **ctx) +{ + unsigned char tmp[32]; + + if (getentropy(tmp, sizeof tmp) == 0) { + (*ctx)->update(ctx, tmp, sizeof tmp); + return 1; + } +#if BR_USE_URANDOM + return seeder_urandom(ctx); +#else + return 0; +#endif +} +#endif + +/* + * Seeder that uses CryptGenRandom() (on Windows). + */ #if BR_USE_WIN32_RAND static int seeder_win32(const br_prng_class **ctx) @@ -139,6 +189,29 @@ seeder_win32(const br_prng_class **ctx) } #endif +/* + * An aggregate seeder that uses RDRAND, and falls back to an OS-provided + * source if RDRAND fails. + */ +#if BR_RDRAND && (BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND) +static int +seeder_rdrand_with_fallback(const br_prng_class **ctx) +{ + if (!seeder_rdrand(ctx)) { +#if BR_USE_GETENTROPY + return seeder_getentropy(ctx); +#elif BR_USE_URANDOM + return seeder_urandom(ctx); +#elif BR_USE_WIN32_RAND + return seeder_win32(ctx); +#else +#error "macro selection has gone wrong" +#endif + } + return 1; +} +#endif + /* see bearssl_rand.h */ br_prng_seeder br_prng_seeder_system(const char **name) @@ -148,10 +221,19 @@ br_prng_seeder_system(const char **name) if (name != NULL) { *name = "rdrand"; } +#if BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND + return &seeder_rdrand_with_fallback; +#else return &seeder_rdrand; +#endif } #endif -#if BR_USE_URANDOM +#if BR_USE_GETENTROPY + if (name != NULL) { + *name = "getentropy"; + } + return &seeder_getentropy; +#elif BR_USE_URANDOM if (name != NULL) { *name = "urandom"; } @@ -161,9 +243,10 @@ br_prng_seeder_system(const char **name) *name = "win32"; } return &seeder_win32; -#endif +#else if (name != NULL) { *name = "none"; } return 0; +#endif } diff --git a/src/bearssl/src/rsa/rsa_default_pss_sign.c b/src/bearssl/src/rsa/rsa_default_pss_sign.c new file mode 100644 index 0000000..ce4f3e0 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_pss_sign.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_pss_sign +br_rsa_pss_sign_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_pss_sign; +#elif BR_LOMUL + return &br_rsa_i15_pss_sign; +#else + return &br_rsa_i31_pss_sign; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_default_pss_vrfy.c b/src/bearssl/src/rsa/rsa_default_pss_vrfy.c new file mode 100644 index 0000000..e3a9ad9 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_default_pss_vrfy.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +br_rsa_pss_vrfy +br_rsa_pss_vrfy_get_default(void) +{ +#if BR_INT128 || BR_UMUL128 + return &br_rsa_i62_pss_vrfy; +#elif BR_LOMUL + return &br_rsa_i15_pss_vrfy; +#else + return &br_rsa_i31_pss_vrfy; +#endif +} diff --git a/src/bearssl/src/rsa/rsa_i15_keygen.c b/src/bearssl/src/rsa/rsa_i15_keygen.c index 1c011fe..e8da419 100644 --- a/src/bearssl/src/rsa/rsa_i15_keygen.c +++ b/src/bearssl/src/rsa/rsa_i15_keygen.c @@ -318,9 +318,9 @@ mkprime(const br_prng_class **rng, uint16_t *x, uint32_t esize, continue; } if ((pubexp == 3 && m3 == 1) - || (pubexp == 5 && m5 == 5) - || (pubexp == 7 && m5 == 7) - || (pubexp == 11 && m5 == 11)) + || (pubexp == 5 && m5 == 1) + || (pubexp == 7 && m7 == 1) + || (pubexp == 11 && m11 == 1)) { continue; } diff --git a/src/bearssl/src/rsa/rsa_i15_modulus.c b/src/bearssl/src/rsa/rsa_i15_modulus.c index d61c794..16458c3 100644 --- a/src/bearssl/src/rsa/rsa_i15_modulus.c +++ b/src/bearssl/src/rsa/rsa_i15_modulus.c @@ -28,7 +28,7 @@ size_t br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk) { - uint16_t tmp[2 * ((BR_MAX_RSA_SIZE + 14) / 15) + 5]; + uint16_t tmp[4 * (((BR_MAX_RSA_SIZE / 2) + 14) / 15) + 5]; uint16_t *t, *p, *q; const unsigned char *pbuf, *qbuf; size_t nlen, plen, qlen, tlen; diff --git a/src/bearssl/src/rsa/rsa_i15_pss_sign.c b/src/bearssl/src/rsa/rsa_i15_pss_sign.c new file mode 100644 index 0000000..dd9385b --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_pss_sign.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash, + salt_len, sk->n_bitlen, x)) + { + return 0; + } + return br_rsa_i15_private(x, sk); +} diff --git a/src/bearssl/src/rsa/rsa_i15_pss_vrfy.c b/src/bearssl/src/rsa/rsa_i15_pss_vrfy.c new file mode 100644 index 0000000..7d9f2cb --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i15_pss_vrfy.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i15_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i15_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pss_sig_unpad(hf_data, hf_mgf1, + hash, salt_len, pk, sig); +} diff --git a/src/bearssl/src/rsa/rsa_i31_keygen_inner.c b/src/bearssl/src/rsa/rsa_i31_keygen_inner.c index 9ec881b..98df445 100644 --- a/src/bearssl/src/rsa/rsa_i31_keygen_inner.c +++ b/src/bearssl/src/rsa/rsa_i31_keygen_inner.c @@ -340,9 +340,9 @@ mkprime(const br_prng_class **rng, uint32_t *x, uint32_t esize, continue; } if ((pubexp == 3 && m3 == 1) - || (pubexp == 5 && m5 == 5) - || (pubexp == 7 && m5 == 7) - || (pubexp == 11 && m5 == 11)) + || (pubexp == 5 && m5 == 1) + || (pubexp == 7 && m7 == 1) + || (pubexp == 11 && m11 == 1)) { continue; } diff --git a/src/bearssl/src/rsa/rsa_i31_modulus.c b/src/bearssl/src/rsa/rsa_i31_modulus.c index c469cf3..f5f997f 100644 --- a/src/bearssl/src/rsa/rsa_i31_modulus.c +++ b/src/bearssl/src/rsa/rsa_i31_modulus.c @@ -28,7 +28,7 @@ size_t br_rsa_i31_compute_modulus(void *n, const br_rsa_private_key *sk) { - uint32_t tmp[2 * ((BR_MAX_RSA_SIZE + 30) / 31) + 5]; + uint32_t tmp[4 * (((BR_MAX_RSA_SIZE / 2) + 30) / 31) + 5]; uint32_t *t, *p, *q; const unsigned char *pbuf, *qbuf; size_t nlen, plen, qlen, tlen; diff --git a/src/bearssl/src/rsa/rsa_i31_pss_sign.c b/src/bearssl/src/rsa/rsa_i31_pss_sign.c new file mode 100644 index 0000000..b06f3e2 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_pss_sign.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash, + salt_len, sk->n_bitlen, x)) + { + return 0; + } + return br_rsa_i31_private(x, sk); +} diff --git a/src/bearssl/src/rsa/rsa_i31_pss_vrfy.c b/src/bearssl/src/rsa/rsa_i31_pss_vrfy.c new file mode 100644 index 0000000..77a9b28 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i31_pss_vrfy.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i31_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i31_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pss_sig_unpad(hf_data, hf_mgf1, + hash, salt_len, pk, sig); +} diff --git a/src/bearssl/src/rsa/rsa_i32_pss_sign.c b/src/bearssl/src/rsa/rsa_i32_pss_sign.c new file mode 100644 index 0000000..0f72f92 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_pss_sign.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i32_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash, + salt_len, sk->n_bitlen, x)) + { + return 0; + } + return br_rsa_i32_private(x, sk); +} diff --git a/src/bearssl/src/rsa/rsa_i32_pss_vrfy.c b/src/bearssl/src/rsa/rsa_i32_pss_vrfy.c new file mode 100644 index 0000000..2e70d23 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i32_pss_vrfy.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i32_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i32_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pss_sig_unpad(hf_data, hf_mgf1, + hash, salt_len, pk, sig); +} diff --git a/src/bearssl/src/rsa/rsa_i62_pss_sign.c b/src/bearssl/src/rsa/rsa_i62_pss_sign.c new file mode 100644 index 0000000..7232f6d --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_pss_sign.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x) +{ + if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash, + salt_len, sk->n_bitlen, x)) + { + return 0; + } + return br_rsa_i62_private(x, sk); +} + +/* see bearssl_rsa.h */ +br_rsa_pss_sign +br_rsa_i62_pss_sign_get(void) +{ + return &br_rsa_i62_pss_sign; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_pss_sign +br_rsa_i62_pss_sign_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_i62_pss_vrfy.c b/src/bearssl/src/rsa/rsa_i62_pss_vrfy.c new file mode 100644 index 0000000..e726e82 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_i62_pss_vrfy.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +#if BR_INT128 || BR_UMUL128 + +/* see bearssl_rsa.h */ +uint32_t +br_rsa_i62_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk) +{ + unsigned char sig[BR_MAX_RSA_SIZE >> 3]; + + if (xlen > (sizeof sig)) { + return 0; + } + memcpy(sig, x, xlen); + if (!br_rsa_i62_public(sig, xlen, pk)) { + return 0; + } + return br_rsa_pss_sig_unpad(hf_data, hf_mgf1, + hash, salt_len, pk, sig); +} + +/* see bearssl_rsa.h */ +br_rsa_pss_vrfy +br_rsa_i62_pss_vrfy_get(void) +{ + return &br_rsa_i62_pss_vrfy; +} + +#else + +/* see bearssl_rsa.h */ +br_rsa_pss_vrfy +br_rsa_i62_pss_vrfy_get(void) +{ + return 0; +} + +#endif diff --git a/src/bearssl/src/rsa/rsa_pss_sig_pad.c b/src/bearssl/src/rsa/rsa_pss_sig_pad.c new file mode 100644 index 0000000..13e9027 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_pss_sig_pad.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_rsa_pss_sig_pad(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + uint32_t n_bitlen, unsigned char *x) +{ + size_t xlen, hash_len; + br_hash_compat_context hc; + unsigned char *salt, *seed; + + hash_len = br_digest_size(hf_data); + + /* + * The padded string is one bit smaller than the modulus; + * notably, if the modulus length is equal to 1 modulo 8, then + * the padded string will be one _byte_ smaller, and the first + * byte will be set to 0. We apply these transformations here. + */ + n_bitlen --; + if ((n_bitlen & 7) == 0) { + *x ++ = 0; + } + xlen = (n_bitlen + 7) >> 3; + + /* + * Check that the modulus is large enough for the hash value + * length combined with the intended salt length. + */ + if (hash_len > xlen || salt_len > xlen + || (hash_len + salt_len + 2) > xlen) + { + return 0; + } + + /* + * Produce a random salt. + */ + salt = x + xlen - hash_len - salt_len - 1; + if (salt_len != 0) { + (*rng)->generate(rng, salt, salt_len); + } + + /* + * Compute the seed for MGF1. + */ + seed = x + xlen - hash_len - 1; + hf_data->init(&hc.vtable); + memset(seed, 0, 8); + hf_data->update(&hc.vtable, seed, 8); + hf_data->update(&hc.vtable, hash, hash_len); + hf_data->update(&hc.vtable, salt, salt_len); + hf_data->out(&hc.vtable, seed); + + /* + * Prepare string PS (padded salt). The salt is already at the + * right place. + */ + memset(x, 0, xlen - salt_len - hash_len - 2); + x[xlen - salt_len - hash_len - 2] = 0x01; + + /* + * Generate the mask and XOR it into PS. + */ + br_mgf1_xor(x, xlen - hash_len - 1, hf_mgf1, seed, hash_len); + + /* + * Clear the top bits to ensure the value is lower than the + * modulus. + */ + x[0] &= 0xFF >> (((uint32_t)xlen << 3) - n_bitlen); + + /* + * The seed (H) is already in the right place. We just set the + * last byte. + */ + x[xlen - 1] = 0xBC; + + return 1; +} diff --git a/src/bearssl/src/rsa/rsa_pss_sig_unpad.c b/src/bearssl/src/rsa/rsa_pss_sig_unpad.c new file mode 100644 index 0000000..a9f8ca3 --- /dev/null +++ b/src/bearssl/src/rsa/rsa_pss_sig_unpad.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_rsa_pss_sig_unpad(const br_hash_class *hf_data, + const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + const br_rsa_public_key *pk, unsigned char *x) +{ + size_t u, xlen, hash_len; + br_hash_compat_context hc; + unsigned char *seed, *salt; + unsigned char tmp[64]; + uint32_t r, n_bitlen; + + hash_len = br_digest_size(hf_data); + + /* + * Value r will be set to a non-zero value is any test fails. + */ + r = 0; + + /* + * The value bit length (as an integer) must be strictly less than + * that of the modulus. + */ + for (u = 0; u < pk->nlen; u ++) { + if (pk->n[u] != 0) { + break; + } + } + if (u == pk->nlen) { + return 0; + } + n_bitlen = BIT_LENGTH(pk->n[u]) + ((uint32_t)(pk->nlen - u - 1) << 3); + n_bitlen --; + if ((n_bitlen & 7) == 0) { + r |= *x ++; + } else { + r |= x[0] & (0xFF << (n_bitlen & 7)); + } + xlen = (n_bitlen + 7) >> 3; + + /* + * Check that the modulus is large enough for the hash value + * length combined with the intended salt length. + */ + if (hash_len > xlen || salt_len > xlen + || (hash_len + salt_len + 2) > xlen) + { + return 0; + } + + /* + * Check value of rightmost byte. + */ + r |= x[xlen - 1] ^ 0xBC; + + /* + * Generate the mask and XOR it into the first bytes to reveal PS; + * we must also mask out the leading bits. + */ + seed = x + xlen - hash_len - 1; + br_mgf1_xor(x, xlen - hash_len - 1, hf_mgf1, seed, hash_len); + if ((n_bitlen & 7) != 0) { + x[0] &= 0xFF >> (8 - (n_bitlen & 7)); + } + + /* + * Check that all padding bytes have the expected value. + */ + for (u = 0; u < (xlen - hash_len - salt_len - 2); u ++) { + r |= x[u]; + } + r |= x[xlen - hash_len - salt_len - 2] ^ 0x01; + + /* + * Recompute H. + */ + salt = x + xlen - hash_len - salt_len - 1; + hf_data->init(&hc.vtable); + memset(tmp, 0, 8); + hf_data->update(&hc.vtable, tmp, 8); + hf_data->update(&hc.vtable, hash, hash_len); + hf_data->update(&hc.vtable, salt, salt_len); + hf_data->out(&hc.vtable, tmp); + + /* + * Check that the recomputed H value matches the one appearing + * in the string. + */ + for (u = 0; u < hash_len; u ++) { + r |= tmp[u] ^ x[(xlen - salt_len - 1) + u]; + } + + return EQ0(r); +} diff --git a/src/bearssl/src/ssl/ssl_client_full.c b/src/bearssl/src/ssl/ssl_client_full.c index bc34e92..fd35b3c 100644 --- a/src/bearssl/src/ssl/ssl_client_full.c +++ b/src/bearssl/src/ssl/ssl_client_full.c @@ -119,7 +119,6 @@ br_ssl_client_init_full(br_ssl_client_context *cc, * to TLS-1.2 (inclusive). */ br_ssl_client_zero(cc); - memset(xc, 0, sizeof *xc); br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); /* diff --git a/src/bearssl/src/ssl/ssl_engine.c b/src/bearssl/src/ssl/ssl_engine.c index f4ffe18..f59fe1a 100644 --- a/src/bearssl/src/ssl/ssl_engine.c +++ b/src/bearssl/src/ssl/ssl_engine.c @@ -1232,6 +1232,21 @@ void br_ssl_engine_close(br_ssl_engine_context *cc) { if (!br_ssl_engine_closed(cc)) { + /* + * If we are not already closed, then we need to + * initiate the closure. Once closing, any incoming + * application data is discarded; we should also discard + * application data which is already there but has not + * been acknowledged by the application yet (this mimics + * usual semantics on BSD sockets: you cannot read() + * once you called close(), even if there was some + * unread data already buffered). + */ + size_t len; + + if (br_ssl_engine_recvapp_buf(cc, &len) != NULL && len != 0) { + br_ssl_engine_recvapp_ack(cc, len); + } jump_handshake(cc, 1); } } diff --git a/src/bearssl/src/ssl/ssl_io.c b/src/bearssl/src/ssl/ssl_io.c index e929228..1952615 100644 --- a/src/bearssl/src/ssl/ssl_io.c +++ b/src/bearssl/src/ssl/ssl_io.c @@ -48,8 +48,8 @@ br_sslio_init(br_sslio_context *ctx, * combination of both (the combination matches either). When a match is * achieved, this function returns 0. On error, it returns -1. */ -int -br_run_until(br_sslio_context *ctx, unsigned target) +static int +run_until(br_sslio_context *ctx, unsigned target) { for (;;) { unsigned state; @@ -152,7 +152,7 @@ br_sslio_read(br_sslio_context *ctx, void *dst, size_t len) if (len == 0) { return 0; } - if (br_run_until(ctx, BR_SSL_RECVAPP) < 0) { + if (run_until(ctx, BR_SSL_RECVAPP) < 0) { return -1; } buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen); @@ -194,7 +194,7 @@ br_sslio_write(br_sslio_context *ctx, const void *src, size_t len) if (len == 0) { return 0; } - if (br_run_until(ctx, BR_SSL_SENDAPP) < 0) { + if (run_until(ctx, BR_SSL_SENDAPP) < 0) { return -1; } buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen); @@ -238,7 +238,7 @@ br_sslio_flush(br_sslio_context *ctx) * first sent down the wire before considering anything else. */ br_ssl_engine_flush(ctx->engine, 0); - return br_run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP); + return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP); } /* see bearssl_ssl.h */ @@ -252,7 +252,7 @@ br_sslio_close(br_sslio_context *ctx) */ size_t len; - br_run_until(ctx, BR_SSL_RECVAPP); + run_until(ctx, BR_SSL_RECVAPP); if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) { br_ssl_engine_recvapp_ack(ctx->engine, len); } diff --git a/src/bearssl/src/x509/asn1.t0 b/src/bearssl/src/x509/asn1.t0 index ba59252..c329514 100644 --- a/src/bearssl/src/x509/asn1.t0 +++ b/src/bearssl/src/x509/asn1.t0 @@ -480,7 +480,7 @@ OID: id-at-commonName 2.5.4.3 \ 66 noncharacters, and also the surrogate range; this function does NOT \ check that the value is in the 0..10FFFF range. : valid-unicode? ( val -- bool ) - dup 0xFDD0 0xFEDF between? if drop 0 ret then + dup 0xFDD0 0xFDEF between? if drop 0 ret then dup 0xD800 0xDFFF between? if drop 0 ret then 0xFFFF and 0xFFFE < ; diff --git a/src/bearssl/src/x509/skey_decoder.c b/src/bearssl/src/x509/skey_decoder.c index f4e43e7..9e285d7 100644 --- a/src/bearssl/src/x509/skey_decoder.c +++ b/src/bearssl/src/x509/skey_decoder.c @@ -155,7 +155,7 @@ static const unsigned char t0_codeblock[] = { 0x02, 0x06, 0x1E, 0x00, 0x00, 0x19, 0x19, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x00, 0x20, 0x14, 0x06, 0x08, 0x01, 0x01, 0x21, 0x20, 0x22, 0x20, 0x04, 0x75, 0x13, 0x00, 0x00, 0x01, - T0_INT2(3 * BR_X509_BUFSIZE_KEY), 0x00, 0x01, 0x01, 0x87, 0xFF, 0xFF, + T0_INT2(3 * BR_X509_BUFSIZE_SIG), 0x00, 0x01, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x54, 0x57, 0x01, 0x02, 0x3E, 0x55, 0x01, 0x01, 0x0E, 0x06, 0x02, 0x30, 0x16, 0x57, 0x01, 0x02, 0x19, 0x0D, 0x06, 0x06, 0x13, 0x3B, 0x44, 0x32, 0x04, 0x1C, 0x01, 0x04, 0x19, 0x0D, 0x06, 0x08, 0x13, 0x3B, 0x01, diff --git a/src/bearssl/src/x509/skey_decoder.t0 b/src/bearssl/src/x509/skey_decoder.t0 index 5b59421..f00e614 100644 --- a/src/bearssl/src/x509/skey_decoder.t0 +++ b/src/bearssl/src/x509/skey_decoder.t0 @@ -80,7 +80,7 @@ cc: read-blob-inner ( addr len -- addr len ) { \ Get the length of the key_data buffer. : len-key_data - CX 0 8191 { 3 * BR_X509_BUFSIZE_KEY } ; + CX 0 8191 { 3 * BR_X509_BUFSIZE_SIG } ; \ Get the address and length for the key_data buffer. : addr-len-key_data ( -- addr len ) diff --git a/src/bearssl/src/x509/x509_minimal.c b/src/bearssl/src/x509/x509_minimal.c index 3b876ef..6103c08 100644 --- a/src/bearssl/src/x509/x509_minimal.c +++ b/src/bearssl/src/x509/x509_minimal.c @@ -703,7 +703,7 @@ static const unsigned char t0_codeblock[] = { 0x76, 0x00, 0x00, 0x01, 0x00, 0x30, 0x31, 0x0B, 0x42, 0x00, 0x00, 0x01, 0x81, 0x70, 0x00, 0x00, 0x01, 0x82, 0x0D, 0x00, 0x00, 0x01, 0x82, 0x22, 0x00, 0x00, 0x01, 0x82, 0x05, 0x00, 0x00, 0x01, 0x03, 0x33, 0x01, 0x03, - 0x33, 0x00, 0x00, 0x25, 0x01, 0x83, 0xFB, 0x50, 0x01, 0x83, 0xFD, 0x5F, + 0x33, 0x00, 0x00, 0x25, 0x01, 0x83, 0xFB, 0x50, 0x01, 0x83, 0xFB, 0x6F, 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x83, 0xB0, 0x00, 0x01, 0x83, 0xBF, 0x7F, 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x15, 0x01, 0x83, 0xFF, 0x7E, 0x0D, 0x00 diff --git a/src/bearssl/src/x509/x509_minimal.t0 b/src/bearssl/src/x509/x509_minimal.t0 index 1e60016..50995dc 100644 --- a/src/bearssl/src/x509/x509_minimal.t0 +++ b/src/bearssl/src/x509/x509_minimal.t0 @@ -106,7 +106,7 @@ preamble { * -- Extensions: extension values are processed in due order. * * -- Basic Constraints: for all certificates except EE, must be - * present, indicate a CA, and have a path legnth compatible with + * present, indicate a CA, and have a path length compatible with * the chain length so far. * * -- Key Usage: for the EE, if present, must allow signatures diff --git a/src/bearssl_ec.h b/src/bearssl_ec.h index b03984a..9c76c95 100644 --- a/src/bearssl_ec.h +++ b/src/bearssl_ec.h @@ -108,7 +108,7 @@ extern "C" { * * - The multipliers (integers) MUST be lower than the subgroup order. * If this property is not met, then the result is indeterminate, - * but an error value is not ncessearily returned. + * but an error value is not necessarily returned. * * * ## ECDSA @@ -451,6 +451,42 @@ extern const br_ec_impl br_ec_p256_m15; */ extern const br_ec_impl br_ec_p256_m31; +/** + * \brief EC implementation "m62" (specialised code) for P-256. + * + * This implementation uses custom code relying on multiplication of + * integers up to 64 bits, with a 128-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_p256_m62_get()` to dynamically obtain a pointer + * to that implementation. + */ +extern const br_ec_impl br_ec_p256_m62; + +/** + * \brief Get the "m62" implementation of P-256, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_p256_m62_get(void); + +/** + * \brief EC implementation "m64" (specialised code) for P-256. + * + * This implementation uses custom code relying on multiplication of + * integers up to 64 bits, with a 128-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_p256_m64_get()` to dynamically obtain a pointer + * to that implementation. + */ +extern const br_ec_impl br_ec_p256_m64; + +/** + * \brief Get the "m64" implementation of P-256, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_p256_m64_get(void); + /** * \brief EC implementation "i15" (generic code) for Curve25519. * @@ -507,6 +543,54 @@ extern const br_ec_impl br_ec_c25519_m15; */ extern const br_ec_impl br_ec_c25519_m31; +/** + * \brief EC implementation "m62" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 62 bits, with a 124-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_c25519_m62_get()` to dynamically obtain a pointer + * to that implementation. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m62; + +/** + * \brief Get the "m62" implementation of Curve25519, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_c25519_m62_get(void); + +/** + * \brief EC implementation "m64" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 64 bits, with a 128-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_c25519_m64_get()` to dynamically obtain a pointer + * to that implementation. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m64; + +/** + * \brief Get the "m64" implementation of Curve25519, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_c25519_m64_get(void); + /** * \brief Aggregate EC implementation "m15". * diff --git a/src/bearssl_hash.h b/src/bearssl_hash.h index 3b15ba7..ca4fa26 100644 --- a/src/bearssl_hash.h +++ b/src/bearssl_hash.h @@ -724,7 +724,7 @@ void br_sha256_update(br_sha256_context *ctx, const void *data, size_t len); */ void br_sha256_out(const br_sha256_context *ctx, void *out); -#if BR_DOXYGEN_IGNORE +#ifdef BR_DOXYGEN_IGNORE /** * \brief Save SHA-256 running state. * @@ -742,7 +742,7 @@ uint64_t br_sha256_state(const br_sha256_context *ctx, void *out); #define br_sha256_state br_sha224_state #endif -#if BR_DOXYGEN_IGNORE +#ifdef BR_DOXYGEN_IGNORE /** * \brief Restore SHA-256 running state. * diff --git a/src/bearssl_kdf.h b/src/bearssl_kdf.h index f018d7e..955b843 100644 --- a/src/bearssl_kdf.h +++ b/src/bearssl_kdf.h @@ -81,6 +81,30 @@ extern "C" { * Note that the HKDF total output size (the number of bytes that * HKDF-Expand is willing to produce) is limited: if the hash output size * is _n_ bytes, then the maximum output size is _255*n_. + * + * ## SHAKE + * + * SHAKE is defined in + * [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final) + * under two versions: SHAKE128 and SHAKE256, offering an alleged + * "security level" of 128 and 256 bits, respectively (SHAKE128 is + * about 20 to 25% faster than SHAKE256). SHAKE internally relies on + * the Keccak family of sponge functions, not on any externally provided + * hash function. Contrary to HKDF, SHAKE does not have a concept of + * either a "salt" or an "info" string. The API consists in four + * functions: + * + * - `br_shake_init()`: initialize a SHAKE context for a given + * security level. + * + * - `br_shake_inject()`: inject more input bytes. This function may be + * called repeatedly if the input data is provided by chunks. + * + * - `br_shake_flip()`: end the data injection process, and start the + * data production process. + * + * - `br_shake_produce()`: get the next bytes of output. This function + * may be called several times to obtain the full output by chunks. */ /** @@ -178,6 +202,81 @@ void br_hkdf_flip(br_hkdf_context *hc); size_t br_hkdf_produce(br_hkdf_context *hc, const void *info, size_t info_len, void *out, size_t out_len); +/** + * \brief SHAKE context. + * + * The HKDF context is initialized with a "security level". The internal + * notion is called "capacity"; the capacity is twice the security level + * (for instance, SHAKE128 has capacity 256). + * + * The caller is responsible for allocating the context where + * appropriate. Context initialisation and usage incurs no dynamic + * allocation, so there is no release function. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + unsigned char dbuf[200]; + size_t dptr; + size_t rate; + uint64_t A[25]; +#endif +} br_shake_context; + +/** + * \brief SHAKE context initialization. + * + * The context is initialized for the provided "security level". + * Internally, this sets the "capacity" to twice the security level; + * thus, for SHAKE128, the `security_level` parameter should be 128, + * which corresponds to a 256-bit capacity. + * + * Allowed security levels are all multiples of 32, from 32 to 768, + * inclusive. Larger security levels imply lower performance; levels + * beyond 256 bits don't make much sense. Standard levels are 128 + * and 256 bits (for SHAKE128 and SHAKE256, respectively). + * + * \param sc SHAKE context to initialise. + * \param security_level security level (in bits). + */ +void br_shake_init(br_shake_context *sc, int security_level); + +/** + * \brief SHAKE input injection. + * + * This function injects some more input bytes ("key material") into + * SHAKE. This function may be called several times, after `br_shake_init()` + * but before `br_shake_flip()`. + * + * \param sc SHAKE context. + * \param data extra input bytes. + * \param len number of extra input bytes. + */ +void br_shake_inject(br_shake_context *sc, const void *data, size_t len); + +/** + * \brief SHAKE switch to production phase. + * + * This call terminates the input injection process, and starts the + * output production process. + * + * \param sc SHAKE context. + */ +void br_shake_flip(br_shake_context *hc); + +/** + * \brief SHAKE output production. + * + * Produce more output bytes from the current state. This function may be + * called several times, but only after `br_shake_flip()`. + * + * There is no practical limit to the number of bytes that may be produced. + * + * \param sc SHAKE context. + * \param out destination buffer for the SHAKE output. + * \param len the length of the requested output (in bytes). + */ +void br_shake_produce(br_shake_context *sc, void *out, size_t len); + #ifdef __cplusplus } #endif diff --git a/src/bearssl_rsa.h b/src/bearssl_rsa.h index 0eaf2a2..0a069fd 100644 --- a/src/bearssl_rsa.h +++ b/src/bearssl_rsa.h @@ -28,6 +28,7 @@ #include #include +#include "bearssl_hash.h" #include "bearssl_rand.h" #ifdef __cplusplus @@ -279,6 +280,55 @@ typedef uint32_t (*br_rsa_pkcs1_vrfy)(const unsigned char *x, size_t xlen, const unsigned char *hash_oid, size_t hash_len, const br_rsa_public_key *pk, unsigned char *hash_out); +/** + * \brief Type for a RSA signature verification engine (PSS). + * + * Parameters are: + * + * - The signature itself. The provided array is NOT modified. + * + * - The hash function which was used to hash the message. + * + * - The hash function to use with MGF1 within the PSS padding. This + * is not necessarily the same hash function as the one which was + * used to hash the signed message. + * + * - The hashed message (as an array of bytes). + * + * - The PSS salt length (in bytes). + * + * - The public key. + * + * **Constraints:** + * + * - Hash message length MUST be no more than 64 bytes. + * + * Note that, contrary to PKCS#1 v1.5 signature, the hash value of the + * signed data cannot be extracted from the signature; it must be + * provided to the verification function. + * + * This function verifies that the signature length (`xlen`) matches the + * modulus length (this function returns 0 on mismatch). If the modulus + * size exceeds the maximum supported RSA size, then the function also + * returns 0. + * + * Returned value is 1 on success, 0 on error. + * + * Implementations of this type need not be constant-time. + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pss_vrfy)(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + /** * \brief Type for a RSA encryption engine (OAEP). * @@ -385,6 +435,53 @@ typedef uint32_t (*br_rsa_pkcs1_sign)(const unsigned char *hash_oid, const unsigned char *hash, size_t hash_len, const br_rsa_private_key *sk, unsigned char *x); +/** + * \brief Type for a RSA signature generation engine (PSS). + * + * Parameters are: + * + * - An initialized PRNG for salt generation. If the salt length is + * zero (`salt_len` parameter), then the PRNG is optional (this is + * not the typical case, as the security proof of RSA/PSS is + * tighter when a non-empty salt is used). + * + * - The hash function which was used to hash the message. + * + * - The hash function to use with MGF1 within the PSS padding. This + * is not necessarily the same function as the one used to hash the + * message. + * + * - The hashed message. + * + * - The salt length, in bytes. + * + * - The RSA private key. + * + * - The output buffer, that receives the signature. + * + * Returned value is 1 on success, 0 on error. Error conditions include + * a too small modulus for the provided hash and salt lengths, or some + * invalid key parameters. The signature length is exactly + * `(sk->n_bitlen+7)/8` bytes. + * + * This function is expected to be constant-time with regards to the + * private key bytes (lengths of the modulus and the individual factors + * may leak, though) and to the hashed data. + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pss_sign)(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + /** * \brief Encoded OID for SHA-1 (in RSA PKCS#1 signatures). */ @@ -476,7 +573,7 @@ uint32_t br_rsa_i32_public(unsigned char *x, size_t xlen, const br_rsa_public_key *pk); /** - * \brief RSA signature verification engine "i32". + * \brief RSA signature verification engine "i32" (PKCS#1 v1.5 signatures). * * \see br_rsa_pkcs1_vrfy * @@ -492,6 +589,24 @@ uint32_t br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen, const unsigned char *hash_oid, size_t hash_len, const br_rsa_public_key *pk, unsigned char *hash_out); +/** + * \brief RSA signature verification engine "i32" (PSS signatures). + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + /** * \brief RSA private key engine "i32". * @@ -505,7 +620,7 @@ uint32_t br_rsa_i32_private(unsigned char *x, const br_rsa_private_key *sk); /** - * \brief RSA signature generation engine "i32". + * \brief RSA signature generation engine "i32" (PKCS#1 v1.5 signatures). * * \see br_rsa_pkcs1_sign * @@ -520,6 +635,25 @@ uint32_t br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid, const unsigned char *hash, size_t hash_len, const br_rsa_private_key *sk, unsigned char *x); +/** + * \brief RSA signature generation engine "i32" (PSS signatures). + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + /* * RSA "i31" engine. Similar to i32, but only 31 bits are used per 32-bit * word. This uses slightly more stack space (about 4% more) and code @@ -540,7 +674,7 @@ uint32_t br_rsa_i31_public(unsigned char *x, size_t xlen, const br_rsa_public_key *pk); /** - * \brief RSA signature verification engine "i31". + * \brief RSA signature verification engine "i31" (PKCS#1 v1.5 signatures). * * \see br_rsa_pkcs1_vrfy * @@ -556,6 +690,24 @@ uint32_t br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen, const unsigned char *hash_oid, size_t hash_len, const br_rsa_public_key *pk, unsigned char *hash_out); +/** + * \brief RSA signature verification engine "i31" (PSS signatures). + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + /** * \brief RSA private key engine "i31". * @@ -569,7 +721,7 @@ uint32_t br_rsa_i31_private(unsigned char *x, const br_rsa_private_key *sk); /** - * \brief RSA signature generation engine "i31". + * \brief RSA signature generation engine "i31" (PKCS#1 v1.5 signatures). * * \see br_rsa_pkcs1_sign * @@ -584,6 +736,25 @@ uint32_t br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid, const unsigned char *hash, size_t hash_len, const br_rsa_private_key *sk, unsigned char *x); +/** + * \brief RSA signature generation engine "i31" (PSS signatures). + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + /* * RSA "i62" engine. Similar to i31, but internal multiplication use * 64x64->128 multiplications. This is available only on architecture @@ -608,7 +779,7 @@ uint32_t br_rsa_i62_public(unsigned char *x, size_t xlen, const br_rsa_public_key *pk); /** - * \brief RSA signature verification engine "i62". + * \brief RSA signature verification engine "i62" (PKCS#1 v1.5 signatures). * * This function is defined only on architecture that offer a 64x64->128 * opcode. Use `br_rsa_i62_pkcs1_vrfy_get()` to dynamically obtain a pointer @@ -628,6 +799,28 @@ uint32_t br_rsa_i62_pkcs1_vrfy(const unsigned char *x, size_t xlen, const unsigned char *hash_oid, size_t hash_len, const br_rsa_public_key *pk, unsigned char *hash_out); +/** + * \brief RSA signature verification engine "i62" (PSS signatures). + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pss_vrfy_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + /** * \brief RSA private key engine "i62". * @@ -645,7 +838,7 @@ uint32_t br_rsa_i62_private(unsigned char *x, const br_rsa_private_key *sk); /** - * \brief RSA signature generation engine "i62". + * \brief RSA signature generation engine "i62" (PKCS#1 v1.5 signatures). * * This function is defined only on architecture that offer a 64x64->128 * opcode. Use `br_rsa_i62_pkcs1_sign_get()` to dynamically obtain a pointer @@ -664,6 +857,29 @@ uint32_t br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid, const unsigned char *hash, size_t hash_len, const br_rsa_private_key *sk, unsigned char *x); +/** + * \brief RSA signature generation engine "i62" (PSS signatures). + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pss_sign_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + /** * \brief Get the RSA "i62" implementation (public key operations), * if available. @@ -673,13 +889,21 @@ uint32_t br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid, br_rsa_public br_rsa_i62_public_get(void); /** - * \brief Get the RSA "i62" implementation (PKCS#1 signature verification), + * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature verification), * if available. * * \return the implementation, or 0. */ br_rsa_pkcs1_vrfy br_rsa_i62_pkcs1_vrfy_get(void); +/** + * \brief Get the RSA "i62" implementation (PSS signature verification), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pss_vrfy br_rsa_i62_pss_vrfy_get(void); + /** * \brief Get the RSA "i62" implementation (private key operations), * if available. @@ -689,13 +913,21 @@ br_rsa_pkcs1_vrfy br_rsa_i62_pkcs1_vrfy_get(void); br_rsa_private br_rsa_i62_private_get(void); /** - * \brief Get the RSA "i62" implementation (PKCS#1 signature generation), + * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature generation), * if available. * * \return the implementation, or 0. */ br_rsa_pkcs1_sign br_rsa_i62_pkcs1_sign_get(void); +/** + * \brief Get the RSA "i62" implementation (PSS signature generation), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pss_sign br_rsa_i62_pss_sign_get(void); + /** * \brief Get the RSA "i62" implementation (OAEP encryption), * if available. @@ -732,7 +964,7 @@ uint32_t br_rsa_i15_public(unsigned char *x, size_t xlen, const br_rsa_public_key *pk); /** - * \brief RSA signature verification engine "i15". + * \brief RSA signature verification engine "i15" (PKCS#1 v1.5 signatures). * * \see br_rsa_pkcs1_vrfy * @@ -748,6 +980,24 @@ uint32_t br_rsa_i15_pkcs1_vrfy(const unsigned char *x, size_t xlen, const unsigned char *hash_oid, size_t hash_len, const br_rsa_public_key *pk, unsigned char *hash_out); +/** + * \brief RSA signature verification engine "i15" (PSS signatures). + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + /** * \brief RSA private key engine "i15". * @@ -761,7 +1011,7 @@ uint32_t br_rsa_i15_private(unsigned char *x, const br_rsa_private_key *sk); /** - * \brief RSA signature generation engine "i15". + * \brief RSA signature generation engine "i15" (PKCS#1 v1.5 signatures). * * \see br_rsa_pkcs1_sign * @@ -776,6 +1026,25 @@ uint32_t br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid, const unsigned char *hash, size_t hash_len, const br_rsa_private_key *sk, unsigned char *x); +/** + * \brief RSA signature generation engine "i15" (PSS signatures). + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + /** * \brief Get "default" RSA implementation (public-key operations). * @@ -797,7 +1066,7 @@ br_rsa_public br_rsa_public_get_default(void); br_rsa_private br_rsa_private_get_default(void); /** - * \brief Get "default" RSA implementation (PKCS#1 signature verification). + * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature verification). * * This returns the preferred implementation of RSA (signature verification) * on the current system. @@ -807,7 +1076,17 @@ br_rsa_private br_rsa_private_get_default(void); br_rsa_pkcs1_vrfy br_rsa_pkcs1_vrfy_get_default(void); /** - * \brief Get "default" RSA implementation (PKCS#1 signature generation). + * \brief Get "default" RSA implementation (PSS signature verification). + * + * This returns the preferred implementation of RSA (signature verification) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pss_vrfy br_rsa_pss_vrfy_get_default(void); + +/** + * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature generation). * * This returns the preferred implementation of RSA (signature generation) * on the current system. @@ -816,6 +1095,16 @@ br_rsa_pkcs1_vrfy br_rsa_pkcs1_vrfy_get_default(void); */ br_rsa_pkcs1_sign br_rsa_pkcs1_sign_get_default(void); +/** + * \brief Get "default" RSA implementation (PSS signature generation). + * + * This returns the preferred implementation of RSA (signature generation) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pss_sign br_rsa_pss_sign_get_default(void); + /** * \brief Get "default" RSA implementation (OAEP encryption). * diff --git a/src/bearssl_ssl.h b/src/bearssl_ssl.h index d28405a..5dc2228 100644 --- a/src/bearssl_ssl.h +++ b/src/bearssl_ssl.h @@ -1250,8 +1250,8 @@ static inline void br_ssl_engine_set_versions(br_ssl_engine_context *cc, unsigned version_min, unsigned version_max) { - cc->version_min = version_min; - cc->version_max = version_max; + cc->version_min = (uint16_t)version_min; + cc->version_max = (uint16_t)version_max; } /** @@ -1324,7 +1324,7 @@ br_ssl_engine_set_protocol_names(br_ssl_engine_context *ctx, const char **names, size_t num) { ctx->protocol_names = names; - ctx->protocol_names_num = num; + ctx->protocol_names_num = (uint16_t)num; } /** @@ -2102,7 +2102,7 @@ void br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len); /** * \brief Get buffer for received application data. * - * If the engine has received application data from the peer, hen this + * If the engine has received application data from the peer, then this * call returns a pointer to the buffer from where such data shall be * read, and its length is written in `*len`. Otherwise, `*len` is set * to 0 and `NULL` is returned. @@ -4154,20 +4154,6 @@ int br_sslio_flush(br_sslio_context *cc); */ int br_sslio_close(br_sslio_context *cc); -/* - * Run the engine, until the specified target state is achieved, or - * an error occurs. The target state is SENDAPP, RECVAPP, or the - * combination of both (the combination matches either). When a match is - * achieved, this function returns 0. On error, it returns -1. - * - * Static function made public since we would like to be able to - * initialize the ssl socket in a single function - * - * \return 0 on success, or -1 on error. - */ -int -br_run_until(br_sslio_context *ctx, unsigned target); - /* ===================================================================== */ /* diff --git a/src/config.h b/src/config.h index d7c2e19..d07408a 100644 --- a/src/config.h +++ b/src/config.h @@ -108,9 +108,27 @@ #define BR_RDRAND 1 */ +/* + * When BR_USE_GETENTROPY is enabled, the SSL engine will use the + * getentropy() function to obtain quality randomness for seeding its + * internal PRNG. On Linux and FreeBSD, getentropy() is implemented by + * the standard library with the system call getrandom(); on OpenBSD, + * getentropy() is the system call, and there is no getrandom() wrapper, + * hence the use of the getentropy() function for maximum portability. + * + * If the getentropy() call fails, and BR_USE_URANDOM is not explicitly + * disabled, then /dev/urandom will be used as a fallback mechanism. On + * FreeBSD and OpenBSD, this does not change much, since /dev/urandom + * will block if not enough entropy has been obtained since last boot. + * On Linux, /dev/urandom might not block, which can be troublesome in + * early boot stages, which is why getentropy() is preferred. + * +#define BR_USE_GETENTROPY 1 + */ + /* * When BR_USE_URANDOM is enabled, the SSL engine will use /dev/urandom - * to automatically obtain quality randomness for seedings its internal + * to automatically obtain quality randomness for seeding its internal * PRNG. * #define BR_USE_URANDOM 1 @@ -119,7 +137,7 @@ /* * When BR_USE_WIN32_RAND is enabled, the SSL engine will use the Win32 * (CryptoAPI) functions (CryptAcquireContext(), CryptGenRandom()...) to - * automatically obtain quality randomness for seedings its internal PRNG. + * automatically obtain quality randomness for seeding its internal PRNG. * * Note: if both BR_USE_URANDOM and BR_USE_WIN32_RAND are defined, the * former takes precedence. @@ -132,10 +150,10 @@ * the current time from the OS by calling time(), and assuming that the * returned value (a 'time_t') is an integer that counts time in seconds * since the Unix Epoch (Jan 1st, 1970, 00:00 UTC). - * */ #define BR_USE_UNIX_TIME 0 + /* * When BR_USE_WIN32_TIME is enabled, the X.509 validation engine obtains * the current time from the OS by calling the Win32 function @@ -143,8 +161,9 @@ * * Note: if both BR_USE_UNIX_TIME and BR_USE_WIN32_TIME are defined, the * former takes precedence. + * +#define BR_USE_WIN32_TIME 1 */ -#define BR_USE_WIN32_TIME 0 /* * When BR_ARMEL_CORTEXM_GCC is enabled, some operations are replaced with @@ -158,9 +177,7 @@ * Note: if BR_LOMUL is not explicitly enabled or disabled, then * enabling BR_ARMEL_CORTEXM_GCC also enables BR_LOMUL. */ -#ifdef ARDUINO_ARCH_SAMD #define BR_ARMEL_CORTEXM_GCC 1 -#endif /* * When BR_AES_X86NI is enabled, the AES implementation using the x86 "NI" diff --git a/src/inner.h b/src/inner.h index 8c7f04e..07e1d0a 100644 --- a/src/inner.h +++ b/src/inner.h @@ -114,6 +114,10 @@ #define BR_64 1 #elif defined(__x86_64__) || defined(_M_X64) #define BR_64 1 +#elif defined(__aarch64__) || defined(_M_ARM64) +#define BR_64 1 +#elif defined(__mips64) +#define BR_64 1 #endif #endif @@ -305,9 +309,20 @@ * values are documented on: * https://sourceforge.net/p/predef/wiki/OperatingSystems/ * - * TODO: enrich the list of detected system. Also add detection for - * alternate system calls like getentropy(), which are usually - * preferable when available. + * Win32's CryptGenRandom() should be available on Windows systems. + * + * /dev/urandom should work on all Unix-like systems (including macOS X). + * + * getentropy() is present on Linux (Glibc 2.25+), FreeBSD (12.0+) and + * OpenBSD (5.6+). For OpenBSD, there does not seem to be easy to use + * macros to test the minimum version, so we just assume that it is + * recent enough (last version without getentropy() has gone out of + * support in May 2015). + * + * Ideally we should use getentropy() on macOS (10.12+) too, but I don't + * know how to test the exact OS version with preprocessor macros. + * + * TODO: enrich the list of detected system. */ #ifndef BR_USE_URANDOM @@ -324,6 +339,15 @@ #endif #endif +#ifndef BR_USE_GETENTROPY +#if (defined __linux__ \ + && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) \ + || (defined __FreeBSD__ && __FreeBSD__ >= 12) \ + || defined __OpenBSD__ +#define BR_USE_GETENTROPY 1 +#endif +#endif + #ifndef BR_USE_WIN32_RAND #if defined _WIN32 || defined _WIN64 #define BR_USE_WIN32_RAND 1 @@ -1943,6 +1967,27 @@ uint32_t br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len, const unsigned char *hash_oid, size_t hash_len, unsigned char *hash_out); +/* + * Apply proper PSS padding. The 'x' buffer is output only: it + * receives the value that is to be exponentiated. + */ +uint32_t br_rsa_pss_sig_pad(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + uint32_t n_bitlen, unsigned char *x); + +/* + * Check PSS padding. The provided value is the one _after_ + * the modular exponentiation; it is modified by this function. + * This function infers the signature length from the public key + * size, i.e. it assumes that this has already been verified (as + * part of the exponentiation). + */ +uint32_t br_rsa_pss_sig_unpad( + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + const br_rsa_public_key *pk, unsigned char *x); + /* * Apply OAEP padding. Returned value is the actual padded string length, * or zero on error. @@ -2448,8 +2493,8 @@ int br_ssl_choose_hash(unsigned bf); #else #define BR_TARGETS_X86_UP \ _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")") -#endif #define BR_TARGETS_X86_DOWN +#endif #pragma GCC diagnostic ignored "-Wpsabi" #endif From 650aec2e1d6b1bafafde214a319575482d40a842 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 10 Feb 2020 11:38:06 -0800 Subject: [PATCH 108/205] Upgrade docs, and bump version --- .travis/library.properties | 2 +- docs/{html => }/_r_e_a_d_m_e_8md.html | 7 +- docs/{html => }/_s_s_l_client_8cpp.html | 7 +- docs/{html => }/_s_s_l_client_8h.html | 7 +- docs/{html => }/_s_s_l_client_8h_source.html | 7 +- .../_s_s_l_client_parameters_8h.html | 7 +- .../_s_s_l_client_parameters_8h_source.html | 7 +- docs/{html => }/_s_s_l_obj_8cpp.html | 7 +- docs/{html => }/_s_s_l_obj_8cpp.js | 0 docs/{html => }/_s_s_l_obj_8h.html | 7 +- docs/{html => }/_s_s_l_obj_8h.js | 0 docs/{html => }/_s_s_l_obj_8h_source.html | 7 +- docs/{html => }/_s_s_l_session_8h.html | 7 +- docs/{html => }/_s_s_l_session_8h_source.html | 7 +- docs/{html => }/_trust_anchors_8md.html | 7 +- docs/{html => }/annotated.html | 3 +- docs/{html => }/annotated_dup.js | 0 docs/{html => }/bc_s.png | Bin docs/{html => }/bdwn.png | Bin .../class_s_s_l_client-members.html | 3 +- docs/{html => }/class_s_s_l_client.html | 7 +- docs/{html => }/class_s_s_l_client.js | 0 docs/{html => }/class_s_s_l_client.png | Bin .../class_s_s_l_session-members.html | 3 +- docs/{html => }/class_s_s_l_session.html | 5 +- docs/{html => }/class_s_s_l_session.js | 0 docs/{html => }/class_s_s_l_session.png | Bin docs/{html => }/classes.html | 3 +- docs/{html => }/closed.png | Bin ...dir_08af369098809553e22f6e2d01d17ab8.html} | 15 +- ...dir_2b7ad9a5497045797632e667f22e5690.html} | 17 +- ...dir_3d74bfb32a2df79d6a95a208a23e6425.html} | 17 +- ...dir_732ec7fb04c2890977d3e4bc2bf648f7.html} | 13 +- ...dir_74140a1086282c406444869b48f08cd0.html} | 17 +- .../dir_c9cc9f7bc7a220ef9764bcae1bd480a3.html | 111 ++ ...dir_d522931ffa1371640980b621734a4381.html} | 20 +- docs/{html => }/doc.png | Bin docs/{html => }/doxygen.css | 0 docs/{html => }/doxygen.png | Bin docs/{html => }/dynsections.js | 0 ...s_s_l_client_impl_8cpp.html => files.html} | 43 +- ...a1af8e8297ef4c3efbcdba.js => files_dup.js} | 6 +- docs/{html => }/folderclosed.png | Bin docs/{html => }/folderopen.png | Bin docs/{html => }/functions.html | 3 +- docs/{html => }/functions_enum.html | 3 +- docs/{html => }/functions_eval.html | 3 +- docs/{html => }/functions_func.html | 3 +- docs/{html => }/functions_vars.html | 3 +- docs/{html => }/globals.html | 14 +- docs/{html => }/globals_defs.html | 8 +- docs/{html => }/hierarchy.html | 3 +- docs/{html => }/hierarchy.js | 0 docs/html/_s_s_l_client_8cpp.js | 4 - docs/html/_s_s_l_client_8h.js | 5 - docs/html/_s_s_l_client_impl_8cpp.js | 4 - docs/html/_s_s_l_client_impl_8h.html | 206 ---- docs/html/_s_s_l_client_impl_8h.js | 19 - docs/html/_s_s_l_client_impl_8h_source.html | 149 --- docs/html/_t_l_s12__only__profile_8c.html | 158 --- docs/html/_t_l_s12__only__profile_8c.js | 4 - docs/html/cert_8h.html | 131 -- docs/html/cert_8h.js | 4 - docs/html/cert_8h_source.html | 106 -- .../html/class_s_s_l_client_impl-members.html | 137 --- docs/html/class_s_s_l_client_impl.html | 1091 ----------------- docs/html/class_s_s_l_client_impl.js | 32 - docs/html/class_s_s_l_client_impl.png | Bin 870 -> 0 bytes .../dir_386349f6a9bc1e2cd0767d257d5e5b91.js | 4 - .../dir_9c42dc81377249a918256dbb9cfb2167.js | 4 - .../dir_d28a4824dc47e487b107a5db32ef43c4.js | 5 - .../dir_dfc5a9f91fbfb9426c406a3f10131a54.js | 4 - docs/html/ec__prime__fast__256_8c.html | 130 -- docs/html/ec__prime__fast__256_8c.js | 4 - docs/html/files.html | 126 -- docs/html/files_dup.js | 6 - docs/html/globals_enum.html | 109 -- docs/html/globals_eval.html | 136 -- docs/html/globals_func.html | 106 -- docs/html/globals_vars.html | 106 -- docs/html/index.html | 177 --- ..._libraries__s_s_l_client__r_e_a_d_m_e.html | 166 --- docs/html/search/all_11.html | 30 - docs/html/search/all_12.html | 30 - docs/html/search/all_12.js | 5 - docs/html/search/all_2.js | 5 - docs/html/search/all_e.js | 11 - docs/html/search/defines_5.js | 4 - docs/html/search/defines_6.html | 30 - docs/html/search/files_0.js | 4 - docs/html/search/files_1.js | 4 - docs/html/search/files_3.html | 30 - docs/html/search/files_4.html | 30 - docs/html/search/files_4.js | 8 - docs/html/search/functions_1.js | 4 - docs/html/search/functions_b.html | 30 - docs/html/search/functions_c.html | 30 - docs/html/search/functions_c.js | 4 - docs/html/search/functions_d.html | 30 - docs/html/search/functions_d.js | 5 - docs/html/search/pages_1.js | 4 - docs/html/search/variables_0.js | 4 - docs/html/search/variables_4.html | 30 - docs/html/search/variables_5.html | 30 - docs/html/search/variables_5.js | 4 - docs/html/trust__anchors_8h.html | 131 -- docs/html/trust__anchors_8h.js | 4 - docs/html/trust__anchors_8h_source.html | 106 -- docs/html/trustanchors_8h.html | 131 -- docs/html/trustanchors_8h.js | 4 - docs/html/trustanchors_8h_source.html | 106 -- docs/index.html | 187 ++- docs/{html => }/jquery.js | 0 ...braries__s_s_l_client__trust_anchors.html} | 9 +- docs/{html => }/menu.js | 0 docs/{html => }/menudata.js | 2 - docs/{html => }/namespace_s_s_l_obj.html | 3 +- docs/{html => }/namespacemembers.html | 3 +- docs/{html => }/namespacemembers_func.html | 3 +- docs/{html => }/namespaces.html | 3 +- docs/{html => }/namespaces_dup.js | 0 docs/{html => }/nav_f.png | Bin docs/{html => }/nav_g.png | Bin docs/{html => }/nav_h.png | Bin docs/{html => }/navtree.css | 0 docs/{html => }/navtree.js | 0 docs/{html => }/navtreedata.js | 4 +- docs/{html => }/navtreeindex0.js | 92 +- docs/{html => }/open.png | Bin docs/{html => }/pages.html | 5 +- docs/{html => }/resize.js | 0 docs/{html => }/search/all_0.html | 0 docs/{html => }/search/all_0.js | 0 docs/{html => }/search/all_1.html | 0 docs/{html => }/search/all_1.js | 0 docs/{html => }/search/all_10.html | 0 .../search/all_11.js => search/all_10.js} | 0 docs/{html => }/search/all_2.html | 0 .../{html/search/all_3.js => search/all_2.js} | 1 - docs/{html => }/search/all_3.html | 0 .../{html/search/all_4.js => search/all_3.js} | 0 docs/{html => }/search/all_4.html | 0 .../{html/search/all_5.js => search/all_4.js} | 1 - docs/{html => }/search/all_5.html | 0 .../{html/search/all_6.js => search/all_5.js} | 0 docs/{html => }/search/all_6.html | 0 .../{html/search/all_7.js => search/all_6.js} | 0 docs/{html => }/search/all_7.html | 0 .../{html/search/all_8.js => search/all_7.js} | 0 docs/{html => }/search/all_8.html | 0 .../{html/search/all_9.js => search/all_8.js} | 0 docs/{html => }/search/all_9.html | 0 .../{html/search/all_a.js => search/all_9.js} | 0 docs/{html => }/search/all_a.html | 0 .../{html/search/all_b.js => search/all_a.js} | 0 docs/{html => }/search/all_b.html | 0 .../{html/search/all_c.js => search/all_b.js} | 0 docs/{html => }/search/all_c.html | 0 .../{html/search/all_d.js => search/all_c.js} | 0 docs/{html => }/search/all_d.html | 0 docs/search/all_d.js | 7 + docs/{html => }/search/all_e.html | 0 .../{html/search/all_f.js => search/all_e.js} | 0 docs/{html => }/search/all_f.html | 0 .../search/all_10.js => search/all_f.js} | 0 docs/{html => }/search/classes_0.html | 0 docs/{html => }/search/classes_0.js | 0 docs/{html => }/search/close.png | Bin docs/{html => }/search/defines_0.html | 0 docs/{html => }/search/defines_0.js | 0 docs/{html => }/search/defines_1.html | 0 docs/{html => }/search/defines_1.js | 0 docs/{html => }/search/defines_2.html | 0 docs/{html => }/search/defines_2.js | 0 docs/{html => }/search/defines_3.html | 0 docs/{html => }/search/defines_3.js | 0 docs/{html => }/search/defines_4.html | 0 docs/{html => }/search/defines_4.js | 0 docs/{html => }/search/defines_5.html | 0 .../defines_6.js => search/defines_5.js} | 0 docs/{html => }/search/enums_0.html | 0 docs/{html => }/search/enums_0.js | 0 docs/{html => }/search/enums_1.html | 0 docs/{html => }/search/enums_1.js | 0 docs/{html => }/search/enumvalues_0.html | 0 docs/{html => }/search/enumvalues_0.js | 0 docs/{html => }/search/files_0.html | 0 .../search/files_2.js => search/files_0.js} | 0 docs/{html => }/search/files_1.html | 0 .../search/files_3.js => search/files_1.js} | 0 docs/{html => }/search/files_2.html | 0 docs/search/files_2.js | 5 + docs/{html => }/search/functions_0.html | 0 docs/{html => }/search/functions_0.js | 0 docs/{html => }/search/functions_1.html | 0 .../functions_2.js => search/functions_1.js} | 0 docs/{html => }/search/functions_2.html | 0 .../functions_3.js => search/functions_2.js} | 0 docs/{html => }/search/functions_3.html | 0 .../functions_4.js => search/functions_3.js} | 0 docs/{html => }/search/functions_4.html | 0 .../functions_5.js => search/functions_4.js} | 0 docs/{html => }/search/functions_5.html | 0 .../functions_6.js => search/functions_5.js} | 0 docs/{html => }/search/functions_6.html | 0 .../functions_7.js => search/functions_6.js} | 0 docs/{html => }/search/functions_7.html | 0 .../functions_8.js => search/functions_7.js} | 0 docs/{html => }/search/functions_8.html | 0 .../functions_9.js => search/functions_8.js} | 0 docs/{html => }/search/functions_9.html | 0 .../functions_a.js => search/functions_9.js} | 0 docs/{html => }/search/functions_a.html | 0 .../functions_b.js => search/functions_a.js} | 0 docs/{html => }/search/mag_sel.png | Bin docs/{html => }/search/namespaces_0.html | 0 docs/{html => }/search/namespaces_0.js | 0 docs/{html => }/search/nomatches.html | 0 docs/{html => }/search/pages_0.html | 0 docs/{html => }/search/pages_0.js | 0 docs/{html => }/search/pages_1.html | 0 docs/search/pages_1.js | 4 + docs/{html => }/search/search.css | 0 docs/{html => }/search/search.js | 0 docs/{html => }/search/search_l.png | Bin docs/{html => }/search/search_m.png | Bin docs/{html => }/search/search_r.png | Bin docs/{html => }/search/searchdata.js | 10 +- docs/{html => }/search/variables_0.html | 0 .../variables_1.js => search/variables_0.js} | 0 docs/{html => }/search/variables_1.html | 0 .../variables_2.js => search/variables_1.js} | 0 docs/{html => }/search/variables_2.html | 0 .../variables_3.js => search/variables_2.js} | 0 docs/{html => }/search/variables_3.html | 0 .../variables_4.js => search/variables_3.js} | 0 docs/{html => }/splitbar.png | Bin ...truct_s_s_l_client_parameters-members.html | 3 +- .../struct_s_s_l_client_parameters.html | 5 +- .../struct_s_s_l_client_parameters.js | 0 ...structssl__pem__decode__state-members.html | 3 +- .../structssl__pem__decode__state.html | 5 +- .../structssl__pem__decode__state.js | 0 docs/{html => }/sync_off.png | Bin docs/{html => }/sync_on.png | Bin docs/{html => }/tab_a.png | Bin docs/{html => }/tab_b.png | Bin docs/{html => }/tab_h.png | Bin docs/{html => }/tab_s.png | Bin docs/{html => }/tabs.css | 0 docs/{html => }/time__macros_8h.html | 7 +- docs/{html => }/time__macros_8h.js | 0 docs/{html => }/time__macros_8h_source.html | 7 +- library.properties | 2 +- 254 files changed, 484 insertions(+), 4277 deletions(-) rename docs/{html => }/_r_e_a_d_m_e_8md.html (91%) rename docs/{html => }/_s_s_l_client_8cpp.html (81%) rename docs/{html => }/_s_s_l_client_8h.html (85%) rename docs/{html => }/_s_s_l_client_8h_source.html (98%) rename docs/{html => }/_s_s_l_client_parameters_8h.html (84%) rename docs/{html => }/_s_s_l_client_parameters_8h_source.html (92%) rename docs/{html => }/_s_s_l_obj_8cpp.html (83%) rename docs/{html => }/_s_s_l_obj_8cpp.js (100%) rename docs/{html => }/_s_s_l_obj_8h.html (86%) rename docs/{html => }/_s_s_l_obj_8h.js (100%) rename docs/{html => }/_s_s_l_obj_8h_source.html (92%) rename docs/{html => }/_s_s_l_session_8h.html (84%) rename docs/{html => }/_s_s_l_session_8h_source.html (93%) rename docs/{html => }/_trust_anchors_8md.html (91%) rename docs/{html => }/annotated.html (97%) rename docs/{html => }/annotated_dup.js (100%) rename docs/{html => }/bc_s.png (100%) rename docs/{html => }/bdwn.png (100%) rename docs/{html => }/class_s_s_l_client-members.html (99%) rename docs/{html => }/class_s_s_l_client.html (99%) rename docs/{html => }/class_s_s_l_client.js (100%) rename docs/{html => }/class_s_s_l_client.png (100%) rename docs/{html => }/class_s_s_l_session-members.html (97%) rename docs/{html => }/class_s_s_l_session.html (97%) rename docs/{html => }/class_s_s_l_session.js (100%) rename docs/{html => }/class_s_s_l_session.png (100%) rename docs/{html => }/classes.html (97%) rename docs/{html => }/closed.png (100%) rename docs/{html/dir_d28a4824dc47e487b107a5db32ef43c4.html => dir_08af369098809553e22f6e2d01d17ab8.html} (80%) rename docs/{html/dir_386349f6a9bc1e2cd0767d257d5e5b91.html => dir_2b7ad9a5497045797632e667f22e5690.html} (80%) rename docs/{html/dir_dfc5a9f91fbfb9426c406a3f10131a54.html => dir_3d74bfb32a2df79d6a95a208a23e6425.html} (83%) rename docs/{html/dir_68267d1309a1af8e8297ef4c3efbcdba.html => dir_732ec7fb04c2890977d3e4bc2bf648f7.html} (85%) rename docs/{html/dir_9c42dc81377249a918256dbb9cfb2167.html => dir_74140a1086282c406444869b48f08cd0.html} (80%) create mode 100644 docs/dir_c9cc9f7bc7a220ef9764bcae1bd480a3.html rename docs/{html/_s_s_l_session_8cpp.html => dir_d522931ffa1371640980b621734a4381.html} (81%) rename docs/{html => }/doc.png (100%) rename docs/{html => }/doxygen.css (100%) rename docs/{html => }/doxygen.png (100%) rename docs/{html => }/dynsections.js (100%) rename docs/{html/_s_s_l_client_impl_8cpp.html => files.html} (62%) rename docs/{html/dir_68267d1309a1af8e8297ef4c3efbcdba.js => files_dup.js} (74%) rename docs/{html => }/folderclosed.png (100%) rename docs/{html => }/folderopen.png (100%) rename docs/{html => }/functions.html (98%) rename docs/{html => }/functions_enum.html (96%) rename docs/{html => }/functions_eval.html (97%) rename docs/{html => }/functions_func.html (97%) rename docs/{html => }/functions_vars.html (97%) rename docs/{html => }/globals.html (89%) rename docs/{html => }/globals_defs.html (93%) rename docs/{html => }/hierarchy.html (98%) rename docs/{html => }/hierarchy.js (100%) delete mode 100644 docs/html/_s_s_l_client_8cpp.js delete mode 100644 docs/html/_s_s_l_client_8h.js delete mode 100644 docs/html/_s_s_l_client_impl_8cpp.js delete mode 100644 docs/html/_s_s_l_client_impl_8h.html delete mode 100644 docs/html/_s_s_l_client_impl_8h.js delete mode 100644 docs/html/_s_s_l_client_impl_8h_source.html delete mode 100644 docs/html/_t_l_s12__only__profile_8c.html delete mode 100644 docs/html/_t_l_s12__only__profile_8c.js delete mode 100644 docs/html/cert_8h.html delete mode 100644 docs/html/cert_8h.js delete mode 100644 docs/html/cert_8h_source.html delete mode 100644 docs/html/class_s_s_l_client_impl-members.html delete mode 100644 docs/html/class_s_s_l_client_impl.html delete mode 100644 docs/html/class_s_s_l_client_impl.js delete mode 100644 docs/html/class_s_s_l_client_impl.png delete mode 100644 docs/html/dir_386349f6a9bc1e2cd0767d257d5e5b91.js delete mode 100644 docs/html/dir_9c42dc81377249a918256dbb9cfb2167.js delete mode 100644 docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js delete mode 100644 docs/html/dir_dfc5a9f91fbfb9426c406a3f10131a54.js delete mode 100644 docs/html/ec__prime__fast__256_8c.html delete mode 100644 docs/html/ec__prime__fast__256_8c.js delete mode 100644 docs/html/files.html delete mode 100644 docs/html/files_dup.js delete mode 100644 docs/html/globals_enum.html delete mode 100644 docs/html/globals_eval.html delete mode 100644 docs/html/globals_func.html delete mode 100644 docs/html/globals_vars.html delete mode 100644 docs/html/index.html delete mode 100644 docs/html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__r_e_a_d_m_e.html delete mode 100644 docs/html/search/all_11.html delete mode 100644 docs/html/search/all_12.html delete mode 100644 docs/html/search/all_12.js delete mode 100644 docs/html/search/all_2.js delete mode 100644 docs/html/search/all_e.js delete mode 100644 docs/html/search/defines_5.js delete mode 100644 docs/html/search/defines_6.html delete mode 100644 docs/html/search/files_0.js delete mode 100644 docs/html/search/files_1.js delete mode 100644 docs/html/search/files_3.html delete mode 100644 docs/html/search/files_4.html delete mode 100644 docs/html/search/files_4.js delete mode 100644 docs/html/search/functions_1.js delete mode 100644 docs/html/search/functions_b.html delete mode 100644 docs/html/search/functions_c.html delete mode 100644 docs/html/search/functions_c.js delete mode 100644 docs/html/search/functions_d.html delete mode 100644 docs/html/search/functions_d.js delete mode 100644 docs/html/search/pages_1.js delete mode 100644 docs/html/search/variables_0.js delete mode 100644 docs/html/search/variables_4.html delete mode 100644 docs/html/search/variables_5.html delete mode 100644 docs/html/search/variables_5.js delete mode 100644 docs/html/trust__anchors_8h.html delete mode 100644 docs/html/trust__anchors_8h.js delete mode 100644 docs/html/trust__anchors_8h_source.html delete mode 100644 docs/html/trustanchors_8h.html delete mode 100644 docs/html/trustanchors_8h.js delete mode 100644 docs/html/trustanchors_8h_source.html rename docs/{html => }/jquery.js (100%) rename docs/{html/md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html => md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html} (93%) rename docs/{html => }/menu.js (100%) rename docs/{html => }/menudata.js (96%) rename docs/{html => }/namespace_s_s_l_obj.html (98%) rename docs/{html => }/namespacemembers.html (96%) rename docs/{html => }/namespacemembers_func.html (96%) rename docs/{html => }/namespaces.html (97%) rename docs/{html => }/namespaces_dup.js (100%) rename docs/{html => }/nav_f.png (100%) rename docs/{html => }/nav_g.png (100%) rename docs/{html => }/nav_h.png (100%) rename docs/{html => }/navtree.css (100%) rename docs/{html => }/navtree.js (100%) rename docs/{html => }/navtreedata.js (90%) rename docs/{html => }/navtreeindex0.js (55%) rename docs/{html => }/open.png (100%) rename docs/{html => }/pages.html (93%) rename docs/{html => }/resize.js (100%) rename docs/{html => }/search/all_0.html (100%) rename docs/{html => }/search/all_0.js (100%) rename docs/{html => }/search/all_1.html (100%) rename docs/{html => }/search/all_1.js (100%) rename docs/{html => }/search/all_10.html (100%) rename docs/{html/search/all_11.js => search/all_10.js} (100%) rename docs/{html => }/search/all_2.html (100%) rename docs/{html/search/all_3.js => search/all_2.js} (95%) rename docs/{html => }/search/all_3.html (100%) rename docs/{html/search/all_4.js => search/all_3.js} (100%) rename docs/{html => }/search/all_4.html (100%) rename docs/{html/search/all_5.js => search/all_4.js} (71%) rename docs/{html => }/search/all_5.html (100%) rename docs/{html/search/all_6.js => search/all_5.js} (100%) rename docs/{html => }/search/all_6.html (100%) rename docs/{html/search/all_7.js => search/all_6.js} (100%) rename docs/{html => }/search/all_7.html (100%) rename docs/{html/search/all_8.js => search/all_7.js} (100%) rename docs/{html => }/search/all_8.html (100%) rename docs/{html/search/all_9.js => search/all_8.js} (100%) rename docs/{html => }/search/all_9.html (100%) rename docs/{html/search/all_a.js => search/all_9.js} (100%) rename docs/{html => }/search/all_a.html (100%) rename docs/{html/search/all_b.js => search/all_a.js} (100%) rename docs/{html => }/search/all_b.html (100%) rename docs/{html/search/all_c.js => search/all_b.js} (100%) rename docs/{html => }/search/all_c.html (100%) rename docs/{html/search/all_d.js => search/all_c.js} (100%) rename docs/{html => }/search/all_d.html (100%) create mode 100644 docs/search/all_d.js rename docs/{html => }/search/all_e.html (100%) rename docs/{html/search/all_f.js => search/all_e.js} (100%) rename docs/{html => }/search/all_f.html (100%) rename docs/{html/search/all_10.js => search/all_f.js} (100%) rename docs/{html => }/search/classes_0.html (100%) rename docs/{html => }/search/classes_0.js (100%) rename docs/{html => }/search/close.png (100%) rename docs/{html => }/search/defines_0.html (100%) rename docs/{html => }/search/defines_0.js (100%) rename docs/{html => }/search/defines_1.html (100%) rename docs/{html => }/search/defines_1.js (100%) rename docs/{html => }/search/defines_2.html (100%) rename docs/{html => }/search/defines_2.js (100%) rename docs/{html => }/search/defines_3.html (100%) rename docs/{html => }/search/defines_3.js (100%) rename docs/{html => }/search/defines_4.html (100%) rename docs/{html => }/search/defines_4.js (100%) rename docs/{html => }/search/defines_5.html (100%) rename docs/{html/search/defines_6.js => search/defines_5.js} (100%) rename docs/{html => }/search/enums_0.html (100%) rename docs/{html => }/search/enums_0.js (100%) rename docs/{html => }/search/enums_1.html (100%) rename docs/{html => }/search/enums_1.js (100%) rename docs/{html => }/search/enumvalues_0.html (100%) rename docs/{html => }/search/enumvalues_0.js (100%) rename docs/{html => }/search/files_0.html (100%) rename docs/{html/search/files_2.js => search/files_0.js} (100%) rename docs/{html => }/search/files_1.html (100%) rename docs/{html/search/files_3.js => search/files_1.js} (100%) rename docs/{html => }/search/files_2.html (100%) create mode 100644 docs/search/files_2.js rename docs/{html => }/search/functions_0.html (100%) rename docs/{html => }/search/functions_0.js (100%) rename docs/{html => }/search/functions_1.html (100%) rename docs/{html/search/functions_2.js => search/functions_1.js} (100%) rename docs/{html => }/search/functions_2.html (100%) rename docs/{html/search/functions_3.js => search/functions_2.js} (100%) rename docs/{html => }/search/functions_3.html (100%) rename docs/{html/search/functions_4.js => search/functions_3.js} (100%) rename docs/{html => }/search/functions_4.html (100%) rename docs/{html/search/functions_5.js => search/functions_4.js} (100%) rename docs/{html => }/search/functions_5.html (100%) rename docs/{html/search/functions_6.js => search/functions_5.js} (100%) rename docs/{html => }/search/functions_6.html (100%) rename docs/{html/search/functions_7.js => search/functions_6.js} (100%) rename docs/{html => }/search/functions_7.html (100%) rename docs/{html/search/functions_8.js => search/functions_7.js} (100%) rename docs/{html => }/search/functions_8.html (100%) rename docs/{html/search/functions_9.js => search/functions_8.js} (100%) rename docs/{html => }/search/functions_9.html (100%) rename docs/{html/search/functions_a.js => search/functions_9.js} (100%) rename docs/{html => }/search/functions_a.html (100%) rename docs/{html/search/functions_b.js => search/functions_a.js} (100%) rename docs/{html => }/search/mag_sel.png (100%) rename docs/{html => }/search/namespaces_0.html (100%) rename docs/{html => }/search/namespaces_0.js (100%) rename docs/{html => }/search/nomatches.html (100%) rename docs/{html => }/search/pages_0.html (100%) rename docs/{html => }/search/pages_0.js (100%) rename docs/{html => }/search/pages_1.html (100%) create mode 100644 docs/search/pages_1.js rename docs/{html => }/search/search.css (100%) rename docs/{html => }/search/search.js (100%) rename docs/{html => }/search/search_l.png (100%) rename docs/{html => }/search/search_m.png (100%) rename docs/{html => }/search/search_r.png (100%) rename docs/{html => }/search/searchdata.js (83%) rename docs/{html => }/search/variables_0.html (100%) rename docs/{html/search/variables_1.js => search/variables_0.js} (100%) rename docs/{html => }/search/variables_1.html (100%) rename docs/{html/search/variables_2.js => search/variables_1.js} (100%) rename docs/{html => }/search/variables_2.html (100%) rename docs/{html/search/variables_3.js => search/variables_2.js} (100%) rename docs/{html => }/search/variables_3.html (100%) rename docs/{html/search/variables_4.js => search/variables_3.js} (100%) rename docs/{html => }/splitbar.png (100%) rename docs/{html => }/struct_s_s_l_client_parameters-members.html (97%) rename docs/{html => }/struct_s_s_l_client_parameters.html (97%) rename docs/{html => }/struct_s_s_l_client_parameters.js (100%) rename docs/{html => }/structssl__pem__decode__state-members.html (97%) rename docs/{html => }/structssl__pem__decode__state.html (96%) rename docs/{html => }/structssl__pem__decode__state.js (100%) rename docs/{html => }/sync_off.png (100%) rename docs/{html => }/sync_on.png (100%) rename docs/{html => }/tab_a.png (100%) rename docs/{html => }/tab_b.png (100%) rename docs/{html => }/tab_h.png (100%) rename docs/{html => }/tab_s.png (100%) rename docs/{html => }/tabs.css (100%) rename docs/{html => }/time__macros_8h.html (97%) rename docs/{html => }/time__macros_8h.js (100%) rename docs/{html => }/time__macros_8h_source.html (96%) diff --git a/.travis/library.properties b/.travis/library.properties index a69a9fe..c356157 100644 --- a/.travis/library.properties +++ b/.travis/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.4.7 +version=1.5.0 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add SSL functionality to any Client class diff --git a/docs/html/_r_e_a_d_m_e_8md.html b/docs/_r_e_a_d_m_e_8md.html similarity index 91% rename from docs/html/_r_e_a_d_m_e_8md.html rename to docs/_r_e_a_d_m_e_8md.html index af50fef..700c3e4 100644 --- a/docs/html/_r_e_a_d_m_e_8md.html +++ b/docs/_r_e_a_d_m_e_8md.html @@ -5,7 +5,7 @@ -SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/README.md File Reference +SSLClient: README.md File Reference @@ -30,9 +30,8 @@
          SSLClient -  v1.4.7 +  v1.5.0
          -
          Add TLS 1.2 functionality to any network library.
          @@ -88,7 +87,7 @@ $(document).ready(function(){initNavTree('_r_e_a_d_m_e_8md.html','');});
          -
          C:/Users/Noah/Documents/Arduino/libraries/SSLClient/README.md File Reference
          +
          README.md File Reference
      diff --git a/docs/html/_s_s_l_client_8cpp.html b/docs/_s_s_l_client_8cpp.html similarity index 81% rename from docs/html/_s_s_l_client_8cpp.html rename to docs/_s_s_l_client_8cpp.html index 25e3925..bbbf26e 100644 --- a/docs/html/_s_s_l_client_8cpp.html +++ b/docs/_s_s_l_client_8cpp.html @@ -5,7 +5,7 @@ -SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/SSLClient.cpp File Reference +SSLClient: SSLClient.cpp File Reference @@ -30,9 +30,8 @@
      SSLClient -  v1.4.7 +  v1.5.0
      -
      Add TLS 1.2 functionality to any network library.
      @@ -97,7 +96,7 @@ $(document).ready(function(){initNavTree('_s_s_l_client_8cpp.html','');});
      @@ -88,15 +87,13 @@ $(document).ready(function(){initNavTree('dir_d28a4824dc47e487b107a5db32ef43c4.h
      -
      examples Directory Reference
      +
      libraries Directory Reference
      - - - +

      Directories

      directory  EthernetHTTPS
       
      directory  EthernetMultiHTTPS
      directory  SSLClient
       
      @@ -104,7 +101,7 @@ Directories
      @@ -88,13 +87,13 @@ $(document).ready(function(){initNavTree('dir_386349f6a9bc1e2cd0767d257d5e5b91.h
      -
      EthernetMultiHTTPS Directory Reference
      +
      Arduino Directory Reference
      - - + +

      -Files

      file  trustanchors.h [code]

      +Directories

      directory  libraries
       
      @@ -102,7 +101,7 @@ Files
      @@ -88,13 +87,13 @@ $(document).ready(function(){initNavTree('dir_dfc5a9f91fbfb9426c406a3f10131a54.h
      -
      readme Directory Reference
      +
      Noah Directory Reference
      - - + +

      -Files

      file  cert.h [code]

      +Directories

      directory  Documents
       
      @@ -102,7 +101,7 @@ Files
      @@ -94,8 +93,6 @@ $(document).ready(function(){initNavTree('dir_68267d1309a1af8e8297ef4c3efbcdba.h - - @@ -110,15 +107,13 @@ Files - -

      Files

      file  ec_prime_fast_256.c
       
      file  SSLClient.cpp
       
      file  SSLClient.h [code]
       
      file  time_macros.h [code]
       
      file  TLS12_only_profile.c
       
    @@ -88,13 +87,13 @@ $(document).ready(function(){initNavTree('dir_9c42dc81377249a918256dbb9cfb2167.h
    -
    EthernetHTTPS Directory Reference
    +
    Documents Directory Reference
    - - + +

    -Files

    file  trust_anchors.h [code]

    +Directories

    directory  Arduino
     
    @@ -102,7 +101,7 @@ Files
    @@ -88,16 +87,21 @@ $(document).ready(function(){initNavTree('_s_s_l_session_8cpp.html','');});
    -
    SSLSession.cpp File Reference
    +
    Users Directory Reference
    -
    #include "SSLSession.h"
    -
    + + + + +

    +Directories

    directory  Noah
     
    +
    @@ -87,40 +86,26 @@ $(document).ready(function(){initNavTree('_s_s_l_client_impl_8cpp.html','');});
    -
    -
    SSLClientImpl.cpp File Reference
    +
    File List
    -
    #include "SSLClient.h"
    -
    - - - +
    Here is a list of all files with brief descriptions:
    +

    -Variables

    char * __brkval
     
    + + + + + + +
     SSLClient.cpp
     SSLClient.h
     SSLClientParameters.h
     SSLObj.cpp
     SSLObj.h
     SSLSession.h
     time_macros.h
    -

    Variable Documentation

    - -

    ◆ __brkval

    - -
    -
    - - - - -
    char* __brkval
    -
    - -
    -
    +
    @@ -98,10 +97,10 @@ $(document).ready(function(){initNavTree('md__c_1__users__noah__documents__ardui

    For HTTPS, there a couple of tools you can use. Ordered from easiest to hardest:

    Other Connections

    -

    For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convert command to convert the certificate into a trust anchor header.

    +

    For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convet --no-search command to convert the certificate into a trust anchor header.

    Using Trust Anchors

    Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

    {C++}
    #include "yourtrustanchorfile.h"
    // ...
    SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
    // ...

    Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

    diff --git a/docs/html/menu.js b/docs/menu.js similarity index 100% rename from docs/html/menu.js rename to docs/menu.js diff --git a/docs/html/menudata.js b/docs/menudata.js similarity index 96% rename from docs/html/menudata.js rename to docs/menudata.js index 529ffec..5407264 100644 --- a/docs/html/menudata.js +++ b/docs/menudata.js @@ -57,6 +57,4 @@ var menudata={children:[ {text:"File List",url:"files.html"}, {text:"File Members",url:"globals.html",children:[ {text:"All",url:"globals.html"}, -{text:"Functions",url:"globals_func.html"}, -{text:"Variables",url:"globals_vars.html"}, {text:"Macros",url:"globals_defs.html"}]}]}]} diff --git a/docs/html/namespace_s_s_l_obj.html b/docs/namespace_s_s_l_obj.html similarity index 98% rename from docs/html/namespace_s_s_l_obj.html rename to docs/namespace_s_s_l_obj.html index 5d3af7a..d4f55e3 100644 --- a/docs/html/namespace_s_s_l_obj.html +++ b/docs/namespace_s_s_l_obj.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers.html b/docs/namespacemembers.html similarity index 96% rename from docs/html/namespacemembers.html rename to docs/namespacemembers.html index 53d7762..cac29f8 100644 --- a/docs/html/namespacemembers.html +++ b/docs/namespacemembers.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespacemembers_func.html b/docs/namespacemembers_func.html similarity index 96% rename from docs/html/namespacemembers_func.html rename to docs/namespacemembers_func.html index 46f8a15..07aea65 100644 --- a/docs/html/namespacemembers_func.html +++ b/docs/namespacemembers_func.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespaces.html b/docs/namespaces.html similarity index 97% rename from docs/html/namespaces.html rename to docs/namespaces.html index edad91b..01c331b 100644 --- a/docs/html/namespaces.html +++ b/docs/namespaces.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/namespaces_dup.js b/docs/namespaces_dup.js similarity index 100% rename from docs/html/namespaces_dup.js rename to docs/namespaces_dup.js diff --git a/docs/html/nav_f.png b/docs/nav_f.png similarity index 100% rename from docs/html/nav_f.png rename to docs/nav_f.png diff --git a/docs/html/nav_g.png b/docs/nav_g.png similarity index 100% rename from docs/html/nav_g.png rename to docs/nav_g.png diff --git a/docs/html/nav_h.png b/docs/nav_h.png similarity index 100% rename from docs/html/nav_h.png rename to docs/nav_h.png diff --git a/docs/html/navtree.css b/docs/navtree.css similarity index 100% rename from docs/html/navtree.css rename to docs/navtree.css diff --git a/docs/html/navtree.js b/docs/navtree.js similarity index 100% rename from docs/html/navtree.js rename to docs/navtree.js diff --git a/docs/html/navtreedata.js b/docs/navtreedata.js similarity index 90% rename from docs/html/navtreedata.js rename to docs/navtreedata.js index 8d74ad1..d766bc3 100644 --- a/docs/html/navtreedata.js +++ b/docs/navtreedata.js @@ -24,7 +24,7 @@ for the JavaScript code in this file var NAVTREE = [ [ "SSLClient", "index.html", [ - [ "Trust Anchors", "md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html", null ], + [ "Trust Anchors", "md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html", null ], [ "Namespaces", "namespaces.html", [ [ "Namespace List", "namespaces.html", "namespaces_dup" ], [ "Namespace Members", "namespacemembers.html", [ @@ -48,8 +48,6 @@ var NAVTREE = [ "File List", "files.html", "files_dup" ], [ "File Members", "globals.html", [ [ "All", "globals.html", null ], - [ "Functions", "globals_func.html", null ], - [ "Variables", "globals_vars.html", null ], [ "Macros", "globals_defs.html", null ] ] ] ] ] diff --git a/docs/html/navtreeindex0.js b/docs/navtreeindex0.js similarity index 55% rename from docs/html/navtreeindex0.js rename to docs/navtreeindex0.js index 0dde6b3..142b068 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -1,22 +1,17 @@ var NAVTREEINDEX0 = { -"_s_s_l_client_8cpp.html":[3,0,2,1], -"_s_s_l_client_8h.html":[3,0,2,2], -"_s_s_l_client_8h_source.html":[3,0,2,2], -"_s_s_l_client_parameters_8h.html":[3,0,2,3], -"_s_s_l_client_parameters_8h_source.html":[3,0,2,3], -"_s_s_l_obj_8cpp.html":[3,0,2,4], -"_s_s_l_obj_8h.html":[3,0,2,5], -"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[3,0,2,5,0], -"_s_s_l_obj_8h_source.html":[3,0,2,5], -"_s_s_l_session_8h.html":[3,0,2,6], -"_s_s_l_session_8h_source.html":[3,0,2,6], -"_t_l_s12__only__profile_8c.html":[3,0,2,8], -"_t_l_s12__only__profile_8c.html#a32c8112a1c37ba21a05952eeefc435f3":[3,0,2,8,0], +"_s_s_l_client_8cpp.html":[3,0,0], +"_s_s_l_client_8h.html":[3,0,1], +"_s_s_l_client_8h_source.html":[3,0,1], +"_s_s_l_client_parameters_8h.html":[3,0,2], +"_s_s_l_client_parameters_8h_source.html":[3,0,2], +"_s_s_l_obj_8cpp.html":[3,0,3], +"_s_s_l_obj_8h.html":[3,0,4], +"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[3,0,4,0], +"_s_s_l_obj_8h_source.html":[3,0,4], +"_s_s_l_session_8h.html":[3,0,5], +"_s_s_l_session_8h_source.html":[3,0,5], "annotated.html":[2,0], -"cert_8h.html":[3,0,1,0], -"cert_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,1,0,0], -"cert_8h_source.html":[3,0,1,0], "class_s_s_l_client.html":[2,0,1], "class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86":[2,0,1,20], "class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86":[2,0,1,13], @@ -56,13 +51,6 @@ var NAVTREEINDEX0 = "class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[2,0,3,1], "class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[2,0,3,2], "classes.html":[2,1], -"dir_386349f6a9bc1e2cd0767d257d5e5b91.html":[3,0,0,1], -"dir_68267d1309a1af8e8297ef4c3efbcdba.html":[3,0,2], -"dir_9c42dc81377249a918256dbb9cfb2167.html":[3,0,0,0], -"dir_d28a4824dc47e487b107a5db32ef43c4.html":[3,0,0], -"dir_dfc5a9f91fbfb9426c406a3f10131a54.html":[3,0,1], -"ec__prime__fast__256_8c.html":[3,0,2,0], -"ec__prime__fast__256_8c.html#aedcd6aae4367c3fdfe7db296b4da85ab":[3,0,2,0,0], "files.html":[3,0], "functions.html":[2,3,0], "functions_enum.html":[2,3,3], @@ -70,12 +58,10 @@ var NAVTREEINDEX0 = "functions_func.html":[2,3,1], "functions_vars.html":[2,3,2], "globals.html":[3,1,0], -"globals_defs.html":[3,1,3], -"globals_func.html":[3,1,1], -"globals_vars.html":[3,1,2], +"globals_defs.html":[3,1,1], "hierarchy.html":[2,2], "index.html":[], -"md__c_1__users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[0], +"md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[0], "namespace_s_s_l_obj.html":[1,0,0], "namespacemembers.html":[1,1,0], "namespacemembers_func.html":[1,1,1], @@ -88,33 +74,27 @@ var NAVTREEINDEX0 = "structssl__pem__decode__state.html":[2,0,0], "structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3":[2,0,0,0], "structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9":[2,0,0,1], -"time__macros_8h.html":[3,0,2,7], -"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,2,7,19], -"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,2,7,14], -"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,2,7,1], -"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,2,7,20], -"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,2,7,16], -"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,2,7,4], -"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,2,7,15], -"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,2,7,13], -"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,2,7,5], -"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,2,7,8], -"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,2,7,0], -"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,2,7,6], -"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,2,7,18], -"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,2,7,12], -"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,2,7,11], -"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,2,7,2], -"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,2,7,7], -"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,2,7,17], -"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,2,7,3], -"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,2,7,9], -"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,2,7,10], -"time__macros_8h_source.html":[3,0,2,7], -"trust__anchors_8h.html":[3,0,0,0,0], -"trust__anchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,0,0,0], -"trust__anchors_8h_source.html":[3,0,0,0,0], -"trustanchors_8h.html":[3,0,0,1,0], -"trustanchors_8h.html#ae2e26a4e8e97b0f15c18ba1ace062948":[3,0,0,1,0,0], -"trustanchors_8h_source.html":[3,0,0,1,0] +"time__macros_8h.html":[3,0,6], +"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,6,19], +"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,6,14], +"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,6,1], +"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,6,20], +"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,6,16], +"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,6,4], +"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,6,15], +"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,6,13], +"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,6,5], +"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,6,8], +"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,6,0], +"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,6,6], +"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,6,18], +"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,6,12], +"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,6,11], +"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,6,2], +"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,6,7], +"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,6,17], +"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,6,3], +"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,6,9], +"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,6,10], +"time__macros_8h_source.html":[3,0,6] }; diff --git a/docs/html/open.png b/docs/open.png similarity index 100% rename from docs/html/open.png rename to docs/open.png diff --git a/docs/html/pages.html b/docs/pages.html similarity index 93% rename from docs/html/pages.html rename to docs/pages.html index 73a881b..37ed9e0 100644 --- a/docs/html/pages.html +++ b/docs/pages.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    @@ -93,7 +92,7 @@ $(document).ready(function(){initNavTree('pages.html','');});
    Here is a list of all related documentation pages:
    diff --git a/docs/html/resize.js b/docs/resize.js similarity index 100% rename from docs/html/resize.js rename to docs/resize.js diff --git a/docs/html/search/all_0.html b/docs/search/all_0.html similarity index 100% rename from docs/html/search/all_0.html rename to docs/search/all_0.html diff --git a/docs/html/search/all_0.js b/docs/search/all_0.js similarity index 100% rename from docs/html/search/all_0.js rename to docs/search/all_0.js diff --git a/docs/html/search/all_1.html b/docs/search/all_1.html similarity index 100% rename from docs/html/search/all_1.html rename to docs/search/all_1.html diff --git a/docs/html/search/all_1.js b/docs/search/all_1.js similarity index 100% rename from docs/html/search/all_1.js rename to docs/search/all_1.js diff --git a/docs/html/search/all_10.html b/docs/search/all_10.html similarity index 100% rename from docs/html/search/all_10.html rename to docs/search/all_10.html diff --git a/docs/html/search/all_11.js b/docs/search/all_10.js similarity index 100% rename from docs/html/search/all_11.js rename to docs/search/all_10.js diff --git a/docs/html/search/all_2.html b/docs/search/all_2.html similarity index 100% rename from docs/html/search/all_2.html rename to docs/search/all_2.html diff --git a/docs/html/search/all_3.js b/docs/search/all_2.js similarity index 95% rename from docs/html/search/all_3.js rename to docs/search/all_2.js index 13385d1..0b06fcf 100644 --- a/docs/html/search/all_3.js +++ b/docs/search/all_2.js @@ -1,6 +1,5 @@ var searchData= [ - ['cert_2eh',['cert.h',['../cert_8h.html',1,'']]], ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]], ['connect',['connect',['../class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90',1,'SSLClient::connect(const char *host, uint16_t port) override']]], diff --git a/docs/html/search/all_3.html b/docs/search/all_3.html similarity index 100% rename from docs/html/search/all_3.html rename to docs/search/all_3.html diff --git a/docs/html/search/all_4.js b/docs/search/all_3.js similarity index 100% rename from docs/html/search/all_4.js rename to docs/search/all_3.js diff --git a/docs/html/search/all_4.html b/docs/search/all_4.html similarity index 100% rename from docs/html/search/all_4.html rename to docs/search/all_4.html diff --git a/docs/html/search/all_5.js b/docs/search/all_4.js similarity index 71% rename from docs/html/search/all_5.js rename to docs/search/all_4.js index 143336e..8369997 100644 --- a/docs/html/search/all_5.js +++ b/docs/search/all_4.js @@ -1,6 +1,5 @@ var searchData= [ ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]], - ['ec_5fprime_5ffast_5f256_2ec',['ec_prime_fast_256.c',['../ec__prime__fast__256_8c.html',1,'']]], ['error',['Error',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea',1,'SSLClient']]] ]; diff --git a/docs/html/search/all_5.html b/docs/search/all_5.html similarity index 100% rename from docs/html/search/all_5.html rename to docs/search/all_5.html diff --git a/docs/html/search/all_6.js b/docs/search/all_5.js similarity index 100% rename from docs/html/search/all_6.js rename to docs/search/all_5.js diff --git a/docs/html/search/all_6.html b/docs/search/all_6.html similarity index 100% rename from docs/html/search/all_6.html rename to docs/search/all_6.html diff --git a/docs/html/search/all_7.js b/docs/search/all_6.js similarity index 100% rename from docs/html/search/all_7.js rename to docs/search/all_6.js diff --git a/docs/html/search/all_7.html b/docs/search/all_7.html similarity index 100% rename from docs/html/search/all_7.html rename to docs/search/all_7.html diff --git a/docs/html/search/all_8.js b/docs/search/all_7.js similarity index 100% rename from docs/html/search/all_8.js rename to docs/search/all_7.js diff --git a/docs/html/search/all_8.html b/docs/search/all_8.html similarity index 100% rename from docs/html/search/all_8.html rename to docs/search/all_8.html diff --git a/docs/html/search/all_9.js b/docs/search/all_8.js similarity index 100% rename from docs/html/search/all_9.js rename to docs/search/all_8.js diff --git a/docs/html/search/all_9.html b/docs/search/all_9.html similarity index 100% rename from docs/html/search/all_9.html rename to docs/search/all_9.html diff --git a/docs/html/search/all_a.js b/docs/search/all_9.js similarity index 100% rename from docs/html/search/all_a.js rename to docs/search/all_9.js diff --git a/docs/html/search/all_a.html b/docs/search/all_a.html similarity index 100% rename from docs/html/search/all_a.html rename to docs/search/all_a.html diff --git a/docs/html/search/all_b.js b/docs/search/all_a.js similarity index 100% rename from docs/html/search/all_b.js rename to docs/search/all_a.js diff --git a/docs/html/search/all_b.html b/docs/search/all_b.html similarity index 100% rename from docs/html/search/all_b.html rename to docs/search/all_b.html diff --git a/docs/html/search/all_c.js b/docs/search/all_b.js similarity index 100% rename from docs/html/search/all_c.js rename to docs/search/all_b.js diff --git a/docs/html/search/all_c.html b/docs/search/all_c.html similarity index 100% rename from docs/html/search/all_c.html rename to docs/search/all_c.html diff --git a/docs/html/search/all_d.js b/docs/search/all_c.js similarity index 100% rename from docs/html/search/all_d.js rename to docs/search/all_c.js diff --git a/docs/html/search/all_d.html b/docs/search/all_d.html similarity index 100% rename from docs/html/search/all_d.html rename to docs/search/all_d.html diff --git a/docs/search/all_d.js b/docs/search/all_d.js new file mode 100644 index 0000000..4b4b251 --- /dev/null +++ b/docs/search/all_d.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['trust_20anchors',['Trust Anchors',['../md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]], + ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], + ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]], + ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] +]; diff --git a/docs/html/search/all_e.html b/docs/search/all_e.html similarity index 100% rename from docs/html/search/all_e.html rename to docs/search/all_e.html diff --git a/docs/html/search/all_f.js b/docs/search/all_e.js similarity index 100% rename from docs/html/search/all_f.js rename to docs/search/all_e.js diff --git a/docs/html/search/all_f.html b/docs/search/all_f.html similarity index 100% rename from docs/html/search/all_f.html rename to docs/search/all_f.html diff --git a/docs/html/search/all_10.js b/docs/search/all_f.js similarity index 100% rename from docs/html/search/all_10.js rename to docs/search/all_f.js diff --git a/docs/html/search/classes_0.html b/docs/search/classes_0.html similarity index 100% rename from docs/html/search/classes_0.html rename to docs/search/classes_0.html diff --git a/docs/html/search/classes_0.js b/docs/search/classes_0.js similarity index 100% rename from docs/html/search/classes_0.js rename to docs/search/classes_0.js diff --git a/docs/html/search/close.png b/docs/search/close.png similarity index 100% rename from docs/html/search/close.png rename to docs/search/close.png diff --git a/docs/html/search/defines_0.html b/docs/search/defines_0.html similarity index 100% rename from docs/html/search/defines_0.html rename to docs/search/defines_0.html diff --git a/docs/html/search/defines_0.js b/docs/search/defines_0.js similarity index 100% rename from docs/html/search/defines_0.js rename to docs/search/defines_0.js diff --git a/docs/html/search/defines_1.html b/docs/search/defines_1.html similarity index 100% rename from docs/html/search/defines_1.html rename to docs/search/defines_1.html diff --git a/docs/html/search/defines_1.js b/docs/search/defines_1.js similarity index 100% rename from docs/html/search/defines_1.js rename to docs/search/defines_1.js diff --git a/docs/html/search/defines_2.html b/docs/search/defines_2.html similarity index 100% rename from docs/html/search/defines_2.html rename to docs/search/defines_2.html diff --git a/docs/html/search/defines_2.js b/docs/search/defines_2.js similarity index 100% rename from docs/html/search/defines_2.js rename to docs/search/defines_2.js diff --git a/docs/html/search/defines_3.html b/docs/search/defines_3.html similarity index 100% rename from docs/html/search/defines_3.html rename to docs/search/defines_3.html diff --git a/docs/html/search/defines_3.js b/docs/search/defines_3.js similarity index 100% rename from docs/html/search/defines_3.js rename to docs/search/defines_3.js diff --git a/docs/html/search/defines_4.html b/docs/search/defines_4.html similarity index 100% rename from docs/html/search/defines_4.html rename to docs/search/defines_4.html diff --git a/docs/html/search/defines_4.js b/docs/search/defines_4.js similarity index 100% rename from docs/html/search/defines_4.js rename to docs/search/defines_4.js diff --git a/docs/html/search/defines_5.html b/docs/search/defines_5.html similarity index 100% rename from docs/html/search/defines_5.html rename to docs/search/defines_5.html diff --git a/docs/html/search/defines_6.js b/docs/search/defines_5.js similarity index 100% rename from docs/html/search/defines_6.js rename to docs/search/defines_5.js diff --git a/docs/html/search/enums_0.html b/docs/search/enums_0.html similarity index 100% rename from docs/html/search/enums_0.html rename to docs/search/enums_0.html diff --git a/docs/html/search/enums_0.js b/docs/search/enums_0.js similarity index 100% rename from docs/html/search/enums_0.js rename to docs/search/enums_0.js diff --git a/docs/html/search/enums_1.html b/docs/search/enums_1.html similarity index 100% rename from docs/html/search/enums_1.html rename to docs/search/enums_1.html diff --git a/docs/html/search/enums_1.js b/docs/search/enums_1.js similarity index 100% rename from docs/html/search/enums_1.js rename to docs/search/enums_1.js diff --git a/docs/html/search/enumvalues_0.html b/docs/search/enumvalues_0.html similarity index 100% rename from docs/html/search/enumvalues_0.html rename to docs/search/enumvalues_0.html diff --git a/docs/html/search/enumvalues_0.js b/docs/search/enumvalues_0.js similarity index 100% rename from docs/html/search/enumvalues_0.js rename to docs/search/enumvalues_0.js diff --git a/docs/html/search/files_0.html b/docs/search/files_0.html similarity index 100% rename from docs/html/search/files_0.html rename to docs/search/files_0.html diff --git a/docs/html/search/files_2.js b/docs/search/files_0.js similarity index 100% rename from docs/html/search/files_2.js rename to docs/search/files_0.js diff --git a/docs/html/search/files_1.html b/docs/search/files_1.html similarity index 100% rename from docs/html/search/files_1.html rename to docs/search/files_1.html diff --git a/docs/html/search/files_3.js b/docs/search/files_1.js similarity index 100% rename from docs/html/search/files_3.js rename to docs/search/files_1.js diff --git a/docs/html/search/files_2.html b/docs/search/files_2.html similarity index 100% rename from docs/html/search/files_2.html rename to docs/search/files_2.html diff --git a/docs/search/files_2.js b/docs/search/files_2.js new file mode 100644 index 0000000..a77b038 --- /dev/null +++ b/docs/search/files_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], + ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] +]; diff --git a/docs/html/search/functions_0.html b/docs/search/functions_0.html similarity index 100% rename from docs/html/search/functions_0.html rename to docs/search/functions_0.html diff --git a/docs/html/search/functions_0.js b/docs/search/functions_0.js similarity index 100% rename from docs/html/search/functions_0.js rename to docs/search/functions_0.js diff --git a/docs/html/search/functions_1.html b/docs/search/functions_1.html similarity index 100% rename from docs/html/search/functions_1.html rename to docs/search/functions_1.html diff --git a/docs/html/search/functions_2.js b/docs/search/functions_1.js similarity index 100% rename from docs/html/search/functions_2.js rename to docs/search/functions_1.js diff --git a/docs/html/search/functions_2.html b/docs/search/functions_2.html similarity index 100% rename from docs/html/search/functions_2.html rename to docs/search/functions_2.html diff --git a/docs/html/search/functions_3.js b/docs/search/functions_2.js similarity index 100% rename from docs/html/search/functions_3.js rename to docs/search/functions_2.js diff --git a/docs/html/search/functions_3.html b/docs/search/functions_3.html similarity index 100% rename from docs/html/search/functions_3.html rename to docs/search/functions_3.html diff --git a/docs/html/search/functions_4.js b/docs/search/functions_3.js similarity index 100% rename from docs/html/search/functions_4.js rename to docs/search/functions_3.js diff --git a/docs/html/search/functions_4.html b/docs/search/functions_4.html similarity index 100% rename from docs/html/search/functions_4.html rename to docs/search/functions_4.html diff --git a/docs/html/search/functions_5.js b/docs/search/functions_4.js similarity index 100% rename from docs/html/search/functions_5.js rename to docs/search/functions_4.js diff --git a/docs/html/search/functions_5.html b/docs/search/functions_5.html similarity index 100% rename from docs/html/search/functions_5.html rename to docs/search/functions_5.html diff --git a/docs/html/search/functions_6.js b/docs/search/functions_5.js similarity index 100% rename from docs/html/search/functions_6.js rename to docs/search/functions_5.js diff --git a/docs/html/search/functions_6.html b/docs/search/functions_6.html similarity index 100% rename from docs/html/search/functions_6.html rename to docs/search/functions_6.html diff --git a/docs/html/search/functions_7.js b/docs/search/functions_6.js similarity index 100% rename from docs/html/search/functions_7.js rename to docs/search/functions_6.js diff --git a/docs/html/search/functions_7.html b/docs/search/functions_7.html similarity index 100% rename from docs/html/search/functions_7.html rename to docs/search/functions_7.html diff --git a/docs/html/search/functions_8.js b/docs/search/functions_7.js similarity index 100% rename from docs/html/search/functions_8.js rename to docs/search/functions_7.js diff --git a/docs/html/search/functions_8.html b/docs/search/functions_8.html similarity index 100% rename from docs/html/search/functions_8.html rename to docs/search/functions_8.html diff --git a/docs/html/search/functions_9.js b/docs/search/functions_8.js similarity index 100% rename from docs/html/search/functions_9.js rename to docs/search/functions_8.js diff --git a/docs/html/search/functions_9.html b/docs/search/functions_9.html similarity index 100% rename from docs/html/search/functions_9.html rename to docs/search/functions_9.html diff --git a/docs/html/search/functions_a.js b/docs/search/functions_9.js similarity index 100% rename from docs/html/search/functions_a.js rename to docs/search/functions_9.js diff --git a/docs/html/search/functions_a.html b/docs/search/functions_a.html similarity index 100% rename from docs/html/search/functions_a.html rename to docs/search/functions_a.html diff --git a/docs/html/search/functions_b.js b/docs/search/functions_a.js similarity index 100% rename from docs/html/search/functions_b.js rename to docs/search/functions_a.js diff --git a/docs/html/search/mag_sel.png b/docs/search/mag_sel.png similarity index 100% rename from docs/html/search/mag_sel.png rename to docs/search/mag_sel.png diff --git a/docs/html/search/namespaces_0.html b/docs/search/namespaces_0.html similarity index 100% rename from docs/html/search/namespaces_0.html rename to docs/search/namespaces_0.html diff --git a/docs/html/search/namespaces_0.js b/docs/search/namespaces_0.js similarity index 100% rename from docs/html/search/namespaces_0.js rename to docs/search/namespaces_0.js diff --git a/docs/html/search/nomatches.html b/docs/search/nomatches.html similarity index 100% rename from docs/html/search/nomatches.html rename to docs/search/nomatches.html diff --git a/docs/html/search/pages_0.html b/docs/search/pages_0.html similarity index 100% rename from docs/html/search/pages_0.html rename to docs/search/pages_0.html diff --git a/docs/html/search/pages_0.js b/docs/search/pages_0.js similarity index 100% rename from docs/html/search/pages_0.js rename to docs/search/pages_0.js diff --git a/docs/html/search/pages_1.html b/docs/search/pages_1.html similarity index 100% rename from docs/html/search/pages_1.html rename to docs/search/pages_1.html diff --git a/docs/search/pages_1.js b/docs/search/pages_1.js new file mode 100644 index 0000000..7918701 --- /dev/null +++ b/docs/search/pages_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['trust_20anchors',['Trust Anchors',['../md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]] +]; diff --git a/docs/html/search/search.css b/docs/search/search.css similarity index 100% rename from docs/html/search/search.css rename to docs/search/search.css diff --git a/docs/html/search/search.js b/docs/search/search.js similarity index 100% rename from docs/html/search/search.js rename to docs/search/search.js diff --git a/docs/html/search/search_l.png b/docs/search/search_l.png similarity index 100% rename from docs/html/search/search_l.png rename to docs/search/search_l.png diff --git a/docs/html/search/search_m.png b/docs/search/search_m.png similarity index 100% rename from docs/html/search/search_m.png rename to docs/search/search_m.png diff --git a/docs/html/search/search_r.png b/docs/search/search_r.png similarity index 100% rename from docs/html/search/search_r.png rename to docs/search/search_r.png diff --git a/docs/html/search/searchdata.js b/docs/search/searchdata.js similarity index 83% rename from docs/html/search/searchdata.js rename to docs/search/searchdata.js index a1efc7e..25ef3f7 100644 --- a/docs/html/search/searchdata.js +++ b/docs/search/searchdata.js @@ -1,14 +1,14 @@ var indexSectionsWithContent = { - 0: "_abcdefgimoprstuvw", + 0: "_acdefgimoprstuvw", 1: "s", 2: "s", - 3: "cerst", - 4: "abcfgmoprstw", - 5: "bceiv", + 3: "rst", + 4: "acfgmoprstw", + 5: "ceiv", 6: "de", 7: "s", - 8: "_cgpstu", + 8: "_cgpsu", 9: "st" }; diff --git a/docs/html/search/variables_0.html b/docs/search/variables_0.html similarity index 100% rename from docs/html/search/variables_0.html rename to docs/search/variables_0.html diff --git a/docs/html/search/variables_1.js b/docs/search/variables_0.js similarity index 100% rename from docs/html/search/variables_1.js rename to docs/search/variables_0.js diff --git a/docs/html/search/variables_1.html b/docs/search/variables_1.html similarity index 100% rename from docs/html/search/variables_1.html rename to docs/search/variables_1.html diff --git a/docs/html/search/variables_2.js b/docs/search/variables_1.js similarity index 100% rename from docs/html/search/variables_2.js rename to docs/search/variables_1.js diff --git a/docs/html/search/variables_2.html b/docs/search/variables_2.html similarity index 100% rename from docs/html/search/variables_2.html rename to docs/search/variables_2.html diff --git a/docs/html/search/variables_3.js b/docs/search/variables_2.js similarity index 100% rename from docs/html/search/variables_3.js rename to docs/search/variables_2.js diff --git a/docs/html/search/variables_3.html b/docs/search/variables_3.html similarity index 100% rename from docs/html/search/variables_3.html rename to docs/search/variables_3.html diff --git a/docs/html/search/variables_4.js b/docs/search/variables_3.js similarity index 100% rename from docs/html/search/variables_4.js rename to docs/search/variables_3.js diff --git a/docs/html/splitbar.png b/docs/splitbar.png similarity index 100% rename from docs/html/splitbar.png rename to docs/splitbar.png diff --git a/docs/html/struct_s_s_l_client_parameters-members.html b/docs/struct_s_s_l_client_parameters-members.html similarity index 97% rename from docs/html/struct_s_s_l_client_parameters-members.html rename to docs/struct_s_s_l_client_parameters-members.html index b326fb4..6246a74 100644 --- a/docs/html/struct_s_s_l_client_parameters-members.html +++ b/docs/struct_s_s_l_client_parameters-members.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/struct_s_s_l_client_parameters.html b/docs/struct_s_s_l_client_parameters.html similarity index 97% rename from docs/html/struct_s_s_l_client_parameters.html rename to docs/struct_s_s_l_client_parameters.html index c889f7c..142f1e3 100644 --- a/docs/html/struct_s_s_l_client_parameters.html +++ b/docs/struct_s_s_l_client_parameters.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    @@ -164,7 +163,7 @@ Public Attributes
    The documentation for this struct was generated from the following file: diff --git a/docs/html/struct_s_s_l_client_parameters.js b/docs/struct_s_s_l_client_parameters.js similarity index 100% rename from docs/html/struct_s_s_l_client_parameters.js rename to docs/struct_s_s_l_client_parameters.js diff --git a/docs/html/structssl__pem__decode__state-members.html b/docs/structssl__pem__decode__state-members.html similarity index 97% rename from docs/html/structssl__pem__decode__state-members.html rename to docs/structssl__pem__decode__state-members.html index de3d26c..ac3c7aa 100644 --- a/docs/html/structssl__pem__decode__state-members.html +++ b/docs/structssl__pem__decode__state-members.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    diff --git a/docs/html/structssl__pem__decode__state.html b/docs/structssl__pem__decode__state.html similarity index 96% rename from docs/html/structssl__pem__decode__state.html rename to docs/structssl__pem__decode__state.html index df3c8e2..c050a22 100644 --- a/docs/html/structssl__pem__decode__state.html +++ b/docs/structssl__pem__decode__state.html @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    @@ -132,7 +131,7 @@ Public Attributes
    The documentation for this struct was generated from the following file: diff --git a/docs/html/structssl__pem__decode__state.js b/docs/structssl__pem__decode__state.js similarity index 100% rename from docs/html/structssl__pem__decode__state.js rename to docs/structssl__pem__decode__state.js diff --git a/docs/html/sync_off.png b/docs/sync_off.png similarity index 100% rename from docs/html/sync_off.png rename to docs/sync_off.png diff --git a/docs/html/sync_on.png b/docs/sync_on.png similarity index 100% rename from docs/html/sync_on.png rename to docs/sync_on.png diff --git a/docs/html/tab_a.png b/docs/tab_a.png similarity index 100% rename from docs/html/tab_a.png rename to docs/tab_a.png diff --git a/docs/html/tab_b.png b/docs/tab_b.png similarity index 100% rename from docs/html/tab_b.png rename to docs/tab_b.png diff --git a/docs/html/tab_h.png b/docs/tab_h.png similarity index 100% rename from docs/html/tab_h.png rename to docs/tab_h.png diff --git a/docs/html/tab_s.png b/docs/tab_s.png similarity index 100% rename from docs/html/tab_s.png rename to docs/tab_s.png diff --git a/docs/html/tabs.css b/docs/tabs.css similarity index 100% rename from docs/html/tabs.css rename to docs/tabs.css diff --git a/docs/html/time__macros_8h.html b/docs/time__macros_8h.html similarity index 97% rename from docs/html/time__macros_8h.html rename to docs/time__macros_8h.html index 7709738..aee4b86 100644 --- a/docs/html/time__macros_8h.html +++ b/docs/time__macros_8h.html @@ -5,7 +5,7 @@ -SSLClient: C:/Users/Noah/Documents/Arduino/libraries/SSLClient/src/time_macros.h File Reference +SSLClient: time_macros.h File Reference @@ -30,9 +30,8 @@
    SSLClient -  v1.4.7 +  v1.5.0
    -
    Add TLS 1.2 functionality to any network library.
    @@ -579,7 +578,7 @@ Macros
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include "SSLObj.h"
    25 #include <vector>
    26 
    27 #ifndef SSLClient_H_
    28 #define SSLClient_H_
    29 
    35 class SSLClient : public Client {
    36 public:
    45  enum Error {
    46  SSL_OK = 0,
    59  };
    60 
    67  enum DebugLevel {
    69  SSL_NONE = 0,
    71  SSL_ERROR = 1,
    73  SSL_WARN = 2,
    75  SSL_INFO = 3,
    76  };
    77 
    95  explicit SSLClient( Client& client,
    96  const br_x509_trust_anchor *trust_anchors,
    97  const size_t trust_anchors_num,
    98  const int analog_pin,
    99  const size_t max_sessions = 1,
    100  const DebugLevel debug = SSL_WARN);
    101 
    102  //========================================
    103  //= Functions implemented in SSLClient.cpp
    104  //========================================
    105 
    145  int connect(IPAddress ip, uint16_t port) override;
    146 
    183  int connect(const char *host, uint16_t port) override;
    184 
    208  size_t write(const uint8_t *buf, size_t size) override;
    210  size_t write(uint8_t b) override { return write(&b, 1); }
    211 
    230  int available() override;
    231 
    253  int read(uint8_t *buf, size_t size) override;
    258  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    259 
    268  int peek() override;
    269 
    277  void flush() override;
    278 
    287  void stop() override;
    288 
    302  uint8_t connected() override;
    303 
    304  //========================================
    305  //= Functions Not in the Client Interface
    306  //========================================
    307 
    316  void setMutualAuthParams(const SSLClientParameters* params);
    317 
    332  SSLSession* getSession(const char* host);
    333 
    342  void removeSession(const char* host);
    343 
    349  size_t getSessionCount() const { return m_sessions.size(); }
    350 
    356  operator bool() { return connected() > 0; }
    357 
    359  Client& getClient() { return m_client; }
    360 
    365  void setTimeout(unsigned int t) { m_timeout = t; }
    366 
    371  unsigned int getTimeout() const { return m_timeout; }
    372 
    373 private:
    375  Client& get_arduino_client() { return m_client; }
    376  const Client& get_arduino_client() const { return m_client; }
    377 
    379  bool m_soft_connected(const char* func_name);
    381  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    383  int m_run_until(const unsigned target);
    385  unsigned m_update_engine();
    387  int m_get_session_index(const char* host) const;
    388 
    390  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    391 
    393  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    394 
    396  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    397 
    399  template<typename T>
    400  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    401  // check the current debug level and serial status
    402  if (level > m_debug || !Serial) return;
    403  // print prefix
    404  m_print_prefix(func_name, level);
    405  // print the message
    406  Serial.println(str);
    407  }
    408 
    410  template<typename T>
    411  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    412 
    413  template<typename T>
    414  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    415 
    416  template<typename T>
    417  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    418 
    419  //============================================
    420  //= Data Members
    421  //============================================
    422  // create a reference the client
    423  Client& m_client;
    424  // also store an array of SSLSessions, so we can resume communication with multiple websites
    425  std::vector<SSLSession> m_sessions;
    426  // as well as the maximmum number of sessions we can store
    427  const size_t m_max_sessions;
    428  // store the pin to fetch an RNG see from
    429  const int m_analog_pin;
    430  // store whether to enable debug logging
    431  const DebugLevel m_debug;
    432  // store if we are connected in bearssl or not
    433  bool m_is_connected;
    434  // store the timeout for SSL internals
    435  unsigned int m_timeout;
    436  // store the context values required for SSL
    437  br_ssl_client_context m_sslctx;
    438  br_x509_minimal_context m_x509ctx;
    439  // use a mono-directional buffer by default to cut memory in half
    440  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    441  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    442  // simply edit this value to change the buffer size to the desired value
    443  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    444  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    452  unsigned char m_iobuf[2048];
    453  // store the index of where we are writing in the buffer
    454  // so we can send our records all at once to prevent
    455  // weird timing issues
    456  size_t m_write_idx;
    457 };
    458 
    459 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:251
    -
    Definition: SSLClient.h:58
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    21 #include "Client.h"
    22 #include "SSLSession.h"
    23 #include "SSLClientParameters.h"
    24 #include <vector>
    25 
    26 #ifndef SSLClient_H_
    27 #define SSLClient_H_
    28 
    34 class SSLClient : public Client {
    35 public:
    44  enum Error {
    45  SSL_OK = 0,
    58  };
    59 
    66  enum DebugLevel {
    68  SSL_NONE = 0,
    70  SSL_ERROR = 1,
    72  SSL_WARN = 2,
    74  SSL_INFO = 3,
    75  };
    76 
    94  explicit SSLClient( Client& client,
    95  const br_x509_trust_anchor *trust_anchors,
    96  const size_t trust_anchors_num,
    97  const int analog_pin,
    98  const size_t max_sessions = 1,
    99  const DebugLevel debug = SSL_WARN);
    100 
    101  //========================================
    102  //= Functions implemented in SSLClient.cpp
    103  //========================================
    104 
    144  int connect(IPAddress ip, uint16_t port) override;
    145 
    182  int connect(const char *host, uint16_t port) override;
    183 
    207  size_t write(const uint8_t *buf, size_t size) override;
    209  size_t write(uint8_t b) override { return write(&b, 1); }
    210 
    229  int available() override;
    230 
    252  int read(uint8_t *buf, size_t size) override;
    257  int read() override { uint8_t read_val; return read(&read_val, 1) > 0 ? read_val : -1; };
    258 
    267  int peek() override;
    268 
    276  void flush() override;
    277 
    286  void stop() override;
    287 
    301  uint8_t connected() override;
    302 
    303  //========================================
    304  //= Functions Not in the Client Interface
    305  //========================================
    306 
    315  void setMutualAuthParams(const SSLClientParameters& params);
    316 
    331  SSLSession* getSession(const char* host);
    332 
    341  void removeSession(const char* host);
    342 
    348  size_t getSessionCount() const { return m_sessions.size(); }
    349 
    355  operator bool() { return connected() > 0; }
    356 
    358  Client& getClient() { return m_client; }
    359 
    364  void setTimeout(unsigned int t) { m_timeout = t; }
    365 
    370  unsigned int getTimeout() const { return m_timeout; }
    371 
    372 private:
    374  Client& get_arduino_client() { return m_client; }
    375  const Client& get_arduino_client() const { return m_client; }
    376 
    378  bool m_soft_connected(const char* func_name);
    380  int m_start_ssl(const char* host = nullptr, SSLSession* ssl_ses = nullptr);
    382  int m_run_until(const unsigned target);
    384  unsigned m_update_engine();
    386  int m_get_session_index(const char* host) const;
    387 
    389  void m_print_prefix(const char* func_name, const DebugLevel level) const;
    390 
    392  void m_print_ssl_error(const int ssl_error, const DebugLevel level) const;
    393 
    395  void m_print_br_error(const unsigned br_error_code, const DebugLevel level) const;
    396 
    398  template<typename T>
    399  void m_print(const T str, const char* func_name, const DebugLevel level) const {
    400  // check the current debug level and serial status
    401  if (level > m_debug || !Serial) return;
    402  // print prefix
    403  m_print_prefix(func_name, level);
    404  // print the message
    405  Serial.println(str);
    406  }
    407 
    409  template<typename T>
    410  void m_info(const T str, const char* func_name) const { m_print(str, func_name, SSL_INFO); }
    411 
    412  template<typename T>
    413  void m_warn(const T str, const char* func_name) const { m_print(str, func_name, SSL_WARN); }
    414 
    415  template<typename T>
    416  void m_error(const T str, const char* func_name) const { m_print(str, func_name, SSL_ERROR); }
    417 
    418  //============================================
    419  //= Data Members
    420  //============================================
    421  // create a reference the client
    422  Client& m_client;
    423  // also store an array of SSLSessions, so we can resume communication with multiple websites
    424  std::vector<SSLSession> m_sessions;
    425  // as well as the maximmum number of sessions we can store
    426  const size_t m_max_sessions;
    427  // store the pin to fetch an RNG see from
    428  const int m_analog_pin;
    429  // store whether to enable debug logging
    430  const DebugLevel m_debug;
    431  // store if we are connected in bearssl or not
    432  bool m_is_connected;
    433  // store the timeout for SSL internals
    434  unsigned int m_timeout;
    435  // store the context values required for SSL
    436  br_ssl_client_context m_sslctx;
    437  br_x509_minimal_context m_x509ctx;
    438  // use a mono-directional buffer by default to cut memory in half
    439  // can expand to a bi-directional buffer with maximum of BR_SSL_BUFSIZE_BIDI
    440  // or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
    441  // simply edit this value to change the buffer size to the desired value
    442  // additionally, we need to correct buffer size based off of how many sessions we decide to cache
    443  // since SSL takes so much memory if we don't it will cause the stack and heap to collide
    451  unsigned char m_iobuf[2048];
    452  // store the index of where we are writing in the buffer
    453  // so we can send our records all at once to prevent
    454  // weird timing issues
    455  size_t m_write_idx;
    456 };
    457 
    458 #endif
    uint8_t connected() override
    Check if the device is connected.
    Definition: SSLClient.cpp:220
    +
    Definition: SSLClient.h:57
    This class stores values which allow SSLClient to save and resume SSL sessions.
    Definition: SSLSession.h:51
    -
    void setTimeout(unsigned int t)
    Set the timeout when waiting for an SSL response.
    Definition: SSLClient.h:365
    -
    Definition: SSLClient.h:48
    -
    Definition: SSLClient.h:75
    -
    Definition: SSLClient.h:54
    -
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:55
    -
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:218
    -
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:282
    -
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    -
    void setMutualAuthParams(const SSLClientParameters *params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:306
    -
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:170
    -
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:35
    -
    Definition: SSLClient.h:73
    -
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:224
    -
    Definition: SSLClient.h:71
    -
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:82
    -
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:127
    -
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:258
    -
    Error
    Static constants defining the possible errors encountered.
    Definition: SSLClient.h:45
    -
    Definition: SSLClient.h:52
    -
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClient.h:67
    -
    size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:349
    -
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:206
    +
    void setTimeout(unsigned int t)
    Set the timeout when waiting for an SSL response.
    Definition: SSLClient.h:364
    +
    Definition: SSLClient.h:47
    +
    Definition: SSLClient.h:74
    +
    Definition: SSLClient.h:53
    +
    SSLClient(Client &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const size_t max_sessions=1, const DebugLevel debug=SSL_WARN)
    Initialize SSLClient with all of the prerequisites needed.
    Definition: SSLClient.cpp:24
    +
    void flush() override
    Force writing the buffered bytes from SSLClient::write to the network.
    Definition: SSLClient.cpp:187
    +
    SSLSession * getSession(const char *host)
    Gets a session reference corresponding to a host and IP, or a reference to a empty session if none ex...
    Definition: SSLClient.cpp:251
    +
    int available() override
    Returns the number of bytes available to read from the data that has been received and decrypted.
    Definition: SSLClient.cpp:139
    +
    The main SSLClient class. Check out README.md for more info.
    Definition: SSLClient.h:34
    +
    Definition: SSLClient.h:72
    +
    void stop() override
    Close the connection.
    Definition: SSLClient.cpp:193
    +
    Definition: SSLClient.h:70
    +
    int connect(IPAddress ip, uint16_t port) override
    Connect over SSL to a host specified by an IP address.
    Definition: SSLClient.cpp:51
    +
    size_t write(const uint8_t *buf, size_t size) override
    Write some bytes to the SSL connection.
    Definition: SSLClient.cpp:96
    +
    int read() override
    Read a single byte, or -1 if none is available.
    Definition: SSLClient.h:257
    +
    void setMutualAuthParams(const SSLClientParameters &params)
    Add a client certificate and enable support for mutual auth.
    Definition: SSLClient.cpp:275
    +
    Error
    Static constants defining the possible errors encountered.
    Definition: SSLClient.h:44
    +
    Definition: SSLClient.h:51
    +
    DebugLevel
    Level of verbosity used in logging for SSLClient.
    Definition: SSLClient.h:66
    +
    size_t getSessionCount() const
    Get the maximum number of SSL sessions that can be stored at once.
    Definition: SSLClient.h:348
    +
    int peek() override
    View the first byte of the buffer, without removing it from the SSLClient Buffer.
    Definition: SSLClient.cpp:175
    -
    Definition: SSLClient.h:50
    +
    Definition: SSLClient.h:49
    -
    size_t write(uint8_t b) override
    Definition: SSLClient.h:210
    -
    Client & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:359
    -
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:295
    -
    unsigned int getTimeout() const
    Get the timeout when waiting for an SSL response.
    Definition: SSLClient.h:371
    - -
    Definition: SSLClient.h:69
    -
    Definition: SSLClient.h:46
    -
    Definition: SSLClient.h:56
    +
    size_t write(uint8_t b) override
    Definition: SSLClient.h:209
    +
    Client & getClient()
    Returns a reference to the client object stored in this class. Take care not to break it.
    Definition: SSLClient.h:358
    +
    void removeSession(const char *host)
    Clear the session corresponding to a host and IP.
    Definition: SSLClient.cpp:264
    +
    unsigned int getTimeout() const
    Get the timeout when waiting for an SSL response.
    Definition: SSLClient.h:370
    +
    This class stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    +
    Definition: SSLClient.h:68
    +
    Definition: SSLClient.h:45
    +
    Definition: SSLClient.h:55
    diff --git a/docs/_s_s_l_client_parameters_8cpp.html b/docs/_s_s_l_client_parameters_8cpp.html new file mode 100644 index 0000000..7abe07a --- /dev/null +++ b/docs/_s_s_l_client_parameters_8cpp.html @@ -0,0 +1,114 @@ + + + + + + + +SSLClient: SSLClientParameters.cpp File Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.5.0 +
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    SSLClientParameters.cpp File Reference
    +
    +
    + + + + +

    +Classes

    struct  ssl_pem_decode_state
     
    +
    +
    + + + + diff --git a/docs/_s_s_l_client_parameters_8cpp.js b/docs/_s_s_l_client_parameters_8cpp.js new file mode 100644 index 0000000..3671b5b --- /dev/null +++ b/docs/_s_s_l_client_parameters_8cpp.js @@ -0,0 +1,4 @@ +var _s_s_l_client_parameters_8cpp = +[ + [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", "structssl__pem__decode__state" ] +]; \ No newline at end of file diff --git a/docs/_s_s_l_client_parameters_8h.html b/docs/_s_s_l_client_parameters_8h.html index 6c8b9fa..a9ad155 100644 --- a/docs/_s_s_l_client_parameters_8h.html +++ b/docs/_s_s_l_client_parameters_8h.html @@ -93,13 +93,14 @@ $(document).ready(function(){initNavTree('_s_s_l_client_parameters_8h.html','');
    #include "bearssl.h"
    +#include <vector>

    Go to the source code of this file.

    - - + +

    Classes

    struct  SSLClientParameters
     This struct stores data required for SSLClient to use mutual authentication. More...
    class  SSLClientParameters
     This class stores data required for SSLClient to use mutual authentication. More...
     
    diff --git a/docs/_s_s_l_client_parameters_8h_source.html b/docs/_s_s_l_client_parameters_8h_source.html index 0abb581..5656b99 100644 --- a/docs/_s_s_l_client_parameters_8h_source.html +++ b/docs/_s_s_l_client_parameters_8h_source.html @@ -90,10 +90,14 @@ $(document).ready(function(){initNavTree('_s_s_l_client_parameters_8h_source.htm
    SSLClientParameters.h
    -Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    28 #include "bearssl.h"
    29 
    30 #ifndef SSLClientParameters_H_
    31 #define SSLClientParameters_H_
    32 
    59  const br_x509_certificate* client_cert_chain;
    61  const size_t chain_len;
    63  const br_ec_private_key ec_key;
    64 };
    65 
    66 #endif
    const br_x509_certificate * client_cert_chain
    Pointer to the client certificate chain.
    Definition: SSLClientParameters.h:59
    -
    This struct stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    -
    const size_t chain_len
    Definition: SSLClientParameters.h:61
    -
    const br_ec_private_key ec_key
    Definition: SSLClientParameters.h:63
    +Go to the documentation of this file.
    1 /* Copyright 2019 OSU OPEnS Lab
    2  *
    3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    4  * software and associated documentation files (the "Software"), to deal in the Software
    5  * without restriction, including without limitation the rights to use, copy, modify,
    6  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    7  * permit persons to whom the Software is furnished to do so, subject to the following
    8  * conditions:
    9  *
    10  * The above copyright notice and this permission notice shall be included in all
    11  * copies or substantial portions of the Software.
    12  *
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    15  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    16  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    17  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    18  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    19  */
    20 
    28 #include "bearssl.h"
    29 #undef min
    30 #undef max
    31 #include <vector>
    32 
    33 #ifndef SSLClientParameters_H_
    34 #define SSLClientParameters_H_
    35 
    53 public:
    84  static SSLClientParameters fromPEM(const char* cert_pem, const size_t cert_len, const char* key_pem, const size_t key_len);
    85 
    112  static SSLClientParameters fromDER(const char* cert_der, const size_t cert_len, const char* key_der, const size_t key_len);
    113 
    115  const br_x509_certificate* getCertChain() const { return &m_cert_struct; }
    116 
    118  int getCertType() const { return br_skey_decoder_key_type(&m_key_struct); }
    119 
    121  const br_ec_private_key* getECKey() const { return br_skey_decoder_get_ec(&m_key_struct); }
    122 
    124  const br_rsa_private_key* getRSAKey() const { return br_skey_decoder_get_rsa(&m_key_struct); }
    125 
    126 protected:
    127  SSLClientParameters(const char* cert, const size_t cert_len, const char* key, const size_t key_len, bool is_der);
    128 
    129 private:
    130  const std::vector<char> m_cert;
    131  const br_x509_certificate m_cert_struct;
    132  const br_skey_decoder_context m_key_struct;
    133 };
    134 
    135 #endif
    int getCertType() const
    Definition: SSLClientParameters.h:118
    +
    static SSLClientParameters fromDER(const char *cert_der, const size_t cert_len, const char *key_der, const size_t key_len)
    Create mutual authentication parameters from a DER certificate and private key.
    Definition: SSLClientParameters.cpp:92
    +
    static SSLClientParameters fromPEM(const char *cert_pem, const size_t cert_len, const char *key_pem, const size_t key_len)
    Create mutual authentication parameters from a PEM certificate and private key.
    Definition: SSLClientParameters.cpp:87
    +
    const br_rsa_private_key * getRSAKey() const
    Definition: SSLClientParameters.h:124
    +
    SSLClientParameters(const char *cert, const size_t cert_len, const char *key, const size_t key_len, bool is_der)
    Definition: SSLClientParameters.cpp:81
    +
    const br_x509_certificate * getCertChain() const
    Definition: SSLClientParameters.h:115
    +
    This class stores data required for SSLClient to use mutual authentication.
    Definition: SSLClientParameters.h:52
    +
    const br_ec_private_key * getECKey() const
    Definition: SSLClientParameters.h:121
    diff --git a/docs/annotated.html b/docs/annotated.html index a1783da..24db1d6 100644 --- a/docs/annotated.html +++ b/docs/annotated.html @@ -94,7 +94,7 @@ $(document).ready(function(){initNavTree('annotated.html','');}); - +
     Cssl_pem_decode_state
     CSSLClientThe main SSLClient class. Check out README.md for more info
     CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication
     CSSLClientParametersThis class stores data required for SSLClient to use mutual authentication
     CSSLSessionThis class stores values which allow SSLClient to save and resume SSL sessions
    diff --git a/docs/annotated_dup.js b/docs/annotated_dup.js index 997b666..a72472c 100644 --- a/docs/annotated_dup.js +++ b/docs/annotated_dup.js @@ -2,6 +2,6 @@ var annotated_dup = [ [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", "structssl__pem__decode__state" ], [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ], - [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ], + [ "SSLClientParameters", "class_s_s_l_client_parameters.html", "class_s_s_l_client_parameters" ], [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] ]; \ No newline at end of file diff --git a/docs/class_s_s_l_client-members.html b/docs/class_s_s_l_client-members.html index c43c371..b0ba8c6 100644 --- a/docs/class_s_s_l_client-members.html +++ b/docs/class_s_s_l_client-members.html @@ -109,7 +109,7 @@ $(document).ready(function(){initNavTree('class_s_s_l_client.html','');}); read(uint8_t *buf, size_t size) overrideSSLClient read() overrideSSLClientinline removeSession(const char *host)SSLClient - setMutualAuthParams(const SSLClientParameters *params)SSLClient + setMutualAuthParams(const SSLClientParameters &params)SSLClient setTimeout(unsigned int t)SSLClientinline SSL_BR_CONNECT_FAIL enum valueSSLClient SSL_BR_WRITE_ERROR enum valueSSLClient diff --git a/docs/class_s_s_l_client.html b/docs/class_s_s_l_client.html index a22ac7e..66de223 100644 --- a/docs/class_s_s_l_client.html +++ b/docs/class_s_s_l_client.html @@ -166,9 +166,9 @@ Public Member Functions uint8_t connected () override  Check if the device is connected. More...
      -void setMutualAuthParams (const SSLClientParameters *params) - Add a client certificate and enable support for mutual auth. More...
    -  +void setMutualAuthParams (const SSLClientParameters &params) + Add a client certificate and enable support for mutual auth. More...
    SSLSessiongetSession (const char *host)  Gets a session reference corresponding to a host and IP, or a reference to a empty session if none exist. More...
      @@ -810,8 +810,8 @@ There must be a trust anchor given to the constructor that corresponds to the ce - -

    ◆ setMutualAuthParams()

    + +

    ◆ setMutualAuthParams()

    @@ -819,7 +819,7 @@ There must be a trust anchor given to the constructor that corresponds to the ce void SSLClient::setMutualAuthParams ( - const SSLClientParameters *  + const SSLClientParametersparams) diff --git a/docs/class_s_s_l_client.js b/docs/class_s_s_l_client.js index d2eadc2..861496f 100644 --- a/docs/class_s_s_l_client.js +++ b/docs/class_s_s_l_client.js @@ -30,7 +30,7 @@ var class_s_s_l_client = [ "read", "class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95", null ], [ "read", "class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb", null ], [ "removeSession", "class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4", null ], - [ "setMutualAuthParams", "class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29", null ], + [ "setMutualAuthParams", "class_s_s_l_client.html#aeee217b5558dfb0724f2319888a77256", null ], [ "setTimeout", "class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae", null ], [ "stop", "class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe", null ], [ "write", "class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86", null ], diff --git a/docs/class_s_s_l_client_parameters-members.html b/docs/class_s_s_l_client_parameters-members.html new file mode 100644 index 0000000..caa4047 --- /dev/null +++ b/docs/class_s_s_l_client_parameters-members.html @@ -0,0 +1,114 @@ + + + + + + + +SSLClient: Member List + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.5.0 +
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    SSLClientParameters Member List
    +
    +
    + +

    This is the complete list of members for SSLClientParameters, including all inherited members.

    + + + + + + + + +
    fromDER(const char *cert_der, const size_t cert_len, const char *key_der, const size_t key_len)SSLClientParametersstatic
    fromPEM(const char *cert_pem, const size_t cert_len, const char *key_pem, const size_t key_len)SSLClientParametersstatic
    getCertChain() constSSLClientParametersinline
    getCertType() constSSLClientParametersinline
    getECKey() constSSLClientParametersinline
    getRSAKey() constSSLClientParametersinline
    SSLClientParameters(const char *cert, const size_t cert_len, const char *key, const size_t key_len, bool is_der)SSLClientParametersprotected
    +
    + + + + diff --git a/docs/class_s_s_l_client_parameters.html b/docs/class_s_s_l_client_parameters.html new file mode 100644 index 0000000..9811c6e --- /dev/null +++ b/docs/class_s_s_l_client_parameters.html @@ -0,0 +1,436 @@ + + + + + + + +SSLClient: SSLClientParameters Class Reference + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    SSLClient +  v1.5.0 +
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    + +
    + + +
    + +

    This class stores data required for SSLClient to use mutual authentication. + More...

    + +

    #include <SSLClientParameters.h>

    + + + + + + + + + + +

    +Public Member Functions

    const br_x509_certificate * getCertChain () const
     
    int getCertType () const
     
    const br_ec_private_key * getECKey () const
     
    const br_rsa_private_key * getRSAKey () const
     
    + + + + + + + +

    +Static Public Member Functions

    static SSLClientParameters fromPEM (const char *cert_pem, const size_t cert_len, const char *key_pem, const size_t key_len)
     Create mutual authentication parameters from a PEM certificate and private key. More...
     
    static SSLClientParameters fromDER (const char *cert_der, const size_t cert_len, const char *key_der, const size_t key_len)
     Create mutual authentication parameters from a DER certificate and private key. More...
     
    + + + +

    +Protected Member Functions

     SSLClientParameters (const char *cert, const size_t cert_len, const char *key, const size_t key_len, bool is_der)
     
    +

    Detailed Description

    +

    This class stores data required for SSLClient to use mutual authentication.

    +

    SSLClientParameters.h

    +

    This file contains a simple utility class to store parameters about an SSL Session for reuse later.TLS mutual authentication is a process in which both the server and client perform cryptographic operations to verify the authenticity of eachother, for more information check out this article: https://medium.com/sitewards/the-magic-of-tls-x509-and-mutual-authentication-explained-b2162dec4401 . If this struct is provided to SSLClient::SSLClient via SSLClient::setMutualAuthParams, SSLClient will automatically send a client certificate if one is requested by the server. This will happen for all SSLClient connections, and may cause issues for websites that do not need mutual authentication—as a result, please only turn on mutual authentication if you are sure it is neccesary.

    +

    SSLClientParameters supports both ECC and RSA client certificates. I recommend using ECC certificates if possible, as SSLClientParameters will make a copy of both the certificate and the private key in memory, and ECC keys tend to be smaller than RSA ones.

    +

    Constructor & Destructor Documentation

    + +

    ◆ SSLClientParameters()

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SSLClientParameters::SSLClientParameters (const char * cert,
    const size_t cert_len,
    const char * key,
    const size_t key_len,
    bool is_der 
    )
    +
    +protected
    +
    + +
    +
    +

    Member Function Documentation

    + +

    ◆ fromDER()

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SSLClientParameters SSLClientParameters::fromDER (const char * cert_der,
    const size_t cert_len,
    const char * key_der,
    const size_t key_len 
    )
    +
    +static
    +
    + +

    Create mutual authentication parameters from a DER certificate and private key.

    +

    Use this function to create a mutual tls context from a DER client certificate and DER private key. This function will copy the certificate and private key, extract the needed information from the private key, and store both that information and the copied cert into a SSLClientParameters object. Given the key parsed correctly, you can then use SSLClient::setMutualAuthParams at the begining of your sketch to enable mTLS with SSLClient. This function supports both ECC and RSA certificate/private keys (use EC keys wherever possible, as they are signifigantly smaller and faster), however SSLClient only supports the p256, p384, and p512 curves for ECC.

    +

    Because SSLClientParameters creates a copy of both the certificate and key, you do not need to ensure that the data pointed to by cert_der or key_der is accessible after this function (i.e. you can free them afterwards).

    +

    Please note that if the private key is incorrect, this function will not report an error, and instead SSLClient will fall back to regular TLS when making a connection.

    +
    Parameters
    + + + + + +
    cert_derA DER encoded certificate, can be ECC or RSA.
    cert_lenThe number of bytes in cert_der.
    key_derA DER encoded private key, can be ECC or RSA.
    key_lenThe number of bytes in key_ders
    +
    +
    +
    Returns
    An SSLClientParameters context, to be used with SSLClient::setMutualAuthParams.
    + +
    +
    + +

    ◆ fromPEM()

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SSLClientParameters SSLClientParameters::fromPEM (const char * cert_pem,
    const size_t cert_len,
    const char * key_pem,
    const size_t key_len 
    )
    +
    +static
    +
    + +

    Create mutual authentication parameters from a PEM certificate and private key.

    +

    Use this function to create a mutual tls context from a PEM client certificate and PEM private key. This function will convert the PEM certificates into DER format (creating a copy in the process), extract the needed information from the private key, and store that information into a SSLClientParameters object. Given the certifiate and key parsed correctly, you can then use SSLClient::setMutualAuthParams at the begining of your sketch to enable mTLS with SSLClient. This function supports both ECC and RSA certificate/private keys (use EC keys wherever possible, as they are signifigantly smaller and faster), however SSLClient only supports the p256, p384, and p512 curves for ECC.

    +

    Because SSLClientParameters creates a copy of both the certificate and key, you do not need to ensure that the data pointed to by cert_pem or key_pem is accessible after this function (i.e. you can free them afterwards).

    +

    Please note that if the certificate or private key are incorrect, this function will not report an error, and instead SSLClient will fall back to regular TLS when making a connection.

    +
    Parameters
    + + + + + +
    cert_pemA PEM formatted certificate, including the "BEGIN" and "END" header/footers. Can be ECC or RSA. cert_pem supports both LF and CRLF for endlines, but all other constraints on a valid PEM file apply.
    cert_lenThe number of bytes in cert_pem.
    key_pemA PEM formatted private key, including the "BEGIN" and "END" header/footers. Can be ECC or RSA. key_pem supports both LF and CRLF for endlines, but all other constraints \ on a valid PEM file apply.
    key_lenThe number of bytes in key_pem
    +
    +
    +
    Returns
    An SSLClientParameters context, to be used with SSLClient::setMutualAuthParams.
    + +
    +
    + +

    ◆ getCertChain()

    + +
    +
    + + + + + +
    + + + + + + + +
    const br_x509_certificate* SSLClientParameters::getCertChain () const
    +
    +inline
    +
    +

    mTLS information used by SSLClient during authentication

    + +
    +
    + +

    ◆ getCertType()

    + +
    +
    + + + + + +
    + + + + + + + +
    int SSLClientParameters::getCertType () const
    +
    +inline
    +
    +

    mTLS information used by SSLClient during authentication

    + +
    +
    + +

    ◆ getECKey()

    + +
    +
    + + + + + +
    + + + + + + + +
    const br_ec_private_key* SSLClientParameters::getECKey () const
    +
    +inline
    +
    +

    mTLS information used by SSLClient during authentication

    + +
    +
    + +

    ◆ getRSAKey()

    + +
    +
    + + + + + +
    + + + + + + + +
    const br_rsa_private_key* SSLClientParameters::getRSAKey () const
    +
    +inline
    +
    +

    mTLS information used by SSLClient during authentication

    + +
    +
    +
    The documentation for this class was generated from the following files: +
    +
    + + + + diff --git a/docs/class_s_s_l_client_parameters.js b/docs/class_s_s_l_client_parameters.js new file mode 100644 index 0000000..11f9ac1 --- /dev/null +++ b/docs/class_s_s_l_client_parameters.js @@ -0,0 +1,8 @@ +var class_s_s_l_client_parameters = +[ + [ "SSLClientParameters", "class_s_s_l_client_parameters.html#a97213b5554e90908fbf284669b5f22f3", null ], + [ "getCertChain", "class_s_s_l_client_parameters.html#af5686b2c601812f55477a7089b3b2c2d", null ], + [ "getCertType", "class_s_s_l_client_parameters.html#a90d581703308881714d64d1ada785ad2", null ], + [ "getECKey", "class_s_s_l_client_parameters.html#ad9beb80ce98ed9aa34db28783f0264c5", null ], + [ "getRSAKey", "class_s_s_l_client_parameters.html#a82c21b0ae4690a6b7842a0d74b12f67f", null ] +]; \ No newline at end of file diff --git a/docs/classes.html b/docs/classes.html index 31016db..c746b99 100644 --- a/docs/classes.html +++ b/docs/classes.html @@ -94,7 +94,7 @@ $(document).ready(function(){initNavTree('classes.html','');}); - +
      s  
    SSLClient   SSLSession   
    SSLClientParameters   
    SSLClientParameters   
    ssl_pem_decode_state   
    diff --git a/docs/dir_732ec7fb04c2890977d3e4bc2bf648f7.html b/docs/dir_732ec7fb04c2890977d3e4bc2bf648f7.html index b5a4cd0..55fc22c 100644 --- a/docs/dir_732ec7fb04c2890977d3e4bc2bf648f7.html +++ b/docs/dir_732ec7fb04c2890977d3e4bc2bf648f7.html @@ -97,12 +97,10 @@ Files   file  SSLClient.h [code]   +file  SSLClientParameters.cpp +  file  SSLClientParameters.h [code]   -file  SSLObj.cpp -  -file  SSLObj.h [code] -  file  SSLSession.h [code]   file  time_macros.h [code] diff --git a/docs/files.html b/docs/files.html index 7c976e6..ff8604b 100644 --- a/docs/files.html +++ b/docs/files.html @@ -94,11 +94,10 @@ $(document).ready(function(){initNavTree('files.html','');}); - - - - - + + + +
     SSLClient.cpp
     SSLClient.h
     SSLClientParameters.h
     SSLObj.cpp
     SSLObj.h
     SSLSession.h
     time_macros.h
     SSLClientParameters.cpp
     SSLClientParameters.h
     SSLSession.h
     time_macros.h
    diff --git a/docs/files_dup.js b/docs/files_dup.js index 8050b9b..be727b1 100644 --- a/docs/files_dup.js +++ b/docs/files_dup.js @@ -4,11 +4,10 @@ var files_dup = [ "SSLClient.h", "_s_s_l_client_8h.html", [ [ "SSLClient", "class_s_s_l_client.html", "class_s_s_l_client" ] ] ], + [ "SSLClientParameters.cpp", "_s_s_l_client_parameters_8cpp.html", "_s_s_l_client_parameters_8cpp" ], [ "SSLClientParameters.h", "_s_s_l_client_parameters_8h.html", [ - [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", "struct_s_s_l_client_parameters" ] + [ "SSLClientParameters", "class_s_s_l_client_parameters.html", "class_s_s_l_client_parameters" ] ] ], - [ "SSLObj.cpp", "_s_s_l_obj_8cpp.html", "_s_s_l_obj_8cpp" ], - [ "SSLObj.h", "_s_s_l_obj_8h.html", "_s_s_l_obj_8h" ], [ "SSLSession.h", "_s_s_l_session_8h.html", [ [ "SSLSession", "class_s_s_l_session.html", "class_s_s_l_session" ] ] ], diff --git a/docs/functions.html b/docs/functions.html index 7359072..9ec5b7f 100644 --- a/docs/functions.html +++ b/docs/functions.html @@ -96,12 +96,6 @@ $(document).ready(function(){initNavTree('functions.html','');});

    - c -

      -
    • chain_len -: SSLClientParameters -
    • -
    • client_cert_chain -: SSLClientParameters -
    • connect() : SSLClient
    • @@ -119,9 +113,6 @@ $(document).ready(function(){initNavTree('functions.html','');});

      - e -

      @@ -139,9 +136,21 @@ $(document).ready(function(){initNavTree('functions.html','');});
    • get_hostname() : SSLSession
    • +
    • getCertChain() +: SSLClientParameters +
    • +
    • getCertType() +: SSLClientParameters +
    • getClient() : SSLClient
    • +
    • getECKey() +: SSLClientParameters +
    • +
    • getRSAKey() +: SSLClientParameters +
    • getSession() : SSLClient
    • @@ -187,7 +196,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

      - s -

      • setMutualAuthParams() -: SSLClient +: SSLClient
      • setTimeout() : SSLClient @@ -228,6 +237,9 @@ $(document).ready(function(){initNavTree('functions.html','');});
      • SSLClient() : SSLClient
      • +
      • SSLClientParameters() +: SSLClientParameters +
      • SSLSession() : SSLSession
      • @@ -246,7 +258,7 @@ $(document).ready(function(){initNavTree('functions.html','');});

        - v -

        diff --git a/docs/functions_func.html b/docs/functions_func.html index 7b31d7e..345da92 100644 --- a/docs/functions_func.html +++ b/docs/functions_func.html @@ -99,12 +99,30 @@ $(document).ready(function(){initNavTree('functions_func.html','');});
      • flush() : SSLClient
      • +
      • fromDER() +: SSLClientParameters +
      • +
      • fromPEM() +: SSLClientParameters +
      • get_hostname() : SSLSession
      • +
      • getCertChain() +: SSLClientParameters +
      • +
      • getCertType() +: SSLClientParameters +
      • getClient() : SSLClient
      • +
      • getECKey() +: SSLClientParameters +
      • +
      • getRSAKey() +: SSLClientParameters +
      • getSession() : SSLClient
      • @@ -127,7 +145,7 @@ $(document).ready(function(){initNavTree('functions_func.html','');}); : SSLClient
      • setMutualAuthParams() -: SSLClient +: SSLClient
      • setTimeout() : SSLClient @@ -135,6 +153,9 @@ $(document).ready(function(){initNavTree('functions_func.html','');});
      • SSLClient() : SSLClient
      • +
      • SSLClientParameters() +: SSLClientParameters +
      • SSLSession() : SSLSession
      • diff --git a/docs/functions_vars.html b/docs/functions_vars.html index b608684..7906622 100644 --- a/docs/functions_vars.html +++ b/docs/functions_vars.html @@ -87,20 +87,11 @@ $(document).ready(function(){initNavTree('functions_vars.html','');});
         
        diff --git a/docs/hierarchy.html b/docs/hierarchy.html index a60c3c8..f3f3709 100644 --- a/docs/hierarchy.html +++ b/docs/hierarchy.html @@ -97,7 +97,7 @@ $(document).ready(function(){initNavTree('hierarchy.html','');});  CClient  CSSLClientThe main SSLClient class. Check out README.md for more info  Cssl_pem_decode_state - CSSLClientParametersThis struct stores data required for SSLClient to use mutual authentication + CSSLClientParametersThis class stores data required for SSLClient to use mutual authentication diff --git a/docs/hierarchy.js b/docs/hierarchy.js index 5a0d7ae..20eae65 100644 --- a/docs/hierarchy.js +++ b/docs/hierarchy.js @@ -7,5 +7,5 @@ var hierarchy = [ "SSLClient", "class_s_s_l_client.html", null ] ] ], [ "ssl_pem_decode_state", "structssl__pem__decode__state.html", null ], - [ "SSLClientParameters", "struct_s_s_l_client_parameters.html", null ] + [ "SSLClientParameters", "class_s_s_l_client_parameters.html", null ] ]; \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 40684c1..17415d0 100644 --- a/docs/index.html +++ b/docs/index.html @@ -93,7 +93,7 @@ $(document).ready(function(){initNavTree('index.html','');});

        Build Status

        SSLClient requires at least 110kb flash and 7kb RAM, and will not compile otherwise. This means that most Arduino boards are not supported. Check your board's specifications before attempting to use this library.

        -

        You can also view this README in doxygen.

        +

        You can also view this README in doxygen.

        SSLClient is a simple library to add TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it.

        SSLClient has been tested on the SAMD21, ESP32, TIVA C, and STM32 (in progress). SSClient does not currently support the ESP8266 (see this issue).

        Overview

        diff --git a/docs/md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html b/docs/md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html index 1c0c115..8acf101 100644 --- a/docs/md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html +++ b/docs/md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html @@ -100,7 +100,7 @@ $(document).ready(function(){initNavTree('md___users__noah__documents__arduino_l
      • The brssl command line utility, included in the BearSSL source. You will need to compile this file yourself.

      Other Connections

      -

      For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convet --no-search command to convert the certificate into a trust anchor header.

      +

      For other kinds of SSL connections, you will need to find the root certificate being used by your host. You can check out this StackExchange post for numerous methods of acquiring this certificate from a server. If these methods are not sufficient, you may need to request this certificate from your network administrator. Once you have the certificate, convert it to PEM format if needed (I use this website), and use the pycert_bearssl.py convert --no-search command to convert the certificate into a trust anchor header.

      Using Trust Anchors

      Once you've generated a trust anchor array, add it to your Arduino sketch using the Sketch->Add File button in the Arduino IDE, and link it to your SSLClient like so:

      {C++}
      #include "yourtrustanchorfile.h"
      // ...
      SSLClient client(SomeClient, TAs, (size_t)TAs_NUM, SomePin);
      // ...

      Where yourtrustanchorfile.h contains a generated trust anchor array names TAs, with length TAs_NUM. BearSSL will now automatically use these trust anchors when SSLClient::connect is called.

      diff --git a/docs/menudata.js b/docs/menudata.js index 5407264..41d28dc 100644 --- a/docs/menudata.js +++ b/docs/menudata.js @@ -24,11 +24,6 @@ for the JavaScript code in this file var menudata={children:[ {text:"Main Page",url:"index.html"}, {text:"Related Pages",url:"pages.html"}, -{text:"Namespaces",url:"namespaces.html",children:[ -{text:"Namespace List",url:"namespaces.html"}, -{text:"Namespace Members",url:"namespacemembers.html",children:[ -{text:"All",url:"namespacemembers.html"}, -{text:"Functions",url:"namespacemembers_func.html"}]}]}, {text:"Classes",url:"annotated.html",children:[ {text:"Class List",url:"annotated.html"}, {text:"Class Index",url:"classes.html"}, diff --git a/docs/navtreedata.js b/docs/navtreedata.js index d766bc3..a0f3d5c 100644 --- a/docs/navtreedata.js +++ b/docs/navtreedata.js @@ -25,13 +25,6 @@ var NAVTREE = [ [ "SSLClient", "index.html", [ [ "Trust Anchors", "md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html", null ], - [ "Namespaces", "namespaces.html", [ - [ "Namespace List", "namespaces.html", "namespaces_dup" ], - [ "Namespace Members", "namespacemembers.html", [ - [ "All", "namespacemembers.html", null ], - [ "Functions", "namespacemembers_func.html", null ] - ] ] - ] ], [ "Classes", "annotated.html", [ [ "Class List", "annotated.html", "annotated_dup" ], [ "Class Index", "classes.html", null ], diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js index 142b068..00e0e20 100644 --- a/docs/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -1,100 +1,95 @@ var NAVTREEINDEX0 = { -"_s_s_l_client_8cpp.html":[3,0,0], -"_s_s_l_client_8h.html":[3,0,1], -"_s_s_l_client_8h_source.html":[3,0,1], -"_s_s_l_client_parameters_8h.html":[3,0,2], -"_s_s_l_client_parameters_8h_source.html":[3,0,2], -"_s_s_l_obj_8cpp.html":[3,0,3], -"_s_s_l_obj_8h.html":[3,0,4], -"_s_s_l_obj_8h.html#a9a58d01c9073b90f2b42c655828aea6d":[3,0,4,0], -"_s_s_l_obj_8h_source.html":[3,0,4], -"_s_s_l_session_8h.html":[3,0,5], -"_s_s_l_session_8h_source.html":[3,0,5], -"annotated.html":[2,0], -"class_s_s_l_client.html":[2,0,1], -"class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86":[2,0,1,20], -"class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86":[2,0,1,13], -"class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78":[2,0,1,3], -"class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90":[2,0,1,5], -"class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498":[2,0,1,11], -"class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3":[2,0,1,9], -"class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b":[2,0,1,12], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea":[2,0,1,1], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08":[2,0,1,1,6], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94":[2,0,1,1,0], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016":[2,0,1,1,4], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5":[2,0,1,1,2], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd":[2,0,1,1,1], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8":[2,0,1,1,3], -"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84":[2,0,1,1,5], -"class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95":[2,0,1,14], -"class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae":[2,0,1,6], -"class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376":[2,0,1,2], -"class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d":[2,0,1,21], -"class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae":[2,0,1,18], -"class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21":[2,0,1,8], -"class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29":[2,0,1,17], -"class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c":[2,0,1,7], -"class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3":[2,0,1,4], -"class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4":[2,0,1,16], -"class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe":[2,0,1,19], -"class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22":[2,0,1,10], -"class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb":[2,0,1,15], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1":[2,0,1,0], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5":[2,0,1,0,1], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75":[2,0,1,0,0], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97":[2,0,1,0,2], -"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2":[2,0,1,0,3], -"class_s_s_l_session.html":[2,0,3], -"class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74":[2,0,3,0], -"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[2,0,3,1], -"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[2,0,3,2], -"classes.html":[2,1], -"files.html":[3,0], -"functions.html":[2,3,0], -"functions_enum.html":[2,3,3], -"functions_eval.html":[2,3,4], -"functions_func.html":[2,3,1], -"functions_vars.html":[2,3,2], -"globals.html":[3,1,0], -"globals_defs.html":[3,1,1], -"hierarchy.html":[2,2], +"_s_s_l_client_8cpp.html":[2,0,0], +"_s_s_l_client_8h.html":[2,0,1], +"_s_s_l_client_8h_source.html":[2,0,1], +"_s_s_l_client_parameters_8cpp.html":[2,0,2], +"_s_s_l_client_parameters_8h.html":[2,0,3], +"_s_s_l_client_parameters_8h_source.html":[2,0,3], +"_s_s_l_session_8h.html":[2,0,4], +"_s_s_l_session_8h_source.html":[2,0,4], +"annotated.html":[1,0], +"class_s_s_l_client.html":[1,0,1], +"class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86":[1,0,1,20], +"class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86":[1,0,1,13], +"class_s_s_l_client.html#a0e775669b4a040fbd3f281dcbcd2de78":[1,0,1,3], +"class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90":[1,0,1,5], +"class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498":[1,0,1,11], +"class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3":[1,0,1,9], +"class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b":[1,0,1,12], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea":[1,0,1,1], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08":[1,0,1,1,6], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94":[1,0,1,1,0], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016":[1,0,1,1,4], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5":[1,0,1,1,2], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd":[1,0,1,1,1], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8":[1,0,1,1,3], +"class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84":[1,0,1,1,5], +"class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95":[1,0,1,14], +"class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae":[1,0,1,6], +"class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376":[1,0,1,2], +"class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d":[1,0,1,21], +"class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae":[1,0,1,18], +"class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21":[1,0,1,8], +"class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c":[1,0,1,7], +"class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3":[1,0,1,4], +"class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4":[1,0,1,16], +"class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe":[1,0,1,19], +"class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22":[1,0,1,10], +"class_s_s_l_client.html#aeee217b5558dfb0724f2319888a77256":[1,0,1,17], +"class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb":[1,0,1,15], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1":[1,0,1,0], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5":[1,0,1,0,1], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75":[1,0,1,0,0], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97":[1,0,1,0,2], +"class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2":[1,0,1,0,3], +"class_s_s_l_client_parameters.html":[1,0,2], +"class_s_s_l_client_parameters.html#a82c21b0ae4690a6b7842a0d74b12f67f":[1,0,2,4], +"class_s_s_l_client_parameters.html#a90d581703308881714d64d1ada785ad2":[1,0,2,2], +"class_s_s_l_client_parameters.html#a97213b5554e90908fbf284669b5f22f3":[1,0,2,0], +"class_s_s_l_client_parameters.html#ad9beb80ce98ed9aa34db28783f0264c5":[1,0,2,3], +"class_s_s_l_client_parameters.html#af5686b2c601812f55477a7089b3b2c2d":[1,0,2,1], +"class_s_s_l_session.html":[1,0,3], +"class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74":[1,0,3,0], +"class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820":[1,0,3,1], +"class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc":[1,0,3,2], +"classes.html":[1,1], +"files.html":[2,0], +"functions.html":[1,3,0], +"functions_enum.html":[1,3,3], +"functions_eval.html":[1,3,4], +"functions_func.html":[1,3,1], +"functions_vars.html":[1,3,2], +"globals.html":[2,1,0], +"globals_defs.html":[2,1,1], +"hierarchy.html":[1,2], "index.html":[], "md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html":[0], -"namespace_s_s_l_obj.html":[1,0,0], -"namespacemembers.html":[1,1,0], -"namespacemembers_func.html":[1,1,1], -"namespaces.html":[1,0], "pages.html":[], -"struct_s_s_l_client_parameters.html":[2,0,2], -"struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95":[2,0,2,1], -"struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2":[2,0,2,0], -"struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449":[2,0,2,2], -"structssl__pem__decode__state.html":[2,0,0], -"structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3":[2,0,0,0], -"structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9":[2,0,0,1], -"time__macros_8h.html":[3,0,6], -"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[3,0,6,19], -"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[3,0,6,14], -"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[3,0,6,1], -"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[3,0,6,20], -"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[3,0,6,16], -"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[3,0,6,4], -"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[3,0,6,15], -"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[3,0,6,13], -"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[3,0,6,5], -"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[3,0,6,8], -"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[3,0,6,0], -"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[3,0,6,6], -"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[3,0,6,18], -"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[3,0,6,12], -"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[3,0,6,11], -"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[3,0,6,2], -"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[3,0,6,7], -"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[3,0,6,17], -"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[3,0,6,3], -"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[3,0,6,9], -"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[3,0,6,10], -"time__macros_8h_source.html":[3,0,6] +"structssl__pem__decode__state.html":[1,0,0], +"structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3":[1,0,0,0], +"structssl__pem__decode__state.html#aa004af7ee6bfb65161dc47558e3a2ac2":[1,0,0,1], +"time__macros_8h.html":[2,0,5], +"time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487":[2,0,5,19], +"time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb":[2,0,5,14], +"time__macros_8h.html#a2488d1ddab7e5fa119da3421462231c4":[2,0,5,1], +"time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3":[2,0,5,20], +"time__macros_8h.html#a2d540510d5860d7f190d13124956bc57":[2,0,5,16], +"time__macros_8h.html#a38ac93dd8bfe385ff915a82c92bbfc97":[2,0,5,4], +"time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2":[2,0,5,15], +"time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994":[2,0,5,13], +"time__macros_8h.html#a56482fcc86a55713dee595c2092ed376":[2,0,5,5], +"time__macros_8h.html#a5ab60a7e3e1b6e0a919b3a37bc0d4b97":[2,0,5,8], +"time__macros_8h.html#a7f2cdee2eebbccd45c179a50a0bbabcf":[2,0,5,0], +"time__macros_8h.html#a868143e0521daf07b25a2f3947cf54a3":[2,0,5,6], +"time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9":[2,0,5,18], +"time__macros_8h.html#a9da779a8ca64782ea49babce14122d34":[2,0,5,12], +"time__macros_8h.html#aad01b5fb233c0091aff2a837a8de32f4":[2,0,5,11], +"time__macros_8h.html#ab3592442029a102b388fafeadc4a6ab8":[2,0,5,2], +"time__macros_8h.html#ab6c76862964ff7e543fd9d5807b2fa79":[2,0,5,7], +"time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76":[2,0,5,17], +"time__macros_8h.html#ac8f6b75d9e04634818984ba400d0dee1":[2,0,5,3], +"time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a":[2,0,5,9], +"time__macros_8h.html#ae90924c33a05839b3eb1426472f40eb3":[2,0,5,10], +"time__macros_8h_source.html":[2,0,5] }; diff --git a/docs/search/all_2.js b/docs/search/all_2.js index 0b06fcf..58b9073 100644 --- a/docs/search/all_2.js +++ b/docs/search/all_2.js @@ -1,7 +1,5 @@ var searchData= [ - ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], - ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]], ['connect',['connect',['../class_s_s_l_client.html#ab97c0745f65a6c6009ac938b3b9912c3',1,'SSLClient::connect(IPAddress ip, uint16_t port) override'],['../class_s_s_l_client.html#a248a5152cc3c3e7666bf5443bfd57c90',1,'SSLClient::connect(const char *host, uint16_t port) override']]], ['connected',['connected',['../class_s_s_l_client.html#a5488f01ccfddfd9e41f54dfbda48bcae',1,'SSLClient']]], ['conv_5fstr2dec_5f1',['CONV_STR2DEC_1',['../time__macros_8h.html#ae0574ced3f997b97d357c1cb68000e3a',1,'time_macros.h']]], diff --git a/docs/search/all_4.js b/docs/search/all_4.js index 8369997..2f4b1da 100644 --- a/docs/search/all_4.js +++ b/docs/search/all_4.js @@ -1,5 +1,4 @@ var searchData= [ - ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]], ['error',['Error',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6cea',1,'SSLClient']]] ]; diff --git a/docs/search/all_5.js b/docs/search/all_5.js index 47e3882..af098e6 100644 --- a/docs/search/all_5.js +++ b/docs/search/all_5.js @@ -1,4 +1,6 @@ var searchData= [ - ['flush',['flush',['../class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c',1,'SSLClient']]] + ['flush',['flush',['../class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c',1,'SSLClient']]], + ['fromder',['fromDER',['../class_s_s_l_client_parameters.html#a12e44f4b8340ef7f1dcbbed7649e4bef',1,'SSLClientParameters']]], + ['frompem',['fromPEM',['../class_s_s_l_client_parameters.html#ac5ddf993f7d560581297471593051ea6',1,'SSLClientParameters']]] ]; diff --git a/docs/search/all_6.js b/docs/search/all_6.js index e8142e4..0a27338 100644 --- a/docs/search/all_6.js +++ b/docs/search/all_6.js @@ -2,7 +2,11 @@ var searchData= [ ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], ['get_5fmonth',['GET_MONTH',['../time__macros_8h.html#a4dbe4cf7c879a2cdac386ce72c5e5994',1,'time_macros.h']]], + ['getcertchain',['getCertChain',['../class_s_s_l_client_parameters.html#af5686b2c601812f55477a7089b3b2c2d',1,'SSLClientParameters']]], + ['getcerttype',['getCertType',['../class_s_s_l_client_parameters.html#a90d581703308881714d64d1ada785ad2',1,'SSLClientParameters']]], ['getclient',['getClient',['../class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21',1,'SSLClient']]], + ['geteckey',['getECKey',['../class_s_s_l_client_parameters.html#ad9beb80ce98ed9aa34db28783f0264c5',1,'SSLClientParameters']]], + ['getrsakey',['getRSAKey',['../class_s_s_l_client_parameters.html#a82c21b0ae4690a6b7842a0d74b12f67f',1,'SSLClientParameters']]], ['getsession',['getSession',['../class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3',1,'SSLClient']]], ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]], ['gettimeout',['getTimeout',['../class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498',1,'SSLClient']]] diff --git a/docs/search/all_8.js b/docs/search/all_8.js index e4f8b0f..0aecf24 100644 --- a/docs/search/all_8.js +++ b/docs/search/all_8.js @@ -1,4 +1,4 @@ var searchData= [ - ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b',1,'SSLClient']]] ]; diff --git a/docs/search/all_9.js b/docs/search/all_9.js index 0aecf24..95f21a7 100644 --- a/docs/search/all_9.js +++ b/docs/search/all_9.js @@ -1,4 +1,5 @@ var searchData= [ - ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b',1,'SSLClient']]] + ['peek',['peek',['../class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86',1,'SSLClient']]], + ['pst_5foffset',['PST_OFFSET',['../time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb',1,'time_macros.h']]] ]; diff --git a/docs/search/all_a.js b/docs/search/all_a.js index 95f21a7..3e07012 100644 --- a/docs/search/all_a.js +++ b/docs/search/all_a.js @@ -1,5 +1,6 @@ var searchData= [ - ['peek',['peek',['../class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86',1,'SSLClient']]], - ['pst_5foffset',['PST_OFFSET',['../time__macros_8h.html#a243cf438274412bbecf4b8d5eeb02ccb',1,'time_macros.h']]] + ['read',['read',['../class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95',1,'SSLClient::read(uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb',1,'SSLClient::read() override']]], + ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]], + ['removesession',['removeSession',['../class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4',1,'SSLClient']]] ]; diff --git a/docs/search/all_b.js b/docs/search/all_b.js index 3e07012..3d35fb2 100644 --- a/docs/search/all_b.js +++ b/docs/search/all_b.js @@ -1,6 +1,31 @@ var searchData= [ - ['read',['read',['../class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95',1,'SSLClient::read(uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb',1,'SSLClient::read() override']]], - ['readme_2emd',['README.md',['../_r_e_a_d_m_e_8md.html',1,'']]], - ['removesession',['removeSession',['../class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4',1,'SSLClient']]] + ['sslclient',['SSLClient',['../index.html',1,'']]], + ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], + ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], + ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], + ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], + ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#aeee217b5558dfb0724f2319888a77256',1,'SSLClient']]], + ['settimeout',['setTimeout',['../class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae',1,'SSLClient']]], + ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5',1,'SSLClient']]], + ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016',1,'SSLClient']]], + ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd',1,'SSLClient']]], + ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8',1,'SSLClient']]], + ['ssl_5ferror',['SSL_ERROR',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5',1,'SSLClient']]], + ['ssl_5finfo',['SSL_INFO',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2',1,'SSLClient']]], + ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84',1,'SSLClient']]], + ['ssl_5fnone',['SSL_NONE',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75',1,'SSLClient']]], + ['ssl_5fok',['SSL_OK',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94',1,'SSLClient']]], + ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08',1,'SSLClient']]], + ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], + ['ssl_5fwarn',['SSL_WARN',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97',1,'SSLClient']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient'],['../class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376',1,'SSLClient::SSLClient()']]], + ['sslclient_2ecpp',['SSLClient.cpp',['../_s_s_l_client_8cpp.html',1,'']]], + ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], + ['sslclientparameters',['SSLClientParameters',['../class_s_s_l_client_parameters.html',1,'SSLClientParameters'],['../class_s_s_l_client_parameters.html#a97213b5554e90908fbf284669b5f22f3',1,'SSLClientParameters::SSLClientParameters()']]], + ['sslclientparameters_2ecpp',['SSLClientParameters.cpp',['../_s_s_l_client_parameters_8cpp.html',1,'']]], + ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], + ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74',1,'SSLSession::SSLSession()']]], + ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], + ['stop',['stop',['../class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe',1,'SSLClient']]] ]; diff --git a/docs/search/all_c.js b/docs/search/all_c.js index 1b4cde8..4b4b251 100644 --- a/docs/search/all_c.js +++ b/docs/search/all_c.js @@ -1,33 +1,7 @@ var searchData= [ - ['sslclient',['SSLClient',['../index.html',1,'']]], - ['sec_5fper_5fday',['SEC_PER_DAY',['../time__macros_8h.html#a3aaee30ddedb3f6675aac341a66e39e2',1,'time_macros.h']]], - ['sec_5fper_5fhour',['SEC_PER_HOUR',['../time__macros_8h.html#a2d540510d5860d7f190d13124956bc57',1,'time_macros.h']]], - ['sec_5fper_5fmin',['SEC_PER_MIN',['../time__macros_8h.html#ac47b302f1b8d2a7a9c035c417247be76',1,'time_macros.h']]], - ['sec_5fper_5fyear',['SEC_PER_YEAR',['../time__macros_8h.html#a8cd8e04105fec7cd442d078c303e46b9',1,'time_macros.h']]], - ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29',1,'SSLClient']]], - ['settimeout',['setTimeout',['../class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae',1,'SSLClient']]], - ['ssl_5fbr_5fconnect_5ffail',['SSL_BR_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa6a9cc2412a53b5981e937a41523eece5',1,'SSLClient']]], - ['ssl_5fbr_5fwrite_5ferror',['SSL_BR_WRITE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa37bef298be71b84a57e59fadbfbd9016',1,'SSLClient']]], - ['ssl_5fclient_5fconnect_5ffail',['SSL_CLIENT_CONNECT_FAIL',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa7510402478ffbecd6e1aa3811b175cfd',1,'SSLClient']]], - ['ssl_5fclient_5fwrtie_5ferror',['SSL_CLIENT_WRTIE_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaab8581e1172fbf15067d435706d3a03a8',1,'SSLClient']]], - ['ssl_5ferror',['SSL_ERROR',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a199742ec5c99c72d9cede1fda0f125c5',1,'SSLClient']]], - ['ssl_5finfo',['SSL_INFO',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a8d5f7561f9cc0a2f3e5f362b02f4a5b2',1,'SSLClient']]], - ['ssl_5finternal_5ferror',['SSL_INTERNAL_ERROR',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaaf66f8d5f6601f9e7607b78bf7a07fc84',1,'SSLClient']]], - ['ssl_5fnone',['SSL_NONE',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a24122d1e1bb724237f305a0b4a21ff75',1,'SSLClient']]], - ['ssl_5fok',['SSL_OK',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa18dbddc0a3d4a94ee0f298fe55a06a94',1,'SSLClient']]], - ['ssl_5fout_5fof_5fmemory',['SSL_OUT_OF_MEMORY',['../class_s_s_l_client.html#a48239f60f1b4318cc112706fc40c6ceaa0a4f8af0226cf29ede8f6fe4a9047b08',1,'SSLClient']]], - ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], - ['ssl_5fwarn',['SSL_WARN',['../class_s_s_l_client.html#af632625f8d247f3885c81e1f05043ad1a26f3e5f1481f3ea22ea4ab5370b0fa97',1,'SSLClient']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'SSLClient'],['../class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376',1,'SSLClient::SSLClient()']]], - ['sslclient_2ecpp',['SSLClient.cpp',['../_s_s_l_client_8cpp.html',1,'']]], - ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], - ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], - ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], - ['sslobj',['SSLObj',['../namespace_s_s_l_obj.html',1,'']]], - ['sslobj_2ecpp',['SSLObj.cpp',['../_s_s_l_obj_8cpp.html',1,'']]], - ['sslobj_2eh',['SSLObj.h',['../_s_s_l_obj_8h.html',1,'']]], - ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'SSLSession'],['../class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74',1,'SSLSession::SSLSession()']]], - ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]], - ['stop',['stop',['../class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe',1,'SSLClient']]] + ['trust_20anchors',['Trust Anchors',['../md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]], + ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], + ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]], + ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] ]; diff --git a/docs/search/all_d.js b/docs/search/all_d.js index 4b4b251..a658122 100644 --- a/docs/search/all_d.js +++ b/docs/search/all_d.js @@ -1,7 +1,5 @@ var searchData= [ - ['trust_20anchors',['Trust Anchors',['../md___users__noah__documents__arduino_libraries__s_s_l_client__trust_anchors.html',1,'']]], - ['time_5fmacros_2eh',['time_macros.h',['../time__macros_8h.html',1,'']]], - ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]], - ['trustanchors_2emd',['TrustAnchors.md',['../_trust_anchors_8md.html',1,'']]] + ['unix_5ftimestamp',['UNIX_TIMESTAMP',['../time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487',1,'time_macros.h']]], + ['unix_5ftimestamp_5futc',['UNIX_TIMESTAMP_UTC',['../time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3',1,'time_macros.h']]] ]; diff --git a/docs/search/all_e.js b/docs/search/all_e.js index a658122..5a20807 100644 --- a/docs/search/all_e.js +++ b/docs/search/all_e.js @@ -1,5 +1,4 @@ var searchData= [ - ['unix_5ftimestamp',['UNIX_TIMESTAMP',['../time__macros_8h.html#a04e76e262f0920441e5f0c5552e83487',1,'time_macros.h']]], - ['unix_5ftimestamp_5futc',['UNIX_TIMESTAMP_UTC',['../time__macros_8h.html#a2af3d1d741ae2b49627adf56bbc95dc3',1,'time_macros.h']]] + ['vect',['vect',['../structssl__pem__decode__state.html#aa004af7ee6bfb65161dc47558e3a2ac2',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/search/all_f.js b/docs/search/all_f.js index a18bd2a..451bfc6 100644 --- a/docs/search/all_f.js +++ b/docs/search/all_f.js @@ -1,4 +1,4 @@ var searchData= [ - ['vect',['vect',['../structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9',1,'ssl_pem_decode_state']]] + ['write',['write',['../class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86',1,'SSLClient::write(const uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d',1,'SSLClient::write(uint8_t b) override']]] ]; diff --git a/docs/search/classes_0.js b/docs/search/classes_0.js index 81431f8..30a6271 100644 --- a/docs/search/classes_0.js +++ b/docs/search/classes_0.js @@ -2,6 +2,6 @@ var searchData= [ ['ssl_5fpem_5fdecode_5fstate',['ssl_pem_decode_state',['../structssl__pem__decode__state.html',1,'']]], ['sslclient',['SSLClient',['../class_s_s_l_client.html',1,'']]], - ['sslclientparameters',['SSLClientParameters',['../struct_s_s_l_client_parameters.html',1,'']]], + ['sslclientparameters',['SSLClientParameters',['../class_s_s_l_client_parameters.html',1,'']]], ['sslsession',['SSLSession',['../class_s_s_l_session.html',1,'']]] ]; diff --git a/docs/search/files_1.js b/docs/search/files_1.js index 212b513..2f119fd 100644 --- a/docs/search/files_1.js +++ b/docs/search/files_1.js @@ -2,8 +2,7 @@ var searchData= [ ['sslclient_2ecpp',['SSLClient.cpp',['../_s_s_l_client_8cpp.html',1,'']]], ['sslclient_2eh',['SSLClient.h',['../_s_s_l_client_8h.html',1,'']]], + ['sslclientparameters_2ecpp',['SSLClientParameters.cpp',['../_s_s_l_client_parameters_8cpp.html',1,'']]], ['sslclientparameters_2eh',['SSLClientParameters.h',['../_s_s_l_client_parameters_8h.html',1,'']]], - ['sslobj_2ecpp',['SSLObj.cpp',['../_s_s_l_obj_8cpp.html',1,'']]], - ['sslobj_2eh',['SSLObj.h',['../_s_s_l_obj_8h.html',1,'']]], ['sslsession_2eh',['SSLSession.h',['../_s_s_l_session_8h.html',1,'']]] ]; diff --git a/docs/search/functions_2.js b/docs/search/functions_2.js index 47e3882..af098e6 100644 --- a/docs/search/functions_2.js +++ b/docs/search/functions_2.js @@ -1,4 +1,6 @@ var searchData= [ - ['flush',['flush',['../class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c',1,'SSLClient']]] + ['flush',['flush',['../class_s_s_l_client.html#aaf2192a6621fdf2f89cc26a9a1584f8c',1,'SSLClient']]], + ['fromder',['fromDER',['../class_s_s_l_client_parameters.html#a12e44f4b8340ef7f1dcbbed7649e4bef',1,'SSLClientParameters']]], + ['frompem',['fromPEM',['../class_s_s_l_client_parameters.html#ac5ddf993f7d560581297471593051ea6',1,'SSLClientParameters']]] ]; diff --git a/docs/search/functions_3.js b/docs/search/functions_3.js index 7554e48..4e3c32e 100644 --- a/docs/search/functions_3.js +++ b/docs/search/functions_3.js @@ -1,7 +1,11 @@ var searchData= [ ['get_5fhostname',['get_hostname',['../class_s_s_l_session.html#a825373c5ba1aa6c45e74dc8a72b21820',1,'SSLSession']]], + ['getcertchain',['getCertChain',['../class_s_s_l_client_parameters.html#af5686b2c601812f55477a7089b3b2c2d',1,'SSLClientParameters']]], + ['getcerttype',['getCertType',['../class_s_s_l_client_parameters.html#a90d581703308881714d64d1ada785ad2',1,'SSLClientParameters']]], ['getclient',['getClient',['../class_s_s_l_client.html#a9a4e9c9877ab73cf7e82d6942cc7db21',1,'SSLClient']]], + ['geteckey',['getECKey',['../class_s_s_l_client_parameters.html#ad9beb80ce98ed9aa34db28783f0264c5',1,'SSLClientParameters']]], + ['getrsakey',['getRSAKey',['../class_s_s_l_client_parameters.html#a82c21b0ae4690a6b7842a0d74b12f67f',1,'SSLClientParameters']]], ['getsession',['getSession',['../class_s_s_l_client.html#a2bd012ef6f01df9694ba9fd0a3c227c3',1,'SSLClient']]], ['getsessioncount',['getSessionCount',['../class_s_s_l_client.html#ae3f9e6f8e8a50e520c936239abecfd22',1,'SSLClient']]], ['gettimeout',['getTimeout',['../class_s_s_l_client.html#a2a178251978e0622f7e241da702ae498',1,'SSLClient']]] diff --git a/docs/search/functions_4.js b/docs/search/functions_4.js index e4f8b0f..0aecf24 100644 --- a/docs/search/functions_4.js +++ b/docs/search/functions_4.js @@ -1,4 +1,4 @@ var searchData= [ - ['make_5fvector_5fpem',['make_vector_pem',['../namespace_s_s_l_obj.html#a9a58d01c9073b90f2b42c655828aea6d',1,'SSLObj']]] + ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b',1,'SSLClient']]] ]; diff --git a/docs/search/functions_5.js b/docs/search/functions_5.js index 0aecf24..53b8b47 100644 --- a/docs/search/functions_5.js +++ b/docs/search/functions_5.js @@ -1,4 +1,4 @@ var searchData= [ - ['operator_20bool',['operator bool',['../class_s_s_l_client.html#a4192ee3562c4806d4a6829356ca2636b',1,'SSLClient']]] + ['peek',['peek',['../class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86',1,'SSLClient']]] ]; diff --git a/docs/search/functions_6.js b/docs/search/functions_6.js index 53b8b47..c66bc46 100644 --- a/docs/search/functions_6.js +++ b/docs/search/functions_6.js @@ -1,4 +1,5 @@ var searchData= [ - ['peek',['peek',['../class_s_s_l_client.html#a0c0b6f2ad25701d1e45adb613d072d86',1,'SSLClient']]] + ['read',['read',['../class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95',1,'SSLClient::read(uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb',1,'SSLClient::read() override']]], + ['removesession',['removeSession',['../class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4',1,'SSLClient']]] ]; diff --git a/docs/search/functions_7.js b/docs/search/functions_7.js index c66bc46..0caa7b0 100644 --- a/docs/search/functions_7.js +++ b/docs/search/functions_7.js @@ -1,5 +1,9 @@ var searchData= [ - ['read',['read',['../class_s_s_l_client.html#a4c5420541a06213133ae308a3bca1c95',1,'SSLClient::read(uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#aef1b52f4ad9633126cb68739175920eb',1,'SSLClient::read() override']]], - ['removesession',['removeSession',['../class_s_s_l_client.html#ad5d9d8a4187a3f8918bf66af83e733c4',1,'SSLClient']]] + ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#aeee217b5558dfb0724f2319888a77256',1,'SSLClient']]], + ['settimeout',['setTimeout',['../class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae',1,'SSLClient']]], + ['sslclient',['SSLClient',['../class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376',1,'SSLClient']]], + ['sslclientparameters',['SSLClientParameters',['../class_s_s_l_client_parameters.html#a97213b5554e90908fbf284669b5f22f3',1,'SSLClientParameters']]], + ['sslsession',['SSLSession',['../class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74',1,'SSLSession']]], + ['stop',['stop',['../class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe',1,'SSLClient']]] ]; diff --git a/docs/search/functions_8.js b/docs/search/functions_8.js index d2a5842..96d95c1 100644 --- a/docs/search/functions_8.js +++ b/docs/search/functions_8.js @@ -1,8 +1,4 @@ var searchData= [ - ['setmutualauthparams',['setMutualAuthParams',['../class_s_s_l_client.html#a9e7ce7f8a72d7cdc071be3fa7a4c8f29',1,'SSLClient']]], - ['settimeout',['setTimeout',['../class_s_s_l_client.html#a8da354f30537c1064d554921937a73ae',1,'SSLClient']]], - ['sslclient',['SSLClient',['../class_s_s_l_client.html#a68f026a625ca1ccd1aba87bb6e670376',1,'SSLClient']]], - ['sslsession',['SSLSession',['../class_s_s_l_session.html#a0c8e01b0944c1f4b0ec6d4c423c95b74',1,'SSLSession']]], - ['stop',['stop',['../class_s_s_l_client.html#ad8ed697371748e31e01c3f697bc36cbe',1,'SSLClient']]] + ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]] ]; diff --git a/docs/search/functions_9.js b/docs/search/functions_9.js index 96d95c1..451bfc6 100644 --- a/docs/search/functions_9.js +++ b/docs/search/functions_9.js @@ -1,4 +1,4 @@ var searchData= [ - ['to_5fbr_5fsession',['to_br_session',['../class_s_s_l_session.html#acbe6549b55d50541d09a16f770e65afc',1,'SSLSession']]] + ['write',['write',['../class_s_s_l_client.html#a03c7926938acd57cfc3b982edf725a86',1,'SSLClient::write(const uint8_t *buf, size_t size) override'],['../class_s_s_l_client.html#a7343a58457b4659f83b61cac1f442c3d',1,'SSLClient::write(uint8_t b) override']]] ]; diff --git a/docs/search/searchdata.js b/docs/search/searchdata.js index 25ef3f7..2c637cb 100644 --- a/docs/search/searchdata.js +++ b/docs/search/searchdata.js @@ -1,42 +1,39 @@ var indexSectionsWithContent = { - 0: "_acdefgimoprstuvw", + 0: "_acdefgioprstuvw", 1: "s", - 2: "s", - 3: "rst", - 4: "acfgmoprstw", - 5: "ceiv", - 6: "de", - 7: "s", - 8: "_cgpsu", - 9: "st" + 2: "rst", + 3: "acfgoprstw", + 4: "iv", + 5: "de", + 6: "s", + 7: "_cgpsu", + 8: "st" }; var indexSectionNames = { 0: "all", 1: "classes", - 2: "namespaces", - 3: "files", - 4: "functions", - 5: "variables", - 6: "enums", - 7: "enumvalues", - 8: "defines", - 9: "pages" + 2: "files", + 3: "functions", + 4: "variables", + 5: "enums", + 6: "enumvalues", + 7: "defines", + 8: "pages" }; var indexSectionLabels = { 0: "All", 1: "Classes", - 2: "Namespaces", - 3: "Files", - 4: "Functions", - 5: "Variables", - 6: "Enumerations", - 7: "Enumerator", - 8: "Macros", - 9: "Pages" + 2: "Files", + 3: "Functions", + 4: "Variables", + 5: "Enumerations", + 6: "Enumerator", + 7: "Macros", + 8: "Pages" }; diff --git a/docs/search/variables_0.js b/docs/search/variables_0.js index faff15d..2d07945 100644 --- a/docs/search/variables_0.js +++ b/docs/search/variables_0.js @@ -1,5 +1,4 @@ var searchData= [ - ['chain_5flen',['chain_len',['../struct_s_s_l_client_parameters.html#aa523f407ac673da95bf651617fbf94b2',1,'SSLClientParameters']]], - ['client_5fcert_5fchain',['client_cert_chain',['../struct_s_s_l_client_parameters.html#a3e0440790d1acdee221b8ef6be6def95',1,'SSLClientParameters']]] + ['index',['index',['../structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/search/variables_1.js b/docs/search/variables_1.js index eb3b769..5a20807 100644 --- a/docs/search/variables_1.js +++ b/docs/search/variables_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['ec_5fkey',['ec_key',['../struct_s_s_l_client_parameters.html#aca2dba04e30c8d7b962add0c353fc449',1,'SSLClientParameters']]] + ['vect',['vect',['../structssl__pem__decode__state.html#aa004af7ee6bfb65161dc47558e3a2ac2',1,'ssl_pem_decode_state']]] ]; diff --git a/docs/structssl__pem__decode__state-members.html b/docs/structssl__pem__decode__state-members.html index ac3c7aa..a9a31c6 100644 --- a/docs/structssl__pem__decode__state-members.html +++ b/docs/structssl__pem__decode__state-members.html @@ -94,7 +94,7 @@ $(document).ready(function(){initNavTree('structssl__pem__decode__state.html',''

      This is the complete list of members for ssl_pem_decode_state, including all inherited members.

      - +
      indexssl_pem_decode_state
      vectssl_pem_decode_state
      vectssl_pem_decode_state
      diff --git a/docs/structssl__pem__decode__state.html b/docs/structssl__pem__decode__state.html index c050a22..6117c99 100644 --- a/docs/structssl__pem__decode__state.html +++ b/docs/structssl__pem__decode__state.html @@ -96,8 +96,8 @@ $(document).ready(function(){initNavTree('structssl__pem__decode__state.html','' - - + +

      Public Attributes

      std::vector< unsigned char > * vect
       
      std::vector< char > * vect
       
      size_t index = 0
       
      @@ -116,14 +116,14 @@ Public Attributes - -

      ◆ vect

      + +

      ◆ vect

      - +
      std::vector<unsigned char>* ssl_pem_decode_state::vectstd::vector<char>* ssl_pem_decode_state::vect
      @@ -131,7 +131,7 @@ Public Attributes

      The documentation for this struct was generated from the following file: diff --git a/docs/structssl__pem__decode__state.js b/docs/structssl__pem__decode__state.js index fe8cbfc..613852e 100644 --- a/docs/structssl__pem__decode__state.js +++ b/docs/structssl__pem__decode__state.js @@ -1,5 +1,5 @@ var structssl__pem__decode__state = [ [ "index", "structssl__pem__decode__state.html#a8abbaad636bfcf50ef38f529e3cfd5f3", null ], - [ "vect", "structssl__pem__decode__state.html#a95f2366376d5f958f9bc1e859b59bae9", null ] + [ "vect", "structssl__pem__decode__state.html#aa004af7ee6bfb65161dc47558e3a2ac2", null ] ]; \ No newline at end of file From 3b9082cec9d94be2d3a1398e232bb2ca2988dccf Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 2 Mar 2020 16:39:30 -0800 Subject: [PATCH 117/205] fix a typo in the convert parameters --- tools/pycert_bearssl/pycert_bearssl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/pycert_bearssl/pycert_bearssl.py b/tools/pycert_bearssl/pycert_bearssl.py index 082fe6f..14cd792 100644 --- a/tools/pycert_bearssl/pycert_bearssl.py +++ b/tools/pycert_bearssl/pycert_bearssl.py @@ -100,10 +100,10 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom help='the location of the .pem file containing a list of trusted root certificates (default: use certifi.where())') @click.option('--keep-dupes', '-d', is_flag=True, default=False, help='write all certs including any duplicates (default: remove duplicates)') -@click.option('--no-verify', '-n', is_flag=True, default=False, +@click.option('--no-search', '-n', is_flag=True, default=False, help='Do not attempt to search for a root certificate to the provided PEM files, instead treat the PEM files as the root certificates') @click.argument('cert', type=click.File('r'), nargs=-1) -def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_verify, cert): +def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_search, cert): """Convert PEM certificates into a C header that can be imported into a sketch. Specify each certificate to encode as a separate argument (each must be in PEM format) and they will be merged into a single file. @@ -134,7 +134,7 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_verify, cert_objs.append(cert_parsed) # find a root certificate for each root_certs = [] - if no_verify: + if no_search: root_certs = cert_objs else: for i, c in enumerate(cert_objs): From 7a1a2a823babc0944339e130122957c93b3f1407 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Tue, 3 Mar 2020 14:52:47 -0800 Subject: [PATCH 118/205] update README for clarification and mTLS documentation --- README.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ed9c15a..c748618 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ You can also view this README in [doxygen](https://openslab-osu.github.io/SSLClient/index.html). -SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. +SSLClient is a simple library to add [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through TLS on devices that do not otherwise support it. SSLClient has been tested on the SAMD21, ESP32, TIVA C, and STM32 (in progress). SSClient does not currently support the ESP8266 (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)). @@ -14,12 +14,12 @@ SSLClient has been tested on the SAMD21, ESP32, TIVA C, and STM32 (in progress). Using SSLClient should be similar to using any other Arduino-based Client class, since this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few extra things, however, that you will need to get started: -1. A board with a lot of resources (>110kb flash and >7kb RAM), and a network peripheral with a large internal buffer (>7kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Gotchas](#sslclient-with-ethernet)). -2. A header containing array of trust anchors, which will look like [this file](./readme/cert.h). These are used to verify the SSL connection later on, and without them you will be unable to use this library. Check out [this document](./TrustAnchors.md) on how to generate this file for your project, and for more information about what a trust anchor is. -3. A Client class associated with a network interface. We tested this library using [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient), however in theory it will work for any class implementing Client. -4. An analog pin, used for generating random data at the start of the connection (see the [Implementation Gotchas](#implementation-gotchas)). +1. **Board and Network Peripheral** - Your board should have a lot of resources (>110kb flash and >7kb RAM), and your network peripheral should have a large internal buffer (>7kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Gotchas](#sslclient-with-ethernet)). +2. **Trust Anchors** - You will need a header containing array of trust anchors ([example](./readme/cert.h)), which are used to verify the SSL connection later on. **This file must generated for every project.** Check out [TrustAnchors.md](./TrustAnchors.md) on how to generate this file for your project, and for more information about what a trust anchor is. +3. **Network Peripheral Driver Implementing `Client`** - Examples include `EthernetClient`, `WiFiClient`, and so on—SSLClient will run on top of any network driver exposing the `Client` interface. We tested this library using [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). +4. **Analog Pin** - Used for generating random data at the start of the connection (see the [Implementation Gotchas](#implementation-gotchas)). -Once all those are ready, you can create a simple SSLClient object like this: +Once all those are ready, you can create an SSLClient object like this: ```C++ BaseClientType baseClientInstance; SSLClient client(baseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin); @@ -36,7 +36,7 @@ Where: EthernetClient baseClient; SSLClient client(baseClient, TAs, 2, A7); ``` -Once that is setup, simply use SSLClient as you would the base client class: +Given this client, simply use SSLClient as you would the base client class: ```C++ // connect to ardiuino.cc over ssl (port 443 for websites) client.connect("www.arduino.cc", 443); @@ -136,6 +136,47 @@ Sessions are managed internally using the SSLSession::getSession function. This If you need to clear a session, you can do so using the SSLSession::removeSession function. +### mTLS + +As of `v1.6.0`, SSLClient supports [mutual TLS authentication](https://developers.cloudflare.com/access/service-auth/mtls/). mTLS is a varient of TLS that verifys both the server and device identities before a connection, and is commonly used in IoT protocols as a secure layer (MQTT over TLS, HTTPS over TLS, etc.). + +To use mTLS with SSLClient you will need to a client certificate and client private key associated with the server you are attempting to connect to. Depending on your use case, you will either generate these yourself (ex. [Mosquito MQTT setup](http://www.steves-internet-guide.com/creating-and-using-client-certificates-with-mqtt-and-mosquitto/)), or have them generated for you (ex. [AWS IoT Certificate Generation](https://docs.aws.amazon.com/iot/latest/developerguide/create-device-certificate.html)). Given this cryptographic information, you can modify the standard SSLClient connection sketch to enable mTLS authentication: +```C++ +... +/* Somewhere above setup() */ + +// The client certificate, can be PEM or DER format +// DER format will be an array of raw bytes, and PEM format will be a string +// PEM format is shown below +const char my_cert[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIDpDCCAowCCQC7mCk5Iu3YmDANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMC\n" +... +"-----END CERTIFICATE-----\n"; + +// The client private key, must be the same format as the client certificate +// Both RSA and ECC are supported, ECC is shown below +const char my_key[] = +"-----BEGIN EC PRIVATE KEY-----\n" +... +"-----END EC PRIVATE KEY-----\n"; + +// This line will parse and store the above information so SSLClient can use it later +// Replace `fromPEM` with `fromDER` if you are using DER formatted certificates. +SSLClientParameters mTLS = SSLClientParameters::fromPEM(my_cert, sizeof(cert), my_key, sizeof(key)); +SSLClient my_client(...); +... +void setup() { + ... + /* Before SSLClient connects */ + + my_client.setMutualAuthParams(mTLS); + ... +} +... +``` +Note that both the above client information *as well as* the correct trust anchors associated with the server are needed for the connection to succeed. Additionally, the certificate must be formatted correctly (according to [BearSSL's specification](https://bearssl.org/apidoc/bearssl__pem_8h.html)) in order for mTLS to work. If the certificate is improperly formatted, SSLClient will attempt to make a regular TLS connection instead of an mTLS one, and fail to connect as a result. Because of this, if you are seeing errors similar to `"peer did not send certificate chain"` on your server, check that your certificate and key are formatted correctly (see https://github.com/OPEnSLab-OSU/SSLClient/issues/7#issuecomment-593704969). For more information on SSLClient's mTLS functionality, please see the [SSLClientParameters documentation](https://openslab-osu.github.io/SSLClient/class_s_s_l_client_parameters.html). + ## Implementation Gotchas Some ideas that didn't quite fit in the API documentation. From 5ae689bf726055c3b7f4a515b96a21922fd09236 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 9 Mar 2020 09:39:03 -0700 Subject: [PATCH 119/205] Add EthernetMQTT example to demonstrate mTLS (credit @Atalonica) --- examples/EthernetMQTT/EthernetMQTT.ino | 87 ++++++++++++++++++++++++++ tools/pycert_bearssl/certificates.h | 75 ++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 examples/EthernetMQTT/EthernetMQTT.ino create mode 100644 tools/pycert_bearssl/certificates.h diff --git a/examples/EthernetMQTT/EthernetMQTT.ino b/examples/EthernetMQTT/EthernetMQTT.ino new file mode 100644 index 0000000..5eab3fe --- /dev/null +++ b/examples/EthernetMQTT/EthernetMQTT.ino @@ -0,0 +1,87 @@ +/* + Basic MQTT example (with SSL!) + This sketch demonstrates the basic capabilities of the library. + It connects to an MQTT server then: + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "inTopic", printing out any messages + it receives. NB - it assumes the received payloads are strings not binary + It will reconnect to the server if the connection is lost using a blocking + reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to + achieve the same result without blocking the main loop. + + You will need to populate "certificates.h" with your trust anchors + (see https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md) + and my_cert/my_key with your certificate/private key pair + (see https://github.com/OPEnSLab-OSU/SSLClient#mtls). +*/ +#include +#include +#include +#include "certificates.h" // This file must be regenerated +#include + +const char my_cert[] = "FIXME"; +const char my_key[] = "FIXME"; +SSLClientParameters mTLS = SSLClientParameters::fromPEM(my_cert, sizeof my_cert, my_key, sizeof my_key); + +byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; +const char* mqttServer = "broker.example"; // Broker address +IPAddress ip (192, 168, 1, 2); // Custom client static IP + +void callback(char* topic, byte* payload, unsigned int length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + for (int i=0;i Date: Mon, 9 Mar 2020 09:40:25 -0700 Subject: [PATCH 120/205] add trust anchors to example --- examples/EthernetMQTT/certificates.h | 46 +++++++++++++++++ tools/pycert_bearssl/certificates.h | 75 ---------------------------- 2 files changed, 46 insertions(+), 75 deletions(-) create mode 100644 examples/EthernetMQTT/certificates.h delete mode 100644 tools/pycert_bearssl/certificates.h diff --git a/examples/EthernetMQTT/certificates.h b/examples/EthernetMQTT/certificates.h new file mode 100644 index 0000000..146187f --- /dev/null +++ b/examples/EthernetMQTT/certificates.h @@ -0,0 +1,46 @@ +#ifndef _CERTIFICATES_H_ +#define _CERTIFICATES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* You will need to generate the information in this file manually + * using pycert_bearssl. For more information, please see + * https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md + */ + +#define TAs_NUM 1 + +static const unsigned char TA_DN0[] = { + // FIXME +}; + +static const unsigned char TA_RSA_N0[] = { + // FIXME +}; + +static const unsigned char TA_RSA_E0[] = { + // FIXME +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef _CERTIFICATES_H_ */ \ No newline at end of file diff --git a/tools/pycert_bearssl/certificates.h b/tools/pycert_bearssl/certificates.h deleted file mode 100644 index ed91009..0000000 --- a/tools/pycert_bearssl/certificates.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _CERTIFICATES_H_ -#define _CERTIFICATES_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. - * Certificates are BearSSL br_x509_trust_anchor format. Included certs: - * - * Index: 0 - * Label: OPEnS - * Subject: C=US,ST=OR,L=Corvallis,O=OPEnS - */ - -#define TAs_NUM 1 - -static const unsigned char TA_DN0[] = { - 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, - 0x0c, 0x02, 0x4f, 0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, - 0x07, 0x0c, 0x09, 0x43, 0x6f, 0x72, 0x76, 0x61, 0x6c, 0x6c, 0x69, 0x73, - 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x05, 0x4f, - 0x50, 0x45, 0x6e, 0x53, -}; - -static const unsigned char TA_RSA_N0[] = { - 0xe2, 0x80, 0x32, 0x18, 0xe7, 0xa6, 0x94, 0x04, 0x62, 0x43, 0xbc, 0x1e, - 0x14, 0x13, 0xaf, 0x40, 0x82, 0x0e, 0x14, 0x57, 0xe8, 0x50, 0x98, 0x38, - 0xa4, 0xd9, 0xf1, 0x8a, 0x20, 0x5f, 0x37, 0xae, 0xd1, 0xdf, 0xc1, 0xc0, - 0x53, 0x47, 0xd2, 0x4b, 0x10, 0x63, 0xe8, 0x8f, 0xb5, 0x58, 0x9f, 0xd8, - 0x69, 0x86, 0x31, 0xbc, 0x9f, 0x39, 0xf5, 0x88, 0xb3, 0xae, 0xcb, 0x25, - 0x50, 0xc0, 0x47, 0x7c, 0xde, 0x68, 0xdc, 0x5c, 0xb6, 0x68, 0xef, 0x17, - 0xe3, 0xf1, 0xd9, 0x41, 0xb1, 0x8a, 0xde, 0x31, 0x74, 0x82, 0xa9, 0x14, - 0x4b, 0x12, 0x7d, 0x7a, 0xbc, 0x2a, 0x8e, 0x6c, 0xf6, 0xfc, 0xeb, 0xda, - 0xe3, 0x55, 0x11, 0x77, 0x98, 0x71, 0xe6, 0xa7, 0x0d, 0x9a, 0x10, 0x47, - 0xe9, 0xde, 0x38, 0x71, 0x68, 0xe6, 0xbc, 0x8a, 0xec, 0xdd, 0xac, 0x53, - 0xdf, 0x20, 0x13, 0x55, 0x59, 0x70, 0xf1, 0xd5, 0x38, 0xc0, 0x4b, 0x46, - 0x3b, 0xe4, 0x82, 0x56, 0x27, 0x36, 0xaf, 0x4e, 0x80, 0x4d, 0xc4, 0xbc, - 0x21, 0x4c, 0x20, 0xc8, 0x4e, 0x87, 0x7d, 0x6c, 0x6f, 0xa2, 0x7b, 0x61, - 0xf1, 0x0b, 0xdc, 0xaa, 0x0c, 0xbb, 0x95, 0xdd, 0xe0, 0x1b, 0x92, 0x29, - 0x96, 0xf8, 0xf3, 0x5e, 0x47, 0x5b, 0x88, 0xe3, 0x8e, 0xb0, 0x4b, 0x89, - 0xaf, 0x73, 0x55, 0x08, 0x7d, 0xcc, 0xdf, 0x84, 0x7e, 0xaf, 0xba, 0x7c, - 0xdd, 0x6e, 0x5c, 0xc7, 0xd8, 0x2b, 0x25, 0x35, 0xdb, 0x2e, 0x53, 0x90, - 0xd1, 0x46, 0x20, 0x77, 0x5a, 0x39, 0xed, 0x5f, 0xcd, 0xee, 0x12, 0xe4, - 0x12, 0xdf, 0xaa, 0xa3, 0x18, 0x82, 0x69, 0x31, 0xc6, 0x0c, 0x7b, 0xa4, - 0x5b, 0x11, 0x9a, 0xd5, 0x0e, 0x21, 0x7d, 0x68, 0xc0, 0x5b, 0x2a, 0xb4, - 0xb5, 0x89, 0x18, 0x7d, 0x01, 0x27, 0xa7, 0x2e, 0x60, 0x0a, 0xc4, 0x58, - 0xca, 0x8e, 0x26, 0x03, -}; - -static const unsigned char TA_RSA_E0[] = { - 0x01, 0x00, 0x01, -}; - -static const br_x509_trust_anchor TAs[] = { - { - { (unsigned char *)TA_DN0, sizeof TA_DN0 }, - BR_X509_TA_CA, - { - BR_KEYTYPE_RSA, - { .rsa = { - (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, - (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, - } } - } - }, -}; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ifndef _CERTIFICATES_H_ */ From 8cbf028b986429e78595b5289bb3f7c50ce1a3cb Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 9 Mar 2020 10:12:01 -0700 Subject: [PATCH 121/205] restructure examples, validate stm32 (don't have hardware to test, so I can hope). Address https://github.com/OPEnSLab-OSU/SSLClient/issues/3. --- .../EthernetHTTPSstm32/EthernetHTTPSstm32.ino | 130 ++++++++++++++++++ .../stm32/EthernetHTTPSstm32/trust_anchors.h | 80 +++++++++++ .../EthernetHTTPStivac/EthernetHTTPStivac.ino | 32 +---- .../EthernetHTTPStivac/trust_anchors.h | 0 library.properties | 4 +- 5 files changed, 215 insertions(+), 31 deletions(-) create mode 100644 examples/stm32/EthernetHTTPSstm32/EthernetHTTPSstm32.ino create mode 100644 examples/stm32/EthernetHTTPSstm32/trust_anchors.h rename examples/{ => tivac}/EthernetHTTPStivac/EthernetHTTPStivac.ino (78%) rename examples/{ => tivac}/EthernetHTTPStivac/trust_anchors.h (100%) diff --git a/examples/stm32/EthernetHTTPSstm32/EthernetHTTPSstm32.ino b/examples/stm32/EthernetHTTPSstm32/EthernetHTTPSstm32.ino new file mode 100644 index 0000000..e685813 --- /dev/null +++ b/examples/stm32/EthernetHTTPSstm32/EthernetHTTPSstm32.ino @@ -0,0 +1,130 @@ +/* + Web client + + This sketch connects to a website (http://www.arduino.cc/asciilogo.txt) + using an Arduino Wiznet Ethernet shield or STM32 built-in Ethernet. + Tested on ST Micro Nucleo-F767ZI. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Noah Koontz, based on work by Adrian McEwen and Tom Igoe + + Modified 16 Oct 2019 by gdsports625@gmail.com for STM32duino_STM32Ethernet + */ + +#include +#include +#include +#include "trust_anchors.h" + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(54,85,55,79); // numeric IP for Google (no DNS) +const char server[] = "www.arduino.cc"; // name address for Arduino (using DNS) +const char server_host[] = "www.arduino.cc"; // leave this alone, change only above two + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 177); +IPAddress myDns(8, 8, 8, 8); + +// Choose the analog pin to get semi-random data from for SSL +// Pick a pin that's not connected or attached to a randomish voltage source +const int rand_pin = A5; + +// Initialize the SSL client library +// We input an EthernetClient, our trust anchors, and the analog pin +EthernetClient base_client; +SSLClient client(base_client, TAs, (size_t)TAs_NUM, rand_pin); +// Variables to measure the speed +unsigned long beginMicros, endMicros; +unsigned long byteCount = 0; +bool printWebData = true; // set to false for better speed measurement + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + // STM32 built-in Ethernet has a factory installed MAC address. + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + while (1) delay(1); + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + // give the Ethernet shield a second to initialize: + delay(2000); + + Serial.print("connecting to "); + Serial.print(server); + Serial.println("..."); + + // if you get a connection, report back via serial: + auto start = millis(); + // specify the server and port, 443 is the standard port for HTTPS + if (client.connect(server, 443)) { + auto time = millis() - start; + Serial.print("connected to "); + Serial.println(base_client.remoteIP()); + Serial.print("Took: "); + Serial.println(time); + // Make a HTTP request: + client.println("GET /asciilogo.txt HTTP/1.1"); + client.println("User-Agent: SSLClientOverEthernet"); + client.print("Host: "); + client.println(server_host); + client.println("Connection: close"); + client.println(); + } else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } + beginMicros = micros(); +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + int len = client.available(); + if (len > 0) { + byte buffer[80]; + if (len > 80) len = 80; + client.read(buffer, len); + if (printWebData) { + Serial.write(buffer, len); // show in the serial monitor (slows some boards) + } + byteCount = byteCount + len; + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + endMicros = micros(); + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + Serial.print("Received "); + Serial.print(byteCount); + Serial.print(" bytes in "); + float seconds = (float)(endMicros - beginMicros) / 1000000.0; + Serial.print(seconds, 4); + float rate = (float)byteCount / seconds / 1000.0; + Serial.print(", rate = "); + Serial.print(rate); + Serial.print(" kbytes/second"); + Serial.println(); + + // do nothing forevermore: + while (true) { + delay(1); + } + } +} \ No newline at end of file diff --git a/examples/stm32/EthernetHTTPSstm32/trust_anchors.h b/examples/stm32/EthernetHTTPSstm32/trust_anchors.h new file mode 100644 index 0000000..0ecbe4b --- /dev/null +++ b/examples/stm32/EthernetHTTPSstm32/trust_anchors.h @@ -0,0 +1,80 @@ +#ifndef _CERTIFICATES_H_ +#define _CERTIFICATES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. + * Certificates are BearSSL br_x509_trust_anchor format. Included certs: + * + * Index: 0 + * Label: AddTrust External CA Root + * Subject: C=SE,O=AddTrust AB,OU=AddTrust External TTP Network,CN=AddTrust External CA Root + * Domain(s): www.arduino.cc + */ + +#define TAs_NUM 1 + +static const unsigned char TA_DN0[] = { + 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, + 0x42, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, + 0x20, 0x52, 0x6f, 0x6f, 0x74, +}; + +static const unsigned char TA_RSA_N0[] = { + 0xb7, 0xf7, 0x1a, 0x33, 0xe6, 0xf2, 0x00, 0x04, 0x2d, 0x39, 0xe0, 0x4e, + 0x5b, 0xed, 0x1f, 0xbc, 0x6c, 0x0f, 0xcd, 0xb5, 0xfa, 0x23, 0xb6, 0xce, + 0xde, 0x9b, 0x11, 0x33, 0x97, 0xa4, 0x29, 0x4c, 0x7d, 0x93, 0x9f, 0xbd, + 0x4a, 0xbc, 0x93, 0xed, 0x03, 0x1a, 0xe3, 0x8f, 0xcf, 0xe5, 0x6d, 0x50, + 0x5a, 0xd6, 0x97, 0x29, 0x94, 0x5a, 0x80, 0xb0, 0x49, 0x7a, 0xdb, 0x2e, + 0x95, 0xfd, 0xb8, 0xca, 0xbf, 0x37, 0x38, 0x2d, 0x1e, 0x3e, 0x91, 0x41, + 0xad, 0x70, 0x56, 0xc7, 0xf0, 0x4f, 0x3f, 0xe8, 0x32, 0x9e, 0x74, 0xca, + 0xc8, 0x90, 0x54, 0xe9, 0xc6, 0x5f, 0x0f, 0x78, 0x9d, 0x9a, 0x40, 0x3c, + 0x0e, 0xac, 0x61, 0xaa, 0x5e, 0x14, 0x8f, 0x9e, 0x87, 0xa1, 0x6a, 0x50, + 0xdc, 0xd7, 0x9a, 0x4e, 0xaf, 0x05, 0xb3, 0xa6, 0x71, 0x94, 0x9c, 0x71, + 0xb3, 0x50, 0x60, 0x0a, 0xc7, 0x13, 0x9d, 0x38, 0x07, 0x86, 0x02, 0xa8, + 0xe9, 0xa8, 0x69, 0x26, 0x18, 0x90, 0xab, 0x4c, 0xb0, 0x4f, 0x23, 0xab, + 0x3a, 0x4f, 0x84, 0xd8, 0xdf, 0xce, 0x9f, 0xe1, 0x69, 0x6f, 0xbb, 0xd7, + 0x42, 0xd7, 0x6b, 0x44, 0xe4, 0xc7, 0xad, 0xee, 0x6d, 0x41, 0x5f, 0x72, + 0x5a, 0x71, 0x08, 0x37, 0xb3, 0x79, 0x65, 0xa4, 0x59, 0xa0, 0x94, 0x37, + 0xf7, 0x00, 0x2f, 0x0d, 0xc2, 0x92, 0x72, 0xda, 0xd0, 0x38, 0x72, 0xdb, + 0x14, 0xa8, 0x45, 0xc4, 0x5d, 0x2a, 0x7d, 0xb7, 0xb4, 0xd6, 0xc4, 0xee, + 0xac, 0xcd, 0x13, 0x44, 0xb7, 0xc9, 0x2b, 0xdd, 0x43, 0x00, 0x25, 0xfa, + 0x61, 0xb9, 0x69, 0x6a, 0x58, 0x23, 0x11, 0xb7, 0xa7, 0x33, 0x8f, 0x56, + 0x75, 0x59, 0xf5, 0xcd, 0x29, 0xd7, 0x46, 0xb7, 0x0a, 0x2b, 0x65, 0xb6, + 0xd3, 0x42, 0x6f, 0x15, 0xb2, 0xb8, 0x7b, 0xfb, 0xef, 0xe9, 0x5d, 0x53, + 0xd5, 0x34, 0x5a, 0x27, +}; + +static const unsigned char TA_RSA_E0[] = { + 0x01, 0x00, 0x01, +}; + +static const br_x509_trust_anchor TAs[] = { + { + { (unsigned char *)TA_DN0, sizeof TA_DN0 }, + BR_X509_TA_CA, + { + BR_KEYTYPE_RSA, + { .rsa = { + (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, + (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, + } } + } + }, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef _CERTIFICATES_H_ */ \ No newline at end of file diff --git a/examples/EthernetHTTPStivac/EthernetHTTPStivac.ino b/examples/tivac/EthernetHTTPStivac/EthernetHTTPStivac.ino similarity index 78% rename from examples/EthernetHTTPStivac/EthernetHTTPStivac.ino rename to examples/tivac/EthernetHTTPStivac/EthernetHTTPStivac.ino index b1f52da..62b2a5d 100644 --- a/examples/EthernetHTTPStivac/EthernetHTTPStivac.ino +++ b/examples/tivac/EthernetHTTPStivac/EthernetHTTPStivac.ino @@ -2,24 +2,19 @@ Web client This sketch connects to a website (http://www.arduino.cc/asciilogo.txt) - using an Arduino Wiznet Ethernet shield. + using an Arduino Wiznet Ethernet shield and TLS. This Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 created 18 Dec 2009 by David A. Mellis - modified 9 Apr 2012 + modified 9 March 2020 by Noah Koontz, based on work by Adrian McEwen and Tom Igoe - */ - // NOTE: This example REQUIRES the EthernetLarge library. - // You can get it here: https://github.com/OPEnSLab-OSU/EthernetLarge - #include -//#include -#include "Ethernet.h" +#include #include #include "trust_anchors.h" @@ -56,14 +51,6 @@ unsigned long byteCount = 0; bool printWebData = true; // set to false for better speed measurement void setup() { - // You can use Ethernet.init(pin) to configure the CS pin - //Ethernet.init(10); // Most Arduino shields - //Ethernet.init(5); // MKR ETH shield - //Ethernet.init(0); // Teensy 2.0 - //Ethernet.init(20); // Teensy++ 2.0 - //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet - //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet - // Open serial communications and wait for port to open: Serial.begin(115200); while (!Serial) { @@ -75,18 +62,6 @@ void setup() { //if (Ethernet.begin(mac) == 0) { if (Ethernet.begin(0) == 0) { Serial.println(F("Failed to configure Ethernet using DHCP")); - // Check for Ethernet hardware present -/* if (Ethernet.hardwareStatus() == EthernetNoHardware) { - Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); - while (true) { - delay(1); // do nothing, no point running without Ethernet hardware - } - }*/ -/* if (Ethernet.linkStatus() == LinkOFF) { - Serial.println("Ethernet cable is not connected."); - }*/ - // try to configure using IP address instead of DHCP: - //Ethernet.begin(mac, ip, myDns); Ethernet.begin(0, ip, myDns, gw, mask); } else { Serial.print(F(" DHCP assigned IP ")); @@ -125,7 +100,6 @@ void loop() { // from the server, read them and print them: int len = client.available(); while (len > 0) { - //if (len > 0) { byte buffer[BUFFLEN]; if (len > BUFFLEN) len = BUFFLEN; client.read(buffer, len); diff --git a/examples/EthernetHTTPStivac/trust_anchors.h b/examples/tivac/EthernetHTTPStivac/trust_anchors.h similarity index 100% rename from examples/EthernetHTTPStivac/trust_anchors.h rename to examples/tivac/EthernetHTTPStivac/trust_anchors.h diff --git a/library.properties b/library.properties index f8382d6..b924bc5 100644 --- a/library.properties +++ b/library.properties @@ -2,9 +2,9 @@ name=SSLClient version=1.5.0 author=Noah Koontz maintainer=OPEnS Lab -sentence=Arduino library to add SSL functionality to any Client class +sentence=Arduino library to add TLS functionality to any Client class paragraph=including the Arduino EthernetClient and WiFiClient classes (though it is better to prefer WiFClient.connectSSL if implemented). In other words, SSLClient implements encrypted communication through SSL on devices that do not otherwise support it. category=Communication url=https://github.com/OPEnSLab-OSU/SSLClient -architectures=samd,tivac +architectures=samd,tivac,stm32 includes=SSLClient.h From 79aa5b8fd95f8c2c60aa47424a0987f0de8492ea Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 9 Mar 2020 11:09:25 -0700 Subject: [PATCH 122/205] update travis to include esp32, stm32, removed precompiled releases for now --- .travis.yml | 56 +++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92f62d3..410af9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,47 +3,49 @@ env: global: # You can uncomment this to explicitly choose an (old) version of the Arduino IDE #- ARDUINO_IDE_VERSION="1.8.7" - - ADDITIONAL_URLS="https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" + - ADDITIONAL_URLS="https://adafruit.github.io/arduino-board-index/package_adafruit_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" cache: directories: - ~/arduino_ide - ~/.arduino15/packages/ + jobs: include: - - stage: "Feather M0" - env: BOARD_NAME="FeatherM0" ARCH="cortex-m0plus" CORE="adafruit:samd" BOARD="adafruit:samd:adafruit_feather_m0" - - stage: "Arduino Zero" - env: BOARD_NAME="ArduinoZero" ARCH="cortex-m0plus" CORE="arduino:samd" BOARD="arduino:samd:mzero_bl" + - stage: "Build" + name: "Feather M0" + env: CORE="adafruit:samd" BOARD="adafruit:samd:adafruit_feather_m0" + - name: "Arduino Zero" + env: CORE="arduino:samd" BOARD="arduino:samd:mzero_bl" + - name: "ESP32" + env: CORE="esp32:esp32" BOARD="esp32:esp32:d32" + - name: "STM32" + env: CORE="STM32:stm32" BOARD="STM32:stm32:Nucleo_144" + script: + - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/stm32/EthernetHTTPSstm32 + - stage: "Deploy" + if: branch = master AND tag is present + env: DEPLOY=1 + script: skip + deploy: + provider: releases + api_key: $GITHUB_TOKEN + file: "SSLClient.zip" + skip_cleanup: true -before_install: + +install: - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/bin sudo sh - arduino-cli core update-index --additional-urls $ADDITIONAL_URLS - arduino-cli core install arduino:samd -v - - arduino-cli core install adafruit:samd -v --additional-urls $ADDITIONAL_URLS + - arduino-cli core install $CORE -v --additional-urls $ADDITIONAL_URLS - mkdir -p $HOME/Arduino/libraries - rm -rf $HOME/Arduino/libraries/EthernetLarge - git clone https://github.com/OPEnSLab-OSU/EthernetLarge.git $HOME/Arduino/libraries/EthernetLarge -install: + - arduino-cli lib install "STM32duino STM32Ethernet" + - arduino-cli lib install "PubSubClient" - ln -s $PWD $HOME/Arduino/libraries/. - - echo "dot_a_linkage=true" >> library.properties + script: - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetHTTPS - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetMultiHTTPS -before_deploy: - - mkdir src/$ARCH - - cp "$(find /tmp/ -maxdepth 1 -type d -name "arduino-sketch*" -print | head -n 1)/libraries/SSLClient/SSLClient.a" src/$ARCH/ - - cp .travis/library.properties . - - rm -rf .git - - find src/ -iname "*.c" -delete - - find src/ -iname "*.cpp" -delete - - zip -r SSLClient-$BOARD_NAME.zip . -deploy: - provider: releases - api_key: $GITHUB_TOKEN - file: "SSLClient-$BOARD_NAME.zip" - skip_cleanup: true - draft: true - overwrite: true - on: - tags: true - branch: master + - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetMQTT \ No newline at end of file From b8144e4c2ebeeb843861040aa27cd08c62cd5ed3 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 9 Mar 2020 11:24:41 -0700 Subject: [PATCH 123/205] fix travis overflowing the log (impressive), and fix stm32 build --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 410af9c..78e0d99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,12 +19,11 @@ jobs: - name: "ESP32" env: CORE="esp32:esp32" BOARD="esp32:esp32:d32" - name: "STM32" - env: CORE="STM32:stm32" BOARD="STM32:stm32:Nucleo_144" + env: CORE="STM32:stm32" BOARD="STM32:stm32:Nucleo_144:pnum=NUCLEO_F767ZI" script: - - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/stm32/EthernetHTTPSstm32 + - arduino-cli compile --warnings all --fqbn $BOARD $PWD/examples/stm32/EthernetHTTPSstm32 - stage: "Deploy" if: branch = master AND tag is present - env: DEPLOY=1 script: skip deploy: provider: releases @@ -46,6 +45,6 @@ install: - ln -s $PWD $HOME/Arduino/libraries/. script: - - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetHTTPS - - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetMultiHTTPS - - arduino-cli compile --verbose --warnings all --fqbn $BOARD $PWD/examples/EthernetMQTT \ No newline at end of file + - arduino-cli compile --warnings all --fqbn $BOARD $PWD/examples/EthernetHTTPS + - arduino-cli compile --warnings all --fqbn $BOARD $PWD/examples/EthernetMultiHTTPS + - arduino-cli compile --warnings all --fqbn $BOARD $PWD/examples/EthernetMQTT \ No newline at end of file From 26c80b61d1777c057f5fe44447f4cac25eed6724 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 11 Mar 2020 12:40:48 -0700 Subject: [PATCH 124/205] Update travis to autogenerate documentation --- .travis.yml | 30 +- .travis/Doxyfile | 2572 ++++++++++++++++++++++++++++++++++++ .travis/library.properties | 12 - 3 files changed, 2601 insertions(+), 13 deletions(-) create mode 100644 .travis/Doxyfile delete mode 100644 .travis/library.properties diff --git a/.travis.yml b/.travis.yml index 78e0d99..3eb6cd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,28 @@ env: # You can uncomment this to explicitly choose an (old) version of the Arduino IDE #- ARDUINO_IDE_VERSION="1.8.7" - ADDITIONAL_URLS="https://adafruit.github.io/arduino-board-index/package_adafruit_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" + - DOXYFILE=$TRAVIS_BUILD_DIR/.travis/Doxyfile + cache: directories: - ~/arduino_ide - ~/.arduino15/packages/ +# Blacklist +branches: + except: + - gh-pages + +# Install dependencies +addons: + apt: + packages: + - doxygen + - doxygen-doc + - doxygen-latex + - doxygen-gui + - graphviz + jobs: include: - stage: "Build" @@ -22,6 +39,18 @@ jobs: env: CORE="STM32:stm32" BOARD="STM32:stm32:Nucleo_144:pnum=NUCLEO_F767ZI" script: - arduino-cli compile --warnings all --fqbn $BOARD $PWD/examples/stm32/EthernetHTTPSstm32 + + - stage: "Documentation" + if: branch = master + install: skip + script: + - doxygen $DOXYFILE + deploy: + provider: pages + skip_cleanup: true + local_dir: docs/html + github_token: $GITHUB_TOKEN + - stage: "Deploy" if: branch = master AND tag is present script: skip @@ -31,7 +60,6 @@ jobs: file: "SSLClient.zip" skip_cleanup: true - install: - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/bin sudo sh - arduino-cli core update-index --additional-urls $ADDITIONAL_URLS diff --git a/.travis/Doxyfile b/.travis/Doxyfile new file mode 100644 index 0000000..092d4f5 --- /dev/null +++ b/.travis/Doxyfile @@ -0,0 +1,2572 @@ +# Doxyfile 1.8.15 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = SSLClient + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = v1.6.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = */bearssl/** \ + */examples/** \ + */tools/** \ + */.travis/** \ + */docs/** \ + */config.h \ + */inner.h \ + bearssl* \ + */readme/** + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = . + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /
    From f95facc2545736df78a28e1abd00b6a1afb1de79 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 21 Mar 2021 20:11:50 -0700 Subject: [PATCH 199/205] docs: remove workaround to #9 from examples --- examples/EthernetAWSIoT/EthernetAWSIoT.ino | 2 -- examples/EthernetMQTT/EthernetMQTT.ino | 4 ---- 2 files changed, 6 deletions(-) diff --git a/examples/EthernetAWSIoT/EthernetAWSIoT.ino b/examples/EthernetAWSIoT/EthernetAWSIoT.ino index eabfce1..292bcbc 100644 --- a/examples/EthernetAWSIoT/EthernetAWSIoT.ino +++ b/examples/EthernetAWSIoT/EthernetAWSIoT.ino @@ -93,7 +93,6 @@ void reconnect() { // Serial.println(subscribeTopic[i]); mqtt.subscribe(subscribeTopic[i]); - ethClientSSL.flush(); } Serial.println("Started updateThing "); updateThing(); @@ -161,7 +160,6 @@ void updateThing() void MQTTPublish(const char *topic, char *payload) { mqtt.publish(topic, payload); - ethClientSSL.flush(); Serial.print("Published ["); Serial.print(topic); Serial.print("] "); diff --git a/examples/EthernetMQTT/EthernetMQTT.ino b/examples/EthernetMQTT/EthernetMQTT.ino index 1cb8a4b..5eab3fe 100644 --- a/examples/EthernetMQTT/EthernetMQTT.ino +++ b/examples/EthernetMQTT/EthernetMQTT.ino @@ -51,12 +51,8 @@ void reconnect() { Serial.println("connected"); // Once connected, publish an announcement... client.publish("outTopic","hello world"); - // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9 - ethClientSSL.flush(); // ... and resubscribe client.subscribe("inTopic"); - // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9 - ethClientSSL.flush(); } else { Serial.print("failed, rc="); Serial.print(client.state()); From 978d6020d446107a182d135d4c58570622933266 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Sun, 21 Mar 2021 20:12:30 -0700 Subject: [PATCH 200/205] chore: bump version --- Doxyfile | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index f884f06..03531a3 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = SSLClient # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = v1.6.10 +PROJECT_NUMBER = v1.6.11 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/library.properties b/library.properties index 70532f6..0676eba 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SSLClient -version=1.6.10 +version=1.6.11 author=Noah Koontz maintainer=OPEnS Lab sentence=Arduino library to add TLS functionality to any Client class From f5b385bfb52abdef8530d25608ca42fdaf32b685 Mon Sep 17 00:00:00 2001 From: prototypicalpro Date: Mon, 22 Mar 2021 03:13:12 +0000 Subject: [PATCH 201/205] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20=20@?= =?UTF-8?q?=20978d6020d446107a182d135d4c58570622933266=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _c_o_d_e___o_f___c_o_n_d_u_c_t_8md.html | 2 +- _c_o_n_t_r_i_b_u_t_i_n_g_8md.html | 2 +- _r_e_a_d_m_e_8md.html | 2 +- _s_s_l_client_8cpp.html | 2 +- _s_s_l_client_8h.html | 2 +- _s_s_l_client_8h_source.html | 2 +- _s_s_l_client_parameters_8cpp.html | 2 +- _s_s_l_client_parameters_8h.html | 2 +- _s_s_l_client_parameters_8h_source.html | 2 +- _s_s_l_session_8h.html | 2 +- _s_s_l_session_8h_source.html | 2 +- _trust_anchors_8md.html | 2 +- annotated.html | 2 +- class_s_s_l_client-members.html | 2 +- class_s_s_l_client.html | 2 +- class_s_s_l_client_parameters-members.html | 2 +- class_s_s_l_client_parameters.html | 2 +- class_s_s_l_session-members.html | 2 +- class_s_s_l_session.html | 2 +- classes.html | 2 +- dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- files.html | 2 +- functions.html | 2 +- functions_enum.html | 2 +- functions_eval.html | 2 +- functions_func.html | 2 +- functions_vars.html | 2 +- globals.html | 2 +- globals_defs.html | 2 +- hierarchy.html | 2 +- index.html | 2 +- md__c_o_d_e__o_f__c_o_n_d_u_c_t.html | 2 +- md__c_o_n_t_r_i_b_u_t_i_n_g.html | 2 +- md__trust_anchors.html | 2 +- namespacemembers.html | 2 +- namespacemembers_func.html | 2 +- namespaces.html | 2 +- namespacestd.html | 2 +- pages.html | 2 +- structssl__pem__decode__state-members.html | 2 +- structssl__pem__decode__state.html | 2 +- time__macros_8h.html | 2 +- time__macros_8h_source.html | 2 +- 43 files changed, 43 insertions(+), 43 deletions(-) diff --git a/_c_o_d_e___o_f___c_o_n_d_u_c_t_8md.html b/_c_o_d_e___o_f___c_o_n_d_u_c_t_8md.html index f7e7af5..5dbdfb4 100644 --- a/_c_o_d_e___o_f___c_o_n_d_u_c_t_8md.html +++ b/_c_o_d_e___o_f___c_o_n_d_u_c_t_8md.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_c_o_n_t_r_i_b_u_t_i_n_g_8md.html b/_c_o_n_t_r_i_b_u_t_i_n_g_8md.html index e39a2de..5857a55 100644 --- a/_c_o_n_t_r_i_b_u_t_i_n_g_8md.html +++ b/_c_o_n_t_r_i_b_u_t_i_n_g_8md.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_r_e_a_d_m_e_8md.html b/_r_e_a_d_m_e_8md.html index 7263763..92191d5 100644 --- a/_r_e_a_d_m_e_8md.html +++ b/_r_e_a_d_m_e_8md.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_client_8cpp.html b/_s_s_l_client_8cpp.html index 62c77b0..6e74f78 100644 --- a/_s_s_l_client_8cpp.html +++ b/_s_s_l_client_8cpp.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_client_8h.html b/_s_s_l_client_8h.html index cab7cff..1aa7f76 100644 --- a/_s_s_l_client_8h.html +++ b/_s_s_l_client_8h.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_client_8h_source.html b/_s_s_l_client_8h_source.html index 8b86a35..f131198 100644 --- a/_s_s_l_client_8h_source.html +++ b/_s_s_l_client_8h_source.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_client_parameters_8cpp.html b/_s_s_l_client_parameters_8cpp.html index 021285f..1d70404 100644 --- a/_s_s_l_client_parameters_8cpp.html +++ b/_s_s_l_client_parameters_8cpp.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_client_parameters_8h.html b/_s_s_l_client_parameters_8h.html index aa90ac8..5f0e1b0 100644 --- a/_s_s_l_client_parameters_8h.html +++ b/_s_s_l_client_parameters_8h.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_client_parameters_8h_source.html b/_s_s_l_client_parameters_8h_source.html index e6e148d..6ea3222 100644 --- a/_s_s_l_client_parameters_8h_source.html +++ b/_s_s_l_client_parameters_8h_source.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_session_8h.html b/_s_s_l_session_8h.html index 389080e..5618ee9 100644 --- a/_s_s_l_session_8h.html +++ b/_s_s_l_session_8h.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_s_s_l_session_8h_source.html b/_s_s_l_session_8h_source.html index 27133ae..fd5c90d 100644 --- a/_s_s_l_session_8h_source.html +++ b/_s_s_l_session_8h_source.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/_trust_anchors_8md.html b/_trust_anchors_8md.html index 8c6e846..caa7994 100644 --- a/_trust_anchors_8md.html +++ b/_trust_anchors_8md.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/annotated.html b/annotated.html index f24001a..fe0e97e 100644 --- a/annotated.html +++ b/annotated.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/class_s_s_l_client-members.html b/class_s_s_l_client-members.html index b5dcba2..6c4bb90 100644 --- a/class_s_s_l_client-members.html +++ b/class_s_s_l_client-members.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/class_s_s_l_client.html b/class_s_s_l_client.html index df711d4..00b2e11 100644 --- a/class_s_s_l_client.html +++ b/class_s_s_l_client.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/class_s_s_l_client_parameters-members.html b/class_s_s_l_client_parameters-members.html index 1341822..fa4effd 100644 --- a/class_s_s_l_client_parameters-members.html +++ b/class_s_s_l_client_parameters-members.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/class_s_s_l_client_parameters.html b/class_s_s_l_client_parameters.html index 16d0fb9..536dfaa 100644 --- a/class_s_s_l_client_parameters.html +++ b/class_s_s_l_client_parameters.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/class_s_s_l_session-members.html b/class_s_s_l_session-members.html index 1203c50..e4c4c19 100644 --- a/class_s_s_l_session-members.html +++ b/class_s_s_l_session-members.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/class_s_s_l_session.html b/class_s_s_l_session.html index c94d2fe..a449442 100644 --- a/class_s_s_l_session.html +++ b/class_s_s_l_session.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/classes.html b/classes.html index c4bde63..b746ae0 100644 --- a/classes.html +++ b/classes.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/dir_68267d1309a1af8e8297ef4c3efbcdba.html index 7947146..891cef6 100644 --- a/dir_68267d1309a1af8e8297ef4c3efbcdba.html +++ b/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/files.html b/files.html index 784d05b..6e73ed6 100644 --- a/files.html +++ b/files.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/functions.html b/functions.html index df33449..81099e2 100644 --- a/functions.html +++ b/functions.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/functions_enum.html b/functions_enum.html index 9f7e1e1..1eaec11 100644 --- a/functions_enum.html +++ b/functions_enum.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/functions_eval.html b/functions_eval.html index 92d44ea..66ecc0a 100644 --- a/functions_eval.html +++ b/functions_eval.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/functions_func.html b/functions_func.html index da39762..7717232 100644 --- a/functions_func.html +++ b/functions_func.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/functions_vars.html b/functions_vars.html index 63318b0..5d279d7 100644 --- a/functions_vars.html +++ b/functions_vars.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/globals.html b/globals.html index 2a2b78e..4d871f7 100644 --- a/globals.html +++ b/globals.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/globals_defs.html b/globals_defs.html index 0fa1c55..79a9ae6 100644 --- a/globals_defs.html +++ b/globals_defs.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/hierarchy.html b/hierarchy.html index 4eefbcd..4556519 100644 --- a/hierarchy.html +++ b/hierarchy.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/index.html b/index.html index 7244672..1e9db8c 100644 --- a/index.html +++ b/index.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/md__c_o_d_e__o_f__c_o_n_d_u_c_t.html b/md__c_o_d_e__o_f__c_o_n_d_u_c_t.html index ae97100..ce313dc 100644 --- a/md__c_o_d_e__o_f__c_o_n_d_u_c_t.html +++ b/md__c_o_d_e__o_f__c_o_n_d_u_c_t.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/md__c_o_n_t_r_i_b_u_t_i_n_g.html b/md__c_o_n_t_r_i_b_u_t_i_n_g.html index 9911a06..d7aadd6 100644 --- a/md__c_o_n_t_r_i_b_u_t_i_n_g.html +++ b/md__c_o_n_t_r_i_b_u_t_i_n_g.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/md__trust_anchors.html b/md__trust_anchors.html index d9b5621..111cf9a 100644 --- a/md__trust_anchors.html +++ b/md__trust_anchors.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/namespacemembers.html b/namespacemembers.html index 6ba906d..672fa2a 100644 --- a/namespacemembers.html +++ b/namespacemembers.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/namespacemembers_func.html b/namespacemembers_func.html index bf68995..302310a 100644 --- a/namespacemembers_func.html +++ b/namespacemembers_func.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/namespaces.html b/namespaces.html index 5d473ff..73ea986 100644 --- a/namespaces.html +++ b/namespaces.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/namespacestd.html b/namespacestd.html index 83bcfc7..a3fc29f 100644 --- a/namespacestd.html +++ b/namespacestd.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/pages.html b/pages.html index eb9564f..c67d10a 100644 --- a/pages.html +++ b/pages.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/structssl__pem__decode__state-members.html b/structssl__pem__decode__state-members.html index c4df943..404c9c8 100644 --- a/structssl__pem__decode__state-members.html +++ b/structssl__pem__decode__state-members.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/structssl__pem__decode__state.html b/structssl__pem__decode__state.html index f42e6fd..5169ccb 100644 --- a/structssl__pem__decode__state.html +++ b/structssl__pem__decode__state.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/time__macros_8h.html b/time__macros_8h.html index 1de53af..0a9468d 100644 --- a/time__macros_8h.html +++ b/time__macros_8h.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    diff --git a/time__macros_8h_source.html b/time__macros_8h_source.html index 33f9b7e..1ed12e7 100644 --- a/time__macros_8h_source.html +++ b/time__macros_8h_source.html @@ -26,7 +26,7 @@
    SSLClient -  v1.6.10 +  v1.6.11
    From 3f4434043194de2b88c89fc2b7b1bfc79513af5e Mon Sep 17 00:00:00 2001 From: prototypicalpro Date: Mon, 22 Mar 2021 17:58:18 +0000 Subject: [PATCH 202/205] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20=20@?= =?UTF-8?q?=20a2708d0b54d0bcb8877ca05e83f872ad26ab651e=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 88 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/index.html b/index.html index 1e9db8c..20db02f 100644 --- a/index.html +++ b/index.html @@ -88,12 +88,12 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });

    CI

    SSLClient adds TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes. SSLClient was created to integrate TLS seamlessly with the Arduino infrastructure using BearSSL as an underlying TLS engine. Unlike ArduinoBearSSL, SSLClient is completly self-contained, and does not require any additional hardware (other than a network connection).

    -

    SSLClient officially supports SAMD21, SAM3X, ESP32, TIVA C, STM32F7, and Teensy >= 3.0; but it should work on any board with at least 110kb flash and 7kb RAM. SSClient does not currently support ESP8266 (see this issue) or AVR due to memory constraints on both platforms.

    +

    SSLClient officially supports SAMD21, SAM3X, ESP32, TIVA C, STM32F7, and Teensy >= 3.0; but it should work on any board with at least 110kB flash and 7kB RAM. SSClient does not currently support ESP8266 (see this issue) or AVR due to memory constraints on both platforms.

    You can also view this README in doxygen.

    Overview

    Using SSLClient is similar to using any other Arduino-based Client class, as this library was developed around compatibility with EthernetClient. There are a few extra things, however, that you will need to get started:

      -
    1. Board and Network Peripheral - Your board should have a lot of resources (>110kb flash and >7kb RAM), and your network peripheral should have a large internal buffer (>7kb). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Gotchas).
    2. +
    3. Board and Network Peripheral - Your board should have a lot of resources (>110kB flash and >7kB RAM), and your network peripheral should have a large internal buffer (>7kB). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kB Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Gotchas).
    4. Trust Anchors - You will need a header containing array of trust anchors (example), which are used to verify the SSL connection later on. This file must generated for every project. Check out TrustAnchors.md on how to generate this file for your project, and for more information about what a trust anchor is.
    5. Network Peripheral Driver Implementing Client - Examples include EthernetClient, WiFiClient, and so on—SSLClient will run on top of any network driver exposing the Client interface.
    6. Analog Pin - Used for generating random data at the start of the connection (see the Implementation Gotchas).
    7. @@ -150,7 +150,7 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });
      // wait for response
      while (!client.available()) { /* ... */ }
      // ...
      -

    Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

    +

    Notice that every single client.write() call immediately writes to the network. This behavior is fine for most network clients; with SSL, however, it results in many small encryption tasks that consume resources. To reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

    {C++}
    EthernetClient baseClient;
    SSLClient client(baseClient, TAs, (size_t)2, A7);
    @@ -167,15 +167,17 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });
    // ...

    If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

    Session Caching

    -

    As detailed in the resources section, SSL handshakes take an extended period (1-4sec) to negotiate. To remedy this problem, BearSSL is able to keep a SSL session cache of the clients it has connected to. If BearSSL successfully resumes an SSL session, it can reduce connection time to 100-500ms.

    +

    As detailed in the resources section, SSL handshakes take an extended period (1-4sec) to negotiate. BearSSL is able to keep a SSL session cache of the clients it has connected to which can drastically reduce this time: if BearSSL successfully resumes an SSL session, connection time is typically 100-500ms.

    In order to use SSL session resumption:

      -
    • The website you are connecting to must support it. Support is widespread, but you can verify easily using the SSLLabs tool.
    • +
    • The website you are connecting to must support it. Support is widespread, and you can verify it using SSLLabs.
    • You must reuse the same SSLClient object (SSL Sessions are stored in the object itself).
    • -
    • You must reconnect to the exact same server.
    • +
    • You must reconnect to the exact same server (detailed below).
    -

    SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call connect("www.google.com") SSLClient will use the SSL session with that hostname. However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection.

    -

    You can test whether or not a website can resume SSL Sessions using the Session Example included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume.

    -

    SSL sessions take a lot of memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration:

    {C++}
    +
    +

    NOTE: SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call connect("www.google.com") SSLClient will use the same SSL session for that hostname. Unfortunately some websites have multiple servers on a single IP address (github.com being an example), so you may find that even if you are connecting to the same host the connection will not resume. This is a flaw in the SSL session protocol—though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being resolved here.

    +

    SSL sessions can also expire based on server criteria (ex. timeout), which will result in a standard 4-10 second connection.

    +
    +

    SSL sessions take memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration:

    {C++}
    EthernetClient baseClient;
    SSLClient client(baseClient, TAs, (size_t)2, A7, SomeNumber);

    Where SomeNumber is the number of sessions you would like to store. For example this declaration can store 3 sessions:

    {C++}
    @@ -184,7 +186,7 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });

    Sessions are managed internally using the SSLSession::getSession function. This function will cycle through sessions in a rotating order, allowing the session cache to continually overwrite old sessions. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

    If you need to clear a session, you can do so using the SSLSession::removeSession function.

    mTLS

    -

    As of v1.6.0, SSLClient supports mutual TLS authentication. mTLS is a varient of TLS that verifys both the server and device identities before a connection, and is commonly used in IoT protocols as a secure layer (MQTT over TLS, HTTPS over TLS, etc.).

    +

    As of v1.6.0, SSLClient supports mutual TLS authentication. mTLS is a varient of TLS that verifies both the server and device identities before a connection, and is commonly used in IoT protocols as a secure layer (MQTT over TLS, HTTP over TLS, etc.).

    To use mTLS with SSLClient you will need to a client certificate and client private key associated with the server you are attempting to connect to. Depending on your use case, you will either generate these yourself (ex. Mosquito MQTT setup), or have them generated for you (ex. AWS IoT Certificate Generation). Given this cryptographic information, you can modify the standard SSLClient connection sketch to enable mTLS authentication:

    {C++}
    ...
    /* Somewhere above setup() */
    @@ -226,7 +228,7 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });

    Implementation Gotchas

    Some ideas that didn't quite fit in the API documentation.

    SSLClient with Ethernet

    -

    If you are using the Arduino Ethernet library, you will need to modify the library to support the large buffer sizes required by SSL (detailed in resources). You can either modify the library yourself, or use this fork of the Ethernet library with the modification. To use the fork, simply install the library using the "add a .zip library" button in Arduino, and replace #include "Ethernet.h" with #include "EthernetLarge.h" in your sketch. Alternatively if for some reason this solution does not work, you can apply the modification using the instructions below.

    +

    If you are using the Arduino Ethernet library you will need to modify the library to support the large buffer sizes required by SSL (detailed in resources). You can either modify the library yourself, or use this fork of the Ethernet library with the modification. To use the fork: download a zipped copy of the fork through GiThub, use the "add a .zip library" button in Arduino to install the library, and replace #include "Ethernet.h" with #include "EthernetLarge.h" in your sketch. Alternatively if for some reason this solution does not work, you can apply the modification manually using the instructions below.

    Manual Modification

    First find the location of the library in the directory where Arduino is installed (C:\Program Files (x86)\Arduino on Windows). Inside of this directory, navigate to libraries\Ethernet\src (C:\Program Files (x86)\Arduino\libraries\Ethernet\src on Windows). Modify Ethernet.h to replace these lines:

    {C++}
    ...
    @@ -273,19 +275,52 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });

    Time

    The minimal x509 verification engine requires an accurate source of time to properly verify the creation and expiration dates of a certificate. As most embedded devices do not have a reliable source of time, by default SSLClient opts to use the compilation timestamp (__DATE__ and __TIME__) as the "current time" during the verification process. While this approach reduces the complexity of using SSLClient, it is inherently insecure, and can cause errors if certificates are redeployed (see #27): to accommodate these edge cases, SSLClient::setVerificationTime can be used to update the timestamp before connecting, resolving the above issues.

    Resources

    -

    The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive.

    -

    To illustrate this, I will run some tests on various domains below. I haven't yet, but I will.

    -

    If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from SSLClient.h, SSLClientImpl.h, and SSLClientImpl.cpp. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself.

    +

    The SSL/TLS protocol recommends a device support many different encryption and handshake algorithms. The complexity of these components results in many medium-footprint algorithms forming an extremely large whole. Compilation size of the EthernetHTTPS example in SSLClient v1.6.11 for various boards is shown below:

    + + + + + + + + + + + + + + + + + + + + + +
    Board Size
    Arduino Zero
    `RAM:   [===       ]  33.7% (used 11052 bytes from 32768 bytes)`
    +`Flash: [=== ] 34.7% (used 90988 bytes from 262144 bytes)`
    Arduino Due
    `RAM:   [=         ]  11.7% (used 11548 bytes from 98304 bytes)`
    +`Flash: [== ] 16.7% (used 87572 bytes from 524288 bytes)`
    Adafruit Feather M0
    `RAM:   [====      ]  40.4% (used 13240 bytes from 32768 bytes)`
    +`Flash: [==== ] 40.0% (used 104800 bytes from 262144 bytes)`
    ESP32 (Lolin32)
    `RAM:   [=         ]   6.9% (used 22476 bytes from 327680 bytes)`
    +`Flash: [== ] 24.0% (used 314956 bytes from 1310720 bytes)`
    Teensy 3.0
    `RAM:   [========  ]  78.2% (used 12812 bytes from 16384 bytes)`
    +`Flash: [======== ] 79.8% (used 104532 bytes from 131072 bytes)`
    Teensy 3.1
    `RAM:   [==        ]  19.9% (used 13020 bytes from 65536 bytes)`
    +`Flash: [==== ] 40.6% (used 106332 bytes from 262144 bytes)`
    Teensy 3.5
    `RAM:   [          ]   5.0% (used 12996 bytes from 262136 bytes)`
    +`Flash: [== ] 20.1% (used 105476 bytes from 524288 bytes)`
    Teensy 3.6
    `RAM:   [          ]   5.0% (used 13060 bytes from 262144 bytes)`
    +`Flash: [= ] 10.2% (used 106828 bytes from 1048576 bytes)`
    Teensy 4.0
    `RAM:   [===       ]  25.9% (used 135860 bytes from 524288 bytes)`
    +`Flash: [= ] 5.7% (used 115344 bytes from 2031616 bytes)`
    +

    In addition to the above, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, which results in slow and memory intensive execution of these algorithms. Because of this, it is recommended that SSLClient have 8kb of memory available on the stack during a connection, and 4-10 seconds should be allowed for the connection to complete. Note that this requirement is based on the SAMD21—more powerful processors (such as the ESP32) will see faster connection times.

    +
    +

    NOTE: If flash footprint is becoming a problem, there are numerous debugging strings (~3kB estimated) that can be removed from SSLClient.h, SSLClientImpl.h, and SSLClientImpl.cpp. Unfortunately I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself.

    +

    Read Buffer Overflow

    -

    SSL is a buffered protocol, and since most microcontrollers have limited resources (see Resources), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow, caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received, forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems, this could be the reason why.

    -

    In order to remedy this problem, the device must be able to read the data faster than it is being received, or alternatively have a cache large enough to store the entire payload. Since SSL's encryption forces the device to read slowly, this means we must increase the cache size. Depending on your platform, there are a number of ways this can be done:

      -
    • Sometimes your communication shield will have an internal buffer, which can be expanded through the driver code. This is the case with the Arduino Ethernet library (in the form of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be modified for the change to take effect.
    • -
    • SSLClient has an internal buffer SSLClient::m_iobuf, which can be expanded. BearSSL limits the amount of data that can be processed based on the stage in the SSL handshake, and so this will change will have limited usefulness.
    • -
    • In some cases, a website will send so much data that even with the above solutions, SSLClient will be unable to keep up (a website with a lot of HTML is an example). In these cases you will have to find another method of retrieving the data you need.
    • -
    • If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM.
    • +

      SSL is a buffered protocol, and since most microcontrollers have limited resources (see Resources), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received—forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems this could be the reason why.

      +

      In order to remedy this problem, the device must be able to read the data faster than it is being received or have a cache large enough to store the entire payload. Since the device is typically already reading as fast as it can, we must increase the cache size in order to resolve this issue. Depending on your platform there are a number of ways this can be done:

        +
      • Sometimes your communication shield will have an internal buffer which can be expanded through the driver code: this is the case with the Arduino Ethernet library (in the form of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros show here), but mileage may vary with other drivers.
      • +
      • SSLClient has an internal buffer SSLClient::m_iobuf which can be expanded. Unfortunately, BearSSL limits the amount of data that can be put into the buffer based on the stage in the SSL handshake, and so increasing the buffer will have limited usefulness.
      • +
      • In some cases, a website will send so much data that even with the above solutions SSLClient will be unable to keep up. In these cases you will have to find another method of retrieving the data you need.
      • +
      • If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This implementation would require in-depth knowledge of communication shield you are working with and a microcontroller with a significant amount of RAM, but would be the most robust solution available.

      Cipher Support

      -

      By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

      {C++}
      +

      By default, SSLClient supports only TLS1.2 and the ciphers listed in this file under suites[], and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher you can change the BearSSL profile being used by SSLClient to an alternate one with support for older protocols. To do this, edit SSLClientImpl::SSLClientImpl to change these lines:

      {C++}
      br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
      // comment the above line and uncomment the line below if you're having trouble connecting over SSL
      // br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);
      @@ -295,15 +330,14 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });
      br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num);

      If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the BearSSL profiles documentation and I wish you the best of luck.

      Security

      -

      Unlike BearSSL, SSLClient is not rigorously vetted to be secure. If your project has security requirements, I recommend you utilize BearSSL directly.

      +

      Unlike BearSSL, SSLClient is not rigorously vetted to be secure. If your project has security requirements I recommend you utilize BearSSL directly.

      Known Issues

      • In some drivers (Ethernet), calls to Client::flush will hang if internet is available but there is no route to the destination. Unfortunately SSLClient cannot correct for this without modifying the driver itself, and as a result the recommended solution is ensuring you choose a driver with built-in timeouts to prevent freezing. More information here.
      • -
      • When using PubSubClient on the ESP32, a stack overflow will occur if the user does not flush the buffer immediately after writing. The cause of this issue is under active investigation. More information in issue https://github.com/OPEnSLab-OSU/SSLClient/issues/9.
      • -
      • Previous to SSLClient v1.6.7, calls to SSLClient::stop would sometimes hang the device. More information in issue https://github.com/OPEnSLab-OSU/SSLClient/issues/13.
      • -
      • Previous to SSLClient v1.6.6, calls to SSLClient::connect would fail if the driver indicated that a socket was already opened (Client::connected returned true). This behavior created unintentional permanent failures when Client::stop would fail to close the socket, and as a result was downgraded to a warning in v1.6.6.
      • -
      • Previous to SSLClient v1.6.3, calling SSLClient::write with more than 2Kb of total data before flushing the write buffer would cause a buffer overflow.
      • -
      • Previous to SSLClient v1.6.11, SSLClient::write would sometimes call br_ssl_engine_sendapp_ack with zero bytes, which resulted in a variety of issues including (but not limited to) and infinite recursion loop on the esp32 ( #9, #30).
      • +
      • Previous to SSLClient v1.6.7, calls to SSLClient::stop would sometimes hang the device. More information in issue https://github.com/OPEnSLab-OSU/SSLClient/issues/13.
      • +
      • Previous to SSLClient v1.6.6, calls to SSLClient::connect would fail if the driver indicated that a socket was already opened (Client::connected returned true). This behavior created unintentional permanent failures when Client::stop would fail to close the socket, and as a result was downgraded to a warning in v1.6.6.
      • +
      • Previous to SSLClient v1.6.3, calling SSLClient::write with more than 2kB of total data before flushing the write buffer would cause a buffer overflow.
      • +
      • Previous to SSLClient v1.6.11, SSLClient::write would sometimes call br_ssl_engine_sendapp_ack with zero bytes, which resulted in a variety of issues including (but not limited to) and infinite recursion loop on the esp32 (#9, #30).
    From 028e33728d0b1544169f0e6dd41a83753ca84f9f Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Mon, 22 Mar 2021 10:57:29 -0700 Subject: [PATCH 203/205] docs: grammer fixes and add resources table to README --- README.md | 67 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 7cf24c7..98c5fa0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ SSLClient adds [TLS 1.2](https://www.websecurity.symantec.com/security-topics/what-is-ssl-tls-https) functionality to any network library implementing the [Arduino Client interface](https://www.arduino.cc/en/Reference/ClientConstructor), including the Arduino [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient) and [WiFiClient](https://www.arduino.cc/en/Reference/WiFiClient) classes. SSLClient was created to integrate TLS seamlessly with the Arduino infrastructure using [BearSSL](https://bearssl.org/) as an underlying TLS engine. Unlike [ArduinoBearSSL](https://github.com/arduino-libraries/ArduinoBearSSL), SSLClient is completly self-contained, and does not require any additional hardware (other than a network connection). -SSLClient officially supports SAMD21, SAM3X, ESP32, TIVA C, STM32F7, and Teensy >= 3.0; but it should work on any board with at least 110kb flash and 7kb RAM. SSClient does not currently support ESP8266 (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)) or AVR due to memory constraints on both platforms. +SSLClient officially supports SAMD21, SAM3X, ESP32, TIVA C, STM32F7, and Teensy >= 3.0; but it should work on any board with at least 110kB flash and 7kB RAM. SSClient does not currently support ESP8266 (see [this issue](https://github.com/OPEnSLab-OSU/SSLClient/issues/5#issuecomment-569968546)) or AVR due to memory constraints on both platforms. You can also view this README in [doxygen](https://openslab-osu.github.io/SSLClient/index.html). @@ -12,7 +12,7 @@ You can also view this README in [doxygen](https://openslab-osu.github.io/SSLCli Using SSLClient is similar to using any other Arduino-based Client class, as this library was developed around compatibility with [EthernetClient](https://www.arduino.cc/en/Reference/EthernetClient). There are a few extra things, however, that you will need to get started: -1. **Board and Network Peripheral** - Your board should have a lot of resources (>110kb flash and >7kb RAM), and your network peripheral should have a large internal buffer (>7kb). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kb Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Gotchas](#sslclient-with-ethernet)). +1. **Board and Network Peripheral** - Your board should have a lot of resources (>110kB flash and >7kB RAM), and your network peripheral should have a large internal buffer (>7kB). This library was tested with the [Adafruit Feather M0](https://www.adafruit.com/product/2772) (256K flash, 32K RAM) and the [Adafruit Ethernet Featherwing](https://www.adafruit.com/product/3201) (16kB Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the [Implementation Gotchas](#sslclient-with-ethernet)). 2. **Trust Anchors** - You will need a header containing array of trust anchors ([example](./readme/cert.h)), which are used to verify the SSL connection later on. **This file must generated for every project.** Check out [TrustAnchors.md](./TrustAnchors.md#generating-trust-anchors) on how to generate this file for your project, and for more information about what a trust anchor is. 3. **Network Peripheral Driver Implementing `Client`** - Examples include `EthernetClient`, `WiFiClient`, and so on—SSLClient will run on top of any network driver exposing the `Client` interface. 4. **Analog Pin** - Used for generating random data at the start of the connection (see the [Implementation Gotchas](#implementation-gotchas)). @@ -84,7 +84,7 @@ client.write("Connection: close\r\n"); while (!client.available()) { /* ... */ } // ... ``` -Notice that every single write() call immediately writes to the network, which is fine with most network clients. With SSL, however, if we are encrypting and writing to the network every write() call, this will result in a lot of small encryption tasks. Encryption takes a lot of time and code, so to reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below: +Notice that every single `client.write()` call immediately writes to the network. This behavior is fine for most network clients; with SSL, however, it results in many small encryption tasks that consume resources. To reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below: ```C++ EthernetClient baseClient; @@ -105,18 +105,18 @@ while (!client.available()) { /* ... */ } If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished. ### Session Caching -As detailed in the [resources section](#resources), SSL handshakes take an extended period (1-4sec) to negotiate. To remedy this problem, BearSSL is able to keep a [SSL session cache](https://bearssl.org/api1.html#session-cache) of the clients it has connected to. If BearSSL successfully resumes an SSL session, it can reduce connection time to 100-500ms. +As detailed in the [resources section](#resources), SSL handshakes take an extended period (1-4sec) to negotiate. BearSSL is able to keep a [SSL session cache](https://bearssl.org/api1.html#session-cache) of the clients it has connected to which can drastically reduce this time: if BearSSL successfully resumes an SSL session, connection time is typically 100-500ms. In order to use SSL session resumption: - * The website you are connecting to must support it. Support is widespread, but you can verify easily using the [SSLLabs tool](https://www.ssllabs.com/ssltest/). + * The website you are connecting to must support it. Support is widespread, and you can verify it using [SSLLabs](https://www.ssllabs.com/ssltest/). * You must reuse the same SSLClient object (SSL Sessions are stored in the object itself). - * You must reconnect to the exact same server. + * You must reconnect to the exact same server (detailed below). -SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use the SSL session with that hostname. However, because some websites have multiple servers on a single IP address (github.com being an example), you may find that even if you are connecting to the same host the connection does not resume. This is a flaw in the SSL session protocol — though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being used here. SSL sessions can also expire based on server criteria, which will result in a standard 4-10 second connection. +> NOTE: SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call `connect("www.google.com")` SSLClient will use the same SSL session for that hostname. Unfortunately some websites have multiple servers on a single IP address (github.com being an example), so you may find that even if you are connecting to the same host the connection will not resume. This is a flaw in the SSL session protocol—though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being resolved here. +> +> SSL sessions can also expire based on server criteria (ex. timeout), which will result in a standard 4-10 second connection. -You can test whether or not a website can resume SSL Sessions using the [Session Example](./examples/Session_Example/Session_Example.ino) included with this library. Because of all the confounding factors of SSL Sessions, it is generally prudent while programming to assume the session will always fail to resume. - -SSL sessions take a lot of memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration: +SSL sessions take memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration: ```C++ EthernetClient baseClient; SSLClient client(baseClient, TAs, (size_t)2, A7, SomeNumber); @@ -132,7 +132,7 @@ If you need to clear a session, you can do so using the SSLSession::removeSessio ### mTLS -As of `v1.6.0`, SSLClient supports [mutual TLS authentication](https://developers.cloudflare.com/access/service-auth/mtls/). mTLS is a varient of TLS that verifys both the server and device identities before a connection, and is commonly used in IoT protocols as a secure layer (MQTT over TLS, HTTPS over TLS, etc.). +As of `v1.6.0`, SSLClient supports [mutual TLS authentication](https://developers.cloudflare.com/access/service-auth/mtls/). mTLS is a varient of TLS that verifies both the server and device identities before a connection, and is commonly used in IoT protocols as a secure layer (MQTT over TLS, HTTP over TLS, etc.). To use mTLS with SSLClient you will need to a client certificate and client private key associated with the server you are attempting to connect to. Depending on your use case, you will either generate these yourself (ex. [Mosquito MQTT setup](http://www.steves-internet-guide.com/creating-and-using-client-certificates-with-mqtt-and-mosquitto/)), or have them generated for you (ex. [AWS IoT Certificate Generation](https://docs.aws.amazon.com/iot/latest/developerguide/create-device-certificate.html)). Given this cryptographic information, you can modify the standard SSLClient connection sketch to enable mTLS authentication: ```C++ @@ -181,7 +181,7 @@ Note that both the above client certificate information *as well as* the correct Some ideas that didn't quite fit in the API documentation. ### SSLClient with Ethernet -If you are using the [Arduino Ethernet library](https://github.com/arduino-libraries/Ethernet), you will need to modify the library to support the large buffer sizes required by SSL (detailed in [resources](#resources)). You can either modify the library yourself, or use [this fork of the Ethernet library with the modification](https://github.com/OPEnSLab-OSU/EthernetLarge). To use the fork, simply install the library using the "add a .zip library" button in Arduino, and replace `#include "Ethernet.h"` with `#include "EthernetLarge.h"` in your sketch. Alternatively if for some reason this solution does not work, you can apply the modification using the instructions below. +If you are using the [Arduino Ethernet library](https://github.com/arduino-libraries/Ethernet) you will need to modify the library to support the large buffer sizes required by SSL (detailed in [resources](#resources)). You can either modify the library yourself, or use [this fork of the Ethernet library with the modification](https://github.com/OPEnSLab-OSU/EthernetLarge). To use the fork: download a zipped copy of the fork through GiThub, use the "add a .zip library" button in Arduino to install the library, and replace `#include "Ethernet.h"` with `#include "EthernetLarge.h"` in your sketch. Alternatively if for some reason this solution does not work, you can apply the modification manually using the instructions below. #### Manual Modification @@ -239,23 +239,35 @@ BearSSL also features a [known certificate validation engine](https://bearssl.or The minimal x509 verification engine requires an accurate source of time to properly verify the creation and expiration dates of a certificate. As most embedded devices do not have a reliable source of time, by default SSLClient opts to use the compilation timestamp ([`__DATE__` and `__TIME__`](https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html)) as the "current time" during the verification process. While this approach reduces the complexity of using SSLClient, it is inherently insecure, and can cause errors if certificates are redeployed (see [#27](https://github.com/OPEnSLab-OSU/SSLClient/issues/27)): to accommodate these edge cases, SSLClient::setVerificationTime can be used to update the timestamp before connecting, resolving the above issues. ### Resources -The SSL protocol recommends a device support many different encryption algorithms, as well as protocols for SSL itself. The complexity of both of those components results in many medium sized components forming an extremely large whole. Additionally, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, and as a result require more instructions to create the encryption algorithms SSL requires. This not only increases size but makes the algorithms slow and memory intensive. +The SSL/TLS protocol recommends a device support many different encryption and handshake algorithms. The complexity of these components results in many medium-footprint algorithms forming an extremely large whole. Compilation size of the [EthernetHTTPS](examples/EthernetHTTPS/EthernetHTTPS.ino) example in SSLClient `v1.6.11` for various boards is shown below: -To illustrate this, I will run some tests on various domains below. I haven't yet, but I will. +| Board | Size +| :--- | :--- | +| Arduino Zero |
    `RAM:   [===       ]  33.7% (used 11052 bytes from 32768 bytes)`
    `Flash: [=== ] 34.7% (used 90988 bytes from 262144 bytes)`
    | +| Arduino Due |
    `RAM:   [=         ]  11.7% (used 11548 bytes from 98304 bytes)`
    `Flash: [== ] 16.7% (used 87572 bytes from 524288 bytes)`
    | +| Adafruit Feather M0 |
    `RAM:   [====      ]  40.4% (used 13240 bytes from 32768 bytes)`
    `Flash: [==== ] 40.0% (used 104800 bytes from 262144 bytes)`
    | +| ESP32 (Lolin32) |
    `RAM:   [=         ]   6.9% (used 22476 bytes from 327680 bytes)`
    `Flash: [== ] 24.0% (used 314956 bytes from 1310720 bytes)`
    | +| Teensy 3.0 |
    `RAM:   [========  ]  78.2% (used 12812 bytes from 16384 bytes)`
    `Flash: [======== ] 79.8% (used 104532 bytes from 131072 bytes)`
    | +| Teensy 3.1 |
    `RAM:   [==        ]  19.9% (used 13020 bytes from 65536 bytes)`
    `Flash: [==== ] 40.6% (used 106332 bytes from 262144 bytes)`
    | +| Teensy 3.5 |
    `RAM:   [          ]   5.0% (used 12996 bytes from 262136 bytes)`
    `Flash: [== ] 20.1% (used 105476 bytes from 524288 bytes)`
    +| Teensy 3.6 |
    `RAM:   [          ]   5.0% (used 13060 bytes from 262144 bytes)`
    `Flash: [= ] 10.2% (used 106828 bytes from 1048576 bytes)`
    | +| Teensy 4.0 |
    `RAM:   [===       ]  25.9% (used 135860 bytes from 524288 bytes)`
    `Flash: [= ] 5.7% (used 115344 bytes from 2031616 bytes)`
    | -If flash footprint is becoming a problem, there are numerous debugging strings (~3kb estimated) that can be removed from `SSLClient.h`, `SSLClientImpl.h`, and `SSLClientImpl.cpp`. I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself. +In addition to the above, most embedded processors lack the sophisticated math hardware commonly found in a modern CPU, which results in slow and memory intensive execution of these algorithms. Because of this, it is recommended that SSLClient have 8kb of memory available on the stack during a connection, and 4-10 seconds should be allowed for the connection to complete. Note that this requirement is based on the SAMD21—more powerful processors (such as the ESP32) will see faster connection times. + +> NOTE: If flash footprint is becoming a problem, there are numerous debugging strings (~3kB estimated) that can be removed from `SSLClient.h`, `SSLClientImpl.h`, and `SSLClientImpl.cpp`. Unfortunately I have not figured out a way to configure compilation of these strings, so you will need to modify the library to remove them yourself. ### Read Buffer Overflow -SSL is a buffered protocol, and since most microcontrollers have limited resources (see [Resources](#resources)), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow, caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received, forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems, this could be the reason why. +SSL is a buffered protocol, and since most microcontrollers have limited resources (see [Resources](#resources)), SSLClient is limited in the size of its buffers. A common problem I encountered with SSL connections is buffer overflow caused by the server sending too much data at once. This problem is caused by the microcontroller being unable to copy and decrypt data faster than it is being received—forcing some data to be discarded. This usually puts BearSSL in an unrecoverable state, forcing SSLClient to close the connection with a write error. If you are experiencing frequent timeout problems this could be the reason why. -In order to remedy this problem, the device must be able to read the data faster than it is being received, or alternatively have a cache large enough to store the entire payload. Since SSL's encryption forces the device to read slowly, this means we must increase the cache size. Depending on your platform, there are a number of ways this can be done: -* Sometimes your communication shield will have an internal buffer, which can be expanded through the driver code. This is the case with the Arduino Ethernet library (in the form of the MAX_SOCK_NUM and ETHERNET_LARGE_BUFFERS macros), however the library must be modified for the change to take effect. -* SSLClient has an internal buffer SSLClient::m_iobuf, which can be expanded. BearSSL limits the amount of data that can be processed based on the stage in the SSL handshake, and so this will change will have limited usefulness. -* In some cases, a website will send so much data that even with the above solutions, SSLClient will be unable to keep up (a website with a lot of HTML is an example). In these cases you will have to find another method of retrieving the data you need. -* If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This would require in-depth knowledge of programming and the communication shield you are working with, as well as a microcontroller with a significant amount of RAM. +In order to remedy this problem, the device must be able to read the data faster than it is being received or have a cache large enough to store the entire payload. Since the device is typically already reading as fast as it can, we must increase the cache size in order to resolve this issue. Depending on your platform there are a number of ways this can be done: +* Sometimes your communication shield will have an internal buffer which can be expanded through the driver code: this is the case with the Arduino Ethernet library (in the form of the `MAX_SOCK_NUM` and `ETHERNET_LARGE_BUFFERS` macros show [here](#manual-modification)), but mileage may vary with other drivers. +* SSLClient has an internal buffer SSLClient::m_iobuf which can be expanded. Unfortunately, BearSSL limits the amount of data that can be put into the buffer based on the stage in the SSL handshake, and so increasing the buffer will have limited usefulness. +* In some cases, a website will send so much data that even with the above solutions SSLClient will be unable to keep up. In these cases you will have to find another method of retrieving the data you need. +* If none of the above are viable, it is possible to implement your own Client class which has an internal buffer much larger than both the driver and BearSSL. This implementation would require in-depth knowledge of communication shield you are working with and a microcontroller with a significant amount of RAM, but would be the most robust solution available. ### Cipher Support -By default, SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile.c) under `suites[]`, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher, you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl/ssl_client_full.c). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: +By default, SSLClient supports only TLS1.2 and the ciphers listed in [this file](./src/TLS12_only_profile.c) under `suites[]`, and the list is relatively small to keep the connection secure and the flash footprint down. These ciphers should work for most applications, however if for some reason you would like to use an older version of TLS or a different cipher you can change the BearSSL profile being used by SSLClient to an [alternate one with support for older protocols](./src/bearssl/src/ssl/ssl_client_full.c). To do this, edit `SSLClientImpl::SSLClientImpl` to change these lines: ```C++ br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // comment the above line and uncomment the line below if you're having trouble connecting over SSL @@ -270,12 +282,11 @@ br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_ If for some unfortunate reason you need SSL 3.0 or SSL 2.0, you will need to modify the BearSSL profile to enable support. Check out the [BearSSL profiles documentation](https://bearssl.org/api1.html#profiles) and I wish you the best of luck. ### Security -Unlike BearSSL, SSLClient is not rigorously vetted to be secure. If your project has security requirements, I recommend you utilize BearSSL directly. +Unlike BearSSL, SSLClient is not rigorously vetted to be secure. If your project has security requirements I recommend you utilize BearSSL directly. ### Known Issues * In some drivers (Ethernet), calls to `Client::flush` will hang if internet is available but there is no route to the destination. Unfortunately SSLClient cannot correct for this without modifying the driver itself, and as a result the recommended solution is ensuring you choose a driver with built-in timeouts to prevent freezing. [More information here](https://github.com/OPEnSLab-OSU/SSLClient/issues/13#issuecomment-643855923). - * When using PubSubClient on the ESP32, a stack overflow will occur if the user does not flush the buffer immediately after writing. The cause of this issue is under active investigation. More information in issue https://github.com/OPEnSLab-OSU/SSLClient/issues/9. - * Previous to SSLClient v1.6.7, calls to `SSLClient::stop` would sometimes hang the device. More information in issue https://github.com/OPEnSLab-OSU/SSLClient/issues/13. - * Previous to SSLClient v1.6.6, calls to `SSLClient::connect` would fail if the driver indicated that a socket was already opened (`Client::connected` returned true). This behavior created unintentional permanent failures when `Client::stop` would fail to close the socket, and as a result was downgraded to a warning in v1.6.6. - * Previous to SSLClient v1.6.3, calling `SSLClient::write` with more than 2Kb of total data before flushing the write buffer would cause a buffer overflow. - * Previous to SSLClient v1.6.11, `SSLClient::write` would sometimes call `br_ssl_engine_sendapp_ack` with zero bytes, which resulted in a variety of issues including (but not limited to) and infinite recursion loop on the esp32 ( [#9](https://github.com/OPEnSLab-OSU/SSLClient/issues/9), [#30](https://github.com/OPEnSLab-OSU/SSLClient/issues/30)). + * Previous to SSLClient `v1.6.11`, `SSLClient::write` would sometimes call `br_ssl_engine_sendapp_ack` with zero bytes, which resulted in a variety of issues including (but not limited to) and infinite recursion loop on the esp32 ([#9](https://github.com/OPEnSLab-OSU/SSLClient/issues/9), [#30](https://github.com/OPEnSLab-OSU/SSLClient/issues/30)). + * Previous to SSLClient `v1.6.7`, calls to `SSLClient::stop` would sometimes hang the device. More information in issue https://github.com/OPEnSLab-OSU/SSLClient/issues/13. + * Previous to SSLClient `v1.6.6`, calls to `SSLClient::connect` would fail if the driver indicated that a socket was already opened (`Client::connected` returned true). This behavior created unintentional permanent failures when `Client::stop` would fail to close the socket, and as a result was downgraded to a warning in v1.6.6. + * Previous to SSLClient `v1.6.3`, calling `SSLClient::write` with more than 2kB of total data before flushing the write buffer would cause a buffer overflow. \ No newline at end of file From 25821450e76e431478055d3dfb196eff037d0212 Mon Sep 17 00:00:00 2001 From: prototypicalpro Date: Mon, 22 Mar 2021 18:06:56 +0000 Subject: [PATCH 204/205] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20=20@?= =?UTF-8?q?=20028e33728d0b1544169f0e6dd41a83753ca84f9f=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 20db02f..808b74a 100644 --- a/index.html +++ b/index.html @@ -334,10 +334,10 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });

    Known Issues

    • In some drivers (Ethernet), calls to Client::flush will hang if internet is available but there is no route to the destination. Unfortunately SSLClient cannot correct for this without modifying the driver itself, and as a result the recommended solution is ensuring you choose a driver with built-in timeouts to prevent freezing. More information here.
    • +
    • Previous to SSLClient v1.6.11, SSLClient::write would sometimes call br_ssl_engine_sendapp_ack with zero bytes, which resulted in a variety of issues including (but not limited to) and infinite recursion loop on the esp32 (#9, #30).
    • Previous to SSLClient v1.6.7, calls to SSLClient::stop would sometimes hang the device. More information in issue https://github.com/OPEnSLab-OSU/SSLClient/issues/13.
    • Previous to SSLClient v1.6.6, calls to SSLClient::connect would fail if the driver indicated that a socket was already opened (Client::connected returned true). This behavior created unintentional permanent failures when Client::stop would fail to close the socket, and as a result was downgraded to a warning in v1.6.6.
    • -
    • Previous to SSLClient v1.6.3, calling SSLClient::write with more than 2kB of total data before flushing the write buffer would cause a buffer overflow.
    • -
    • Previous to SSLClient v1.6.11, SSLClient::write would sometimes call br_ssl_engine_sendapp_ack with zero bytes, which resulted in a variety of issues including (but not limited to) and infinite recursion loop on the esp32 (#9, #30).
    • +
    • Previous to SSLClient v1.6.3, calling SSLClient::write with more than 2kB of total data before flushing the write buffer would cause a buffer overflow.
    From 1fe48948004a3ad52705ab26db4f65833ecb4e12 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 31 Mar 2021 13:26:12 -0700 Subject: [PATCH 205/205] chore: update pycert_bearssl to detect end entity certificates (#35) --- tools/pycert_bearssl/cert_util.py | 20 +++++++++++++++++--- tools/pycert_bearssl/pycert_bearssl.py | 7 ++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/tools/pycert_bearssl/cert_util.py b/tools/pycert_bearssl/cert_util.py index 998c8a9..335be4c 100644 --- a/tools/pycert_bearssl/cert_util.py +++ b/tools/pycert_bearssl/cert_util.py @@ -36,6 +36,8 @@ RSA_E_PRE = "TA_RSA_E" EC_CURVE_PRE = "TA_EC_CURVE" # EC curve type enum prefix EC_CURVE_NAME_PRE = "BR_EC_" +# CA flag +CA_FLAG = "BR_X509_TA_CA" # Template that defines the C header output format. @@ -95,7 +97,7 @@ static const {ray_type} {ray_name}[] = {{ CROOTCA_TEMPLATE = """\ {{ {{ (unsigned char *){ta_dn_name}, sizeof {ta_dn_name} }}, - BR_X509_TA_CA, + {ca_flag}, {{ BR_KEYTYPE_RSA, {{ .rsa = {{ @@ -135,7 +137,8 @@ CROOTCA_EC_TEMPLATE = """\ CCERT_DESC_TEMPLATE = """\ * Index: {cert_num} * Label: {cert_label} - * Subject: {cert_subject}""" + * Subject: {cert_subject} + * Type: {cert_type}""" def PEM_split(cert_pem): """Split a certificate / certificate chain in PEM format into multiple @@ -228,12 +231,17 @@ def decribe_cert_object(cert, cert_num, domain=None): label = com[b'OU'].decode("utf-8") elif b'O' in com: label = com[b'O'].decode("utf-8") + if cert.get_issuer() == cert.get_subject(): + cert_type = "Certificate Authority" + else: + cert_type = "End Entity" # return the formated string crypto = cert.to_cryptography() out_str = CCERT_DESC_TEMPLATE.format( cert_num=cert_num, cert_label=label, cert_subject=crypto.subject.rfc4514_string(), + cert_type=cert_type ) # if domain, then add domain entry if domain is not None: @@ -279,6 +287,8 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes cert_desc.append(decribe_cert_object(cert, cert_index)) else: cert_desc.append(decribe_cert_object(cert, cert_index, domain=domains[i])) + # detect if the cert is a CA + is_ca = cert.get_issuer() == cert.get_subject() # build static arrays containing all the keys of the certificate # start with distinguished name # get the distinguished name in bytes @@ -307,6 +317,7 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes # format the root certificate entry CAs.append(CROOTCA_TEMPLATE.format( ta_dn_name=DN_PRE + str(cert_index), + ca_flag=CA_FLAG if is_ca else "0", rsa_number_name=RSA_N_PRE + str(cert_index), rsa_exp_name=RSA_E_PRE + str(cert_index))) elif 'Elliptic' in numbers_typename: @@ -322,6 +333,7 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes # and then the exponent CAs.append(CROOTCA_EC_TEMPLATE.format( ta_dn_name=DN_PRE + str(cert_index), + ca_flag=CA_FLAG if is_ca else "0", ec_number_name=EC_CURVE_PRE + str(cert_index), ec_curve_name=EC_CURVE_NAME_PRE + curve_name )) @@ -343,4 +355,6 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes cert_length_var=cert_length_var, cert_length=str(len(CAs)), cert_data=cert_data_out, - )) \ No newline at end of file + )) + + return len(cert_ser) \ No newline at end of file diff --git a/tools/pycert_bearssl/pycert_bearssl.py b/tools/pycert_bearssl/pycert_bearssl.py index 7b25f35..40388b9 100644 --- a/tools/pycert_bearssl/pycert_bearssl.py +++ b/tools/pycert_bearssl/pycert_bearssl.py @@ -136,6 +136,10 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_search, else: click.echo('Loaded certificate {0}'.format(c.name)) cert_objs.append(cert_parsed) + + if no_search and cert_parsed.get_subject() != cert_parsed.get_issuer(): + click.echo(f'Warning: certificate {c.name} is an end entity certificate (not a CA). ' + 'SSLClient may fail to validate if the server certificate changes.') # find a root certificate for each root_certs = [] if no_search: @@ -149,7 +153,8 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_search, root_certs.append(cert_dict[cn_hash]) # Combine PEMs and write output header. try: - cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes) + written = cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes) + click.echo(f'Wrote {written} trust anchors to {output.name}') except Exception as E: click.echo(f'Recieved error when converting certificate to header: {E}') exit(1)