aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2005-06-05 20:52:14 +0000
committerSam Leffler <sam@FreeBSD.org>2005-06-05 20:52:14 +0000
commitf1fb6907abb279cfabe81d79e2ffac54c4e7aa98 (patch)
tree98be326632e2ea3857ee0d9f831c91ea0823bb0d
downloadsrc-f1fb6907abb279cfabe81d79e2ffac54c4e7aa98.tar.gz
src-f1fb6907abb279cfabe81d79e2ffac54c4e7aa98.zip
Stripped down import of wpa_supplicant v0.3.8vendor/wpa_supplicant/0.3.8
Notes
Notes: svn path=/vendor/wpa_supplicant/dist/; revision=147013 svn path=/vendor/wpa_supplicant/0.3.8/; revision=147015; tag=vendor/wpa_supplicant/0.3.8
-rw-r--r--contrib/wpa_supplicant/COPYING340
-rw-r--r--contrib/wpa_supplicant/ChangeLog395
-rw-r--r--contrib/wpa_supplicant/Makefile385
-rw-r--r--contrib/wpa_supplicant/README860
-rw-r--r--contrib/wpa_supplicant/aes.c1132
-rw-r--r--contrib/wpa_supplicant/aes_wrap.c642
-rw-r--r--contrib/wpa_supplicant/aes_wrap.h21
-rw-r--r--contrib/wpa_supplicant/common.c335
-rw-r--r--contrib/wpa_supplicant/common.h222
-rw-r--r--contrib/wpa_supplicant/config.c1051
-rw-r--r--contrib/wpa_supplicant/config.h33
-rw-r--r--contrib/wpa_supplicant/config_ssid.h109
-rw-r--r--contrib/wpa_supplicant/crypto.c71
-rw-r--r--contrib/wpa_supplicant/crypto.h8
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.c728
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.h31
-rw-r--r--contrib/wpa_supplicant/defconfig154
-rw-r--r--contrib/wpa_supplicant/defs.h14
-rw-r--r--contrib/wpa_supplicant/developer.txt458
-rw-r--r--contrib/wpa_supplicant/doc/wpa_supplicant.fig221
-rw-r--r--contrib/wpa_supplicant/driver.h436
-rw-r--r--contrib/wpa_supplicant/drivers.c96
-rw-r--r--contrib/wpa_supplicant/eap.c1243
-rw-r--r--contrib/wpa_supplicant/eap.h70
-rw-r--r--contrib/wpa_supplicant/eap_aka.c915
-rw-r--r--contrib/wpa_supplicant/eap_defs.h41
-rw-r--r--contrib/wpa_supplicant/eap_fast.c1906
-rw-r--r--contrib/wpa_supplicant/eap_gtc.c164
-rw-r--r--contrib/wpa_supplicant/eap_i.h106
-rw-r--r--contrib/wpa_supplicant/eap_leap.c379
-rw-r--r--contrib/wpa_supplicant/eap_md5.c112
-rw-r--r--contrib/wpa_supplicant/eap_mschapv2.c564
-rw-r--r--contrib/wpa_supplicant/eap_otp.c113
-rw-r--r--contrib/wpa_supplicant/eap_peap.c820
-rw-r--r--contrib/wpa_supplicant/eap_psk.c563
-rw-r--r--contrib/wpa_supplicant/eap_sim.c1004
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.c788
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.h101
-rw-r--r--contrib/wpa_supplicant/eap_testing.txt349
-rw-r--r--contrib/wpa_supplicant/eap_tls.c245
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.c338
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.h51
-rw-r--r--contrib/wpa_supplicant/eap_tlv.c176
-rw-r--r--contrib/wpa_supplicant/eap_tlv.h73
-rw-r--r--contrib/wpa_supplicant/eap_ttls.c1384
-rw-r--r--contrib/wpa_supplicant/eap_ttls.h57
-rw-r--r--contrib/wpa_supplicant/eapol_sm.c1421
-rw-r--r--contrib/wpa_supplicant/eapol_sm.h138
-rw-r--r--contrib/wpa_supplicant/eapol_test.c1012
-rw-r--r--contrib/wpa_supplicant/eloop.c380
-rw-r--r--contrib/wpa_supplicant/eloop.h53
-rw-r--r--contrib/wpa_supplicant/hostap_common.h557
-rw-r--r--contrib/wpa_supplicant/l2_packet.h34
-rw-r--r--contrib/wpa_supplicant/md5.c355
-rw-r--r--contrib/wpa_supplicant/md5.h43
-rw-r--r--contrib/wpa_supplicant/ms_funcs.c333
-rw-r--r--contrib/wpa_supplicant/ms_funcs.h25
-rw-r--r--contrib/wpa_supplicant/openssl-tls-extensions.patch166
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.c776
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.h50
-rw-r--r--contrib/wpa_supplicant/preauth_test.c396
-rw-r--r--contrib/wpa_supplicant/radius_client.c674
-rw-r--r--contrib/wpa_supplicant/radius_client.h81
-rw-r--r--contrib/wpa_supplicant/rc4.c63
-rw-r--r--contrib/wpa_supplicant/rc4.h7
-rw-r--r--contrib/wpa_supplicant/sha1.c910
-rw-r--r--contrib/wpa_supplicant/sha1.h50
-rw-r--r--contrib/wpa_supplicant/tls.h312
-rw-r--r--contrib/wpa_supplicant/tls_none.c22
-rw-r--r--contrib/wpa_supplicant/tls_openssl.c876
-rw-r--r--contrib/wpa_supplicant/todo.txt54
-rw-r--r--contrib/wpa_supplicant/version.h6
-rw-r--r--contrib/wpa_supplicant/wpa.c2445
-rw-r--r--contrib/wpa_supplicant/wpa.h112
-rw-r--r--contrib/wpa_supplicant/wpa_cli.c850
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.c230
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.h15
-rw-r--r--contrib/wpa_supplicant/wpa_passphrase.c53
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.c2439
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.conf505
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.h81
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant_i.h469
82 files changed, 35297 insertions, 0 deletions
diff --git a/contrib/wpa_supplicant/COPYING b/contrib/wpa_supplicant/COPYING
new file mode 100644
index 000000000000..60549be514af
--- /dev/null
+++ b/contrib/wpa_supplicant/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. 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.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+ 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
+convey 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) 19yy <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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This 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 Library General
+Public License instead of this License.
diff --git a/contrib/wpa_supplicant/ChangeLog b/contrib/wpa_supplicant/ChangeLog
new file mode 100644
index 000000000000..57098581aee3
--- /dev/null
+++ b/contrib/wpa_supplicant/ChangeLog
@@ -0,0 +1,395 @@
+ChangeLog for wpa_supplicant
+
+2005-02-13 - v0.3.8
+ * fixed EAPOL-Key validation to drop packets with invalid Key Data
+ Length; such frames could have crashed wpa_supplicant due to buffer
+ overflow
+
+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
+ * added new phase1 option parameter, include_tls_length=1, to force
+ wpa_supplicant to add TLS Message Length field to all TLS messages
+ even if the packet is not fragmented; this may be needed with some
+ authentication servers
+ * fixed WPA/RSN IE verification in message 3 of 4-Way Handshake when
+ using drivers that take care of AP selection (e.g., when using
+ ap_scan=2)
+ * fixed reprocessing of pending request after ctrl_iface requests for
+ identity/password/otp
+ * fixed ctrl_iface requests for identity/password/otp in Phase 2 of
+ EAP-PEAP and EAP-TTLS
+ * all drivers using driver_wext: set interface up and select Managed
+ mode when starting wpa_supplicant; set interface down when exiting
+ * renamed driver_ipw2100.c to driver_ipw.c since it now supports both
+ ipw2100 and ipw2200; please note that this also changed the
+ configuration variable in .config to CONFIG_DRIVER_IPW
+
+2005-01-24 - v0.3.6
+ * fixed a busy loop introduced in v0.3.5 for scan result processing
+ when no matching AP is found
+
+2005-01-23 - v0.3.5
+ * added a workaround for an interoperability issue with a Cisco AP
+ when using WPA2-PSK
+ * fixed non-WPA IEEE 802.1X to use the same authentication timeout as
+ WPA with IEEE 802.1X (i.e., timeout 10 -> 70 sec to allow
+ retransmission of dropped frames)
+ * fixed issues with 64-bit CPUs and SHA1 cleanup in previous version
+ (e.g., segfault when processing EAPOL-Key frames)
+ * fixed EAP workaround and fast reauthentication configuration for
+ RSN pre-authentication; previously these were disabled and
+ pre-authentication would fail if the used authentication server
+ requires EAP workarounds
+ * added support for blacklisting APs that fail or timeout
+ authentication in ap_scan=1 mode so that all APs are tried in cases
+ where the ones with strongest signal level are failing authentication
+ * fixed CA certificate loading after a failed EAP-TLS/PEAP/TTLS
+ authentication attempt
+ * allow EAP-PEAP/TTLS fast reauthentication only if Phase 2 succeeded
+ in the previous authentication (previously, only Phase 1 success was
+ verified)
+
+2005-01-09 - v0.3.4
+ * added preliminary support for IBSS (ad-hoc) mode configuration
+ (mode=1 in network block); this included a new key_mgmt mode
+ WPA-NONE, i.e., TKIP or CCMP with a fixed key (based on psk) and no
+ key management; see wpa_supplicant.conf for more details and an
+ example on how to configure this (note: this is currently implemented
+ only for driver_hostapd.c, but the changes should be trivial to add
+ in associate() handler for other drivers, too (assuming the driver
+ supports WPA-None)
+ * added preliminary port for native Windows (i.e., no cygwin) using
+ mingw
+
+2005-01-02 - v0.3.3
+ * added optional support for GNU Readline and History Libraries for
+ wpa_cli (CONFIG_READLINE)
+ * cleaned up EAP state machine <-> method interface and number of
+ small problems with error case processing not terminating on
+ EAP-Failure but waiting for timeout
+ * added couple of workarounds for interoperability issues with a
+ Cisco AP when using WPA2
+ * added support for EAP-FAST (draft-cam-winget-eap-fast-00.txt);
+ Note: This requires a patch for openssl to add support for TLS
+ extensions and number of workarounds for operations without
+ certificates. Proof of concept type of experimental patch is
+ included in openssl-tls-extensions.patch.
+
+2004-12-19 - v0.3.2
+ * fixed private key loading for cases where passphrase is not set
+ * fixed Windows/cygwin L2 packet handler freeing; previous version
+ could cause a segfault when RSN pre-authentication was completed
+ * added support for PMKSA caching with drivers that generate RSN IEs
+ (e.g., NDIS); currently, this is only implemented in driver_ndis.c,
+ but similar code can be easily added to driver_ndiswrapper.c once
+ ndiswrapper gets full support for RSN PMKSA caching
+ * improved recovery from PMKID mismatches by requesting full EAP
+ authentication in case of failed PMKSA caching attempt
+ * driver_ndis: added support for NDIS NdisMIncidateStatus() events
+ (this requires that ndis_events is ran while wpa_supplicant is
+ running)
+ * driver_ndis: use ADD_WEP/REMOVE_WEP when configuring WEP keys
+ * added support for driver interfaces to replace the interface name
+ based on driver/OS specific mapping, e.g., in case of driver_ndis,
+ this allows the beginning of the adapter description to be used as
+ the interface name
+ * added support for CR+LF (Windows-style) line ends in configuration
+ file
+ * driver_ndis: enable radio before starting scanning, disable radio
+ when exiting
+ * modified association event handler to set portEnabled = FALSE before
+ clearing port Valid in order to reset EAP state machine and avoid
+ problems with new authentication getting ignored because of state
+ machines ending up in AUTHENTICATED/SUCCESS state based on old
+ information
+ * added support for driver events to add PMKID candidates in order to
+ allow drivers to give priority to most likely roaming candidates
+ * driver_hostap: moved PrivacyInvoked configuration to associate()
+ function so that this will not be set for plaintext connections
+ * added KEY_MGMT_802_1X_NO_WPA as a new key_mgmt type so that driver
+ interface can distinguish plaintext and IEEE 802.1X (no WPA)
+ authentication
+ * fixed static WEP key configuration to use broadcast/default type for
+ all keys (previously, the default TX key was configured as pairwise/
+ unicast key)
+ * driver_ndis: added legacy WPA capability detection for non-WPA2
+ drivers
+ * added support for setting static WEP keys for IEEE 802.1X without
+ dynamic WEP keying (eapol_flags=0)
+
+2004-12-12 - v0.3.1
+ * added support for reading PKCS#12 (PFX) files (as a replacement for
+ PEM/DER) to get certificate and private key (CONFIG_PKCS12)
+ * fixed compilation with CONFIG_PCSC=y
+ * added new ap_scan mode, ap_scan=2, for drivers that take care of
+ association, but need to be configured with security policy and SSID,
+ e.g., ndiswrapper and NDIS driver; this mode should allow such
+ drivers to work with hidden SSIDs and optimized roaming; when
+ ap_scan=2 is used, only the first network block in the configuration
+ file is used and this configuration should have explicit security
+ policy (i.e., only one option in the lists) for key_mgmt, pairwise,
+ group, proto variables
+ * added experimental port of wpa_supplicant for Windows
+ - driver_ndis.c driver interface (NDIS OIDs)
+ - currently, this requires cygwin and WinPcap
+ - small utility, win_if_list, can be used to get interface name
+ * control interface can now be removed at build time; add
+ CONFIG_CTRL_IFACE=y to .config to maintain old functionality
+ * optional Xsupplicant interface can now be removed at build time;
+ (CONFIG_XSUPPLICANT_IFACE=y in .config to bring it back)
+ * added auth_alg to driver interface associate() parameters to make it
+ easier for drivers to configure authentication algorithm as part of
+ the association
+
+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
+ * driver_broadcom: added new driver interface for Broadcom wl.o driver
+ (a generic driver for Broadcom IEEE 802.11a/g cards)
+ * wpa_cli: fixed parsing of -p <path> command line argument
+ * PEAPv1: fixed tunneled EAP-Success reply handling to reply with TLS
+ ACK, not tunneled EAP-Success (of which only the first byte was
+ actually send due to a bug in previous code); this seems to
+ interoperate with most RADIUS servers that implements PEAPv1
+ * PEAPv1: added support for terminating PEAP authentication on tunneled
+ EAP-Success message; this can be configured by adding
+ peap_outer_success=0 on phase1 parameters in wpa_supplicant.conf
+ (some RADIUS servers require this whereas others require a tunneled
+ reply
+ * PEAPv1: changed phase1 option peaplabel to use default to 0, i.e., to
+ the old label for key derivation; previously, the default was 1,
+ but it looks like most existing PEAPv1 implementations use the old
+ label which is thus more suitable default option
+ * added support for EAP-PSK (draft-bersani-eap-psk-03.txt)
+ * fixed parsing of wep_tx_keyidx
+ * added support for configuring list of allowed Phase 2 EAP types
+ (for both EAP-PEAP and EAP-TTLS) instead of only one type
+ * added support for configuring IEEE 802.11 authentication algorithm
+ (auth_alg; mainly for using Shared Key authentication with static
+ WEP keys)
+ * added support for EAP-AKA (with UMTS SIM)
+ * fixed couple of errors in PCSC handling that could have caused
+ random-looking errors for EAP-SIM
+ * added support for EAP-SIM pseudonyms and fast re-authentication
+ * added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS
+ session resumption)
+ * added support for EAP-SIM with two challanges
+ (phase1="sim_min_num_chal=3" can be used to require three challenges)
+ * added support for configuring DH/DSA parameters for an ephemeral DH
+ key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters
+ dh_file and dh_file2 (phase 2); this adds support for using DSA keys
+ and optional DH key exchange to achieve forward secracy with RSA keys
+ * added support for matching subject of the authentication server
+ certificate with a substring when using EAP-TLS/PEAP/TTLS; new
+ configuration variables subject_match and subject_match2
+ * changed SSID configuration in driver_wext.c (used by many driver
+ interfaces) to use ssid_len+1 as the length for SSID since some Linux
+ drivers expect this
+ * fixed couple of unaligned reads in scan result parsing to fix WPA
+ connection on some platforms (e.g., ARM)
+ * added driver interface for Intel ipw2100 driver
+ * added support for LEAP with WPA
+ * added support for larger scan results report (old limit was 4 kB of
+ data, i.e., about 35 or so APs) when using Linux wireless extensions
+ v17 or newer
+ * fixed a bug in PMKSA cache processing: skip sending of EAPOL-Start
+ only if there is a PMKSA cache entry for the current AP
+ * fixed error handling for case where reading of scan results fails:
+ must schedule a new scan or wpa_supplicant will remain waiting
+ forever
+ * changed debug output to remove shared password/key material by
+ default; all key information can be included with -K command line
+ argument to match the previous behavior
+ * added support for timestamping debug log messages (disabled by
+ default, can be enabled with -t command line argument)
+ * set pairwise/group cipher suite for non-WPA IEEE 802.1X to WEP-104
+ if keys are not configured to be used; this fixes IEEE 802.1X mode
+ with drivers that use this information to configure whether Privacy
+ bit can be in Beacon frames (e.g., ndiswrapper)
+ * avoid clearing driver keys if no keys have been configured since last
+ key clear request; this seems to improve reliability of group key
+ handshake for ndiswrapper & NDIS driver which seems to be suffering
+ of some kind of timing issue when the keys are cleared again after
+ association
+ * changed driver interface API:
+ - WPA_SUPPLICANT_DRIVER_VERSION define can be used to determine which
+ version is being used (now, this is set to 2; previously, it was
+ not defined)
+ - pass pointer to private data structure to all calls
+ - the new API is not backwards compatible; all in-tree driver
+ interfaces has been converted to the new API
+ * added support for controlling multiple interfaces (radios) per
+ wpa_supplicant process; each interface needs to be listed on the
+ command line (-c, -i, -D arguments) with -N as a separator
+ (-cwpa1.conf -iwlan0 -Dhostap -N -cwpa2.conf -iath0 -Dmadwifi)
+ * added a workaround for EAP servers that incorrectly use same Id for
+ sequential EAP packets
+ * changed libpcap/libdnet configuration to use .config variable,
+ CONFIG_DNET_PCAP, instead of requiring Makefile modification
+ * improved downgrade attack detection in IE verification of msg 3/4:
+ verify both WPA and RSN IEs, if present, not only the selected one;
+ reject the AP if an RSN IE is found in msg 3/4, but not in Beacon or
+ Probe Response frame, and RSN is enabled in wpa_supplicant
+ configuration
+ * fixed WPA msg 3/4 processing to allow Key Data field contain other
+ IEs than just one WPA IE
+ * added support for FreeBSD and driver interface for the BSD net80211
+ layer (CONFIG_DRIVER_BSD=y in .config); please note that some of the
+ required kernel mods have not yet been committed
+ * made EAP workarounds configurable; enabled by default, can be
+ disabled with network block option eap_workaround=0
+
+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
+ * resolved couple of interoperability issues with EAP-PEAPv1 and
+ Phase 2 (inner EAP) fragment reassembly
+ * driver_madwifi: fixed WEP key configuration for IEEE 802.1X when the
+ AP is using non-zero key index for the unicast key and key index zero
+ for the broadcast key
+ * driver_hostap: fixed IEEE 802.1X WEP key updates and
+ re-authentication by allowing unencrypted EAPOL frames when not using
+ WPA
+ * added a new driver interface, 'wext', which uses only standard,
+ driver independent functionality in Linux wireless extensions;
+ currently, this can be used only for non-WPA IEEE 802.1X mode, but
+ eventually, this is to be extended to support full WPA/WPA2 once
+ Linux wireless extensions get support for this
+ * added support for mode in which the driver is responsible for AP
+ scanning and selection; this is disabled by default and can be
+ enabled with global ap_scan=0 variable in wpa_supplicant.conf;
+ this mode can be used, e.g., with generic 'wext' driver interface to
+ use wpa_supplicant as IEEE 802.1X Supplicant with any Linux driver
+ supporting wireless extensions.
+ * driver_madwifi: fixed WPA2 configuration and scan_ssid=1 (e.g.,
+ operation with an AP that does not include SSID in the Beacon frames)
+ * added support for new EAP authentication methods:
+ EAP-TTLS/EAP-OTP, EAP-PEAPv0/OTP, EAP-PEAPv1/OTP, EAP-OTP
+ * added support for asking one-time-passwords from frontends (e.g.,
+ wpa_cli); this 'otp' command works otherwise like 'password' command,
+ but the password is used only once and the frontend will be asked for
+ a new password whenever a request from authenticator requires a
+ password; this can be used with both EAP-OTP and EAP-GTC
+ * changed wpa_cli to automatically re-establish connection so that it
+ does not need to be re-started when wpa_supplicant is terminated and
+ started again
+ * improved user data (identity/password/otp) requests through
+ frontends: process pending EAPOL packets after getting new
+ information so that full authentication does not need to be
+ restarted; in addition, send pending requests again whenever a new
+ frontend is attached
+ * changed control frontends to use a new directory for socket files to
+ make it easier for wpa_cli to automatically select between interfaces
+ and to provide access control for the control interface;
+ wpa_supplicant.conf: ctrl_interface is now a path
+ (/var/run/wpa_supplicant is the recommended path) and
+ ctrl_interface_group can be used to select which group gets access to
+ the control interface;
+ wpa_cli: by default, try to connect to the first interface available
+ in /var/run/wpa_supplicant; this path can be overriden with -p option
+ and an interface can be selected with -i option (i.e., in most common
+ cases, wpa_cli does not need to get any arguments)
+ * added support for LEAP
+ * added driver interface for Linux ndiswrapper
+ * added priority option for network blocks in the configuration file;
+ this allows networks to be grouped based on priority (the scan
+ results are searched for matches with network blocks in this order)
+
+2004-06-20 - v0.2.3
+ * sort scan results to improve AP selection
+ * fixed control interface socket removal for some error cases
+ * improved scan requesting and authentication timeout
+ * small improvements/bug fixes for EAP-MSCHAPv2, EAP-PEAP, and
+ TLS processing
+ * PEAP version can now be forced with phase1="peapver=<ver>"
+ (mostly for testing; by default, the highest version supported by
+ both the Supplicant and Authentication Server is selected
+ automatically)
+ * added support for madwifi driver (Atheros ar521x)
+ * added a workaround for cases where AP sets Install Tx/Rx bit for
+ WPA Group Key messages when pairwise keys are used (without this,
+ the Group Key would be used for Tx and the AP would drop frames
+ from the station)
+ * added GSM SIM/USIM interface for GSM authentication algorithm for
+ EAP-SIM; this requires pcsc-lite
+ * added support for ATMEL AT76C5XXx driver
+ * fixed IEEE 802.1X WEP key derivation in the case where Authenticator
+ does not include key data in the EAPOL-Key frame (i.e., part of
+ EAP keying material is used as data encryption key)
+ * added support for using plaintext and static WEP networks
+ (key_mgmt=NONE)
+
+2004-05-31 - v0.2.2
+ * added support for new EAP authentication methods:
+ EAP-TTLS/EAP-MD5-Challenge
+ EAP-TTLS/EAP-GTC
+ EAP-TTLS/EAP-MSCHAPv2
+ EAP-TTLS/EAP-TLS
+ EAP-TTLS/MSCHAPv2
+ EAP-TTLS/MSCHAP
+ EAP-TTLS/PAP
+ EAP-TTLS/CHAP
+ EAP-PEAP/TLS
+ EAP-PEAP/GTC
+ EAP-PEAP/MD5-Challenge
+ EAP-GTC
+ EAP-SIM (not yet complete; needs GSM/SIM authentication interface)
+ * added support for anonymous identity (to be used when identity is
+ sent in plaintext; real identity will be used within TLS protected
+ tunnel (e.g., with EAP-TTLS)
+ * added event messages from wpa_supplicant to frontends, e.g., wpa_cli
+ * added support for requesting identity and password information using
+ control interface; in other words, the password for EAP-PEAP or
+ EAP-TTLS does not need to be included in the configuration file since
+ a frontand (e.g., wpa_cli) can ask it from the user
+ * improved RSN pre-authentication to use a candidate list and process
+ all candidates from each scan; not only one per scan
+ * fixed RSN IE and WPA IE capabilities field parsing
+ * ignore Tx bit in GTK IE when Pairwise keys are used
+ * avoid making new scan requests during IEEE 802.1X negotiation
+ * use openssl/libcrypto for MD5 and SHA-1 when compiling wpa_supplicant
+ with TLS support (this replaces the included implementation with
+ library code to save about 8 kB since the library code is needed
+ anyway for TLS)
+ * fixed WPA-PSK only mode when compiled without IEEE 802.1X support
+ (i.e., without CONFIG_IEEE8021X_EAPOL=y in .config)
+
+2004-05-06 - v0.2.1
+ * added support for internal IEEE 802.1X (actually, IEEE 802.1aa/D6.1)
+ Supplicant
+ - EAPOL state machines for Supplicant [IEEE 802.1aa/D6.1]
+ - EAP peer state machine [draft-ietf-eap-statemachine-02.pdf]
+ - EAP-MD5 (cannot be used with WPA-RADIUS)
+ [draft-ietf-eap-rfc2284bis-09.txt]
+ - EAP-TLS [RFC 2716]
+ - EAP-MSCHAPv2 (currently used only with EAP-PEAP)
+ - EAP-PEAP/MSCHAPv2 [draft-josefsson-pppext-eap-tls-eap-07.txt]
+ [draft-kamath-pppext-eap-mschapv2-00.txt]
+ (PEAP version 0, 1, and parts of 2; only 0 and 1 are enabled by
+ default; tested with FreeRADIUS, Microsoft IAS, and Funk Odyssey)
+ - new configuration file options: eap, identity, password, ca_cert,
+ client_cert, privatekey, private_key_passwd
+ - Xsupplicant is not required anymore, but it can be used by
+ disabling the internal IEEE 802.1X Supplicant with -e command line
+ option
+ - this code is not included in the default build; Makefile need to
+ be edited for this (uncomment lines for selected functionality)
+ - EAP-TLS and EAP-PEAP require openssl libraries
+ * use module prefix in debug messages (WPA, EAP, EAP-TLS, ..)
+ * added support for non-WPA IEEE 802.1X mode with dynamic WEP keys
+ (i.e., complete IEEE 802.1X/EAP authentication and use IEEE 802.1X
+ EAPOL-Key frames instead of WPA key handshakes)
+ * added support for IEEE 802.11i/RSN (WPA2)
+ - improved PTK Key Handshake
+ - PMKSA caching, pre-authentication
+ * fixed wpa_supplicant to ignore possible extra data after WPA
+ EAPOL-Key packets (this fixes 'Invalid EAPOL-Key MIC when using
+ TPTK' error from message 3 of 4-Way Handshake in case the AP
+ includes extra data after the EAPOL-Key)
+ * added interface for external programs (frontends) to control
+ wpa_supplicant
+ - CLI example (wpa_cli) with interactive mode and command line
+ mode
+ - replaced SIGUSR1 status/statistics with the new control interface
+ * made some feature compile time configurable
+ - .config file for make
+ - driver interfaces (hostap, hermes, ..)
+ - EAPOL/EAP functions
+
+2004-02-15 - v0.2.0
+ * Initial version of wpa_supplicant
diff --git a/contrib/wpa_supplicant/Makefile b/contrib/wpa_supplicant/Makefile
new file mode 100644
index 000000000000..fa912436c86e
--- /dev/null
+++ b/contrib/wpa_supplicant/Makefile
@@ -0,0 +1,385 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+# Include directories for CVS version
+CFLAGS += -I../driver/modules -I../utils -I../hostapd
+
+ALL=wpa_supplicant wpa_passphrase wpa_cli
+
+all: verify_config $(ALL)
+
+verify_config:
+ @if [ ! -r .config ]; then \
+ echo 'Building wpa_supplicant requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+
+mkconfig:
+ @if [ -e .config ]; then \
+ echo '.config exists - did not replace it'; \
+ exit 1; \
+ fi
+ echo CONFIG_DRIVER_HOSTAP=y >> .config
+ echo CONFIG_DRIVER_WEXT=y >> .config
+ echo CONFIG_WIRELESS_EXTENSION=y >> .config
+
+install: all
+ mkdir -p $(DESTDIR)/usr/local/sbin/
+ for i in $(ALL); do cp $$i $(DESTDIR)/usr/local/sbin/$$i; done
+
+OBJS = config.o \
+ eloop.o common.o md5.o \
+ rc4.o sha1.o aes_wrap.o
+OBJS_p = wpa_passphrase.o sha1.o md5.o
+OBJS_c = wpa_cli.o wpa_ctrl.o
+
+-include .config
+
+ifdef CONFIG_EAPOL_TEST
+CFLAGS += -Werror -DEAPOL_TEST
+endif
+
+ifdef CONFIG_DRIVER_HOSTAP
+CFLAGS += -DCONFIG_DRIVER_HOSTAP
+OBJS += driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_WEXT
+CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_PRISM54
+CFLAGS += -DCONFIG_DRIVER_PRISM54
+OBJS += driver_prism54.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_HERMES
+CFLAGS += -DCONFIG_DRIVER_HERMES
+OBJS += driver_hermes.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+CFLAGS += -DCONFIG_DRIVER_MADWIFI
+OBJS += driver_madwifi.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_ATMEL
+CFLAGS += -DCONFIG_DRIVER_ATMEL
+OBJS += driver_atmel.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_NDISWRAPPER
+CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER
+OBJS += driver_ndiswrapper.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_BROADCOM
+CFLAGS += -DCONFIG_DRIVER_BROADCOM
+OBJS += driver_broadcom.o
+endif
+
+ifdef CONFIG_DRIVER_IPW
+CFLAGS += -DCONFIG_DRIVER_IPW
+OBJS += driver_ipw.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_BSD
+CFLAGS += -DCONFIG_DRIVER_BSD
+OBJS += driver_bsd.o
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+CFLAGS += -DCONFIG_DRIVER_NDIS
+OBJS += driver_ndis.o driver_ndis_.o
+CONFIG_DNET_PCAP=y
+CONFIG_WINPCAP=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+CFLAGS += -DCONFIG_DRIVER_TEST
+OBJS += driver_test.o
+endif
+
+ifdef CONFIG_DNET_PCAP
+CFLAGS += -DUSE_DNET_PCAP
+ifdef CONFIG_WINPCAP
+CFLAGS += -DCONFIG_WINPCAP
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+else
+LIBS += -ldnet -lpcap
+endif
+endif
+
+ifdef CONFIG_EAP_TLS
+# EAP-TLS
+CFLAGS += -DEAP_TLS
+OBJS += eap_tls.o
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+# EAP-PEAP
+CFLAGS += -DEAP_PEAP
+OBJS += eap_peap.o
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_TLV=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+# EAP-TTLS
+CFLAGS += -DEAP_TTLS
+OBJS += eap_ttls.o
+MS_FUNCS=y
+TLS_FUNCS=y
+CONFIG_EAP_MD5=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_MD5
+# EAP-MD5 (also used by EAP-TTLS)
+CFLAGS += -DEAP_MD5
+OBJS += eap_md5.o
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+# backwards compatibility for old spelling
+ifdef CONFIG_MSCHAPV2
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+# EAP-MSCHAPv2 (also used by EAP-PEAP)
+CFLAGS += -DEAP_MSCHAPv2
+OBJS += eap_mschapv2.o
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GTC
+# EAP-GTC (also used by EAP-PEAP)
+CFLAGS += -DEAP_GTC
+OBJS += eap_gtc.o
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_OTP
+# EAP-OTP
+CFLAGS += -DEAP_OTP
+OBJS += eap_otp.o
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SIM
+# EAP-SIM
+CFLAGS += -DEAP_SIM
+OBJS += eap_sim.o
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_LEAP
+# EAP-LEAP
+CFLAGS += -DEAP_LEAP
+OBJS += eap_leap.o
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PSK
+# EAP-PSK
+CFLAGS += -DEAP_PSK
+OBJS += eap_psk.o
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_AKA
+# EAP-AKA
+CFLAGS += -DEAP_AKA
+OBJS += eap_aka.o
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += eap_sim_common.o
+endif
+
+ifdef CONFIG_EAP_TLV
+# EAP-TLV
+CFLAGS += -DEAP_TLV
+OBJS += eap_tlv.o
+endif
+
+ifdef CONFIG_EAP_FAST
+# EAP-FAST
+CFLAGS += -DEAP_FAST
+OBJS += eap_fast.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
+CFLAGS += -DIEEE8021X_EAPOL
+OBJS += eapol_sm.o eap.o
+endif
+
+ifdef CONFIG_PCSC
+# PC/SC interface for smartcards (USIM, GSM SIM)
+CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
+OBJS += pcsc_funcs.o
+# -lpthread may not be needed depending on how pcsc-lite was configured
+LIBS += -lpcsclite -lpthread
+endif
+
+ifdef TLS_FUNCS
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += eap_tls_common.o tls_openssl.o
+LIBS += -lssl -lcrypto
+LIBS_p += -lcrypto
+else
+OBJS += tls_none.o
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+ifndef TLS_FUNCS
+LIBS += -lcrypto
+endif
+OBJS += ms_funcs.o crypto.o
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+OBJS += driver_wext.o
+endif
+
+ifdef CONFIG_CTRL_IFACE
+CFLAGS += -DCONFIG_CTRL_IFACE
+OBJS += ctrl_iface.o
+endif
+
+ifdef CONFIG_XSUPPLICANT_IFACE
+CFLAGS += -DCONFIG_XSUPPLICANT_IFACE
+endif
+
+ifdef CONFIG_READLINE
+CFLAGS += -DCONFIG_READLINE
+LIBS_c += -lncurses -lreadline
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS -DCONFIG_CTRL_IFACE_UDP
+LIBS += -lws2_32 -lgdi32
+LIBS_c += -lws2_32
+endif
+
+OBJS_t := $(OBJS) eapol_test.o radius.o radius_client.o
+OBJS_t2 := $(OBJS) preauth_test.o l2_packet.o
+OBJS += wpa_supplicant.o wpa.o l2_packet.o drivers.o
+
+wpa_supplicant: .config $(OBJS)
+ $(CC) -o wpa_supplicant $(OBJS) $(LIBS)
+
+eapol_test: .config $(OBJS_t)
+ $(CC) -o eapol_test $(OBJS_t) $(LIBS)
+
+preauth_test: .config $(OBJS_t2)
+ $(CC) -o preauth_test $(OBJS_t2) $(LIBS)
+
+wpa_passphrase: $(OBJS_p)
+ $(CC) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+
+wpa_cli: $(OBJS_c)
+ $(CC) -o wpa_cli $(OBJS_c) $(LIBS_c)
+
+win_if_list: win_if_list.c
+ $(CC) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+
+# parameters for Microsoft Visual C++ Toolkit 2003 compiler
+CL=cl
+CLDIR=C:\Program Files\Microsoft Visual C++ Toolkit 2003
+PSDKDIR=C:\Program Files\Microsoft Platform SDK for Windows XP SP2
+CLFLAGS=-O
+CLLIBS=wbemuuid.lib libcmt.lib kernel32.lib uuid.lib ole32.lib oleaut32.lib \
+ ws2_32.lib
+
+ndis_events: ndis_events.cpp
+ INCLUDE="$(CLDIR)\include;$(PSDKDIR)\Include" \
+ LIB="$(CLDIR)\lib;$(PSDKDIR)\Lib" \
+ $(CL) $(CLFLAGS) -o ndis_events.exe ndis_events.cpp \
+ /link -nodefaultlib $(CLLIBS)
+
+wpa_supplicant.exe: wpa_supplicant
+ mv -f $< $@
+wpa_cli.exe: wpa_cli
+ mv -f $< $@
+wpa_passphrase.exe: wpa_passphrase
+ mv -f $< $@
+win_if_list.exe: win_if_list
+ mv -f $< $@
+
+WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
+
+windows-bin: $(WINALL)
+ $(STRIP) $(WINALL)
+
+TEST_SRC_MS_FUNCS = ms_funcs.c crypto.c sha1.c md5.c
+test-ms_funcs: $(TEST_SRC_MS_FUNCS)
+ $(CC) -o test-ms_funcs -Wall -Werror $(TEST_SRC_MS_FUNCS) \
+ -DTEST_MAIN_MS_FUNCS -lcrypto -I../hostapd
+ ./test-ms_funcs
+ rm test-ms_funcs
+
+TEST_SRC_SHA1 = sha1.c
+test-sha1: $(TEST_SRC_SHA1)
+ $(CC) -o test-sha1 -Wall -Werror $(TEST_SRC_SHA1) \
+ -DTEST_MAIN -I../hostad
+ ./test-sha1
+ rm test-sha1
+
+TEST_SRC_AES_WRAP = aes_wrap.c
+test-aes_wrap: $(TEST_SRC_AES_WRAP)
+ $(CC) -o test-aes_wrap -Wall -Werror $(TEST_SRC_AES_WRAP) \
+ -DTEST_MAIN -I../hostad
+ ./test-aes_wrap
+ rm test-aes_wrap
+
+TEST_SRC_EAP_SIM_COMMON = eap_sim_common.c sha1.c md5.c \
+ aes_wrap.c common.c
+test-eap_sim_common: $(TEST_SRC_EAP_SIM_COMMON)
+ $(CC) -o test-eap_sim_common -Wall -Werror $(TEST_SRC_EAP_SIM_COMMON) \
+ -DTEST_MAIN_EAP_SIM_COMMON -I../hostapd
+ ./test-eap_sim_common
+ rm test-eap_sim_common
+
+tests: test-ms_funcs test-sha1 test-aes_wrap test-eap_sim_common
+
+clean:
+ rm -f core *~ *.o *.d $(ALL) $(WINALL)
+
+-include $(OBJS:%.o=%.d)
diff --git a/contrib/wpa_supplicant/README b/contrib/wpa_supplicant/README
new file mode 100644
index 000000000000..7b5f5476a160
--- /dev/null
+++ b/contrib/wpa_supplicant/README
@@ -0,0 +1,860 @@
+WPA Supplicant
+==============
+
+Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> and
+contributors
+All Rights Reserved.
+
+This program is dual-licensed under both the GPL version 2 and BSD
+license. Either license may be used at your option. Please note that
+some of the driver interface implementations (driver_*.c) may be
+licensed under a different license.
+
+
+
+License
+-------
+
+GPL v2:
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+(this copy of the license is in COPYING file)
+
+
+Alternatively, this software may be distributed under the terms of BSD
+license:
+
+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. Neither the name(s) of the above-listed copyright holder(s) nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"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 COPYRIGHT
+OWNER 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.
+
+
+
+Features
+--------
+
+Supported WPA/IEEE 802.11i features:
+- WPA-PSK ("WPA-Personal")
+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
+ Following authentication methods are supported with an integrate IEEE 802.1X
+ Supplicant:
+ * EAP-TLS
+ * EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
+ * EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
+ * EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
+ * EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
+ * EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
+ * EAP-TTLS/EAP-MD5-Challenge
+ * EAP-TTLS/EAP-GTC
+ * EAP-TTLS/EAP-OTP
+ * EAP-TTLS/EAP-MSCHAPv2
+ * EAP-TTLS/EAP-TLS
+ * EAP-TTLS/MSCHAPv2
+ * EAP-TTLS/MSCHAP
+ * EAP-TTLS/PAP
+ * EAP-TTLS/CHAP
+ * EAP-SIM
+ * EAP-AKA
+ * EAP-PSK
+ * LEAP (note: requires special support from the driver for IEEE 802.11
+ authentication)
+ (following methods are supported, but since they do not generate keying
+ material, they cannot be used with WPA or IEEE 802.1X WEP keying)
+ * EAP-MD5-Challenge
+ * EAP-MSCHAPv2
+ * EAP-GTC
+ * EAP-OTP
+ Alternatively, an external program, e.g., Xsupplicant, can be used for EAP
+ authentication.
+- key management for CCMP, TKIP, WEP104, WEP40
+- RSN/WPA2 (IEEE 802.11i)
+ * pre-authentication
+ * PMKSA caching
+
+
+
+Requirements
+------------
+
+Current hardware/software requirements:
+- Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer
+- FreeBSD 6-CURRENT
+- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
+- drivers:
+ Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
+ (http://hostap.epitest.fi/)
+ Driver need to be set in Managed mode ('iwconfig wlan0 mode managed').
+ Please note that station firmware version needs to be 1.7.0 or newer
+ to work in WPA mode.
+
+ Linuxant DriverLoader (http://www.linuxant.com/driverloader/)
+ with Windows NDIS driver for your wlan card supporting WPA.
+
+ Agere Systems Inc. Linux Driver
+ (http://www.agere.com/support/drivers/)
+ Please note that the driver interface file (driver_hermes.c) and
+ hardware specific include files are not included in the
+ wpa_supplicant distribution. You will need to copy these from the
+ source package of the Agere driver.
+
+ madwifi driver for cards based on Atheros chip set (ar521x)
+ (http://sourceforge.net/projects/madwifi/)
+ Please note that you will need to modify the wpa_supplicant .config
+ file to use the correct path for the madwifi driver root directory
+ (CFLAGS += -I../madwifi/wpa line in example defconfig).
+
+ ATMEL AT76C5XXx driver for USB and PCMCIA cards
+ (http://atmelwlandriver.sourceforge.net/).
+
+ Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with
+ Windows NDIS driver.
+
+ Broadcom wl.o driver
+ This is a generic Linux driver for Broadcom IEEE 802.11a/g cards.
+ However, it is proprietary driver that is not publicly available
+ except for couple of exceptions, mainly Broadcom-based APs/wireless
+ routers that use Linux. The driver binary can be downloaded, e.g.,
+ from Linksys support site (http://www.linksys.com/support/gpl.asp)
+ for Linksys WRT54G. The GPL tarball includes cross-compiler and
+ the needed header file, wlioctl.h, for compiling wpa_supplicant.
+ This driver support in wpa_supplicant is expected to work also with
+ other devices based on Broadcom driver (assuming the driver includes
+ client mode support).
+
+ Intel ipw2100 driver
+ (http://sourceforge.net/projects/ipw2100/)
+
+ Intel ipw2200 driver
+ (http://sourceforge.net/projects/ipw2200/)
+
+ In theory, any driver that supports Linux wireless extensions can be
+ used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
+ configuration file.
+
+ BSD net80211 layer (e.g., Atheros driver)
+ At the moment, this is for FreeBSD 6-CURRENT branch.
+
+ Windows NDIS
+ The current Windows port requires WinPcap (http://winpcap.polito.it/).
+ See README-Windows.txt for more information.
+
+wpa_supplicant was designed to be portable for different drivers and
+operating systems. Hopefully, support for more wlan cards and OSes will be
+added in the future. See developer.txt for more information about the
+design of wpa_supplicant and porting to other drivers. One main goal
+is to add full WPA/WPA2 support to Linux wireless extensions to allow
+new drivers to be supported without having to implement new
+driver-specific interface code in wpa_supplicant.
+
+Optional libraries for layer2 packet processing:
+- libpcap (tested with 0.7.2, most relatively recent versions assumed to work,
+ this is likely to be available with most distributions,
+ http://tcpdump.org/)
+- libdnet (tested with v1.4, most versions assumed to work,
+ http://libdnet.sourceforge.net/)
+
+These libraries are _not_ used in the default Linux build. Instead,
+internal Linux specific implementation is used. libpcap/libdnet are
+more portable and they can be used by adding CONFIG_DNET_PCAP=y into
+.config. They may also be selected automatically for other operating
+systems.
+
+
+Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS:
+- openssl (tested with 0.9.7c and 0.9.7d, assumed to work with most
+ relatively recent versions; this is likely to be available with most
+ distributions, http://www.openssl.org/)
+
+This library is only needed when EAP-TLS, EAP-PEAP, or EAP-TTLS
+support is enabled. WPA-PSK mode does not require this or EAPOL/EAP
+implementation. A configuration file, .config, for compilation is
+needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5,
+EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so
+they should only be enabled if testing the EAPOL/EAP state
+machines. However, there can be used as inner authentication
+algorithms with EAP-PEAP and EAP-TTLS.
+
+See Building and installing section below for more detailed
+information about the wpa_supplicant build time configuration.
+
+
+
+WPA
+---
+
+The original security mechanism of IEEE 802.11 standard was not
+designed to be strong and has proven to be insufficient for most
+networks that require some kind of security. Task group I (Security)
+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
+to address the flaws of the base standard and has in practice
+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
+802.11 standard was approved in June 2004 and this amendment is likely
+to be published in July 2004.
+
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
+IEEE 802.11i work (draft 3.0) to define a subset of the security
+enhancements that can be implemented with existing wlan hardware. This
+is called Wi-Fi Protected Access<TM> (WPA). This has now become a
+mandatory component of interoperability testing and certification done
+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
+site (http://www.wi-fi.org/OpenSection/protected_access.asp).
+
+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
+for protecting wireless networks. WEP uses RC4 with 40-bit keys,
+24-bit initialization vector (IV), and CRC32 to protect against packet
+forgery. All these choices have proven to be insufficient: key space is
+too small against current attacks, RC4 key scheduling is insufficient
+(beginning of the pseudorandom stream should be skipped), IV space is
+too small and IV reuse makes attacks easier, there is no replay
+protection, and non-keyed authentication does not protect against bit
+flipping packet data.
+
+WPA is an intermediate solution for the security issues. It uses
+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
+compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+
+Keys can be managed using two different mechanisms. WPA can either use
+an external authentication server (e.g., RADIUS) and EAP just like
+IEEE 802.1X is using or pre-shared keys without need for additional
+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
+respectively. Both mechanisms will generate a master session key for
+the Authenticator (AP) and Supplicant (client station).
+
+WPA implements a new key handshake (4-Way Handshake and Group Key
+Handshake) for generating and exchanging data encryption keys between
+the Authenticator and Supplicant. This handshake is also used to
+verify that both Authenticator and Supplicant know the master session
+key. These handshakes are identical regardless of the selected key
+management mechanism (only the method for generating master session
+key changes).
+
+
+
+IEEE 802.11i / WPA2
+-------------------
+
+The design for parts of IEEE 802.11i that were not included in WPA has
+finished (May 2004) and this amendment to IEEE 802.11 was approved in
+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
+version of WPA called WPA2. This includes, e.g., support for more
+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
+to replace TKIP and optimizations for handoff (reduced number of
+messages in initial key handshake, pre-authentication, and PMKSA caching).
+
+Some wireless LAN vendors are already providing support for CCMP in
+their WPA products. There is no "official" interoperability
+certification for CCMP and/or mixed modes using both TKIP and CCMP, so
+some interoperability issues can be expected even though many
+combinations seem to be working with equipment from different vendors.
+Certification for WPA2 is likely to start during the second half of
+2004.
+
+
+
+wpa_supplicant
+--------------
+
+wpa_supplicant is an implementation of the WPA Supplicant component,
+i.e., the part that runs in the client stations. It implements WPA key
+negotiation with a WPA Authenticator and EAP authentication with
+Authentication Server. In addition, it controls the roaming and IEEE
+802.11 authentication/association of the wlan driver.
+
+wpa_supplicant is designed to be a "daemon" program that runs in the
+background and acts as the backend component controlling the wireless
+connection. wpa_supplicant supports separate frontend programs and an
+example text-based frontend, wpa_cli, is included with wpa_supplicant.
+
+Following steps are used when associating with an AP using WPA:
+
+- wpa_supplicant requests the kernel driver to scan neighboring BSSes
+- wpa_supplicant selects a BSS based on its configuration
+- wpa_supplicant requests the kernel driver to associate with the chosen
+ BSS
+- If WPA-EAP: integrated IEEE 802.1X Supplicant or external Xsupplicant
+ completes EAP authentication with the authentication server (proxied
+ by the Authenticator in the AP)
+- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant
+- If WPA-PSK: wpa_supplicant uses PSK as the master session key
+- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake
+ with the Authenticator (AP)
+- wpa_supplicant configures encryption keys for unicast and broadcast
+- normal data packets can be transmitted and received
+
+
+
+Building and installing
+-----------------------
+
+In order to be able to build wpa_supplicant, you will first need to
+select which parts of it will be included. This is done by creating a
+build time configuration file, .config, in the wpa_supplicant root
+directory. Configuration options are text lines using following
+format: CONFIG_<option>=y. Lines starting with # are considered
+comments and are ignored. See defconfig file for example configuration
+and list of available option.
+
+The build time configuration can be used to select only the needed
+features and limit the binary size and requirements for external
+libraries. The main configuration parts are the selection of which
+driver interfaces (e.g., hostap, madwifi, ..) and which authentication
+methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
+
+Following build time configuration options are used to control IEEE
+802.1X/EAPOL and EAP state machines and all EAP methods. Including
+TLS, PEAP, or TTLS will require linking wpa_supplicant with openssl
+library for TLS implementation.
+
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_MD5=y
+CONFIG_EAP_MSCHAPV2=y
+CONFIG_EAP_TLS=y
+CONFIG_EAP_PEAP=y
+CONFIG_EAP_TTLS=y
+CONFIG_EAP_GTC=y
+CONFIG_EAP_OTP=y
+CONFIG_EAP_SIM=y
+CONFIG_EAP_AKA=y
+CONFIG_EAP_PSK=y
+CONFIG_EAP_LEAP=y
+
+Following option can be used to include GSM SIM/USIM interface for GSM/UMTS
+authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite
+(http://www.linuxnet.com/) for smart card access.
+
+CONFIG_PCSC=y
+
+Following option can be used to replace the native Linux packet socket
+interface with libpcap/libdnet.
+
+CONFIG_DNET_PCAP=y
+
+Following options can be added to .config to select which driver
+interfaces are included. Prism54.org driver is not yet complete and
+Hermes driver interface needs to be downloaded from Agere (see above).
+Most Linux driver need to include CONFIG_WIRELESS_EXTENSION.
+
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_DRIVER_HOSTAP=y
+CONFIG_DRIVER_PRISM54=y
+CONFIG_DRIVER_HERMES=y
+CONFIG_DRIVER_MADWIFI=y
+CONFIG_DRIVER_ATMEL=y
+CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_NDISWRAPPER=y
+CONFIG_DRIVER_BROADCOM=y
+CONFIG_DRIVER_IPW=y
+CONFIG_DRIVER_BSD=y
+CONFIG_DRIVER_NDIS=y
+
+Following example includes all features and driver interfaces that are
+included in the wpa_supplicant package:
+
+CONFIG_DRIVER_HOSTAP=y
+CONFIG_DRIVER_PRISM54=y
+CONFIG_DRIVER_HERMES=y
+CONFIG_DRIVER_MADWIFI=y
+CONFIG_DRIVER_ATMEL=y
+CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_NDISWRAPPER=y
+CONFIG_DRIVER_BROADCOM=y
+CONFIG_DRIVER_IPW=y
+CONFIG_DRIVER_BSD=y
+CONFIG_DRIVER_NDIS=y
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_MD5=y
+CONFIG_EAP_MSCHAPV2=y
+CONFIG_EAP_TLS=y
+CONFIG_EAP_PEAP=y
+CONFIG_EAP_TTLS=y
+CONFIG_EAP_GTC=y
+CONFIG_EAP_OTP=y
+CONFIG_EAP_SIM=y
+CONFIG_EAP_AKA=y
+CONFIG_EAP_PSK=y
+CONFIG_EAP_LEAP=y
+CONFIG_PCSC=y
+
+EAP-PEAP and EAP-TTLS will automatically include configured EAP
+methods (MD5, OTP, GTC, MSCHAPV2) for inner authentication selection.
+
+
+After you have created a configuration file, you can build
+wpa_supplicant and wpa_cli with 'make' command. You may then install
+the binaries to a suitable system directory, e.g., /usr/local/bin.
+
+Example commands:
+
+# build wpa_supplicant and wpa_cli
+make
+# install binaries (this may need root privileges)
+cp wpa_cli wpa_supplicant /usr/local/bin
+
+
+You will need to make a configuration file, e.g.,
+/etc/wpa_supplicant.conf, with network configuration for the networks
+you are going to use. Configuration file section below includes
+explanation fo the configuration file format and includes various
+examples. Once the configuration is ready, you can test whether the
+configuration work by first running wpa_supplicant with following
+command to start it on foreground with debugging enabled:
+
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
+
+Assuming everything goes fine, you can start using following command
+to start wpa_supplicant on background without debugging:
+
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
+
+Please note that if you included more than one driver interface in the
+build time configuration (.config), you may need to specify which
+interface to use by including -D<driver name> option on the command
+line. See following section for more details on command line options
+for wpa_supplicant.
+
+
+
+Command line options
+--------------------
+
+usage:
+ wpa_supplicant [-BddehLqqvw] -i<ifname> -c<config file> [-D<driver>] \
+ [-N -i<ifname> -c<conf> [-D<driver>] ...]
+
+options:
+ -B = run daemon in the background
+ -d = increase debugging verbosity (-dd even more)
+ -K = include keys (passwords, etc.) in debug output
+ -t = include timestamp in debug messages
+ -e = use external IEEE 802.1X Supplicant (e.g., xsupplicant)
+ (this disables the internal Supplicant)
+ -h = show this help text
+ -L = show license (GPL and BSD)
+ -q = decrease debugging verbosity (-qq even less)
+ -v = show version
+ -w = wait for interface to be added, if needed
+ -N = start describing new interface
+
+drivers:
+ hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
+ (this can also be used with Linuxant DriverLoader)
+ prism54 = Prism54.org driver (Intersil Prism GT/Duette/Indigo)
+ not yet fully implemented
+ hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
+ madwifi = MADWIFI 802.11 support (Atheros, etc.)
+ atmel = ATMEL AT76C5XXx (USB, PCMCIA)
+ wext = Linux wireless extensions (generic)
+ ndiswrapper = Linux ndiswrapper
+ broadcom = Broadcom wl.o driver
+ ipw = Intel ipw2100/2200 driver
+ bsd = BSD 802.11 support (Atheros, etc.)
+ ndis = Windows NDIS driver
+
+In most common cases, wpa_supplicant is started with
+
+wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -iwlan0
+
+This makes the process fork into background and wait for the wlan0
+interface if it is not available at startup time.
+
+The easiest way to debug problems, and to get debug log for bug
+reports, is to start wpa_supplicant on foreground with debugging
+enabled:
+
+wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
+
+
+wpa_supplicant can control multiple interfaces (radios) either by
+running one process for each interface separately or by running just
+one process and list of options at command line. Each interface is
+separated with -N argument. As an example, following command would
+start wpa_supplicant for two interfaces:
+
+wpa_supplicant \
+ -c wpa1.conf -i wlan0 -D hostap -N \
+ -c wpa2.conf -i ath0 -D madwifi
+
+
+Configuration file
+------------------
+
+wpa_supplicant is configured using a text file that lists all accepted
+networks and security policies, including pre-shared keys. See
+example configuration file, wpa_supplicant.conf, for detailed
+information about the configuration format and supported fields.
+
+Changes to configuration file can be reloaded be sending SIGHUP signal
+to wpa_supplicant ('killall -HUP wpa_supplicant'). Similarly,
+reloading can be triggered with 'wpa_cli reconfigure' command.
+
+Configuration file can include one or more network blocks, e.g., one
+for each used SSID. wpa_supplicant will automatically select the best
+betwork based on the order of network blocks in the configuration
+file, network security level (WPA/WPA2 is prefered), and signal
+strength.
+
+Example configuration files for some common configurations:
+
+1) WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work
+ network
+
+# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+#
+# home network; allow all valid ciphers
+network={
+ ssid="home"
+ scan_ssid=1
+ key_mgmt=WPA-PSK
+ psk="very secret passphrase"
+}
+#
+# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
+network={
+ ssid="work"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ pairwise=CCMP TKIP
+ group=CCMP TKIP
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+}
+
+
+2) WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel
+ (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series)
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=PEAP
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase1="peaplabel=0"
+ phase2="auth=MSCHAPV2"
+}
+
+
+3) EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
+ unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="user@example.com"
+ anonymous_identity="anonymous@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase2="auth=MD5"
+}
+
+
+4) IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and
+ broadcast); use EAP-TLS for authentication
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="1x-test"
+ scan_ssid=1
+ key_mgmt=IEEE8021X
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ eapol_flags=3
+}
+
+
+5) Catch all example that allows more or less all configuration modes. The
+ configuration options are used based on what security policy is used in the
+ selected SSID. This is mostly for testing and is not recommended for normal
+ use.
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+ pairwise=CCMP TKIP
+ group=CCMP TKIP WEP104 WEP40
+ psk="very secret passphrase"
+ eap=TTLS PEAP TLS
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ phase1="peaplabel=0"
+ ca_cert2="/etc/cert/ca2.pem"
+ client_cert2="/etc/cer/user.pem"
+ private_key2="/etc/cer/user.prv"
+ private_key2_passwd="password"
+}
+
+
+
+Certificates
+------------
+
+Some EAP authentication methods require use of certificates. EAP-TLS
+uses both server side and client certificates whereas EAP-PEAP and
+EAP-TTLS only require the server side certificate. When client
+certificate is used, a matching private key file has to also be
+included in configuration. If the private key uses a passphrase, this
+has to be configured in wpa_supplicant.conf ("private_key_passwd").
+
+wpa_supplicant supports X.509 certificates in PEM and DER
+formats. User certificate and private key can be included in the same
+file.
+
+If the user certificate and private key is received in PKCS#12/PFX
+format, they need to be converted to suitable PEM/DER format for
+wpa_supplicant. This can be done, e.g., with following commands:
+
+# convert client certificate and private key to PEM format
+openssl pkcs12 -in example.pfx -out user.pem -clcerts
+# convert CA certificate (if included in PFX file) to PEM format
+openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
+
+
+
+wpa_cli
+-------
+
+wpa_cli is a text-based frontend program for interacting with
+wpa_supplicant. It is used to query current status, change
+configuration, trigger events, and request interactive user input.
+
+wpa_cli can show the current authentication status, selected security
+mode, dot11 and dot1x MIBs, etc. In addition, it can configuring some
+variables like EAPOL state machine parameters and trigger events like
+reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user
+interface to request authentication information, like username and
+password, if these are not included in the configuration. This can be
+used to implement, e.g., one-time-passwords or generic token card
+authentication where the authentication is based on a
+challenge-response that uses an external device for generating the
+response.
+
+The control interface of wpa_supplicant can be configured to allow
+non-root user access (ctrl_interface_group in the configuration
+file). This makes it possible to run wpa_cli with a normal user
+account.
+
+wpa_cli supports two modes: interactive and command line. Both modes
+share the same command set and the main difference is in interactive
+mode providing access to unsolicited messages (event messages,
+username/password requests).
+
+Interactive mode is started when wpa_cli is executed without including
+the command as a command line parameter. Commands are then entered on
+the wpa_cli prompt. In command line mode, the same commands are
+entered as command line arguments for wpa_cli.
+
+
+Interactive authentication parameters request
+
+When wpa_supplicant need authentication parameters, like username and
+password, which are not present in the configuration file, it sends a
+request message to all attached frontend programs, e.g., wpa_cli in
+interactive mode. wpa_cli shows these requests with
+"CTRL-REQ-<type>-<id>:<text>" prefix. <type> is IDENTITY, PASSWORD, or
+OTP (one-time-password). <id> is a unique identifier for the current
+network. <text> is description of the request. In case of OTP request,
+it includes the challenge from the authentication server.
+
+The reply to these requests can be given with 'identity', 'password',
+and 'otp' commands. <id> needs to be copied from the the matching
+request. 'password' and 'otp' commands can be used regardless of
+whether the request was for PASSWORD or OTP. The main difference
+between these two commands is that values given with 'password' are
+remembered as long as wpa_supplicant is running whereas values given
+with 'otp' are used only once and then forgotten, i.e., wpa_supplicant
+will ask frontend for a new value for every use. This can be used to
+implement one-time-password lists and generic token card -based
+authentication.
+
+Example request for password and a matching reply:
+
+CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
+> password 1 mysecretpassword
+
+Example request for generic token card challenge-response:
+
+CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
+> otp 2 9876
+
+
+wpa_cli commands
+
+ status = get current WPA/EAPOL/EAP status
+ mib = get MIB variables (dot1x, dot11)
+ help = show this usage help
+ interface [ifname] = show interfaces/select interface
+ level <debug level> = change debug level
+ license = show full wpa_cli license
+ logoff = IEEE 802.1X EAPOL state machine logoff
+ logon = IEEE 802.1X EAPOL state machine logon
+ set = set variables (shows list of variables when run without arguments)
+ pmksa = show PMKSA cache
+ reassociate = force reassociation
+ reconfigure = force wpa_supplicant to re-read its configuration file
+ preauthenticate <BSSID> = force preauthentication
+ identity <network id> <identity> = configure identity for an SSID
+ password <network id> <password> = configure password for an SSID
+ otp <network id> <password> = configure one-time-password for an SSID
+ terminate = terminate wpa_supplicant
+ quit = exit wpa_cli
+
+
+
+Integrating with pcmcia-cs/cardmgr scripts
+------------------------------------------
+
+wpa_supplicant needs to be running when using a wireless network with
+WPA. It can be started either from system startup scripts or from
+pcmcia-cs/cardmgr scripts (when using PC Cards). WPA handshake must be
+completed before data frames can be exchanged, so wpa_supplicant
+should be started before DHCP client.
+
+Command line option '-w' can be used if wpa_supplicant is started
+before the wireless LAN interface is present (e.g., before inserting
+the PC Card) or is not yet up.
+
+For example, following small changes to pcmcia-cs scripts can be used
+to enable WPA support:
+
+Add MODE="Managed" and WPA="y" to the network scheme in
+/etc/pcmcia/wireless.opts.
+
+Add the following block to the end of 'start' action handler in
+/etc/pcmcia/wireless:
+
+ if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ /usr/local/bin/wpa_supplicant -Bw -c/etc/wpa_supplicant.conf \
+ -i$DEVICE
+ fi
+
+Add the following block to the end of 'stop' action handler (may need
+to be separated from other actions) in /etc/pcmcia/wireless:
+
+ if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ killall wpa_supplicant
+ fi
+
+This will make cardmgr start wpa_supplicant when the card is plugged
+in. wpa_supplicant will wait until the interface is set up--either
+when a static IP address is configured or when DHCP client is
+started--and will then negotiate keys with the AP.
+
+
+
+Optional integration with Xsupplicant
+-------------------------------------
+
+wpa_supplicant has an integrated IEEE 802.1X Supplicant that supports
+most commonly used EAP methods. In addition, wpa_supplicant has an
+experimental interface for integrating it with Xsupplicant
+(http://www.open1x.org/) for the WPA with EAP authentication.
+
+When using WPA-EAP, both wpa_supplicant and Xsupplicant must be
+configured with the network security policy. See Xsupplicant documents
+for information about its configuration. Please also note, that a new
+command line option -W (enable WPA) must be used when starting
+xsupplicant.
+
+Example configuration for xsupplicant:
+
+network_list = all
+default_netname = jkm
+
+jkm
+{
+ type = wireless
+ allow_types = eap_peap
+ identity = <BEGIN_ID>jkm<END_ID>
+ eap-peap {
+ random_file = /dev/urandom
+ root_cert = /home/jkm/CA.pem
+ chunk_size = 1398
+ allow_types = eap_mschapv2
+ eap-mschapv2 {
+ username = <BEGIN_UNAME>jkm<END_UNAME>
+ password = <BEGIN_PASS>jkm<END_PASS>
+ }
+ }
+}
+
+
+Example configuration for wpa_supplicant:
+
+network={
+ ssid="jkm"
+ key_mgmt=WPA-EAP
+}
+
+
+Both wpa_supplicant and xsupplicant need to be started. Please remember
+to add '-W' option for xsupplicant in order to provide keying material
+for wpa_supplicant and '-e' option for wpa_supplicant to disable internal
+IEEE 802.1X implementation.
+
+wpa_supplicant -iwlan0 -cwpa_supplicant.conf -e
+xsupplicant -iwlan0 -cxsupplicant.conf -W
diff --git a/contrib/wpa_supplicant/aes.c b/contrib/wpa_supplicant/aes.c
new file mode 100644
index 000000000000..eabebd074653
--- /dev/null
+++ b/contrib/wpa_supplicant/aes.c
@@ -0,0 +1,1132 @@
+/*
+ * Modifications to public domain implementation:
+ * - support only 128-bit keys
+ * - cleanup
+ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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.
+ */
+
+/**
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * 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.
+ */
+
+#define FULL_UNROLL
+
+
+/*
+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];
+*/
+
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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,
+};
+static 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 */
+};
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#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
+
+/**
+ * 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] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ rk += 4;
+ }
+}
+
+/**
+ * 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;
+ rk[0] =
+ Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[0] ) & 0xff] & 0xff];
+ rk[1] =
+ Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[1] ) & 0xff] & 0xff];
+ rk[2] =
+ Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[2] ) & 0xff] & 0xff];
+ rk[3] =
+ Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[3] ) & 0xff] & 0xff];
+ }
+}
+
+void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+{
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+ 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];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Te0[(t0 >> 24) ] ^
+ Te1[(t1 >> 16) & 0xff] ^
+ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Te0[(t1 >> 24) ] ^
+ Te1[(t2 >> 16) & 0xff] ^
+ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Te0[(t2 >> 24) ] ^
+ Te1[(t3 >> 16) & 0xff] ^
+ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Te0[(t3 >> 24) ] ^
+ Te1[(t0 >> 16) & 0xff] ^
+ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Te4[(t0 >> 24) ] & 0xff000000) ^
+ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(ct , s0);
+ s1 =
+ (Te4[(t1 >> 24) ] & 0xff000000) ^
+ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(ct + 4, s1);
+ s2 =
+ (Te4[(t2 >> 24) ] & 0xff000000) ^
+ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(ct + 8, s2);
+ s3 =
+ (Te4[(t3 >> 24) ] & 0xff000000) ^
+ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(ct + 12, s3);
+}
+
+void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
+{
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+ 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];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Td0[(t0 >> 24) ] ^
+ Td1[(t3 >> 16) & 0xff] ^
+ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Td0[(t1 >> 24) ] ^
+ Td1[(t0 >> 16) & 0xff] ^
+ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Td0[(t2 >> 24) ] ^
+ Td1[(t1 >> 16) & 0xff] ^
+ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Td0[(t3 >> 24) ] ^
+ Td1[(t2 >> 16) & 0xff] ^
+ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Td4[(t0 >> 24) ] & 0xff000000) ^
+ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(pt , s0);
+ s1 =
+ (Td4[(t1 >> 24) ] & 0xff000000) ^
+ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(pt + 4, s1);
+ s2 =
+ (Td4[(t2 >> 24) ] & 0xff000000) ^
+ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(pt + 8, s2);
+ s3 =
+ (Td4[(t3 >> 24) ] & 0xff000000) ^
+ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(pt + 12, s3);
+}
diff --git a/contrib/wpa_supplicant/aes_wrap.c b/contrib/wpa_supplicant/aes_wrap.c
new file mode 100644
index 000000000000..dbcc136517e7
--- /dev/null
+++ b/contrib/wpa_supplicant/aes_wrap.c
@@ -0,0 +1,642 @@
+/*
+ * 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-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "common.h"
+#include "aes_wrap.h"
+
+#ifdef EAP_TLS_FUNCS
+
+#include <openssl/aes.h>
+
+#else /* EAP_TLS_FUNCS */
+
+#include "aes.c"
+
+struct aes_key_st {
+ u32 rk[44];
+};
+typedef struct aes_key_st AES_KEY;
+
+#define AES_set_encrypt_key(userKey, bits, key) \
+ rijndaelKeySetupEnc((key)->rk, (userKey))
+#define AES_set_decrypt_key(userKey, bits, key) \
+ rijndaelKeySetupDec((key)->rk, (userKey))
+#define AES_encrypt(in, out, key) \
+ rijndaelEncrypt((key)->rk, in, out)
+#define AES_decrypt(in, out, key) \
+ rijndaelDecrypt((key)->rk, in, out)
+
+#endif /* EAP_TLS_FUNCS */
+
+
+/*
+ * @kek: key encryption key (KEK)
+ * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
+ * @plain: plaintext key to be wrapped, n * 64 bit
+ * @cipher: wrapped key, (n + 1) * 64 bit
+ */
+void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
+{
+ u8 *a, *r, b[16];
+ int i, j;
+ AES_KEY key;
+
+ a = cipher;
+ r = cipher + 8;
+
+ /* 1) Initialize variables. */
+ memset(a, 0xa6, 8);
+ memcpy(r, plain, 8 * n);
+
+ AES_set_encrypt_key(kek, 128, &key);
+
+ /* 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++) {
+ memcpy(b, a, 8);
+ memcpy(b + 8, r, 8);
+ AES_encrypt(b, b, &key);
+ memcpy(a, b, 8);
+ a[7] ^= n * j + i;
+ memcpy(r, b + 8, 8);
+ r += 8;
+ }
+ }
+
+ /* 3) Output the results.
+ *
+ * These are already in @cipher due to the location of temporary
+ * variables.
+ */
+}
+
+
+/*
+ * @kek: key encryption key (KEK)
+ * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
+ * @cipher: wrapped key to be unwrapped, (n + 1) * 64 bit
+ * @plain: plaintext key, n * 64 bit
+ */
+int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain)
+{
+ u8 a[8], *r, b[16];
+ int i, j;
+ AES_KEY key;
+
+ /* 1) Initialize variables. */
+ memcpy(a, cipher, 8);
+ r = plain;
+ memcpy(r, cipher + 8, 8 * n);
+
+ AES_set_decrypt_key(kek, 128, &key);
+
+ /* 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--) {
+ memcpy(b, a, 8);
+ b[7] ^= n * j + i;
+
+ memcpy(b + 8, r, 8);
+ AES_decrypt(b, b, &key);
+ memcpy(a, b, 8);
+ memcpy(r, b + 8, 8);
+ r -= 8;
+ }
+ }
+
+ /* 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;
+}
+
+
+#define BLOCK_SIZE 16
+
+static void gf_mulx(u8 *pad)
+{
+ int i, carry;
+
+ carry = pad[0] & 0x80;
+ for (i = 0; i < BLOCK_SIZE - 1; i++)
+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+ pad[BLOCK_SIZE - 1] <<= 1;
+ if (carry)
+ pad[BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ AES_KEY akey;
+ u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
+ const u8 *pos = data;
+ int i;
+ size_t left = data_len;
+
+ AES_set_encrypt_key(key, 128, &akey);
+ memset(cbc, 0, BLOCK_SIZE);
+
+ while (left >= BLOCK_SIZE) {
+ for (i = 0; i < BLOCK_SIZE; i++)
+ cbc[i] ^= *pos++;
+ if (left > BLOCK_SIZE)
+ AES_encrypt(cbc, cbc, &akey);
+ left -= BLOCK_SIZE;
+ }
+
+ memset(pad, 0, BLOCK_SIZE);
+ AES_encrypt(pad, pad, &akey);
+ gf_mulx(pad);
+
+ if (left || data_len == 0) {
+ for (i = 0; i < left; i++)
+ cbc[i] ^= *pos++;
+ cbc[left] ^= 0x80;
+ gf_mulx(pad);
+ }
+
+ for (i = 0; i < BLOCK_SIZE; i++)
+ pad[i] ^= cbc[i];
+ AES_encrypt(pad, mac, &akey);
+}
+
+
+void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
+{
+ AES_KEY akey;
+ AES_set_encrypt_key(key, 128, &akey);
+ AES_encrypt(in, out, &akey);
+}
+
+
+void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len)
+{
+ AES_KEY akey;
+ size_t len, left = data_len;
+ int i;
+ u8 *pos = data;
+ u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
+
+ AES_set_encrypt_key(key, 128, &akey);
+ memcpy(counter, nonce, BLOCK_SIZE);
+
+ while (left > 0) {
+ AES_encrypt(counter, buf, &akey);
+
+ len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
+ for (i = 0; i < len; i++)
+ pos[i] ^= buf[i];
+ pos += len;
+ left -= len;
+
+ for (i = BLOCK_SIZE - 1; i >= 0; i--) {
+ counter[i]++;
+ if (counter[i])
+ break;
+ }
+ }
+}
+
+
+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[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[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 = malloc(buf_len);
+ if (buf == NULL)
+ return -1;
+
+ memset(buf, 0, 15);
+
+ buf[15] = 0;
+ memcpy(buf + 16, nonce, nonce_len);
+ omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
+
+ buf[15] = 1;
+ memcpy(buf + 16, hdr, hdr_len);
+ omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
+
+ aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
+ buf[15] = 2;
+ memcpy(buf + 16, data, data_len);
+ omac1_aes_128(key, buf, 16 + data_len, data_mac);
+
+ free(buf);
+
+ for (i = 0; i < BLOCK_SIZE; i++)
+ tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
+
+ return 0;
+}
+
+
+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[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[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 = malloc(buf_len);
+ if (buf == NULL)
+ return -1;
+
+ memset(buf, 0, 15);
+
+ buf[15] = 0;
+ memcpy(buf + 16, nonce, nonce_len);
+ omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
+
+ buf[15] = 1;
+ memcpy(buf + 16, hdr, hdr_len);
+ omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
+
+ buf[15] = 2;
+ memcpy(buf + 16, data, data_len);
+ omac1_aes_128(key, buf, 16 + data_len, data_mac);
+
+ free(buf);
+
+ for (i = 0; i < BLOCK_SIZE; i++) {
+ if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
+ return -2;
+ }
+
+ aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
+
+ return 0;
+}
+
+
+void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len)
+{
+ AES_KEY akey;
+ u8 cbc[BLOCK_SIZE];
+ u8 *pos = data;
+ int i, j, blocks;
+
+ AES_set_encrypt_key(key, 128, &akey);
+ memcpy(cbc, iv, BLOCK_SIZE);
+
+ blocks = data_len / BLOCK_SIZE;
+ for (i = 0; i < blocks; i++) {
+ for (j = 0; j < BLOCK_SIZE; j++)
+ cbc[j] ^= pos[j];
+ AES_encrypt(cbc, cbc, &akey);
+ memcpy(pos, cbc, BLOCK_SIZE);
+ pos += BLOCK_SIZE;
+ }
+}
+
+
+void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len)
+{
+ AES_KEY akey;
+ u8 cbc[BLOCK_SIZE], tmp[BLOCK_SIZE];
+ u8 *pos = data;
+ int i, j, blocks;
+
+ AES_set_decrypt_key(key, 128, &akey);
+ memcpy(cbc, iv, BLOCK_SIZE);
+
+ blocks = data_len / BLOCK_SIZE;
+ for (i = 0; i < blocks; i++) {
+ memcpy(tmp, pos, BLOCK_SIZE);
+ AES_decrypt(pos, pos, &akey);
+ for (j = 0; j < BLOCK_SIZE; j++)
+ pos[j] ^= cbc[j];
+ memcpy(cbc, tmp, BLOCK_SIZE);
+ pos += BLOCK_SIZE;
+ }
+}
+
+
+#ifdef TEST_MAIN
+
+#ifdef __i386__
+#define rdtscll(val) \
+ __asm__ __volatile__("rdtsc" : "=A" (val))
+
+static void test_aes_perf(void)
+{
+ const int num_iters = 10;
+ int i;
+ unsigned int start, end;
+ AES_KEY akey;
+ u8 key[16], pt[16], ct[16];
+
+ printf("keySetupEnc:");
+ for (i = 0; i < num_iters; i++) {
+ rdtscll(start);
+ AES_set_encrypt_key(key, 128, &akey);
+ rdtscll(end);
+ printf(" %d", end - start);
+ }
+ printf("\n");
+
+ printf("Encrypt:");
+ for (i = 0; i < num_iters; i++) {
+ rdtscll(start);
+ AES_encrypt(pt, ct, &akey);
+ rdtscll(end);
+ printf(" %d", end - start);
+ }
+ printf("\n");
+}
+#endif /* __i386__ */
+
+
+static int test_eax(void)
+{
+ u8 msg[] = { 0xF7, 0xFB };
+ u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
+ 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
+ u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
+ 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
+ u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
+ u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
+ 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
+ 0x67, 0xE5 };
+ u8 data[sizeof(msg)], tag[BLOCK_SIZE];
+
+ memcpy(data, msg, sizeof(msg));
+ if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ printf("AES-128 EAX mode encryption failed\n");
+ return 1;
+ }
+ if (memcmp(data, cipher, sizeof(data)) != 0) {
+ printf("AES-128 EAX mode encryption returned invalid cipher "
+ "text\n");
+ return 1;
+ }
+ if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
+ printf("AES-128 EAX mode encryption returned invalid tag\n");
+ return 1;
+ }
+
+ if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ printf("AES-128 EAX mode decryption failed\n");
+ return 1;
+ }
+ if (memcmp(data, msg, sizeof(data)) != 0) {
+ printf("AES-128 EAX mode decryption returned invalid plain "
+ "text\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int test_cbc(void)
+{
+ struct cbc_test_vector {
+ u8 key[16];
+ u8 iv[16];
+ u8 plain[32];
+ u8 cipher[32];
+ size_t len;
+ } vectors[] = {
+ {
+ { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+ 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+ { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+ 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+ "Single block msg",
+ { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
+ 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
+ 16
+ },
+ {
+ { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+ 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+ { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+ 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+ { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
+ 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
+ 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
+ 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
+ 32
+ }
+ };
+ int i, ret = 0;
+ u8 *buf;
+
+ for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) {
+ struct cbc_test_vector *tv = &vectors[i];
+ buf = malloc(tv->len);
+ if (buf == NULL) {
+ ret++;
+ break;
+ }
+ memcpy(buf, tv->plain, tv->len);
+ aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len);
+ if (memcmp(buf, tv->cipher, tv->len) != 0) {
+ printf("AES-CBC encrypt %d failed\n", i);
+ ret++;
+ }
+ memcpy(buf, tv->cipher, tv->len);
+ aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len);
+ if (memcmp(buf, tv->plain, tv->len) != 0) {
+ printf("AES-CBC decrypt %d failed\n", i);
+ ret++;
+ }
+ free(buf);
+ }
+
+ return ret;
+}
+
+
+/* OMAC1 AES-128 test vectors from
+ * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
+ */
+
+struct omac1_test_vector {
+ u8 k[16];
+ u8 msg[64];
+ int msg_len;
+ u8 tag[16];
+};
+
+static struct omac1_test_vector test_vectors[] =
+{
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { },
+ 0,
+ { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ 16,
+ { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+ 40,
+ { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+ 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+ 64,
+ { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+ },
+};
+
+
+int main(int argc, char *argv[])
+{
+ u8 kek[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ u8 plain[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt[] = {
+ 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
+ 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
+ 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
+ };
+ u8 result[24];
+ int ret = 0, i;
+ struct omac1_test_vector *tv;
+
+ aes_wrap(kek, 2, plain, result);
+ if (memcmp(result, crypt, 24) != 0) {
+ printf("AES-WRAP-128-128 failed\n");
+ ret++;
+ }
+ if (aes_unwrap(kek, 2, crypt, result)) {
+ printf("AES-UNWRAP-128-128 reported failure\n");
+ ret++;
+ }
+ if (memcmp(result, plain, 16) != 0) {
+ int i;
+ printf("AES-UNWRAP-128-128 failed\n");
+ ret++;
+ for (i = 0; i < 16; i++)
+ printf(" %02x", result[i]);
+ printf("\n");
+ }
+
+#ifdef __i386__
+ test_aes_perf();
+#endif /* __i386__ */
+
+ for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
+ tv = &test_vectors[i];
+ omac1_aes_128(tv->k, tv->msg, tv->msg_len, result);
+ if (memcmp(result, tv->tag, 16) != 0) {
+ printf("OMAC1-AES-128 test vector %d failed\n", i);
+ ret++;
+ }
+ }
+
+ ret += test_eax();
+
+ ret += test_cbc();
+
+ if (ret)
+ printf("FAILED!\n");
+
+ return ret;
+}
+#endif /* TEST_MAIN */
diff --git a/contrib/wpa_supplicant/aes_wrap.h b/contrib/wpa_supplicant/aes_wrap.h
new file mode 100644
index 000000000000..70e83ea09d73
--- /dev/null
+++ b/contrib/wpa_supplicant/aes_wrap.h
@@ -0,0 +1,21 @@
+#ifndef AES_WRAP_H
+#define AES_WRAP_H
+
+void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher);
+int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain);
+void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
+void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len);
+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);
+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);
+void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len);
+void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len);
+
+#endif /* AES_WRAP_H */
diff --git a/contrib/wpa_supplicant/common.c b/contrib/wpa_supplicant/common.c
new file mode 100644
index 000000000000..071ffe87c1d1
--- /dev/null
+++ b/contrib/wpa_supplicant/common.c
@@ -0,0 +1,335 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / common helper functions, etc.
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "common.h"
+
+
+int wpa_debug_level = MSG_INFO;
+int wpa_debug_show_keys = 0;
+int wpa_debug_timestamp = 0;
+
+
+int hostapd_get_rand(u8 *buf, size_t len)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ int i;
+ /* FIX: use more secure pseudo random number generator */
+ for (i = 0; i < len; i++) {
+ buf[i] = rand();
+ }
+ return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+ FILE *f;
+ size_t rc;
+
+ f = fopen("/dev/urandom", "r");
+ 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;
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void hostapd_hexdump(const char *title, const u8 *buf, size_t len)
+{
+ size_t i;
+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ printf("\n");
+}
+
+
+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;
+}
+
+
+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;
+}
+
+
+int hexstr2bin(const char *hex, u8 *buf, size_t len)
+{
+ int i, 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;
+}
+
+
+char * 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 strdup(rel_path);
+
+ for (;;) {
+ buf = malloc(len);
+ if (buf == NULL)
+ return NULL;
+ cwd = getcwd(buf, len);
+ if (cwd == NULL) {
+ 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 = malloc(ret_len);
+ if (ret) {
+ memcpy(ret, cwd, cwd_len);
+ ret[cwd_len] = '/';
+ memcpy(ret + cwd_len + 1, rel_path, rel_len);
+ ret[ret_len - 1] = '\0';
+ }
+ free(buf);
+ return ret;
+}
+
+
+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 print_char(char c)
+{
+ if (c >= 32 && c < 127)
+ printf("%c", c);
+ else
+ printf("<%02x>", c);
+}
+
+
+void fprint_char(FILE *f, char c)
+{
+ if (c >= 32 && c < 127)
+ fprintf(f, "%c", c);
+ else
+ fprintf(f, "<%02x>", c);
+}
+
+
+static void wpa_debug_print_timestamp(void)
+{
+ struct timeval tv;
+ char buf[16];
+
+ if (!wpa_debug_timestamp)
+ return;
+
+ gettimeofday(&tv, NULL);
+ if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S",
+ localtime((const time_t *) &tv.tv_sec)) <= 0) {
+ snprintf(buf, sizeof(buf), "%u", (int) tv.tv_sec);
+ }
+ printf("%s.%06u: ", buf, (unsigned int) tv.tv_usec);
+}
+
+
+void wpa_printf(int level, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (level >= wpa_debug_level) {
+ wpa_debug_print_timestamp();
+ vprintf(fmt, ap);
+ printf("\n");
+ }
+ 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();
+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+ if (show) {
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ } else {
+ printf(" [REMOVED]");
+ }
+ printf("\n");
+}
+
+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)
+{
+ int i, llen;
+ const u8 *pos = buf;
+ const int line_len = 16;
+
+ if (level < wpa_debug_level)
+ return;
+ wpa_debug_print_timestamp();
+ if (!show) {
+ printf("%s - hexdump_ascii(len=%lu): [REMOVED]\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;
+ }
+}
+
+
+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);
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+#define EPOCHFILETIME (116444736000000000ULL)
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ FILETIME ft;
+ LARGE_INTEGER li;
+ ULONGLONG t;
+
+ GetSystemTimeAsFileTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ t = (li.QuadPart - EPOCHFILETIME) / 10;
+ tv->tv_sec = (long) (t / 1000000);
+ tv->tv_usec = (long) (t % 1000000);
+
+ return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/wpa_supplicant/common.h b/contrib/wpa_supplicant/common.h
new file mode 100644
index 000000000000..aa6429c76b96
--- /dev/null
+++ b/contrib/wpa_supplicant/common.h
@@ -0,0 +1,222 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#ifdef __linux__
+#include <endian.h>
+#include <byteswap.h>
+#endif
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/endian.h>
+#define bswap_16 bswap16
+#define bswap_32 bswap32
+#endif
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+#include <winsock2.h>
+
+static inline int daemon(int nochdir, int noclose)
+{
+ printf("Windows - daemon() not supported yet\n");
+ return -1;
+}
+
+static inline void sleep(int seconds)
+{
+ Sleep(seconds * 1000);
+}
+
+static inline void usleep(unsigned long usec)
+{
+ Sleep(usec / 1000);
+}
+
+#ifndef timersub
+#define timersub(a, b, res) do { \
+ (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((res)->tv_usec < 0) { \
+ (res)->tv_sec--; \
+ (res)->tv_usec += 1000000; \
+ } \
+} while (0)
+#endif
+
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+
+int gettimeofday(struct timeval *tv, struct timezone *tz);
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#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)
+
+#else /* __CYGWIN__ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define le_to_host16(n) (n)
+#define host_to_le16(n) (n)
+#define be_to_host16(n) bswap_16(n)
+#define host_to_be16(n) bswap_16(n)
+#define le_to_host32(n) (n)
+#define be_to_host32(n) bswap_32(n)
+#define host_to_be32(n) bswap_32(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)
+#ifndef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN
+#endif
+#else
+#error Could not determine CPU byte order
+#endif
+
+#endif /* __CYGWIN__ */
+
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+#include <stdint.h>
+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;
+
+int hostapd_get_rand(u8 *buf, size_t len);
+void hostapd_hexdump(const char *title, const u8 *buf, size_t len);
+int hwaddr_aton(const char *txt, u8 *addr);
+int hexstr2bin(const char *hex, u8 *buf, size_t len);
+char * rel2abs_path(const char *rel_path);
+void inc_byte_array(u8 *counter, size_t len);
+void print_char(char c);
+void fprint_char(FILE *f, char c);
+
+
+/* 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 };
+
+/**
+ * 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, char *fmt, ...)
+__attribute__ ((format (printf, 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+#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 /* COMMON_H */
diff --git a/contrib/wpa_supplicant/config.c b/contrib/wpa_supplicant/config.c
new file mode 100644
index 000000000000..241c75565f88
--- /dev/null
+++ b/contrib/wpa_supplicant/config.c
@@ -0,0 +1,1051 @@
+/*
+ * WPA Supplicant / Configuration file parser
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "wpa.h"
+#include "config.h"
+#include "sha1.h"
+#include "wpa_supplicant.h"
+#include "eapol_sm.h"
+#include "eap.h"
+#include "config.h"
+
+
+struct parse_data {
+ char *name;
+ int (*parser)(struct parse_data *data, int line, const char *value);
+ void *param1, *param2, *param3, *param4;
+ struct wpa_ssid *ssid;
+ int key_data;
+};
+
+
+static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
+{
+ char *pos, *end, *sstart;
+
+ while (fgets(s, size, stream)) {
+ (*line)++;
+ s[size - 1] = '\0';
+ pos = s;
+
+ while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+ pos++;
+ if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
+ *pos == '\r')
+ continue;
+
+ /* Remove # comments unless they are within a double quoted
+ * string. Remove trailing white space. */
+ sstart = strchr(pos, '"');
+ if (sstart)
+ sstart = strchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + strlen(pos) - 1;
+ while (end > pos &&
+ (*end == '\n' || *end == ' ' || *end == '\t' ||
+ *end == '\r')) {
+ *end-- = '\0';
+ }
+ if (*pos == '\0')
+ continue;
+
+ return pos;
+ }
+
+ return NULL;
+}
+
+
+static char * wpa_config_parse_string(const char *value, size_t *len)
+{
+ if (*value == '"') {
+ char *pos;
+ value++;
+ pos = strchr(value, '"');
+ if (pos == NULL || pos[1] != '\0')
+ return NULL;
+ *pos = '\0';
+ *len = strlen(value);
+ return strdup(value);
+ } else {
+ u8 *str;
+ int hlen = strlen(value);
+ if (hlen % 1)
+ return NULL;
+ *len = hlen / 2;
+ str = malloc(*len);
+ if (str == NULL)
+ return NULL;
+ if (hexstr2bin(value, str, *len)) {
+ free(str);
+ return NULL;
+ }
+ return (char *) str;
+ }
+}
+
+
+static int wpa_config_parse_str(struct parse_data *data,
+ int line, const char *value)
+{
+ size_t res_len, *dst_len;
+ char **dst;
+
+ dst = (char **) (((u8 *) data->ssid) + (long) data->param1);
+ dst_len = (size_t *) (((u8 *) data->ssid) + (long) data->param2);
+
+ free(*dst);
+ *dst = wpa_config_parse_string(value, &res_len);
+ if (*dst == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
+ line, data->name, value);
+ return -1;
+ }
+ if (data->param2)
+ *dst_len = res_len;
+
+ if (data->key_data) {
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+ (u8 *) *dst, res_len);
+ } else {
+ wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
+ (u8 *) *dst, res_len);
+ }
+
+ if (data->param3 && res_len < (size_t) data->param3) {
+ wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+ "min_len=%ld)", line, data->name,
+ (unsigned long) res_len, (long) data->param3);
+ free(*dst);
+ *dst = NULL;
+ return -1;
+ }
+
+ if (data->param4 && res_len > (size_t) data->param4) {
+ wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+ "max_len=%ld)", line, data->name,
+ (unsigned long) res_len, (long) data->param4);
+ free(*dst);
+ *dst = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_config_parse_int(struct parse_data *data,
+ int line, const char *value)
+{
+ int *dst;
+
+ dst = (int *) (((u8 *) data->ssid) + (long) data->param1);
+ *dst = atoi(value);
+ wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
+
+ if (data->param3 && *dst < (long) data->param3) {
+ wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+ "min_value=%ld)", line, data->name, *dst,
+ (long) data->param3);
+ *dst = (long) data->param3;
+ return -1;
+ }
+
+ if (data->param4 && *dst > (long) data->param4) {
+ wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+ "max_value=%ld)", line, data->name, *dst,
+ (long) data->param4);
+ *dst = (long) data->param4;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_config_parse_bssid(struct parse_data *data, int line,
+ const char *value)
+{
+ if (hwaddr_aton(value, data->ssid->bssid)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
+ line, value);
+ return -1;
+ }
+ data->ssid->bssid_set = 1;
+ wpa_hexdump(MSG_MSGDUMP, "BSSID", data->ssid->bssid, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_config_parse_psk(struct parse_data *data, int line,
+ const char *value)
+{
+ if (*value == '"') {
+ char *pos;
+ int len;
+
+ value++;
+ pos = strrchr(value, '"');
+ if (pos)
+ *pos = '\0';
+ len = strlen(value);
+ if (len < 8 || len > 63) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
+ "length %d (expected: 8..63) '%s'.",
+ line, len, value);
+ return -1;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
+ (u8 *) value, len);
+ data->ssid->passphrase = strdup(value);
+ return data->ssid->passphrase == NULL ? -1 : 0;
+ }
+
+ if (hexstr2bin(value, data->ssid->psk, PMK_LEN) ||
+ value[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
+ line, value);
+ return -1;
+ }
+ data->ssid->psk_set = 1;
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK", data->ssid->psk, PMK_LEN);
+ return 0;
+}
+
+
+static int wpa_config_parse_proto(struct parse_data *data, int line,
+ const char *value)
+{
+ int val = 0, last, errors = 0;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "WPA") == 0)
+ val |= WPA_PROTO_WPA;
+ else if (strcmp(start, "RSN") == 0 ||
+ strcmp(start, "WPA2") == 0)
+ val |= WPA_PROTO_RSN;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
+ line, start);
+ errors++;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no proto values configured.", line);
+ errors++;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
+ data->ssid->proto = val;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
+ const char *value)
+{
+ int val = 0, last, errors = 0;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "WPA-PSK") == 0)
+ val |= WPA_KEY_MGMT_PSK;
+ else if (strcmp(start, "WPA-EAP") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X;
+ else if (strcmp(start, "IEEE8021X") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+ else if (strcmp(start, "NONE") == 0)
+ val |= WPA_KEY_MGMT_NONE;
+ else if (strcmp(start, "WPA-NONE") == 0)
+ val |= WPA_KEY_MGMT_WPA_NONE;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+ line, start);
+ errors++;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no key_mgmt values configured.", line);
+ errors++;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
+ data->ssid->key_mgmt = val;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_cipher(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "CCMP") == 0)
+ val |= WPA_CIPHER_CCMP;
+ else if (strcmp(start, "TKIP") == 0)
+ val |= WPA_CIPHER_TKIP;
+ else if (strcmp(start, "WEP104") == 0)
+ val |= WPA_CIPHER_WEP104;
+ else if (strcmp(start, "WEP40") == 0)
+ val |= WPA_CIPHER_WEP40;
+ else if (strcmp(start, "NONE") == 0)
+ val |= WPA_CIPHER_NONE;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, start);
+ free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+ line);
+ return -1;
+ }
+ return val;
+}
+
+
+static int wpa_config_parse_pairwise(struct parse_data *data, int line,
+ const char *value)
+{
+ int val;
+ val = wpa_config_parse_cipher(line, value);
+ if (val == -1)
+ return -1;
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
+ wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
+ "(0x%x).", line, val);
+ return -1;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
+ data->ssid->pairwise_cipher = val;
+ return 0;
+}
+
+
+static int wpa_config_parse_group(struct parse_data *data, int line,
+ const char *value)
+{
+ int val;
+ val = wpa_config_parse_cipher(line, value);
+ if (val == -1)
+ return -1;
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
+ WPA_CIPHER_WEP40)) {
+ wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
+ "(0x%x).", line, val);
+ return -1;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
+ data->ssid->group_cipher = val;
+ return 0;
+}
+
+
+static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
+ const char *value)
+{
+ int val = 0, last, errors = 0;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "OPEN") == 0)
+ val |= WPA_AUTH_ALG_OPEN;
+ else if (strcmp(start, "SHARED") == 0)
+ val |= WPA_AUTH_ALG_SHARED;
+ else if (strcmp(start, "LEAP") == 0)
+ val |= WPA_AUTH_ALG_LEAP;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
+ line, start);
+ errors++;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no auth_alg values configured.", line);
+ errors++;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
+ data->ssid->auth_alg = val;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_eap(struct parse_data *data, int line,
+ const char *value)
+{
+ int last, errors = 0;
+ char *start, *end, *buf;
+ u8 *methods = NULL, *tmp;
+ size_t num_methods = 0;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ tmp = methods;
+ methods = realloc(methods, num_methods + 1);
+ if (methods == NULL) {
+ free(tmp);
+ return -1;
+ }
+ methods[num_methods] = eap_get_type(start);
+ if (methods[num_methods] == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
+ "'%s'", line, start);
+ wpa_printf(MSG_ERROR, "You may need to add support for"
+ " this EAP method during wpa_supplicant\n"
+ "build time configuration.\n"
+ "See README for more information.");
+ errors++;
+ } else if (methods[num_methods] == EAP_TYPE_LEAP)
+ data->ssid->leap++;
+ else
+ data->ssid->non_leap++;
+ num_methods++;
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ tmp = methods;
+ methods = realloc(methods, num_methods + 1);
+ if (methods == NULL) {
+ free(tmp);
+ return -1;
+ }
+ methods[num_methods] = EAP_TYPE_NONE;
+ num_methods++;
+
+ wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods);
+ data->ssid->eap_methods = methods;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
+ const char *value, int idx)
+{
+ char *buf, title[20];
+
+ buf = wpa_config_parse_string(value, len);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
+ line, idx, value);
+ return -1;
+ }
+ if (*len > MAX_WEP_KEY_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
+ line, idx, value);
+ free(buf);
+ return -1;
+ }
+ memcpy(key, buf, *len);
+ free(buf);
+ snprintf(title, sizeof(title), "wep_key%d", idx);
+ wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
+ return 0;
+}
+
+
+static int wpa_config_parse_wep_key0(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[0],
+ &data->ssid->wep_key_len[0], line,
+ value, 0);
+}
+
+
+static int wpa_config_parse_wep_key1(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[1],
+ &data->ssid->wep_key_len[1], line,
+ value, 1);
+}
+
+
+static int wpa_config_parse_wep_key2(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[2],
+ &data->ssid->wep_key_len[2], line,
+ value, 2);
+}
+
+
+static int wpa_config_parse_wep_key3(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[3],
+ &data->ssid->wep_key_len[3], line,
+ value, 3);
+}
+
+
+#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
+#define STR(f) .name = #f, .parser = wpa_config_parse_str, .param1 = OFFSET(f)
+#define STR_LEN(f) STR(f), .param2 = OFFSET(f ## _len)
+#define STR_RANGE(f, min, max) STR_LEN(f), .param3 = (void *) (min), \
+ .param4 = (void *) (max)
+#define INT(f) .name = #f, .parser = wpa_config_parse_int, \
+ .param1 = OFFSET(f), .param2 = (void *) 0
+#define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \
+ .param4 = (void *) (max)
+#define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f
+
+static struct parse_data ssid_fields[] = {
+ { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
+ { INT_RANGE(scan_ssid, 0, 1) },
+ { FUNC(bssid) },
+ { FUNC(psk), .key_data = 1 },
+ { FUNC(proto) },
+ { FUNC(key_mgmt) },
+ { FUNC(pairwise) },
+ { FUNC(group) },
+ { FUNC(auth_alg) },
+ { FUNC(eap) },
+ { STR_LEN(identity) },
+ { STR_LEN(anonymous_identity) },
+ { STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 },
+ { STR_LEN(nai) },
+ { STR_LEN(server_nai) },
+ { STR_LEN(password), .key_data = 1 },
+ { STR(ca_cert) },
+ { STR(client_cert) },
+ { STR(private_key) },
+ { STR(private_key_passwd), .key_data = 1 },
+ { STR(dh_file) },
+ { STR(subject_match) },
+ { STR(ca_cert2) },
+ { STR(client_cert2) },
+ { STR(private_key2) },
+ { STR(private_key2_passwd), .key_data = 1 },
+ { STR(dh_file2) },
+ { STR(subject_match2) },
+ { STR(phase1) },
+ { STR(phase2) },
+ { STR(pcsc) },
+ { STR(pin), .key_data = 1 },
+ { INT(eapol_flags) },
+ { FUNC(wep_key0), .key_data = 1 },
+ { FUNC(wep_key1), .key_data = 1 },
+ { FUNC(wep_key2), .key_data = 1 },
+ { FUNC(wep_key3), .key_data = 1 },
+ { INT(wep_tx_keyidx) },
+ { INT(priority) },
+ { INT(eap_workaround) },
+ { STR(pac_file) },
+ { INT_RANGE(mode, 0, 1) },
+};
+
+#undef OFFSET
+#undef STR
+#undef STR_LEN
+#undef STR_RANGE
+#undef INT
+#undef INT_RANGE
+#undef FUNC
+#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+
+
+static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
+{
+ struct wpa_ssid *ssid;
+ int errors = 0, i, end = 0;
+ char buf[256], *pos, *pos2;
+
+ wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
+ *line);
+ ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
+ if (ssid == NULL)
+ return NULL;
+ memset(ssid, 0, sizeof(*ssid));
+ ssid->id = id;
+
+ ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
+ ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
+ ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
+ WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
+ ssid->key_mgmt = WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X;
+ ssid->eapol_flags = EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+ EAPOL_FLAG_REQUIRE_KEY_BROADCAST;
+ ssid->eap_workaround = (unsigned int) -1;
+
+ while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
+ if (strcmp(pos, "}") == 0) {
+ end = 1;
+ break;
+ }
+
+ pos2 = strchr(pos, '=');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
+ "'%s'.", *line, pos);
+ errors++;
+ continue;
+ }
+
+ *pos2++ = '\0';
+ if (*pos2 == '"') {
+ if (strchr(pos2 + 1, '"') == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "quotation '%s'.", *line, pos2);
+ errors++;
+ continue;
+ }
+ }
+
+ for (i = 0; i < NUM_SSID_FIELDS; i++) {
+ struct parse_data *field = &ssid_fields[i];
+ if (strcmp(pos, field->name) != 0)
+ continue;
+
+ field->ssid = ssid;
+ if (field->parser(field, *line, pos2)) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse %s '%s'.", *line, pos, pos2);
+ errors++;
+ }
+ break;
+ }
+ if (i == NUM_SSID_FIELDS) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown network field "
+ "'%s'.", *line, pos);
+ errors++;
+ }
+ }
+
+ if (!end) {
+ wpa_printf(MSG_ERROR, "Line %d: network block was not "
+ "terminated properly.", *line);
+ errors++;
+ }
+
+ if (ssid->passphrase) {
+ if (ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Line %d: both PSK and "
+ "passphrase configured.", *line);
+ errors++;
+ }
+ pbkdf2_sha1(ssid->passphrase,
+ (char *) ssid->ssid, ssid->ssid_len, 4096,
+ ssid->psk, PMK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+ ssid->psk, PMK_LEN);
+ ssid->psk_set = 1;
+ }
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
+ "management, but no PSK configured.", *line);
+ errors++;
+ }
+
+ if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
+ /* Group cipher cannot be stronger than the pairwise cipher. */
+ wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
+ " list since it was not allowed for pairwise "
+ "cipher", *line);
+ ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+ }
+
+ if (errors) {
+ free(ssid);
+ ssid = NULL;
+ }
+
+ return ssid;
+}
+
+
+static int wpa_config_add_prio_network(struct wpa_config *config,
+ struct wpa_ssid *ssid)
+{
+ int prio;
+ struct wpa_ssid *prev, **nlist;
+
+ for (prio = 0; prio < config->num_prio; prio++) {
+ prev = config->pssid[prio];
+ if (prev->priority == ssid->priority) {
+ while (prev->pnext)
+ prev = prev->pnext;
+ prev->pnext = ssid;
+ return 0;
+ }
+ }
+
+ /* First network for this priority - add new priority list */
+ nlist = realloc(config->pssid,
+ (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+ if (nlist == NULL)
+ return -1;
+
+ for (prio = 0; prio < config->num_prio; prio++) {
+ if (nlist[prio]->priority < ssid->priority)
+ break;
+ }
+
+ memmove(&nlist[prio + 1], &nlist[prio],
+ (config->num_prio - prio) * sizeof(struct wpa_ssid *));
+
+ nlist[prio] = ssid;
+ config->num_prio++;
+ config->pssid = nlist;
+
+ return 0;
+}
+
+
+struct wpa_config * wpa_config_read(const char *config_file)
+{
+ FILE *f;
+ char buf[256], *pos;
+ int errors = 0, line = 0;
+ struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ struct wpa_config *config;
+ int id = 0, prio;
+
+ config = malloc(sizeof(*config));
+ if (config == NULL)
+ return NULL;
+ memset(config, 0, sizeof(*config));
+ config->eapol_version = 1;
+ config->ap_scan = 1;
+ config->fast_reauth = 1;
+ wpa_printf(MSG_DEBUG, "Reading configuration file '%s'",
+ config_file);
+ f = fopen(config_file, "r");
+ if (f == NULL) {
+ free(config);
+ return NULL;
+ }
+
+ while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
+ if (strcmp(pos, "network={") == 0) {
+ ssid = wpa_config_read_network(f, &line, id++);
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse network block.", line);
+ errors++;
+ continue;
+ }
+ if (head == NULL) {
+ head = tail = ssid;
+ } else {
+ tail->next = ssid;
+ tail = ssid;
+ }
+ if (wpa_config_add_prio_network(config, ssid)) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to add "
+ "network block to priority list.",
+ line);
+ errors++;
+ continue;
+ }
+#ifdef CONFIG_CTRL_IFACE
+ } else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
+ free(config->ctrl_interface);
+ config->ctrl_interface = strdup(pos + 15);
+ wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
+ config->ctrl_interface);
+#ifndef CONFIG_CTRL_IFACE_UDP
+ } else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) {
+ struct group *grp;
+ char *endp;
+ const char *group = pos + 21;
+
+ grp = getgrnam(group);
+ if (grp) {
+ config->ctrl_interface_gid = grp->gr_gid;
+ config->ctrl_interface_gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ (int) config->ctrl_interface_gid,
+ group);
+ continue;
+ }
+
+ /* Group name not found - try to parse this as gid */
+ config->ctrl_interface_gid = strtol(group, &endp, 10);
+ if (*group == '\0' || *endp != '\0') {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+ "'%s'", line, group);
+ errors++;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ (int) config->ctrl_interface_gid);
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE */
+ } else if (strncmp(pos, "eapol_version=", 14) == 0) {
+ config->eapol_version = atoi(pos + 14);
+ if (config->eapol_version < 1 ||
+ config->eapol_version > 2) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
+ "version (%d): '%s'.",
+ line, config->eapol_version, pos);
+ errors++;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "eapol_version=%d",
+ config->eapol_version);
+ } else if (strncmp(pos, "ap_scan=", 8) == 0) {
+ config->ap_scan = atoi(pos + 8);
+ wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
+ } else if (strncmp(pos, "fast_reauth=", 12) == 0) {
+ config->fast_reauth = atoi(pos + 12);
+ wpa_printf(MSG_DEBUG, "fast_reauth=%d",
+ config->fast_reauth);
+ } else {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
+ "line '%s'.", line, pos);
+ errors++;
+ continue;
+ }
+ }
+
+ fclose(f);
+
+ config->ssid = head;
+ for (prio = 0; prio < config->num_prio; prio++) {
+ ssid = config->pssid[prio];
+ wpa_printf(MSG_DEBUG, "Priority group %d",
+ ssid->priority);
+ while (ssid) {
+ wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
+ ssid->id,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ssid = ssid->pnext;
+ }
+ }
+ if (errors) {
+ wpa_config_free(config);
+ config = NULL;
+ head = NULL;
+ }
+
+ return config;
+}
+
+
+void wpa_config_free(struct wpa_config *config)
+{
+ struct wpa_ssid *ssid, *prev = NULL;
+ ssid = config->ssid;
+ while (ssid) {
+ prev = ssid;
+ ssid = ssid->next;
+ free(prev->ssid);
+ free(prev->passphrase);
+ free(prev->eap_methods);
+ free(prev->identity);
+ free(prev->anonymous_identity);
+ free(prev->eappsk);
+ free(prev->nai);
+ free(prev->server_nai);
+ free(prev->password);
+ free(prev->ca_cert);
+ free(prev->client_cert);
+ free(prev->private_key);
+ free(prev->private_key_passwd);
+ free(prev->dh_file);
+ free(prev->subject_match);
+ free(prev->ca_cert2);
+ free(prev->client_cert2);
+ free(prev->private_key2);
+ free(prev->private_key2_passwd);
+ free(prev->dh_file2);
+ free(prev->subject_match2);
+ free(prev->phase1);
+ free(prev->phase2);
+ free(prev->pcsc);
+ free(prev->pin);
+ free(prev->otp);
+ free(prev->pending_req_otp);
+ free(prev->pac_file);
+ free(prev);
+ }
+ free(config->ctrl_interface);
+ free(config->pssid);
+ free(config);
+}
+
+
+int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
+{
+ u8 *pos;
+
+ if (ssid == NULL || ssid->eap_methods == NULL)
+ return 1;
+
+ pos = ssid->eap_methods;
+ while (*pos != EAP_TYPE_NONE) {
+ if (*pos == method)
+ return 1;
+ pos++;
+ }
+ return 0;
+}
+
+
+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";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+{
+ switch (key_mgmt) {
+ case WPA_KEY_MGMT_IEEE8021X:
+ return proto == WPA_PROTO_RSN ?
+ "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
+ case WPA_KEY_MGMT_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)";
+ default:
+ return "UNKNOWN";
+ }
+}
diff --git a/contrib/wpa_supplicant/config.h b/contrib/wpa_supplicant/config.h
new file mode 100644
index 000000000000..13deb3e3cb58
--- /dev/null
+++ b/contrib/wpa_supplicant/config.h
@@ -0,0 +1,33 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#ifdef CONFIG_CTRL_IFACE
+#ifndef CONFIG_CTRL_IFACE_UDP
+#include <grp.h>
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE */
+
+#include "config_ssid.h"
+
+struct wpa_config {
+ struct wpa_ssid *ssid; /* global network list */
+ struct wpa_ssid **pssid; /* per priority network lists (in priority
+ * order) */
+ int num_prio; /* number of different priorities */
+ int eapol_version;
+ int ap_scan;
+ char *ctrl_interface; /* directory for UNIX domain sockets */
+#ifdef CONFIG_CTRL_IFACE
+#ifndef CONFIG_CTRL_IFACE_UDP
+ gid_t ctrl_interface_gid;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ int ctrl_interface_gid_set;
+#endif /* CONFIG_CTRL_IFACE */
+ int fast_reauth;
+};
+
+
+struct wpa_config * wpa_config_read(const char *config_file);
+void wpa_config_free(struct wpa_config *ssid);
+
+#endif /* CONFIG_H */
diff --git a/contrib/wpa_supplicant/config_ssid.h b/contrib/wpa_supplicant/config_ssid.h
new file mode 100644
index 000000000000..44bc98947ced
--- /dev/null
+++ b/contrib/wpa_supplicant/config_ssid.h
@@ -0,0 +1,109 @@
+#ifndef CONFIG_SSID_H
+#define CONFIG_SSID_H
+
+#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)
+
+#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_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 MAX_SSID_LEN 32
+#define PMK_LEN 32
+#define EAP_PSK_LEN 16
+
+struct wpa_ssid {
+ struct wpa_ssid *next; /* next network in global list */
+ struct wpa_ssid *pnext; /* next network in per-priority list */
+ int id; /* unique id for ctrl_iface */
+ int priority;
+ u8 *ssid;
+ size_t ssid_len;
+ u8 bssid[ETH_ALEN];
+ int bssid_set;
+ u8 psk[PMK_LEN];
+ int psk_set;
+ char *passphrase;
+ /* Bitfields of allowed Pairwise/Group Ciphers, WPA_CIPHER_* */
+ int pairwise_cipher;
+ int group_cipher;
+ int key_mgmt;
+ int proto; /* Bitfield of allowed protocols (WPA_PROTO_*) */
+ int auth_alg; /* Bitfield of allow authentication algorithms
+ * (WPA_AUTH_ALG_*) */
+ int scan_ssid; /* scan this SSID with Probe Requests */
+ u8 *identity; /* EAP Identity */
+ size_t identity_len;
+ u8 *anonymous_identity; /* Anonymous EAP Identity (for unencrypted use
+ * with EAP types that support different
+ * tunnelled identity, e.g., EAP-TTLS) */
+ size_t anonymous_identity_len;
+ u8 *eappsk;
+ size_t eappsk_len;
+ u8 *nai;
+ size_t nai_len;
+ u8 *server_nai;
+ size_t server_nai_len;
+ u8 *password;
+ size_t password_len;
+ u8 *ca_cert;
+ u8 *client_cert;
+ u8 *private_key;
+ u8 *private_key_passwd;
+ u8 *dh_file;
+ u8 *subject_match;
+ u8 *ca_cert2;
+ u8 *client_cert2;
+ u8 *private_key2;
+ u8 *private_key2_passwd;
+ u8 *dh_file2;
+ u8 *subject_match2;
+ u8 *eap_methods; /* zero (EAP_TYPE_NONE) terminated list of allowed
+ * EAP methods or NULL = any */
+ char *phase1;
+ char *phase2;
+ char *pcsc;
+ char *pin;
+
+#define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0)
+#define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1)
+ int eapol_flags; /* bit field of IEEE 802.1X/EAPOL options */
+
+#define NUM_WEP_KEYS 4
+#define MAX_WEP_KEY_LEN 16
+ u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN];
+ size_t wep_key_len[NUM_WEP_KEYS];
+ int wep_tx_keyidx;
+
+ /* Per SSID variables that are not read from the configuration file */
+ u8 *otp;
+ size_t otp_len;
+ int pending_req_identity, pending_req_password;
+ char *pending_req_otp;
+ size_t pending_req_otp_len;
+ int leap, non_leap;
+
+ unsigned int eap_workaround;
+
+ char *pac_file;
+
+ int mode;
+};
+
+int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method);
+const char * wpa_cipher_txt(int cipher);
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
+
+#endif /* CONFIG_SSID_H */
diff --git a/contrib/wpa_supplicant/crypto.c b/contrib/wpa_supplicant/crypto.c
new file mode 100644
index 000000000000..cd278e0fae59
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto.c
@@ -0,0 +1,71 @@
+/*
+ * WPA Supplicant / wrapper functions for libcrypto
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <openssl/md4.h>
+#include <openssl/des.h>
+
+#include "common.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 */
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
+{
+ MD4_CTX ctx;
+ int i;
+
+ MD4_Init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ MD4_Update(&ctx, addr[i], len[i]);
+ MD4_Final(mac, &ctx);
+}
+
+
+void md4(const u8 *addr, size_t len, u8 *mac)
+{
+ md4_vector(1, &addr, &len, mac);
+}
+
+
+/**
+ * @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)
+{
+ 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);
+}
diff --git a/contrib/wpa_supplicant/crypto.h b/contrib/wpa_supplicant/crypto.h
new file mode 100644
index 000000000000..3e1a0e5cd3f8
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto.h
@@ -0,0 +1,8 @@
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+void md4(const u8 *addr, size_t len, u8 *mac);
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
+
+#endif /* CRYPTO_H */
diff --git a/contrib/wpa_supplicant/ctrl_iface.c b/contrib/wpa_supplicant/ctrl_iface.c
new file mode 100644
index 000000000000..e41881104ede
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface.c
@@ -0,0 +1,728 @@
+/*
+ * WPA Supplicant / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "common.h"
+#include "eloop.h"
+#include "wpa.h"
+#include "wpa_supplicant.h"
+#include "config.h"
+#include "eapol_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+#include "l2_packet.h"
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+typedef int socklen_t;
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define CTRL_IFACE_SOCK struct sockaddr_in
+#else /* CONFIG_CTRL_IFACE_UDP */
+#define CTRL_IFACE_SOCK struct sockaddr_un
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+struct wpa_ctrl_dst {
+ struct wpa_ctrl_dst *next;
+ CTRL_IFACE_SOCK addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+};
+
+
+static const char * wpa_state_txt(int state)
+{
+ switch (state) {
+ case WPA_DISCONNECTED:
+ return "DISCONNECTED";
+ case WPA_SCANNING:
+ return "SCANNING";
+ case WPA_ASSOCIATING:
+ return "ASSOCIATING";
+ case WPA_ASSOCIATED:
+ return "ASSOCIATED";
+ case WPA_4WAY_HANDSHAKE:
+ return "4WAY_HANDSHAKE";
+ case WPA_GROUP_HANDSHAKE:
+ return "GROUP_HANDSHAKE";
+ case WPA_COMPLETED:
+ return "COMPLETED";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *value;
+
+ value = strchr(cmd, ' ');
+ if (value == NULL)
+ return -1;
+ *value++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
+ if (strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
+ eapol_sm_configure(wpa_s->eapol,
+ atoi(value), -1, -1, -1);
+ } else if (strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
+ eapol_sm_configure(wpa_s->eapol,
+ -1, atoi(value), -1, -1);
+ } else if (strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
+ eapol_sm_configure(wpa_s->eapol,
+ -1, -1, atoi(value), -1);
+ } else if (strcasecmp(cmd, "EAPOL::maxStart") == 0) {
+ eapol_sm_configure(wpa_s->eapol,
+ -1, -1, -1, atoi(value));
+ } else
+ return -1;
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
+ char *addr)
+{
+ u8 bssid[ETH_ALEN];
+
+ if (hwaddr_aton(addr, bssid)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
+ "'%s'", addr);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
+ rsn_preauth_deinit(wpa_s);
+ if (rsn_preauth_init(wpa_s, bssid))
+ return -1;
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct wpa_supplicant *wpa_s,
+ CTRL_IFACE_SOCK *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dst = malloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ memset(dst, 0, sizeof(*dst));
+ memcpy(&dst->addr, from, sizeof(CTRL_IFACE_SOCK));
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ dst->next = wpa_s->ctrl_dst;
+ wpa_s->ctrl_dst = dst;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
+ inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+#else /* CONFIG_CTRL_IFACE_UDP */
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+ (u8 *) from->sun_path, fromlen);
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_detach(struct wpa_supplicant *wpa_s,
+ CTRL_IFACE_SOCK *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst, *prev = NULL;
+
+ dst = wpa_s->ctrl_dst;
+ while (dst) {
+#ifdef CONFIG_CTRL_IFACE_UDP
+ if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
+ from->sin_port == dst->addr.sin_port) {
+ if (prev == NULL)
+ wpa_s->ctrl_dst = dst->next;
+ else
+ prev->next = dst->next;
+ free(dst);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
+ "%s:%d", inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
+ return 0;
+ }
+#else /* CONFIG_CTRL_IFACE_UDP */
+ if (fromlen == dst->addrlen &&
+ memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
+ if (prev == NULL)
+ wpa_s->ctrl_dst = dst->next;
+ else
+ prev->next = dst->next;
+ free(dst);
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+ (u8 *) from->sun_path, fromlen);
+ return 0;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ prev = dst;
+ dst = dst->next;
+ }
+ return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_level(struct wpa_supplicant *wpa_s,
+ CTRL_IFACE_SOCK *from,
+ socklen_t fromlen,
+ char *level)
+{
+ struct wpa_ctrl_dst *dst;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+ dst = wpa_s->ctrl_dst;
+ while (dst) {
+#ifdef CONFIG_CTRL_IFACE_UDP
+ if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
+ from->sin_port == dst->addr.sin_port) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
+ "level %s:%d", inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+#else /* CONFIG_CTRL_IFACE_UDP */
+ if (fromlen == dst->addrlen &&
+ memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+ "level", (u8 *) from->sun_path, fromlen);
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ dst = dst->next;
+ }
+
+ return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
+ char *rsp)
+{
+ char *pos, *id_pos;
+ int id;
+ struct wpa_ssid *ssid;
+
+ pos = strchr(rsp, '-');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ id_pos = pos;
+ pos = strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ id = atoi(id_pos);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d value='%s'",
+ rsp, id, pos);
+
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (id == ssid->id)
+ break;
+ ssid = ssid->next;
+ }
+
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+ "to update", id);
+ return -1;
+ }
+
+ if (strcmp(rsp, "IDENTITY") == 0) {
+ free(ssid->identity);
+ ssid->identity = (u8 *) strdup(pos);
+ ssid->identity_len = strlen(pos);
+ ssid->pending_req_identity = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ } else if (strcmp(rsp, "PASSWORD") == 0) {
+ free(ssid->password);
+ ssid->password = (u8 *) strdup(pos);
+ ssid->password_len = strlen(pos);
+ ssid->pending_req_password = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ } else if (strcmp(rsp, "OTP") == 0) {
+ free(ssid->otp);
+ ssid->otp = (u8 *) strdup(pos);
+ ssid->otp_len = strlen(pos);
+ free(ssid->pending_req_otp);
+ ssid->pending_req_otp = NULL;
+ ssid->pending_req_otp_len = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
+ const char *params,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ int res, verbose;
+
+ verbose = strcmp(params, "-VERBOSE") == 0;
+ pos = buf;
+ end = buf + buflen;
+ pos += snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+ MAC2STR(wpa_s->bssid));
+ if (wpa_s->current_ssid) {
+ pos += snprintf(pos, end - pos, "ssid=%s\n",
+ wpa_ssid_txt(wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len));
+ }
+ pos += snprintf(pos, end - pos,
+ "pairwise_cipher=%s\n"
+ "group_cipher=%s\n"
+ "key_mgmt=%s\n"
+ "wpa_state=%s\n",
+ wpa_cipher_txt(wpa_s->pairwise_cipher),
+ wpa_cipher_txt(wpa_s->group_cipher),
+ wpa_key_mgmt_txt(wpa_s->key_mgmt, wpa_s->proto),
+ wpa_state_txt(wpa_s->wpa_state));
+
+ res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, verbose);
+ if (res >= 0)
+ pos += res;
+
+ if (wpa_s->preauth_eapol) {
+ pos += snprintf(pos, end - pos, "Pre-authentication "
+ "EAPOL state machines:\n");
+ res = eapol_sm_get_status(wpa_s->preauth_eapol,
+ pos, end - pos, verbose);
+ if (res >= 0)
+ pos += res;
+ }
+
+ return pos - buf;
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ char buf[256];
+ int res;
+ CTRL_IFACE_SOCK from;
+ socklen_t fromlen = sizeof(from);
+ char *reply;
+ const int reply_size = 2048;
+ int reply_len;
+ int new_attached = 0, ctrl_rsp = 0;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+ if (strncmp(buf, "CTRL-RSP-", 9) == 0) {
+ wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
+ (u8 *) buf, res);
+ } else {
+ wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
+ }
+
+ reply = malloc(reply_size);
+ if (reply == NULL) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ return;
+ }
+
+ memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ if (strcmp(buf, "PING") == 0) {
+ memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (strcmp(buf, "MIB") == 0) {
+ reply_len = wpa_get_mib(wpa_s, reply, reply_size);
+ if (reply_len >= 0) {
+ res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
+ reply_size - reply_len);
+ if (res < 0)
+ reply_len = -1;
+ else
+ reply_len += res;
+ }
+ } else if (strncmp(buf, "STATUS", 6) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_status(
+ wpa_s, buf + 6, reply, reply_size);
+ } else if (strcmp(buf, "PMKSA") == 0) {
+ reply_len = pmksa_cache_list(wpa_s, reply, reply_size);
+ } else if (strncmp(buf, "SET ", 4) == 0) {
+ if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
+ reply_len = -1;
+ } else if (strcmp(buf, "LOGON") == 0) {
+ eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ } else if (strcmp(buf, "LOGOFF") == 0) {
+ eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+ } else if (strcmp(buf, "REASSOCIATE") == 0) {
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (strncmp(buf, "PREAUTH ", 8) == 0) {
+ if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
+ reply_len = -1;
+ } else if (strcmp(buf, "ATTACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_attach(wpa_s, &from, fromlen))
+ reply_len = -1;
+ else
+ new_attached = 1;
+ } else if (strcmp(buf, "DETACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_detach(wpa_s, &from, fromlen))
+ reply_len = -1;
+ } else if (strncmp(buf, "LEVEL ", 6) == 0) {
+ if (wpa_supplicant_ctrl_iface_level(wpa_s, &from, fromlen,
+ buf + 6))
+ reply_len = -1;
+ } else if (strncmp(buf, "CTRL-RSP-", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_ctrl_rsp(wpa_s, buf + 9))
+ reply_len = -1;
+ else
+ ctrl_rsp = 1;
+ } else if (strcmp(buf, "RECONFIGURE") == 0) {
+ if (wpa_supplicant_reload_configuration(wpa_s))
+ reply_len = -1;
+ } else if (strcmp(buf, "TERMINATE") == 0) {
+ eloop_terminate();
+ } else {
+ memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ reply_len = 16;
+ }
+
+ if (reply_len < 0) {
+ memcpy(reply, "FAIL\n", 5);
+ reply_len = 5;
+ }
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+ free(reply);
+
+ if (new_attached)
+ eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+ if (ctrl_rsp)
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
+static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
+{
+ char *buf;
+ size_t len;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return NULL;
+
+ len = strlen(wpa_s->conf->ctrl_interface) + strlen(wpa_s->ifname) + 2;
+ buf = malloc(len);
+ if (buf == NULL)
+ return NULL;
+
+ snprintf(buf, len, "%s/%s",
+ wpa_s->conf->ctrl_interface, wpa_s->ifname);
+#ifdef __CYGWIN__
+ {
+ /* Windows/WinPcap uses interface names that are not suitable
+ * as a file name - convert invalid chars to underscores */
+ char *pos = buf;
+ while (*pos) {
+ if (*pos == '\\')
+ *pos = '_';
+ pos++;
+ }
+ }
+#endif /* __CYGWIN__ */
+ return buf;
+}
+
+
+int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ CTRL_IFACE_SOCK addr;
+ int s = -1;
+ char *fname = NULL;
+
+ wpa_s->ctrl_sock = -1;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return 0;
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_INET)");
+ goto fail;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl((127 << 24) | 1);
+ addr.sin_port = htons(9877);
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(AF_UNIX)");
+ goto fail;
+ }
+#else /* CONFIG_CTRL_IFACE_UDP */
+ if (mkdir(wpa_s->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG, "Using existing control "
+ "interface directory.");
+ } else {
+ perror("mkdir[ctrl_interface]");
+ goto fail;
+ }
+ }
+
+ if (wpa_s->conf->ctrl_interface_gid_set &&
+ chown(wpa_s->conf->ctrl_interface, 0,
+ wpa_s->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface]");
+ return -1;
+ }
+
+ if (strlen(wpa_s->conf->ctrl_interface) + 1 + strlen(wpa_s->ifname) >=
+ sizeof(addr.sun_path))
+ goto fail;
+
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ fname = wpa_supplicant_ctrl_iface_path(wpa_s);
+ if (fname == NULL)
+ goto fail;
+ strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+ " allow connections - assuming it was left"
+ "over from forced program termination");
+ if (unlink(fname) < 0) {
+ perror("unlink[ctrl_iface]");
+ wpa_printf(MSG_ERROR, "Could not unlink "
+ "existing ctrl_iface socket '%s'",
+ fname);
+ goto fail;
+ }
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+ "ctrl_iface socket '%s'", fname);
+ } else {
+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+ "be in use - cannot override it");
+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+ "not used anymore", fname);
+ free(fname);
+ fname = NULL;
+ goto fail;
+ }
+ }
+
+ if (wpa_s->conf->ctrl_interface_gid_set &&
+ chown(fname, 0, wpa_s->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface/ifname]");
+ goto fail;
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ perror("chmod[ctrl_interface/ifname]");
+ goto fail;
+ }
+ free(fname);
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+ wpa_s->ctrl_sock = s;
+ eloop_register_read_sock(s, wpa_supplicant_ctrl_iface_receive, wpa_s,
+ NULL);
+
+ return 0;
+
+fail:
+ if (s >= 0)
+ close(s);
+ if (fname) {
+ unlink(fname);
+ free(fname);
+ }
+ return -1;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ctrl_dst *dst, *prev;
+
+ if (wpa_s->ctrl_sock > -1) {
+ char *fname;
+ eloop_unregister_read_sock(wpa_s->ctrl_sock);
+ close(wpa_s->ctrl_sock);
+ wpa_s->ctrl_sock = -1;
+ fname = wpa_supplicant_ctrl_iface_path(wpa_s);
+ if (fname)
+ unlink(fname);
+ free(fname);
+
+ if (rmdir(wpa_s->conf->ctrl_interface) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG, "Control interface "
+ "directory not empty - leaving it "
+ "behind");
+ } else {
+ perror("rmdir[ctrl_interface]");
+ }
+ }
+ }
+
+ dst = wpa_s->ctrl_dst;
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ free(prev);
+ }
+}
+
+
+void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
+ char *buf, size_t len)
+{
+ struct wpa_ctrl_dst *dst, *next;
+ char levelstr[10];
+ int idx;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ char *sbuf;
+ int llen;
+
+ dst = wpa_s->ctrl_dst;
+ if (wpa_s->ctrl_sock < 0 || dst == NULL)
+ return;
+
+ snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+
+ llen = strlen(levelstr);
+ sbuf = malloc(llen + len);
+ if (sbuf == NULL)
+ return;
+
+ memcpy(sbuf, levelstr, llen);
+ memcpy(sbuf + llen, buf, len);
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (level >= dst->debug_level) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
+ inet_ntoa(dst->addr.sin_addr),
+ ntohs(dst->addr.sin_port));
+ if (sendto(wpa_s->ctrl_sock, sbuf, llen + len, 0,
+ (struct sockaddr *) &dst->addr,
+ sizeof(dst->addr)) < 0) {
+ fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
+ idx);
+ perror("sendto");
+ dst->errors++;
+ if (dst->errors > 10) {
+ wpa_supplicant_ctrl_iface_detach(
+ wpa_s, &dst->addr,
+ dst->addrlen);
+ }
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+ free(sbuf);
+#else /* CONFIG_CTRL_IFACE_UDP */
+ struct msghdr msg;
+ struct iovec io[2];
+
+ dst = wpa_s->ctrl_dst;
+ if (wpa_s->ctrl_sock < 0 || dst == NULL)
+ return;
+
+ snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ io[0].iov_base = levelstr;
+ io[0].iov_len = strlen(levelstr);
+ io[1].iov_base = buf;
+ io[1].iov_len = len;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (level >= dst->debug_level) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+ (u8 *) dst->addr.sun_path, dst->addrlen);
+ msg.msg_name = &dst->addr;
+ msg.msg_namelen = dst->addrlen;
+ if (sendmsg(wpa_s->ctrl_sock, &msg, 0) < 0) {
+ fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
+ idx);
+ perror("sendmsg");
+ dst->errors++;
+ if (dst->errors > 10) {
+ wpa_supplicant_ctrl_iface_detach(
+ wpa_s, &dst->addr,
+ dst->addrlen);
+ }
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+}
diff --git a/contrib/wpa_supplicant/ctrl_iface.h b/contrib/wpa_supplicant/ctrl_iface.h
new file mode 100644
index 000000000000..d7ad6dfe670a
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface.h
@@ -0,0 +1,31 @@
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+#ifdef CONFIG_CTRL_IFACE
+
+int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
+ char *buf, size_t len);
+
+#else /* CONFIG_CTRL_IFACE */
+
+static inline int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
+ char *buf, size_t len)
+{
+}
+
+#endif /* CONFIG_CTRL_IFACE */
+
+#endif /* CTRL_IFACE_H */
diff --git a/contrib/wpa_supplicant/defconfig b/contrib/wpa_supplicant/defconfig
new file mode 100644
index 000000000000..7e8e3811d06f
--- /dev/null
+++ b/contrib/wpa_supplicant/defconfig
@@ -0,0 +1,154 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed openssl
+# in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Example configuration for various cross-compilation platforms
+
+#### sveasoft (e.g., for Linksys WRT54G) ######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
+#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
+###############################################################################
+
+#### openwrt (e.g., for Linksys WRT54G) #######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
+# -I../WRT54GS/release/src/include
+#LIBS = -lssl
+###############################################################################
+
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../madwifi/wpa
+
+# Driver interface for Prism54 driver
+CONFIG_DRIVER_PRISM54=y
+
+# Driver interface for ndiswrapper
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for Broadcom driver
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for generic Linux wireless extensions
+CONFIG_DRIVER_WEXT=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5 (automatically included if EAP-TTLS is enabled)
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2 (automatically included if EAP-PEAP is enabled)
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+#CONFIG_EAP_AKA=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Replace native Linux implementation of packet sockets with libdnet/libpcap.
+# This will be automatically set for non-Linux OS.
+#CONFIG_DNET_PCAP=y
+
+# Include control interface for external programs, e.g, wpa_cli
+CONFIG_CTRL_IFACE=y
+
+# Include interface for using external supplicant (Xsupplicant) for EAP
+# authentication
+#CONFIG_XSUPPLICANT_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
diff --git a/contrib/wpa_supplicant/defs.h b/contrib/wpa_supplicant/defs.h
new file mode 100644
index 000000000000..a5a515c552f5
--- /dev/null
+++ b/contrib/wpa_supplicant/defs.h
@@ -0,0 +1,14 @@
+#ifndef DEFS_H
+#define DEFS_H
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#ifdef FALSE
+#undef FALSE
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
+#endif /* CONFIG_NATIVE_WINDOWS */
+typedef enum { FALSE = 0, TRUE = 1 } Boolean;
+
+#endif /* DEFS_H */
diff --git a/contrib/wpa_supplicant/developer.txt b/contrib/wpa_supplicant/developer.txt
new file mode 100644
index 000000000000..bc5b34645d1a
--- /dev/null
+++ b/contrib/wpa_supplicant/developer.txt
@@ -0,0 +1,458 @@
+Developer notes for wpa_supplicant
+==================================
+
+The design goal for wpa_supplicant was to use hardware, driver, and OS
+independent, portable C code for all WPA functionality. All
+hardware/driver specific functionality is in separate files that
+implement a well-defined driver API.
+
+The goal of this file and the comments in the header files is to give
+enough information for other developers to be able to port the example
+code. If any information is missing, feel free to contact Jouni Malinen
+<jkmaline@cc.hut.fi> for more information. Contributions as patch files
+are also very welcome at the same address.
+
+Structure of the source code
+----------------------------
+
+Program initialization, main control loop and event handling is
+implemented in wpa_supplicant.c. WPA state machines and 4-Way/Group
+Key Handshake processing in in wpa.c. IEEE 802.1X/EAPOL processing and
+state machines are in eapol_sm.c. EAP state machine is in eap.c. EAP
+methods for the internal EAP peer are in eap_*.c. Parser for the
+configuration file is implemented in config.c.
+
+Driver interface API is defined in driver.h and all hardware/driver
+dependent functionality is implemented in driver_*.c (see below).
+
+
+Generic helper functions
+------------------------
+
+wpa_supplicant uses generic helper functions some of which are shared
+with with hostapd. The following C files are currently used:
+
+eloop.[ch]
+ event loop (select() loop with registerable timeouts, socket read
+ callbacks, and signal callbacks)
+
+common.[ch]
+ common helper functions
+
+defs.h
+ definitions shared by multiple files
+
+l2_packet.[ch]
+ Layer 2 (link) access wrapper (includes native Linux implementation
+ and wrappers for libdnet/libpcap)
+
+pcsc_funcs.[ch]
+ Wrapper for PC/SC lite SIM and smart card readers
+
+
+Cryptographic functions
+-----------------------
+
+md5.c
+ MD5 (replaced with openssl/crypto if TLS support is included)
+ HMAC-MD5 (keyed checksum for message authenticity validation)
+
+rc4.c
+ RC4 (broadcast/default key encryption)
+
+sha1.c
+ SHA-1 (replaced with openssl/crypto if TLS support is included)
+ HMAC-SHA-1 (keyed checksum for message authenticity validation)
+ PRF-SHA-1 (pseudorandom (key/nonce generation) function)
+ PBKDF2-SHA-1 (ASCII passphrase to shared secret)
+ T-PRF (for EAP-FAST)
+ TLS-PRF (RFC 2246)
+
+aes_wrap.[ch], aes.c
+ AES
+ AES Key Wrap Algorithm with 128-bit KEK, RFC3394 (broadcast/default
+ key encryption)
+ One-Key CBC MAC (OMAC1) hash with AES-128
+ AES-128 CTR mode encryption
+ AES-128 EAX mode encryption/decryption
+ AES-128 CBC
+
+crypto.[ch]
+ Wrapper functions for libcrypto (MD4 and DES)
+
+ms_funcs.[ch]
+ Helper functions for MSCHAPV2 and LEAP
+
+tls.h
+ Definition of TLS library wrapper
+
+tls_none.c
+ Dummy implementation of TLS library wrapper for cases where TLS
+ functionality is not included.
+
+tls_openssl.c
+ TLS library wrapper for openssl
+
+
+Configuration
+-------------
+
+config_ssid.h
+ Definition of per network configuration items
+
+config.h
+ Definition of the wpa_supplicant configuration
+
+config.c
+ Configuration file parser
+
+
+Control interface
+-----------------
+
+wpa_supplicant has a control interface that can be used to get status
+information and manage operations from external programs. An example,
+command line interface, wpa_cli, for this interface is included in the
+wpa_supplicant distribution.
+
+ctrl_iface.[ch]
+ wpa_supplicant-side of the control interface
+
+wpa_ctrl.[ch]
+ Library functions for external programs to provide access to the
+ wpa_supplicant control interface
+
+wpa_cli.c
+ Example program for using wpa_supplicant control interface
+
+
+EAP peer
+--------
+
+eap.[ch]
+ EAP state machine
+
+eap_defs.h
+ Common EAP definitions
+
+eap_i.h
+ Internal definitions for EAP state machine and EAP methods
+
+eap_sim_common.[ch]
+ Common code for EAP-SIM and EAP-AKA
+
+eap_tls_common.[ch]
+ Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST
+
+eap_tlv.[ch]
+ EAP-TLV code for EAP-PEAP and EAP-FAST
+
+eap_{aka,fast,gtc,leap,md5,mschapv2,otp,peap,psk,sim,tls,ttls}.c
+ EAP method implementations
+
+
+EAPOL supplicant
+----------------
+
+eapol_sm.[ch]
+ EAPOL supplicant state machine and IEEE 802.1X processing
+
+
+Windows port
+------------
+
+ndis_events.cpp
+ External program for receiving NdisMIndicateStatus() events and
+ delivering them to wpa_supplicant in more easier to use form
+
+win_if_list.c
+ External program for listing current network interface
+
+
+Test programs
+-------------
+
+radius_client.[ch]
+ RADIUS authentication client implementation for eapol_test
+
+eapol_test.c
+ Standalone EAP testing tool with integrated RADIUS authentication
+ client
+
+preauth_test.c
+ Standalone RSN pre-authentication tool
+
+
+wpa_supplicant.c
+----------------
+
+main()
+- parse command line
+- call config file parser
+- initialize Supplicant data structures
+- call functions to initialize WPA support in the driver
+- initialize event loop
+- cleanup when exiting
+
+wpa_supplicant_dot1x_receive()
+- receive master session key update from Xsupplicant (optional)
+
+wpa_supplicant_get_beacon_ie()
+
+wpa_supplicant_deauthenticate()
+
+wpa_supplicant_disassociate()
+
+wpa_supplicant_scan()
+
+wpa_supplicant_reconfig()
+- SIGHUP signal processing
+
+wpa_supplicant_terminate()
+- SIGINT and SIGTERM processing
+
+wpa_supplicant_reload_configuration()
+
+wpa_supplicant_event()
+- receive driver events (through driver wrapper functions)
+ * wpa_supplicant_scan_results(): process scan result event, BSS selection
+ * wpa_supplicant_associnfo(): process association information event
+
+wpa_supplicant_associate()
+- control association (select cipher and key management suites, initiate
+ association)
+
+wpa_supplicant_req_auth_timeout()
+
+wpa_supplicant_cancel_auth_timeout()
+
+wpa_supplicant_req_scan()
+
+wpa_supplicant_cancel_scan()
+
+wpa_supplicant_notify_eapol_done()
+
+wpa_eapol_send()
+- send EAPOL frames
+
+wpa_eapol_send_preauth()
+- send RSN preauthentication frames
+
+wpa_msg()
+- event/debug function
+
+
+wpa_supplicant.h
+----------------
+
+- driver event definition
+- common function definition (e.g., wpa_msg)
+
+
+wpa_supplicant_i.h
+------------------
+- internal definitions for wpa_supplicant; must not be included into
+ common code, EAP methods, driver interface implementations
+
+
+wpa.[ch]
+--------
+- WPA supplicant state machine and 4-Way/Group Key Handshake processing
+- PMKSA cache and RSN pre-authentication
+
+pmksa_cache_free()
+
+pmksa_cache_get()
+
+pmksa_cache_list()
+
+pmksa_candidate_free()
+
+wpa_parse_wpa_ie()
+- WPA/RSN IE parsing
+
+wpa_gen_wpa_ei()
+- WPA/RSN IE generation
+
+wpa_supplicant_get_ssid()
+
+wpa_supplicant_key_request()
+- trigger function to start key requests
+
+wpa_sm_rx_eapol()
+- WPA processing for received EAPOL-Key frames
+ * wpa_supplicant_process_1_of_4() (message 1 of 4-Way Handshake)
+ * wpa_supplicant_process_3_of_4() (message 3 of 4-Way Handshake)
+ * wpa_supplicant_process_1_of_2() (message 1 of Group Key Handshake)
+
+wpa_supplicant_rx_eapol()
+- l2_packet RX callback for EAPOL frames; sends the frames to WPA and EAPOL
+ state machines for further processing
+
+wpa_get_mib()
+
+rsn_preauth_receive()
+- l2_packet RX callback for preauthentication frames
+
+rsn_preauth_eapol_cb()
+- callback function to be called when EAPOL authentication has been completed
+ (either successfully or unsuccessfully) for RSN pre-authentication
+
+rsn_preauth_init()
+rsn_preauth_deinit()
+
+pmksa_candidate_add()
+- add a BSSID to PMKSA candidate list
+
+rsn_preauth_scan_results()
+- update RSN pre-authentication candidate list based on scan results
+
+
+Driver wrapper implementation (driver.h, drivers.c)
+---------------------------------------------------
+
+All hardware and driver dependent functionality is implemented in as a
+separate C file(s) implementing defined wrapper functions. Other parts
+of the wpa_supplicant are designed to be hardware, driver, and operating
+system independent.
+
+Driver wrappers need to implement whatever calls are used in the
+target operating system/driver for controlling wireless LAN
+devices. As an example, in case of Linux, these are mostly some glue
+code and ioctl() calls and netlink message parsing for Linux Wireless
+Extensions. Since all features required for WPA are not yet included
+in Wireless Extensions, some driver specific code is used in the
+example implementation for Host AP driver. These driver dependent parts
+are to be replaced with generic code once the needed changes are
+included in the Wireless Extensions. After that, all Linux drivers, at
+least in theory, could use the same driver wrapper code.
+
+A driver wrapper needs to implement some or all of the functions
+defined in driver.h (see that file for detailed documentation of the
+functions). Hardware independent parts of wpa_supplicant will call
+these functions to control the driver/wlan card. In addition, support
+for driver events is required. The event callback function,
+wpa_supplicant_event(), and its parameters are documented in
+wpa_supplicant.h. In addition, pointer to the 'struct wpa_driver_ops'
+needs to be registered in drivers.c file.
+
+When porting to other operating systems, driver wrapper should be
+modified to use the native interface of the target OS. It is possible
+that some extra requirements for the interface between the driver
+wrapper and generic wpa_supplicant code are discovered during porting
+to a new operating system. These will be addresses on case by case
+basic by modifying the interface and updating the other driver
+wrappers for this. The goal is to avoid changing this interface
+without very good reasons in order to limit the number of changes
+needed to other wrappers and hardware independent parts of
+wpa_supplicant.
+
+Generic Linux Wireless Extensions functions are implemented in
+driver_wext.c. All Linux driver wrappers can use these when the kernel
+driver supports the generic ioctl()s and wireless events. Driver
+specific functions are implemented in separate C files, e.g.,
+driver_hostap.c. These files need to define struct wpa_driver_ops
+entry that will be used in wpa_supplicant.c when calling driver
+functions. These entries need to be added to the lists in
+wpa_supplicant_set_driver() and usage() functions in wpa_supplicant.c.
+
+In general, it is likely to be useful to first take a look at couple
+of the driver interfaces before starting on implementing a new
+one. driver_hostap.c and driver_wext.c include a complete
+implementation for Linux drivers that use wpa_supplicant-based control
+of WPA IE and roaming. driver_ndis.c (with help from driver_ndis_.c)
+is an example of a complete interface for Windows NDIS interface for
+drivers that generate WPA IE themselves and decide when to roam. These
+example implementations include full support for all security modes.
+
+
+Driver requirements for WPA
+---------------------------
+
+WPA introduces new requirements for the device driver. At least some
+of these need to be implemented in order to provide enough support for
+wpa_supplicant.
+
+TKIP/CCMP
+
+WPA requires that the pairwise cipher suite (encryption algorithm for
+unicast data packets) is TKIP or CCMP. These are new encryption
+protocols and thus, the driver will need to be modified to support
+them. Depending on the used wlan hardware, some parts of these may be
+implemented by the hardware/firmware.
+
+Specification for both TKIP and CCMP is available from IEEE (IEEE
+802.11i draft version 3.0). Fully functional, hardware independent
+implementation of both encryption protocols is also available in Host
+AP driver (driver/modules/hostap_{tkip,ccmp}.c).
+
+The driver will also need to provide configuration mechanism to allow
+user space programs to configure TKIP and CCMP. Current Linux Wireless
+Extensions (v16) does not yet support these algorithms or
+individual/non-default keys. Host AP driver has an example of private
+ioctl()s for this. Eventually, this should be replaced with modified
+Linux Wireless Extensions.
+
+Roaming control and scanning support
+
+wpa_supplicant controls AP selections based on the information
+received from Beacon and/or Probe Response frames. This means that the
+driver should support external control for scan process. In case of
+Linux, use of new Wireless Extensions scan support (i.e., 'iwlist
+wlan0 scan') is recommended. The current driver wrapper (driver_wext.c)
+uses this for scan results.
+
+Scan results must also include WPA information element. This is not
+yet defined in Linux Wireless Extensions and Host AP driver uses a
+custom event to provide the full WPA IE (including element id and
+length) as a hex string that is included in the scan results.
+Eventually, this should be defined as a Wireless Extensions ioctl
+that can be used both with scan results and with configuration of WPA IE
+for association request (and Beacon/Probe Response in case of an
+AP/IBSS).
+
+wpa_supplicant needs to also be able to request the driver to
+associate with a specific BSS. Current Host AP driver and matching
+driver_hostap.c wrapper uses following sequence for this
+request. Similar/identical mechanism should be usable also with other
+drivers.
+
+- set WPA IE for AssocReq with private ioctl
+- set SSID with SIOCSIWESSID
+- set channel/frequency with SIOCSIWFREQ
+- set BSSID with SIOCSIWAP
+ (this last ioctl will trigger the driver to request association)
+
+WPA IE generation
+
+wpa_supplicant selects which cipher suites and key management suites
+are used. Based on this information, it generates a WPA IE. This is
+provided to the driver interface in the associate call. This does not
+match with Windows NDIS drivers which generate the WPA IE
+themselves.
+
+wpa_supplicant allows Windows NDIS-like behavior by providing the
+selected cipher and key management suites in the associate call. If
+the driver generates its own WPA IE and that differs from the one
+generated by wpa_supplicant, the driver has to inform wpa_supplicant
+about the used WPA IE (i.e., the one it used in (Re)Associate
+Request). This notification is done using EVENT_ASSOCINFO event (see
+wpa_supplicant.h).
+
+Driver events
+
+wpa_supplicant needs to receive event callbacks when certain events
+occur (association, disassociation, Michael MIC failure, scan results
+available, PMKSA caching candidate). These events and the callback
+details are defined in wpa_supplicant.h.
+
+On Linux, association and disassociation can use existing Wireless
+Extensions event that is reporting new AP with SIOCGIWAP
+event. Similarly, completion of scan can be reported with SIOCGIWSCAN
+event.
+
+Michael MIC failure event is not yet included in Wireless Extensions,
+so this needs a custom event. Host AP driver uses custom event with
+following contents: MLME-MICHAELMICFAILURE.indication(keyid=#
+broadcast/unicast addr=addr2). This is the recommended format until
+the event is added to Linux Wireless Extensions.
diff --git a/contrib/wpa_supplicant/doc/wpa_supplicant.fig b/contrib/wpa_supplicant/doc/wpa_supplicant.fig
new file mode 100644
index 000000000000..dc1d9dfcf738
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/wpa_supplicant.fig
@@ -0,0 +1,221 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 1875 4050 2925 4350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
+4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
+-6
+6 3450 1200 4275 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3450 1200 4275 1200 4275 1500 3450 1500 3450 1200
+4 0 0 50 -1 0 12 0.0000 4 180 585 3600 1425 wpa_cli\001
+-6
+6 4725 1200 5925 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
+4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
+-6
+6 6000 2700 7200 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
+4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
+-6
+6 6000 4950 7200 5475
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
+4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
+-6
+6 8700 3000 9375 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8700 3000 9375 3000 9375 3300 8700 3300 8700 3000
+4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3225 crypto\001
+-6
+6 4350 3900 5025 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
+4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
+4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
+-6
+6 4275 2550 5100 2850
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
+4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
+-6
+6 6000 3900 7200 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
+4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
+-6
+6 1800 6000 7800 8100
+6 1800 6000 7800 7200
+6 1800 6900 2700 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
+4 0 0 50 -1 0 12 0.0000 4 105 375 1875 7125 wext\001
+-6
+6 4725 6900 5625 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
+4 0 0 50 -1 0 12 0.0000 4 135 555 4800 7125 hermes\001
+-6
+6 6675 6900 7800 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
+4 0 0 50 -1 0 12 0.0000 4 180 930 6750 7125 ndiswrapper\001
+-6
+6 5700 6900 6600 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
+4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 atmel\001
+-6
+6 4275 6000 5100 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
+4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+ 2250 6900 2250 6600 7200 6600 7200 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3225 6900 3225 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4200 6900 4200 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5175 6900 5175 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6150 6900 6150 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 6600 4650 6300
+4 0 0 50 -1 0 12 0.0000 4 180 510 2850 7125 hostap\001
+4 0 0 50 -1 0 12 0.0000 4 135 600 3825 7125 madwifi\001
+-6
+6 3525 7800 5775 8100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
+4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
+-6
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 2250 7200 4200 7800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 7200 7200 5100 7800
+-6
+6 9600 3000 10275 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9600 3000 10275 3000 10275 3300 9600 3300 9600 3000
+4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3225 TLS\001
+-6
+6 8100 4425 10425 6975
+6 8175 4725 9225 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
+4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
+-6
+6 9300 4725 10350 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
+4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
+-6
+6 8175 5100 9225 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
+4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
+-6
+6 9300 5100 10350 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
+4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
+-6
+6 8175 5475 9225 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
+4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
+-6
+6 9300 5475 10350 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
+4 0 0 50 -1 0 12 0.0000 4 135 765 9375 5700 EAP-OTP\001
+-6
+6 8175 5850 9225 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
+4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
+-6
+6 8175 6600 9675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
+-6
+6 9300 6225 10350 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 6225 10350 6225 10350 6525 9300 6525 9300 6225
+4 0 0 50 -1 0 12 0.0000 4 135 465 9375 6450 LEAP\001
+-6
+6 8175 6225 9225 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
+4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
+-6
+6 9300 5850 10350 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
+4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
+4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
+-6
+2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
+ 1275 4200 1875 4200
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 4500 2550 3900 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 4800 2550 5400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2925 4200 4350 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 3900 6000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 4200 6000 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 6000 4650 4425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 4425 6600 4950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 3225 6600 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 5250 8100 5250
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 9075 4425 9075 3300
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 3000 8700 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 3900 4650 2850
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 4125 8700 3300
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6000 4350 5025 6000
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6000 3150 4875 6000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 9900 4425 9900 3300
+4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
+4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
+4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
+4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
+4 0 0 50 -1 2 14 0.0000 4 195 1425 1637 2371 wpa_supplicant\001
diff --git a/contrib/wpa_supplicant/driver.h b/contrib/wpa_supplicant/driver.h
new file mode 100644
index 000000000000..da28014c9270
--- /dev/null
+++ b/contrib/wpa_supplicant/driver.h
@@ -0,0 +1,436 @@
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#define WPA_SUPPLICANT_DRIVER_VERSION 2
+
+typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
+typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
+ CIPHER_WEP104 } wpa_cipher;
+typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
+ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
+
+#define AUTH_ALG_OPEN_SYSTEM 0x01
+#define AUTH_ALG_SHARED_KEY 0x02
+#define AUTH_ALG_LEAP 0x04
+
+#define IEEE80211_MODE_INFRA 0
+#define IEEE80211_MODE_IBSS 1
+
+#define SSID_MAX_WPA_IE_LEN 40
+struct wpa_scan_result {
+ u8 bssid[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+ u8 wpa_ie[SSID_MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[SSID_MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+ int freq; /* MHz */
+ int caps; /* e.g. privacy */
+ int qual; /* signal quality */
+ int noise;
+ int level;
+ int maxrate;
+};
+
+/* Parameters for associate driver_ops. */
+struct wpa_driver_associate_params {
+ /* BSSID of the selected AP */
+ const u8 *bssid;
+
+ /* The selected SSID and its length in bytes */
+ const u8 *ssid;
+ size_t ssid_len;
+
+ /* frequency that the selected AP is using (in MHz as
+ * reported in the scan results) */
+ int freq;
+
+ /* WPA information element to be included in (Re)Association
+ * Request (including information element id and length). Use
+ * of this WPA IE is optional. If the driver generates the WPA
+ * IE, it can use @pairwise_suite, @group_suite, and
+ * @key_mgmt_suite to select proper algorithms. In this case,
+ * the driver has to notify wpa_supplicant about the used WPA
+ * IE by generating an event that the interface code will
+ * convert into EVENT_ASSOCINFO data (see wpa_supplicant.h).
+ * When using WPA2/IEEE 802.11i, @wpa_ie is used for RSN IE
+ * instead. The driver can determine which version is used by
+ * looking at the first byte of the IE (0xdd for WPA, 0x30 for
+ * WPA2/RSN). @wpa_ie_len: length of the @wpa_ie */
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+
+ /* The selected pairwise/group cipher and key management
+ * suites. These are usually ignored if @wpa_ie is used. */
+ wpa_cipher pairwise_suite;
+ wpa_cipher group_suite;
+ wpa_key_mgmt key_mgmt_suite;
+
+ int auth_alg; /* bit field of AUTH_ALG_* */
+ int mode; /* IEEE80211_MODE_* */
+};
+
+struct wpa_driver_capa {
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA 0x00000001
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2 0x00000002
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK 0x00000004
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK 0x00000008
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE 0x00000010
+ unsigned int key_mgmt;
+
+#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001
+#define WPA_DRIVER_CAPA_ENC_WEP104 0x00000002
+#define WPA_DRIVER_CAPA_ENC_TKIP 0x00000004
+#define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008
+ unsigned int enc;
+
+#define WPA_DRIVER_AUTH_OPEN 0x00000001
+#define WPA_DRIVER_AUTH_SHARED 0x00000002
+#define WPA_DRIVER_AUTH_LEAP 0x00000004
+ unsigned int auth;
+
+/* Driver generated WPA/RSN IE */
+#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
+ unsigned int flags;
+};
+
+
+struct wpa_driver_ops {
+ /* name of the driver interface */
+ const char *name;
+ /* one line description of the driver interface */
+ const char *desc;
+
+ /**
+ * get_bssid - get the current BSSID
+ * @priv: private driver interface data
+ * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes)
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Query kernel driver for the current BSSID and copy it to @bssid.
+ * Setting @bssid to 00:00:00:00:00:00 is recommended if the STA is not
+ * associated.
+ */
+ int (*get_bssid)(void *priv, u8 *bssid);
+
+ /**
+ * get_ssid - get the current SSID
+ * @priv: private driver interface data
+ * @ssid: buffer for SSID (at least 32 bytes)
+ *
+ * Returns: length of the SSID on success, -1 on failure
+ *
+ * Query kernel driver for the current SSID and copy it to @ssid.
+ * Returning zero is recommended if the STA is not associated.
+ *
+ * Note: SSID is an array of octets, i.e., it is not nul terminated and
+ * can, at least in theory, contain control characters (including nul)
+ * and as such, should be processed as binary data, not a printable
+ * string.
+ */
+ int (*get_ssid)(void *priv, u8 *ssid);
+
+ /**
+ * set_wpa - enable/disable WPA support
+ * @priv: private driver interface data
+ * @enabled: 1 = enable, 0 = disable
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Configure the kernel driver to enable/disable WPA support. This may
+ * be empty function, if WPA support is always enabled. Common
+ * configuration items are WPA IE (clearing it when WPA support is
+ * disabled), Privacy flag for capability field, roaming mode (need to
+ * allow wpa_supplicant to control roaming).
+ */
+ int (*set_wpa)(void *priv, int enabled);
+
+ /**
+ * set_key - configure encryption key
+ * @priv: private driver interface data
+ * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
+ * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
+ * broadcast/default keys
+ * @key_idx: key index (0..3), always 0 for unicast keys
+ * @set_tx: configure this key as the default Tx key (only used when
+ * driver does not support separate unicast/individual key
+ * @seq: sequence number/packet number, @seq_len octets, the next
+ * packet number to be used for in replay protection; configured
+ * for Rx keys (in most cases, this is only used with broadcast
+ * keys and set to zero for unicast keys)
+ * @seq_len: length of the @seq, depends on the algorithm:
+ * TKIP: 6 octets, CCMP: 6 octets
+ * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+ * 8-byte Rx Mic Key
+ * @key_len: length of the key buffer in octets (WEP: 5 or 13,
+ * TKIP: 32, CCMP: 16)
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Configure the given key for the kernel driver. If the driver
+ * supports separate individual keys (4 default keys + 1 individual),
+ * @addr can be used to determine whether the key is default or
+ * individual. If only 4 keys are supported, the default key with key
+ * index 0 is used as the individual key. STA must be configured to use
+ * it as the default Tx key (@set_tx is set) and accept Rx for all the
+ * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
+ * broadcast keys, so key index 0 is available for this kind of
+ * configuration.
+ */
+ int (*set_key)(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len);
+
+ /**
+ * init - initialize driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ *
+ * Return: pointer to private data, %NULL on failure
+ *
+ * Initialize driver interface, including event processing for kernel
+ * driver events (e.g., associated, scan results, Michael MIC failure).
+ * This function can allocate a private configuration data area for
+ * @ctx, file descriptor, interface name, etc. information that may be
+ * needed in future driver operations. If this is not used, non-NULL
+ * value will need to be returned because %NULL is used to indicate
+ * failure. The returned value will be used as 'void *priv' data for
+ * all other driver_ops functions.
+ *
+ * The main event loop (eloop.c) of wpa_supplicant can be used to
+ * register callback for read sockets (eloop_register_read_sock()).
+ *
+ * See wpa_supplicant.h for more information about events and
+ * wpa_supplicant_event() function.
+ */
+ void * (*init)(void *ctx, const char *ifname);
+
+ /**
+ * deinit - deinitialize driver interface
+ * @priv: pointer to private data (from matching
+ * wpa_driver_events_init())
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in init() handler.
+ */
+ void (*deinit)(void *priv);
+
+ /**
+ * set_countermeasures - enable/disable TKIP countermeasures
+ * @priv: private driver interface data
+ * @enabled: 1 = countermeasures enabled, 0 = disabled
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * Configure TKIP countermeasures. When these are enabled, the driver
+ * should drop all received and queued frames that are using TKIP.
+ */
+ int (*set_countermeasures)(void *priv, int enabled);
+
+ /**
+ * set_drop_unencrypted - enable/disable unencrypted frame filtering
+ * @priv: private driver interface data
+ * @enabled: 1 = unencrypted Tx/Rx frames will be dropped, 0 = disabled
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * Configure the driver to drop all non-EAPOL frames (both receive and
+ * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
+ * still be allowed for key negotiation.
+ */
+ int (*set_drop_unencrypted)(void *priv, int enabled);
+
+ /**
+ * scan - request the driver to initiate scan
+ * @priv: private driver interface data
+ * @ssid: specific SSID to scan for (ProbeReq) or %NULL to scan for
+ * all SSIDs (either active scan with broadcast SSID or passive
+ * scan
+ * @ssid_len: length of the SSID
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * Once the scan results are ready, the driver should report scan
+ * results event for wpa_supplicant which will eventually request the
+ * results with wpa_driver_get_scan_results().
+ */
+ int (*scan)(void *priv, const u8 *ssid, size_t ssid_len);
+
+ /**
+ * get_scan_results - fetch the latest scan results
+ * @priv: private driver interface data
+ * @results: pointer to buffer for scan results
+ * @max_size: maximum number of entries (buffer size)
+ *
+ * Return: number of scan result entries used on success, -1 on failure
+ *
+ * If scan results include more than @max_size BSSes, @max_size will be
+ * returned and the remaining entries will not be included in the
+ * buffer.
+ */
+ int (*get_scan_results)(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size);
+
+ /**
+ * deauthenticate - request driver to deauthenticate
+ * @priv: private driver interface data
+ * @addr: peer address (BSSID of the AP)
+ * @reason_code: 16-bit reason code to be sent in the deauthentication
+ * frame
+ *
+ * Return: 0 on success, -1 on failure
+ */
+ int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
+
+ /**
+ * disassociate - request driver to disassociate
+ * @priv: private driver interface data
+ * @addr: peer address (BSSID of the AP)
+ * @reason_code: 16-bit reason code to be sent in the disassociation
+ * frame
+ *
+ * Return: 0 on success, -1 on failure
+ */
+ int (*disassociate)(void *priv, const u8 *addr, int reason_code);
+
+ /**
+ * associate - request driver to associate
+ * @priv: private driver interface data
+ * @params: association parameters
+ *
+ * Return: 0 on success, -1 on failure
+ */
+ int (*associate)(void *priv,
+ struct wpa_driver_associate_params *params);
+
+ /**
+ * set_auth_alg - set IEEE 802.11 authentication algorithm
+ * @priv: private driver interface data
+ * @auth_alg: bit field of AUTH_ALG_*
+ *
+ * If the driver supports more than one authentication algorithm at the
+ * same time, it should configure all supported algorithms. If not, one
+ * algorithm needs to be selected arbitrarily. Open System
+ * authentication should be ok for most cases and it is recommended to
+ * be used if other options are not supported. Static WEP configuration
+ * may also use Shared Key authentication and LEAP requires its own
+ * algorithm number. For LEAP, user can make sure that only one
+ * algorithm is used at a time by configuring LEAP as the only
+ * supported EAP method. This information is also available in
+ * associate() params, so set_auth_alg may not be needed in case of
+ * most drivers.
+ *
+ * Return: 0 on success, -1 on failure
+ */
+ int (*set_auth_alg)(void *priv, int auth_alg);
+
+ /**
+ * add_pmkid - add PMKSA cache entry to the driver
+ * @priv: private driver interface data
+ * @bssid: BSSID for the PMKSA cache entry
+ * @pmkid: PMKID for the PMKSA cache entry
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * This function is called when a new PMK is received, as a result of
+ * either normal authentication or RSN pre-authentication.
+ *
+ * If the driver generates RSN IE, i.e., it does not use @wpa_ie in
+ * associate(), add_pmkid() can be used to add new PMKSA cache entries
+ * in the driver. If the driver uses @wpa_ie from wpa_supplicant, this
+ * driver_ops function does not need to be implemented. Likewise, if
+ * the driver does not support WPA, this function is not needed.
+ */
+ int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+ /**
+ * remove_pmkid - remove PMKSA cache entry to the driver
+ * @priv: private driver interface data
+ * @bssid: BSSID for the PMKSA cache entry
+ * @pmkid: PMKID for the PMKSA cache entry
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * This function is called when the supplicant drops a PMKSA cache
+ * entry for any reason.
+ *
+ * If the driver generates RSN IE, i.e., it does not use @wpa_ie in
+ * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+ * between the driver and wpa_supplicant. If the driver uses @wpa_ie
+ * from wpa_supplicant, this driver_ops function does not need to be
+ * implemented. Likewise, if the driver does not support WPA, this
+ * function is not needed.
+ */
+ int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+ /**
+ * flush_pmkid - flush PMKSA cache
+ * @priv: private driver interface data
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * This function is called when the supplicant drops all PMKSA cache
+ * entries for any reason.
+ *
+ * If the driver generates RSN IE, i.e., it does not use @wpa_ie in
+ * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+ * between the driver and wpa_supplicant. If the driver uses @wpa_ie
+ * from wpa_supplicant, this driver_ops function does not need to be
+ * implemented. Likewise, if the driver does not support WPA, this
+ * function is not needed.
+ */
+ int (*flush_pmkid)(void *priv);
+
+ /**
+ * flush_pmkid - flush PMKSA cache
+ * @priv: private driver interface data
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * Get driver/firmware/hardware capabilities.
+ */
+ int (*get_capa)(void *priv, struct wpa_driver_capa *capa);
+
+ /**
+ * poll - poll driver for association information
+ * @priv: private driver interface data
+ *
+ * This is an option callback that can be used when the driver does not
+ * provide event mechanism for association events. This is called when
+ * receiving WPA EAPOL-Key messages that require association
+ * information. The driver interface is supposed to generate associnfo
+ * event before returning from this callback function. In addition, the
+ * driver interface should generate an association event after having
+ * sent out associnfo.
+ */
+ void (*poll)(void *priv);
+
+ /**
+ * get_ifname - get interface name
+ *
+ * This optional function can be used to allow the driver interface to
+ * replace the interface name with something else, e.g., based on an
+ * interface mapping from a more descriptive name.
+ *
+ * Returns a pointer to the interface name. This can differ from the
+ * interface name used in init() call.
+ */
+ const char * (*get_ifname)(void *priv);
+
+ /**
+ * get_mac_addr - get own MAC address
+ *
+ * This optional function can be used to get the own MAC address of the
+ * device from the driver interface code. This is only needed if the
+ * l2_packet implementation for the OS does not provide easy access to
+ * a MAC address. */
+ const u8 * (*get_mac_addr)(void *priv);
+};
+
+#endif /* DRIVER_H */
diff --git a/contrib/wpa_supplicant/drivers.c b/contrib/wpa_supplicant/drivers.c
new file mode 100644
index 000000000000..cb016ba803e5
--- /dev/null
+++ b/contrib/wpa_supplicant/drivers.c
@@ -0,0 +1,96 @@
+/*
+ * WPA Supplicant / driver interface list
+ * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+
+
+#ifdef CONFIG_DRIVER_HOSTAP
+extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_PRISM54
+extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */
+#endif /* CONFIG_DRIVER_PRISM54 */
+#ifdef CONFIG_DRIVER_HERMES
+extern struct wpa_driver_ops wpa_driver_hermes_ops; /* driver_hermes.c */
+#endif /* CONFIG_DRIVER_HERMES */
+#ifdef CONFIG_DRIVER_MADWIFI
+extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
+#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_ATMEL
+extern struct wpa_driver_ops wpa_driver_atmel_ops; /* driver_atmel.c */
+#endif /* CONFIG_DRIVER_ATMEL */
+#ifdef CONFIG_DRIVER_WEXT
+extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NDISWRAPPER
+/* driver_ndiswrapper.c */
+extern struct wpa_driver_ops wpa_driver_ndiswrapper_ops;
+#endif /* CONFIG_DRIVER_NDISWRAPPER */
+#ifdef CONFIG_DRIVER_BROADCOM
+extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */
+#endif /* CONFIG_DRIVER_BROADCOM */
+#ifdef CONFIG_DRIVER_IPW
+extern struct wpa_driver_ops wpa_driver_ipw_ops; /* driver_ipw.c */
+#endif /* CONFIG_DRIVER_IPW */
+#ifdef CONFIG_DRIVER_BSD
+extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_NDIS
+extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_TEST
+extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
+#endif /* CONFIG_DRIVER_TEST */
+
+
+struct wpa_driver_ops *wpa_supplicant_drivers[] =
+{
+#ifdef CONFIG_DRIVER_HOSTAP
+ &wpa_driver_hostap_ops,
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_PRISM54
+ &wpa_driver_prism54_ops,
+#endif /* CONFIG_DRIVER_PRISM54 */
+#ifdef CONFIG_DRIVER_HERMES
+ &wpa_driver_hermes_ops,
+#endif /* CONFIG_DRIVER_HERMES */
+#ifdef CONFIG_DRIVER_MADWIFI
+ &wpa_driver_madwifi_ops,
+#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_ATMEL
+ &wpa_driver_atmel_ops,
+#endif /* CONFIG_DRIVER_ATMEL */
+#ifdef CONFIG_DRIVER_WEXT
+ &wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NDISWRAPPER
+ &wpa_driver_ndiswrapper_ops,
+#endif /* CONFIG_DRIVER_NDISWRAPPER */
+#ifdef CONFIG_DRIVER_BROADCOM
+ &wpa_driver_broadcom_ops,
+#endif /* CONFIG_DRIVER_BROADCOM */
+#ifdef CONFIG_DRIVER_IPW
+ &wpa_driver_ipw_ops,
+#endif /* CONFIG_DRIVER_IPW */
+#ifdef CONFIG_DRIVER_BSD
+ &wpa_driver_bsd_ops,
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_NDIS
+ &wpa_driver_ndis_ops,
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_TEST
+ &wpa_driver_test_ops,
+#endif /* CONFIG_DRIVER_TEST */
+ NULL
+};
diff --git a/contrib/wpa_supplicant/eap.c b/contrib/wpa_supplicant/eap.c
new file mode 100644
index 000000000000..a76b942464e8
--- /dev/null
+++ b/contrib/wpa_supplicant/eap.c
@@ -0,0 +1,1243 @@
+/*
+ * WPA Supplicant / EAP state machines
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "tls.h"
+#include "md5.h"
+
+
+#define EAP_MAX_AUTH_ROUNDS 50
+
+
+#ifdef EAP_MD5
+extern const struct eap_method eap_method_md5;
+#endif
+#ifdef EAP_TLS
+extern const struct eap_method eap_method_tls;
+#endif
+#ifdef EAP_MSCHAPv2
+extern const struct eap_method eap_method_mschapv2;
+#endif
+#ifdef EAP_PEAP
+extern const struct eap_method eap_method_peap;
+#endif
+#ifdef EAP_TTLS
+extern const struct eap_method eap_method_ttls;
+#endif
+#ifdef EAP_GTC
+extern const struct eap_method eap_method_gtc;
+#endif
+#ifdef EAP_OTP
+extern const struct eap_method eap_method_otp;
+#endif
+#ifdef EAP_SIM
+extern const struct eap_method eap_method_sim;
+#endif
+#ifdef EAP_LEAP
+extern const struct eap_method eap_method_leap;
+#endif
+#ifdef EAP_PSK
+extern const struct eap_method eap_method_psk;
+#endif
+#ifdef EAP_AKA
+extern const struct eap_method eap_method_aka;
+#endif
+#ifdef EAP_FAST
+extern const struct eap_method eap_method_fast;
+#endif
+
+static const struct eap_method *eap_methods[] =
+{
+#ifdef EAP_MD5
+ &eap_method_md5,
+#endif
+#ifdef EAP_TLS
+ &eap_method_tls,
+#endif
+#ifdef EAP_MSCHAPv2
+ &eap_method_mschapv2,
+#endif
+#ifdef EAP_PEAP
+ &eap_method_peap,
+#endif
+#ifdef EAP_TTLS
+ &eap_method_ttls,
+#endif
+#ifdef EAP_GTC
+ &eap_method_gtc,
+#endif
+#ifdef EAP_OTP
+ &eap_method_otp,
+#endif
+#ifdef EAP_SIM
+ &eap_method_sim,
+#endif
+#ifdef EAP_LEAP
+ &eap_method_leap,
+#endif
+#ifdef EAP_PSK
+ &eap_method_psk,
+#endif
+#ifdef EAP_AKA
+ &eap_method_aka,
+#endif
+#ifdef EAP_FAST
+ &eap_method_fast,
+#endif
+};
+#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
+
+
+const struct eap_method * eap_sm_get_eap_methods(int method)
+{
+ int i;
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ if (eap_methods[i]->method == method)
+ return eap_methods[i];
+ }
+ return NULL;
+}
+
+
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method);
+static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len);
+static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len);
+static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len);
+static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len);
+static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len);
+static const char * eap_sm_method_state_txt(int state);
+static const char * eap_sm_decision_txt(int decision);
+
+
+/* Definitions for clarifying state machine implementation */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
+ int global)
+
+#define SM_ENTRY(machine, state) \
+if (!global || sm->machine ## _state != machine ## _ ## state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
+} \
+sm->machine ## _state = machine ## _ ## state;
+
+#define SM_ENTER(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 0)
+#define SM_ENTER_GLOBAL(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 1)
+
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(struct eap_sm *sm)
+
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+
+static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
+{
+ return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
+}
+
+
+static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
+ Boolean value)
+{
+ sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
+}
+
+
+static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
+{
+ return sm->eapol_cb->get_int(sm->eapol_ctx, var);
+}
+
+
+static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
+ unsigned int value)
+{
+ sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
+}
+
+
+static u8 * eapol_get_eapReqData(struct eap_sm *sm, size_t *len)
+{
+ return sm->eapol_cb->get_eapReqData(sm->eapol_ctx, len);
+}
+
+
+static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
+{
+ if (sm->m == NULL || sm->eap_method_priv == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
+ "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
+ sm->m->deinit(sm, sm->eap_method_priv);
+ sm->eap_method_priv = NULL;
+ sm->m = NULL;
+}
+
+
+SM_STATE(EAP, INITIALIZE)
+{
+ SM_ENTRY(EAP, INITIALIZE);
+ if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
+ sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
+ "fast reauthentication");
+ sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
+ } else {
+ eap_deinit_prev_method(sm, "INITIALIZE");
+ }
+ sm->selectedMethod = EAP_TYPE_NONE;
+ sm->methodState = METHOD_NONE;
+ sm->allowNotifications = TRUE;
+ sm->decision = DECISION_FAIL;
+ eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+ eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+ eapol_set_bool(sm, EAPOL_eapFail, FALSE);
+ free(sm->eapKeyData);
+ sm->eapKeyData = NULL;
+ sm->eapKeyAvailable = FALSE;
+ eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
+ sm->lastId = -1; /* new session - make sure this does not match with
+ * the first EAP-Packet */
+ /* draft-ietf-eap-statemachine-02.pdf does not reset eapResp and
+ * eapNoResp here. However, this seemed to be able to trigger cases
+ * where both were set and if EAPOL state machine uses eapNoResp first,
+ * it may end up not sending a real reply correctly. This occurred
+ * when the workaround in FAIL state set eapNoResp = TRUE.. Maybe that
+ * workaround needs to be fixed to do something else(?) */
+ eapol_set_bool(sm, EAPOL_eapResp, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
+ sm->num_rounds = 0;
+}
+
+
+SM_STATE(EAP, DISABLED)
+{
+ SM_ENTRY(EAP, DISABLED);
+ sm->num_rounds = 0;
+}
+
+
+SM_STATE(EAP, IDLE)
+{
+ SM_ENTRY(EAP, IDLE);
+}
+
+
+SM_STATE(EAP, RECEIVED)
+{
+ u8 *eapReqData;
+ size_t eapReqDataLen;
+
+ SM_ENTRY(EAP, RECEIVED);
+ eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
+ /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
+ eap_sm_parseEapReq(sm, eapReqData, eapReqDataLen);
+ sm->num_rounds++;
+}
+
+
+SM_STATE(EAP, GET_METHOD)
+{
+ SM_ENTRY(EAP, GET_METHOD);
+ if (eap_sm_allowMethod(sm, sm->reqMethod)) {
+ int reinit = 0;
+ if (sm->fast_reauth &&
+ sm->m && sm->m->method == sm->reqMethod &&
+ sm->m->has_reauth_data &&
+ sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP: using previous method data"
+ " for fast re-authentication");
+ reinit = 1;
+ } else
+ eap_deinit_prev_method(sm, "GET_METHOD");
+ sm->selectedMethod = sm->reqMethod;
+ if (sm->m == NULL)
+ sm->m = eap_sm_get_eap_methods(sm->selectedMethod);
+ if (sm->m) {
+ wpa_printf(MSG_DEBUG, "EAP: initialize selected EAP "
+ "method (%d, %s)",
+ sm->selectedMethod, sm->m->name);
+ if (reinit)
+ sm->eap_method_priv = sm->m->init_for_reauth(
+ sm, sm->eap_method_priv);
+ else
+ sm->eap_method_priv = sm->m->init(sm);
+ if (sm->eap_method_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP: Failed to "
+ "initialize EAP method %d",
+ sm->selectedMethod);
+ sm->m = NULL;
+ sm->methodState = METHOD_NONE;
+ sm->selectedMethod = EAP_TYPE_NONE;
+ } else {
+ sm->methodState = METHOD_INIT;
+ return;
+ }
+ }
+ }
+
+ free(sm->eapRespData);
+ sm->eapRespData = eap_sm_buildNak(sm, sm->reqId, &sm->eapRespDataLen);
+}
+
+
+SM_STATE(EAP, METHOD)
+{
+ u8 *eapReqData;
+ size_t eapReqDataLen;
+ struct eap_method_ret ret;
+
+ SM_ENTRY(EAP, METHOD);
+ if (sm->m == NULL) {
+ wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
+ return;
+ }
+
+ eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
+
+ /* Get ignore, methodState, decision, allowNotifications, and
+ * eapRespData. */
+ memset(&ret, 0, sizeof(ret));
+ ret.ignore = sm->ignore;
+ ret.methodState = sm->methodState;
+ ret.decision = sm->decision;
+ ret.allowNotifications = sm->allowNotifications;
+ free(sm->eapRespData);
+ sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
+ eapReqData, eapReqDataLen,
+ &sm->eapRespDataLen);
+ wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
+ "methodState=%s decision=%s",
+ ret.ignore ? "TRUE" : "FALSE",
+ eap_sm_method_state_txt(ret.methodState),
+ eap_sm_decision_txt(ret.decision));
+
+ sm->ignore = ret.ignore;
+ if (sm->ignore)
+ return;
+ sm->methodState = ret.methodState;
+ sm->decision = ret.decision;
+ sm->allowNotifications = ret.allowNotifications;
+
+ if (sm->m->isKeyAvailable && sm->m->getKey &&
+ sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
+ free(sm->eapKeyData);
+ sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
+ &sm->eapKeyDataLen);
+ }
+}
+
+
+SM_STATE(EAP, SEND_RESPONSE)
+{
+ SM_ENTRY(EAP, SEND_RESPONSE);
+ free(sm->lastRespData);
+ if (sm->eapRespData) {
+ if (sm->workaround)
+ memcpy(sm->last_md5, sm->req_md5, 16);
+ sm->lastId = sm->reqId;
+ sm->lastRespData = malloc(sm->eapRespDataLen);
+ if (sm->lastRespData) {
+ memcpy(sm->lastRespData, sm->eapRespData,
+ sm->eapRespDataLen);
+ sm->lastRespDataLen = sm->eapRespDataLen;
+ }
+ eapol_set_bool(sm, EAPOL_eapResp, TRUE);
+ } else
+ sm->lastRespData = NULL;
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+}
+
+
+SM_STATE(EAP, DISCARD)
+{
+ SM_ENTRY(EAP, DISCARD);
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+}
+
+
+SM_STATE(EAP, IDENTITY)
+{
+ u8 *eapReqData;
+ size_t eapReqDataLen;
+
+ SM_ENTRY(EAP, IDENTITY);
+ eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
+ eap_sm_processIdentity(sm, eapReqData, eapReqDataLen);
+ free(sm->eapRespData);
+ sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId,
+ &sm->eapRespDataLen, 0);
+}
+
+
+SM_STATE(EAP, NOTIFICATION)
+{
+ u8 *eapReqData;
+ size_t eapReqDataLen;
+
+ SM_ENTRY(EAP, NOTIFICATION);
+ eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
+ eap_sm_processNotify(sm, eapReqData, eapReqDataLen);
+ free(sm->eapRespData);
+ sm->eapRespData = eap_sm_buildNotify(sm, sm->reqId,
+ &sm->eapRespDataLen);
+}
+
+
+SM_STATE(EAP, RETRANSMIT)
+{
+ SM_ENTRY(EAP, RETRANSMIT);
+ free(sm->eapRespData);
+ if (sm->lastRespData) {
+ sm->eapRespData = malloc(sm->lastRespDataLen);
+ if (sm->eapRespData) {
+ memcpy(sm->eapRespData, sm->lastRespData,
+ sm->lastRespDataLen);
+ sm->eapRespDataLen = sm->lastRespDataLen;
+ }
+ } else
+ sm->eapRespData = NULL;
+}
+
+
+SM_STATE(EAP, SUCCESS)
+{
+ SM_ENTRY(EAP, SUCCESS);
+ if (sm->eapKeyData != NULL)
+ sm->eapKeyAvailable = TRUE;
+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
+ * this seems to be required to avoid processing the same request
+ * twice when state machine is initialized. */
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here, but
+ * this seems to be required to get EAPOL Supplicant backend state
+ * machine into SUCCESS state. In addition, either eapResp or eapNoResp
+ * is required to be set after processing the received EAP frame. */
+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+}
+
+
+SM_STATE(EAP, FAILURE)
+{
+ SM_ENTRY(EAP, FAILURE);
+ eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+ /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
+ * this seems to be required to avoid processing the same request
+ * twice when state machine is initialized. */
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here.
+ * However, either eapResp or eapNoResp is required to be set after
+ * processing the received EAP frame. */
+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+}
+
+
+static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
+{
+ /* At least Microsoft IAS and Meetinghouse Aegis seem to be sending
+ * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
+ * draft-ietf-eap-statemachine-05.pdf require that reqId == lastId.
+ * Accept this kind of Id if EAP workarounds are enabled. These are
+ * unauthenticated plaintext messages, so this should have minimal
+ * security implications (bit easier to fake EAP-Success/Failure). */
+ if (sm->workaround && reqId == ((lastId + 1) & 0xff)) {
+ wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
+ "identifier field in EAP Success: "
+ "reqId=%d lastId=%d (these are supposed to be "
+ "same)", reqId, lastId);
+ return 1;
+ }
+ return 0;
+}
+
+
+SM_STEP(EAP)
+{
+ int duplicate;
+
+ if (eapol_get_bool(sm, EAPOL_eapRestart) &&
+ eapol_get_bool(sm, EAPOL_portEnabled))
+ SM_ENTER_GLOBAL(EAP, INITIALIZE);
+ else if (!eapol_get_bool(sm, EAPOL_portEnabled))
+ SM_ENTER_GLOBAL(EAP, DISABLED);
+ else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
+ if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+ wpa_printf(MSG_DEBUG, "EAP: more than %d "
+ "authentication rounds - abort",
+ EAP_MAX_AUTH_ROUNDS);
+ sm->num_rounds++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
+ } else switch (sm->EAP_state) {
+ case EAP_INITIALIZE:
+ SM_ENTER(EAP, IDLE);
+ break;
+ case EAP_DISABLED:
+ if (eapol_get_bool(sm, EAPOL_portEnabled))
+ SM_ENTER(EAP, INITIALIZE);
+ break;
+ case EAP_IDLE:
+ if (eapol_get_bool(sm, EAPOL_eapReq))
+ SM_ENTER(EAP, RECEIVED);
+ else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
+ sm->decision != DECISION_FAIL) ||
+ (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
+ sm->decision == DECISION_UNCOND_SUCC))
+ SM_ENTER(EAP, SUCCESS);
+ else if (eapol_get_bool(sm, EAPOL_altReject) ||
+ (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
+ sm->decision != DECISION_UNCOND_SUCC) ||
+ (eapol_get_bool(sm, EAPOL_altAccept) &&
+ sm->methodState != METHOD_CONT &&
+ sm->decision == DECISION_FAIL))
+ SM_ENTER(EAP, FAILURE);
+ else if (sm->selectedMethod == EAP_TYPE_LEAP &&
+ sm->leap_done && sm->decision != DECISION_FAIL &&
+ sm->methodState == METHOD_DONE)
+ SM_ENTER(EAP, SUCCESS);
+ else if (sm->selectedMethod == EAP_TYPE_PEAP &&
+ sm->peap_done && sm->decision != DECISION_FAIL &&
+ sm->methodState == METHOD_DONE)
+ SM_ENTER(EAP, SUCCESS);
+ break;
+ case EAP_RECEIVED:
+ duplicate = sm->reqId == sm->lastId;
+ if (sm->workaround && duplicate &&
+ memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
+ /* draft-ietf-eap-statemachine-05.txt uses
+ * (reqId == lastId) as the only verification for
+ * duplicate EAP requests. However, this misses cases
+ * where the AS is incorrectly using the same id again;
+ * and unfortunately, such implementations exist. Use
+ * MD5 hash as an extra verification for the packets
+ * being duplicate to workaround these issues. */
+ wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"
+ " but EAP packets were not identical");
+ wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "
+ "is not a duplicate packet");
+ duplicate = 0;
+ }
+
+ if (sm->rxSuccess &&
+ (sm->reqId == sm->lastId ||
+ eap_success_workaround(sm, sm->reqId, sm->lastId)) &&
+ sm->decision != DECISION_FAIL)
+ SM_ENTER(EAP, SUCCESS);
+ else if (sm->methodState != METHOD_CONT &&
+ ((sm->rxFailure &&
+ sm->decision != DECISION_UNCOND_SUCC) ||
+ (sm->rxSuccess && sm->decision == DECISION_FAIL)) &&
+ (sm->reqId == sm->lastId ||
+ eap_success_workaround(sm, sm->reqId, sm->lastId)))
+ SM_ENTER(EAP, FAILURE);
+ else if (sm->rxReq && duplicate)
+ SM_ENTER(EAP, RETRANSMIT);
+ else if (sm->rxReq && !duplicate &&
+ sm->reqMethod == EAP_TYPE_NOTIFICATION &&
+ sm->allowNotifications)
+ SM_ENTER(EAP, NOTIFICATION);
+ else if (sm->rxReq && !duplicate &&
+ sm->selectedMethod == EAP_TYPE_NONE &&
+ sm->reqMethod == EAP_TYPE_IDENTITY)
+ SM_ENTER(EAP, IDENTITY);
+ else if (sm->rxReq && !duplicate &&
+ sm->selectedMethod == EAP_TYPE_NONE &&
+ sm->reqMethod != EAP_TYPE_IDENTITY &&
+ sm->reqMethod != EAP_TYPE_NOTIFICATION)
+ SM_ENTER(EAP, GET_METHOD);
+ else if (sm->rxReq && !duplicate &&
+ sm->reqMethod == sm->selectedMethod &&
+ sm->methodState != METHOD_DONE)
+ SM_ENTER(EAP, METHOD);
+ else if (sm->selectedMethod == EAP_TYPE_LEAP &&
+ (sm->rxSuccess || sm->rxResp))
+ SM_ENTER(EAP, METHOD);
+ else
+ SM_ENTER(EAP, DISCARD);
+ break;
+ case EAP_GET_METHOD:
+ if (sm->selectedMethod == sm->reqMethod)
+ SM_ENTER(EAP, METHOD);
+ else
+ SM_ENTER(EAP, SEND_RESPONSE);
+ break;
+ case EAP_METHOD:
+ if (sm->ignore)
+ SM_ENTER(EAP, DISCARD);
+ else
+ SM_ENTER(EAP, SEND_RESPONSE);
+ break;
+ case EAP_SEND_RESPONSE:
+ SM_ENTER(EAP, IDLE);
+ break;
+ case EAP_DISCARD:
+ SM_ENTER(EAP, IDLE);
+ break;
+ case EAP_IDENTITY:
+ SM_ENTER(EAP, SEND_RESPONSE);
+ break;
+ case EAP_NOTIFICATION:
+ SM_ENTER(EAP, SEND_RESPONSE);
+ break;
+ case EAP_RETRANSMIT:
+ SM_ENTER(EAP, SEND_RESPONSE);
+ break;
+ case EAP_SUCCESS:
+ break;
+ case EAP_FAILURE:
+ break;
+ }
+}
+
+
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ int i;
+
+ if (!wpa_config_allowed_eap_method(config, method))
+ return FALSE;
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ if (eap_methods[i]->method == method)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *resp;
+ u8 *pos;
+ int i, found = 0;
+
+ wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %d not "
+ "allowed)", sm->reqMethod);
+ *len = sizeof(struct eap_hdr) + 1;
+ resp = malloc(*len + NUM_EAP_METHODS);
+ if (resp == NULL)
+ return NULL;
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_NAK;
+
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ if (wpa_config_allowed_eap_method(config,
+ eap_methods[i]->method)) {
+ *pos++ = eap_methods[i]->method;
+ (*len)++;
+ found++;
+ }
+ }
+ if (!found) {
+ *pos = EAP_TYPE_NONE;
+ (*len)++;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP: allowed methods",
+ ((u8 *) (resp + 1)) + 1, found);
+
+ resp->length = host_to_be16(*len);
+
+ return (u8 *) resp;
+}
+
+
+static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
+{
+ struct eap_hdr *hdr = (struct eap_hdr *) req;
+ u8 *pos = (u8 *) (hdr + 1);
+ pos++;
+ /* TODO: could save displayable message so that it can be shown to the
+ * user in case of interaction is required */
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
+ pos, be_to_host16(hdr->length) - 5);
+}
+
+
+u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
+ int encrypted)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *resp;
+ u8 *pos;
+ const u8 *identity;
+ size_t identity_len;
+
+ if (config == NULL) {
+ wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
+ "was not available");
+ return NULL;
+ }
+
+ if (sm->m && sm->m->get_identity &&
+ (identity = sm->m->get_identity(sm, sm->eap_method_priv,
+ &identity_len)) != NULL) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
+ "identity", identity, identity_len);
+ } else if (!encrypted && config->anonymous_identity) {
+ identity = config->anonymous_identity;
+ identity_len = config->anonymous_identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
+ identity, identity_len);
+ } else {
+ identity = config->identity;
+ identity_len = config->identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
+ identity, identity_len);
+ }
+
+ if (identity == NULL) {
+ wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
+ "configuration was not available");
+ eap_sm_request_identity(sm, config);
+ return NULL;
+ }
+
+
+ *len = sizeof(struct eap_hdr) + 1 + identity_len;
+ resp = malloc(*len);
+ if (resp == NULL)
+ return NULL;
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+ resp->length = host_to_be16(*len);
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_IDENTITY;
+ memcpy(pos, identity, identity_len);
+
+ return (u8 *) resp;
+}
+
+
+static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len)
+{
+ struct eap_hdr *hdr = (struct eap_hdr *) req;
+ u8 *pos = (u8 *) (hdr + 1);
+ pos++;
+ /* TODO: log the Notification Request and make it available for UI */
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
+ pos, be_to_host16(hdr->length) - 5);
+}
+
+
+static u8 *eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
+ *len = sizeof(struct eap_hdr) + 1;
+ resp = malloc(*len);
+ if (resp == NULL)
+ return NULL;
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+ resp->length = host_to_be16(*len);
+ pos = (u8 *) (resp + 1);
+ *pos = EAP_TYPE_NOTIFICATION;
+
+ return (u8 *) resp;
+}
+
+
+static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
+{
+ struct eap_hdr *hdr;
+ size_t plen;
+ MD5_CTX context;
+
+ sm->rxReq = sm->rxSuccess = sm->rxFailure = FALSE;
+ sm->reqId = 0;
+ sm->reqMethod = EAP_TYPE_NONE;
+
+ if (req == NULL || len < sizeof(*hdr))
+ return;
+
+ hdr = (struct eap_hdr *) req;
+ plen = be_to_host16(hdr->length);
+ if (plen > len) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
+ "(len=%lu plen=%lu)",
+ (unsigned long) len, (unsigned long) plen);
+ return;
+ }
+
+ sm->reqId = hdr->identifier;
+
+ if (sm->workaround) {
+ MD5Init(&context);
+ MD5Update(&context, req, len);
+ MD5Final(sm->req_md5, &context);
+ }
+
+ switch (hdr->code) {
+ case EAP_CODE_REQUEST:
+ sm->rxReq = TRUE;
+ if (plen > sizeof(*hdr))
+ sm->reqMethod = *((u8 *) (hdr + 1));
+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request method=%d "
+ "id=%d", sm->reqMethod, sm->reqId);
+ break;
+ case EAP_CODE_RESPONSE:
+ if (sm->selectedMethod == EAP_TYPE_LEAP) {
+ sm->rxResp = TRUE;
+ if (plen > sizeof(*hdr))
+ sm->reqMethod = *((u8 *) (hdr + 1));
+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
+ "LEAP method=%d id=%d",
+ sm->reqMethod, sm->reqId);
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
+ break;
+ case EAP_CODE_SUCCESS:
+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
+ sm->rxSuccess = TRUE;
+ break;
+ case EAP_CODE_FAILURE:
+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
+ sm->rxFailure = TRUE;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
+ "code %d", hdr->code);
+ break;
+ }
+}
+
+
+struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx)
+{
+ struct eap_sm *sm;
+
+ sm = malloc(sizeof(*sm));
+ if (sm == NULL)
+ return NULL;
+ memset(sm, 0, sizeof(*sm));
+ sm->eapol_ctx = eapol_ctx;
+ sm->eapol_cb = eapol_cb;
+ sm->msg_ctx = msg_ctx;
+ sm->ClientTimeout = 60;
+
+ sm->ssl_ctx = tls_init();
+ if (sm->ssl_ctx == NULL) {
+ wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
+ "context.");
+ free(sm);
+ return NULL;
+ }
+
+ return sm;
+}
+
+
+void eap_sm_deinit(struct eap_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ eap_deinit_prev_method(sm, "EAP deinit");
+ free(sm->lastRespData);
+ free(sm->eapRespData);
+ free(sm->eapKeyData);
+ tls_deinit(sm->ssl_ctx);
+ free(sm);
+}
+
+
+int eap_sm_step(struct eap_sm *sm)
+{
+ int res = 0;
+ do {
+ sm->changed = FALSE;
+ SM_STEP_RUN(EAP);
+ if (sm->changed)
+ res = 1;
+ } while (sm->changed);
+ return res;
+}
+
+
+void eap_sm_abort(struct eap_sm *sm)
+{
+ /* release system resources that may have been allocated for the
+ * authentication session */
+ free(sm->eapRespData);
+ sm->eapRespData = NULL;
+ free(sm->eapKeyData);
+ sm->eapKeyData = NULL;
+}
+
+
+static const char * eap_sm_state_txt(int state)
+{
+ switch (state) {
+ case EAP_INITIALIZE:
+ return "INITIALIZE";
+ case EAP_DISABLED:
+ return "DISABLED";
+ case EAP_IDLE:
+ return "IDLE";
+ case EAP_RECEIVED:
+ return "RECEIVED";
+ case EAP_GET_METHOD:
+ return "GET_METHOD";
+ case EAP_METHOD:
+ return "METHOD";
+ case EAP_SEND_RESPONSE:
+ return "SEND_RESPONSE";
+ case EAP_DISCARD:
+ return "DISCARD";
+ case EAP_IDENTITY:
+ return "IDENTITY";
+ case EAP_NOTIFICATION:
+ return "NOTIFICATION";
+ case EAP_RETRANSMIT:
+ return "RETRANSMIT";
+ case EAP_SUCCESS:
+ return "SUCCESS";
+ case EAP_FAILURE:
+ return "FAILURE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+static const char * eap_sm_method_state_txt(int state)
+{
+ switch (state) {
+ case METHOD_NONE:
+ return "NONE";
+ case METHOD_INIT:
+ return "INIT";
+ case METHOD_CONT:
+ return "CONT";
+ case METHOD_MAY_CONT:
+ return "MAY_CONT";
+ case METHOD_DONE:
+ return "DONE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+static const char * eap_sm_decision_txt(int decision)
+{
+ switch (decision) {
+ case DECISION_FAIL:
+ return "FAIL";
+ case DECISION_COND_SUCC:
+ return "COND_SUCC";
+ case DECISION_UNCOND_SUCC:
+ return "UNCOND_SUCC";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
+{
+ int len;
+
+ if (sm == NULL)
+ return 0;
+
+ len = snprintf(buf, buflen,
+ "EAP state=%s\n",
+ eap_sm_state_txt(sm->EAP_state));
+
+ if (sm->selectedMethod != EAP_TYPE_NONE) {
+ const char *name;
+ if (sm->m) {
+ name = sm->m->name;
+ } else {
+ const struct eap_method *m =
+ eap_sm_get_eap_methods(sm->selectedMethod);
+ if (m)
+ name = m->name;
+ else
+ name = "?";
+ }
+ len += snprintf(buf + len, buflen - len,
+ "selectedMethod=%d (EAP-%s)\n",
+ sm->selectedMethod, name);
+
+ if (sm->m && sm->m->get_status) {
+ len += sm->m->get_status(sm, sm->eap_method_priv,
+ buf + len, buflen - len,
+ verbose);
+ }
+ }
+
+ if (verbose) {
+ len += snprintf(buf + len, buflen - len,
+ "reqMethod=%d\n"
+ "methodState=%s\n"
+ "decision=%s\n"
+ "ClientTimeout=%d\n",
+ sm->reqMethod,
+ eap_sm_method_state_txt(sm->methodState),
+ eap_sm_decision_txt(sm->decision),
+ sm->ClientTimeout);
+ }
+
+ return len;
+}
+
+
+typedef enum { TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP } eap_ctrl_req_type;
+
+static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
+ eap_ctrl_req_type type, char *msg, size_t msglen)
+{
+ char *buf;
+ size_t buflen;
+ int len;
+ char *field;
+ char *txt, *tmp;
+
+ if (config == NULL || sm == NULL)
+ return;
+
+ switch (type) {
+ case TYPE_IDENTITY:
+ field = "IDENTITY";
+ txt = "Identity";
+ config->pending_req_identity++;
+ break;
+ case TYPE_PASSWORD:
+ field = "PASSWORD";
+ txt = "Password";
+ config->pending_req_password++;
+ break;
+ case TYPE_OTP:
+ field = "OTP";
+ if (msg) {
+ tmp = malloc(msglen + 3);
+ if (tmp == NULL)
+ return;
+ tmp[0] = '[';
+ memcpy(tmp + 1, msg, msglen);
+ tmp[msglen + 1] = ']';
+ tmp[msglen + 2] = '\0';
+ txt = tmp;
+ free(config->pending_req_otp);
+ config->pending_req_otp = tmp;
+ config->pending_req_otp_len = msglen + 3;
+ } else {
+ if (config->pending_req_otp == NULL)
+ return;
+ txt = config->pending_req_otp;
+ }
+ break;
+ default:
+ return;
+ }
+
+ buflen = 100 + strlen(txt) + config->ssid_len;
+ buf = malloc(buflen);
+ if (buf == NULL)
+ return;
+ len = snprintf(buf, buflen, "CTRL-REQ-%s-%d:%s needed for SSID ",
+ field, config->id, txt);
+ if (config->ssid && buflen > len + config->ssid_len) {
+ memcpy(buf + len, config->ssid, config->ssid_len);
+ len += config->ssid_len;
+ buf[len] = '\0';
+ }
+ wpa_msg(sm->msg_ctx, MSG_INFO, buf);
+ free(buf);
+}
+
+
+void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config)
+{
+ eap_sm_request(sm, config, TYPE_IDENTITY, NULL, 0);
+}
+
+
+void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config)
+{
+ eap_sm_request(sm, config, TYPE_PASSWORD, NULL, 0);
+}
+
+
+void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
+ char *msg, size_t msg_len)
+{
+ eap_sm_request(sm, config, TYPE_OTP, msg, msg_len);
+}
+
+
+void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+
+ if (config == NULL)
+ return;
+
+ /* Re-send any pending requests for user data since a new control
+ * interface was added. This handles cases where the EAP authentication
+ * starts immediately after system startup when the user interface is
+ * not yet running. */
+ if (config->pending_req_identity)
+ eap_sm_request_identity(sm, config);
+ if (config->pending_req_password)
+ eap_sm_request_password(sm, config);
+ if (config->pending_req_otp)
+ eap_sm_request_otp(sm, config, NULL, 0);
+}
+
+
+u8 eap_get_type(const char *name)
+{
+ int i;
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ if (strcmp(eap_methods[i]->name, name) == 0)
+ return eap_methods[i]->method;
+ }
+ return EAP_TYPE_NONE;
+}
+
+
+static int eap_allowed_phase2_type(int type)
+{
+ return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
+ type != EAP_TYPE_FAST;
+}
+
+
+u8 eap_get_phase2_type(const char *name)
+{
+ u8 type = eap_get_type(name);
+ if (eap_allowed_phase2_type(type))
+ return type;
+ return EAP_TYPE_NONE;
+}
+
+
+u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
+{
+ u8 *buf, method;
+ int i;
+
+ *count = 0;
+ buf = malloc(NUM_EAP_METHODS);
+ if (buf == NULL)
+ return NULL;
+
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ method = eap_methods[i]->method;
+ if (eap_allowed_phase2_type(method)) {
+ if (method == EAP_TYPE_TLS && config &&
+ config->private_key2 == NULL)
+ continue;
+ buf[*count] = method;
+ (*count)++;
+ }
+ }
+
+ return buf;
+}
+
+
+void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
+{
+ sm->fast_reauth = enabled;
+}
+
+
+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
+{
+ sm->workaround = workaround;
+}
+
+
+struct wpa_ssid * eap_get_config(struct eap_sm *sm)
+{
+ return sm->eapol_cb->get_config(sm->eapol_ctx);
+}
+
+
+int eap_key_available(struct eap_sm *sm)
+{
+ return sm ? sm->eapKeyAvailable : 0;
+}
+
+
+void eap_notify_success(struct eap_sm *sm)
+{
+ if (sm) {
+ sm->decision = DECISION_COND_SUCC;
+ sm->EAP_state = EAP_SUCCESS;
+ }
+}
+
+
+u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
+{
+ if (sm == NULL || sm->eapKeyData == NULL) {
+ *len = 0;
+ return NULL;
+ }
+
+ *len = sm->eapKeyDataLen;
+ return sm->eapKeyData;
+}
+
+
+u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
+{
+ u8 *resp;
+
+ if (sm == NULL || sm->eapRespData == NULL) {
+ *len = 0;
+ return NULL;
+ }
+
+ resp = sm->eapRespData;
+ *len = sm->eapRespDataLen;
+ sm->eapRespData = NULL;
+ sm->eapRespDataLen = 0;
+
+ return resp;
+}
+
+
+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
+{
+ if (sm)
+ sm->scard_ctx = ctx;
+}
diff --git a/contrib/wpa_supplicant/eap.h b/contrib/wpa_supplicant/eap.h
new file mode 100644
index 000000000000..3d7cc7210d7a
--- /dev/null
+++ b/contrib/wpa_supplicant/eap.h
@@ -0,0 +1,70 @@
+#ifndef EAP_H
+#define EAP_H
+
+#include "defs.h"
+#include "eap_defs.h"
+
+struct eap_sm;
+struct wpa_ssid;
+
+
+#ifdef IEEE8021X_EAPOL
+
+enum eapol_bool_var {
+ EAPOL_eapSuccess, EAPOL_eapRestart, EAPOL_eapFail, EAPOL_eapResp,
+ EAPOL_eapNoResp, EAPOL_eapReq, EAPOL_portEnabled, EAPOL_altAccept,
+ EAPOL_altReject
+};
+
+enum eapol_int_var {
+ EAPOL_idleWhile
+};
+
+struct eapol_callbacks {
+ struct wpa_ssid * (*get_config)(void *ctx);
+ Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
+ void (*set_bool)(void *ctx, enum eapol_bool_var variable,
+ Boolean value);
+ unsigned int (*get_int)(void *ctx, enum eapol_int_var variable);
+ void (*set_int)(void *ctx, enum eapol_int_var variable,
+ unsigned int value);
+ u8 * (*get_eapReqData)(void *ctx, size_t *len);
+};
+
+struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx);
+void eap_sm_deinit(struct eap_sm *sm);
+int eap_sm_step(struct eap_sm *sm);
+void eap_sm_abort(struct eap_sm *sm);
+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
+ int verbose);
+u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
+ int encrypted);
+const struct eap_method * eap_sm_get_eap_methods(int method);
+void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config);
+void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config);
+void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
+ char *msg, size_t msg_len);
+void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
+u8 eap_get_type(const char *name);
+u8 eap_get_phase2_type(const char *name);
+u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count);
+void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
+struct wpa_ssid * eap_get_config(struct eap_sm *sm);
+int eap_key_available(struct eap_sm *sm);
+void eap_notify_success(struct eap_sm *sm);
+u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
+u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len);
+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
+
+#else /* IEEE8021X_EAPOL */
+
+static inline u8 eap_get_type(const char *name)
+{
+ return EAP_TYPE_NONE;
+}
+
+#endif /* IEEE8021X_EAPOL */
+
+#endif /* EAP_H */
diff --git a/contrib/wpa_supplicant/eap_aka.c b/contrib/wpa_supplicant/eap_aka.c
new file mode 100644
index 000000000000..7fe6449ab896
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_aka.c
@@ -0,0 +1,915 @@
+/*
+ * WPA Supplicant / EAP-AKA (draft-arkko-pppext-eap-aka-12.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "sha1.h"
+#include "pcsc_funcs.h"
+#include "eap_sim_common.h"
+
+/* EAP-AKA Subtypes */
+#define EAP_AKA_SUBTYPE_CHALLENGE 1
+#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
+#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
+#define EAP_AKA_SUBTYPE_IDENTITY 5
+#define EAP_AKA_SUBTYPE_NOTIFICATION 12
+#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
+#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
+
+#define AKA_AUTS_LEN 14
+#define RES_MAX_LEN 16
+#define IK_LEN 16
+#define CK_LEN 16
+#define EAP_AKA_MAX_FAST_REAUTHS 1000
+
+struct eap_aka_data {
+ u8 ik[IK_LEN], ck[CK_LEN], res[RES_MAX_LEN];
+ size_t res_len;
+ u8 nonce_s[EAP_SIM_NONCE_S_LEN];
+ u8 mk[EAP_SIM_MK_LEN];
+ u8 k_aut[EAP_SIM_K_AUT_LEN];
+ u8 k_encr[EAP_SIM_K_ENCR_LEN];
+ u8 msk[EAP_SIM_KEYING_DATA_LEN];
+ u8 rand[AKA_RAND_LEN], autn[AKA_AUTN_LEN];
+ u8 auts[AKA_AUTS_LEN];
+
+ int num_id_req, num_notification;
+ u8 *pseudonym;
+ size_t pseudonym_len;
+ u8 *reauth_id;
+ size_t reauth_id_len;
+ int reauth;
+ unsigned int counter, counter_too_small;
+ u8 *last_eap_identity;
+ size_t last_eap_identity_len;
+ enum { CONTINUE, SUCCESS, FAILURE } state;
+};
+
+
+static void * eap_aka_init(struct eap_sm *sm)
+{
+ struct eap_aka_data *data;
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+
+ data->state = CONTINUE;
+
+ return data;
+}
+
+
+static void eap_aka_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ if (data) {
+ free(data->pseudonym);
+ free(data->reauth_id);
+ free(data->last_eap_identity);
+ free(data);
+ }
+}
+
+
+static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
+#ifdef PCSC_FUNCS
+ return scard_umts_auth(sm->scard_ctx, data->rand,
+ data->autn, data->res, &data->res_len,
+ data->ik, data->ck, data->auts);
+#else /* PCSC_FUNCS */
+ /* These hardcoded Kc and SRES values are used for testing.
+ * Could consider making them configurable. */
+ memset(data->res, '2', RES_MAX_LEN);
+ data->res_len = 16;
+ memset(data->ik, '3', IK_LEN);
+ memset(data->ck, '4', CK_LEN);
+ {
+ u8 autn[AKA_AUTN_LEN];
+ memset(autn, '1', AKA_AUTN_LEN);
+ if (memcmp(autn, data->autn, AKA_AUTN_LEN) != 0) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
+ "with expected value");
+ return -1;
+ }
+ }
+ return 0;
+#endif /* PCSC_FUNCS */
+}
+
+
+static void eap_aka_derive_mk(struct eap_aka_data *data,
+ const u8 *identity, size_t identity_len)
+{
+ const u8 *addr[3];
+ size_t len[3];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = data->ik;
+ len[1] = IK_LEN;
+ addr[2] = data->ck;
+ len[2] = CK_LEN;
+
+ /* MK = SHA1(Identity|IK|CK) */
+ sha1_vector(3, addr, len, data->mk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, IK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, CK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", data->mk, EAP_SIM_MK_LEN);
+}
+
+
+#define CLEAR_PSEUDONYM 0x01
+#define CLEAR_REAUTH_ID 0x02
+#define CLEAR_EAP_ID 0x04
+
+static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
+ id & CLEAR_PSEUDONYM ? " pseudonym" : "",
+ id & CLEAR_REAUTH_ID ? " reauth_id" : "",
+ id & CLEAR_EAP_ID ? " eap_id" : "");
+ if (id & CLEAR_PSEUDONYM) {
+ free(data->pseudonym);
+ data->pseudonym = NULL;
+ data->pseudonym_len = 0;
+ }
+ if (id & CLEAR_REAUTH_ID) {
+ free(data->reauth_id);
+ data->reauth_id = NULL;
+ data->reauth_id_len = 0;
+ }
+ if (id & CLEAR_EAP_ID) {
+ free(data->last_eap_identity);
+ data->last_eap_identity = NULL;
+ data->last_eap_identity_len = 0;
+ }
+}
+
+
+static int eap_aka_learn_ids(struct eap_aka_data *data,
+ struct eap_sim_attrs *attr)
+{
+ if (attr->next_pseudonym) {
+ free(data->pseudonym);
+ data->pseudonym = malloc(attr->next_pseudonym_len);
+ if (data->pseudonym == NULL) {
+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
+ "next pseudonym");
+ return -1;
+ }
+ memcpy(data->pseudonym, attr->next_pseudonym,
+ attr->next_pseudonym_len);
+ data->pseudonym_len = attr->next_pseudonym_len;
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
+ data->pseudonym,
+ data->pseudonym_len);
+ }
+
+ if (attr->next_reauth_id) {
+ free(data->reauth_id);
+ data->reauth_id = malloc(attr->next_reauth_id_len);
+ if (data->reauth_id == NULL) {
+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
+ "next reauth_id");
+ return -1;
+ }
+ memcpy(data->reauth_id, attr->next_reauth_id,
+ attr->next_reauth_id_len);
+ data->reauth_id_len = attr->next_reauth_id_len;
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
+ data->reauth_id,
+ data->reauth_id_len);
+ }
+
+ return 0;
+}
+
+
+static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen, int err)
+{
+ struct eap_sim_msg *msg;
+
+ data->state = FAILURE;
+ data->num_id_req = 0;
+ data->num_notification = 0;
+
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CLIENT_ERROR);
+ eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
+ return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_aka_authentication_reject(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ data->state = FAILURE;
+ data->num_id_req = 0;
+ data->num_notification = 0;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
+ "(id=%d)", req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_AKA,
+ EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
+ return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_aka_synchronization_failure(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ data->state = FAILURE;
+ data->num_id_req = 0;
+ data->num_notification = 0;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
+ "(id=%d)", req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_AKA,
+ EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
+ wpa_printf(MSG_DEBUG, " AT_AUTS");
+ eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, AKA_AUTS_LEN);
+ return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_aka_response_identity(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen,
+ enum eap_sim_id_req id_req)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ u8 *identity = NULL;
+ size_t identity_len = 0;
+ struct eap_sim_msg *msg;
+
+ data->reauth = 0;
+ if (id_req == ANY_ID && data->reauth_id) {
+ identity = data->reauth_id;
+ identity_len = data->reauth_id_len;
+ data->reauth = 1;
+ } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
+ data->pseudonym) {
+ identity = data->pseudonym;
+ identity_len = data->pseudonym_len;
+ eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
+ } else if (id_req != NO_ID_REQ && config && config->identity) {
+ identity = config->identity;
+ identity_len = config->identity_len;
+ eap_aka_clear_identities(data,
+ CLEAR_PSEUDONYM | CLEAR_REAUTH_ID);
+ }
+ if (id_req != NO_ID_REQ)
+ eap_aka_clear_identities(data, CLEAR_EAP_ID);
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY);
+
+ if (identity) {
+ wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
+ identity, identity_len);
+ eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
+ identity, identity_len);
+ }
+
+ return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_aka_response_challenge(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE);
+ wpa_printf(MSG_DEBUG, " AT_RES");
+ eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len,
+ data->res, data->res_len);
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, respDataLen, data->k_aut, (u8 *) "", 0);
+}
+
+
+static u8 * eap_aka_response_reauth(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen, int counter_too_small)
+{
+ struct eap_sim_msg *msg;
+ unsigned int counter;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_AKA,
+ EAP_AKA_SUBTYPE_REAUTHENTICATION);
+ wpa_printf(MSG_DEBUG, " AT_IV");
+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+ if (counter_too_small) {
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL");
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
+ counter = data->counter_too_small;
+ } else
+ counter = data->counter;
+
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter);
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+
+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
+ "AT_ENCR_DATA");
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, respDataLen, data->k_aut, data->nonce_s,
+ EAP_SIM_NONCE_S_LEN);
+}
+
+
+static u8 * eap_aka_response_notification(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen,
+ u16 notification)
+{
+ struct eap_sim_msg *msg;
+ u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION);
+ wpa_printf(MSG_DEBUG, " AT_NOTIFICATION");
+ eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, notification, NULL, 0);
+ if (k_aut && data->reauth) {
+ wpa_printf(MSG_DEBUG, " AT_IV");
+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
+ EAP_SIM_AT_ENCR_DATA);
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter);
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
+ NULL, 0);
+ if (eap_sim_msg_add_encr_end(msg, data->k_encr,
+ EAP_SIM_AT_PADDING)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
+ "AT_ENCR_DATA");
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+ }
+ if (k_aut) {
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ }
+ return eap_sim_msg_finish(msg, respDataLen, k_aut, (u8 *) "", 0);
+}
+
+
+static u8 * eap_aka_process_identity(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req, size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ int id_error;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
+
+ id_error = 0;
+ switch (attr->id_req) {
+ case NO_ID_REQ:
+ break;
+ case ANY_ID:
+ if (data->num_id_req > 0)
+ id_error++;
+ data->num_id_req++;
+ break;
+ case FULLAUTH_ID:
+ if (data->num_id_req > 1)
+ id_error++;
+ data->num_id_req++;
+ break;
+ case PERMANENT_ID:
+ if (data->num_id_req > 2)
+ id_error++;
+ data->num_id_req++;
+ break;
+ }
+ if (id_error) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
+ "used within one authentication");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ return eap_aka_response_identity(sm, data, req, respDataLen,
+ attr->id_req);
+}
+
+
+static u8 * eap_aka_process_challenge(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req, size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ u8 *identity;
+ size_t identity_len;
+ int res;
+ struct eap_sim_attrs eattr;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
+ data->reauth = 0;
+ if (!attr->mac || !attr->rand || !attr->autn) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
+ "did not include%s%s%s",
+ !attr->mac ? " AT_MAC" : "",
+ !attr->rand ? " AT_RAND" : "",
+ !attr->autn ? " AT_AUTN" : "");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+ memcpy(data->rand, attr->rand, AKA_RAND_LEN);
+ memcpy(data->autn, attr->autn, AKA_AUTN_LEN);
+
+ res = eap_aka_umts_auth(sm, data);
+ if (res == -1) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
+ "failed (AUTN)");
+ return eap_aka_authentication_reject(sm, data, req,
+ respDataLen);
+ } else if (res == -2) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
+ "failed (AUTN seq# -> AUTS)");
+ return eap_aka_synchronization_failure(sm, data, req,
+ respDataLen);
+ } else if (res) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+ if (data->last_eap_identity) {
+ identity = data->last_eap_identity;
+ identity_len = data->last_eap_identity_len;
+ } else if (data->pseudonym) {
+ identity = data->pseudonym;
+ identity_len = data->pseudonym_len;
+ } else {
+ identity = config->identity;
+ identity_len = config->identity_len;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
+ "derivation", identity, identity_len);
+ eap_aka_derive_mk(data, identity, identity_len);
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
+ if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
+ (u8 *) "", 0)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
+ "used invalid AT_MAC");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ /* Old reauthentication and pseudonym identities must not be used
+ * anymore. In other words, if no new identities are received, full
+ * authentication will be used on next reauthentication. */
+ eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
+ CLEAR_EAP_ID);
+
+ if (attr->encr_data) {
+ if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0)) {
+ return eap_aka_client_error(
+ sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+ eap_aka_learn_ids(data, &eattr);
+ }
+
+ if (data->state != FAILURE)
+ data->state = SUCCESS;
+
+ data->num_id_req = 0;
+ data->num_notification = 0;
+ /* draft-arkko-pppext-eap-aka-12.txt specifies that counter
+ * is initialized to one after fullauth, but initializing it to
+ * zero makes it easier to implement reauth verification. */
+ data->counter = 0;
+ return eap_aka_response_challenge(sm, data, req, respDataLen);
+}
+
+
+static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct eap_sim_attrs eattr;
+
+ if (attr->encr_data == NULL || attr->iv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
+ "reauth did not include encrypted data");
+ return -1;
+ }
+
+ if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr, 0)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
+ "data from notification message");
+ return -1;
+ }
+
+ if (eattr.counter != data->counter) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
+ "message does not match with counter in reauth "
+ "message");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_aka_process_notification_auth(struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ struct eap_sim_attrs *attr)
+{
+ if (attr->mac == NULL) {
+ wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
+ "Notification message");
+ return -1;
+ }
+
+ if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
+ (u8 *) "", 0)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
+ "used invalid AT_MAC");
+ return -1;
+ }
+
+ if (data->reauth &&
+ eap_aka_process_notification_reauth(data, req, reqDataLen, attr)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
+ "message after reauth");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static u8 * eap_aka_process_notification(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
+ if (data->num_notification > 0) {
+ wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
+ "rounds (only one allowed)");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+ data->num_notification++;
+ if (attr->notification == -1) {
+ wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
+ "Notification message");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if ((attr->notification & 0x4000) == 0 &&
+ eap_aka_process_notification_auth(data, req, reqDataLen, attr)) {
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
+ if (attr->notification >= 0 && attr->notification < 32768) {
+ data->state = FAILURE;
+ }
+ return eap_aka_response_notification(sm, data, req, respDataLen,
+ attr->notification);
+}
+
+
+static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct eap_sim_attrs eattr;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
+
+ if (data->reauth_id == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
+ "reauthentication, but no reauth_id available");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ data->reauth = 1;
+ if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen,
+ attr->mac, (u8 *) "", 0)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
+ "did not have valid AT_MAC");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (attr->encr_data == NULL || attr->iv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
+ "message did not include encrypted data");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr, 0)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
+ "data from reauthentication message");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (eattr.nonce_s == NULL || eattr.counter < 0) {
+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
+ !eattr.nonce_s ? " AT_NONCE_S" : "",
+ eattr.counter < 0 ? " AT_COUNTER" : "");
+ return eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (eattr.counter <= data->counter) {
+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
+ "(%d <= %d)", eattr.counter, data->counter);
+ data->counter_too_small = eattr.counter;
+ /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
+ * reauth_id must not be used to start a new reauthentication.
+ * However, since it was used in the last EAP-Response-Identity
+ * packet, it has to saved for the following fullauth to be
+ * used in MK derivation. */
+ free(data->last_eap_identity);
+ data->last_eap_identity = data->reauth_id;
+ data->last_eap_identity_len = data->reauth_id_len;
+ data->reauth_id = NULL;
+ data->reauth_id_len = 0;
+ return eap_aka_response_reauth(sm, data, req, respDataLen, 1);
+ }
+ data->counter = eattr.counter;
+
+ memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
+ data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+ eap_sim_derive_keys_reauth(data->counter,
+ data->reauth_id, data->reauth_id_len,
+ data->nonce_s, data->mk, data->msk);
+ eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_aka_learn_ids(data, &eattr);
+
+ if (data->state != FAILURE)
+ data->state = SUCCESS;
+
+ data->num_id_req = 0;
+ data->num_notification = 0;
+ if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
+ "fast reauths performed - force fullauth");
+ eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ }
+ return eap_aka_response_reauth(sm, data, req, respDataLen, 0);
+}
+
+
+static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_aka_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *req;
+ u8 *pos, subtype, *res;
+ struct eap_sim_attrs attr;
+ size_t len;
+
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: EAP data", reqData, reqDataLen);
+ if (config == NULL || config->identity == NULL) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
+ eap_sm_request_identity(sm, config);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_AKA ||
+ (len = be_to_host16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ pos++;
+ subtype = *pos++;
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
+ pos += 2; /* Reserved */
+
+ if (eap_sim_parse_attr(pos, reqData + len, &attr, 1, 0)) {
+ res = eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ goto done;
+ }
+
+ switch (subtype) {
+ case EAP_AKA_SUBTYPE_IDENTITY:
+ res = eap_aka_process_identity(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_AKA_SUBTYPE_CHALLENGE:
+ res = eap_aka_process_challenge(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_AKA_SUBTYPE_NOTIFICATION:
+ res = eap_aka_process_notification(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_AKA_SUBTYPE_REAUTHENTICATION:
+ res = eap_aka_process_reauthentication(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_AKA_SUBTYPE_CLIENT_ERROR:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
+ res = eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
+ res = eap_aka_client_error(sm, data, req, respDataLen,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ break;
+ }
+
+done:
+ if (data->state == FAILURE) {
+ ret->decision = DECISION_FAIL;
+ ret->methodState = METHOD_DONE;
+ } else if (data->state == SUCCESS) {
+ ret->decision = DECISION_UNCOND_SUCC;
+ ret->methodState = METHOD_DONE;
+ }
+
+ if (ret->methodState == METHOD_DONE) {
+ ret->allowNotifications = FALSE;
+ }
+
+ return res;
+}
+
+
+static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ return data->pseudonym || data->reauth_id;
+}
+
+
+static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ eap_aka_clear_identities(data, CLEAR_EAP_ID);
+}
+
+
+static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ data->num_id_req = 0;
+ data->num_notification = 0;
+ data->state = CONTINUE;
+ return priv;
+}
+
+
+static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
+ size_t *len)
+{
+ struct eap_aka_data *data = priv;
+
+ if (data->reauth_id) {
+ *len = data->reauth_id_len;
+ return data->reauth_id;
+ }
+
+ if (data->pseudonym) {
+ *len = data->pseudonym_len;
+ return data->pseudonym;
+ }
+
+ return NULL;
+}
+
+
+static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_SIM_KEYING_DATA_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_SIM_KEYING_DATA_LEN;
+ memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+
+ return key;
+}
+
+
+const struct eap_method eap_method_aka =
+{
+ .method = EAP_TYPE_AKA,
+ .name = "AKA",
+ .init = eap_aka_init,
+ .deinit = eap_aka_deinit,
+ .process = eap_aka_process,
+ .isKeyAvailable = eap_aka_isKeyAvailable,
+ .getKey = eap_aka_getKey,
+ .has_reauth_data = eap_aka_has_reauth_data,
+ .deinit_for_reauth = eap_aka_deinit_for_reauth,
+ .init_for_reauth = eap_aka_init_for_reauth,
+ .get_identity = eap_aka_get_identity,
+};
diff --git a/contrib/wpa_supplicant/eap_defs.h b/contrib/wpa_supplicant/eap_defs.h
new file mode 100644
index 000000000000..effe665f0919
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_defs.h
@@ -0,0 +1,41 @@
+#ifndef EAP_DEFS_H
+#define EAP_DEFS_H
+
+/* RFC 3748 - Extensible Authentication Protocol (EAP) */
+
+struct eap_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code and identifier */
+ /* followed by length-4 octets of data */
+} __attribute__ ((packed));
+
+enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
+ EAP_CODE_FAILURE = 4 };
+
+/* EAP Request and Response data begins with one octet Type. Success and
+ * Failure do not have additional data. */
+
+typedef enum {
+ EAP_TYPE_NONE = 0,
+ EAP_TYPE_IDENTITY = 1,
+ EAP_TYPE_NOTIFICATION = 2,
+ EAP_TYPE_NAK = 3 /* Response only */,
+ EAP_TYPE_MD5 = 4,
+ EAP_TYPE_OTP = 5 /* RFC 2284 */,
+ EAP_TYPE_GTC = 6, /* RFC 2284 */
+ EAP_TYPE_TLS = 13 /* RFC 2716 */,
+ EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
+ EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
+ EAP_TYPE_TTLS = 21 /* draft-ietf-pppext-eap-ttls-02.txt */,
+ EAP_TYPE_AKA = 23 /* draft-arkko-pppext-eap-aka-12.txt */,
+ EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
+ EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
+ EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
+ EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
+ EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
+ EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
+ * draft-bersani-eap-psk-03 */
+} EapType;
+
+#endif /* EAP_DEFS_H */
diff --git a/contrib/wpa_supplicant/eap_fast.c b/contrib/wpa_supplicant/eap_fast.c
new file mode 100644
index 000000000000..1c9c3ff2370f
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_fast.c
@@ -0,0 +1,1906 @@
+/*
+ * WPA Supplicant / EAP-FAST (draft-cam-winget-eap-fast-00.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "tls.h"
+#include "eap_tlv.h"
+#include "sha1.h"
+
+/* TODO:
+ * - encrypt PAC-Key in the PAC file
+ * - test session resumption and enable it if it interoperates
+ */
+
+#define EAP_FAST_VERSION 1
+#define EAP_FAST_KEY_LEN 64
+#define EAP_FAST_PAC_KEY_LEN 32
+
+#define TLS_EXT_PAC_OPAQUE 35
+
+static char *pac_file_hdr = "wpa_supplicant EAP-FAST PAC file - version 1";
+
+
+static void eap_fast_deinit(struct eap_sm *sm, void *priv);
+
+
+#define PAC_TYPE_PAC_KEY 1
+#define PAC_TYPE_PAC_OPAQUE 2
+#define PAC_TYPE_CRED_LIFETIME 3
+#define PAC_TYPE_A_ID 4
+#define PAC_TYPE_I_ID 5
+#define PAC_TYPE_SERVER_PROTECTED_DATA 6
+#define PAC_TYPE_A_ID_INFO 7
+#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
+#define PAC_TYPE_PAC_INFO 9
+
+struct pac_tlv_hdr {
+ u16 type;
+ u16 len;
+};
+
+
+/* draft-cam-winget-eap-fast-00.txt, 6.2 EAP-FAST Authentication Phase 1 */
+struct eap_fast_key_block_auth {
+ /* RC4-128-SHA */
+ u8 client_write_MAC_secret[20];
+ u8 server_write_MAC_secret[20];
+ u8 client_write_key[16];
+ u8 server_write_key[16];
+ /* u8 client_write_IV[0]; */
+ /* u8 server_write_IV[0]; */
+ u8 session_key_seed[40];
+};
+
+
+/* draft-cam-winget-eap-fast-00.txt, 7.3 EAP-FAST Provisioning Exchange */
+struct eap_fast_key_block_provisioning {
+ /* AES128-SHA */
+ u8 client_write_MAC_secret[20];
+ u8 server_write_MAC_secret[20];
+ u8 client_write_key[16];
+ u8 server_write_key[16];
+ u8 client_write_IV[16];
+ u8 server_write_IV[16];
+ u8 session_key_seed[40];
+ u8 server_challenge[16];
+ u8 client_challenge[16];
+};
+
+
+struct eap_fast_pac {
+ struct eap_fast_pac *next;
+
+ u8 pac_key[EAP_FAST_PAC_KEY_LEN];
+ u8 *pac_opaque;
+ size_t pac_opaque_len;
+ u8 *pac_info;
+ size_t pac_info_len;
+ u8 *a_id;
+ size_t a_id_len;
+ u8 *i_id;
+ size_t i_id_len;
+ u8 *a_id_info;
+ size_t a_id_info_len;
+};
+
+
+struct eap_fast_data {
+ struct eap_ssl_data ssl;
+
+ int fast_version;
+
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+ int phase2_success;
+
+ u8 phase2_type;
+ u8 *phase2_types;
+ size_t num_phase2_types;
+ int resuming; /* starting a resumed session */
+ struct eap_fast_key_block_auth *key_block_a;
+ struct eap_fast_key_block_provisioning *key_block_p;
+ int provisioning_allowed; /* is PAC provisioning allowed */
+ int provisioning; /* doing PAC provisioning (not the normal auth) */
+
+ u8 key_data[EAP_FAST_KEY_LEN];
+ int success;
+
+ struct eap_fast_pac *pac;
+ struct eap_fast_pac *current_pac;
+
+ int tls_master_secret_set;
+};
+
+
+static void eap_fast_free_pac(struct eap_fast_pac *pac)
+{
+ free(pac->pac_opaque);
+ free(pac->pac_info);
+ free(pac->a_id);
+ free(pac->i_id);
+ free(pac->a_id_info);
+ free(pac);
+}
+
+
+static struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_data *data,
+ const u8 *a_id, size_t a_id_len)
+{
+ struct eap_fast_pac *pac = data->pac;
+
+ while (pac) {
+ if (pac->a_id_len == a_id_len &&
+ memcmp(pac->a_id, a_id, a_id_len) == 0) {
+ return pac;
+ }
+ pac = pac->next;
+ }
+ return NULL;
+}
+
+
+static int eap_fast_add_pac(struct eap_fast_data *data,
+ struct eap_fast_pac *entry)
+{
+ struct eap_fast_pac *pac, *prev;
+
+ if (entry == NULL || entry->a_id == NULL)
+ return -1;
+
+ /* Remove a possible old entry for the matching A-ID. */
+ pac = data->pac;
+ prev = NULL;
+ while (pac) {
+ if (pac->a_id_len == entry->a_id_len &&
+ memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) {
+ if (prev == NULL) {
+ data->pac = pac->next;
+ } else {
+ prev->next = pac->next;
+ }
+ if (data->current_pac == pac)
+ data->current_pac = NULL;
+ eap_fast_free_pac(pac);
+ break;
+ }
+ prev = pac;
+ pac = pac->next;
+ }
+
+ /* Allocate a new entry and add it to the list of PACs. */
+ pac = malloc(sizeof(*pac));
+ if (pac == NULL)
+ return -1;
+
+ memset(pac, 0, sizeof(*pac));
+ memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
+ if (entry->pac_opaque) {
+ pac->pac_opaque = malloc(entry->pac_opaque_len);
+ if (pac->pac_opaque == NULL) {
+ eap_fast_free_pac(pac);
+ return -1;
+ }
+ memcpy(pac->pac_opaque, entry->pac_opaque,
+ entry->pac_opaque_len);
+ pac->pac_opaque_len = entry->pac_opaque_len;
+ }
+ if (entry->pac_info) {
+ pac->pac_info = malloc(entry->pac_info_len);
+ if (pac->pac_info == NULL) {
+ eap_fast_free_pac(pac);
+ return -1;
+ }
+ memcpy(pac->pac_info, entry->pac_info,
+ entry->pac_info_len);
+ pac->pac_info_len = entry->pac_info_len;
+ }
+ if (entry->a_id) {
+ pac->a_id = malloc(entry->a_id_len);
+ if (pac->a_id == NULL) {
+ eap_fast_free_pac(pac);
+ return -1;
+ }
+ memcpy(pac->a_id, entry->a_id,
+ entry->a_id_len);
+ pac->a_id_len = entry->a_id_len;
+ }
+ if (entry->i_id) {
+ pac->i_id = malloc(entry->i_id_len);
+ if (pac->i_id == NULL) {
+ eap_fast_free_pac(pac);
+ return -1;
+ }
+ memcpy(pac->i_id, entry->i_id,
+ entry->i_id_len);
+ pac->i_id_len = entry->i_id_len;
+ }
+ if (entry->a_id_info) {
+ pac->a_id_info = malloc(entry->a_id_info_len);
+ if (pac->a_id_info == NULL) {
+ eap_fast_free_pac(pac);
+ return -1;
+ }
+ memcpy(pac->a_id_info, entry->a_id_info,
+ entry->a_id_info_len);
+ pac->a_id_info_len = entry->a_id_info_len;
+ }
+ pac->next = data->pac;
+ data->pac = pac;
+ return 0;
+}
+
+
+static int eap_fast_read_line(FILE *f, char *buf, size_t buf_len)
+{
+ char *pos;
+
+ if (fgets(buf, buf_len, f) == NULL) {
+ return -1;
+ }
+
+ buf[buf_len - 1] = '\0';
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n' || *pos == '\r') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+
+ return 0;
+}
+
+
+static u8 * eap_fast_parse_hex(const char *value, size_t *len)
+{
+ int hlen;
+ u8 *buf;
+
+ if (value == NULL)
+ return NULL;
+ hlen = strlen(value);
+ if (hlen & 1)
+ return NULL;
+ *len = hlen / 2;
+ buf = malloc(*len);
+ if (buf == NULL)
+ return NULL;
+ if (hexstr2bin(value, buf, *len)) {
+ free(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+
+static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
+{
+ FILE *f;
+ struct eap_fast_pac *pac = NULL;
+ int count = 0;
+ char *buf, *pos;
+ const int buf_len = 2048;
+ int ret = 0, line = 0;
+
+ if (pac_file == NULL)
+ return -1;
+
+ f = fopen(pac_file, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - assume no "
+ "PAC entries have been provisioned", pac_file);
+ return 0;
+ }
+
+ buf = malloc(buf_len);
+ if (buf == NULL) {
+ return -1;
+ }
+
+ line++;
+ if (eap_fast_read_line(f, buf, buf_len) < 0 ||
+ strcmp(pac_file_hdr, buf) != 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in "
+ "PAC file '%s'", pac_file);
+ free(buf);
+ fclose(f);
+ return -1;
+ }
+
+ while (eap_fast_read_line(f, buf, buf_len) == 0) {
+ line++;
+ pos = strchr(buf, '=');
+ if (pos) {
+ *pos++ = '\0';
+ }
+
+ if (strcmp(buf, "START") == 0) {
+ if (pac) {
+ wpa_printf(MSG_INFO, "EAP-FAST: START line "
+ "without END in '%s:%d'",
+ pac_file, line);
+ ret = -1;
+ break;
+ }
+ pac = malloc(sizeof(*pac));
+ if (pac == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No memory for "
+ "PAC entry");
+ ret = -1;
+ break;
+ }
+ memset(pac, 0, sizeof(*pac));
+ } else if (strcmp(buf, "END") == 0) {
+ if (pac == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: END line "
+ "without START in '%s:%d'",
+ pac_file, line);
+ ret = -1;
+ break;
+ }
+ pac->next = data->pac;
+ data->pac = pac;
+ pac = NULL;
+ count++;
+ } else if (pac && strcmp(buf, "PAC-Key") == 0) {
+ u8 *key;
+ size_t key_len;
+ key = eap_fast_parse_hex(pos, &key_len);
+ if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
+ "PAC-Key '%s:%d'", pac_file, line);
+ ret = -1;
+ free(key);
+ break;
+ }
+
+ memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
+ free(key);
+ } else if (pac && strcmp(buf, "PAC-Opaque") == 0) {
+ pac->pac_opaque =
+ eap_fast_parse_hex(pos, &pac->pac_opaque_len);
+ if (pac->pac_opaque == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
+ "PAC-Opaque '%s:%d'",
+ pac_file, line);
+ ret = -1;
+ break;
+ }
+ } else if (pac && strcmp(buf, "A-ID") == 0) {
+ pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
+ if (pac->a_id == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
+ "A-ID '%s:%d'", pac_file, line);
+ ret = -1;
+ break;
+ }
+ } else if (pac && strcmp(buf, "I-ID") == 0) {
+ pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
+ if (pac->i_id == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
+ "I-ID '%s:%d'", pac_file, line);
+ ret = -1;
+ break;
+ }
+ } else if (pac && strcmp(buf, "A-ID-Info") == 0) {
+ pac->a_id_info =
+ eap_fast_parse_hex(pos, &pac->a_id_info_len);
+ if (pac->a_id_info == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
+ "A-ID-Info '%s:%d'",
+ pac_file, line);
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ if (pac) {
+ wpa_printf(MSG_INFO, "EAP-FAST: PAC block not terminated with "
+ "END in '%s'", pac_file);
+ eap_fast_free_pac(pac);
+ ret = -1;
+ }
+
+ free(buf);
+ fclose(f);
+
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: read %d PAC entries from "
+ "'%s'", count, pac_file);
+ }
+
+ return ret;
+}
+
+
+static void eap_fast_write(FILE *f, const char *field, const u8 *data,
+ size_t len, int txt)
+{
+ int i;
+
+ if (data == NULL)
+ return;
+
+ fprintf(f, "%s=", field);
+ for (i = 0; i < len; i++) {
+ fprintf(f, "%02x", data[i]);
+ }
+ fprintf(f, "\n");
+
+ if (txt) {
+ fprintf(f, "%s-txt=", field);
+ for (i = 0; i < len; i++) {
+ fprintf(f, "%c", data[i]);
+ }
+ fprintf(f, "\n");
+ }
+}
+
+
+static int eap_fast_save_pac(struct eap_fast_data *data, const char *pac_file)
+{
+ FILE *f;
+ struct eap_fast_pac *pac;
+ int count = 0;
+
+ if (pac_file == NULL)
+ return -1;
+
+ f = fopen(pac_file, "w");
+ if (f == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC file '%s' "
+ "for writing", pac_file);
+ return -1;
+ }
+
+ fprintf(f, "%s\n", pac_file_hdr);
+
+ pac = data->pac;
+ while (pac) {
+ fprintf(f, "START\n");
+ eap_fast_write(f, "PAC-Key", pac->pac_key,
+ EAP_FAST_PAC_KEY_LEN, 0);
+ eap_fast_write(f, "PAC-Opaque", pac->pac_opaque,
+ pac->pac_opaque_len, 0);
+ eap_fast_write(f, "PAC-Info", pac->pac_info,
+ pac->pac_info_len, 0);
+ eap_fast_write(f, "A-ID", pac->a_id, pac->a_id_len, 0);
+ eap_fast_write(f, "I-ID", pac->i_id, pac->i_id_len, 1);
+ eap_fast_write(f, "A-ID-Info", pac->a_id_info,
+ pac->a_id_info_len, 1);
+ fprintf(f, "END\n");
+ count++;
+ pac = pac->next;
+ }
+
+ fclose(f);
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: wrote %d PAC entries into '%s'",
+ count, pac_file);
+
+ return 0;
+}
+
+
+static void * eap_fast_init(struct eap_sm *sm)
+{
+ struct eap_fast_data *data;
+ struct wpa_ssid *config = eap_get_config(sm);
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+ data->fast_version = EAP_FAST_VERSION;
+
+ if (config && config->phase1) {
+ if (strstr(config->phase1, "fast_provisioning=1")) {
+ data->provisioning_allowed = 1;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC "
+ "provisioning is allowed");
+ }
+ }
+
+ if (config && config->phase2) {
+ char *start, *pos, *buf;
+ u8 method, *methods = NULL, *_methods;
+ size_t num_methods = 0;
+ start = buf = strdup(config->phase2);
+ if (buf == NULL) {
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+ while (start && *start != '\0') {
+ pos = strstr(start, "auth=");
+ if (pos == NULL)
+ break;
+ if (start != pos && *(pos - 1) != ' ') {
+ start = pos + 5;
+ continue;
+ }
+
+ start = pos + 5;
+ pos = strchr(start, ' ');
+ if (pos)
+ *pos++ = '\0';
+ method = eap_get_phase2_type(start);
+ if (method == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "EAP-FAST: Unsupported "
+ "Phase2 method '%s'", start);
+ } else {
+ num_methods++;
+ _methods = realloc(methods, num_methods);
+ if (_methods == NULL) {
+ free(methods);
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+ methods = _methods;
+ methods[num_methods - 1] = method;
+ }
+
+ start = pos;
+ }
+ free(buf);
+ data->phase2_types = methods;
+ data->num_phase2_types = num_methods;
+ }
+ if (data->phase2_types == NULL) {
+ data->phase2_types =
+ eap_get_phase2_types(config, &data->num_phase2_types);
+ }
+ if (data->phase2_types == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-FAST: No Phase2 method available");
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 EAP types",
+ data->phase2_types, data->num_phase2_types);
+ data->phase2_type = EAP_TYPE_NONE;
+
+ if (eap_tls_ssl_init(sm, &data->ssl, config)) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+
+ /* The local RADIUS server in a Cisco AP does not seem to like empty
+ * fragments before data, so disable that workaround for CBC.
+ * TODO: consider making this configurable */
+ tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn);
+
+ if (eap_fast_load_pac(data, config->pac_file) < 0) {
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+
+ if (data->pac == NULL && !data->provisioning_allowed) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and "
+ "provisioning disabled");
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+static void eap_fast_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_fast_data *data = priv;
+ struct eap_fast_pac *pac, *prev;
+
+ if (data == NULL)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ free(data->phase2_types);
+ free(data->key_block_a);
+ free(data->key_block_p);
+ eap_tls_ssl_deinit(sm, &data->ssl);
+
+ pac = data->pac;
+ prev = NULL;
+ while (pac) {
+ prev = pac;
+ pac = pac->next;
+ eap_fast_free_pac(prev);
+ }
+ free(data);
+}
+
+
+static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
+ int id, u8 *plain, size_t plain_len,
+ u8 **out_data, size_t *out_len)
+{
+ int res;
+ u8 *pos;
+ struct eap_hdr *resp;
+
+ /* TODO: add support for fragmentation, if needed. This will need to
+ * add TLS Message Length field, if the frame is fragmented. */
+ resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ if (resp == NULL)
+ return 0;
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_FAST;
+ *pos++ = data->fast_version;
+
+ res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+ plain, plain_len,
+ pos, data->ssl.tls_out_limit);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
+ "data");
+ free(resp);
+ return 0;
+ }
+
+ *out_len = sizeof(struct eap_hdr) + 2 + res;
+ resp->length = host_to_be16(*out_len);
+ *out_data = (u8 *) resp;
+ return 0;
+}
+
+
+static int eap_fast_phase2_nak(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ struct eap_hdr *hdr,
+ u8 **resp, size_t *resp_len)
+{
+ struct eap_hdr *resp_hdr;
+ u8 *pos = (u8 *) (hdr + 1);
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: Nak type=%d", *pos);
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Allowed Phase2 EAP types",
+ data->phase2_types, data->num_phase2_types);
+ *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;
+ *resp = malloc(*resp_len);
+ if (*resp == NULL)
+ return -1;
+
+ resp_hdr = (struct eap_hdr *) (*resp);
+ resp_hdr->code = EAP_CODE_RESPONSE;
+ resp_hdr->identifier = hdr->identifier;
+ resp_hdr->length = host_to_be16(*resp_len);
+ pos = (u8 *) (resp_hdr + 1);
+ *pos++ = EAP_TYPE_NAK;
+ memcpy(pos, data->phase2_types, data->num_phase2_types);
+
+ return 0;
+}
+
+
+static int eap_fast_derive_msk(struct eap_sm *sm, struct eap_fast_data *data)
+{
+ u8 isk[32];
+ u8 imck[60];
+
+ if (data->key_block_a == NULL)
+ return -1;
+
+ memset(isk, 0, sizeof(isk));
+ sha1_t_prf(data->key_block_a->session_key_seed,
+ sizeof(data->key_block_a->session_key_seed),
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ sha1_t_prf(imck, 40, "Session Key Generating Function", (u8 *) "", 0,
+ data->key_data, EAP_FAST_KEY_LEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
+ data->key_data, EAP_FAST_KEY_LEN);
+
+ data->success = 1;
+
+ return 0;
+}
+
+
+static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ const u8 *tls, size_t tls_len)
+{
+ struct tls_keys keys;
+ u8 master_secret[48], *seed;
+ const u8 *server_random;
+ size_t seed_len, server_random_len;
+
+ if (data->tls_master_secret_set || !data->current_pac ||
+ tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys)) {
+ return 0;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
+ keys.client_random, keys.client_random_len);
+
+ /* TLS master secret is needed before TLS library has processed this
+ * message which includes both ServerHello and an encrypted handshake
+ * message, so we need to parse server_random from this message before
+ * passing it to TLS library.
+ *
+ * Example TLS packet header:
+ * (16 03 01 00 2a 02 00 00 26 03 01 <32 bytes server_random>)
+ * Content Type: Handshake: 0x16
+ * Version: TLS 1.0 (0x0301)
+ * Lenghth: 42 (0x002a)
+ * Handshake Type: Server Hello: 0x02
+ * Length: 38 (0x000026)
+ * Version TLS 1.0 (0x0301)
+ * Random: 32 bytes
+ */
+ if (tls_len < 43 || tls[0] != 0x16 ||
+ tls[1] != 0x03 || tls[2] != 0x01 ||
+ tls[5] != 0x02 || tls[9] != 0x03 || tls[10] != 0x01) {
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: unrecognized TLS "
+ "ServerHello", tls, tls_len);
+ return -1;
+ }
+ server_random = tls + 11;
+ server_random_len = 32;
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
+ server_random, server_random_len);
+
+
+ seed_len = keys.client_random_len + server_random_len;
+ seed = malloc(seed_len);
+ if (seed == NULL)
+ return -1;
+ memcpy(seed, server_random, server_random_len);
+ memcpy(seed + server_random_len,
+ keys.client_random, keys.client_random_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key",
+ data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN);
+ /* master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
+ * server_random + client_random, 48) */
+ sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
+ "PAC to master secret label hash",
+ seed, seed_len, master_secret, sizeof(master_secret));
+ free(seed);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret",
+ master_secret, sizeof(master_secret));
+
+ data->tls_master_secret_set = 1;
+
+ return tls_connection_set_master_key(sm->ssl_ctx, data->ssl.conn,
+ master_secret,
+ sizeof(master_secret));
+}
+
+
+static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+ char *label, size_t len)
+{
+ struct tls_keys keys;
+ u8 *random;
+ u8 *out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+ out = malloc(len);
+ random = malloc(keys.client_random_len + keys.server_random_len);
+ if (out == NULL || random == NULL) {
+ free(out);
+ free(random);
+ return NULL;
+ }
+ memcpy(random, keys.server_random, keys.server_random_len);
+ memcpy(random + keys.server_random_len, keys.client_random,
+ keys.client_random_len);
+
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
+ "expansion", keys.master_key, keys.master_key_len);
+ if (tls_prf(keys.master_key, keys.master_key_len,
+ label, random, keys.client_random_len +
+ keys.server_random_len, out, len)) {
+ free(random);
+ free(out);
+ return NULL;
+ }
+ free(random);
+ return out;
+}
+
+
+static void eap_fast_derive_key_auth(struct eap_sm *sm,
+ struct eap_fast_data *data)
+{
+ free(data->key_block_a);
+ data->key_block_a = (struct eap_fast_key_block_auth *)
+ eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ sizeof(*data->key_block_a));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed",
+ data->key_block_a->session_key_seed,
+ sizeof(data->key_block_a->session_key_seed));
+}
+
+
+static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
+ struct eap_fast_data *data)
+{
+ free(data->key_block_p);
+ data->key_block_p = (struct eap_fast_key_block_provisioning *)
+ eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ sizeof(*data->key_block_p));
+ if (data->key_block_p == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
+ return;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed",
+ data->key_block_p->session_key_seed,
+ sizeof(data->key_block_p->session_key_seed));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
+ data->key_block_p->server_challenge,
+ sizeof(data->key_block_p->server_challenge));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
+ data->key_block_p->client_challenge,
+ sizeof(data->key_block_p->client_challenge));
+}
+
+
+static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
+{
+ if (data->current_pac) {
+ eap_fast_derive_key_auth(sm, data);
+ } else {
+ eap_fast_derive_key_provisioning(sm, data);
+ }
+}
+
+
+static int eap_fast_phase2_request(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ struct eap_method_ret *ret,
+ struct eap_hdr *req,
+ struct eap_hdr *hdr,
+ u8 **resp, size_t *resp_len)
+{
+ size_t len = be_to_host16(hdr->length);
+ u8 *pos;
+ struct eap_method_ret iret;
+
+ if (len <= sizeof(struct eap_hdr)) {
+ wpa_printf(MSG_INFO, "EAP-FAST: too short "
+ "Phase 2 request (len=%lu)", (unsigned long) len);
+ return -1;
+ }
+ pos = (u8 *) (hdr + 1);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
+ switch (*pos) {
+ case EAP_TYPE_IDENTITY:
+ *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
+ break;
+ default:
+ if (data->phase2_type == EAP_TYPE_NONE) {
+ int i;
+ for (i = 0; i < data->num_phase2_types; i++) {
+ if (data->phase2_types[i] != *pos)
+ continue;
+
+ data->phase2_type = *pos;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Selected "
+ "Phase 2 EAP method %d",
+ data->phase2_type);
+ break;
+ }
+ }
+ if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {
+ if (eap_fast_phase2_nak(sm, data, hdr, resp, resp_len))
+ return -1;
+ return 0;
+ }
+
+ if (data->phase2_priv == NULL) {
+ data->phase2_method = eap_sm_get_eap_methods(*pos);
+ if (data->phase2_method) {
+ if (data->key_block_p) {
+ sm->auth_challenge =
+ data->key_block_p->
+ server_challenge;
+ sm->peer_challenge =
+ data->key_block_p->
+ client_challenge;
+ }
+ sm->init_phase2 = 1;
+ data->phase2_priv =
+ data->phase2_method->init(sm);
+ sm->init_phase2 = 0;
+ sm->auth_challenge = NULL;
+ sm->peer_challenge = NULL;
+ }
+ }
+ if (data->phase2_priv == NULL || data->phase2_method == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: failed to initialize "
+ "Phase 2 EAP method %d", *pos);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return -1;
+ }
+ memset(&iret, 0, sizeof(iret));
+ *resp = data->phase2_method->process(sm, data->phase2_priv,
+ &iret, (u8 *) hdr, len,
+ resp_len);
+ if (*resp == NULL ||
+ (iret.methodState == METHOD_DONE &&
+ iret.decision == DECISION_FAIL)) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ } else if ((iret.methodState == METHOD_DONE ||
+ iret.methodState == METHOD_MAY_CONT) &&
+ (iret.decision == DECISION_UNCOND_SUCC ||
+ iret.decision == DECISION_COND_SUCC)) {
+ data->phase2_success = 1;
+ }
+ if (*resp == NULL)
+ return -1;
+ break;
+ }
+ return 0;
+}
+
+
+static u8 * eap_fast_tlv_nak(int vendor_id, int tlv_type, size_t *len)
+{
+ struct eap_tlv_nak_tlv *nak;
+ *len = sizeof(*nak);
+ nak = malloc(*len);
+ if (nak == NULL)
+ return NULL;
+ nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
+ nak->length = host_to_be16(6);
+ nak->vendor_id = host_to_be32(vendor_id);
+ nak->nak_type = host_to_be16(tlv_type);
+ return (u8 *) nak;
+}
+
+
+static u8 * eap_fast_tlv_result(int status, int intermediate, size_t *len)
+{
+ struct eap_tlv_intermediate_result_tlv *result;
+ *len = sizeof(*result);
+ result = malloc(*len);
+ if (result == NULL)
+ return NULL;
+ result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ (intermediate ?
+ EAP_TLV_INTERMEDIATE_RESULT_TLV :
+ EAP_TLV_RESULT_TLV));
+ result->length = host_to_be16(2);
+ result->status = host_to_be16(status);
+ return (u8 *) result;
+}
+
+
+static u8 * eap_fast_tlv_pac_ack(size_t *len)
+{
+ struct eap_tlv_result_tlv *res;
+ struct eap_tlv_pac_ack_tlv *ack;
+
+ *len = sizeof(*res) + sizeof(*ack);
+ res = malloc(*len);
+ if (res == NULL)
+ return NULL;
+
+ memset(res, 0, *len);
+ res->tlv_type = host_to_be16(EAP_TLV_RESULT_TLV |
+ EAP_TLV_TYPE_MANDATORY);
+ res->length = host_to_be16(sizeof(*res) - sizeof(struct eap_tlv_hdr));
+ res->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+
+ ack = (struct eap_tlv_pac_ack_tlv *) (res + 1);
+ ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |
+ EAP_TLV_TYPE_MANDATORY);
+ ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr));
+ ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
+ ack->pac_len = host_to_be16(2);
+ ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+
+ return (u8 *) res;
+}
+
+
+static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
+{
+ struct eap_tlv_hdr *tlv;
+
+ /* Encapsulate EAP packet in EAP Payload TLV */
+ tlv = malloc(sizeof(*tlv) + *len);
+ if (tlv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
+ "allocate memory for TLV "
+ "encapsulation");
+ free(buf);
+ return NULL;
+ }
+ tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ EAP_TLV_EAP_PAYLOAD_TLV);
+ tlv->length = host_to_be16(*len);
+ memcpy(tlv + 1, buf, *len);
+ free(buf);
+ *len += sizeof(*tlv);
+ return (u8 *) tlv;
+}
+
+
+static u8 * eap_fast_process_crypto_binding(
+ struct eap_sm *sm, struct eap_fast_data *data,
+ struct eap_method_ret *ret,
+ struct eap_tlv_crypto_binding__tlv *bind, size_t bind_len,
+ size_t *resp_len, int final)
+{
+ u8 *resp, *sks = NULL;
+ struct eap_tlv_intermediate_result_tlv *rresult;
+ struct eap_tlv_crypto_binding__tlv *rbind;
+ u8 isk[32], imck[60], *cmk, cmac[20], *key;
+ size_t key_len;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
+ "Received Version %d SubType %d",
+ bind->version, bind->received_version, bind->subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+ bind->nonce, sizeof(bind->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+ bind->compound_mac, sizeof(bind->compound_mac));
+
+ if (bind->version != EAP_FAST_VERSION ||
+ bind->received_version != EAP_FAST_VERSION ||
+ bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
+ "Crypto-Binding TLV: Version %d "
+ "Received Version %d SubType %d",
+ bind->version, bind->received_version,
+ bind->subtype);
+ resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
+ resp_len);
+ return resp;
+ }
+
+
+ if (data->provisioning) {
+ if (data->key_block_p) {
+ sks = data->key_block_p->session_key_seed;
+ }
+ } else {
+ if (data->key_block_a) {
+ sks = data->key_block_a->session_key_seed;
+ }
+ }
+ if (sks == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No Session Key Seed available "
+ "for processing Crypto-Binding TLV");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK for Compound MIC "
+ "calculation");
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[0] = SKS", sks, 40);
+
+ memset(isk, 0, sizeof(isk));
+ if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
+ "available");
+ return NULL;
+ }
+ if (data->phase2_method->isKeyAvailable && data->phase2_method->getKey)
+ {
+ if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv)
+ ||
+ (key = data->phase2_method->getKey(sm, data->phase2_priv,
+ &key_len)) == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key "
+ "material from Phase 2");
+ return NULL;
+ }
+ if (key_len > sizeof(isk))
+ key_len = sizeof(isk);
+ /* FIX: which end is being padded? */
+#if 0
+ memcpy(isk + (sizeof(isk) - key_len), key, key_len);
+#else
+ memcpy(isk, key, key_len);
+#endif
+ free(key);
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[0]", isk, sizeof(isk));
+ sha1_t_prf(sks, 40, "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ /* S-IMCK[1] = imkc[0..39] */
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[1]", imck, 40);
+ cmk = imck + 40;
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK", cmk, 20);
+
+ memcpy(cmac, bind->compound_mac, sizeof(cmac));
+ memset(bind->compound_mac, 0, sizeof(cmac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
+ "MAC calculation", (u8 *) bind, bind_len);
+ hmac_sha1(cmk, 20, (u8 *) bind, bind_len, bind->compound_mac);
+ res = memcmp(cmac, bind->compound_mac, sizeof(cmac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
+ cmac, sizeof(cmac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
+ bind->compound_mac, sizeof(cmac));
+ if (res != 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
+ resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
+ resp_len);
+ memcpy(bind->compound_mac, cmac, sizeof(cmac));
+ return resp;
+ }
+
+ *resp_len = sizeof(*rresult) + sizeof(*rbind);
+ resp = malloc(*resp_len);
+ if (resp == NULL)
+ return NULL;
+ memset(resp, 0, *resp_len);
+
+ /* Both intermediate and final Result TLVs are identical, so ok to use
+ * the same structure definition for them. */
+ rresult = (struct eap_tlv_intermediate_result_tlv *) resp;
+ rresult->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ (final ? EAP_TLV_RESULT_TLV :
+ EAP_TLV_INTERMEDIATE_RESULT_TLV));
+ rresult->length = host_to_be16(2);
+ rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+
+ if (!data->provisioning && data->phase2_success &&
+ eap_fast_derive_msk(sm, data) < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ rresult->status = host_to_be16(EAP_TLV_RESULT_FAILURE);
+ data->phase2_success = 0;
+ }
+
+ rbind = (struct eap_tlv_crypto_binding__tlv *) (rresult + 1);
+ rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ EAP_TLV_CRYPTO_BINDING_TLV_);
+ rbind->length = host_to_be16(sizeof(*rbind) -
+ sizeof(struct eap_tlv_hdr));
+ rbind->version = EAP_FAST_VERSION;
+ rbind->received_version = bind->version;
+ rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
+ memcpy(rbind->nonce, bind->nonce, sizeof(bind->nonce));
+ inc_byte_array(rbind->nonce, sizeof(bind->nonce));
+ hmac_sha1(cmk, 20, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac);
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
+ "Received Version %d SubType %d",
+ rbind->version, rbind->received_version, rbind->subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+ rbind->nonce, sizeof(rbind->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+ rbind->compound_mac, sizeof(rbind->compound_mac));
+
+ if (final && data->phase2_success) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication completed "
+ "successfully.");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+
+ return resp;
+}
+
+
+static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
+ struct eap_method_ret *ret,
+ u8 *pac, size_t pac_len, size_t *resp_len)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct pac_tlv_hdr *hdr;
+ u8 *pos;
+ size_t left, len;
+ int type, pac_key_found = 0;
+ struct eap_fast_pac entry;
+
+ memset(&entry, 0, sizeof(entry));
+ pos = pac;
+ left = pac_len;
+ while (left > sizeof(*hdr)) {
+ hdr = (struct pac_tlv_hdr *) pos;
+ type = be_to_host16(hdr->type);
+ len = be_to_host16(hdr->len);
+ pos += sizeof(*hdr);
+ left -= sizeof(*hdr);
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun "
+ "(type=%d len=%lu left=%lu)",
+ type, (unsigned long) len,
+ (unsigned long) left);
+ return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
+ resp_len);
+ }
+ switch (type) {
+ case PAC_TYPE_PAC_KEY:
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key",
+ pos, len);
+ if (len != EAP_FAST_PAC_KEY_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
+ "PAC-Key length %lu",
+ (unsigned long) len);
+ break;
+ }
+ pac_key_found = 1;
+ memcpy(entry.pac_key, pos, len);
+ break;
+ case PAC_TYPE_PAC_OPAQUE:
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
+ pos, len);
+ entry.pac_opaque = pos;
+ entry.pac_opaque_len = len;
+ break;
+ case PAC_TYPE_PAC_INFO:
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info",
+ pos, len);
+ entry.pac_info = pos;
+ entry.pac_info_len = len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC "
+ "type %d", type);
+ break;
+ }
+
+ pos += len;
+ left -= len;
+ }
+
+ if (!pac_key_found || !entry.pac_opaque || !entry.pac_info) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include "
+ "all the required fields");
+ return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
+ resp_len);
+ }
+
+ pos = entry.pac_info;
+ left = entry.pac_info_len;
+ while (left > sizeof(*hdr)) {
+ hdr = (struct pac_tlv_hdr *) pos;
+ type = be_to_host16(hdr->type);
+ len = be_to_host16(hdr->len);
+ pos += sizeof(*hdr);
+ left -= sizeof(*hdr);
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun "
+ "(type=%d len=%lu left=%lu)",
+ type, (unsigned long) len,
+ (unsigned long) left);
+ return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
+ resp_len);
+ }
+ switch (type) {
+ case PAC_TYPE_A_ID:
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
+ "A-ID", pos, len);
+ entry.a_id = pos;
+ entry.a_id_len = len;
+ break;
+ case PAC_TYPE_I_ID:
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
+ "I-ID", pos, len);
+ entry.i_id = pos;
+ entry.i_id_len = len;
+ break;
+ case PAC_TYPE_A_ID_INFO:
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - "
+ "A-ID-Info", pos, len);
+ entry.a_id_info = pos;
+ entry.a_id_info_len = len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown "
+ "PAC-Info type %d", type);
+ break;
+ }
+
+ pos += len;
+ left -= len;
+ }
+
+ if (entry.a_id == NULL || entry.a_id_info == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include "
+ "all the required fields");
+ return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
+ resp_len);
+ }
+
+ eap_fast_add_pac(data, &entry);
+ eap_fast_save_pac(data, config->pac_file);
+
+ if (data->provisioning) {
+ /* EAP-FAST provisioning does not provide keying material and
+ * must end with an EAP-Failure. Authentication will be done
+ * separately after this. */
+ data->success = 0;
+ ret->decision = DECISION_FAIL;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
+ "- Provisioning completed successfully");
+ } else {
+ /* This is PAC refreshing, i.e., normal authentication that is
+ * expected to be completed with an EAP-Success. */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
+ "- PAC refreshing completed successfully");
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+ ret->methodState = METHOD_DONE;
+ return eap_fast_tlv_pac_ack(resp_len);
+}
+
+
+static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
+ struct eap_method_ret *ret, struct eap_hdr *req,
+ u8 *in_data, size_t in_len,
+ u8 **out_data, size_t *out_len)
+{
+ u8 *in_decrypted, *pos, *end;
+ int buf_len, len_decrypted, len, res;
+ struct eap_hdr *hdr;
+ u8 *resp = NULL;
+ size_t resp_len;
+ int mandatory, tlv_type;
+ u8 *eap_payload_tlv = NULL, *pac = NULL;
+ size_t eap_payload_tlv_len = 0, pac_len = 0;
+ int iresult = 0, result = 0;
+ struct eap_tlv_crypto_binding__tlv *crypto_binding = NULL;
+ size_t crypto_binding_len = 0;
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: received %lu bytes encrypted data for"
+ " Phase 2", (unsigned long) in_len);
+
+ res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
+ if (res < 0 || res == 1)
+ return res;
+
+ buf_len = in_len;
+ if (data->ssl.tls_in_total > buf_len)
+ buf_len = data->ssl.tls_in_total;
+ in_decrypted = malloc(buf_len);
+ if (in_decrypted == NULL) {
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ wpa_printf(MSG_WARNING, "EAP-FAST: failed to allocate memory "
+ "for decryption");
+ return -1;
+ }
+
+ len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_data, in_len,
+ in_decrypted, buf_len);
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ if (len_decrypted < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
+ "data");
+ free(in_decrypted);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)",
+ in_decrypted, len_decrypted);
+
+ if (len_decrypted < 4) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
+ "TLV frame (len=%d)", len_decrypted);
+ return -1;
+ }
+
+ pos = in_decrypted;
+ end = in_decrypted + len_decrypted;
+ while (pos < end) {
+ mandatory = pos[0] & 0x80;
+ tlv_type = ((pos[0] & 0x3f) << 8) | pos[1];
+ len = (pos[2] << 8) | pos[3];
+ pos += 4;
+ if (pos + len > end) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: received Phase 2: "
+ "TLV type %d length %d%s",
+ tlv_type, len, mandatory ? " (mandatory)" : "");
+
+ switch (tlv_type) {
+ case EAP_TLV_EAP_PAYLOAD_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP Payload TLV",
+ pos, len);
+ eap_payload_tlv = pos;
+ eap_payload_tlv_len = len;
+ break;
+ case EAP_TLV_RESULT_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV",
+ pos, len);
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+ "Result TLV");
+ result = EAP_TLV_RESULT_FAILURE;
+ break;
+ }
+ result = (pos[0] << 16) | pos[1];
+ if (result != EAP_TLV_RESULT_SUCCESS &&
+ result != EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
+ "Result %d", result);
+ result = EAP_TLV_RESULT_FAILURE;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
+ result == EAP_TLV_RESULT_SUCCESS ?
+ "Success" : "Failure");
+ break;
+ case EAP_TLV_INTERMEDIATE_RESULT_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate "
+ "Result TLV", pos, len);
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+ "Intermediate Result TLV");
+ iresult = EAP_TLV_RESULT_FAILURE;
+ break;
+ }
+ iresult = (pos[0] << 16) | pos[1];
+ if (iresult != EAP_TLV_RESULT_SUCCESS &&
+ iresult != EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
+ "Intermediate Result %d", iresult);
+ iresult = EAP_TLV_RESULT_FAILURE;
+ }
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Intermediate Result: %s",
+ iresult == EAP_TLV_RESULT_SUCCESS ?
+ "Success" : "Failure");
+ break;
+ case EAP_TLV_CRYPTO_BINDING_TLV_:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding "
+ "TLV", pos, len);
+ crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
+ if (crypto_binding_len < sizeof(*crypto_binding)) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+ "Crypto-Binding TLV");
+ iresult = EAP_TLV_RESULT_FAILURE;
+ pos = end;
+ break;
+ }
+ crypto_binding =
+ (struct eap_tlv_crypto_binding__tlv *)
+ (pos - sizeof(struct eap_tlv_hdr));
+ break;
+ case EAP_TLV_PAC_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV",
+ pos, len);
+ pac = pos;
+ pac_len = len;
+ break;
+ default:
+ if (mandatory) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
+ "mandatory TLV type %d", tlv_type);
+ resp = eap_fast_tlv_nak(0, tlv_type,
+ &resp_len);
+ pos = end;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
+ "unknown optional TLV type %d",
+ tlv_type);
+ }
+ break;
+ }
+
+ pos += len;
+ }
+
+ if (!resp && result == EAP_TLV_RESULT_FAILURE) {
+ resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
+ &resp_len);
+ if (!resp) {
+ free(in_decrypted);
+ return 0;
+ }
+ }
+
+ if (!resp && iresult == EAP_TLV_RESULT_FAILURE) {
+ resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
+ &resp_len);
+ if (!resp) {
+ free(in_decrypted);
+ return 0;
+ }
+ }
+
+ if (!resp && eap_payload_tlv) {
+ if (eap_payload_tlv_len < sizeof(*hdr)) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
+ "Payload TLV (len=%lu)",
+ (unsigned long) eap_payload_tlv_len);
+ free(in_decrypted);
+ return 0;
+ }
+ hdr = (struct eap_hdr *) eap_payload_tlv;
+ if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow "
+ "in EAP Payload TLV");
+ }
+ if (hdr->code == EAP_CODE_REQUEST) {
+ if (eap_fast_phase2_request(sm, data, ret, req, hdr,
+ &resp, &resp_len)) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-FAST: Phase2 "
+ "Request processing failed");
+ return 0;
+ }
+ resp = eap_fast_tlv_eap_payload(resp, &resp_len);
+ if (resp == NULL) {
+ free(in_decrypted);
+ return 0;
+ }
+ } else {
+ wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
+ "Phase 2 EAP header", hdr->code);
+ free(in_decrypted);
+ return 0;
+ }
+ }
+
+ if (!resp && crypto_binding) {
+ int final = result == EAP_TLV_RESULT_SUCCESS;
+ resp = eap_fast_process_crypto_binding(sm, data, ret,
+ crypto_binding,
+ crypto_binding_len,
+ &resp_len, final);
+ if (!resp) {
+ free(in_decrypted);
+ return 0;
+ }
+ }
+
+ if (!resp && pac && result != EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
+ "acnowledging success");
+ resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
+ &resp_len);
+ if (!resp) {
+ free(in_decrypted);
+ return 0;
+ }
+ }
+
+ if (!resp && pac && result == EAP_TLV_RESULT_SUCCESS) {
+ resp = eap_fast_process_pac(sm, data, ret, pac, pac_len,
+ &resp_len);
+ if (!resp) {
+ free(in_decrypted);
+ return 0;
+ }
+ }
+
+ free(in_decrypted);
+
+ if (resp == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
+ "empty response packet");
+ resp = malloc(0);
+ if (resp == NULL)
+ return 0;
+ resp_len = 0;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data",
+ resp, resp_len);
+ if (eap_fast_encrypt(sm, data, req->identifier, resp, resp_len,
+ out_data, out_len)) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
+ "frame");
+ }
+ free(resp);
+
+ return 0;
+}
+
+
+static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_hdr *req;
+ int left, res;
+ unsigned int tls_msg_len;
+ u8 flags, *pos, *resp, id;
+ struct eap_fast_data *data = priv;
+
+ if (tls_get_errors(sm->ssl_ctx)) {
+ wpa_printf(MSG_INFO, "EAP-FAST: TLS errors detected");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_FAST ||
+ (left = host_to_be16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ left -= sizeof(struct eap_hdr);
+ id = req->identifier;
+ pos++;
+ flags = *pos++;
+ left -= 2;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received packet(len=%lu) - "
+ "Flags 0x%02x", (unsigned long) reqDataLen, flags);
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Short frame with TLS "
+ "length");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
+ pos[3];
+ wpa_printf(MSG_DEBUG, "EAP-FAST: TLS Message Length: %d",
+ tls_msg_len);
+ if (data->ssl.tls_in_left == 0) {
+ data->ssl.tls_in_total = tls_msg_len;
+ data->ssl.tls_in_left = tls_msg_len;
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ if (flags & EAP_TLS_FLAGS_START) {
+ u8 *a_id;
+ size_t a_id_len;
+ struct pac_tlv_hdr *hdr;
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own "
+ "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
+ data->fast_version);
+ if ((flags & EAP_PEAP_VERSION_MASK) < data->fast_version)
+ data->fast_version = flags & EAP_PEAP_VERSION_MASK;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d",
+ data->fast_version);
+
+ a_id = pos;
+ a_id_len = left;
+ if (left > sizeof(*hdr)) {
+ int tlen;
+ hdr = (struct pac_tlv_hdr *) pos;
+ tlen = be_to_host16(hdr->len);
+ if (be_to_host16(hdr->type) == PAC_TYPE_A_ID &&
+ sizeof(*hdr) + tlen <= left) {
+ a_id = (u8 *) (hdr + 1);
+ a_id_len = tlen;
+ }
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, a_id_len);
+
+ data->current_pac = eap_fast_get_pac(data, a_id, a_id_len);
+ if (data->current_pac) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this "
+ "A-ID");
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info",
+ data->current_pac->a_id_info,
+ data->current_pac->a_id_info_len);
+ }
+
+ if (data->resuming && data->current_pac) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume "
+ "session - do not add PAC-Opaque to TLS "
+ "ClientHello");
+ if (tls_connection_client_hello_ext(
+ sm->ssl_ctx, data->ssl.conn,
+ TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
+ "remove PAC-Opaque TLS extension");
+ return NULL;
+ }
+
+ } else if (data->current_pac) {
+ u8 *tlv;
+ size_t tlv_len, olen;
+ struct eap_tlv_hdr *hdr;
+ olen = data->current_pac->pac_opaque_len;
+ tlv_len = sizeof(*hdr) + olen;
+ tlv = malloc(tlv_len);
+ if (tlv) {
+ hdr = (struct eap_tlv_hdr *) tlv;
+ hdr->tlv_type =
+ host_to_be16(PAC_TYPE_PAC_OPAQUE);
+ hdr->length = host_to_be16(olen);
+ memcpy(hdr + 1, data->current_pac->pac_opaque,
+ olen);
+ }
+ if (tlv == NULL ||
+ tls_connection_client_hello_ext(
+ sm->ssl_ctx, data->ssl.conn,
+ TLS_EXT_PAC_OPAQUE, tlv, tlv_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
+ "add PAC-Opaque TLS extension");
+ free(tlv);
+ return NULL;
+ }
+ free(tlv);
+ } else {
+ if (!data->provisioning_allowed) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found "
+ "and provisioning disabled");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
+ "starting provisioning");
+ if (tls_connection_set_anon_dh(sm->ssl_ctx,
+ data->ssl.conn)) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Could not "
+ "configure anonymous DH for TLS "
+ "connection");
+ return NULL;
+ }
+ if (tls_connection_client_hello_ext(
+ sm->ssl_ctx, data->ssl.conn,
+ TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
+ "remove PAC-Opaque TLS extension");
+ return NULL;
+ }
+ data->provisioning = 1;
+ }
+
+ left = 0; /* A-ID is not used in further packet processing */
+ }
+
+ resp = NULL;
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+ !data->resuming) {
+ res = eap_fast_decrypt(sm, data, ret, req, pos, left,
+ &resp, respDataLen);
+ if (res < 0) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ /* Ack possible Alert that may have caused failure in
+ * decryption */
+ res = 1;
+ }
+ } else {
+ if (eap_fast_set_tls_master_secret(sm, data, pos, left) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to configure "
+ "TLS master secret");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+
+ res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_FAST,
+ data->fast_version, id, pos, left,
+ &resp, respDataLen);
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: TLS done, proceed to Phase 2");
+ data->resuming = 0;
+ eap_fast_derive_keys(sm, data);
+ }
+ }
+
+ if (res == 1)
+ return eap_tls_build_ack(&data->ssl, respDataLen, id,
+ EAP_TYPE_FAST, data->fast_version);
+ return resp;
+}
+
+
+#if 0 /* FIX */
+static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+ struct eap_fast_data *data = priv;
+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+}
+
+
+static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_fast_data *data = priv;
+ if (eap_tls_reauth_init(sm, &data->ssl)) {
+ free(data);
+ return NULL;
+ }
+ data->phase2_success = 0;
+ data->resuming = 1;
+ data->provisioning = 0;
+ return priv;
+}
+#endif
+
+
+static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
+ size_t buflen, int verbose)
+{
+ struct eap_fast_data *data = priv;
+ return eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
+}
+
+
+static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_fast_data *data = priv;
+ return data->success;
+}
+
+
+static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+ u8 *key;
+
+ if (!data->success)
+ return NULL;
+
+ key = malloc(EAP_FAST_KEY_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_FAST_KEY_LEN;
+ memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
+
+ return key;
+}
+
+
+const struct eap_method eap_method_fast =
+{
+ .method = EAP_TYPE_FAST,
+ .name = "FAST",
+ .init = eap_fast_init,
+ .deinit = eap_fast_deinit,
+ .process = eap_fast_process,
+ .isKeyAvailable = eap_fast_isKeyAvailable,
+ .getKey = eap_fast_getKey,
+ .get_status = eap_fast_get_status,
+#if 0
+ .has_reauth_data = eap_fast_has_reauth_data,
+ .deinit_for_reauth = eap_fast_deinit_for_reauth,
+ .init_for_reauth = eap_fast_init_for_reauth,
+#endif
+};
diff --git a/contrib/wpa_supplicant/eap_gtc.c b/contrib/wpa_supplicant/eap_gtc.c
new file mode 100644
index 000000000000..42a7a49acaf1
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_gtc.c
@@ -0,0 +1,164 @@
+/*
+ * WPA Supplicant / EAP-GTC (RFC 2284)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+
+
+struct eap_gtc_data {
+ int prefix;
+};
+
+
+static void * eap_gtc_init(struct eap_sm *sm)
+{
+ struct eap_gtc_data *data;
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+
+ if (sm->m && sm->m->method == EAP_TYPE_FAST) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
+ "with challenge/response");
+ data->prefix = 1;
+ }
+ return data;
+}
+
+
+static void eap_gtc_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_gtc_data *data = priv;
+ free(data);
+}
+
+
+static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_gtc_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *req, *resp;
+ u8 *pos, *password;
+ size_t password_len, len, msg_len;
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_GTC ||
+ (len = be_to_host16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos++;
+ msg_len = len - sizeof(*req) - 1;
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message",
+ pos, msg_len);
+ if (data->prefix &&
+ (msg_len < 10 || memcmp(pos, "CHALLENGE=", 10) != 0)) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
+ "expected prefix");
+
+ /* Send an empty response in order to allow tunneled
+ * acknowledgement of the failure. This will also cover the
+ * error case which seems to use EAP-MSCHAPv2 like error
+ * reporting with EAP-GTC inside EAP-FAST tunnel. */
+ *respDataLen = sizeof(struct eap_hdr) + 1;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(*respDataLen);
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_GTC;
+ return (u8 *) resp;
+ }
+
+ if (config == NULL ||
+ (config->password == NULL && config->otp == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
+ eap_sm_request_otp(sm, config, (char *) pos,
+ len - sizeof(*req) - 1);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (config->otp) {
+ password = config->otp;
+ password_len = config->otp_len;
+ } else {
+ password = config->password;
+ password_len = config->password_len;
+ }
+
+ ret->ignore = FALSE;
+
+ ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
+ ret->decision = DECISION_COND_SUCC;
+ ret->allowNotifications = FALSE;
+
+ *respDataLen = sizeof(struct eap_hdr) + 1 + password_len;
+ if (data->prefix) {
+ *respDataLen += 9 + config->identity_len + 1;
+ }
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(*respDataLen);
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_GTC;
+ if (data->prefix) {
+ memcpy(pos, "RESPONSE=", 9);
+ pos += 9;
+ memcpy(pos, config->identity, config->identity_len);
+ pos += config->identity_len;
+ *pos++ = '\0';
+ }
+ memcpy(pos, password, password_len);
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
+ (u8 *) (resp + 1) + 1,
+ *respDataLen - sizeof(struct eap_hdr) - 1);
+
+ if (config->otp) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password");
+ memset(config->otp, 0, config->otp_len);
+ free(config->otp);
+ config->otp = NULL;
+ config->otp_len = 0;
+ }
+
+ return (u8 *) resp;
+}
+
+
+const struct eap_method eap_method_gtc =
+{
+ .method = EAP_TYPE_GTC,
+ .name = "GTC",
+ .init = eap_gtc_init,
+ .deinit = eap_gtc_deinit,
+ .process = eap_gtc_process,
+};
diff --git a/contrib/wpa_supplicant/eap_i.h b/contrib/wpa_supplicant/eap_i.h
new file mode 100644
index 000000000000..c71981255783
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_i.h
@@ -0,0 +1,106 @@
+#ifndef EAP_I_H
+#define EAP_I_H
+
+#include "eap.h"
+
+/* draft-ietf-eap-statemachine-05.pdf - Peer state machine */
+
+typedef enum {
+ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC
+} EapDecision;
+
+typedef enum {
+ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE
+} EapMethodState;
+
+struct eap_method_ret {
+ Boolean ignore;
+ EapMethodState methodState;
+ EapDecision decision;
+ Boolean allowNotifications;
+};
+
+
+struct eap_method {
+ EapType method;
+ const char *name;
+
+ void * (*init)(struct eap_sm *sm);
+ void (*deinit)(struct eap_sm *sm, void *priv);
+ u8 * (*process)(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen);
+ Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
+ u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
+ int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
+ size_t buflen, int verbose);
+
+ /* Optional handlers for fast re-authentication */
+ Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
+ void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
+ void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
+ const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
+};
+
+
+struct eap_sm {
+ enum {
+ EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED,
+ EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD,
+ EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS,
+ EAP_FAILURE
+ } EAP_state;
+ /* Long-term local variables */
+ EapType selectedMethod;
+ EapMethodState methodState;
+ int lastId;
+ u8 *lastRespData;
+ size_t lastRespDataLen;
+ EapDecision decision;
+ /* Short-term local variables */
+ Boolean rxReq;
+ Boolean rxSuccess;
+ Boolean rxFailure;
+ int reqId;
+ EapType reqMethod;
+ Boolean ignore;
+ /* Constants */
+ int ClientTimeout;
+
+ /* Miscellaneous variables */
+ Boolean allowNotifications; /* peer state machine <-> methods */
+ u8 *eapRespData; /* peer to lower layer */
+ size_t eapRespDataLen; /* peer to lower layer */
+ Boolean eapKeyAvailable; /* peer to lower layer */
+ u8 *eapKeyData; /* peer to lower layer */
+ size_t eapKeyDataLen; /* peer to lower layer */
+ const struct eap_method *m; /* selected EAP method */
+ /* not defined in draft-ietf-eap-statemachine-02 */
+ Boolean changed;
+ void *eapol_ctx;
+ struct eapol_callbacks *eapol_cb;
+ void *eap_method_priv;
+ int init_phase2;
+ int fast_reauth;
+
+ Boolean rxResp /* LEAP only */;
+ Boolean leap_done;
+ Boolean peap_done;
+ u8 req_md5[16]; /* MD5() of the current EAP packet */
+ u8 last_md5[16]; /* MD5() of the previously received EAP packet; used
+ * in duplicate request detection. */
+
+ void *msg_ctx;
+ void *scard_ctx;
+ void *ssl_ctx;
+
+ unsigned int workaround;
+
+ /* Optional challenges generated in Phase 1 (EAP-FAST) */
+ u8 *peer_challenge, *auth_challenge;
+
+ int num_rounds;
+};
+
+#endif /* EAP_I_H */
diff --git a/contrib/wpa_supplicant/eap_leap.c b/contrib/wpa_supplicant/eap_leap.c
new file mode 100644
index 000000000000..6409a6855f92
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_leap.c
@@ -0,0 +1,379 @@
+/*
+ * WPA Supplicant / EAP-LEAP
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "ms_funcs.h"
+#include "md5.h"
+
+#define LEAP_VERSION 1
+#define LEAP_CHALLENGE_LEN 8
+#define LEAP_RESPONSE_LEN 24
+#define LEAP_KEY_LEN 16
+
+
+struct eap_leap_data {
+ enum {
+ LEAP_WAIT_CHALLENGE,
+ LEAP_WAIT_SUCCESS,
+ LEAP_WAIT_RESPONSE,
+ LEAP_DONE
+ } state;
+
+ u8 peer_challenge[LEAP_CHALLENGE_LEN];
+ u8 peer_response[LEAP_RESPONSE_LEN];
+
+ u8 ap_challenge[LEAP_CHALLENGE_LEN];
+ u8 ap_response[LEAP_RESPONSE_LEN];
+};
+
+
+static void * eap_leap_init(struct eap_sm *sm)
+{
+ struct eap_leap_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+ data->state = LEAP_WAIT_CHALLENGE;
+
+ sm->leap_done = FALSE;
+ return data;
+}
+
+
+static void eap_leap_deinit(struct eap_sm *sm, void *priv)
+{
+ free(priv);
+}
+
+
+static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_leap_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *req, *resp;
+ u8 *pos, *challenge, challenge_len;
+
+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_LEAP) {
+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos++;
+
+ if (*pos != LEAP_VERSION) {
+ wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
+ "%d", *pos);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos++;
+
+ pos++; /* skip unused byte */
+
+ challenge_len = *pos++;
+ if (challenge_len != LEAP_CHALLENGE_LEN ||
+ challenge_len > reqDataLen - sizeof(*req) - 4) {
+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
+ "(challenge_len=%d reqDataLen=%lu",
+ challenge_len, (unsigned long) reqDataLen);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ challenge = pos;
+ memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
+ challenge, LEAP_CHALLENGE_LEN);
+
+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
+
+ *respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_RESPONSE_LEN +
+ config->identity_len;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(*respDataLen);
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_LEAP;
+ *pos++ = LEAP_VERSION;
+ *pos++ = 0; /* unused */
+ *pos++ = LEAP_RESPONSE_LEN;
+ nt_challenge_response(challenge,
+ config->password, config->password_len, pos);
+ memcpy(data->peer_response, pos, LEAP_RESPONSE_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", pos, LEAP_RESPONSE_LEN);
+ pos += LEAP_RESPONSE_LEN;
+ memcpy(pos, config->identity, config->identity_len);
+
+ data->state = LEAP_WAIT_SUCCESS;
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_leap_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *req, *resp;
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
+
+ if (data->state != LEAP_WAIT_SUCCESS) {
+ wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
+ "unexpected state (%d) - ignored", data->state);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_hdr *) reqData;
+
+ *respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_CHALLENGE_LEN +
+ config->identity_len;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_REQUEST;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(*respDataLen);
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_LEAP;
+ *pos++ = LEAP_VERSION;
+ *pos++ = 0; /* unused */
+ *pos++ = LEAP_CHALLENGE_LEN;
+ if (hostapd_get_rand(pos, LEAP_CHALLENGE_LEN)) {
+ wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
+ "for challenge");
+ free(resp);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
+ LEAP_CHALLENGE_LEN);
+ pos += LEAP_CHALLENGE_LEN;
+ memcpy(pos, config->identity, config->identity_len);
+
+ data->state = LEAP_WAIT_RESPONSE;
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_leap_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *resp;
+ u8 *pos, response_len, pw_hash[16], pw_hash_hash[16],
+ expected[LEAP_RESPONSE_LEN];
+
+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
+
+ resp = (struct eap_hdr *) reqData;
+ pos = (u8 *) (resp + 1);
+ if (reqDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_LEAP) {
+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos++;
+
+ if (*pos != LEAP_VERSION) {
+ wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
+ "%d", *pos);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos++;
+
+ pos++; /* skip unused byte */
+
+ response_len = *pos++;
+ if (response_len != LEAP_RESPONSE_LEN ||
+ response_len > reqDataLen - sizeof(*resp) - 4) {
+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
+ "(response_len=%d reqDataLen=%lu",
+ response_len, (unsigned long) reqDataLen);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
+ pos, LEAP_RESPONSE_LEN);
+ memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
+
+ nt_password_hash(config->password, config->password_len, pw_hash);
+ hash_nt_password_hash(pw_hash, pw_hash_hash);
+ challenge_response(data->ap_challenge, pw_hash_hash, expected);
+
+ ret->methodState = METHOD_DONE;
+ ret->allowNotifications = FALSE;
+
+ if (memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
+ wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
+ "response - authentication failed");
+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
+ expected, LEAP_RESPONSE_LEN);
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+
+ ret->decision = DECISION_UNCOND_SUCC;
+
+ /* LEAP is somewhat odd method since it sends EAP-Success in the middle
+ * of the authentication. Use special variable to transit EAP state
+ * machine to SUCCESS state. */
+ sm->leap_done = TRUE;
+ data->state = LEAP_DONE;
+
+ /* No more authentication messages expected; AP will send EAPOL-Key
+ * frames if encryption is enabled. */
+ return NULL;
+}
+
+
+static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *eap;
+ size_t len;
+
+ if (config == NULL || config->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
+ eap_sm_request_password(sm, config);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ eap = (struct eap_hdr *) reqData;
+
+ if (reqDataLen < sizeof(*eap) ||
+ (len = be_to_host16(eap->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ ret->ignore = FALSE;
+ ret->allowNotifications = TRUE;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+
+ sm->leap_done = FALSE;
+
+ switch (eap->code) {
+ case EAP_CODE_REQUEST:
+ return eap_leap_process_request(sm, priv, ret, reqData, len,
+ respDataLen);
+ case EAP_CODE_SUCCESS:
+ return eap_leap_process_success(sm, priv, ret, reqData, len,
+ respDataLen);
+ case EAP_CODE_RESPONSE:
+ return eap_leap_process_response(sm, priv, ret, reqData, len,
+ respDataLen);
+ default:
+ wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
+ "ignored", eap->code);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+}
+
+
+static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_leap_data *data = priv;
+ return data->state == LEAP_DONE;
+}
+
+
+static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_leap_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ u8 *key, pw_hash_hash[16], pw_hash[16];
+ MD5_CTX context;
+
+ if (data->state != LEAP_DONE)
+ return NULL;
+
+ key = malloc(LEAP_KEY_LEN);
+ if (key == NULL)
+ return NULL;
+
+ nt_password_hash(config->password, config->password_len, pw_hash);
+ hash_nt_password_hash(pw_hash, pw_hash_hash);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
+ pw_hash_hash, 16);
+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
+ data->peer_challenge, LEAP_CHALLENGE_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
+ data->peer_response, LEAP_RESPONSE_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
+ data->ap_challenge, LEAP_CHALLENGE_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
+ data->ap_response, LEAP_RESPONSE_LEN);
+
+ MD5Init(&context);
+ MD5Update(&context, pw_hash_hash, 16);
+ MD5Update(&context, data->ap_challenge, LEAP_CHALLENGE_LEN);
+ MD5Update(&context, data->ap_response, LEAP_RESPONSE_LEN);
+ MD5Update(&context, data->peer_challenge, LEAP_CHALLENGE_LEN);
+ MD5Update(&context, data->peer_response, LEAP_RESPONSE_LEN);
+ MD5Final(key, &context);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
+ *len = LEAP_KEY_LEN;
+
+ return key;
+}
+
+
+const struct eap_method eap_method_leap =
+{
+ .method = EAP_TYPE_LEAP,
+ .name = "LEAP",
+ .init = eap_leap_init,
+ .deinit = eap_leap_deinit,
+ .process = eap_leap_process,
+ .isKeyAvailable = eap_leap_isKeyAvailable,
+ .getKey = eap_leap_getKey,
+};
diff --git a/contrib/wpa_supplicant/eap_md5.c b/contrib/wpa_supplicant/eap_md5.c
new file mode 100644
index 000000000000..bcb5558be97e
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_md5.c
@@ -0,0 +1,112 @@
+/*
+ * WPA Supplicant / EAP-MD5
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "md5.h"
+
+
+static void * eap_md5_init(struct eap_sm *sm)
+{
+ return (void *) 1;
+}
+
+
+static void eap_md5_deinit(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *req, *resp;
+ u8 *pos, *challenge;
+ int challenge_len;
+ MD5_CTX context;
+ size_t len;
+
+ if (config == NULL || config->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
+ eap_sm_request_password(sm, config);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_MD5 ||
+ (len = be_to_host16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos++;
+ challenge_len = *pos++;
+ if (challenge_len == 0 ||
+ challenge_len > len - sizeof(*req) - 2) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
+ "(challenge_len=%d len=%lu",
+ challenge_len, (unsigned long) len);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ ret->ignore = FALSE;
+ challenge = pos;
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
+ challenge, challenge_len);
+
+ wpa_printf(MSG_DEBUG, "EAP-MD5: generating Challenge Response");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ ret->allowNotifications = TRUE;
+
+ *respDataLen = sizeof(struct eap_hdr) + 1 + 1 + MD5_MAC_LEN;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(*respDataLen);
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_MD5;
+ *pos++ = MD5_MAC_LEN; /* Value-Size */
+
+ MD5Init(&context);
+ MD5Update(&context, &resp->identifier, 1);
+ MD5Update(&context, config->password, config->password_len);
+ MD5Update(&context, challenge, challenge_len);
+ MD5Final(pos, &context);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN);
+
+ return (u8 *) resp;
+}
+
+
+const struct eap_method eap_method_md5 =
+{
+ .method = EAP_TYPE_MD5,
+ .name = "MD5",
+ .init = eap_md5_init,
+ .deinit = eap_md5_deinit,
+ .process = eap_md5_process,
+};
diff --git a/contrib/wpa_supplicant/eap_mschapv2.c b/contrib/wpa_supplicant/eap_mschapv2.c
new file mode 100644
index 000000000000..a39a5d330a78
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_mschapv2.c
@@ -0,0 +1,564 @@
+/*
+ * WPA Supplicant / EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "ms_funcs.h"
+
+
+struct eap_mschapv2_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_MSCHAPV2 */
+ u8 op_code; /* MSCHAPV2_OP_* */
+ u8 mschapv2_id; /* usually same as identifier */
+ u8 ms_length[2]; /* Note: misaligned; length - 5 */
+ /* followed by data */
+} __attribute__ ((packed));
+
+#define MSCHAPV2_OP_CHALLENGE 1
+#define MSCHAPV2_OP_RESPONSE 2
+#define MSCHAPV2_OP_SUCCESS 3
+#define MSCHAPV2_OP_FAILURE 4
+#define MSCHAPV2_OP_CHANGE_PASSWORD 7
+
+#define MSCHAPV2_RESP_LEN 49
+
+#define ERROR_RESTRICTED_LOGON_HOURS 646
+#define ERROR_ACCT_DISABLED 647
+#define ERROR_PASSWD_EXPIRED 648
+#define ERROR_NO_DIALIN_PERMISSION 649
+#define ERROR_AUTHENTICATION_FAILURE 691
+#define ERROR_CHANGING_PASSWORD 709
+
+#define PASSWD_CHANGE_CHAL_LEN 16
+#define MSCHAPV2_KEY_LEN 16
+
+
+struct eap_mschapv2_data {
+ u8 auth_response[20];
+ int auth_response_valid;
+
+ int prev_error;
+ u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
+ int passwd_change_challenge_valid;
+ int passwd_change_version;
+
+ /* Optional challenge values generated in EAP-FAST Phase 1 negotiation
+ */
+ u8 *peer_challenge;
+ u8 *auth_challenge;
+
+ int phase2;
+ u8 master_key[16];
+ int master_key_valid;
+ int success;
+};
+
+
+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_mschapv2_init(struct eap_sm *sm)
+{
+ struct eap_mschapv2_data *data;
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+
+ if (sm->peer_challenge) {
+ data->peer_challenge = malloc(16);
+ if (data->peer_challenge == NULL) {
+ eap_mschapv2_deinit(sm, data);
+ return NULL;
+ }
+ memcpy(data->peer_challenge, sm->peer_challenge, 16);
+ }
+
+ if (sm->auth_challenge) {
+ data->auth_challenge = malloc(16);
+ if (data->auth_challenge == NULL) {
+ eap_mschapv2_deinit(sm, data);
+ return NULL;
+ }
+ memcpy(data->auth_challenge, sm->auth_challenge, 16);
+ }
+
+ data->phase2 = sm->init_phase2;
+
+ return data;
+}
+
+
+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_mschapv2_data *data = priv;
+ free(data->peer_challenge);
+ free(data->auth_challenge);
+ free(data);
+}
+
+
+static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ struct eap_method_ret *ret,
+ struct eap_mschapv2_hdr *req,
+ size_t *respDataLen)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ u8 *challenge, *peer_challenge, *username, *pos;
+ int challenge_len, i, ms_len;
+ size_t len, username_len;
+ struct eap_mschapv2_hdr *resp;
+ u8 password_hash[16], password_hash_hash[16];
+
+ /* MSCHAPv2 does not include optional domain name in the
+ * challenge-response calculation, so remove domain prefix
+ * (if present). */
+ username = config->identity;
+ username_len = config->identity_len;
+ for (i = 0; i < username_len; i++) {
+ if (username[i] == '\\') {
+ username_len -= i + 1;
+ username += i + 1;
+ break;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
+ len = be_to_host16(req->length);
+ pos = (u8 *) (req + 1);
+ challenge_len = *pos++;
+ if (challenge_len != 16) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
+ "%d", challenge_len);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (len - challenge_len - 10 < 0) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
+ " packet: len=%lu challenge_len=%d",
+ (unsigned long) len, challenge_len);
+ }
+
+ challenge = pos;
+ pos += challenge_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
+ pos, len - challenge_len - 10);
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
+
+ *respDataLen = sizeof(*resp) + 1 + MSCHAPV2_RESP_LEN +
+ config->identity_len;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ memset(resp, 0, *respDataLen);
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(*respDataLen);
+ resp->type = EAP_TYPE_MSCHAPV2;
+ resp->op_code = MSCHAPV2_OP_RESPONSE;
+ resp->mschapv2_id = req->mschapv2_id;
+ ms_len = *respDataLen - 5;
+ resp->ms_length[0] = ms_len >> 8;
+ resp->ms_length[1] = ms_len & 0xff;
+ pos = (u8 *) (resp + 1);
+ *pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */
+
+ /* Response */
+ peer_challenge = pos;
+ if (data->peer_challenge) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
+ "in Phase 1");
+ peer_challenge = data->peer_challenge;
+ } else if (hostapd_get_rand(peer_challenge, 16)) {
+ free(resp);
+ return NULL;
+ }
+ pos += 16;
+ pos += 8; /* Reserved, must be zero */
+ if (data->auth_challenge) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
+ "in Phase 1");
+ challenge = data->auth_challenge;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", challenge, 16);
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
+ peer_challenge, 16);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
+ username, username_len);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
+ config->password, config->password_len);
+ generate_nt_response(challenge, peer_challenge,
+ username, username_len,
+ config->password, config->password_len,
+ pos);
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", pos, 24);
+ /* Authenticator response is not really needed yet, but calculate it
+ * here so that challenges need not be saved. */
+ generate_authenticator_response(config->password, config->password_len,
+ peer_challenge, challenge,
+ username, username_len, pos,
+ data->auth_response);
+ data->auth_response_valid = 1;
+
+ /* Likewise, generate master_key here since we have the needed data
+ * available. */
+ nt_password_hash(config->password, config->password_len,
+ password_hash);
+ hash_nt_password_hash(password_hash, password_hash_hash);
+ get_master_key(password_hash_hash, pos /* nt_response */,
+ data->master_key);
+ data->master_key_valid = 1;
+
+ pos += 24;
+ pos++; /* Flag / reserved, must be zero */
+
+ memcpy(pos, config->identity, config->identity_len);
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_mschapv2_success(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ struct eap_method_ret *ret,
+ struct eap_mschapv2_hdr *req,
+ size_t *respDataLen)
+{
+ struct eap_mschapv2_hdr *resp;
+ u8 *pos, recv_response[20];
+ int len, left;
+
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
+ len = be_to_host16(req->length);
+ pos = (u8 *) (req + 1);
+ if (!data->auth_response_valid || len < sizeof(*req) + 42 ||
+ pos[0] != 'S' || pos[1] != '=' ||
+ hexstr2bin((char *) (pos + 2), recv_response, 20) ||
+ memcmp(data->auth_response, recv_response, 20) != 0) {
+ wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
+ "response in success request");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+ pos += 42;
+ left = len - sizeof(*req) - 42;
+ while (left > 0 && *pos == ' ') {
+ pos++;
+ left--;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
+ pos, left);
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
+ *respDataLen = 6;
+ resp = malloc(6);
+ if (resp == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
+ "buffer for success response");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(6);
+ resp->type = EAP_TYPE_MSCHAPV2;
+ resp->op_code = MSCHAPV2_OP_SUCCESS;
+
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ ret->allowNotifications = FALSE;
+ data->success = 1;
+
+ return (u8 *) resp;
+}
+
+
+static int eap_mschapv2_failure_txt(struct eap_sm *sm,
+ struct eap_mschapv2_data *data, char *txt)
+{
+ char *pos, *msg = "";
+ int retry = 1;
+ struct wpa_ssid *config = eap_get_config(sm);
+
+ /* For example:
+ * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
+ */
+
+ pos = txt;
+
+ if (pos && strncmp(pos, "E=", 2) == 0) {
+ pos += 2;
+ data->prev_error = atoi(pos);
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
+ data->prev_error);
+ pos = strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ if (pos && strncmp(pos, "R=", 2) == 0) {
+ pos += 2;
+ retry = atoi(pos);
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
+ retry == 1 ? "" : "not ");
+ pos = strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ if (pos && strncmp(pos, "C=", 2) == 0) {
+ int hex_len;
+ pos += 2;
+ hex_len = strchr(pos, ' ') - (char *) pos;
+ if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
+ if (hexstr2bin(pos, data->passwd_change_challenge,
+ PASSWD_CHANGE_CHAL_LEN)) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
+ "failure challenge");
+ } else {
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
+ "challenge",
+ data->passwd_change_challenge,
+ PASSWD_CHANGE_CHAL_LEN);
+ data->passwd_change_challenge_valid = 1;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
+ "challenge len %d", hex_len);
+ }
+ pos = strchr(pos, ' ');
+ if (pos)
+ pos++;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
+ "was not present in failure message");
+ }
+
+ if (pos && strncmp(pos, "V=", 2) == 0) {
+ pos += 2;
+ data->passwd_change_version = atoi(pos);
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
+ "protocol version %d", data->passwd_change_version);
+ pos = strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ if (pos && strncmp(pos, "M=", 2) == 0) {
+ pos += 2;
+ msg = pos;
+ }
+ wpa_msg(sm->msg_ctx, MSG_WARNING,
+ "EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
+ "%d)",
+ msg, retry == 1 ? "" : "not ", data->prev_error);
+ if (retry == 1 && config) {
+ /* TODO: could prevent the current password from being used
+ * again at least for some period of time */
+ eap_sm_request_identity(sm, config);
+ eap_sm_request_password(sm, config);
+ } else if (config) {
+ /* TODO: prevent retries using same username/password */
+ }
+
+ return retry == 1;
+}
+
+
+static u8 * eap_mschapv2_failure(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ struct eap_method_ret *ret,
+ struct eap_mschapv2_hdr *req,
+ size_t *respDataLen)
+{
+ struct eap_mschapv2_hdr *resp;
+ u8 *msdata = (u8 *) (req + 1);
+ char *buf;
+ int len = be_to_host16(req->length) - sizeof(*req);
+ int retry = 0;
+
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
+ msdata, len);
+ buf = malloc(len + 1);
+ if (buf) {
+ memcpy(buf, msdata, len);
+ buf[len] = '\0';
+ retry = eap_mschapv2_failure_txt(sm, data, buf);
+ free(buf);
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = FALSE;
+
+ if (retry) {
+ /* TODO: could try to retry authentication, e.g, after having
+ * changed the username/password. In this case, EAP MS-CHAP-v2
+ * Failure Response would not be sent here. */
+ }
+
+ *respDataLen = 6;
+ resp = malloc(6);
+ if (resp == NULL) {
+ return NULL;
+ }
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(6);
+ resp->type = EAP_TYPE_MSCHAPV2;
+ resp->op_code = MSCHAPV2_OP_FAILURE;
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_mschapv2_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_mschapv2_hdr *req;
+ int ms_len, len;
+
+ if (config == NULL || config->identity == NULL) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
+ eap_sm_request_identity(sm, config);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (config->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+ eap_sm_request_password(sm, config);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_mschapv2_hdr *) reqData;
+ len = be_to_host16(req->length);
+ if (len < sizeof(*req) + 2 || req->type != EAP_TYPE_MSCHAPV2) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ ms_len = ((int) req->ms_length[0] << 8) | req->ms_length[1];
+ if (ms_len != len - 5) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%d "
+ "ms_len=%d", len, ms_len);
+ if (sm->workaround) {
+ /* Some authentication servers use invalid ms_len,
+ * ignore it for interoperability. */
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
+ " invalid ms_len");
+ } else {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ }
+
+ switch (req->op_code) {
+ case MSCHAPV2_OP_CHALLENGE:
+ return eap_mschapv2_challenge(sm, data, ret, req, respDataLen);
+ case MSCHAPV2_OP_SUCCESS:
+ return eap_mschapv2_success(sm, data, ret, req, respDataLen);
+ case MSCHAPV2_OP_FAILURE:
+ return eap_mschapv2_failure(sm, data, ret, req, respDataLen);
+ default:
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
+ req->op_code);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+}
+
+
+static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_mschapv2_data *data = priv;
+ return data->success && data->master_key_valid;
+}
+
+
+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_mschapv2_data *data = priv;
+ u8 *key;
+ int key_len;
+
+ if (!data->master_key_valid || !data->success)
+ return NULL;
+
+ if (data->peer_challenge) {
+ /* EAP-FAST needs both send and receive keys */
+ key_len = 2 * MSCHAPV2_KEY_LEN;
+ } else {
+ key_len = MSCHAPV2_KEY_LEN;
+ }
+
+ key = malloc(key_len);
+ if (key == NULL)
+ return NULL;
+
+ if (data->peer_challenge) {
+ get_asymetric_start_key(data->master_key, key,
+ MSCHAPV2_KEY_LEN, 0, 0);
+ get_asymetric_start_key(data->master_key,
+ key + MSCHAPV2_KEY_LEN,
+ MSCHAPV2_KEY_LEN, 1, 0);
+ } else {
+ get_asymetric_start_key(data->master_key, key,
+ MSCHAPV2_KEY_LEN, 1, 0);
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
+ key, key_len);
+
+ *len = key_len;
+ return key;
+}
+
+
+const struct eap_method eap_method_mschapv2 =
+{
+ .method = EAP_TYPE_MSCHAPV2,
+ .name = "MSCHAPV2",
+ .init = eap_mschapv2_init,
+ .deinit = eap_mschapv2_deinit,
+ .process = eap_mschapv2_process,
+ .isKeyAvailable = eap_mschapv2_isKeyAvailable,
+ .getKey = eap_mschapv2_getKey,
+};
diff --git a/contrib/wpa_supplicant/eap_otp.c b/contrib/wpa_supplicant/eap_otp.c
new file mode 100644
index 000000000000..e50de636accd
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_otp.c
@@ -0,0 +1,113 @@
+/*
+ * WPA Supplicant / EAP-OTP (RFC 3748)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+
+
+static void * eap_otp_init(struct eap_sm *sm)
+{
+ return (void *) 1;
+}
+
+
+static void eap_otp_deinit(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static u8 * eap_otp_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *req, *resp;
+ u8 *pos, *password;
+ size_t password_len, len;
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_OTP ||
+ (len = be_to_host16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-OTP: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos++;
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
+ pos, len - sizeof(*req) - 1);
+
+ if (config == NULL ||
+ (config->password == NULL && config->otp == NULL)) {
+ wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
+ eap_sm_request_otp(sm, config, (char *) pos,
+ len - sizeof(*req) - 1);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (config->otp) {
+ password = config->otp;
+ password_len = config->otp_len;
+ } else {
+ password = config->password;
+ password_len = config->password_len;
+ }
+
+ ret->ignore = FALSE;
+
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_COND_SUCC;
+ ret->allowNotifications = FALSE;
+
+ *respDataLen = sizeof(struct eap_hdr) + 1 + password_len;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(*respDataLen);
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_OTP;
+ memcpy(pos, password, password_len);
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response",
+ password, password_len);
+
+ if (config->otp) {
+ wpa_printf(MSG_DEBUG, "EAP-OTP: Forgetting used password");
+ memset(config->otp, 0, config->otp_len);
+ free(config->otp);
+ config->otp = NULL;
+ config->otp_len = 0;
+ }
+
+ return (u8 *) resp;
+}
+
+
+const struct eap_method eap_method_otp =
+{
+ .method = EAP_TYPE_OTP,
+ .name = "OTP",
+ .init = eap_otp_init,
+ .deinit = eap_otp_deinit,
+ .process = eap_otp_process,
+};
diff --git a/contrib/wpa_supplicant/eap_peap.c b/contrib/wpa_supplicant/eap_peap.c
new file mode 100644
index 000000000000..27f0793cb8c1
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_peap.c
@@ -0,0 +1,820 @@
+/*
+ * WPA Supplicant / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "tls.h"
+#include "eap_tlv.h"
+
+
+/* Maximum supported PEAP version
+ * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
+ * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
+ * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
+ */
+#define EAP_PEAP_VERSION 1
+
+
+static void eap_peap_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_peap_data {
+ struct eap_ssl_data ssl;
+
+ int peap_version, force_peap_version, force_new_label;
+
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+ int phase2_success;
+
+ u8 phase2_type;
+ u8 *phase2_types;
+ size_t num_phase2_types;
+
+ int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
+ * EAP-Success
+ * 1 = reply with tunneled EAP-Success to inner
+ * EAP-Success and expect AS to send outer
+ * (unencrypted) EAP-Success after this
+ * 2 = reply with PEAP/TLS ACK to inner
+ * EAP-Success and expect AS to send outer
+ * (unencrypted) EAP-Success after this */
+ int resuming; /* starting a resumed session */
+ u8 *key_data;
+
+ u8 *pending_phase2_req;
+ size_t pending_phase2_req_len;
+};
+
+
+static void * eap_peap_init(struct eap_sm *sm)
+{
+ struct eap_peap_data *data;
+ struct wpa_ssid *config = eap_get_config(sm);
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ sm->peap_done = FALSE;
+ memset(data, 0, sizeof(*data));
+ data->peap_version = EAP_PEAP_VERSION;
+ data->force_peap_version = -1;
+ data->peap_outer_success = 2;
+
+ if (config && config->phase1) {
+ char *pos = strstr(config->phase1, "peapver=");
+ if (pos) {
+ data->force_peap_version = atoi(pos + 8);
+ data->peap_version = data->force_peap_version;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version "
+ "%d", data->force_peap_version);
+ }
+
+ if (strstr(config->phase1, "peaplabel=1")) {
+ data->force_new_label = 1;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for "
+ "key derivation");
+ }
+
+ if (strstr(config->phase1, "peap_outer_success=0")) {
+ data->peap_outer_success = 0;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate "
+ "authentication on tunneled EAP-Success");
+ } else if (strstr(config->phase1, "peap_outer_success=1")) {
+ data->peap_outer_success = 1;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled "
+ "EAP-Success after receiving tunneled "
+ "EAP-Success");
+ } else if (strstr(config->phase1, "peap_outer_success=2")) {
+ data->peap_outer_success = 2;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK "
+ "after receiving tunneled EAP-Success");
+ }
+ }
+
+ if (config && config->phase2) {
+ char *start, *pos, *buf;
+ u8 method, *methods = NULL, *_methods;
+ size_t num_methods = 0;
+ start = buf = strdup(config->phase2);
+ if (buf == NULL) {
+ eap_peap_deinit(sm, data);
+ return NULL;
+ }
+ while (start && *start != '\0') {
+ pos = strstr(start, "auth=");
+ if (pos == NULL)
+ break;
+ if (start != pos && *(pos - 1) != ' ') {
+ start = pos + 5;
+ continue;
+ }
+
+ start = pos + 5;
+ pos = strchr(start, ' ');
+ if (pos)
+ *pos++ = '\0';
+ method = eap_get_phase2_type(start);
+ if (method == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "EAP-PEAP: Unsupported "
+ "Phase2 method '%s'", start);
+ } else {
+ num_methods++;
+ _methods = realloc(methods, num_methods);
+ if (_methods == NULL) {
+ free(methods);
+ eap_peap_deinit(sm, data);
+ return NULL;
+ }
+ methods = _methods;
+ methods[num_methods - 1] = method;
+ }
+
+ start = pos;
+ }
+ free(buf);
+ data->phase2_types = methods;
+ data->num_phase2_types = num_methods;
+ }
+ if (data->phase2_types == NULL) {
+ data->phase2_types =
+ eap_get_phase2_types(config, &data->num_phase2_types);
+ }
+ if (data->phase2_types == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-PEAP: No Phase2 method available");
+ eap_peap_deinit(sm, data);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 EAP types",
+ data->phase2_types, data->num_phase2_types);
+ data->phase2_type = EAP_TYPE_NONE;
+
+ if (eap_tls_ssl_init(sm, &data->ssl, config)) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
+ eap_peap_deinit(sm, data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+static void eap_peap_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ if (data == NULL)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ free(data->phase2_types);
+ eap_tls_ssl_deinit(sm, &data->ssl);
+ free(data->key_data);
+ free(data->pending_phase2_req);
+ free(data);
+}
+
+
+static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
+ int id, u8 *plain, size_t plain_len,
+ u8 **out_data, size_t *out_len)
+{
+ int res;
+ u8 *pos;
+ struct eap_hdr *resp;
+
+ /* TODO: add support for fragmentation, if needed. This will need to
+ * add TLS Message Length field, if the frame is fragmented.
+ * Note: Microsoft IAS did not seem to like TLS Message Length with
+ * PEAP/MSCHAPv2. */
+ resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ if (resp == NULL)
+ return -1;
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_PEAP;
+ *pos++ = data->peap_version;
+
+ res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+ plain, plain_len,
+ pos, data->ssl.tls_out_limit);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
+ "data");
+ free(resp);
+ return -1;
+ }
+
+ *out_len = sizeof(struct eap_hdr) + 2 + res;
+ resp->length = host_to_be16(*out_len);
+ *out_data = (u8 *) resp;
+ return 0;
+}
+
+
+static int eap_peap_phase2_nak(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ struct eap_hdr *hdr,
+ u8 **resp, size_t *resp_len)
+{
+ struct eap_hdr *resp_hdr;
+ u8 *pos = (u8 *) (hdr + 1);
+
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: Nak type=%d", *pos);
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Allowed Phase2 EAP types",
+ data->phase2_types, data->num_phase2_types);
+ *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;
+ *resp = malloc(*resp_len);
+ if (*resp == NULL)
+ return -1;
+
+ resp_hdr = (struct eap_hdr *) (*resp);
+ resp_hdr->code = EAP_CODE_RESPONSE;
+ resp_hdr->identifier = hdr->identifier;
+ resp_hdr->length = host_to_be16(*resp_len);
+ pos = (u8 *) (resp_hdr + 1);
+ *pos++ = EAP_TYPE_NAK;
+ memcpy(pos, data->phase2_types, data->num_phase2_types);
+
+ return 0;
+}
+
+
+static int eap_peap_phase2_request(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ struct eap_method_ret *ret,
+ struct eap_hdr *req,
+ struct eap_hdr *hdr,
+ u8 **resp, size_t *resp_len)
+{
+ size_t len = be_to_host16(hdr->length);
+ u8 *pos;
+ struct eap_method_ret iret;
+ struct wpa_ssid *config = eap_get_config(sm);
+
+ if (len <= sizeof(struct eap_hdr)) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: too short "
+ "Phase 2 request (len=%lu)", (unsigned long) len);
+ return -1;
+ }
+ pos = (u8 *) (hdr + 1);
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
+ switch (*pos) {
+ case EAP_TYPE_IDENTITY:
+ *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
+ break;
+ case EAP_TYPE_TLV:
+ memset(&iret, 0, sizeof(iret));
+ if (eap_tlv_process(sm, &iret, hdr, resp, resp_len)) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return -1;
+ }
+ if (iret.methodState == METHOD_DONE ||
+ iret.methodState == METHOD_MAY_CONT) {
+ ret->methodState = iret.methodState;
+ ret->decision = iret.decision;
+ data->phase2_success = 1;
+ }
+ break;
+ default:
+ if (data->phase2_type == EAP_TYPE_NONE) {
+ int i;
+ for (i = 0; i < data->num_phase2_types; i++) {
+ if (data->phase2_types[i] != *pos)
+ continue;
+
+ data->phase2_type = *pos;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
+ "Phase 2 EAP method %d",
+ data->phase2_type);
+ break;
+ }
+ }
+ if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {
+ if (eap_peap_phase2_nak(sm, data, hdr, resp, resp_len))
+ return -1;
+ return 0;
+ }
+
+ if (data->phase2_priv == NULL) {
+ data->phase2_method = eap_sm_get_eap_methods(*pos);
+ if (data->phase2_method) {
+ sm->init_phase2 = 1;
+ data->phase2_priv =
+ data->phase2_method->init(sm);
+ sm->init_phase2 = 0;
+ }
+ }
+ if (data->phase2_priv == NULL || data->phase2_method == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
+ "Phase 2 EAP method %d", *pos);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return -1;
+ }
+ memset(&iret, 0, sizeof(iret));
+ *resp = data->phase2_method->process(sm, data->phase2_priv,
+ &iret, (u8 *) hdr, len,
+ resp_len);
+ if ((iret.methodState == METHOD_DONE ||
+ iret.methodState == METHOD_MAY_CONT) &&
+ (iret.decision == DECISION_UNCOND_SUCC ||
+ iret.decision == DECISION_COND_SUCC)) {
+ data->phase2_success = 1;
+ }
+ break;
+ }
+
+ if (*resp == NULL &&
+ (config->pending_req_identity || config->pending_req_password ||
+ config->pending_req_otp)) {
+ free(data->pending_phase2_req);
+ data->pending_phase2_req = malloc(len);
+ if (data->pending_phase2_req) {
+ memcpy(data->pending_phase2_req, hdr, len);
+ data->pending_phase2_req_len = len;
+ }
+ }
+
+ return 0;
+}
+
+
+static int eap_peap_decrypt(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ struct eap_method_ret *ret,
+ struct eap_hdr *req,
+ u8 *in_data, size_t in_len,
+ u8 **out_data, size_t *out_len)
+{
+ u8 *in_decrypted;
+ int buf_len, len_decrypted, len, skip_change = 0, res;
+ struct eap_hdr *hdr, *rhdr;
+ u8 *resp = NULL;
+ size_t resp_len;
+
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
+ " Phase 2", (unsigned long) in_len);
+
+ if (data->pending_phase2_req) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
+ "skip decryption and use old data");
+ in_decrypted = data->pending_phase2_req;
+ data->pending_phase2_req = NULL;
+ len_decrypted = data->pending_phase2_req_len;
+ skip_change = 1;
+ goto continue_req;
+ }
+
+ res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
+ if (res < 0 || res == 1)
+ return res;
+
+ buf_len = in_len;
+ if (data->ssl.tls_in_total > buf_len)
+ buf_len = data->ssl.tls_in_total;
+ in_decrypted = malloc(buf_len);
+ if (in_decrypted == NULL) {
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
+ "for decryption");
+ return -1;
+ }
+
+ len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_data, in_len,
+ in_decrypted, buf_len);
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ if (len_decrypted < 0) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
+ "data");
+ free(in_decrypted);
+ return 0;
+ }
+
+continue_req:
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted,
+ len_decrypted);
+
+ hdr = (struct eap_hdr *) in_decrypted;
+ if (len_decrypted == 5 && hdr->code == EAP_CODE_REQUEST &&
+ be_to_host16(hdr->length) == 5 &&
+ in_decrypted[4] == EAP_TYPE_IDENTITY) {
+ /* At least FreeRADIUS seems to send full EAP header with
+ * EAP Request Identity */
+ skip_change = 1;
+ }
+ if (len_decrypted >= 5 && hdr->code == EAP_CODE_REQUEST &&
+ in_decrypted[4] == EAP_TYPE_TLV) {
+ skip_change = 1;
+ }
+
+ if (data->peap_version == 0 && !skip_change) {
+ struct eap_hdr *nhdr = malloc(sizeof(struct eap_hdr) +
+ len_decrypted);
+ if (nhdr == NULL) {
+ free(in_decrypted);
+ return 0;
+ }
+ memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
+ free(in_decrypted);
+ nhdr->code = req->code;
+ nhdr->identifier = req->identifier;
+ nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
+ len_decrypted);
+
+ len_decrypted += sizeof(struct eap_hdr);
+ in_decrypted = (u8 *) nhdr;
+ }
+ hdr = (struct eap_hdr *) in_decrypted;
+ if (len_decrypted < sizeof(*hdr)) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
+ "EAP frame (len=%d)", len_decrypted);
+ return 0;
+ }
+ len = be_to_host16(hdr->length);
+ if (len > len_decrypted) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
+ "Phase 2 EAP frame (len=%d hdr->length=%d)",
+ len_decrypted, len);
+ return 0;
+ }
+ if (len < len_decrypted) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
+ "shorter length than full decrypted data (%d < %d)",
+ len, len_decrypted);
+ if (sm->workaround && len == 4 && len_decrypted == 5 &&
+ in_decrypted[4] == EAP_TYPE_IDENTITY) {
+ /* Radiator 3.9 seems to set Phase 2 EAP header to use
+ * incorrect length for the EAP-Request Identity
+ * packet, so fix the inner header to interoperate..
+ * This was fixed in 2004-06-23 patch for Radiator and
+ * this workaround can be removed at some point. */
+ wpa_printf(MSG_INFO, "EAP-PEAP: workaround -> replace "
+ "Phase 2 EAP header len (%d) with real "
+ "decrypted len (%d)", len, len_decrypted);
+ len = len_decrypted;
+ hdr->length = host_to_be16(len);
+ }
+ }
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
+ "identifier=%d length=%d", hdr->code, hdr->identifier, len);
+ switch (hdr->code) {
+ case EAP_CODE_REQUEST:
+ if (eap_peap_phase2_request(sm, data, ret, req, hdr,
+ &resp, &resp_len)) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
+ "processing failed");
+ return 0;
+ }
+ break;
+ case EAP_CODE_SUCCESS:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
+ if (data->peap_version == 1) {
+ /* EAP-Success within TLS tunnel is used to indicate
+ * shutdown of the TLS channel. The authentication has
+ * been completed. */
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
+ "EAP-Success within TLS tunnel - "
+ "authentication completed");
+ ret->decision = DECISION_UNCOND_SUCC;
+ ret->methodState = METHOD_DONE;
+ data->phase2_success = 1;
+ if (data->peap_outer_success == 2) {
+ free(in_decrypted);
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
+ "to finish authentication");
+ return 1;
+ } else if (data->peap_outer_success == 1) {
+ /* Reply with EAP-Success within the TLS
+ * channel to complete the authentication. */
+ resp_len = sizeof(struct eap_hdr);
+ resp = malloc(resp_len);
+ if (resp) {
+ memset(resp, 0, resp_len);
+ rhdr = (struct eap_hdr *) resp;
+ rhdr->code = EAP_CODE_SUCCESS;
+ rhdr->identifier = hdr->identifier;
+ rhdr->length = host_to_be16(resp_len);
+ }
+ } else {
+ /* No EAP-Success expected for Phase 1 (outer,
+ * unencrypted auth), so force EAP state
+ * machine to SUCCESS state. */
+ sm->peap_done = TRUE;
+ }
+ } else {
+ /* FIX: ? */
+ }
+ break;
+ case EAP_CODE_FAILURE:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
+ ret->decision = DECISION_FAIL;
+ ret->methodState = METHOD_MAY_CONT;
+ ret->allowNotifications = FALSE;
+ /* Reply with EAP-Failure within the TLS channel to complete
+ * failure reporting. */
+ resp_len = sizeof(struct eap_hdr);
+ resp = malloc(resp_len);
+ if (resp) {
+ memset(resp, 0, resp_len);
+ rhdr = (struct eap_hdr *) resp;
+ rhdr->code = EAP_CODE_FAILURE;
+ rhdr->identifier = hdr->identifier;
+ rhdr->length = host_to_be16(resp_len);
+ }
+ break;
+ default:
+ wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
+ "Phase 2 EAP header", hdr->code);
+ break;
+ }
+
+ free(in_decrypted);
+
+ if (resp) {
+ u8 *resp_pos;
+ size_t resp_send_len;
+ int skip_change = 0;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
+ resp, resp_len);
+ /* PEAP version changes */
+ if (resp_len >= 5 && resp[0] == EAP_CODE_RESPONSE &&
+ resp[4] == EAP_TYPE_TLV)
+ skip_change = 1;
+ if (data->peap_version == 0 && !skip_change) {
+ resp_pos = resp + sizeof(struct eap_hdr);
+ resp_send_len = resp_len - sizeof(struct eap_hdr);
+ } else {
+ resp_pos = resp;
+ resp_send_len = resp_len;
+ }
+
+ if (eap_peap_encrypt(sm, data, req->identifier,
+ resp_pos, resp_send_len,
+ out_data, out_len)) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
+ "a Phase 2 frame");
+ }
+ free(resp);
+ }
+
+ return 0;
+}
+
+
+static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_hdr *req;
+ int left, res;
+ unsigned int tls_msg_len;
+ u8 flags, *pos, *resp, id;
+ struct eap_peap_data *data = priv;
+
+ if (tls_get_errors(sm->ssl_ctx)) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: TLS errors detected");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_PEAP ||
+ (left = be_to_host16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ left -= sizeof(struct eap_hdr);
+ id = req->identifier;
+ pos++;
+ flags = *pos++;
+ left -= 2;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
+ "Flags 0x%02x", (unsigned long) reqDataLen, flags);
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
+ "length");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
+ pos[3];
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
+ tls_msg_len);
+ if (data->ssl.tls_in_left == 0) {
+ data->ssl.tls_in_total = tls_msg_len;
+ data->ssl.tls_in_left = tls_msg_len;
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ if (flags & EAP_TLS_FLAGS_START) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
+ "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
+ data->peap_version);
+ if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version)
+ data->peap_version = flags & EAP_PEAP_VERSION_MASK;
+ if (data->force_peap_version >= 0 &&
+ data->force_peap_version != data->peap_version) {
+ wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
+ "forced PEAP version %d",
+ data->force_peap_version);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = FALSE;
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
+ data->peap_version);
+ left = 0; /* make sure that this frame is empty, even though it
+ * should always be, anyway */
+ }
+
+ resp = NULL;
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+ !data->resuming) {
+ res = eap_peap_decrypt(sm, data, ret, req, pos, left,
+ &resp, respDataLen);
+ } else {
+ res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_PEAP,
+ data->peap_version, id, pos, left,
+ &resp, respDataLen);
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ char *label;
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: TLS done, proceed to Phase 2");
+ free(data->key_data);
+ /* draft-josefsson-ppext-eap-tls-eap-05.txt
+ * specifies that PEAPv1 would use "client PEAP
+ * encryption" as the label. However, most existing
+ * PEAPv1 implementations seem to be using the old
+ * label, "client EAP encryption", instead. Use the old
+ * label by default, but allow it to be configured with
+ * phase1 parameter peaplabel=1. */
+ if (data->peap_version > 1 || data->force_new_label)
+ label = "client PEAP encryption";
+ else
+ label = "client EAP encryption";
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
+ "key derivation", label);
+ data->key_data =
+ eap_tls_derive_key(sm, &data->ssl, label,
+ EAP_TLS_KEY_LEN);
+ if (data->key_data) {
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-PEAP: Derived key",
+ data->key_data,
+ EAP_TLS_KEY_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
+ "derive key");
+ }
+ data->resuming = 0;
+ }
+ }
+
+ if (ret->methodState == METHOD_DONE) {
+ ret->allowNotifications = FALSE;
+ }
+
+ if (res == 1) {
+ return eap_tls_build_ack(&data->ssl, respDataLen, id,
+ EAP_TYPE_PEAP, data->peap_version);
+ }
+
+ return resp;
+}
+
+
+static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+ data->phase2_success;
+}
+
+
+static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ free(data->pending_phase2_req);
+ data->pending_phase2_req = NULL;
+}
+
+
+static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ free(data->key_data);
+ data->key_data = NULL;
+ if (eap_tls_reauth_init(sm, &data->ssl)) {
+ free(data);
+ return NULL;
+ }
+ data->phase2_success = 0;
+ data->resuming = 1;
+ sm->peap_done = FALSE;
+ return priv;
+}
+
+
+static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
+ size_t buflen, int verbose)
+{
+ struct eap_peap_data *data = priv;
+ int len;
+
+ len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
+ if (data->phase2_method) {
+ len += snprintf(buf + len, buflen - len,
+ "EAP-PEAPv%d Phase2 method=%s\n",
+ data->peap_version, data->phase2_method->name);
+ }
+ return len;
+}
+
+
+static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ return data->key_data != NULL && data->phase2_success;
+}
+
+
+static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *key;
+
+ if (data->key_data == NULL || !data->phase2_success)
+ return NULL;
+
+ key = malloc(EAP_TLS_KEY_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_TLS_KEY_LEN;
+ memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+ return key;
+}
+
+
+const struct eap_method eap_method_peap =
+{
+ .method = EAP_TYPE_PEAP,
+ .name = "PEAP",
+ .init = eap_peap_init,
+ .deinit = eap_peap_deinit,
+ .process = eap_peap_process,
+ .isKeyAvailable = eap_peap_isKeyAvailable,
+ .getKey = eap_peap_getKey,
+ .get_status = eap_peap_get_status,
+ .has_reauth_data = eap_peap_has_reauth_data,
+ .deinit_for_reauth = eap_peap_deinit_for_reauth,
+ .init_for_reauth = eap_peap_init_for_reauth,
+};
diff --git a/contrib/wpa_supplicant/eap_psk.c b/contrib/wpa_supplicant/eap_psk.c
new file mode 100644
index 000000000000..3b325b59dd91
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_psk.c
@@ -0,0 +1,563 @@
+/*
+ * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-05.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "md5.h"
+#include "aes_wrap.h"
+
+
+/* draft-bersani-eap-psk-03.txt mode. This is retained for interop testing and
+ * will be removed once an AS that supports draft5 becomes available. */
+#define EAP_PSK_DRAFT3
+
+#define EAP_PSK_RAND_LEN 16
+#define EAP_PSK_MAC_LEN 16
+#define EAP_PSK_TEK_LEN 16
+#define EAP_PSK_MSK_LEN 64
+
+#define EAP_PSK_R_FLAG_CONT 1
+#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
+#define EAP_PSK_R_FLAG_DONE_FAILURE 3
+
+/* EAP-PSK First Message (AS -> Supplicant) */
+struct eap_psk_hdr_1 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+#ifndef EAP_PSK_DRAFT3
+ u8 flags;
+#endif /* EAP_PSK_DRAFT3 */
+ u8 rand_s[EAP_PSK_RAND_LEN];
+#ifndef EAP_PSK_DRAFT3
+ /* Followed by variable length ID_S */
+#endif /* EAP_PSK_DRAFT3 */
+} __attribute__ ((packed));
+
+/* EAP-PSK Second Message (Supplicant -> AS) */
+struct eap_psk_hdr_2 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+#ifndef EAP_PSK_DRAFT3
+ u8 flags;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+#endif /* EAP_PSK_DRAFT3 */
+ u8 rand_p[EAP_PSK_RAND_LEN];
+ u8 mac_p[EAP_PSK_MAC_LEN];
+ /* Followed by variable length ID_P */
+} __attribute__ ((packed));
+
+/* EAP-PSK Third Message (AS -> Supplicant) */
+struct eap_psk_hdr_3 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+#ifndef EAP_PSK_DRAFT3
+ u8 flags;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+#endif /* EAP_PSK_DRAFT3 */
+ u8 mac_s[EAP_PSK_MAC_LEN];
+ /* Followed by variable length PCHANNEL */
+} __attribute__ ((packed));
+
+/* EAP-PSK Fourth Message (Supplicant -> AS) */
+struct eap_psk_hdr_4 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+#ifndef EAP_PSK_DRAFT3
+ u8 flags;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+#endif /* EAP_PSK_DRAFT3 */
+ /* Followed by variable length PCHANNEL */
+} __attribute__ ((packed));
+
+
+
+struct eap_psk_data {
+ enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+ u8 rand_p[EAP_PSK_RAND_LEN];
+ u8 ak[16], kdk[16], tek[EAP_PSK_TEK_LEN];
+ u8 *id_s, *id_p;
+ size_t id_s_len, id_p_len;
+ u8 key_data[EAP_PSK_MSK_LEN];
+};
+
+
+#define aes_block_size 16
+
+
+static void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
+{
+ memset(ak, 0, aes_block_size);
+ aes_128_encrypt_block(psk, ak, ak);
+ memcpy(kdk, ak, aes_block_size);
+ ak[aes_block_size - 1] ^= 0x01;
+ kdk[aes_block_size - 1] ^= 0x02;
+ aes_128_encrypt_block(psk, ak, ak);
+ aes_128_encrypt_block(psk, kdk, kdk);
+}
+
+
+static void eap_psk_derive_keys(const u8 *kdk, const u8 *rb, u8 *tek, u8 *msk)
+{
+ u8 hash[aes_block_size];
+ u8 counter = 1;
+ int i;
+
+ aes_128_encrypt_block(kdk, rb, hash);
+
+ hash[aes_block_size - 1] ^= counter;
+ aes_128_encrypt_block(kdk, hash, tek);
+ hash[aes_block_size - 1] ^= counter;
+ counter++;
+
+ for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) {
+ hash[aes_block_size - 1] ^= counter;
+ aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]);
+ hash[aes_block_size - 1] ^= counter;
+ counter++;
+ }
+}
+
+
+static void * eap_psk_init(struct eap_sm *sm)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_psk_data *data;
+
+ if (config == NULL || !config->eappsk) {
+ wpa_printf(MSG_INFO, "EAP-PSK: pre-shared key not configured");
+ return NULL;
+ }
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+ eap_psk_key_setup(config->eappsk, data->ak, data->kdk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, 16);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, 16);
+ data->state = PSK_INIT;
+
+ if (config->nai) {
+ data->id_p = malloc(config->nai_len);
+ if (data->id_p)
+ memcpy(data->id_p, config->nai, config->nai_len);
+ data->id_p_len = config->nai_len;
+ }
+ if (data->id_p == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
+ free(data);
+ return NULL;
+ }
+
+#ifdef EAP_PSK_DRAFT3
+ if (config->server_nai) {
+ data->id_s = malloc(config->server_nai_len);
+ if (data->id_s)
+ memcpy(data->id_s, config->server_nai,
+ config->server_nai_len);
+ data->id_s_len = config->server_nai_len;
+ }
+ if (data->id_s == NULL) {
+ wpa_printf(MSG_INFO, "EAP-PSK: could not get server identity");
+ free(data->id_p);
+ free(data);
+ return NULL;
+ }
+#endif /* EAP_PSK_DRAFT3 */
+
+ return data;
+}
+
+
+static void eap_psk_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_psk_data *data = priv;
+ free(data->id_s);
+ free(data->id_p);
+ free(data);
+}
+
+
+static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_psk_hdr_1 *hdr1;
+ struct eap_psk_hdr_2 *hdr2;
+ u8 *resp, *buf, *pos;
+ size_t buflen;
+
+ wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
+
+ hdr1 = (struct eap_psk_hdr_1 *) reqData;
+ if (reqDataLen < sizeof(*hdr1) ||
+ be_to_host16(hdr1->length) < sizeof(*hdr1) ||
+ be_to_host16(hdr1->length) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
+ "length (%lu %d; expected %lu or more)",
+ (unsigned long) reqDataLen,
+ be_to_host16(hdr1->length),
+ (unsigned long) sizeof(*hdr1));
+ ret->ignore = TRUE;
+ return NULL;
+ }
+#ifndef EAP_PSK_DRAFT3
+ wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
+ if ((hdr1->flags & 0x03) != 0) {
+ wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
+ hdr1->flags & 0x03);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+#endif /* EAP_PSK_DRAFT3 */
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
+ EAP_PSK_RAND_LEN);
+ memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
+#ifndef EAP_PSK_DRAFT3
+ free(data->id_s);
+ data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1);
+ data->id_s = malloc(data->id_s_len);
+ if (data->id_s == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
+ "ID_S (len=%d)", data->id_s_len);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
+ data->id_s, data->id_s_len);
+#endif /* EAP_PSK_DRAFT3 */
+
+ if (hostapd_get_rand(data->rand_p, EAP_PSK_RAND_LEN)) {
+ wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ *respDataLen = sizeof(*hdr2) + data->id_p_len;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ hdr2 = (struct eap_psk_hdr_2 *) resp;
+ hdr2->code = EAP_CODE_RESPONSE;
+ hdr2->identifier = hdr1->identifier;
+ hdr2->length = host_to_be16(*respDataLen);
+ hdr2->type = EAP_TYPE_PSK;
+#ifndef EAP_PSK_DRAFT3
+ hdr2->flags = 1; /* T=1 */
+ memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
+#endif /* EAP_PSK_DRAFT3 */
+ memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
+ memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len);
+ /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
+ buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ free(resp);
+ return NULL;
+ }
+ memcpy(buf, data->id_p, data->id_p_len);
+ pos = buf + data->id_p_len;
+ memcpy(pos, data->id_s, data->id_s_len);
+ pos += data->id_s_len;
+ memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
+ pos += EAP_PSK_RAND_LEN;
+ memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
+ omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p);
+ free(buf);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
+ EAP_PSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
+ (u8 *) (hdr2 + 1), data->id_p_len);
+
+ data->state = PSK_MAC_SENT;
+
+ return resp;
+}
+
+
+static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_psk_hdr_3 *hdr3;
+ struct eap_psk_hdr_4 *hdr4;
+ u8 *resp, *buf, *pchannel, *tag, *msg, nonce[16];
+ u8 mac[EAP_PSK_MAC_LEN];
+ size_t buflen, left;
+ int failed = 0;
+
+ wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
+
+ hdr3 = (struct eap_psk_hdr_3 *) reqData;
+ left = be_to_host16(hdr3->length);
+ if (left < sizeof(*hdr3) || reqDataLen < left) {
+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
+ "length (%lu %d; expected %lu)",
+ (unsigned long) reqDataLen,
+ be_to_host16(hdr3->length),
+ (unsigned long) sizeof(*hdr3));
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ left -= sizeof(*hdr3);
+ pchannel = (u8 *) (hdr3 + 1);
+#ifndef EAP_PSK_DRAFT3
+ wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
+ if ((hdr3->flags & 0x03) != 2) {
+ wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
+ hdr3->flags & 0x03);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
+ EAP_PSK_RAND_LEN);
+ /* TODO: would not need to store RAND_S since it is available in this
+ * message. For now, since we store this anyway, verify that it matches
+ * with whatever the server is sending. */
+ if (memcmp(hdr3->rand_s, data->rand_s, EAP_PSK_RAND_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "EAP-PSK: RAND_S did not match");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+#endif /* EAP_PSK_DRAFT3 */
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
+
+ if (left < 4 + 16 + 1) {
+ wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
+ "third message (len=%lu, expected 21)",
+ (unsigned long) left);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
+ buflen = data->id_s_len + EAP_PSK_RAND_LEN;
+ buf = malloc(buflen);
+ if (buf == NULL)
+ return NULL;
+ memcpy(buf, data->id_s, data->id_s_len);
+ memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+ omac1_aes_128(data->ak, buf, buflen, mac);
+ free(buf);
+ if (memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
+ wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
+ "message");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
+
+ eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
+ data->key_data);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->key_data,
+ EAP_PSK_MSK_LEN);
+
+ memset(nonce, 0, 12);
+ memcpy(nonce + 12, pchannel, 4);
+ pchannel += 4;
+ left -= 4;
+
+ tag = pchannel;
+ pchannel += 16;
+ left -= 16;
+
+ msg = pchannel;
+
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
+ nonce, sizeof(nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", reqData, 5);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
+
+#ifdef EAP_PSK_DRAFT3
+ if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
+ reqData, 5, msg, left, tag))
+#else /* EAP_PSK_DRAFT3 */
+ if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
+ reqData, 22, msg, left, tag))
+#endif /* EAP_PSK_DRAFT3 */
+ {
+ wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
+ msg, left);
+
+ /* Verify R flag */
+ switch (msg[0] >> 6) {
+ case EAP_PSK_R_FLAG_CONT:
+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
+ return NULL;
+ case EAP_PSK_R_FLAG_DONE_SUCCESS:
+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
+ break;
+ case EAP_PSK_R_FLAG_DONE_FAILURE:
+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
+ wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
+ "authentication");
+ failed = 1;
+ break;
+ }
+
+ *respDataLen = sizeof(*hdr4) + 4 + 16 + 1;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ hdr4 = (struct eap_psk_hdr_4 *) resp;
+ hdr4->code = EAP_CODE_RESPONSE;
+ hdr4->identifier = hdr3->identifier;
+ hdr4->length = host_to_be16(*respDataLen);
+ hdr4->type = EAP_TYPE_PSK;
+#ifndef EAP_PSK_DRAFT3
+ hdr4->flags = 3; /* T=3 */
+ memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
+#endif /* EAP_PSK_DRAFT3 */
+ pchannel = (u8 *) (hdr4 + 1);
+
+ /* nonce++ */
+ inc_byte_array(nonce, sizeof(nonce));
+ memcpy(pchannel, nonce + 12, 4);
+
+ pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
+
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
+ pchannel + 4 + 16, 1);
+#ifdef EAP_PSK_DRAFT3
+ aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 5,
+ pchannel + 4 + 16, 1, pchannel + 4);
+#else /* EAP_PSK_DRAFT3 */
+ aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 22,
+ pchannel + 4 + 16, 1, pchannel + 4);
+#endif /* EAP_PSK_DRAFT3 */
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
+ pchannel, 4 + 16 + 1);
+
+ wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
+ failed ? "un" : "");
+ data->state = PSK_DONE;
+ ret->methodState = METHOD_DONE;
+ ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
+
+ return resp;
+}
+
+
+static u8 * eap_psk_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_psk_data *data = priv;
+ struct eap_hdr *req;
+ u8 *pos, *resp = NULL;
+ size_t len;
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_PSK ||
+ (len = be_to_host16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ switch (data->state) {
+ case PSK_INIT:
+ resp = eap_psk_process_1(sm, data, ret, reqData, len,
+ respDataLen);
+ break;
+ case PSK_MAC_SENT:
+ resp = eap_psk_process_3(sm, data, ret, reqData, len,
+ respDataLen);
+ break;
+ case PSK_DONE:
+ wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
+ "unexpected message");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (ret->methodState == METHOD_DONE) {
+ ret->allowNotifications = FALSE;
+ }
+
+ return resp;
+}
+
+
+static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_psk_data *data = priv;
+ return data->state == PSK_DONE;
+}
+
+
+static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_psk_data *data = priv;
+ u8 *key;
+
+ if (data->state != PSK_DONE)
+ return NULL;
+
+ key = malloc(EAP_PSK_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_PSK_MSK_LEN;
+ memcpy(key, data->key_data, EAP_PSK_MSK_LEN);
+
+ return key;
+}
+
+
+const struct eap_method eap_method_psk =
+{
+ .method = EAP_TYPE_PSK,
+ .name = "PSK",
+ .init = eap_psk_init,
+ .deinit = eap_psk_deinit,
+ .process = eap_psk_process,
+ .isKeyAvailable = eap_psk_isKeyAvailable,
+ .getKey = eap_psk_getKey,
+};
diff --git a/contrib/wpa_supplicant/eap_sim.c b/contrib/wpa_supplicant/eap_sim.c
new file mode 100644
index 000000000000..f7ce191a6dda
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_sim.c
@@ -0,0 +1,1004 @@
+/*
+ * WPA Supplicant / EAP-SIM (draft-haverinen-pppext-eap-sim-13.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "sha1.h"
+#include "pcsc_funcs.h"
+#include "eap_sim_common.h"
+
+#define EAP_SIM_VERSION 1
+
+/* EAP-SIM Subtypes */
+#define EAP_SIM_SUBTYPE_START 10
+#define EAP_SIM_SUBTYPE_CHALLENGE 11
+#define EAP_SIM_SUBTYPE_NOTIFICATION 12
+#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
+#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
+#define EAP_SIM_UNSUPPORTED_VERSION 1
+#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
+#define EAP_SIM_RAND_NOT_FRESH 3
+
+#define KC_LEN 8
+#define SRES_LEN 4
+#define EAP_SIM_MAX_FAST_REAUTHS 1000
+
+struct eap_sim_data {
+ u8 *ver_list;
+ size_t ver_list_len;
+ int selected_version;
+ int min_num_chal, num_chal;
+
+ u8 kc[3][KC_LEN];
+ u8 sres[3][SRES_LEN];
+ u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
+ u8 mk[EAP_SIM_MK_LEN];
+ u8 k_aut[EAP_SIM_K_AUT_LEN];
+ u8 k_encr[EAP_SIM_K_ENCR_LEN];
+ u8 msk[EAP_SIM_KEYING_DATA_LEN];
+ u8 rand[3][GSM_RAND_LEN];
+
+ int num_id_req, num_notification;
+ u8 *pseudonym;
+ size_t pseudonym_len;
+ u8 *reauth_id;
+ size_t reauth_id_len;
+ int reauth;
+ unsigned int counter, counter_too_small;
+ u8 *last_eap_identity;
+ size_t last_eap_identity_len;
+ enum { CONTINUE, SUCCESS, FAILURE } state;
+};
+
+
+static void * eap_sim_init(struct eap_sm *sm)
+{
+ struct eap_sim_data *data;
+ struct wpa_ssid *config = eap_get_config(sm);
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+
+ if (hostapd_get_rand(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
+ "for NONCE_MT");
+ free(data);
+ return NULL;
+ }
+
+ data->min_num_chal = 2;
+ if (config && config->phase1) {
+ char *pos = strstr(config->phase1, "sim_min_num_chal=");
+ if (pos) {
+ data->min_num_chal = atoi(pos + 17);
+ if (data->min_num_chal < 2 || data->min_num_chal > 3) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
+ "sim_min_num_chal configuration "
+ "(%d, expected 2 or 3)",
+ data->min_num_chal);
+ free(data);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
+ "challenges to %d", data->min_num_chal);
+ }
+ }
+
+ data->state = CONTINUE;
+
+ return data;
+}
+
+
+static void eap_sim_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ if (data) {
+ free(data->ver_list);
+ free(data->pseudonym);
+ free(data->reauth_id);
+ free(data->last_eap_identity);
+ free(data);
+ }
+}
+
+
+static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
+#ifdef PCSC_FUNCS
+ if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
+ data->sres[0], data->kc[0]) ||
+ scard_gsm_auth(sm->scard_ctx, data->rand[1],
+ data->sres[1], data->kc[1]) ||
+ (data->num_chal > 2 &&
+ scard_gsm_auth(sm->scard_ctx, data->rand[2],
+ data->sres[2], data->kc[2]))) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM authentication could "
+ "not be completed");
+ return -1;
+ }
+#else /* PCSC_FUNCS */
+ /* These hardcoded Kc and SRES values are used for testing. RAND to
+ * KC/SREC mapping is very bogus as far as real authentication is
+ * concerned, but it is quite useful for cases where the AS is rotating
+ * the order of pre-configured values. */
+ {
+ int i;
+ for (i = 0; i < data->num_chal; i++) {
+ if (data->rand[i][0] == 0xaa) {
+ memcpy(data->kc[i],
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
+ KC_LEN);
+ memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
+ SRES_LEN);
+ } else if (data->rand[i][0] == 0xbb) {
+ memcpy(data->kc[i],
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
+ KC_LEN);
+ memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
+ SRES_LEN);
+ } else {
+ memcpy(data->kc[i],
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
+ KC_LEN);
+ memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
+ SRES_LEN);
+ }
+ }
+ }
+#endif /* PCSC_FUNCS */
+ return 0;
+}
+
+
+static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
+{
+ return version == EAP_SIM_VERSION;
+}
+
+
+static void eap_sim_derive_mk(struct eap_sim_data *data,
+ const u8 *identity, size_t identity_len)
+{
+ u8 sel_ver[2];
+ const unsigned char *addr[5];
+ size_t len[5];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = (u8 *) data->kc;
+ len[1] = data->num_chal * KC_LEN;
+ addr[2] = data->nonce_mt;
+ len[2] = EAP_SIM_NONCE_MT_LEN;
+ addr[3] = data->ver_list;
+ len[3] = data->ver_list_len;
+ addr[4] = sel_ver;
+ len[4] = 2;
+
+ sel_ver[0] = data->selected_version >> 8;
+ sel_ver[1] = data->selected_version & 0xff;
+
+ /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+ sha1_vector(5, addr, len, data->mk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", data->mk, EAP_SIM_MK_LEN);
+}
+
+
+#define CLEAR_PSEUDONYM 0x01
+#define CLEAR_REAUTH_ID 0x02
+#define CLEAR_EAP_ID 0x04
+
+static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
+ id & CLEAR_PSEUDONYM ? " pseudonym" : "",
+ id & CLEAR_REAUTH_ID ? " reauth_id" : "",
+ id & CLEAR_EAP_ID ? " eap_id" : "");
+ if (id & CLEAR_PSEUDONYM) {
+ free(data->pseudonym);
+ data->pseudonym = NULL;
+ data->pseudonym_len = 0;
+ }
+ if (id & CLEAR_REAUTH_ID) {
+ free(data->reauth_id);
+ data->reauth_id = NULL;
+ data->reauth_id_len = 0;
+ }
+ if (id & CLEAR_EAP_ID) {
+ free(data->last_eap_identity);
+ data->last_eap_identity = NULL;
+ data->last_eap_identity_len = 0;
+ }
+}
+
+
+static int eap_sim_learn_ids(struct eap_sim_data *data,
+ struct eap_sim_attrs *attr)
+{
+ if (attr->next_pseudonym) {
+ free(data->pseudonym);
+ data->pseudonym = malloc(attr->next_pseudonym_len);
+ if (data->pseudonym == NULL) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
+ "next pseudonym");
+ return -1;
+ }
+ memcpy(data->pseudonym, attr->next_pseudonym,
+ attr->next_pseudonym_len);
+ data->pseudonym_len = attr->next_pseudonym_len;
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
+ data->pseudonym,
+ data->pseudonym_len);
+ }
+
+ if (attr->next_reauth_id) {
+ free(data->reauth_id);
+ data->reauth_id = malloc(attr->next_reauth_id_len);
+ if (data->reauth_id == NULL) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
+ "next reauth_id");
+ return -1;
+ }
+ memcpy(data->reauth_id, attr->next_reauth_id,
+ attr->next_reauth_id_len);
+ data->reauth_id_len = attr->next_reauth_id_len;
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
+ data->reauth_id,
+ data->reauth_id_len);
+ }
+
+ return 0;
+}
+
+
+static u8 * eap_sim_client_error(struct eap_sm *sm, struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen, int err)
+{
+ struct eap_sim_msg *msg;
+
+ data->state = FAILURE;
+ data->num_id_req = 0;
+ data->num_notification = 0;
+
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CLIENT_ERROR);
+ eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
+ return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_sim_response_start(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen,
+ enum eap_sim_id_req id_req)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ u8 *identity = NULL;
+ size_t identity_len = 0;
+ struct eap_sim_msg *msg;
+
+ data->reauth = 0;
+ if (id_req == ANY_ID && data->reauth_id) {
+ identity = data->reauth_id;
+ identity_len = data->reauth_id_len;
+ data->reauth = 1;
+ } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
+ data->pseudonym) {
+ identity = data->pseudonym;
+ identity_len = data->pseudonym_len;
+ eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
+ } else if (id_req != NO_ID_REQ && config && config->identity) {
+ identity = config->identity;
+ identity_len = config->identity_len;
+ eap_sim_clear_identities(data,
+ CLEAR_PSEUDONYM | CLEAR_REAUTH_ID);
+ }
+ if (id_req != NO_ID_REQ)
+ eap_sim_clear_identities(data, CLEAR_EAP_ID);
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
+ wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+ eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+ wpa_printf(MSG_DEBUG, " AT_SELECTED_VERSION %d",
+ data->selected_version);
+ eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
+ data->selected_version, NULL, 0);
+
+ if (identity) {
+ wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
+ identity, identity_len);
+ eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
+ identity, identity_len);
+ }
+
+ return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_sim_response_challenge(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE);
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, respDataLen, data->k_aut,
+ (u8 *) data->sres,
+ data->num_chal * SRES_LEN);
+}
+
+
+static u8 * eap_sim_response_reauth(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen, int counter_too_small)
+{
+ struct eap_sim_msg *msg;
+ unsigned int counter;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_SIM,
+ EAP_SIM_SUBTYPE_REAUTHENTICATION);
+ wpa_printf(MSG_DEBUG, " AT_IV");
+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+ if (counter_too_small) {
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL");
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
+ counter = data->counter_too_small;
+ } else
+ counter = data->counter;
+
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter);
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+
+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
+ "AT_ENCR_DATA");
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, respDataLen, data->k_aut, data->nonce_s,
+ EAP_SIM_NONCE_S_LEN);
+}
+
+
+static u8 * eap_sim_response_notification(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t *respDataLen,
+ u16 notification)
+{
+ struct eap_sim_msg *msg;
+ u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
+
+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)",
+ req->identifier);
+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
+ EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
+ wpa_printf(MSG_DEBUG, " AT_NOTIFICATION");
+ eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, notification, NULL, 0);
+ if (k_aut && data->reauth) {
+ wpa_printf(MSG_DEBUG, " AT_IV");
+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
+ EAP_SIM_AT_ENCR_DATA);
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter);
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
+ NULL, 0);
+ if (eap_sim_msg_add_encr_end(msg, data->k_encr,
+ EAP_SIM_AT_PADDING)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
+ "AT_ENCR_DATA");
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+ }
+ if (k_aut) {
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ }
+ return eap_sim_msg_finish(msg, respDataLen, k_aut, (u8 *) "", 0);
+}
+
+
+static u8 * eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data,
+ struct eap_hdr *req, size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ int i, selected_version = -1, id_error;
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
+ if (attr->version_list == NULL) {
+ wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
+ "SIM/Start");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNSUPPORTED_VERSION);
+ }
+
+ free(data->ver_list);
+ data->ver_list = malloc(attr->version_list_len);
+ if (data->ver_list == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
+ "memory for version list");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+ memcpy(data->ver_list, attr->version_list, attr->version_list_len);
+ data->ver_list_len = attr->version_list_len;
+ pos = data->ver_list;
+ for (i = 0; i < data->ver_list_len / 2; i++) {
+ int ver = pos[0] * 256 + pos[1];
+ pos += 2;
+ if (eap_sim_supported_ver(data, ver)) {
+ selected_version = ver;
+ break;
+ }
+ }
+ if (selected_version < 0) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
+ "version");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNSUPPORTED_VERSION);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
+ selected_version);
+ data->selected_version = selected_version;
+
+ id_error = 0;
+ switch (attr->id_req) {
+ case NO_ID_REQ:
+ break;
+ case ANY_ID:
+ if (data->num_id_req > 0)
+ id_error++;
+ data->num_id_req++;
+ break;
+ case FULLAUTH_ID:
+ if (data->num_id_req > 1)
+ id_error++;
+ data->num_id_req++;
+ break;
+ case PERMANENT_ID:
+ if (data->num_id_req > 2)
+ id_error++;
+ data->num_id_req++;
+ break;
+ }
+ if (id_error) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
+ "used within one authentication");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ return eap_sim_response_start(sm, data, req, respDataLen,
+ attr->id_req);
+}
+
+
+static u8 * eap_sim_process_challenge(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ struct eap_hdr *req, size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ u8 *identity;
+ size_t identity_len;
+ struct eap_sim_attrs eattr;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
+ data->reauth = 0;
+ if (!attr->mac || !attr->rand) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
+ "did not include%s%s",
+ !attr->mac ? " AT_MAC" : "",
+ !attr->rand ? " AT_RAND" : "");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
+ (unsigned long) attr->num_chal);
+ if (attr->num_chal < data->min_num_chal) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
+ "challenges (%lu)", (unsigned long) attr->num_chal);
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
+ }
+ if (attr->num_chal > 3) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
+ "(%lu)", (unsigned long) attr->num_chal);
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ /* Verify that RANDs are different */
+ if (memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
+ GSM_RAND_LEN) == 0 ||
+ (attr->num_chal > 2 &&
+ (memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
+ GSM_RAND_LEN) == 0 ||
+ memcmp(attr->rand + GSM_RAND_LEN,
+ attr->rand + 2 * GSM_RAND_LEN,
+ GSM_RAND_LEN) == 0))) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_RAND_NOT_FRESH);
+ }
+
+ memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
+ data->num_chal = attr->num_chal;
+
+ if (eap_sim_gsm_auth(sm, data)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+ if (data->last_eap_identity) {
+ identity = data->last_eap_identity;
+ identity_len = data->last_eap_identity_len;
+ } else if (data->pseudonym) {
+ identity = data->pseudonym;
+ identity_len = data->pseudonym_len;
+ } else {
+ identity = config->identity;
+ identity_len = config->identity_len;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
+ "derivation", identity, identity_len);
+ eap_sim_derive_mk(data, identity, identity_len);
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
+ if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
+ "used invalid AT_MAC");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ /* Old reauthentication and pseudonym identities must not be used
+ * anymore. In other words, if no new identities are received, full
+ * authentication will be used on next reauthentication. */
+ eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
+ CLEAR_EAP_ID);
+
+ if (attr->encr_data) {
+ if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0)) {
+ return eap_sim_client_error(
+ sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+ eap_sim_learn_ids(data, &eattr);
+ }
+
+ if (data->state != FAILURE)
+ data->state = SUCCESS;
+
+ data->num_id_req = 0;
+ data->num_notification = 0;
+ /* draft-haverinen-pppext-eap-sim-13.txt specifies that counter
+ * is initialized to one after fullauth, but initializing it to
+ * zero makes it easier to implement reauth verification. */
+ data->counter = 0;
+ return eap_sim_response_challenge(sm, data, req, respDataLen);
+}
+
+
+static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct eap_sim_attrs eattr;
+
+ if (attr->encr_data == NULL || attr->iv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
+ "reauth did not include encrypted data");
+ return -1;
+ }
+
+ if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr, 0)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
+ "data from notification message");
+ return -1;
+ }
+
+ if (eattr.counter != data->counter) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
+ "message does not match with counter in reauth "
+ "message");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_sim_process_notification_auth(struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ struct eap_sim_attrs *attr)
+{
+ if (attr->mac == NULL) {
+ wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
+ "Notification message");
+ return -1;
+ }
+
+ if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
+ (u8 *) "", 0)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
+ "used invalid AT_MAC");
+ return -1;
+ }
+
+ if (data->reauth &&
+ eap_sim_process_notification_reauth(data, req, reqDataLen, attr)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
+ "message after reauth");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static u8 * eap_sim_process_notification(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
+ if (data->num_notification > 0) {
+ wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
+ "rounds (only one allowed)");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+ data->num_notification++;
+ if (attr->notification == -1) {
+ wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
+ "Notification message");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if ((attr->notification & 0x4000) == 0 &&
+ eap_sim_process_notification_auth(data, req, reqDataLen, attr)) {
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
+ if (attr->notification >= 0 && attr->notification < 32768) {
+ data->state = FAILURE;
+ }
+ return eap_sim_response_notification(sm, data, req, respDataLen,
+ attr->notification);
+}
+
+
+static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ struct eap_hdr *req,
+ size_t reqDataLen,
+ size_t *respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct eap_sim_attrs eattr;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
+
+ if (data->reauth_id == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
+ "reauthentication, but no reauth_id available");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ data->reauth = 1;
+ if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen,
+ attr->mac, (u8 *) "", 0)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
+ "did not have valid AT_MAC");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (attr->encr_data == NULL || attr->iv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
+ "message did not include encrypted data");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr, 0)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
+ "data from reauthentication message");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (eattr.nonce_s == NULL || eattr.counter < 0) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
+ !eattr.nonce_s ? " AT_NONCE_S" : "",
+ eattr.counter < 0 ? " AT_COUNTER" : "");
+ return eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+
+ if (eattr.counter <= data->counter) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
+ "(%d <= %d)", eattr.counter, data->counter);
+ data->counter_too_small = eattr.counter;
+ /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
+ * reauth_id must not be used to start a new reauthentication.
+ * However, since it was used in the last EAP-Response-Identity
+ * packet, it has to saved for the following fullauth to be
+ * used in MK derivation. */
+ free(data->last_eap_identity);
+ data->last_eap_identity = data->reauth_id;
+ data->last_eap_identity_len = data->reauth_id_len;
+ data->reauth_id = NULL;
+ data->reauth_id_len = 0;
+ return eap_sim_response_reauth(sm, data, req, respDataLen, 1);
+ }
+ data->counter = eattr.counter;
+
+ memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
+ data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+ eap_sim_derive_keys_reauth(data->counter,
+ data->reauth_id, data->reauth_id_len,
+ data->nonce_s, data->mk, data->msk);
+ eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_sim_learn_ids(data, &eattr);
+
+ if (data->state != FAILURE)
+ data->state = SUCCESS;
+
+ data->num_id_req = 0;
+ data->num_notification = 0;
+ if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
+ "fast reauths performed - force fullauth");
+ eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ }
+ return eap_sim_response_reauth(sm, data, req, respDataLen, 0);
+}
+
+
+static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_sim_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *req;
+ u8 *pos, subtype, *res;
+ struct eap_sim_attrs attr;
+ size_t len;
+
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: EAP data", reqData, reqDataLen);
+ if (config == NULL || config->identity == NULL) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
+ eap_sm_request_identity(sm, config);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_SIM ||
+ (len = be_to_host16(req->length)) > reqDataLen) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ pos++;
+ subtype = *pos++;
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
+ pos += 2; /* Reserved */
+
+ if (eap_sim_parse_attr(pos, reqData + len, &attr, 0, 0)) {
+ res = eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ goto done;
+ }
+
+ switch (subtype) {
+ case EAP_SIM_SUBTYPE_START:
+ res = eap_sim_process_start(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_SIM_SUBTYPE_CHALLENGE:
+ res = eap_sim_process_challenge(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_SIM_SUBTYPE_NOTIFICATION:
+ res = eap_sim_process_notification(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_SIM_SUBTYPE_REAUTHENTICATION:
+ res = eap_sim_process_reauthentication(sm, data, req, len,
+ respDataLen, &attr);
+ break;
+ case EAP_SIM_SUBTYPE_CLIENT_ERROR:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
+ res = eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
+ res = eap_sim_client_error(sm, data, req, respDataLen,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ break;
+ }
+
+done:
+ if (data->state == FAILURE) {
+ ret->decision = DECISION_FAIL;
+ ret->methodState = METHOD_DONE;
+ } else if (data->state == SUCCESS) {
+ ret->decision = DECISION_UNCOND_SUCC;
+ ret->methodState = METHOD_DONE;
+ }
+
+ if (ret->methodState == METHOD_DONE) {
+ ret->allowNotifications = FALSE;
+ }
+
+ return res;
+}
+
+
+static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ return data->pseudonym || data->reauth_id;
+}
+
+
+static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ eap_sim_clear_identities(data, CLEAR_EAP_ID);
+}
+
+
+static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ if (hostapd_get_rand(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
+ "for NONCE_MT");
+ free(data);
+ return NULL;
+ }
+ data->num_id_req = 0;
+ data->num_notification = 0;
+ data->state = CONTINUE;
+ return priv;
+}
+
+
+static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
+ size_t *len)
+{
+ struct eap_sim_data *data = priv;
+
+ if (data->reauth_id) {
+ *len = data->reauth_id_len;
+ return data->reauth_id;
+ }
+
+ if (data->pseudonym) {
+ *len = data->pseudonym_len;
+ return data->pseudonym;
+ }
+
+ return NULL;
+}
+
+
+static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_SIM_KEYING_DATA_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_SIM_KEYING_DATA_LEN;
+ memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+
+ return key;
+}
+
+
+const struct eap_method eap_method_sim =
+{
+ .method = EAP_TYPE_SIM,
+ .name = "SIM",
+ .init = eap_sim_init,
+ .deinit = eap_sim_deinit,
+ .process = eap_sim_process,
+ .isKeyAvailable = eap_sim_isKeyAvailable,
+ .getKey = eap_sim_getKey,
+ .has_reauth_data = eap_sim_has_reauth_data,
+ .deinit_for_reauth = eap_sim_deinit_for_reauth,
+ .init_for_reauth = eap_sim_init_for_reauth,
+ .get_identity = eap_sim_get_identity,
+};
diff --git a/contrib/wpa_supplicant/eap_sim_common.c b/contrib/wpa_supplicant/eap_sim_common.c
new file mode 100644
index 000000000000..98f4fb7d3014
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_sim_common.c
@@ -0,0 +1,788 @@
+/*
+ * WPA Supplicant / EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "sha1.h"
+#include "aes_wrap.h"
+#include "eap_sim_common.h"
+
+
+#define MSK_LEN 8
+#define EMSK_LEN 8
+
+
+static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
+{
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ /* FIPS 186-2 + change notice 1 */
+
+ memcpy(xkey, key, EAP_SIM_MK_LEN);
+ memset(xkey + EAP_SIM_MK_LEN, 0, 64 - EAP_SIM_MK_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) */
+ 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]);
+ 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 */
+ }
+}
+
+
+void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
+{
+ u8 buf[120], *pos;
+ eap_sim_prf(mk, buf, 120);
+ pos = buf;
+ memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+ pos += EAP_SIM_K_ENCR_LEN;
+ memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
+ pos += EAP_SIM_K_AUT_LEN;
+ memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+ pos += MSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
+ k_encr, EAP_SIM_K_ENCR_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
+ k_aut, EAP_SIM_K_ENCR_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MSK",
+ msk, MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Ext. MSK",
+ msk + MSK_LEN, EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
+ msk, EAP_SIM_KEYING_DATA_LEN);
+}
+
+
+void eap_sim_derive_keys_reauth(unsigned int _counter,
+ const u8 *identity, size_t identity_len,
+ const u8 *nonce_s, const u8 *mk, u8 *msk)
+{
+ u8 xkey[SHA1_MAC_LEN];
+ u8 counter[2];
+ const u8 *addr[4];
+ size_t len[4];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = counter;
+ len[1] = 2;
+ addr[2] = nonce_s;
+ len[2] = EAP_SIM_NONCE_S_LEN;
+ addr[3] = mk;
+ len[3] = EAP_SIM_MK_LEN;
+
+ counter[0] = _counter >> 8;
+ counter[1] = _counter & 0xff;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
+ identity, identity_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
+ EAP_SIM_NONCE_S_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
+
+ /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
+ sha1_vector(4, addr, len, xkey);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
+
+ eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: MSK", msk, MSK_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Ext. MSK", msk + MSK_LEN, EMSK_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
+ msk, EAP_SIM_KEYING_DATA_LEN);
+}
+
+
+int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
+ u8 *extra, size_t extra_len)
+{
+ unsigned char hmac[SHA1_MAC_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+ u8 rx_mac[EAP_SIM_MAC_LEN];
+
+ if (mac == NULL)
+ return -1;
+
+ addr[0] = req;
+ len[0] = req_len;
+ addr[1] = extra;
+ len[1] = extra_len;
+
+ /* HMAC-SHA1-128 */
+ memcpy(rx_mac, mac, EAP_SIM_MAC_LEN);
+ memset(mac, 0, EAP_SIM_MAC_LEN);
+ hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
+ memcpy(mac, rx_mac, EAP_SIM_MAC_LEN);
+
+ return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+}
+
+
+void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
+ const u8 *extra, size_t extra_len)
+{
+ unsigned char hmac[SHA1_MAC_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = msg;
+ len[0] = msg_len;
+ addr[1] = extra;
+ len[1] = extra_len;
+
+ /* HMAC-SHA1-128 */
+ memset(mac, 0, EAP_SIM_MAC_LEN);
+ hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
+ memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+}
+
+
+int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr, int aka,
+ int encr)
+{
+ u8 *pos = start, *apos;
+ size_t alen, plen;
+ int list_len, i;
+
+ memset(attr, 0, sizeof(*attr));
+ attr->id_req = NO_ID_REQ;
+ attr->notification = -1;
+ attr->counter = -1;
+ attr->selected_version = -1;
+ attr->client_error_code = -1;
+
+ while (pos < end) {
+ if (pos + 2 > end) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
+ return -1;
+ }
+ wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
+ pos[0], pos[1] * 4);
+ if (pos + pos[1] * 4 > end) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
+ "(pos=%p len=%d end=%p)",
+ pos, pos[1] * 4, end);
+ return -1;
+ }
+ apos = pos + 2;
+ alen = pos[1] * 4 - 2;
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
+ apos, alen);
+
+ switch (pos[0]) {
+ case EAP_SIM_AT_RAND:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
+ apos += 2;
+ alen -= 2;
+ if ((!aka && (alen % GSM_RAND_LEN)) ||
+ (aka && alen != AKA_RAND_LEN)) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
+ " (len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->rand = apos;
+ attr->num_chal = alen / GSM_RAND_LEN;
+ break;
+ case EAP_SIM_AT_AUTN:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
+ if (!aka) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: "
+ "Unexpected AT_AUTN");
+ return -1;
+ }
+ apos += 2;
+ alen -= 2;
+ if (alen != AKA_AUTN_LEN) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
+ " (len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->autn = apos;
+ break;
+ case EAP_SIM_AT_PADDING:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_PADDING");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
+ for (i = 2; i < alen; i++) {
+ if (apos[i] != 0) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
+ "AT_PADDING used a non-zero"
+ " padding byte");
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
+ "(encr) padding bytes",
+ apos + 2, alen - 2);
+ return -1;
+ }
+ }
+ break;
+ case EAP_SIM_AT_NONCE_MT:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
+ if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_NONCE_MT length");
+ return -1;
+ }
+ attr->nonce_mt = apos + 2;
+ break;
+ case EAP_SIM_AT_PERMANENT_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
+ attr->id_req = PERMANENT_ID;
+ break;
+ case EAP_SIM_AT_MAC:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
+ if (alen != 2 + EAP_SIM_MAC_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
+ "length");
+ return -1;
+ }
+ attr->mac = apos + 2;
+ break;
+ case EAP_SIM_AT_NOTIFICATION:
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_NOTIFICATION length %lu",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->notification = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
+ attr->notification);
+ break;
+ case EAP_SIM_AT_ANY_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
+ attr->id_req = ANY_ID;
+ break;
+ case EAP_SIM_AT_IDENTITY:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
+ attr->identity = apos + 2;
+ attr->identity_len = alen - 2;
+ break;
+ case EAP_SIM_AT_VERSION_LIST:
+ if (aka) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: "
+ "Unexpected AT_VERSION_LIST");
+ return -1;
+ }
+ list_len = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
+ if (list_len < 2 || list_len > alen - 2) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
+ "AT_VERSION_LIST (list_len=%d "
+ "attr_len=%lu)", list_len,
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->version_list = apos + 2;
+ attr->version_list_len = list_len;
+ break;
+ case EAP_SIM_AT_SELECTED_VERSION:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_SELECTED_VERSION length %lu",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->selected_version = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
+ "%d", attr->selected_version);
+ break;
+ case EAP_SIM_AT_FULLAUTH_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
+ attr->id_req = FULLAUTH_ID;
+ break;
+ case EAP_SIM_AT_COUNTER:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_COUNTER");
+ return -1;
+ }
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+ "AT_COUNTER (alen=%lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->counter = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
+ attr->counter);
+ break;
+ case EAP_SIM_AT_NONCE_S:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_NONCE_S");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_NONCE_S");
+ if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+ "AT_NONCE_S (alen=%lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->nonce_s = apos + 2;
+ break;
+ case EAP_SIM_AT_CLIENT_ERROR_CODE:
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_CLIENT_ERROR_CODE length %lu",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->client_error_code = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
+ "%d", attr->client_error_code);
+ break;
+ case EAP_SIM_AT_IV:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
+ if (alen != 2 + EAP_SIM_MAC_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
+ "length %lu", (unsigned long) alen);
+ return -1;
+ }
+ attr->iv = apos + 2;
+ break;
+ case EAP_SIM_AT_ENCR_DATA:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
+ attr->encr_data = apos + 2;
+ attr->encr_data_len = alen - 2;
+ if (attr->encr_data_len % 16) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_ENCR_DATA length %lu",
+ (unsigned long)
+ attr->encr_data_len);
+ return -1;
+ }
+ break;
+ case EAP_SIM_AT_NEXT_PSEUDONYM:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_NEXT_PSEUDONYM");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_NEXT_PSEUDONYM");
+ plen = apos[0] * 256 + apos[1];
+ if (plen > alen - 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
+ " AT_NEXT_PSEUDONYM (actual"
+ " len %lu, attr len %lu)",
+ (unsigned long) plen,
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->next_pseudonym = pos + 4;
+ attr->next_pseudonym_len = plen;
+ break;
+ case EAP_SIM_AT_NEXT_REAUTH_ID:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_NEXT_REAUTH_ID");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_NEXT_REAUTH_ID");
+ plen = apos[0] * 256 + apos[1];
+ if (plen > alen - 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
+ " AT_NEXT_REAUTH_ID (actual"
+ " len %lu, attr len %lu)",
+ (unsigned long) plen,
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->next_reauth_id = pos + 4;
+ attr->next_reauth_id_len = plen;
+ break;
+ default:
+ if (pos[0] < 128) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
+ "non-skippable attribute %d",
+ pos[0]);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
+ " attribute %d ignored", pos[0]);
+ break;
+ }
+
+ pos += pos[1] * 4;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
+ "(aka=%d encr=%d)", aka, encr);
+
+ return 0;
+}
+
+
+int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
+ const u8 *iv, struct eap_sim_attrs *attr, int aka)
+{
+ if (!iv) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
+ return -1;
+ }
+ aes_128_cbc_decrypt(k_encr, iv, encr_data, encr_data_len);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
+ encr_data, encr_data_len);
+
+ if (eap_sim_parse_attr(encr_data, encr_data + encr_data_len, attr,
+ aka, 1)) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
+ "decrypted AT_ENCR_DATA");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#define EAP_SIM_INIT_LEN 128
+
+struct eap_sim_msg {
+ u8 *buf;
+ size_t buf_len, used;
+ size_t mac, iv, encr; /* index from buf */
+};
+
+
+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
+{
+ struct eap_sim_msg *msg;
+ struct eap_hdr *eap;
+ u8 *pos;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+ memset(msg, 0, sizeof(*msg));
+
+ msg->buf = malloc(EAP_SIM_INIT_LEN);
+ if (msg->buf == NULL) {
+ free(msg);
+ return NULL;
+ }
+ memset(msg->buf, 0, EAP_SIM_INIT_LEN);
+ msg->buf_len = EAP_SIM_INIT_LEN;
+ eap = (struct eap_hdr *) msg->buf;
+ eap->code = code;
+ eap->identifier = id;
+ msg->used = sizeof(*eap);
+
+ pos = (u8 *) (eap + 1);
+ *pos++ = type;
+ *pos++ = subtype;
+ *pos++ = 0; /* Reserved */
+ *pos++ = 0; /* Reserved */
+ msg->used += 4;
+
+ return msg;
+}
+
+
+u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
+ const u8 *extra, size_t extra_len)
+{
+ struct eap_hdr *eap;
+ u8 *buf;
+
+ if (msg == NULL)
+ return NULL;
+
+ eap = (struct eap_hdr *) msg->buf;
+ eap->length = host_to_be16(msg->used);
+
+ if (k_aut && msg->mac) {
+ eap_sim_add_mac(k_aut, msg->buf, msg->used,
+ msg->buf + msg->mac, extra, extra_len);
+ }
+
+ *len = msg->used;
+ buf = msg->buf;
+ free(msg);
+ return buf;
+}
+
+
+void eap_sim_msg_free(struct eap_sim_msg *msg)
+{
+ if (msg) {
+ free(msg->buf);
+ free(msg);
+ }
+}
+
+
+static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
+{
+ if (msg->used + add_len > msg->buf_len) {
+ u8 *nbuf = realloc(msg->buf, msg->used + add_len);
+ if (nbuf == NULL)
+ return -1;
+ msg->buf = nbuf;
+ msg->buf_len = msg->used + add_len;
+ }
+ return 0;
+}
+
+
+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
+ const u8 *data, size_t len)
+{
+ int attr_len = 2 + len;
+ int pad_len;
+ u8 *start, *pos;
+
+ if (msg == NULL)
+ return NULL;
+
+ pad_len = (4 - attr_len % 4) % 4;
+ attr_len += pad_len;
+ if (eap_sim_msg_resize(msg, attr_len))
+ return NULL;
+ start = pos = msg->buf + msg->used;
+ *pos++ = attr;
+ *pos++ = attr_len / 4;
+ memcpy(pos, data, len);
+ if (pad_len) {
+ pos += len;
+ memset(pos, 0, pad_len);
+ }
+ msg->used += attr_len;
+ return start;
+}
+
+
+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
+ const u8 *data, size_t len)
+{
+ int attr_len = 4 + len;
+ int pad_len;
+ u8 *start, *pos;
+
+ if (msg == NULL)
+ return NULL;
+
+ pad_len = (4 - attr_len % 4) % 4;
+ attr_len += pad_len;
+ if (eap_sim_msg_resize(msg, attr_len))
+ return NULL;
+ start = pos = msg->buf + msg->used;
+ *pos++ = attr;
+ *pos++ = attr_len / 4;
+ *pos++ = value >> 8;
+ *pos++ = value & 0xff;
+ if (data)
+ memcpy(pos, data, len);
+ if (pad_len) {
+ pos += len;
+ memset(pos, 0, pad_len);
+ }
+ msg->used += attr_len;
+ return start;
+}
+
+
+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
+{
+ u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
+ if (pos)
+ msg->mac = (pos - msg->buf) + 4;
+ return pos;
+}
+
+
+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
+ u8 attr_encr)
+{
+ u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
+ if (pos == NULL)
+ return -1;
+ msg->iv = (pos - msg->buf) + 4;
+ if (hostapd_get_rand(msg->buf + msg->iv, EAP_SIM_IV_LEN)) {
+ msg->iv = 0;
+ return -1;
+ }
+
+ pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
+ if (pos == NULL) {
+ msg->iv = 0;
+ return -1;
+ }
+ msg->encr = pos - msg->buf;
+
+ return 0;
+}
+
+
+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
+{
+ size_t encr_len;
+
+ if (k_encr == NULL || msg->iv == 0 || msg->encr == 0)
+ return -1;
+
+ encr_len = msg->used - msg->encr - 4;
+ if (encr_len % 16) {
+ u8 *pos;
+ int pad_len = 16 - (encr_len % 16);
+ if (pad_len < 4) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: "
+ "eap_sim_msg_add_encr_end - invalid pad_len"
+ " %d", pad_len);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, " *AT_PADDING");
+ pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
+ if (pos == NULL)
+ return -1;
+ memset(pos + 4, 0, pad_len - 4);
+ encr_len += pad_len;
+ }
+ wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)",
+ (unsigned long) encr_len);
+ msg->buf[msg->encr + 1] = encr_len / 4 + 1;
+ aes_128_cbc_encrypt(k_encr, msg->buf + msg->iv,
+ msg->buf + msg->encr + 4, encr_len);
+
+ return 0;
+}
+
+
+void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
+{
+ const char *type = aka ? "AKA" : "SIM";
+
+ switch (notification) {
+ case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
+ wpa_printf(MSG_WARNING, "EAP-%s: General failure "
+ "notification (after authentication)", type);
+ break;
+ case EAP_SIM_TEMPORARILY_DENIED:
+ wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
+ "User has been temporarily denied access to the "
+ "requested service", type);
+ break;
+ case EAP_SIM_NOT_SUBSCRIBED:
+ wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
+ "User has not subscribed to the requested service",
+ type);
+ break;
+ case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
+ wpa_printf(MSG_WARNING, "EAP-%s: General failure "
+ "notification (before authentication)", type);
+ break;
+ case EAP_SIM_SUCCESS:
+ wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
+ "notification", type);
+ break;
+ default:
+ if (notification >= 32768) {
+ wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
+ "non-failure notification %d",
+ type, notification);
+ } else {
+ wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
+ "failure notification %d",
+ type, notification);
+ }
+ }
+}
+
+
+#ifdef TEST_MAIN_EAP_SIM_COMMON
+static int test_eap_sim_prf(void)
+{
+ /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
+ u8 xkey[] = {
+ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+ 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+ 0xeb, 0x5a, 0x38, 0xb6
+ };
+ u8 w[] = {
+ 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+ 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+ 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+ 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+ 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+ };
+ u8 buf[40];
+
+ printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
+ eap_sim_prf(xkey, buf, sizeof(buf));
+ if (memcmp(w, buf, sizeof(w) != 0)) {
+ printf("eap_sim_prf failed\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int errors = 0;
+
+ errors += test_eap_sim_prf();
+
+ return errors;
+}
+#endif /* TEST_MAIN_EAP_SIM_COMMON */
diff --git a/contrib/wpa_supplicant/eap_sim_common.h b/contrib/wpa_supplicant/eap_sim_common.h
new file mode 100644
index 000000000000..c89e04e410b9
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_sim_common.h
@@ -0,0 +1,101 @@
+#ifndef EAP_SIM_COMMON_H
+#define EAP_SIM_COMMON_H
+
+#define EAP_SIM_NONCE_S_LEN 16
+#define EAP_SIM_NONCE_MT_LEN 16
+#define EAP_SIM_MAC_LEN 16
+#define EAP_SIM_MK_LEN 20
+#define EAP_SIM_K_AUT_LEN 16
+#define EAP_SIM_K_ENCR_LEN 16
+#define EAP_SIM_KEYING_DATA_LEN 64
+#define EAP_SIM_IV_LEN 16
+
+#define GSM_RAND_LEN 16
+
+#define AKA_RAND_LEN 16
+#define AKA_AUTN_LEN 16
+
+void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk);
+void eap_sim_derive_keys_reauth(unsigned int _counter,
+ const u8 *identity, size_t identity_len,
+ const u8 *nonce_s, const u8 *mk, u8 *msk);
+int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
+ u8 *extra, size_t extra_len);
+void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
+ const u8 *extra, size_t extra_len);
+
+
+/* EAP-SIM/AKA Attributes (0..127 non-skippable) */
+#define EAP_SIM_AT_RAND 1
+#define EAP_SIM_AT_AUTN 2 /* only AKA */
+#define EAP_SIM_AT_RES 3 /* only AKA, only send */
+#define EAP_SIM_AT_AUTS 4 /* only AKA, only send */
+#define EAP_SIM_AT_PADDING 6 /* only encrypted */
+#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */
+#define EAP_SIM_AT_PERMANENT_ID_REQ 10
+#define EAP_SIM_AT_MAC 11
+#define EAP_SIM_AT_NOTIFICATION 12
+#define EAP_SIM_AT_ANY_ID_REQ 13
+#define EAP_SIM_AT_IDENTITY 14 /* only send */
+#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */
+#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */
+#define EAP_SIM_AT_FULLAUTH_ID_REQ 17
+#define EAP_SIM_AT_COUNTER 19 /* only encrypted */
+#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */
+#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */
+#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */
+#define EAP_SIM_AT_IV 129
+#define EAP_SIM_AT_ENCR_DATA 130
+#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */
+#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */
+#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */
+#define EAP_SIM_AT_RESULT_IND 135
+
+/* AT_NOTIFICATION notification code values */
+#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0
+#define EAP_SIM_TEMPORARILY_DENIED 1026
+#define EAP_SIM_NOT_SUBSCRIBED 1031
+#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384
+#define EAP_SIM_SUCCESS 32768
+
+
+enum eap_sim_id_req {
+ NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID
+};
+
+
+struct eap_sim_attrs {
+ u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
+ u8 *next_pseudonym, *next_reauth_id;
+ u8 *nonce_mt, *identity;
+ size_t num_chal, version_list_len, encr_data_len;
+ size_t next_pseudonym_len, next_reauth_id_len, identity_len;
+ enum eap_sim_id_req id_req;
+ int notification, counter, selected_version, client_error_code;
+};
+
+int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr,
+ int aka, int encr);
+int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
+ const u8 *iv, struct eap_sim_attrs *attr, int aka);
+
+
+struct eap_sim_msg;
+
+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype);
+u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
+ const u8 *extra, size_t extra_len);
+void eap_sim_msg_free(struct eap_sim_msg *msg);
+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
+ const u8 *data, size_t len);
+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr,
+ u16 value, const u8 *data, size_t len);
+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr);
+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
+ u8 attr_encr);
+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr,
+ int attr_pad);
+
+void eap_sim_report_notification(void *msg_ctx, int notification, int aka);
+
+#endif /* EAP_SIM_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_testing.txt b/contrib/wpa_supplicant/eap_testing.txt
new file mode 100644
index 000000000000..03ef2858e425
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_testing.txt
@@ -0,0 +1,349 @@
+Automatic regression and interoperability testing of wpa_supplicant's
+IEEE 802.1X/EAPOL authentication
+
+Test program:
+- Linked some parts of IEEE 802.1X Authenticator implementation from
+ hostapd (RADIUS client and RADIUS processing, EAP<->RADIUS
+ encapsulation/decapsulation) into wpa_supplicant.
+- Replaced wpa_supplicant.c and wpa.c with test code that trigger
+ IEEE 802.1X authentication automatically without need for wireless
+ client card or AP.
+- For EAP methods that generate keying material, the key derived by the
+ Supplicant is verified to match with the one received by the (now
+ integrated) Authenticator.
+
+The full automated test suite can now be run in couple of seconds, but
+I'm more than willing to add new RADIUS authentication servers to make
+this take a bit more time.. ;-) As an extra bonus, this can also be
+seen as automatic regression/interoperability testing for the RADIUS
+server, too.
+
+In order for me to be able to use a new authentication server, the
+server need to be available from Internet (at least from one static IP
+address) and I will need to get suitable user name/password pairs,
+certificates, and private keys for testing use. Other alternative
+would be to get an evaluation version of the server so that I can
+install it on my own test setup. If you are interested in providing
+either server access or evaluation version, please contact me
+(jkmaline@cc.hut.fi).
+
+
+Test matrix
+
++) tested successfully
+F) failed
+-) server did not support
+?) not tested
+
+hostapd --------------------------------------------------------.
+Cisco Aironet 1200 AP (local RADIUS server) ----------------. |
+Corriente Elektron -------------------------------------. | |
+Lucent NavisRadiator -------------------------------. | | |
+Interlink RAD-Series ---------------------------. | | | |
+Radiator -----------------------------------. | | | | |
+Meetinghouse Aegis ---------------------. | | | | | |
+Funk Steel-Belted ------------------. | | | | | | |
+Funk Odyssey -------------------. | | | | | | | |
+Microsoft IAS --------------. | | | | | | | | |
+FreeRADIUS -------------. | | | | | | | | | |
+ | | | | | | | | | | |
+
+EAP-MD5 + - - + + + + + - - +
+EAP-GTC + - - ? + + + + - - +
+EAP-OTP - - - - - + - - - - -
+EAP-MSCHAPv2 + - - + + + + + - - +
+EAP-TLS + + + + + + + + - - +
+EAP-PEAPv0/MSCHAPv2 + + + + + + + + + - +
+EAP-PEAPv0/GTC + - + - + + + + - - +
+EAP-PEAPv0/OTP - - - - - + - - - - -
+EAP-PEAPv0/MD5 + - - + + + + + - - +
+EAP-PEAPv0/TLS - + - + + + F + - - -
+EAP-PEAPv1/MSCHAPv2 - - + + + +1 + +5 +8 - +
+EAP-PEAPv1/GTC - - + + + +1 + +5 - - +
+EAP-PEAPv1/OTP - - - - - +1 - - - - -
+EAP-PEAPv1/MD5 - - - + + +1 + +5 - - +
+EAP-PEAPv1/TLS - - - + + +1 F +5 - - -
+EAP-TTLS/CHAP + - +2 + + + + + + - +
+EAP-TTLS/MSCHAP + - + + + + + + + - +
+EAP-TTLS/MSCHAPv2 + - + + + + + + + - +
+EAP-TTLS/PAP + - + + + + + + + - +
+EAP-TTLS/EAP-MD5 + - +2 + + + + + - - +
+EAP-TTLS/EAP-GTC + - +2 ? + + + + - - +
+EAP-TTLS/EAP-OTP - - - - - + - - - - -
+EAP-TTLS/EAP-MSCHAPv2 + - +2 + + + + + + - +
+EAP-TTLS/EAP-TLS - - +2 + F + + + - - -
+EAP-SIM +3 - - ? - + - ? - - +
+EAP-AKA - - - - - + - - - - -
+EAP-PSK +7 - - - - - - - - - -
+EAP-FAST - - - - - - - - - + -
+LEAP + - + + + + F +6 - + -
+
+1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP
+ encryption", during key derivation (requires phase1="peaplabel=1" in the
+ network configuration in wpa_supplicant.conf)
+2) used FreeRADIUS as inner auth server
+3) required a patch to FreeRADIUS to fix EAP-SIM
+5) PEAPv1 required termination of negotiation on tunneled EAP-Success and new
+ label in key deriviation
+ (phase1="peap_outer_success=0 peaplabel=1") (in "IETF Draft 5" mode)
+6) Authenticator simulator required patching for handling Access-Accept within
+ negotiation (for the first EAP-Success of LEAP)
+7) EAP-PSK is not included in FreeRADIUS distribution; used external
+ rlm_eap_psk implementation from
+ http://perso.rd.francetelecom.fr/bersani/EAP_PSK/
+ EAP-PSKWindowsimplementations.html
+8) PEAPv1 used non-standard version negotiation (client had to force v1 even
+ though server reported v0 as the highest supported version)
+
+
+Automated tests:
+
+FreeRADIUS (1.0pre and CVS snapshot)
+- EAP-MD5-Challenge
+- EAP-GTC
+- EAP-MSCHAPv2
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / GTC
+- EAP-PEAPv0 / MD5-Challenge
+- EAP-TTLS / EAP-MD5-Challenge
+- EAP-TTLS / EAP-GTC
+- EAP-TTLS / EAP-MSCHAPv2
+- EAP-TTLS / CHAP
+- EAP-TTLS / PAP
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-SIM
+* not supported in FreeRADIUS
+ - EAP-PEAP / TLS (Unable to tunnel TLS inside of TLS)
+ - EAP-TTLS / EAP-TLS (Unable to tunnel TLS inside of TLS)
+
+Microsoft Windows Server 2003 / IAS
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / TLS
+- EAP-MD5
+* IAS does not seem to support other EAP methods
+
+Funk Odyssey 2.01.00.653
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / GTC
+- EAP-PEAPv1 / MSCHAPv2
+- EAP-PEAPv1 / GTC
+ Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption"
+- EAP-TTLS / CHAP (using FreeRADIUS as inner auth srv)
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-TTLS / PAP
+- EAP-TTLS / EAP-MD5-Challenge (using FreeRADIUS as inner auth srv)
+- EAP-TTLS / EAP-GTC (using FreeRADIUS as inner auth srv)
+- EAP-TTLS / EAP-MSCHAPv2 (using FreeRADIUS as inner auth srv)
+- EAP-TTLS / EAP-TLS (using FreeRADIUS as inner auth srv)
+* not supported in Odyssey:
+ - EAP-MD5-Challenge
+ - EAP-GTC
+ - EAP-MSCHAPv2
+ - EAP-PEAP / MD5-Challenge
+ - EAP-PEAP / TLS
+
+Funk Steel-Belted Radius Enterprise Edition v4.71.739
+- EAP-MD5-Challenge
+- EAP-MSCHAPv2
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / MD5
+- EAP-PEAPv0 / TLS
+- EAP-PEAPv1 / MSCHAPv2
+- EAP-PEAPv1 / MD5
+- EAP-PEAPv1 / GTC
+- EAP-PEAPv1 / TLS
+ Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption"
+- EAP-TTLS / CHAP
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-TTLS / PAP
+- EAP-TTLS / EAP-MD5-Challenge
+- EAP-TTLS / EAP-MSCHAPv2
+- EAP-TTLS / EAP-TLS
+
+Meetinghouse Aegis 1.1.4
+- EAP-MD5-Challenge
+- EAP-GTC
+- EAP-MSCHAPv2
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / TLS
+- EAP-PEAPv0 / GTC
+- EAP-PEAPv0 / MD5-Challenge
+- EAP-PEAPv1 / MSCHAPv2
+- EAP-PEAPv1 / TLS
+- EAP-PEAPv1 / GTC
+- EAP-PEAPv1 / MD5-Challenge
+ Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption"
+- EAP-TTLS / CHAP
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-TTLS / PAP
+- EAP-TTLS / EAP-MD5-Challenge
+- EAP-TTLS / EAP-GTC
+- EAP-TTLS / EAP-MSCHAPv2
+* did not work
+ - EAP-TTLS / EAP-TLS
+ (Server rejects authentication without any reason in debug log. It
+ looks like the inner TLS negotiation starts properly and the last
+ packet from Supplicant looks like the one sent in the Phase 1. The
+ server generates a valid looking reply in the same way as in Phase
+ 1, but then ends up sending Access-Reject. Maybe an issue with TTLS
+ fragmentation in the Aegis server(?) The packet seems to include
+ 1328 bytes of EAP-Message and this may go beyond the fragmentation
+ limit with AVP encapsulation and TLS tunneling. Note: EAP-PEAP/TLS
+ did work, so this issue seems to be with something TTLS specific.)
+
+Radiator 3.9 (eval, with all patches up to and including 2004-08-30)
+- EAP-MD5-Challenge
+- EAP-GTC
+- EAP-OTP
+- EAP-MSCHAPv2
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / GTC
+- EAP-PEAPv0 / OTP
+- EAP-PEAPv0 / MD5-Challenge
+- EAP-PEAPv0 / TLS
+ Note: Needed to use unknown identity in outer auth and some times the server
+ seems to get confused and fails to send proper Phase 2 data.
+- EAP-PEAPv1 / MSCHAPv2
+- EAP-PEAPv1 / GTC
+- EAP-PEAPv1 / OTP
+- EAP-PEAPv1 / MD5-Challenge
+- EAP-PEAPv1 / TLS
+ Note: This has some additional requirements for EAPTLS_MaxFragmentSize.
+ Using 1300 for outer auth and 500 for inner auth seemed to work.
+ Note: Needed to use unknown identity in outer auth and some times the server
+ seems to get confused and fails to send proper Phase 2 data.
+- EAP-TTLS / CHAP
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-TTLS / PAP
+- EAP-TTLS / EAP-MD5-Challenge
+- EAP-TTLS / EAP-GTC
+- EAP-TTLS / EAP-OTP
+- EAP-TTLS / EAP-MSCHAPv2
+- EAP-TTLS / EAP-TLS
+ Note: This has some additional requirements for EAPTLS_MaxFragmentSize.
+ Using 1300 for outer auth and 500 for inner auth seemed to work.
+- EAP-SIM
+- EAP-AKA
+
+Interlink Networks RAD-Series 6.1.2.7
+- EAP-MD5-Challenge
+- EAP-GTC
+- EAP-MSCHAPv2
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / GTC
+- EAP-PEAPv0 / MD5-Challenge
+- EAP-PEAPv1 / MSCHAPv2
+- EAP-PEAPv1 / GTC
+- EAP-PEAPv1 / MD5-Challenge
+ Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption"
+- EAP-TTLS / CHAP
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-TTLS / PAP
+- EAP-TTLS / EAP-MD5-Challenge
+- EAP-TTLS / EAP-GTC
+- EAP-TTLS / EAP-MSCHAPv2
+- EAP-TTLS / EAP-TLS
+* did not work
+ - EAP-PEAPv0 / TLS
+ - EAP-PEAPv1 / TLS
+ (Failed to decrypt Phase 2 data)
+
+Lucent NavisRadius 4.4.0
+- EAP-MD5-Challenge
+- EAP-GTC
+- EAP-MSCHAPv2
+- EAP-TLS
+- EAP-PEAPv0 / MD5-Challenge
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / GTC
+- EAP-PEAPv0 / TLS
+- EAP-PEAPv1 / MD5-Challenge
+- EAP-PEAPv1 / MSCHAPv2
+- EAP-PEAPv1 / GTC
+- EAP-PEAPv1 / TLS
+ "IETF Draft 5" mode requires phase1="peap_outer_success=0 peaplabel=1"
+ 'Cisco ACU 5.05' mode works without phase1 configuration
+- EAP-TTLS / CHAP
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-TTLS / PAP
+- EAP-TTLS / EAP-MD5-Challenge
+- EAP-TTLS / EAP-MSCHAPv2
+- EAP-TTLS / EAP-GTC
+- EAP-TTLS / EAP-TLS
+
+Note: user certificate from NavisRadius had private key in a format
+that wpa_supplicant could not use. Converting this to PKCS#12 and then
+back to PEM allowed wpa_supplicant to use the key.
+
+
+hostapd v0.3.3
+- EAP-MD5-Challenge
+- EAP-GTC
+- EAP-MSCHAPv2
+- EAP-TLS
+- EAP-PEAPv0 / MSCHAPv2
+- EAP-PEAPv0 / GTC
+- EAP-PEAPv0 / MD5-Challenge
+- EAP-PEAPv1 / MSCHAPv2
+- EAP-PEAPv1 / GTC
+- EAP-PEAPv1 / MD5-Challenge
+- EAP-TTLS / CHAP
+- EAP-TTLS / MSCHAP
+- EAP-TTLS / MSCHAPv2
+- EAP-TTLS / PAP
+- EAP-TTLS / EAP-MD5-Challenge
+- EAP-TTLS / EAP-GTC
+- EAP-TTLS / EAP-MSCHAPv2
+- EAP-SIM
+
+
+
+PEAPv1:
+
+Funk Odyssey 2.01.00.653:
+- uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE
+ keys with outer EAP-Success message after this
+- uses label "client EAP encryption"
+- (peap_outer_success 1 and 2 work)
+
+Funk Steel-Belted Radius Enterprise Edition v4.71.739
+- uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE
+ keys with outer EAP-Success message after this
+- uses label "client EAP encryption"
+- (peap_outer_success 1 and 2 work)
+
+Radiator 3.9:
+- uses TLV Success and Reply, sends MPPE keys with outer EAP-Success message
+ after this
+- uses label "client PEAP encryption"
+
+Lucent NavisRadius 4.4.0 (in "IETF Draft 5" mode):
+- sends tunneled EAP-Success with MPPE keys and expects the authentication to
+ terminate at this point (gets somewhat confused with reply to this)
+- uses label "client PEAP encryption"
+- phase1="peap_outer_success=0 peaplabel=1"
+
+Lucent NavisRadius 4.4.0 (in "Cisco ACU 5.05" mode):
+- sends tunneled EAP-Success with MPPE keys and expects to receive TLS ACK
+ as a reply
+- uses label "client EAP encryption"
+
+Meetinghouse Aegis 1.1.4
+- uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE
+ keys with outer EAP-Success message after this
+- uses label "client EAP encryption"
+- peap_outer_success 1 and 2 work
diff --git a/contrib/wpa_supplicant/eap_tls.c b/contrib/wpa_supplicant/eap_tls.c
new file mode 100644
index 000000000000..4b02cca14e1f
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_tls.c
@@ -0,0 +1,245 @@
+/*
+ * WPA Supplicant / EAP-TLS (RFC 2716)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "tls.h"
+
+
+static void eap_tls_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_tls_data {
+ struct eap_ssl_data ssl;
+ u8 *key_data;
+};
+
+
+static void * eap_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config == NULL ||
+ (sm->init_phase2 ? config->private_key2 : config->private_key)
+ == NULL) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
+ return NULL;
+ }
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+
+ if (eap_tls_ssl_init(sm, &data->ssl, config)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+ eap_tls_deinit(sm, data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+static void eap_tls_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_tls_data *data = priv;
+ if (data == NULL)
+ return;
+ eap_tls_ssl_deinit(sm, &data->ssl);
+ free(data->key_data);
+ free(data);
+}
+
+
+static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_hdr *req;
+ int left, res;
+ unsigned int tls_msg_len;
+ u8 flags, *pos, *resp, id;
+ struct eap_tls_data *data = priv;
+
+ if (tls_get_errors(sm->ssl_ctx)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: TLS errors detected");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (struct eap_hdr *) reqData;
+ pos = (u8 *) (req + 1);
+ if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_TLS) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ id = req->identifier;
+ pos++;
+ flags = *pos++;
+ left = be_to_host16(req->length) - sizeof(struct eap_hdr) - 2;
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
+ "Flags 0x%02x", (unsigned long) reqDataLen, flags);
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
+ "length");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
+ pos[3];
+ wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
+ tls_msg_len);
+ if (data->ssl.tls_in_left == 0) {
+ data->ssl.tls_in_total = tls_msg_len;
+ data->ssl.tls_in_left = tls_msg_len;
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ ret->ignore = FALSE;
+
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_COND_SUCC;
+ ret->allowNotifications = TRUE;
+
+ if (flags & EAP_TLS_FLAGS_START) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
+ left = 0; /* make sure that this frame is empty, even though it
+ * should always be, anyway */
+ }
+
+ resp = NULL;
+ res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id, pos,
+ left, &resp, respDataLen);
+
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+ return eap_tls_build_ack(&data->ssl, respDataLen, id,
+ EAP_TYPE_TLS, 0);
+ }
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ free(data->key_data);
+ data->key_data = eap_tls_derive_key(sm, &data->ssl,
+ "client EAP encryption",
+ EAP_TLS_KEY_LEN);
+ if (data->key_data) {
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
+ data->key_data, EAP_TLS_KEY_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
+ }
+ }
+
+ if (res == 1) {
+ return eap_tls_build_ack(&data->ssl, respDataLen, id,
+ EAP_TYPE_TLS, 0);
+ }
+ return resp;
+}
+
+
+static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+ struct eap_tls_data *data = priv;
+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+}
+
+
+static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_tls_data *data = priv;
+ free(data->key_data);
+ data->key_data = NULL;
+ if (eap_tls_reauth_init(sm, &data->ssl)) {
+ free(data);
+ return NULL;
+ }
+ return priv;
+}
+
+
+static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
+ size_t buflen, int verbose)
+{
+ struct eap_tls_data *data = priv;
+ return eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
+}
+
+
+static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_tls_data *data = priv;
+ return data->key_data != NULL;
+}
+
+
+static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_tls_data *data = priv;
+ u8 *key;
+
+ if (data->key_data == NULL)
+ return NULL;
+
+ key = malloc(EAP_TLS_KEY_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_TLS_KEY_LEN;
+ memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+ return key;
+}
+
+
+const struct eap_method eap_method_tls =
+{
+ .method = EAP_TYPE_TLS,
+ .name = "TLS",
+ .init = eap_tls_init,
+ .deinit = eap_tls_deinit,
+ .process = eap_tls_process,
+ .isKeyAvailable = eap_tls_isKeyAvailable,
+ .getKey = eap_tls_getKey,
+ .get_status = eap_tls_get_status,
+ .has_reauth_data = eap_tls_has_reauth_data,
+ .deinit_for_reauth = eap_tls_deinit_for_reauth,
+ .init_for_reauth = eap_tls_init_for_reauth,
+};
diff --git a/contrib/wpa_supplicant/eap_tls_common.c b/contrib/wpa_supplicant/eap_tls_common.c
new file mode 100644
index 000000000000..20b141846790
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_tls_common.c
@@ -0,0 +1,338 @@
+/*
+ * WPA Supplicant / EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "md5.h"
+#include "sha1.h"
+#include "tls.h"
+
+
+int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+ struct wpa_ssid *config)
+{
+ int ret = -1;
+ char *ca_cert, *client_cert, *private_key, *private_key_passwd,
+ *dh_file, *subject_match;
+
+ data->eap = sm;
+ data->phase2 = sm->init_phase2;
+ if (config == NULL) {
+ ca_cert = NULL;
+ client_cert = NULL;
+ private_key = NULL;
+ private_key_passwd = NULL;
+ dh_file = NULL;
+ subject_match = NULL;
+ } else if (data->phase2) {
+ ca_cert = (char *) config->ca_cert2;
+ client_cert = (char *) config->client_cert2;
+ private_key = (char *) config->private_key2;
+ private_key_passwd = (char *) config->private_key2_passwd;
+ dh_file = (char *) config->dh_file2;
+ subject_match = (char *) config->subject_match2;
+ } else {
+ ca_cert = (char *) config->ca_cert;
+ client_cert = (char *) config->client_cert;
+ private_key = (char *) config->private_key;
+ private_key_passwd = (char *) config->private_key_passwd;
+ dh_file = (char *) config->dh_file;
+ subject_match = (char *) config->subject_match;
+ }
+ data->conn = tls_connection_init(sm->ssl_ctx);
+ if (data->conn == NULL) {
+ wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
+ "connection");
+ goto done;
+ }
+
+ if (tls_connection_ca_cert(sm->ssl_ctx, data->conn, ca_cert,
+ subject_match)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load root certificate "
+ "'%s'", ca_cert);
+ goto done;
+ }
+
+ if (tls_connection_client_cert(sm->ssl_ctx, data->conn, client_cert)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load client certificate "
+ "'%s'", client_cert);
+ goto done;
+ }
+
+ if (tls_connection_private_key(sm->ssl_ctx, data->conn, private_key,
+ private_key_passwd)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
+ private_key);
+ goto done;
+ }
+
+ if (dh_file && tls_connection_dh(sm->ssl_ctx, data->conn, dh_file)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+ dh_file);
+ goto done;
+ }
+
+ /* TODO: make this configurable */
+ data->tls_out_limit = 1398;
+ if (data->phase2) {
+ /* Limit the fragment size in the inner TLS authentication
+ * since the outer authentication with EAP-PEAP does not yet
+ * support fragmentation */
+ if (data->tls_out_limit > 100)
+ data->tls_out_limit -= 100;
+ }
+
+ if (config && config->phase1 &&
+ strstr(config->phase1, "include_tls_length=1")) {
+ wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
+ "unfragmented packets");
+ data->include_tls_length = 1;
+ }
+
+ ret = 0;
+
+done:
+ return ret;
+}
+
+
+void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+ tls_connection_deinit(sm->ssl_ctx, data->conn);
+ free(data->tls_in);
+ free(data->tls_out);
+}
+
+
+u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+ char *label, size_t len)
+{
+ struct tls_keys keys;
+ u8 *random;
+ u8 *out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+ out = malloc(len);
+ random = malloc(keys.client_random_len + keys.server_random_len);
+ if (out == NULL || random == NULL) {
+ free(out);
+ free(random);
+ return NULL;
+ }
+ memcpy(random, keys.client_random, keys.client_random_len);
+ memcpy(random + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ if (tls_prf(keys.master_key, keys.master_key_len,
+ label, random, keys.client_random_len +
+ keys.server_random_len, out, len)) {
+ free(random);
+ free(out);
+ return NULL;
+ }
+ free(random);
+ return out;
+}
+
+
+int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
+ u8 **in_data, size_t *in_len)
+{
+ u8 *buf;
+
+ if (data->tls_in_left > *in_len || data->tls_in) {
+ buf = realloc(data->tls_in, data->tls_in_len + *in_len);
+ if (buf == NULL) {
+ free(data->tls_in);
+ data->tls_in = NULL;
+ data->tls_in_len = 0;
+ wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
+ "for TLS data");
+ return -1;
+ }
+ memcpy(buf + data->tls_in_len, *in_data, *in_len);
+ data->tls_in = buf;
+ data->tls_in_len += *in_len;
+ if (*in_len > data->tls_in_left) {
+ wpa_printf(MSG_INFO, "SSL: more data than TLS message "
+ "length indicated");
+ data->tls_in_left = 0;
+ return -1;
+ }
+ data->tls_in_left -= *in_len;
+ if (data->tls_in_left > 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
+ "data", (unsigned long) data->tls_in_left);
+ return 1;
+ }
+
+ *in_data = data->tls_in;
+ *in_len = data->tls_in_len;
+ } else
+ data->tls_in_left = 0;
+
+ return 0;
+}
+
+
+int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+ int eap_type, int peap_version,
+ u8 id, u8 *in_data, size_t in_len,
+ u8 **out_data, size_t *out_len)
+{
+ size_t len;
+ u8 *pos, *flags;
+ struct eap_hdr *resp;
+
+ WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
+ *out_len = 0;
+
+ if (data->tls_out_len == 0) {
+ /* No more data to send out - expect to receive more data from
+ * the AS. */
+ int res = eap_tls_data_reassemble(sm, data, &in_data, &in_len);
+ if (res < 0 || res == 1)
+ return res;
+ /* Full TLS message reassembled - continue handshake processing
+ */
+ if (data->tls_out) {
+ /* This should not happen.. */
+ wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - "
+ "pending tls_out data even though "
+ "tls_out_len = 0");
+ free(data->tls_out);
+ WPA_ASSERT(data->tls_out == NULL);
+ }
+ data->tls_out = tls_connection_handshake(sm->ssl_ctx,
+ data->conn,
+ in_data, in_len,
+ &data->tls_out_len);
+
+ /* Clear reassembled input data (if the buffer was needed). */
+ data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
+ free(data->tls_in);
+ data->tls_in = NULL;
+ }
+
+ if (data->tls_out == NULL) {
+ data->tls_out_len = 0;
+ return -1;
+ }
+ if (data->tls_out_len == 0) {
+ /* TLS negotiation should now be complete since all other cases
+ * needing more that should have been catched above based on
+ * the TLS Message Length field. */
+ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
+ free(data->tls_out);
+ data->tls_out = NULL;
+ return 1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
+ "%lu bytes)",
+ (unsigned long) data->tls_out_len - data->tls_out_pos,
+ (unsigned long) data->tls_out_len);
+ resp = malloc(sizeof(struct eap_hdr) + 2 + 4 + data->tls_out_limit);
+ if (resp == NULL) {
+ *out_data = NULL;
+ return -1;
+ }
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+ pos = (u8 *) (resp + 1);
+ *pos++ = eap_type;
+ flags = pos++;
+ *flags = peap_version;
+ if (data->tls_out_pos == 0 &&
+ (data->tls_out_len > data->tls_out_limit ||
+ data->include_tls_length)) {
+ *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+ *pos++ = (data->tls_out_len >> 24) & 0xff;
+ *pos++ = (data->tls_out_len >> 16) & 0xff;
+ *pos++ = (data->tls_out_len >> 8) & 0xff;
+ *pos++ = data->tls_out_len & 0xff;
+ }
+
+ len = data->tls_out_len - data->tls_out_pos;
+ if (len > data->tls_out_limit) {
+ *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+ len = data->tls_out_limit;
+ wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
+ "will follow", (unsigned long) len);
+ }
+ memcpy(pos, &data->tls_out[data->tls_out_pos], len);
+ data->tls_out_pos += len;
+ *out_len = (pos - (u8 *) resp) + len;
+ resp->length = host_to_be16(*out_len);
+ *out_data = (u8 *) resp;
+
+ if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
+ data->tls_out_len = 0;
+ data->tls_out_pos = 0;
+ free(data->tls_out);
+ data->tls_out = NULL;
+ }
+
+ return 0;
+}
+
+
+u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
+ int eap_type, int peap_version)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+
+ *respDataLen = sizeof(struct eap_hdr) + 2;
+ resp = malloc(*respDataLen);
+ if (resp == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "SSL: Building ACK");
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+ resp->length = host_to_be16(*respDataLen);
+ pos = (u8 *) (resp + 1);
+ *pos++ = eap_type; /* Type */
+ *pos = peap_version; /* Flags */
+ return (u8 *) resp;
+}
+
+
+int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+ return tls_connection_shutdown(sm->ssl_ctx, data->conn);
+}
+
+
+int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
+ size_t buflen, int verbose)
+{
+ char name[128];
+ int len = 0;
+
+ if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
+ len += snprintf(buf + len, buflen - len,
+ "EAP TLS cipher=%s\n", name);
+ }
+
+ return len;
+}
diff --git a/contrib/wpa_supplicant/eap_tls_common.h b/contrib/wpa_supplicant/eap_tls_common.h
new file mode 100644
index 000000000000..499cae4c0e10
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_tls_common.h
@@ -0,0 +1,51 @@
+#ifndef EAP_TLS_COMMON_H
+#define EAP_TLS_COMMON_H
+
+struct eap_ssl_data {
+ struct tls_connection *conn;
+
+ u8 *tls_out;
+ size_t tls_out_len;
+ size_t tls_out_pos;
+ size_t tls_out_limit;
+ u8 *tls_in;
+ size_t tls_in_len;
+ size_t tls_in_left;
+ size_t tls_in_total;
+
+ int phase2;
+ int include_tls_length; /* include TLS length field even if the TLS
+ * data is not fragmented */
+
+ struct eap_sm *eap;
+};
+
+
+/* EAP TLS Flags */
+#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TLS_FLAGS_START 0x20
+#define EAP_PEAP_VERSION_MASK 0x07
+
+ /* could be up to 128 bytes, but only the first 64 bytes are used */
+#define EAP_TLS_KEY_LEN 64
+
+
+int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+ struct wpa_ssid *config);
+void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
+u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+ char *label, size_t len);
+int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
+ u8 **in_data, size_t *in_len);
+int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+ int eap_type, int peap_version,
+ u8 id, u8 *in_data, size_t in_len,
+ u8 **out_data, size_t *out_len);
+u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
+ int eap_type, int peap_version);
+int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
+int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
+ size_t buflen, int verbose);
+
+#endif /* EAP_TLS_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_tlv.c b/contrib/wpa_supplicant/eap_tlv.c
new file mode 100644
index 000000000000..5571d8bdf2cb
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_tlv.c
@@ -0,0 +1,176 @@
+/*
+ * WPA Supplicant / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "wpa_supplicant.h"
+#include "eap_i.h"
+#include "eap_tlv.h"
+
+
+u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len)
+{
+ struct eap_hdr *hdr;
+ u8 *pos;
+
+ *resp_len = sizeof(struct eap_hdr) + 1 + 10;
+ hdr = malloc(*resp_len);
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->code = EAP_CODE_RESPONSE;
+ hdr->identifier = id;
+ hdr->length = host_to_be16(*resp_len);
+ pos = (u8 *) (hdr + 1);
+ *pos++ = EAP_TYPE_TLV;
+ *pos++ = 0x80; /* Mandatory */
+ *pos++ = EAP_TLV_NAK_TLV;
+ /* Length */
+ *pos++ = 0;
+ *pos++ = 6;
+ /* Vendor-Id */
+ *pos++ = 0;
+ *pos++ = 0;
+ *pos++ = 0;
+ *pos++ = 0;
+ /* NAK-Type */
+ *pos++ = nak_type >> 8;
+ *pos++ = nak_type & 0xff;
+
+ return (u8 *) hdr;
+}
+
+
+u8 * eap_tlv_build_result(int id, int status, size_t *resp_len)
+{
+ struct eap_hdr *hdr;
+ u8 *pos;
+
+ *resp_len = sizeof(struct eap_hdr) + 1 + 6;
+ hdr = malloc(*resp_len);
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->code = EAP_CODE_RESPONSE;
+ hdr->identifier = id;
+ hdr->length = host_to_be16(*resp_len);
+ pos = (u8 *) (hdr + 1);
+ *pos++ = EAP_TYPE_TLV;
+ *pos++ = 0x80; /* Mandatory */
+ *pos++ = EAP_TLV_RESULT_TLV;
+ /* Length */
+ *pos++ = 0;
+ *pos++ = 2;
+ /* Status */
+ *pos++ = status >> 8;
+ *pos++ = status & 0xff;
+
+ return (u8 *) hdr;
+}
+
+
+int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
+ struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
+{
+ size_t left;
+ u8 *pos;
+ u8 *result_tlv = NULL;
+ size_t result_tlv_len = 0;
+ int tlv_type, mandatory, tlv_len;
+
+ /* Parse TLVs */
+ left = be_to_host16(hdr->length) - sizeof(struct eap_hdr) - 1;
+ pos = (u8 *) (hdr + 1);
+ pos++;
+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
+ while (left >= 4) {
+ mandatory = !!(pos[0] & 0x80);
+ tlv_type = pos[0] & 0x3f;
+ tlv_type = (tlv_type << 8) | pos[1];
+ tlv_len = ((int) pos[2] << 8) | pos[3];
+ pos += 4;
+ left -= 4;
+ if (tlv_len > left) {
+ wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
+ "(tlv_len=%d left=%lu)", tlv_len,
+ (unsigned long) left);
+ return -1;
+ }
+ switch (tlv_type) {
+ case EAP_TLV_RESULT_TLV:
+ result_tlv = pos;
+ result_tlv_len = tlv_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
+ "%d%s", tlv_type,
+ mandatory ? " (mandatory)" : "");
+ if (mandatory) {
+ /* NAK TLV and ignore all TLVs in this packet.
+ */
+ *resp = eap_tlv_build_nak(hdr->identifier,
+ tlv_type, resp_len);
+ return *resp == NULL ? -1 : 0;
+ }
+ /* Ignore this TLV, but process other TLVs */
+ break;
+ }
+
+ pos += tlv_len;
+ left -= tlv_len;
+ }
+ if (left) {
+ wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
+ "Request (left=%lu)", (unsigned long) left);
+ return -1;
+ }
+
+ /* Process supported TLVs */
+ if (result_tlv) {
+ int status, resp_status;
+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
+ result_tlv, result_tlv_len);
+ if (result_tlv_len < 2) {
+ wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
+ "(len=%lu)",
+ (unsigned long) result_tlv_len);
+ return -1;
+ }
+ status = ((int) result_tlv[0] << 8) | result_tlv[1];
+ if (status == EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
+ "- EAP-TLV/Phase2 Completed");
+ resp_status = EAP_TLV_RESULT_SUCCESS;
+ ret->decision = DECISION_UNCOND_SUCC;
+ } else if (status == EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
+ resp_status = EAP_TLV_RESULT_FAILURE;
+ ret->decision = DECISION_FAIL;
+ } else {
+ wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
+ "Status %d", status);
+ resp_status = EAP_TLV_RESULT_FAILURE;
+ ret->decision = DECISION_FAIL;
+ }
+ ret->methodState = METHOD_DONE;
+
+ *resp = eap_tlv_build_result(hdr->identifier, resp_status,
+ resp_len);
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/eap_tlv.h b/contrib/wpa_supplicant/eap_tlv.h
new file mode 100644
index 000000000000..439155263716
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_tlv.h
@@ -0,0 +1,73 @@
+#ifndef EAP_TLV_H
+#define EAP_TLV_H
+
+/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
+#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
+#define EAP_TLV_NAK_TLV 4
+#define EAP_TLV_CRYPTO_BINDING_TLV 5
+#define EAP_TLV_CONNECTION_BINDING_TLV 6
+#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
+#define EAP_TLV_URI_TLV 8
+#define EAP_TLV_EAP_PAYLOAD_TLV 9
+#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
+#define EAP_TLV_PAC_TLV 11 /* draft-cam-winget-eap-fast-01.txt */
+#define EAP_TLV_CRYPTO_BINDING_TLV_ 12 /* draft-cam-winget-eap-fast-01.txt */
+
+#define EAP_TLV_RESULT_SUCCESS 1
+#define EAP_TLV_RESULT_FAILURE 2
+
+#define EAP_TLV_TYPE_MANDATORY 0x8000
+
+struct eap_tlv_hdr {
+ u16 tlv_type;
+ u16 length;
+};
+
+struct eap_tlv_nak_tlv {
+ u16 tlv_type;
+ u16 length;
+ u32 vendor_id;
+ u16 nak_type;
+} __attribute__((packed));
+
+struct eap_tlv_result_tlv {
+ u16 tlv_type;
+ u16 length;
+ u16 status;
+} __attribute__((packed));
+
+struct eap_tlv_intermediate_result_tlv {
+ u16 tlv_type;
+ u16 length;
+ u16 status;
+} __attribute__((packed));
+
+struct eap_tlv_crypto_binding__tlv {
+ u16 tlv_type;
+ u16 length;
+ u8 reserved;
+ u8 version;
+ u8 received_version;
+ u8 subtype;
+ u8 nonce[32];
+ u8 compound_mac[20];
+} __attribute__((packed));
+
+struct eap_tlv_pac_ack_tlv {
+ u16 tlv_type;
+ u16 length;
+ u16 pac_type;
+ u16 pac_len;
+ u16 result;
+} __attribute__((packed));
+
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
+
+
+u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len);
+u8 * eap_tlv_build_result(int id, int status, size_t *resp_len);
+int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
+ struct eap_hdr *hdr, u8 **resp, size_t *resp_len);
+
+#endif /* EAP_TLV_H */
diff --git a/contrib/wpa_supplicant/eap_ttls.c b/contrib/wpa_supplicant/eap_ttls.c
new file mode 100644
index 000000000000..b639fcd54dc8
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_ttls.c
@@ -0,0 +1,1384 @@
+/*
+ * WPA Supplicant / EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "ms_funcs.h"
+#include "md5.h"
+#include "tls.h"
+#include "eap_ttls.h"
+
+
+static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_ttls_data {
+ struct eap_ssl_data ssl;
+
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+ int phase2_success;
+ int phase2_start;
+
+ enum {
+ EAP_TTLS_PHASE2_EAP,
+ EAP_TTLS_PHASE2_MSCHAPV2,
+ EAP_TTLS_PHASE2_MSCHAP,
+ EAP_TTLS_PHASE2_PAP,
+ EAP_TTLS_PHASE2_CHAP
+ } phase2_type;
+ u8 phase2_eap_type;
+ u8 *phase2_eap_types;
+ size_t num_phase2_eap_types;
+
+ u8 auth_response[20];
+ int auth_response_valid;
+ u8 ident;
+ int resuming; /* starting a resumed session */
+ int reauth; /* reauthentication */
+ u8 *key_data;
+
+ u8 *pending_phase2_req;
+ size_t pending_phase2_req_len;
+};
+
+
+static void * eap_ttls_init(struct eap_sm *sm)
+{
+ struct eap_ttls_data *data;
+ struct wpa_ssid *config = eap_get_config(sm);
+ char *selected;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+ selected = "EAP";
+ data->phase2_type = EAP_TTLS_PHASE2_EAP;
+ if (config && config->phase2) {
+ if (strstr(config->phase2, "autheap=")) {
+ selected = "EAP";
+ data->phase2_type = EAP_TTLS_PHASE2_EAP;
+ } else if (strstr(config->phase2, "auth=MSCHAPV2")) {
+ selected = "MSCHAPV2";
+ data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
+ } else if (strstr(config->phase2, "auth=MSCHAP")) {
+ selected = "MSCHAP";
+ data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
+ } else if (strstr(config->phase2, "auth=PAP")) {
+ selected = "PAP";
+ data->phase2_type = EAP_TTLS_PHASE2_PAP;
+ } else if (strstr(config->phase2, "auth=CHAP")) {
+ selected = "CHAP";
+ data->phase2_type = EAP_TTLS_PHASE2_CHAP;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
+
+ if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
+ if (config && config->phase2) {
+ char *start, *pos, *buf;
+ u8 method, *methods = NULL, *_methods;
+ size_t num_methods = 0;
+ start = buf = strdup(config->phase2);
+ if (buf == NULL) {
+ eap_ttls_deinit(sm, data);
+ return NULL;
+ }
+ while (start && *start != '\0') {
+ pos = strstr(start, "autheap=");
+ if (pos == NULL)
+ break;
+ if (start != pos && *(pos - 1) != ' ') {
+ start = pos + 8;
+ continue;
+ }
+
+ start = pos + 8;
+ pos = strchr(start, ' ');
+ if (pos)
+ *pos++ = '\0';
+ method = eap_get_phase2_type(start);
+ if (method == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "EAP-TTLS: "
+ "Unsupported Phase2 EAP "
+ "method '%s'", start);
+ } else {
+ num_methods++;
+ _methods = realloc(methods,
+ num_methods);
+ if (_methods == NULL) {
+ free(methods);
+ eap_ttls_deinit(sm, data);
+ return NULL;
+ }
+ methods = _methods;
+ methods[num_methods - 1] = method;
+ }
+
+ start = pos;
+ }
+ free(buf);
+ data->phase2_eap_types = methods;
+ data->num_phase2_eap_types = num_methods;
+ }
+ if (data->phase2_eap_types == NULL) {
+ data->phase2_eap_types = eap_get_phase2_types(
+ config, &data->num_phase2_eap_types);
+ }
+ if (data->phase2_eap_types == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-TTLS: No Phase2 EAP method "
+ "available");
+ eap_ttls_deinit(sm, data);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase2 EAP types",
+ data->phase2_eap_types,
+ data->num_phase2_eap_types);
+ data->phase2_eap_type = EAP_TYPE_NONE;
+ }
+
+
+ if (eap_tls_ssl_init(sm, &data->ssl, config)) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+ eap_ttls_deinit(sm, data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_ttls_data *data = priv;
+ if (data == NULL)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ free(data->phase2_eap_types);
+ eap_tls_ssl_deinit(sm, &data->ssl);
+ free(data->key_data);
+ free(data->pending_phase2_req);
+ free(data);
+}
+
+
+static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
+ int id, u8 *plain, size_t plain_len,
+ u8 **out_data, size_t *out_len)
+{
+ int res;
+ u8 *pos;
+ struct eap_hdr *resp;
+
+ /* TODO: add support for fragmentation, if needed. This will need to
+ * add TLS Message Length field, if the frame is fragmented. */
+ resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ if (resp == NULL)
+ return 0;
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_TTLS;
+ *pos++ = 0;
+
+ res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+ plain, plain_len,
+ pos, data->ssl.tls_out_limit);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt Phase 2 "
+ "data");
+ free(resp);
+ return 0;
+ }
+
+ *out_len = sizeof(struct eap_hdr) + 2 + res;
+ resp->length = host_to_be16(*out_len);
+ *out_data = (u8 *) resp;
+ return 0;
+}
+
+
+static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
+ int mandatory, size_t len)
+{
+ struct ttls_avp_vendor *avp;
+ u8 flags;
+ size_t hdrlen;
+
+ avp = (struct ttls_avp_vendor *) avphdr;
+ flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
+ if (vendor_id) {
+ flags |= AVP_FLAGS_VENDOR;
+ hdrlen = sizeof(*avp);
+ avp->vendor_id = host_to_be32(vendor_id);
+ } else {
+ hdrlen = sizeof(struct ttls_avp);
+ }
+
+ avp->avp_code = host_to_be32(avp_code);
+ avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+
+ return avphdr + hdrlen;
+}
+
+
+static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
+ u32 vendor_id, int mandatory,
+ u8 *data, size_t len)
+{
+ u8 *pos;
+ pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
+ memcpy(pos, data, len);
+ pos += len;
+ AVP_PAD(start, pos);
+ return pos;
+}
+
+
+static int eap_ttls_avp_encapsulate(u8 **resp, size_t *resp_len, u32 avp_code,
+ int mandatory)
+{
+ u8 *avp, *pos;
+
+ avp = malloc(sizeof(struct ttls_avp) + *resp_len + 4);
+ if (avp == NULL) {
+ free(*resp);
+ *resp_len = 0;
+ return -1;
+ }
+
+ pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, *resp_len);
+ memcpy(pos, *resp, *resp_len);
+ pos += *resp_len;
+ AVP_PAD(avp, pos);
+ free(*resp);
+ *resp = avp;
+ *resp_len = pos - avp;
+ return 0;
+}
+
+
+static int eap_ttls_phase2_nak(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ struct eap_hdr *hdr,
+ u8 **resp, size_t *resp_len)
+{
+ struct eap_hdr *resp_hdr;
+ u8 *pos = (u8 *) (hdr + 1);
+
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 Request: Nak type=%d", *pos);
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Allowed Phase2 EAP types",
+ data->phase2_eap_types, data->num_phase2_eap_types);
+ *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_eap_types;
+ *resp = malloc(*resp_len);
+ if (*resp == NULL)
+ return -1;
+
+ resp_hdr = (struct eap_hdr *) (*resp);
+ resp_hdr->code = EAP_CODE_RESPONSE;
+ resp_hdr->identifier = hdr->identifier;
+ resp_hdr->length = host_to_be16(*resp_len);
+ pos = (u8 *) (resp_hdr + 1);
+ *pos++ = EAP_TYPE_NAK;
+ memcpy(pos, data->phase2_eap_types, data->num_phase2_eap_types);
+
+ return