Revert wpa import.
b51f459a20
resulted in a mismerge
due to having to do a remerge because my tree was over a week out of
date. Changes that were made to fix the build were lost in the remerge
resulting in build errors that were fixed a week ago.
This commit is contained in:
parent
0f29396e49
commit
0aad5de37c
8
contrib/wpa/.gitignore
vendored
8
contrib/wpa/.gitignore
vendored
@ -1,8 +0,0 @@
|
||||
*.pyc
|
||||
*~
|
||||
tests/hwsim/logs
|
||||
tests/remote/logs
|
||||
wpaspy/build
|
||||
**/parallel-vm.log
|
||||
tags
|
||||
build/
|
@ -1,10 +0,0 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
ifneq ($(filter VER_0_8_X VER_2_1_DEVEL,$(WPA_SUPPLICANT_VERSION)),)
|
||||
# The order of the 2 Android.mks does matter!
|
||||
# TODO: Clean up the Android.mks, reset all the temporary variables at the
|
||||
# end of each Android.mk, so that one Android.mk doesn't depend on variables
|
||||
# set up in the other Android.mk.
|
||||
include $(LOCAL_PATH)/hostapd/Android.mk \
|
||||
$(LOCAL_PATH)/wpa_supplicant/Android.mk
|
||||
endif
|
@ -1,47 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "build_release <version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMP=tmp.build_release
|
||||
RELDIR=`pwd`/Release
|
||||
VER=$1
|
||||
NOW=`date +%Y-%m-%d`
|
||||
|
||||
echo "Version: $VER - $NOW"
|
||||
|
||||
DATEw=`head -n 3 wpa_supplicant/ChangeLog | tail -n 1 | sed "s/ .*//"`
|
||||
DATEh=`head -n 3 hostapd/ChangeLog | tail -n 1 | sed "s/ .*//"`
|
||||
|
||||
if [ "$DATEw" != "$NOW" -o "$DATEh" != "$NOW" ]; then
|
||||
echo "NOTE! Date mismatch in ChangeLog: wpa_supplicant $DATEw hostapd $DATEh != $NOW"
|
||||
fi
|
||||
|
||||
if [ -r $TMP ]; then
|
||||
echo "Temporary directory '$TMP' exists. Remove it before running this."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir $TMP
|
||||
mkdir -p $RELDIR
|
||||
|
||||
git archive --format=tar --prefix=wpa-$VER/ HEAD \
|
||||
README COPYING CONTRIBUTIONS src wpa_supplicant hostapd hs20 |
|
||||
gzip > $RELDIR/wpa-$VER.tar.gz
|
||||
git archive --format=tar --prefix=hostapd-$VER/ HEAD \
|
||||
README COPYING CONTRIBUTIONS src hostapd |
|
||||
gzip > $RELDIR/hostapd-$VER.tar.gz
|
||||
git archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
|
||||
README COPYING CONTRIBUTIONS src wpa_supplicant hs20/client |
|
||||
tar --directory=$TMP -xf -
|
||||
|
||||
cd $TMP
|
||||
make -C wpa_supplicant-$VER/wpa_supplicant/doc/docbook man
|
||||
rm -f wpa_supplicant-$VER/wpa_supplicant/doc/docbook/manpage.{links,refs}
|
||||
tar czf $RELDIR/wpa_supplicant-$VER.tar.gz wpa_supplicant-$VER
|
||||
cd ..
|
||||
rm -r $TMP
|
14
contrib/wpa/doc/.gitignore
vendored
14
contrib/wpa/doc/.gitignore
vendored
@ -1,14 +0,0 @@
|
||||
doxygen.warnings
|
||||
hostapd.eps
|
||||
hostapd.png
|
||||
html
|
||||
latex
|
||||
p2p_arch.eps
|
||||
p2p_arch.png
|
||||
p2p_arch2.eps
|
||||
p2p_arch2.png
|
||||
p2p_sm.eps
|
||||
p2p_sm.png
|
||||
wpa_supplicant.eps
|
||||
wpa_supplicant.png
|
||||
wpa_supplicant-devel.pdf
|
@ -1,42 +0,0 @@
|
||||
all: docs
|
||||
|
||||
%.eps: %.fig
|
||||
fig2dev -L eps $*.fig $*.eps
|
||||
|
||||
%.png: %.fig
|
||||
fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
|
||||
> $*.png
|
||||
|
||||
%.png: %.dot
|
||||
dot $*.dot -Tpng -o $*.png
|
||||
|
||||
%.eps: %.dot
|
||||
dot $*.dot -Tps -o $*.eps
|
||||
|
||||
_wpa_supplicant.png: wpa_supplicant.png
|
||||
cp $< $@
|
||||
|
||||
_wpa_supplicant.eps: wpa_supplicant.eps
|
||||
cp $< $@
|
||||
|
||||
docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.eps p2p_sm.png p2p_sm.eps p2p_arch.png p2p_arch.eps p2p_arch2.png p2p_arch2.eps _wpa_supplicant.png _wpa_supplicant.eps
|
||||
|
||||
docs: docs-pics
|
||||
(cd ..; doxygen doc/doxygen.conf; cd doc)
|
||||
$(MAKE) -C latex
|
||||
cp latex/refman.pdf wpa_supplicant-devel.pdf
|
||||
|
||||
html: docs-pics
|
||||
(cd ..; doxygen doc/doxygen.conf; cd doc)
|
||||
|
||||
clean:
|
||||
rm -f *~
|
||||
rm -f wpa_supplicant.eps wpa_supplicant.png
|
||||
rm -f _wpa_supplicant.png _wpa_supplicant.eps
|
||||
rm -f hostapd.eps hostapd.png
|
||||
rm -f p2p_sm.eps p2p_sm.png
|
||||
rm -f p2p_arch.eps p2p_arch.png
|
||||
rm -f p2p_arch2.eps p2p_arch2.png
|
||||
rm -f doxygen.warnings
|
||||
rm -rf html latex
|
||||
rm -f wpa_supplicant-devel.pdf
|
@ -1,315 +0,0 @@
|
||||
/**
|
||||
\page code_structure Structure of the source code
|
||||
|
||||
[ \ref _wpa_supplicant_core "wpa_supplicant core functionality" |
|
||||
\ref generic_helper_func "Generic helper functions" |
|
||||
\ref crypto_func "Cryptographic functions" |
|
||||
\ref tls_func "TLS library" |
|
||||
\ref configuration "Configuration" |
|
||||
\ref ctrl_iface "Control interface" |
|
||||
\ref wpa_code "WPA supplicant" |
|
||||
\ref eap_peer "EAP peer" |
|
||||
\ref eapol_supp "EAPOL supplicant" |
|
||||
\ref win_port "Windows port" |
|
||||
\ref test_programs "Test programs" ]
|
||||
|
||||
wpa_supplicant implementation is divided into number of independent
|
||||
modules. Core code includes functionality for controlling the network
|
||||
selection, association, and configuration. Independent modules include
|
||||
WPA code (key handshake, PMKSA caching, pre-authentication), EAPOL
|
||||
state machine, and EAP state machine and methods. In addition, there
|
||||
are number of separate files for generic helper functions.
|
||||
|
||||
Both WPA and EAPOL/EAP state machines can be used separately in other
|
||||
programs than wpa_supplicant. As an example, the included test
|
||||
programs eapol_test and preauth_test are using these modules.
|
||||
|
||||
\ref driver_wrapper "Driver interface API" is defined in \ref driver.h and
|
||||
all hardware/driver dependent functionality is implemented in
|
||||
driver_*.c.
|
||||
|
||||
|
||||
\section _wpa_supplicant_core wpa_supplicant core functionality
|
||||
|
||||
\ref wpa_supplicant.c
|
||||
Program initialization, main control loop
|
||||
|
||||
\ref wpa_supplicant/main.c
|
||||
main() for UNIX-like operating systems and MinGW (Windows); this
|
||||
uses command line arguments to configure wpa_supplicant
|
||||
|
||||
\ref events.c
|
||||
Driver event processing; \ref wpa_supplicant_event() and related functions
|
||||
|
||||
\ref wpa_supplicant_i.h
|
||||
Internal definitions for wpa_supplicant core; should not be
|
||||
included into independent modules
|
||||
|
||||
|
||||
\section generic_helper_func Generic helper functions
|
||||
|
||||
wpa_supplicant uses generic helper functions some of which are shared
|
||||
with with hostapd. The following C files are currently used:
|
||||
|
||||
\ref eloop.c and \ref eloop.h
|
||||
Event loop (select() loop with registerable timeouts, socket read
|
||||
callbacks, and signal callbacks)
|
||||
|
||||
\ref common.c and \ref common.h
|
||||
Common helper functions
|
||||
|
||||
\ref defs.h
|
||||
Definitions shared by multiple files
|
||||
|
||||
\ref l2_packet.h, \ref l2_packet_linux.c, and \ref l2_packet_pcap.c
|
||||
Layer 2 (link) access wrapper (includes native Linux implementation
|
||||
and wrappers for libdnet/libpcap). A new l2_packet implementation
|
||||
may need to be added when porting to new operating systems that are
|
||||
not supported by libdnet/libpcap. Makefile can be used to select which
|
||||
l2_packet implementation is included. \ref l2_packet_linux.c uses Linux
|
||||
packet sockets and \ref l2_packet_pcap.c has a more portable version using
|
||||
libpcap and libdnet.
|
||||
|
||||
\ref pcsc_funcs.c and \ref pcsc_funcs.h
|
||||
Wrapper for PC/SC lite SIM and smart card readers
|
||||
|
||||
\ref priv_netlink.h
|
||||
Private version of netlink definitions from Linux kernel header files;
|
||||
this could be replaced with C library header file once suitable
|
||||
version becomes commonly available
|
||||
|
||||
\ref version.h
|
||||
Version number definitions
|
||||
|
||||
|
||||
\section crypto_func Cryptographic functions
|
||||
|
||||
\ref md5.c and \ref md5.h
|
||||
MD5 (replaced with a crypto library if TLS support is included)
|
||||
HMAC-MD5 (keyed checksum for message authenticity validation)
|
||||
|
||||
\ref rc4.c and \ref rc4.h
|
||||
RC4 (broadcast/default key encryption)
|
||||
|
||||
\ref sha1.c and \ref sha1.h
|
||||
SHA-1 (replaced with a crypto library 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)
|
||||
|
||||
\ref sha256.c and \ref sha256.h
|
||||
SHA-256 (replaced with a crypto library if TLS support is included)
|
||||
|
||||
\ref aes-wrap.c, \ref aes_wrap.h, \ref aes.c
|
||||
AES (replaced with a crypto library if TLS support is included),
|
||||
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
|
||||
|
||||
\ref crypto.h
|
||||
Definition of crypto library wrapper
|
||||
|
||||
\ref crypto_openssl.c
|
||||
Wrapper functions for libcrypto (OpenSSL)
|
||||
|
||||
\ref crypto_internal.c
|
||||
Wrapper functions for internal crypto implementation
|
||||
|
||||
\ref crypto_gnutls.c
|
||||
Wrapper functions for libgcrypt (used by GnuTLS)
|
||||
|
||||
\ref ms_funcs.c and \ref ms_funcs.h
|
||||
Helper functions for MSCHAPV2 and LEAP
|
||||
|
||||
\ref tls.h
|
||||
Definition of TLS library wrapper
|
||||
|
||||
\ref tls_none.c
|
||||
Dummy implementation of TLS library wrapper for cases where TLS
|
||||
functionality is not included.
|
||||
|
||||
\ref tls_openssl.c
|
||||
TLS library wrapper for openssl
|
||||
|
||||
\ref tls_internal.c
|
||||
TLS library for internal TLS implementation
|
||||
|
||||
\ref tls_gnutls.c
|
||||
TLS library wrapper for GnuTLS
|
||||
|
||||
|
||||
\section tls_func TLS library
|
||||
|
||||
\ref asn1.c and \ref asn1.h
|
||||
ASN.1 DER parsing
|
||||
|
||||
\ref bignum.c and \ref bignum.h
|
||||
Big number math
|
||||
|
||||
\ref rsa.c and \ref rsa.h
|
||||
RSA
|
||||
|
||||
\ref x509v3.c and \ref x509v3.h
|
||||
X.509v3 certificate parsing and processing
|
||||
|
||||
\ref tlsv1_client.c, \ref tlsv1_client.h
|
||||
TLSv1 client (RFC 2246)
|
||||
|
||||
\ref tlsv1_client_i.h
|
||||
Internal structures for TLSv1 client
|
||||
|
||||
\ref tlsv1_client_read.c
|
||||
TLSv1 client: read handshake messages
|
||||
|
||||
\ref tlsv1_client_write.c
|
||||
TLSv1 client: write handshake messages
|
||||
|
||||
\ref tlsv1_common.c and \ref tlsv1_common.h
|
||||
Common TLSv1 routines and definitions
|
||||
|
||||
\ref tlsv1_cred.c and \ref tlsv1_cred.h
|
||||
TLSv1 credentials
|
||||
|
||||
\ref tlsv1_record.c and \ref tlsv1_record.h
|
||||
TLSv1 record protocol
|
||||
|
||||
|
||||
\section configuration Configuration
|
||||
|
||||
\ref config_ssid.h
|
||||
Definition of per network configuration items
|
||||
|
||||
\ref config.h
|
||||
Definition of the wpa_supplicant configuration
|
||||
|
||||
\ref config.c
|
||||
Configuration parser and common functions
|
||||
|
||||
\ref wpa_supplicant/config_file.c
|
||||
Configuration backend for text files (e.g., wpa_supplicant.conf)
|
||||
|
||||
\ref config_winreg.c
|
||||
Configuration backend for Windows registry
|
||||
|
||||
|
||||
\section ctrl_iface Control interface
|
||||
|
||||
wpa_supplicant has a \ref ctrl_iface_page "control interface"
|
||||
that can be used to get status
|
||||
information and manage operations from external programs. An example
|
||||
command line interface (wpa_cli) and GUI (wpa_gui) for this interface
|
||||
are included in the wpa_supplicant distribution.
|
||||
|
||||
\ref wpa_supplicant/ctrl_iface.c and \ref wpa_supplicant/ctrl_iface.h
|
||||
wpa_supplicant-side of the control interface
|
||||
|
||||
\ref ctrl_iface_unix.c
|
||||
UNIX domain sockets -based control interface backend
|
||||
|
||||
\ref ctrl_iface_udp.c
|
||||
UDP sockets -based control interface backend
|
||||
|
||||
\ref ctrl_iface_named_pipe.c
|
||||
Windows named pipes -based control interface backend
|
||||
|
||||
\ref wpa_ctrl.c and \ref wpa_ctrl.h
|
||||
Library functions for external programs to provide access to the
|
||||
wpa_supplicant control interface
|
||||
|
||||
\ref wpa_cli.c
|
||||
Example program for using wpa_supplicant control interface
|
||||
|
||||
|
||||
\section wpa_code WPA supplicant
|
||||
|
||||
\ref wpa.c and \ref wpa.h
|
||||
WPA state machine and 4-Way/Group Key Handshake processing
|
||||
|
||||
\ref preauth.c and \ref preauth.h
|
||||
PMKSA caching and pre-authentication (RSN/WPA2)
|
||||
|
||||
\ref wpa_i.h
|
||||
Internal definitions for WPA code; not to be included to other modules.
|
||||
|
||||
\section eap_peer EAP peer
|
||||
|
||||
\ref eap_peer_module "EAP peer implementation" is a separate module that
|
||||
can be used by other programs than just wpa_supplicant.
|
||||
|
||||
\ref eap.c and \ref eap.h
|
||||
EAP state machine and method interface
|
||||
|
||||
\ref eap_defs.h
|
||||
Common EAP definitions
|
||||
|
||||
\ref eap_i.h
|
||||
Internal definitions for EAP state machine and EAP methods; not to be
|
||||
included in other modules
|
||||
|
||||
\ref eap_sim_common.c and \ref eap_sim_common.h
|
||||
Common code for EAP-SIM and EAP-AKA
|
||||
|
||||
\ref eap_tls_common.c and \ref eap_tls_common.h
|
||||
Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST
|
||||
|
||||
\ref eap_ttls.c and \ref eap_ttls.h
|
||||
EAP-TTLS
|
||||
|
||||
\ref eap_pax.c, \ref eap_pax_common.h, \ref eap_pax_common.c
|
||||
EAP-PAX
|
||||
|
||||
\ref eap_psk.c, \ref eap_psk_common.h, \ref eap_psk_common.c
|
||||
EAP-PSK (note: this is not needed for WPA-PSK)
|
||||
|
||||
\ref eap_sake.c, \ref eap_sake_common.h, \ref eap_sake_common.c
|
||||
EAP-SAKE
|
||||
|
||||
\ref eap_gpsk.c, \ref eap_gpsk_common.h, \ref eap_gpsk_common.c
|
||||
EAP-GPSK
|
||||
|
||||
\ref eap_aka.c, \ref eap_fast.c, \ref eap_gtc.c, \ref eap_leap.c,
|
||||
\ref eap_md5.c, \ref eap_mschapv2.c, \ref eap_otp.c, \ref eap_peap.c,
|
||||
\ref eap_sim.c, \ref eap_tls.c
|
||||
Other EAP method implementations
|
||||
|
||||
|
||||
\section eapol_supp EAPOL supplicant
|
||||
|
||||
\ref eapol_supp_sm.c and \ref eapol_supp_sm.h
|
||||
EAPOL supplicant state machine and IEEE 802.1X processing
|
||||
|
||||
|
||||
\section win_port Windows port
|
||||
|
||||
\ref ndis_events.c
|
||||
Code for receiving NdisMIndicateStatus() events and delivering them to
|
||||
wpa_supplicant \ref driver_ndis.c in more easier to use form
|
||||
|
||||
\ref win_if_list.c
|
||||
External program for listing current network interface
|
||||
|
||||
|
||||
\section test_programs Test programs
|
||||
|
||||
\ref radius_client.c and \ref radius_client.h
|
||||
RADIUS authentication client implementation for eapol_test
|
||||
|
||||
\ref radius.c and \ref radius.h
|
||||
RADIUS message processing for eapol_test
|
||||
|
||||
\ref eapol_test.c
|
||||
Standalone EAP testing tool with integrated RADIUS authentication
|
||||
client
|
||||
|
||||
\ref preauth_test.c
|
||||
Standalone RSN pre-authentication tool
|
||||
|
||||
\ref wpa_passphrase.c
|
||||
WPA ASCII passphrase to PSK conversion
|
||||
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,90 +0,0 @@
|
||||
/**
|
||||
|
||||
\dir hostapd hostapd
|
||||
|
||||
hostapd-specific code for configuration, control interface, and AP
|
||||
management.
|
||||
|
||||
|
||||
\dir src/common Common functionality
|
||||
|
||||
This module includes IEEE 802.11, IEEE 802.1X, and WPA related
|
||||
functionality that is shared between AP and station modes.
|
||||
|
||||
|
||||
\dir src/crypto Cryptographical functionality and wrappers
|
||||
|
||||
This module defines crypto and tls interfaces to provide portability
|
||||
layer for different crypto/TLS libraries. Wrappers for number of
|
||||
libraries are also included here. In addition, internal implementation
|
||||
of various crypto functions are provided as an alternative for an
|
||||
external library and to extend some algorithms.
|
||||
|
||||
|
||||
\dir src/drivers Driver wrappers
|
||||
|
||||
This directory includes the driver interface definition and all the
|
||||
driver wrappers that can be used to interact with different drivers
|
||||
without making rest of the software dependent on which particular
|
||||
driver is used.
|
||||
|
||||
|
||||
\dir src/eap_common Common EAP functionality for server and peer
|
||||
|
||||
|
||||
\dir src/eap_peer EAP peer
|
||||
|
||||
|
||||
\dir src/eap_server EAP server
|
||||
|
||||
|
||||
\dir src/eapol_auth EAPOL authenticator
|
||||
|
||||
|
||||
\dir src/eapol_supp EAPOL supplicant
|
||||
|
||||
|
||||
\dir src/l2_packet Layer 2 packet interface
|
||||
|
||||
This module defines an interface for layer 2 (link layer) packet
|
||||
sendinf and receiving. All the wrappers for supported mechanisms are
|
||||
also included here. This is used to port packet access for new
|
||||
operating systems without having to make rest of the source code
|
||||
depend on which OS network stack is used.
|
||||
|
||||
|
||||
\dir src/radius RADIUS
|
||||
|
||||
RADIUS module includes RADIUS message building and parsing
|
||||
functionality and separate RADIUS client and server functions.
|
||||
|
||||
|
||||
\dir src/rsn_supp IEEE 802.11 RSN and WPA supplicant
|
||||
|
||||
|
||||
\dir src/tls Internal TLS server and client implementation
|
||||
|
||||
This module can be used as an alternative to using an external TLS
|
||||
library.
|
||||
|
||||
|
||||
\dir src/utils Utility functions
|
||||
|
||||
Independent set of helper functions that most other components
|
||||
use. This includes portability wrappers and helpers for common tasks.
|
||||
|
||||
|
||||
\dir src/wps Wi-Fi Protected Setup
|
||||
|
||||
This directory includes Wi-Fi Protected Setup functions for Registrar
|
||||
(both internal in an AP and an External Registrar and
|
||||
Enrollee. Minimal UPnP and HTTP functionality is also provided for the
|
||||
functionality needed to implement Wi-Fi Protected Setup.
|
||||
|
||||
|
||||
\dir wpa_supplicant wpa_supplicant
|
||||
|
||||
wpa_supplicant-specific code for configuration, control interface, and
|
||||
client management.
|
||||
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
@ -1,180 +0,0 @@
|
||||
/**
|
||||
\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
|
||||
|
||||
All hardware and driver dependent functionality is in separate C files
|
||||
that implement 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 (WE). Since features required for WPA were added only recently to
|
||||
Linux Wireless Extensions (in version 18), some driver specific code is used
|
||||
in number of driver interface implementations. These driver dependent parts
|
||||
can be replaced with generic code in \ref driver_wext.c once the target driver
|
||||
includes full support for WE-18. 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 \ref driver.h. These functions are registered by filling struct
|
||||
\ref wpa_driver_ops with function pointers. 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, \ref wpa_supplicant_event(), and its parameters are
|
||||
documented in \ref driver.h. In addition, a pointer to the 'struct
|
||||
\ref wpa_driver_ops' needs to be registered in \ref drivers.c file.
|
||||
|
||||
When porting to other operating systems, the 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 addressed on case by case
|
||||
basis 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. When changes are required, recommended way is to
|
||||
make them in backwards compatible way that allows existing driver
|
||||
interface implementations to be compiled without any modification.
|
||||
|
||||
Generic Linux Wireless Extensions functions are implemented in
|
||||
\ref 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.,
|
||||
\ref driver_hostap.c. These files need to define struct \ref wpa_driver_ops
|
||||
entry that will be used in \ref wpa_supplicant.c when calling driver
|
||||
functions. struct \ref wpa_driver_ops entries are registered in \ref drivers.c.
|
||||
|
||||
In general, it is likely to be useful to first take a look at couple
|
||||
of driver interface examples before starting on implementing a new
|
||||
one. \ref driver_hostap.c and \ref driver_wext.c include a complete
|
||||
implementation for Linux drivers that use wpa_supplicant-based control
|
||||
of WPA IE and roaming. \ref driver_ndis.c (with help from \ref 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.
|
||||
|
||||
|
||||
\section driver_req 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.
|
||||
|
||||
\subsection driver_tkip_ccmp 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 amendment). Fully functional, hardware independent
|
||||
implementation of both encryption protocols is also available in Host
|
||||
AP driver (driver/modules/hostap_{tkip,ccmp}.c). In addition, Linux 2.6
|
||||
kernel tree has generic implementations for WEP, TKIP, and CCMP that can
|
||||
be used in Linux drivers.
|
||||
|
||||
The driver will also need to provide configuration mechanism to allow
|
||||
user space programs to configure TKIP and CCMP. Linux Wireless Extensions
|
||||
v18 added support for configuring these algorithms and
|
||||
individual/non-default keys. If the target kernel does not include WE-18,
|
||||
private ioctls can be used to provide similar functionality.
|
||||
|
||||
\subsection driver_roaming Roaming control and scanning support
|
||||
|
||||
wpa_supplicant can optionally control AP selection based on the
|
||||
information received from Beacon and/or Probe Response frames
|
||||
(ap_scan=1 mode in configuration). 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 (\ref driver_wext.c) uses this for
|
||||
scan results.
|
||||
|
||||
Scan results must also include the WPA information element. Support for
|
||||
this was added in WE-18. With older versions, a custom event can be used
|
||||
to provide the full WPA IE (including element id and length) as a hex
|
||||
string that is included in the scan results.
|
||||
|
||||
wpa_supplicant needs to also be able to request the driver to
|
||||
associate with a specific BSS. Current Host AP driver and matching
|
||||
\ref 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)
|
||||
|
||||
\subsection driver_wpa_ie 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
|
||||
\ref driver.h). wpa_supplicant is normally configured to use
|
||||
ap_scan=2 mode with drivers that control WPA IE generation and roaming.
|
||||
|
||||
\subsection driver_events 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 \ref driver.h (\ref wpa_supplicant_event() function
|
||||
and enum \ref wpa_event_type).
|
||||
|
||||
On Linux, association and disassociation can use existing Wireless
|
||||
Extensions event that is reporting new AP with SIOCGIWAP
|
||||
event. Similarly, completion of a scan can be reported with SIOCGIWSCAN
|
||||
event.
|
||||
|
||||
Michael MIC failure event was added in WE-18. Older versions of Wireless
|
||||
Extensions will need to use a custom event. Host AP driver used a custom
|
||||
event with following contents: MLME-MICHAELMICFAILURE.indication(keyid=#
|
||||
broadcast/unicast addr=addr2). This is the recommended format until
|
||||
the driver can be moved to use WE-18 mechanism.
|
||||
|
||||
\subsection driver_wext_summary Summary of Linux Wireless Extensions use
|
||||
|
||||
AP selection depends on ap_scan configuration:
|
||||
|
||||
ap_scan=1:
|
||||
|
||||
- wpa_supplicant requests scan with SIOCSIWSCAN
|
||||
- driver reports scan complete with wireless event SIOCGIWSCAN
|
||||
- wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
|
||||
a larger buffer is needed)
|
||||
- wpa_supplicant decides which AP to use based on scan results
|
||||
- wpa_supplicant configures driver to associate with the selected BSS
|
||||
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,
|
||||
SIOCSIWESSID, SIOCSIWAP)
|
||||
|
||||
ap_scan=2:
|
||||
|
||||
- wpa_supplicant configures driver to associate with an SSID
|
||||
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID)
|
||||
|
||||
|
||||
After this, both modes use similar steps:
|
||||
|
||||
- optionally (or required for drivers that generate WPA/RSN IE for
|
||||
(Re)AssocReq), driver reports association parameters (AssocReq IEs)
|
||||
with wireless event IWEVASSOCREQIE (and optionally IWEVASSOCRESPIE)
|
||||
- driver reports association with wireless event SIOCGIWAP
|
||||
- wpa_supplicant takes care of EAPOL frame handling (validating
|
||||
information from associnfo and if needed, from scan results if WPA/RSN
|
||||
IE from the Beacon frame is not reported through associnfo)
|
||||
*/
|
@ -1,87 +0,0 @@
|
||||
/**
|
||||
\page eap_peer_module EAP peer implementation
|
||||
|
||||
Extensible Authentication Protocol (EAP) is an authentication framework
|
||||
defined in RFC 3748. wpa_supplicant uses a separate code module for EAP
|
||||
peer implementation. This module was designed to use only a minimal set
|
||||
of direct function calls (mainly, to debug/event functions) in order for
|
||||
it to be usable in other programs. The design of the EAP
|
||||
implementation is based loosely on RFC 4137. The state machine is
|
||||
defined in this RFC and so is the interface between the peer state
|
||||
machine and methods. As such, this RFC provides useful information for
|
||||
understanding the EAP peer implementation in wpa_supplicant.
|
||||
|
||||
Some of the terminology used in EAP state machine is referring to
|
||||
EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
|
||||
layer being IEEE 802.1X if EAP module is built for other programs than
|
||||
wpa_supplicant. These terms should be understood to refer to the
|
||||
lower layer as defined in RFC 4137.
|
||||
|
||||
|
||||
\section adding_eap_methods Adding EAP methods
|
||||
|
||||
Each EAP method is implemented as a separate module, usually as one C
|
||||
file named eap_<name of the method>.c, e.g., \ref eap_md5.c. All EAP
|
||||
methods use the same interface between the peer state machine and
|
||||
method specific functions. This allows new EAP methods to be added
|
||||
without modifying the core EAP state machine implementation.
|
||||
|
||||
New EAP methods need to be registered by adding them into the build
|
||||
(Makefile) and the EAP method registration list in the
|
||||
\ref eap_peer_register_methods() function of \ref eap_methods.c. Each EAP
|
||||
method should use a build-time configuration option, e.g., EAP_TLS, in
|
||||
order to make it possible to select which of the methods are included
|
||||
in the build.
|
||||
|
||||
EAP methods must implement the interface defined in \ref eap_i.h. struct
|
||||
\ref eap_method defines the needed function pointers that each EAP method
|
||||
must provide. In addition, the EAP type and name are registered using
|
||||
this structure. This interface is based on section 4.4 of RFC 4137.
|
||||
|
||||
It is recommended that the EAP methods would use generic helper
|
||||
functions, \ref eap_msg_alloc() and \ref eap_hdr_validate() when processing
|
||||
messages. This allows code sharing and can avoid missing some of the
|
||||
needed validation steps for received packets. In addition, these
|
||||
functions make it easier to change between expanded and legacy EAP
|
||||
header, if needed.
|
||||
|
||||
When adding an EAP method that uses a vendor specific EAP type
|
||||
(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
|
||||
must be registered by passing vendor id instead of EAP_VENDOR_IETF to
|
||||
\ref eap_peer_method_alloc(). These methods must not try to emulate
|
||||
expanded types by registering a legacy EAP method for type 254. See
|
||||
\ref eap_vendor_test.c for an example of an EAP method implementation that
|
||||
is implemented as an expanded type.
|
||||
|
||||
|
||||
\section used_eap_library Using EAP implementation as a library
|
||||
|
||||
The Git repository has an eap_example directory that contains an
|
||||
example showing how EAP peer and server code from wpa_supplicant and
|
||||
hostapd can be used as a library. The example program initializes both
|
||||
an EAP server and an EAP peer entities and then runs through an
|
||||
EAP-PEAP/MSCHAPv2 authentication.
|
||||
|
||||
\ref eap_example_peer.c shows the initialization and glue code needed to
|
||||
control the EAP peer implementation. \ref eap_example_server.c does the
|
||||
same for EAP server. \ref eap_example.c is an example that ties in both the
|
||||
EAP server and client parts to allow an EAP authentication to be
|
||||
shown.
|
||||
|
||||
In this example, the EAP messages are passed between the server and
|
||||
the peer are passed by direct function calls within the same process.
|
||||
In practice, server and peer functionalities would likely reside in
|
||||
separate devices and the EAP messages would be transmitted between the
|
||||
devices based on an external protocol. For example, in IEEE 802.11
|
||||
uses IEEE 802.1X EAPOL state machines to control the transmission of
|
||||
EAP messages and WiMax supports optional PMK EAP authentication
|
||||
mechanism that transmits EAP messages as defined in IEEE 802.16e.
|
||||
|
||||
The EAP library links in number of helper functions from \ref src/utils and
|
||||
\ref src/crypto directories. Most of these are suitable as-is, but it may
|
||||
be desirable to replace the debug output code in \ref src/utils/wpa_debug.c
|
||||
by dropping this file from the library and re-implementing the
|
||||
functions there in a way that better fits in with the main
|
||||
application.
|
||||
|
||||
*/
|
@ -1,56 +0,0 @@
|
||||
/**
|
||||
\page eap_server_module EAP server implementation
|
||||
|
||||
Extensible Authentication Protocol (EAP) is an authentication framework
|
||||
defined in RFC 3748. hostapd uses a separate code module for EAP server
|
||||
implementation. This module was designed to use only a minimal set of
|
||||
direct function calls (mainly, to debug/event functions) in order for
|
||||
it to be usable in other programs. The design of the EAP
|
||||
implementation is based loosely on RFC 4137. The state machine is
|
||||
defined in this RFC and so is the interface between the server state
|
||||
machine and methods. As such, this RFC provides useful information for
|
||||
understanding the EAP server implementation in hostapd.
|
||||
|
||||
Some of the terminology used in EAP state machine is referring to
|
||||
EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
|
||||
layer being IEEE 802.1X if EAP module is built for other programs than
|
||||
wpa_supplicant. These terms should be understood to refer to the
|
||||
lower layer as defined in RFC 4137.
|
||||
|
||||
|
||||
\section adding_eap_methods Adding EAP methods
|
||||
|
||||
Each EAP method is implemented as a separate module, usually as one C
|
||||
file named eap_server_<name of the method>.c, e.g., \ref eap_server_md5.c. All EAP
|
||||
methods use the same interface between the server state machine and
|
||||
method specific functions. This allows new EAP methods to be added
|
||||
without modifying the core EAP state machine implementation.
|
||||
|
||||
New EAP methods need to be registered by adding them into the build
|
||||
(Makefile) and the EAP method registration list in the
|
||||
\ref eap_server_register_methods() function of \ref eap_server_methods.c. Each EAP
|
||||
method should use a build-time configuration option, e.g., EAP_TLS, in
|
||||
order to make it possible to select which of the methods are included
|
||||
in the build.
|
||||
|
||||
EAP methods must implement the interface defined in \ref eap_i.h. struct
|
||||
\ref eap_method defines the needed function pointers that each EAP method
|
||||
must provide. In addition, the EAP type and name are registered using
|
||||
this structure. This interface is based on section 4.4 of RFC 4137.
|
||||
|
||||
It is recommended that the EAP methods would use generic helper
|
||||
functions, \ref eap_msg_alloc() and \ref eap_hdr_validate() when processing
|
||||
messages. This allows code sharing and can avoid missing some of the
|
||||
needed validation steps for received packets. In addition, these
|
||||
functions make it easier to change between expanded and legacy EAP
|
||||
header, if needed.
|
||||
|
||||
When adding an EAP method that uses a vendor specific EAP type
|
||||
(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
|
||||
must be registered by passing vendor id instead of EAP_VENDOR_IETF to
|
||||
\ref eap_server_method_alloc(). These methods must not try to emulate
|
||||
expanded types by registering a legacy EAP method for type 254. See
|
||||
\ref eap_server_vendor_test.c for an example of an EAP method implementation that
|
||||
is implemented as an expanded type.
|
||||
|
||||
*/
|
@ -1,264 +0,0 @@
|
||||
#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 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 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 2775 3150 4050 3450
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
|
||||
-6
|
||||
6 3450 1200 4575 1500
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\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
|
||||
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
|
||||
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 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 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
|
||||
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 795 9375 5700 EAP-PAX\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 8700 3450 9375 3750
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
|
||||
4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
|
||||
-6
|
||||
6 9600 3450 10275 3750
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
|
||||
-6
|
||||
6 6000 5775 7200 6300
|
||||
6 6000 5775 7200 6300
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
|
||||
-6
|
||||
4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
|
||||
-6
|
||||
6 8100 2250 8925 2775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
|
||||
-6
|
||||
6 3150 5475 4425 5775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
|
||||
-6
|
||||
6 1950 5550 2625 6075
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
|
||||
-6
|
||||
6 1875 4725 2925 5250
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\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 3750
|
||||
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7200 3000 8700 3525
|
||||
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 3675
|
||||
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 3750
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
|
||||
4350 3900
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4350 3900 4050 3450
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4350 4425 4050 5475
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
6600 5475 6600 5775
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5025 4425 6000 5775
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||
4800 3900 5925 2550 8100 2550
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7200 3900 8475 2775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
8925 2475 9450 2475
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
2325 5550 2325 5250
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
2925 4950 4350 4275
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||
2850 4725 5775 2400 8100 2400
|
||||
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 720 1637 2371 hostapd\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 nl80211\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001
|
@ -1,66 +0,0 @@
|
||||
/**
|
||||
\page hostapd_ctrl_iface_page hostapd control interface
|
||||
|
||||
hostapd implements a control interface that can be used by
|
||||
external programs to control the operations of the hostapd
|
||||
daemon and to get status information and event notifications. There is
|
||||
a small C library, in a form of a single C file, \ref wpa_ctrl.c, that
|
||||
provides helper functions to facilitate the use of the control
|
||||
interface. External programs can link this file into them and then use
|
||||
the library functions documented in \ref wpa_ctrl.h to interact with
|
||||
wpa_supplicant. This library can also be used with C++. \ref hostapd_cli.c
|
||||
is an example program using this library.
|
||||
|
||||
There are multiple mechanisms for inter-process communication. For
|
||||
example, Linux version of hostapd is using UNIX domain sockets for the
|
||||
control interface. The use of the functions defined in \ref wpa_ctrl.h can
|
||||
be used to hide the details of the used IPC from external programs.
|
||||
|
||||
|
||||
\section using_ctrl_iface Using the control interface
|
||||
|
||||
External programs, e.g., a GUI or a configuration utility, that need to
|
||||
communicate with hostapd should link in \ref wpa_ctrl.c. This
|
||||
allows them to use helper functions to open connection to the control
|
||||
interface with \ref wpa_ctrl_open() and to send commands with
|
||||
\ref wpa_ctrl_request().
|
||||
|
||||
hostapd uses the control interface for two types of communication:
|
||||
commands and unsolicited event messages. Commands are a pair of
|
||||
messages, a request from the external program and a response from
|
||||
hostapd. These can be executed using \ref wpa_ctrl_request().
|
||||
Unsolicited event messages are sent by hostapd to the control
|
||||
interface connection without specific request from the external program
|
||||
for receiving each message. However, the external program needs to
|
||||
attach to the control interface with \ref wpa_ctrl_attach() to receive these
|
||||
unsolicited messages.
|
||||
|
||||
If the control interface connection is used both for commands and
|
||||
unsolicited event messages, there is potential for receiving an
|
||||
unsolicited message between the command request and response.
|
||||
\ref wpa_ctrl_request() caller will need to supply a callback, msg_cb,
|
||||
for processing these messages. Often it is easier to open two
|
||||
control interface connections by calling \ref wpa_ctrl_open() twice and
|
||||
then use one of the connections for commands and the other one for
|
||||
unsolicited messages. This way command request/response pairs will
|
||||
not be broken by unsolicited messages. \ref wpa_cli.c is an example of how
|
||||
to use only one connection for both purposes and wpa_gui demonstrates
|
||||
how to use two separate connections.
|
||||
|
||||
Once the control interface connection is not needed anymore, it should
|
||||
be closed by calling \ref wpa_ctrl_close(). If the connection was used for
|
||||
unsolicited event messages, it should be first detached by calling
|
||||
\ref wpa_ctrl_detach().
|
||||
|
||||
|
||||
\section ctrl_iface_cmds Control interface commands
|
||||
|
||||
Following commands can be used with \ref wpa_ctrl_request():
|
||||
|
||||
\subsection ctrl_iface_PING PING
|
||||
|
||||
This command can be used to test whether hostapd is replying
|
||||
to the control interface commands. The expected reply is \c PONG if the
|
||||
connection is open and hostapd is processing commands.
|
||||
|
||||
*/
|
@ -1,95 +0,0 @@
|
||||
/**
|
||||
\mainpage Developers' documentation for wpa_supplicant and hostapd
|
||||
|
||||
The goal of this documentation and comments in the source code is to
|
||||
give enough information for other developers to understand how
|
||||
wpa_supplicant and hostapd have been implemented, how they can be
|
||||
modified, how new drivers can be supported, and how the source code
|
||||
can be ported to other operating systems. If any information is
|
||||
missing, feel free to contact Jouni Malinen <j@w1.fi> for more
|
||||
information. Contributions as patch files are also very welcome at the
|
||||
same address. Please note that this software is licensed under the
|
||||
BSD license (the one with advertisement clause removed). All
|
||||
contributions to wpa_supplicant and hostapd are expected to use
|
||||
compatible licensing terms.
|
||||
|
||||
The source code and read-only access to the combined wpa_supplicant
|
||||
and hostapd Git repository is available from the project home page at
|
||||
http://w1.fi/wpa_supplicant/. This developers' documentation is also
|
||||
available as a PDF file from
|
||||
http://w1.fi/wpa_supplicant/wpa_supplicant-devel.pdf .
|
||||
|
||||
|
||||
\section _wpa_supplicant wpa_supplicant
|
||||
|
||||
wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
|
||||
support for WPA and WPA2 (IEEE 802.11i / RSN). Supplicant is the IEEE
|
||||
802.1X/WPA component that is used in the client stations. It
|
||||
implements key negotiation with a WPA Authenticator and it can optionally
|
||||
control roaming and IEEE 802.11 authentication/association of the wlan
|
||||
driver.
|
||||
|
||||
The design goal for wpa_supplicant was to use hardware, driver, and
|
||||
OS independent, portable C code for all WPA functionality. The source
|
||||
code is divided into separate C files as shown on the \ref
|
||||
code_structure "code structure page". All hardware/driver specific
|
||||
functionality is in separate files that implement a \ref
|
||||
driver_wrapper "well-defined driver API". Information about porting
|
||||
to different target boards and operating systems is available on
|
||||
the \ref porting "porting page".
|
||||
|
||||
EAPOL (IEEE 802.1X) state machines are implemented as a separate
|
||||
module that interacts with \ref eap_peer_module "EAP peer implementation".
|
||||
In addition to programs aimed at normal production use,
|
||||
wpa_supplicant source tree includes number of \ref testing_tools
|
||||
"testing and development tools" that make it easier to test the
|
||||
programs without having to setup a full test setup with wireless
|
||||
cards. These tools can also be used to implement automatic test
|
||||
suites.
|
||||
|
||||
wpa_supplicant implements a
|
||||
\ref ctrl_iface_page "control interface" that can be used by
|
||||
external programs to control the operations of the wpa_supplicant
|
||||
daemon and to get status information and event notifications. There is
|
||||
a small C library that provides helper functions to facilitate the use of the
|
||||
control interface. This library can also be used with C++.
|
||||
|
||||
\image html _wpa_supplicant.png "wpa_supplicant modules"
|
||||
\image latex _wpa_supplicant.eps "wpa_supplicant modules" width=15cm
|
||||
|
||||
|
||||
\section _hostapd hostapd
|
||||
|
||||
hostapd includes IEEE 802.11 access point management (authentication /
|
||||
association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
|
||||
RADIUS authentication server functionality. It can be build with
|
||||
various configuration option, e.g., a standalone AP management
|
||||
solution or a RADIUS authentication server with support for number of
|
||||
EAP methods.
|
||||
|
||||
The design goal for hostapd was to use hardware, driver, and
|
||||
OS independent, portable C code for all WPA functionality. The source
|
||||
code is divided into separate C files as shown on the \ref
|
||||
code_structure "code structure page". All hardware/driver specific
|
||||
functionality is in separate files that implement a \ref
|
||||
driver_wrapper "well-defined driver API". Information about porting
|
||||
to different target boards and operating systems is available on
|
||||
the \ref porting "porting page".
|
||||
|
||||
EAPOL (IEEE 802.1X) state machines are implemented as a separate
|
||||
module that interacts with \ref eap_server_module "EAP server implementation".
|
||||
Similarly, RADIUS authentication server is in its own separate module.
|
||||
Both IEEE 802.1X and RADIUS authentication server can use EAP server
|
||||
functionality.
|
||||
|
||||
hostapd implements a \ref hostapd_ctrl_iface_page "control interface"
|
||||
that can be used by external programs to control the operations of the
|
||||
hostapdt daemon and to get status information and event notifications.
|
||||
There is a small C library that provides helper functions to facilitate
|
||||
the use of the control interface. This library can also be used with
|
||||
C++.
|
||||
|
||||
\image html hostapd.png "hostapd modules"
|
||||
\image latex hostapd.eps "hostapd modules" width=15cm
|
||||
|
||||
*/
|
@ -1,471 +0,0 @@
|
||||
/**
|
||||
\page p2p Wi-Fi Direct - P2P module
|
||||
|
||||
Wi-Fi Direct functionality is implemented any many levels in the WLAN
|
||||
stack from low-level driver operations to high-level GUI design. This
|
||||
document covers the parts that can be user by wpa_supplicant. However,
|
||||
it should be noted that alternative designs are also possible, so some
|
||||
of the functionality may reside in other components in the system.
|
||||
|
||||
The driver (or WLAN firmware/hardware) is expected to handle low-level
|
||||
operations related to P2P Power Management and channel scheduling. In
|
||||
addition, support for virtual network interface and data frame
|
||||
processing is done inside the driver. Configuration for these
|
||||
low-level operations is defined in the driver interface:
|
||||
src/drivers/driver.h. This defines both the commands and events used to
|
||||
interact with the driver.
|
||||
|
||||
P2P module implements higher layer functionality for management P2P
|
||||
groups. It takes care of Device Discovery, Service Discovery, Group
|
||||
Owner Negotiation, P2P Invitation. In addition, it maintains
|
||||
information about neighboring P2P Devices. This module could be used
|
||||
in designs that do not use wpa_supplicant and it could also reside
|
||||
inside the driver/firmware component. P2P module API is defined in
|
||||
\ref src/p2p/p2p.h.
|
||||
|
||||
Provisioning step of Group Formation is implemented using WPS
|
||||
(\ref src/wps/wps.h).
|
||||
|
||||
wpa_supplicant includes code in interact with both the P2P module
|
||||
(\ref wpa_supplicant/p2p_supplicant.c) and WPS
|
||||
(\ref wpa_supplicant/wps_supplicant.c). The driver operations are passed
|
||||
through these files, i.e., core P2P or WPS code does not interact
|
||||
directly with the driver interface.
|
||||
|
||||
|
||||
\section p2p_arch P2P architecture
|
||||
|
||||
P2P functionality affects many areas of the system architecture. This
|
||||
section shows couple of examples on the location of main P2P
|
||||
components. In the diagrams below, green arrows are used to show
|
||||
communication paths from the P2P module to upper layer management
|
||||
functionality and all the way to a GUI that user could use to manage
|
||||
P2P connections. Blue arrows show the path taken for lower layer
|
||||
operations. Glue code is used to bind the P2P module API to the rest
|
||||
of the system to provide access both towards upper and lower layer
|
||||
functionality.
|
||||
|
||||
\subsection p2p_arch_mac80211 P2P architecture with Linux/mac80211/ath9k
|
||||
|
||||
An architecture where the P2P module resides inside the
|
||||
wpa_supplicant process is used with Linux mac80211-based drivers,
|
||||
e.g., ath9k. The following diagram shows the main components related
|
||||
to P2P functionality in such an architecture.
|
||||
|
||||
\image html p2p_arch.png "P2P module within wpa_supplicant"
|
||||
\image latex p2p_arch.eps "P2P module within wpa_supplicant" width=15cm
|
||||
|
||||
\subsection p2p_arch_umac P2P architecture with UMAC
|
||||
|
||||
The following diagram shows the main components related to P2P
|
||||
functionality in an architecture where the P2P module resides inside
|
||||
the kernel IEEE 802.11 stack (UMAC in the figure).
|
||||
|
||||
\image html p2p_arch2.png "P2P module in kernel
|
||||
\image latex p2p_arch2.eps "P2P module in kernel" width=15cm
|
||||
|
||||
|
||||
\section p2p_module P2P module
|
||||
|
||||
P2P module manages discovery and group formation with a single state
|
||||
machine, i.e., only a single operation per device can be in progress
|
||||
at any given time. The following diagram describes the P2P state
|
||||
machine. For clarity, it does not include state transitions on
|
||||
operation timeouts to the IDLE state. The states that are marked with
|
||||
dotted ellipse are listed for clarity to describe the protocol
|
||||
functionality for Device Discovery phase, but are not used in the
|
||||
implementation (the SEARCH state is used to manage the initial Scan
|
||||
and the alternating Listen and Search states within Find).
|
||||
|
||||
\image html p2p_sm.png "P2P module state machine"
|
||||
\image latex p2p_sm.eps "P2P module state machine" width=15cm
|
||||
|
||||
\subsection p2p_module_api P2P module API
|
||||
|
||||
P2P module API is defined in \ref src/p2p/p2p.h. The API consists of
|
||||
functions for requesting operations and for providing event
|
||||
notifications. Similar set of callback functions are configured with
|
||||
struct p2p_config to provide callback functions that P2P module can
|
||||
use to request operations and to provide event notifications. In
|
||||
addition, there are number of generic helper functions that can be
|
||||
used for P2P related operations.
|
||||
|
||||
These are the main functions for an upper layer management entity to
|
||||
request P2P operations:
|
||||
- \ref p2p_find()
|
||||
- \ref p2p_stop_find()
|
||||
- \ref p2p_listen()
|
||||
- \ref p2p_connect()
|
||||
- \ref p2p_reject()
|
||||
- \ref p2p_prov_disc_req()
|
||||
- \ref p2p_sd_request()
|
||||
- \ref p2p_sd_cancel_request()
|
||||
- \ref p2p_sd_response()
|
||||
- \ref p2p_sd_service_update()
|
||||
- \ref p2p_invite()
|
||||
|
||||
These are the main callback functions for P2P module to provide event
|
||||
notifications to the upper layer management entity:
|
||||
|
||||
- \ref p2p_config::dev_found()
|
||||
- \ref p2p_config::go_neg_req_rx()
|
||||
- \ref p2p_config::go_neg_completed()
|
||||
- \ref p2p_config::sd_request()
|
||||
- \ref p2p_config::sd_response()
|
||||
- \ref p2p_config::prov_disc_req()
|
||||
- \ref p2p_config::prov_disc_resp()
|
||||
- \ref p2p_config::invitation_process()
|
||||
- \ref p2p_config::invitation_received()
|
||||
- \ref p2p_config::invitation_result()
|
||||
|
||||
The P2P module uses following functions to request lower layer driver
|
||||
operations:
|
||||
|
||||
- \ref p2p_config::p2p_scan()
|
||||
- \ref p2p_config::send_probe_resp()
|
||||
- \ref p2p_config::send_action()
|
||||
- \ref p2p_config::send_action_done()
|
||||
- \ref p2p_config::start_listen()
|
||||
- \ref p2p_config::stop_listen()
|
||||
|
||||
Events from lower layer driver operations are delivered to the P2P
|
||||
module with following functions:
|
||||
|
||||
- \ref p2p_probe_req_rx()
|
||||
- \ref p2p_rx_action()
|
||||
- \ref p2p_scan_res_handler()
|
||||
- \ref p2p_scan_res_handled()
|
||||
- \ref p2p_send_action_cb()
|
||||
- \ref p2p_listen_cb()
|
||||
|
||||
In addition to the per-device state, the P2P module maintains
|
||||
per-group state for group owners. This is initialized with a call to
|
||||
p2p_group_init() when a group is created and deinitialized with
|
||||
p2p_group_deinit(). The upper layer GO management entity uses
|
||||
following functions to interact with the P2P per-group state:
|
||||
|
||||
- \ref p2p_group_notif_assoc()
|
||||
- \ref p2p_group_notif_disassoc()
|
||||
- \ref p2p_group_notif_formation_done()
|
||||
- \ref p2p_group_match_dev_type()
|
||||
|
||||
The P2P module will use following callback function to update P2P IE
|
||||
for GO Beacon and Probe Response frames:
|
||||
|
||||
- \ref p2p_group_config::ie_update()
|
||||
|
||||
|
||||
\section p2p_driver P2P driver operations (low-level interface)
|
||||
|
||||
The following driver wrapper functions are needed for P2P in addition
|
||||
to the standard station/AP mode operations when the P2P module resides
|
||||
within wpa_supplicant:
|
||||
- \ref wpa_driver_ops::if_add()
|
||||
- \ref wpa_driver_ops::if_remove()
|
||||
- \ref wpa_driver_ops::remain_on_channel()
|
||||
- \ref wpa_driver_ops::cancel_remain_on_channel()
|
||||
- \ref wpa_driver_ops::send_action()
|
||||
- \ref wpa_driver_ops::probe_req_report()
|
||||
|
||||
The following driver wrapper events are needed for P2P in addition to
|
||||
the standard station/AP mode events when the P2P module resides within
|
||||
wpa_supplicant:
|
||||
- \ref wpa_event_type::EVENT_RX_MGMT
|
||||
- \ref wpa_event_type::EVENT_REMAIN_ON_CHANNEL
|
||||
- \ref wpa_event_type::EVENT_CANCEL_REMAIN_ON_CHANNEL
|
||||
- \ref wpa_event_type::EVENT_RX_PROBE_REQ
|
||||
|
||||
|
||||
\section p2p_go_neg P2P device discovery and group formation
|
||||
|
||||
This section shows an example sequence of operations that can be used
|
||||
to implement P2P device discovery and group formation. The function
|
||||
calls are described based on the P2P module API. The exact design for
|
||||
the glue code outside the P2P module depends on the architecture used
|
||||
in the system.
|
||||
|
||||
An upper layer management entity starts P2P device discovery by
|
||||
calling \ref p2p_find(). The P2P module start the discovery by requesting a
|
||||
full scan to be completed by calling \ref p2p_config::p2p_scan(). Results
|
||||
from the scan will be reported by calling \ref p2p_scan_res_handler() and
|
||||
after last result, the scan result processing is terminated with a
|
||||
call to \ref p2p_scan_res_handled(). The P2P peers that are found during
|
||||
the full scan are reported with the \ref p2p_config::dev_found() callback.
|
||||
|
||||
After the full scan, P2P module start alternating between Listen and
|
||||
Search states until the device discovery operation times out or
|
||||
terminated, e.g., with a call to \ref p2p_stop_find().
|
||||
|
||||
When going into the Listen state, the P2P module requests the driver
|
||||
to be configured to be awake on the listen channel with a call to
|
||||
\ref p2p_config::start_listen(). The glue code using the P2P module may
|
||||
implement this, e.g., by using remain-on-channel low-level driver
|
||||
functionality for off-channel operation. Once the driver is available
|
||||
on the requested channel, notification of this is delivered by calling
|
||||
\ref p2p_listen_cb(). The Probe Request frames that are received during the
|
||||
Listen period are delivered to the P2P module by calling
|
||||
\ref p2p_config::p2p_probe_req_rx() and P2P module request a response to
|
||||
these to be sent by using \ref p2p_config::send_probe_resp() callback
|
||||
function. If a group owner negotiation from another P2P device is
|
||||
received during the device discovery phase, that is indicated to the
|
||||
upper layer code with the \ref p2p_config::go_neg_req_tx() callback.
|
||||
|
||||
The Search state is implemented by using the normal scan interface,
|
||||
i.e., the P2P module will call \ref p2p_config::p2p_scan() just like in the
|
||||
full scan phase described. Similarly, scan results from the search
|
||||
operation will be delivered to the P2P module using the
|
||||
\ref p2p_scan_res_handler() and \ref p2p_scan_res_handled() functions.
|
||||
|
||||
Once the upper layer management entity has found a peer with which it
|
||||
wants to connect by forming a new group, it initiates group owner
|
||||
negotiation by calling \ref p2p_connect(). Before doing this, the upper
|
||||
layer code is responsible for asking the user to provide the PIN to be
|
||||
used during the provisioning step with the peer or the push button
|
||||
press for PBC mode. The glue code will need to figure out the intended
|
||||
interface address for the group before group owner negotiation can be
|
||||
started.
|
||||
|
||||
Optional Provision Discovery mechanism can be used to request the peer
|
||||
to display a PIN for the local device to enter (and vice versa). Upper
|
||||
layer management entity can request the specific mechanism by calling
|
||||
\ref p2p_prov_disc_req(). The response to this will be reported with the
|
||||
\ref p2p_config::prov_disc_resp() callback. If the peer device started
|
||||
Provision Discovery, an accepted request will be reported with the
|
||||
\ref p2p_config::prov_disc_req() callback. The P2P module will
|
||||
automatically accept the Provision Discovery for display and keypad
|
||||
methods, but it is up to the upper layer manegement entity to actually
|
||||
generate the PIN and to configure it with following \ref p2p_connect() call
|
||||
to actually authorize the connection.
|
||||
|
||||
The P2P module will use \ref p2p_config::send_action() callback to request
|
||||
lower layer code to transmit an Action frame during group owner
|
||||
negotiation. \ref p2p_send_action_cb() is used to report the result of
|
||||
transmission. If the peer is not reachable, the P2P module will try to
|
||||
find it by alternating between Action frame send and Listen
|
||||
states. The Listen state for this phase will be used similarly to the
|
||||
Listen state during device discovery as described above.
|
||||
|
||||
Once the group owner negotiation has been completed, its results will
|
||||
be reported with the \ref p2p_config::go_neg_completed() callback. The
|
||||
upper layer management code or the glue code using the P2P module API
|
||||
is responsible for creating a new group interface and starting
|
||||
provisioning step at this point by configuring WPS Registrar or
|
||||
Enrollee functionality based on the reported group owner negotiation
|
||||
results. The upper layer code is also responsible for timing out WPS
|
||||
provisioning if it cannot be completed in 15 seconds.
|
||||
|
||||
Successful completion of the WPS provisioning is reported with a call
|
||||
to \ref p2p_wps_success_cb(). The P2P module will clear its group formation
|
||||
state at this point and allows new group formation attempts to be
|
||||
started. The upper layer management code is responsible for configuring
|
||||
the GO to accept associations from devices and the client to connect to
|
||||
the GO with the provisioned credentials. GO is also responsible for
|
||||
calling \ref p2p_group_notif_formation_done() as described below.
|
||||
|
||||
If the WPS provisioning step fails or times out, this is reported with
|
||||
a call to \ref p2p_group_formation_failed(). The P2P module will clear its
|
||||
group formation state at this point and allows new group formation
|
||||
attempts to be started. The upper layer management code is responsible
|
||||
for removing the group interface for the failed group.
|
||||
|
||||
|
||||
\section p2p_sd P2P service discovery
|
||||
|
||||
P2P protocol includes service discovery functionality that can be used
|
||||
to discover which services are provided by the peers before forming a
|
||||
group. This leverages the Generic Advertisement Service (GAS) protocol
|
||||
from IEEE 802.11u and P2P vendor-specific contents inside the Native
|
||||
GAS messages.
|
||||
|
||||
The P2P module takes care of GAS encapsulation, fragmentation, and
|
||||
actual transmission and reception of the Action frames needed for
|
||||
service discovery. The user of the P2P module is responsible for
|
||||
providing P2P specific Service Request TLV(s) for queries and Service
|
||||
Response TLV(s) for responses.
|
||||
|
||||
\subsection p2p_sd_query Querying services of peers
|
||||
|
||||
Service discovery is implemented by processing pending queries as a
|
||||
part of the device discovery phase. \ref p2p_sd_request() function is used
|
||||
to schedule service discovery queries to a specific peer or to all
|
||||
discovered peers. \ref p2p_sd_cancel_request() can be used to cancel a
|
||||
scheduled query. Queries that are specific to a single peer will be
|
||||
removed automatically after the response has been received.
|
||||
|
||||
After the service discovery queries have been queued, device discovery
|
||||
is started with a call to \ref p2p_find(). The pending service discovery
|
||||
queries are then sent whenever a peer is discovered during the find
|
||||
operation. Responses to the queries will be reported with the
|
||||
\ref p2p_config::sd_response() callback.
|
||||
|
||||
\subsection p2p_sd_response Replying to service discovery queries from peers
|
||||
|
||||
The received service discovery requests will be indicated with the
|
||||
\ref p2p_config::sd_request() callback. The response to the query is sent
|
||||
by calling \ref p2p_sd_response().
|
||||
|
||||
\subsection p2p_sd_indicator Service update indicator
|
||||
|
||||
P2P service discovery provides a mechanism to notify peers about
|
||||
changes in available services. This works by incrementing Service
|
||||
Update Indicator value whenever there is a change in the
|
||||
services. This value is included in all SD request and response
|
||||
frames. The value received from the peers will be included in the
|
||||
\ref p2p_config::sd_request() and \ref p2p_config::sd_response() callbacks. The
|
||||
value to be sent to the peers is incremented with a call to
|
||||
\ref p2p_sd_service_update() whenever availability of the local services
|
||||
changes.
|
||||
|
||||
|
||||
\section p2p_go P2P group owner
|
||||
|
||||
This section describes how P2P module can be used for managing
|
||||
per-group information in a group owner. The function calls are
|
||||
described based on the P2P module API. The exact design for the glue
|
||||
code outside the P2P module depends on the architecture used in the
|
||||
system.
|
||||
|
||||
When a P2P group interface is created in group owner role, per-group
|
||||
data is initialized with \ref p2p_group_init(). This call provides a
|
||||
pointer to the per-device P2P module context and configures the
|
||||
per-group operation. The configured \ref p2p_group_config::ie_update()
|
||||
callback is used to set the initial P2P IE for Beacon and Probe
|
||||
Response frames in the group owner. The AP mode implementation may use
|
||||
this information to add IEs into the frames.
|
||||
|
||||
Once the group formation has been completed (or if it is skipped in
|
||||
case of manual group setup), \ref p2p_group_notif_formation_done() is
|
||||
called. This will allow the P2P module to update the P2P IE for
|
||||
Beacon and Probe Response frames.
|
||||
|
||||
The SME/MLME code that managements IEEE 802.11 association processing
|
||||
needs to inform P2P module whenever a P2P client associates or
|
||||
disassociates with the group. This is done by calling
|
||||
\ref p2p_group_notif_assoc() and \ref p2p_group_notif_disassoc(). The P2P module
|
||||
manages a list of group members and updates the P2P Group Information
|
||||
subelement in the P2P IE based on the information from the P2P
|
||||
clients. The \ref p2p_group_config::ie_update() callback is used whenever
|
||||
the P2P IE in Probe Response frames needs to be changed.
|
||||
|
||||
The SME/MLME code that takes care of replying to Probe Request frames
|
||||
can use \ref p2p_group_match_dev_type() to check whether the Probe Request
|
||||
frame request a reply only from groups that include a specific device
|
||||
type in one of the clients or GO. A match will be reported if the
|
||||
Probe Request does not request a specific device type, so this
|
||||
function can be used to filter or received Probe Request frames and
|
||||
only the ones that result in non-zero return value need to be replied.
|
||||
|
||||
When the P2P group interface for GO role is removed,
|
||||
\ref p2p_group_deinit() is used to deinitialize the per-group P2P module
|
||||
state.
|
||||
|
||||
|
||||
\section p2p_ctrl_iface P2P control interface
|
||||
|
||||
wpa_supplicant \ref ctrl_iface_page "control interface" can be used
|
||||
to manage P2P functionality from an external program (e.g., a GUI or a
|
||||
system configuration manager). This interface can be used directly
|
||||
through the control interface backend mechanism (e.g., local domain
|
||||
sockets on Linux) or with help of wpa_cli (e.g., from a script).
|
||||
|
||||
The following P2P-related commands are available:
|
||||
- \ref ctrl_iface_P2P_FIND P2P_FIND
|
||||
- \ref ctrl_iface_P2P_STOP_FIND P2P_STOP_FIND
|
||||
- \ref ctrl_iface_P2P_CONNECT P2P_CONNECT
|
||||
- \ref ctrl_iface_P2P_LISTEN P2P_LISTEN
|
||||
- \ref ctrl_iface_P2P_GROUP_REMOVE P2P_GROUP_REMOVE
|
||||
- \ref ctrl_iface_P2P_GROUP_ADD P2P_GROUP_ADD
|
||||
- \ref ctrl_iface_P2P_PROV_DISC P2P_PROV_DISC
|
||||
- \ref ctrl_iface_P2P_SERV_DISC_REQ P2P_SERV_DISC_REQ
|
||||
- \ref ctrl_iface_P2P_SERV_DISC_CANCEL_REQ P2P_SERV_DISC_CANCEL_REQ
|
||||
- \ref ctrl_iface_P2P_SERV_DISC_RESP P2P_SERV_DISC_RESP
|
||||
- \ref ctrl_iface_P2P_SERVICE_UPDATE P2P_SERVICE_UPDATE
|
||||
- \ref ctrl_iface_P2P_SERV_DISC_EXTERNAL P2P_SERV_DISC_EXTERNAL
|
||||
- \ref ctrl_iface_P2P_REJECT P2P_REJECT
|
||||
- \ref ctrl_iface_P2P_INVITE P2P_INVITE
|
||||
|
||||
The following P2P-related events are used:
|
||||
- \ref ctrl_iface_event_P2P_EVENT_DEVICE_FOUND P2P-DEVICE-FOUND
|
||||
- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_REQUEST P2P-GO-NEG-REQUEST
|
||||
- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_SUCCESS P2P-GO-NEG-SUCCESS
|
||||
- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_FAILURE P2P-GO-NEG-FAILURE
|
||||
- \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_SUCCESS P2P-GROUP-FORMATION-SUCCESS
|
||||
- \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_FAILURE P2P-GROUP-FORMATION-FAILURE
|
||||
- \ref ctrl_iface_event_P2P_EVENT_GROUP_STARTED P2P-GROUP-STARTED
|
||||
- \ref ctrl_iface_event_P2P_EVENT_GROUP_REMOVED P2P-GROUP-REMOVED
|
||||
- \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_SHOW_PIN P2P-PROV-DISC-SHOW-PIN
|
||||
- \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_ENTER_PIN P2P-PROV-DISC-ENTER-PIN
|
||||
- \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_REQ P2P-SERV-DISC-REQ
|
||||
- \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_RESP P2P-SERV-DISC-RESP
|
||||
- \ref ctrl_iface_event_P2P_EVENT_INVITATION_RECEIVED P2P-INVITATION-RECEIVED
|
||||
- \ref ctrl_iface_event_P2P_EVENT_INVITATION_RESULT P2P-INVITATION-RESULT
|
||||
|
||||
|
||||
\subsection p2p_wpa_gui GUI example (wpa_gui)
|
||||
|
||||
wpa_gui has an example implementation of a GUI that could be used to
|
||||
manage P2P operations. The P2P related functionality is contained
|
||||
mostly in wpa_supplicant/wpa_gui-qt4/peers.cpp and it shows how the
|
||||
control interface commands and events can be used.
|
||||
|
||||
|
||||
\subsection p2p_wpa_cli wpa_cli example
|
||||
|
||||
wpa_cli can be used to control wpa_supplicant in interactive
|
||||
mode. The following sessions show examples of commands used for
|
||||
device discovery and group formation. The lines starting with "> " are
|
||||
commands from the user (followed by command result indication) and
|
||||
lines starting with "<2>" are event messages from wpa_supplicant.
|
||||
|
||||
P2P device "Wireless Client":
|
||||
|
||||
\verbatim
|
||||
> p2p_find
|
||||
OK
|
||||
> <2>P2P-DEVICE-FOUND 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7
|
||||
pri_dev_type=1-0050F204-1 name='Wireless Client 2' config_methods=0x18c
|
||||
dev_capab=0x1 group_capab=0x0
|
||||
<2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7
|
||||
<2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7
|
||||
> p2p_connect 02:40:61:c2:f3:b7 pbc
|
||||
OK
|
||||
<2>P2P-GO-NEG-SUCCESS
|
||||
<2>P2P-GROUP-FORMATION-SUCCESS
|
||||
<2>P2P-GROUP-STARTED sta0-p2p-0 client DIRECT-vM
|
||||
> interface
|
||||
Available interfaces:
|
||||
sta0-p2p-0
|
||||
sta0
|
||||
> p2p_group_remove sta0-p2p-0
|
||||
<2>P2P-GROUP-REMOVED sta0-p2p-0 client
|
||||
OK
|
||||
> term
|
||||
OK
|
||||
\endverbatim
|
||||
|
||||
|
||||
P2P device "Wireless Client2" (which ended up operating in GO role):
|
||||
|
||||
\verbatim
|
||||
> p2p_find
|
||||
OK
|
||||
<2>P2P-DEVICE-FOUND 02:f0:bc:44:87:62 p2p_dev_addr=02:f0:bc:44:87:62
|
||||
pri_dev_type=1-0050F204-1 name='Wireless Client' config_methods=0x18c
|
||||
dev_capab=0x1 group_capab=0x0
|
||||
> p2p_connect 02:f0:bc:44:87:62 pbc
|
||||
OK
|
||||
<2>P2P-GO-NEG-SUCCESS
|
||||
<2>P2P-GROUP-FORMATION-SUCCESS
|
||||
<2>P2P-GROUP-STARTED sta1-p2p-0 GO DIRECT-vM
|
||||
> interface
|
||||
Available interfaces:
|
||||
sta1-p2p-0
|
||||
sta1
|
||||
> p2p_group_remove sta1-p2p-0
|
||||
<2>P2P-GROUP-REMOVED sta1-p2p-0 GO
|
||||
OK
|
||||
> term
|
||||
OK
|
||||
\endverbatim
|
||||
|
||||
*/
|
@ -1,85 +0,0 @@
|
||||
digraph p2p_arch {
|
||||
ranksep=.75;
|
||||
size = "7.5,7.5";
|
||||
|
||||
edge [dir=none];
|
||||
|
||||
subgraph cluster_wpa_gui {
|
||||
label = "wpa_gui";
|
||||
|
||||
status -> Qt;
|
||||
scan -> Qt;
|
||||
network -> Qt;
|
||||
Qt -> peers;
|
||||
Qt -> WPS;
|
||||
Qt -> gui_ctrl;
|
||||
|
||||
gui_ctrl [label="ctrl i/f"];
|
||||
}
|
||||
|
||||
subgraph cluster_wpa_supplicant {
|
||||
label = "wpa_supplicant"
|
||||
|
||||
ctrl_iface [label="ctrl i/f"];
|
||||
authenticator [label="Authenticator"];
|
||||
supplicant [label="Supplicant"];
|
||||
driver_iface [label="driver i/f"];
|
||||
p2p_module [label="P2P\nmodule"];
|
||||
wps_registrar [label="WPS\nRegistrar"];
|
||||
wps_enrollee [label="WPS\nEnrollee"];
|
||||
mgmt_entity [label="Management\nentity"];
|
||||
|
||||
ctrl_iface -> mgmt_entity;
|
||||
p2p_module -> mgmt_entity;
|
||||
wps_registrar -> mgmt_entity;
|
||||
wps_enrollee -> mgmt_entity;
|
||||
mgmt_entity -> authenticator;
|
||||
mgmt_entity -> supplicant;
|
||||
mgmt_entity -> driver_iface;
|
||||
|
||||
{ rank = same; mgmt_entity; p2p_module; }
|
||||
}
|
||||
|
||||
subgraph cluster_wpa_cli {
|
||||
label = "wpa_cli -a"
|
||||
|
||||
wpa_cli_action;
|
||||
}
|
||||
|
||||
subgraph cluster_dnsmasq {
|
||||
label = "dnsmasq"
|
||||
|
||||
dnsmasq;
|
||||
}
|
||||
|
||||
subgraph cluster_dhclient {
|
||||
label = "dhclient"
|
||||
|
||||
dhclient;
|
||||
}
|
||||
|
||||
subgraph cluster_kernel {
|
||||
label = "Linux kernel"
|
||||
|
||||
cfg80211 -> mac80211;
|
||||
netdev -> mac80211;
|
||||
mac80211 -> ath9k;
|
||||
}
|
||||
|
||||
gui_ctrl -> ctrl_iface;
|
||||
wpa_cli_action -> ctrl_iface;
|
||||
|
||||
driver_iface -> cfg80211;
|
||||
|
||||
wpa_cli_action -> dnsmasq;
|
||||
wpa_cli_action -> dhclient;
|
||||
|
||||
dnsmasq -> netdev;
|
||||
dhclient -> netdev;
|
||||
|
||||
edge [color=blue,dir=both];
|
||||
p2p_module -> mgmt_entity -> driver_iface -> cfg80211 -> mac80211 -> ath9k;
|
||||
|
||||
edge [color=green,dir=both];
|
||||
peers -> Qt -> gui_ctrl -> ctrl_iface -> mgmt_entity -> p2p_module;
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
digraph p2p_arch2 {
|
||||
ranksep=.75;
|
||||
size = "7.5,7.5";
|
||||
|
||||
edge [dir=none];
|
||||
|
||||
subgraph cluster_wpa_gui {
|
||||
label = "wpa_gui";
|
||||
|
||||
status -> Qt;
|
||||
scan -> Qt;
|
||||
network -> Qt;
|
||||
Qt -> peers;
|
||||
Qt -> WPS;
|
||||
Qt -> gui_ctrl;
|
||||
|
||||
gui_ctrl [label="ctrl i/f"];
|
||||
}
|
||||
|
||||
subgraph cluster_wpa_supplicant {
|
||||
label = "wpa_supplicant"
|
||||
|
||||
ctrl_iface [label="ctrl i/f"];
|
||||
authenticator [label="Authenticator"];
|
||||
supplicant [label="Supplicant"];
|
||||
driver_iface [label="driver i/f"];
|
||||
wps_registrar [label="WPS\nRegistrar"];
|
||||
wps_enrollee [label="WPS\nEnrollee"];
|
||||
mgmt_entity [label="Management\nentity"];
|
||||
|
||||
ctrl_iface -> mgmt_entity;
|
||||
wps_registrar -> mgmt_entity;
|
||||
wps_enrollee -> mgmt_entity;
|
||||
mgmt_entity -> authenticator;
|
||||
mgmt_entity -> supplicant;
|
||||
mgmt_entity -> driver_iface;
|
||||
}
|
||||
|
||||
subgraph cluster_wpa_cli {
|
||||
label = "wpa_cli -a"
|
||||
|
||||
wpa_cli_action;
|
||||
}
|
||||
|
||||
subgraph cluster_dnsmasq {
|
||||
label = "dnsmasq"
|
||||
|
||||
dnsmasq;
|
||||
}
|
||||
|
||||
subgraph cluster_dhclient {
|
||||
label = "dhclient"
|
||||
|
||||
dhclient;
|
||||
}
|
||||
|
||||
subgraph cluster_kernel {
|
||||
label = "Kernel"
|
||||
|
||||
ioctl -> umac;
|
||||
netdev -> umac;
|
||||
umac -> p2p_module;
|
||||
p2p_module [label="P2P\nmodule"];
|
||||
umac -> driver;
|
||||
|
||||
{ rank = same; umac; p2p_module; }
|
||||
}
|
||||
|
||||
gui_ctrl -> ctrl_iface;
|
||||
wpa_cli_action -> ctrl_iface;
|
||||
|
||||
driver_iface -> ioctl;
|
||||
|
||||
wpa_cli_action -> dnsmasq;
|
||||
wpa_cli_action -> dhclient;
|
||||
|
||||
dnsmasq -> netdev;
|
||||
dhclient -> netdev;
|
||||
|
||||
edge [color=blue,dir=both];
|
||||
p2p_module -> umac -> driver;
|
||||
|
||||
edge [color=green,dir=both];
|
||||
peers -> Qt -> gui_ctrl -> ctrl_iface -> mgmt_entity -> driver_iface -> ioctl -> umac -> p2p_module;
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
digraph p2p {
|
||||
ranksep=.75;
|
||||
size = "8.5,7.5";
|
||||
|
||||
start -> IDLE;
|
||||
start [label="Init",shape=none];
|
||||
|
||||
/* Discovery: Scan followed by Find(SEARCH,LISTEN) */
|
||||
subgraph cluster_0 {
|
||||
label="Discovery";
|
||||
color=lightgrey;
|
||||
node [color=blue];
|
||||
/* SCAN and LISTEN currently not used in the implementation */
|
||||
SCAN [style=dotted];
|
||||
LISTEN [style=dotted];
|
||||
|
||||
SCAN -> LISTEN;
|
||||
LISTEN -> SEARCH -> LISTEN [style=dotted];
|
||||
SEARCH -> SD_DURING_FIND [label="Peer SD capab\nand no info", weight=100];
|
||||
SD_DURING_FIND -> SEARCH [label="RX SD Resp\nor timeout", weight=100];
|
||||
SEARCH -> PROV_DISC_DURING_FIND [label="Prov Disc cmd\nand no Resp", weight=100];
|
||||
PROV_DISC_DURING_FIND -> SEARCH [label="RX Prov Disc Resp\nor timeout", weight=100];
|
||||
}
|
||||
|
||||
/* Group Formation */
|
||||
subgraph cluster_1 {
|
||||
label="Group Formation";
|
||||
color=lightgrey;
|
||||
node [color=green];
|
||||
|
||||
CONNECT -> CONNECT_LISTEN [style=dotted,weight=100];
|
||||
CONNECT_LISTEN -> CONNECT [style=dotted,weight=100];
|
||||
CONNECT -> WAIT_PEER_IDLE [label="RX GO Neg Resp\n(info unavail)"];
|
||||
WAIT_PEER_IDLE -> WAIT_PEER_CONNECT [style=dotted,weight=100];
|
||||
WAIT_PEER_CONNECT -> WAIT_PEER_IDLE [style=dotted,weight=100];
|
||||
|
||||
CONNECT -> GO_NEG [label="RX GO Neg Resp\n(success)", weight=10];
|
||||
CONNECT_LISTEN -> GO_NEG [label="RX GO Neg Req or\nTX GO Neg Resp"];
|
||||
WAIT_PEER_CONNECT -> GO_NEG [label="RX GO Neg Req"];
|
||||
GO_NEG -> PROVISIONING [label="TX/RX GO Neg Conf"];
|
||||
}
|
||||
|
||||
PROVISIONING -> IDLE [label="WPS\nsuccess"];
|
||||
|
||||
/* External triggers */
|
||||
IDLE -> SCAN [label="Find cmd",weight=20];
|
||||
IDLE -> CONNECT [label="Connect cmd",weight=20];
|
||||
IDLE -> LISTEN_ONLY [label="Listen cmd"];
|
||||
|
||||
/* Timeouts */
|
||||
/*
|
||||
edge [color=red];
|
||||
WAIT_PEER_IDLE -> IDLE [label="timeout", weight=0];
|
||||
WAIT_PEER_CONNECT -> IDLE [label="timeout", weight=0];
|
||||
CONNECT -> IDLE [label="timeout", weight=0];
|
||||
CONNECT_LISTEN -> IDLE [label="timeout", weight=0];
|
||||
GO_NEG -> IDLE [label="timeout", weight=0];
|
||||
PROVISIONING -> IDLE [label="timeout", weight=0];
|
||||
LISTEN_ONLY -> IDLE [label="timeout", weight=0];
|
||||
SEARCH -> IDLE [label="timeout", weight=0];
|
||||
*/
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
/**
|
||||
\page porting Porting to different target boards and operating systems
|
||||
|
||||
wpa_supplicant was designed to be easily portable to different
|
||||
hardware (board, CPU) and software (OS, drivers) targets. It is
|
||||
already used with number of operating systems and numerous wireless
|
||||
card models and drivers. The main wpa_supplicant repository includes
|
||||
support for Linux, FreeBSD, and Windows. In addition, the code has been
|
||||
ported to number of other operating systems like VxWorks, PalmOS,
|
||||
Windows CE, and Windows Mobile. On the hardware
|
||||
side, wpa_supplicant is used on various systems: desktops, laptops,
|
||||
PDAs, and embedded devices with CPUs including x86, PowerPC,
|
||||
arm/xscale, and MIPS. Both big and little endian configurations are
|
||||
supported.
|
||||
|
||||
|
||||
\section ansi_c_extra Extra functions on top of ANSI C
|
||||
|
||||
wpa_supplicant is mostly using ANSI C functions that are available on
|
||||
most targets. However, couple of additional functions that are common
|
||||
on modern UNIX systems are used. Number of these are listed with
|
||||
prototypes in \ref common.h (the \verbatim #ifdef CONFIG_ANSI_C_EXTRA \endverbatim
|
||||
block). These functions may need to be implemented or at least defined
|
||||
as macros to native functions in the target OS or C library.
|
||||
|
||||
Many of the common ANSI C functions are used through a wrapper
|
||||
definitions in \ref os.h to allow these to be replaced easily with a
|
||||
platform specific version in case standard C libraries are not
|
||||
available. In addition, \ref os.h defines couple of common platform
|
||||
specific functions that are implemented in \ref os_unix.c for UNIX like
|
||||
targets and in \ref os_win32.c for Win32 API. If the target platform does
|
||||
not support either of these examples, a new os_*.c file may need to be
|
||||
added.
|
||||
|
||||
Unless OS_NO_C_LIB_DEFINES is defined, the standard ANSI C and POSIX
|
||||
functions are used by defining the os_*() wrappers to use them
|
||||
directly in order to avoid extra cost in size and speed. If the target
|
||||
platform needs different versions of the functions, \ref os.h can be
|
||||
modified to define the suitable macros or alternatively,
|
||||
OS_NO_C_LIB_DEFINES may be defined for the build and the wrapper
|
||||
functions can then be implemented in a new os_*.c wrapper file.
|
||||
|
||||
\ref common.h defines number of helper macros for handling integers of
|
||||
different size and byte order. Suitable version of these definitions
|
||||
may need to be added for the target platform.
|
||||
|
||||
|
||||
\section configuration_backend Configuration backend
|
||||
|
||||
wpa_supplicant implements a configuration interface that allows the
|
||||
backend to be easily replaced in order to read configuration data from
|
||||
a suitable source depending on the target platform. \ref config.c
|
||||
implements the generic code that can be shared with all configuration
|
||||
backends. Each backend is implemented in its own config_*.c file.
|
||||
|
||||
The included \ref config_file.c backend uses a text file for configuration
|
||||
and \ref config_winreg.c uses Windows registry. These files can be used as
|
||||
an example for a new configuration backend if the target platform uses
|
||||
different mechanism for configuration parameters. In addition,
|
||||
\ref config_none.c can be used as an empty starting point for building a
|
||||
new configuration backend.
|
||||
|
||||
|
||||
\section driver_iface_porting Driver interface
|
||||
|
||||
Unless the target OS and driver is already supported, most porting
|
||||
projects have to implement a driver wrapper. This may be done by
|
||||
adding a new driver interface module or modifying an existing module
|
||||
(driver_*.c) if the new target is similar to one of them. \ref
|
||||
driver_wrapper "Driver wrapper implementation" describes the details
|
||||
of the driver interface and discusses the tasks involved in porting
|
||||
this part of wpa_supplicant.
|
||||
|
||||
|
||||
\section l2_packet_porting l2_packet (link layer access)
|
||||
|
||||
wpa_supplicant needs to have access to sending and receiving layer 2
|
||||
(link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e
|
||||
and RSN pre-authentication 0x88c7. \ref l2_packet.h defines the interfaces
|
||||
used for this in the core wpa_supplicant implementation.
|
||||
|
||||
If the target operating system supports a generic mechanism for link
|
||||
layer access, that is likely the best mechanism for providing the
|
||||
needed functionality for wpa_supplicant. Linux packet socket is an
|
||||
example of such a generic mechanism. If this is not available, a
|
||||
separate interface may need to be implemented to the network stack or
|
||||
driver. This is usually an intermediate or protocol driver that is
|
||||
operating between the device driver and the OS network stack. If such
|
||||
a mechanism is not feasible, the interface can also be implemented
|
||||
directly in the device driver.
|
||||
|
||||
The main wpa_supplicant repository includes l2_packet implementations
|
||||
for Linux using packet sockets (\ref l2_packet_linux.c), more portable
|
||||
version using libpcap/libdnet libraries (\ref l2_packet_pcap.c; this
|
||||
supports WinPcap, too), and FreeBSD specific version of libpcap
|
||||
interface (\ref l2_packet_freebsd.c).
|
||||
|
||||
If the target operating system is supported by libpcap (receiving) and
|
||||
libdnet (sending), \ref l2_packet_pcap.c can likely be used with minimal or
|
||||
no changes. If this is not a case or a proprietary interface for link
|
||||
layer is required, a new l2_packet module may need to be
|
||||
added. Alternatively, for hostapd,
|
||||
struct \ref wpa_driver_ops::hapd_send_eapol() handler can
|
||||
be used to override the l2_packet library if the link layer access is
|
||||
integrated with the driver interface implementation.
|
||||
|
||||
|
||||
\section eloop_porting Event loop
|
||||
|
||||
wpa_supplicant uses a single process/thread model and an event loop
|
||||
to provide callbacks on events (registered timeout, received packet,
|
||||
signal). eloop.h defines the event loop interface. \ref eloop.c is an
|
||||
implementation of such an event loop using select() and sockets. This
|
||||
is suitable for most UNIX/POSIX systems. When porting to other
|
||||
operating systems, it may be necessary to replace that implementation
|
||||
with OS specific mechanisms that provide similar functionality.
|
||||
|
||||
|
||||
\section ctrl_iface_porting Control interface
|
||||
|
||||
wpa_supplicant uses a \ref ctrl_iface_page "control interface"
|
||||
to allow external processed
|
||||
to get status information and to control the operations. Currently,
|
||||
this is implemented with socket based communication; both UNIX domain
|
||||
sockets and UDP sockets are supported. If the target OS does not
|
||||
support sockets, this interface will likely need to be modified to use
|
||||
another mechanism like message queues. The control interface is
|
||||
optional component, so it is also possible to run wpa_supplicant
|
||||
without porting this part.
|
||||
|
||||
The wpa_supplicant side of the control interface is implemented in
|
||||
\ref wpa_supplicant/ctrl_iface.c. Matching client side is implemented as a control
|
||||
interface library in \ref wpa_ctrl.c.
|
||||
|
||||
|
||||
\section entry_point Program entry point
|
||||
|
||||
wpa_supplicant defines a set of functions that can be used to
|
||||
initialize main supplicant processing. Each operating system has a
|
||||
mechanism for starting new processing or threads. This is usually a
|
||||
function with a specific set of arguments and calling convention. This
|
||||
function is responsible on initializing wpa_supplicant.
|
||||
|
||||
\ref wpa_supplicant/main.c includes an entry point for UNIX-like
|
||||
operating system, i.e., main() function that uses command line arguments
|
||||
for setting parameters for wpa_supplicant. When porting to other
|
||||
operating systems, similar OS-specific entry point implementation is
|
||||
needed. It can be implemented in a new file that is then linked with
|
||||
wpa_supplicant instead of main.o. \ref wpa_supplicant/main.c is also a
|
||||
good example on how the initialization process should be done.
|
||||
|
||||
The supplicant initialization functions are defined in
|
||||
\ref wpa_supplicant_i.h. In most cases, the entry point function should
|
||||
start by fetching configuration parameters. After this, a global
|
||||
wpa_supplicant context is initialized with a call to
|
||||
\ref wpa_supplicant_init(). After this, existing network interfaces can be
|
||||
added with \ref wpa_supplicant_add_iface(). \ref wpa_supplicant_run() is then
|
||||
used to start the main event loop. Once this returns at program
|
||||
termination time, \ref wpa_supplicant_deinit() is used to release global
|
||||
context data.
|
||||
|
||||
\ref wpa_supplicant_add_iface() and \ref wpa_supplicant_remove_iface() can be
|
||||
used dynamically to add and remove interfaces based on when
|
||||
wpa_supplicant processing is needed for them. This can be done, e.g.,
|
||||
when hotplug network adapters are being inserted and ejected. It is
|
||||
also possible to do this when a network interface is being
|
||||
enabled/disabled if it is desirable that wpa_supplicant processing
|
||||
for the interface is fully enabled/disabled at the same time.
|
||||
|
||||
|
||||
\section simple_build Simple build example
|
||||
|
||||
One way to start a porting project is to begin with a very simple
|
||||
build of wpa_supplicant with WPA-PSK support and once that is
|
||||
building correctly, start adding features.
|
||||
|
||||
Following command can be used to build very simple version of
|
||||
wpa_supplicant:
|
||||
|
||||
\verbatim
|
||||
cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \
|
||||
config_none.c l2_packet_none.c tls_none.c wpa.c preauth.c \
|
||||
aes_wrap.c wpa_supplicant.c events.c main_none.c drivers.c
|
||||
\endverbatim
|
||||
|
||||
The end result is not really very useful since it uses empty functions
|
||||
for configuration parsing and layer 2 packet access and does not
|
||||
include a driver interface. However, this is a good starting point
|
||||
since the build is complete in the sense that all functions are
|
||||
present and this is easy to configure to a build system by just
|
||||
including the listed C files.
|
||||
|
||||
Once this version can be build successfully, the end result can be
|
||||
made functional by adding a proper program entry point (main*.c),
|
||||
driver interface (driver_*.c and matching CONFIG_DRIVER_* define for
|
||||
registration in \ref drivers.c), configuration parser/writer (config_*.c),
|
||||
and layer 2 packet access implementation (l2_packet_*.c). After these
|
||||
components have been added, the end result should be a working
|
||||
WPA/WPA2-PSK enabled supplicant.
|
||||
|
||||
After the basic functionality has been verified to work, more features
|
||||
can be added by linking in more files and defining C pre-processor
|
||||
defines. Currently, the best source of information for what options
|
||||
are available and which files needs to be included is in the Makefile
|
||||
used for building the supplicant with make. Similar configuration will
|
||||
be needed for build systems that either use different type of make
|
||||
tool or a GUI-based project configuration.
|
||||
|
||||
*/
|
@ -1,201 +0,0 @@
|
||||
/**
|
||||
\page testing_tools Testing and development tools
|
||||
|
||||
[ \ref eapol_test "eapol_test" |
|
||||
\ref preauth_test "preauth_test" |
|
||||
\ref unit_tests "Unit tests" |
|
||||
\ref wpa_trace "Tracing code" ]
|
||||
|
||||
wpa_supplicant source tree includes number of testing and development
|
||||
tools that make it easier to test the programs without having to setup
|
||||
a full test setup with wireless cards. In addition, these tools can be
|
||||
used to implement automatic tests suites.
|
||||
|
||||
\section eapol_test eapol_test - EAP peer and RADIUS client testing
|
||||
|
||||
eapol_test is a program that links together the same EAP peer
|
||||
implementation that wpa_supplicant is using and the RADIUS
|
||||
authentication client code from hostapd. In addition, it has minimal
|
||||
glue code to combine these two components in similar ways to IEEE
|
||||
802.1X/EAPOL Authenticator state machines. In other words, it
|
||||
integrates IEEE 802.1X Authenticator (normally, an access point) and
|
||||
IEEE 802.1X Supplicant (normally, a wireless client) together to
|
||||
generate a single program that can be used to test EAP methods without
|
||||
having to setup an access point and a wireless client.
|
||||
|
||||
The main uses for eapol_test are in interoperability testing of EAP
|
||||
methods against RADIUS servers and in development testing for new EAP
|
||||
methods. It can be easily used to automate EAP testing for
|
||||
interoperability and regression since the program can be run from
|
||||
shell scripts without require additional test components apart from a
|
||||
RADIUS server. For example, the automated EAP tests described in
|
||||
eap_testing.txt are implemented with eapol_test. Similarly, eapol_test
|
||||
could be used to implement an automated regression test suite for a
|
||||
RADIUS authentication server.
|
||||
|
||||
eapol_test uses the same build time configuration file, .config, as
|
||||
wpa_supplicant. This file is used to select which EAP methods are
|
||||
included in eapol_test. This program is not built with the default
|
||||
Makefile target, so a separate make command needs to be used to
|
||||
compile the tool:
|
||||
|
||||
\verbatim
|
||||
make eapol_test
|
||||
\endverbatim
|
||||
|
||||
The resulting eapol_test binary has following command like options:
|
||||
|
||||
\verbatim
|
||||
usage:
|
||||
eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] [-s<AS secret>] \
|
||||
[-r<count>] [-t<timeout>] [-C<Connect-Info>] \
|
||||
[-M<client MAC address>]
|
||||
eapol_test scard
|
||||
eapol_test sim <PIN> <num triplets> [debug]
|
||||
|
||||
options:
|
||||
-c<conf> = configuration file
|
||||
-a<AS IP> = IP address of the authentication server, default 127.0.0.1
|
||||
-p<AS port> = UDP port of the authentication server, default 1812
|
||||
-s<AS secret> = shared secret with the authentication server, default 'radius'
|
||||
-r<count> = number of re-authentications
|
||||
-W = wait for a control interface monitor before starting
|
||||
-S = save configuration after authentiation
|
||||
-n = no MPPE keys expected
|
||||
-t<timeout> = sets timeout in seconds (default: 30 s)
|
||||
-C<Connect-Info> = RADIUS Connect-Info (default: CONNECT 11Mbps 802.11b)
|
||||
-M<client MAC address> = Set own MAC address (Calling-Station-Id,
|
||||
default: 02:00:00:00:00:01)
|
||||
\endverbatim
|
||||
|
||||
|
||||
As an example,
|
||||
\verbatim
|
||||
eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
|
||||
\endverbatim
|
||||
tries to complete EAP authentication based on the network
|
||||
configuration from test.conf against the RADIUS server running on the
|
||||
local host. A re-authentication is triggered to test fast
|
||||
re-authentication. The configuration file uses the same format for
|
||||
network blocks as wpa_supplicant.
|
||||
|
||||
|
||||
\section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing
|
||||
|
||||
preauth_test is similar to eapol_test in the sense that in combines
|
||||
EAP peer implementation with something else, in this case, with WPA2
|
||||
pre-authentication. This tool can be used to test pre-authentication
|
||||
based on the code that wpa_supplicant is using. As such, it tests
|
||||
both the wpa_supplicant implementation and the functionality of an
|
||||
access point.
|
||||
|
||||
preauth_test is built with:
|
||||
|
||||
\verbatim
|
||||
make preauth_test
|
||||
\endverbatim
|
||||
|
||||
and it uses following command line arguments:
|
||||
|
||||
\verbatim
|
||||
usage: preauth_test <conf> <target MAC address> <ifname>
|
||||
\endverbatim
|
||||
|
||||
For example,
|
||||
\verbatim
|
||||
preauth_test test.conf 02:11:22:33:44:55 eth0
|
||||
\endverbatim
|
||||
would use network configuration from test.conf to try to complete
|
||||
pre-authentication with AP using BSSID 02:11:22:33:44:55. The
|
||||
pre-authentication packets would be sent using the eth0 interface.
|
||||
|
||||
|
||||
\section unit_tests Unit tests
|
||||
|
||||
Number of the components (.c files) used in wpa_supplicant define
|
||||
their own unit tests for automated validation of the basic
|
||||
functionality. Most of the tests for cryptographic algorithms are
|
||||
using standard test vectors to validate functionality. These tests can
|
||||
be useful especially when verifying port to a new CPU target.
|
||||
|
||||
The test programs are collected in the tests subdirectory. All
|
||||
automated unit tests can be run with
|
||||
|
||||
\verbatim
|
||||
make run-tests
|
||||
\endverbatim
|
||||
|
||||
This make target builds and runs each test and terminates with zero
|
||||
exit code if all tests were completed successfully.
|
||||
|
||||
|
||||
\section wpa_trace Tracing code for developer debuggin
|
||||
|
||||
wpa_supplicant and hostapd can be built with tracing code that will
|
||||
track and analyze memory allocations and other resource registrations
|
||||
and certain API uses. If incorrect use is detected, a backtrace of the
|
||||
call location (and/or allocation location) is shown. This can also be
|
||||
used to detect certain categories of memory leaks and report them
|
||||
automatically when the program is terminated. The report will also
|
||||
include information about forgotten eloop events.
|
||||
|
||||
The trace code can be enabled with CONFIG_WPA_TRACE=y build
|
||||
option. More verbose backtrace information can be generated if libbfd
|
||||
is available and the binaries are not stripped of symbol
|
||||
information. This is enabled with CONFIG_WPA_TRACE_BFD=y.
|
||||
|
||||
For example, a memory leak (forgotten os_free() call) would show up
|
||||
like this when the program is terminated:
|
||||
|
||||
\verbatim
|
||||
MEMLEAK[0x82d200]: len 128
|
||||
WPA_TRACE: memleak - START
|
||||
[0]: ./wpa_supplicant(os_malloc+0x59) [0x41a5e9]
|
||||
os_malloc() ../src/utils/os_unix.c:359
|
||||
[1]: ./wpa_supplicant(os_zalloc+0x16) [0x41a676]
|
||||
os_zalloc() ../src/utils/os_unix.c:418
|
||||
[2]: ./wpa_supplicant(wpa_supplicant_init+0x38) [0x48b508]
|
||||
wpa_supplicant_init() wpa_supplicant.c:2315
|
||||
[3]: ./wpa_supplicant(main+0x2f3) [0x491073]
|
||||
main() main.c:252
|
||||
WPA_TRACE: memleak - END
|
||||
MEMLEAK: total 128 bytes
|
||||
\endverbatim
|
||||
|
||||
Another type of error that can be detected is freeing of memory area
|
||||
that was registered for some use and is still be referenced:
|
||||
|
||||
\verbatim
|
||||
WPA_TRACE: Freeing referenced memory - START
|
||||
[2]: ./wpa_supplicant(os_free+0x5c) [0x41a53c]
|
||||
os_free() ../src/utils/os_unix.c:411
|
||||
[3]: ./wpa_supplicant(wpa_supplicant_remove_iface+0x30) [0x48b380]
|
||||
wpa_supplicant_remove_iface() wpa_supplicant.c:2259
|
||||
[4]: ./wpa_supplicant(wpa_supplicant_deinit+0x20) [0x48b3e0]
|
||||
wpa_supplicant_deinit() wpa_supplicant.c:2430
|
||||
[5]: ./wpa_supplicant(main+0x357) [0x4910d7]
|
||||
main() main.c:276
|
||||
WPA_TRACE: Freeing referenced memory - END
|
||||
WPA_TRACE: Reference registration - START
|
||||
[1]: ./wpa_supplicant [0x41c040]
|
||||
eloop_trace_sock_add_ref() ../src/utils/eloop.c:94
|
||||
[2]: ./wpa_supplicant(wpa_supplicant_ctrl_iface_deinit+0x17) [0x473247]
|
||||
wpa_supplicant_ctrl_iface_deinit() ctrl_iface_unix.c:436
|
||||
[3]: ./wpa_supplicant [0x48b21c]
|
||||
wpa_supplicant_cleanup() wpa_supplicant.c:378
|
||||
wpa_supplicant_deinit_iface() wpa_supplicant.c:2155
|
||||
[4]: ./wpa_supplicant(wpa_supplicant_remove_iface+0x30) [0x48b380]
|
||||
wpa_supplicant_remove_iface() wpa_supplicant.c:2259
|
||||
[5]: ./wpa_supplicant(wpa_supplicant_deinit+0x20) [0x48b3e0]
|
||||
wpa_supplicant_deinit() wpa_supplicant.c:2430
|
||||
[6]: ./wpa_supplicant(main+0x357) [0x4910d7]
|
||||
main() main.c:276
|
||||
WPA_TRACE: Reference registration - END
|
||||
Aborted
|
||||
\endverbatim
|
||||
|
||||
This type of error results in showing backtraces for both the location
|
||||
where the incorrect freeing happened and the location where the memory
|
||||
area was marked referenced.
|
||||
|
||||
*/
|
@ -1,247 +0,0 @@
|
||||
#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 nl80211\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 7350
|
||||
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 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
|
||||
6 8175 6975 9675 7275
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 6975 9675 6975 9675 7275 8175 7275 8175 6975
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 7200 EAP-MSCHAPv2\001
|
||||
-6
|
||||
6 9300 6600 10350 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9300 6600 10350 6600 10350 6900 9300 6900 9300 6600
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 870 9375 6825 EAP-FAST\001
|
||||
-6
|
||||
6 8175 6600 9225 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 6600 9225 6600 9225 6900 8175 6900 8175 6600
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 795 8250 6825 EAP-PAX\001
|
||||
-6
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8100 7350 10425 7350 10425 4425 8100 4425 8100 7350
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
|
||||
-6
|
||||
6 2775 5025 4050 5325
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
2775 5025 4050 5025 4050 5325 2775 5325 2775 5025
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 990 2925 5250 driver events\001
|
||||
-6
|
||||
6 2775 3150 4050 3450
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\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
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
|
||||
4350 3900
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4350 3900 4050 3450
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4350 4425 4050 5025
|
||||
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 210 1440 1637 2371 wpa_supplicant\001
|
4
contrib/wpa/eap_example/.gitignore
vendored
4
contrib/wpa/eap_example/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
*.d
|
||||
eap_example
|
||||
libeap.so
|
||||
libeap.a
|
@ -1,119 +0,0 @@
|
||||
ALL=eap_example
|
||||
|
||||
include ../src/build.rules
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../src
|
||||
CFLAGS += -I../src/utils
|
||||
|
||||
|
||||
EAP_LIBS += ../src/utils/libutils.a
|
||||
EAP_LIBS += ../src/crypto/libcrypto.a
|
||||
EAP_LIBS += ../src/tls/libtls.a
|
||||
|
||||
OBJS_both += ../src/eap_common/eap_peap_common.o
|
||||
OBJS_both += ../src/eap_common/eap_psk_common.o
|
||||
OBJS_both += ../src/eap_common/eap_pax_common.o
|
||||
OBJS_both += ../src/eap_common/eap_sake_common.o
|
||||
OBJS_both += ../src/eap_common/eap_gpsk_common.o
|
||||
OBJS_both += ../src/eap_common/chap.o
|
||||
|
||||
OBJS_peer += ../src/eap_peer/eap_tls.o
|
||||
OBJS_peer += ../src/eap_peer/eap_peap.o
|
||||
OBJS_peer += ../src/eap_peer/eap_ttls.o
|
||||
OBJS_peer += ../src/eap_peer/eap_md5.o
|
||||
OBJS_peer += ../src/eap_peer/eap_mschapv2.o
|
||||
OBJS_peer += ../src/eap_peer/mschapv2.o
|
||||
OBJS_peer += ../src/eap_peer/eap_otp.o
|
||||
OBJS_peer += ../src/eap_peer/eap_gtc.o
|
||||
OBJS_peer += ../src/eap_peer/eap_leap.o
|
||||
OBJS_peer += ../src/eap_peer/eap_psk.o
|
||||
OBJS_peer += ../src/eap_peer/eap_pax.o
|
||||
OBJS_peer += ../src/eap_peer/eap_sake.o
|
||||
OBJS_peer += ../src/eap_peer/eap_gpsk.o
|
||||
OBJS_peer += ../src/eap_peer/eap.o
|
||||
OBJS_peer += ../src/eap_common/eap_common.o
|
||||
OBJS_peer += ../src/eap_peer/eap_methods.o
|
||||
OBJS_peer += ../src/eap_peer/eap_tls_common.o
|
||||
|
||||
CFLAGS += -DEAP_TLS
|
||||
CFLAGS += -DEAP_PEAP
|
||||
CFLAGS += -DEAP_TTLS
|
||||
CFLAGS += -DEAP_MD5
|
||||
CFLAGS += -DEAP_MSCHAPv2
|
||||
CFLAGS += -DEAP_GTC
|
||||
CFLAGS += -DEAP_OTP
|
||||
CFLAGS += -DEAP_LEAP
|
||||
CFLAGS += -DEAP_PSK
|
||||
CFLAGS += -DEAP_PAX
|
||||
CFLAGS += -DEAP_SAKE
|
||||
CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
|
||||
|
||||
CFLAGS += -DEAP_SERVER_IDENTITY
|
||||
CFLAGS += -DEAP_SERVER_TLS
|
||||
CFLAGS += -DEAP_SERVER_PEAP
|
||||
CFLAGS += -DEAP_SERVER_TTLS
|
||||
CFLAGS += -DEAP_SERVER_MD5
|
||||
CFLAGS += -DEAP_SERVER_MSCHAPV2
|
||||
CFLAGS += -DEAP_SERVER_GTC
|
||||
CFLAGS += -DEAP_SERVER_PSK
|
||||
CFLAGS += -DEAP_SERVER_PAX
|
||||
CFLAGS += -DEAP_SERVER_SAKE
|
||||
CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256
|
||||
|
||||
CFLAGS += -DIEEE8021X_EAPOL
|
||||
|
||||
|
||||
# Optional components to add EAP server support
|
||||
OBJS_server += ../src/eap_server/eap_server_tls.o
|
||||
OBJS_server += ../src/eap_server/eap_server_peap.o
|
||||
OBJS_server += ../src/eap_server/eap_server_ttls.o
|
||||
OBJS_server += ../src/eap_server/eap_server_md5.o
|
||||
OBJS_server += ../src/eap_server/eap_server_mschapv2.o
|
||||
OBJS_server += ../src/eap_server/eap_server_gtc.o
|
||||
OBJS_server += ../src/eap_server/eap_server_psk.o
|
||||
OBJS_server += ../src/eap_server/eap_server_pax.o
|
||||
OBJS_server += ../src/eap_server/eap_server_sake.o
|
||||
OBJS_server += ../src/eap_server/eap_server_gpsk.o
|
||||
OBJS_server += ../src/eap_server/eap_server.o
|
||||
OBJS_server += ../src/eap_server/eap_server_identity.o
|
||||
OBJS_server += ../src/eap_server/eap_server_methods.o
|
||||
OBJS_server += ../src/eap_server/eap_server_tls_common.o
|
||||
CFLAGS += -DEAP_SERVER
|
||||
|
||||
|
||||
OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
|
||||
_OBJS_VAR := OBJS_lib
|
||||
include ../src/objs.mk
|
||||
|
||||
OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
|
||||
_OBJS_VAR := OBJS_ex
|
||||
include ../src/objs.mk
|
||||
|
||||
_OBJS_VAR := EAP_LIBS
|
||||
include ../src/objs.mk
|
||||
|
||||
|
||||
ifneq ($(CONFIG_SOLIB), yes)
|
||||
LIBEAP = libeap.a
|
||||
libeap.a: $(EAP_LIBS) $(OBJS_lib)
|
||||
$(AR) crT libeap.a $^
|
||||
$(RANLIB) libeap.a
|
||||
|
||||
else
|
||||
CFLAGS += -fPIC -DPIC
|
||||
LDFLAGS += -shared
|
||||
|
||||
LIBEAP = libeap.so
|
||||
libeap.so: $(EAP_LIBS) $(OBJS_lib)
|
||||
$(LDO) $(LDFLAGS) $^ -o $(LIBEAP)
|
||||
|
||||
endif
|
||||
|
||||
eap_example: $(OBJS_ex) $(LIBEAP)
|
||||
$(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
|
||||
|
||||
clean: common-clean
|
||||
rm -f core *~ *.o *.d libeap.a libeap.so
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
@ -1,42 +0,0 @@
|
||||
EAP peer/server library and example program
|
||||
Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||
|
||||
This software may be distributed under the terms of the BSD license.
|
||||
See the parent directory README for more details.
|
||||
|
||||
|
||||
The interfaces of the EAP server/peer implementation are based on RFC
|
||||
4137 (EAP State Machines). This RFC is coordinated with the state
|
||||
machines defined in IEEE 802.1X-2004. hostapd and wpa_supplicant
|
||||
include implementation of the IEEE 802.1X EAPOL state machines and the
|
||||
interface between them and EAP. However, the EAP implementation can be
|
||||
used with other protocols, too, by providing a compatible interface
|
||||
which maps the EAPOL<->EAP variables to another protocol.
|
||||
|
||||
This directory contains an example showing how EAP peer and server
|
||||
code from wpa_supplicant and hostapd can be used as a library. The
|
||||
example program initializes both an EAP server and an EAP peer
|
||||
entities and then runs through an EAP-PEAP/MSCHAPv2 authentication.
|
||||
|
||||
eap_example_peer.c shows the initialization and glue code needed to
|
||||
control the EAP peer implementation. eap_example_server.c does the
|
||||
same for EAP server. eap_example.c is an example that ties in both the
|
||||
EAP server and client parts to allow an EAP authentication to be
|
||||
shown.
|
||||
|
||||
In this example, the EAP messages are passed between the server and
|
||||
the peer are passed by direct function calls within the same process.
|
||||
In practice, server and peer functionalities would likely reside in
|
||||
separate devices and the EAP messages would be transmitted between the
|
||||
devices based on an external protocol. For example, in IEEE 802.11
|
||||
uses IEEE 802.1X EAPOL state machines to control the transmission of
|
||||
EAP messages and WiMax supports optional PMK EAP authentication
|
||||
mechanism that transmits EAP messages as defined in IEEE 802.16e.
|
||||
|
||||
|
||||
The EAP library links in number of helper functions from src/utils and
|
||||
src/crypto directories. Most of these are suitable as-is, but it may
|
||||
be desirable to replace the debug output code in src/utils/wpa_debug.c
|
||||
by dropping this file from the library and re-implementing the
|
||||
functions there in a way that better fits in with the main
|
||||
application.
|
@ -1,55 +0,0 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 15624081837803162817 (0xd8d3e3a6cbe3ccc1)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=FI, O=w1.fi, CN=Root CA
|
||||
Validity
|
||||
Not Before: Jun 29 16:41:22 2013 GMT
|
||||
Not After : Jun 27 16:41:22 2023 GMT
|
||||
Subject: C=FI, O=w1.fi, CN=Root CA
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (1024 bit)
|
||||
Modulus:
|
||||
00:be:1e:86:e4:79:03:c1:d1:94:d5:d4:b3:b1:28:
|
||||
90:76:fb:b8:a6:cd:6d:1c:d1:48:f4:08:9a:67:ff:
|
||||
f9:a6:54:b1:19:29:df:29:1b:cd:f1:6f:66:01:e7:
|
||||
db:79:ce:c0:39:2a:25:13:26:94:0c:2c:7b:5a:2c:
|
||||
81:0f:94:ee:51:d0:75:e6:46:db:17:46:a7:15:8b:
|
||||
0e:57:0f:b0:54:76:63:12:ca:86:18:bc:1a:c3:16:
|
||||
c0:70:09:d6:6b:43:39:b8:98:29:46:ac:cb:6a:ad:
|
||||
38:88:3b:07:dc:81:cd:3a:f6:1d:f6:2f:ef:1d:d7:
|
||||
ae:8a:b6:d1:e7:b3:15:02:b9
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
|
||||
|
||||
X509v3 Basic Constraints:
|
||||
CA:TRUE
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
1a:cf:77:60:44:43:c4:55:0e:99:e0:89:aa:b9:d3:7b:32:b7:
|
||||
5c:9c:7c:ca:fe:8c:d4:94:c6:5e:f3:83:19:5f:29:59:68:a4:
|
||||
4f:dc:04:2e:b8:71:c0:6d:3b:ae:01:e4:b9:88:99:cc:ce:82:
|
||||
be:6a:28:c2:ac:6a:94:c6:87:90:ed:85:3c:10:71:c5:ff:3c:
|
||||
70:64:e2:41:62:31:ea:86:7b:11:8c:93:ea:c6:f3:f3:4e:f9:
|
||||
d4:f2:81:90:d7:f4:fa:a1:91:6e:d4:dd:15:3e:26:3b:ac:1e:
|
||||
c3:c2:1f:ed:bb:34:bf:cb:b2:67:c6:c6:51:e8:51:22:b4:f3:
|
||||
92:e8
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICLDCCAZWgAwIBAgIJANjT46bL48zBMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
|
||||
BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xMzA2
|
||||
MjkxNjQxMjJaFw0yMzA2MjcxNjQxMjJaMC8xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
|
||||
DAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
|
||||
gYkCgYEAvh6G5HkDwdGU1dSzsSiQdvu4ps1tHNFI9AiaZ//5plSxGSnfKRvN8W9m
|
||||
Aefbec7AOSolEyaUDCx7WiyBD5TuUdB15kbbF0anFYsOVw+wVHZjEsqGGLwawxbA
|
||||
cAnWa0M5uJgpRqzLaq04iDsH3IHNOvYd9i/vHdeuirbR57MVArkCAwEAAaNQME4w
|
||||
HQYDVR0OBBYEFLiS3v2KGLMww59V8zNdtMgpikEUMB8GA1UdIwQYMBaAFLiS3v2K
|
||||
GLMww59V8zNdtMgpikEUMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA
|
||||
Gs93YERDxFUOmeCJqrnTezK3XJx8yv6M1JTGXvODGV8pWWikT9wELrhxwG07rgHk
|
||||
uYiZzM6CvmoowqxqlMaHkO2FPBBxxf88cGTiQWIx6oZ7EYyT6sbz80751PKBkNf0
|
||||
+qGRbtTdFT4mO6wew8If7bs0v8uyZ8bGUehRIrTzkug=
|
||||
-----END CERTIFICATE-----
|
@ -1,5 +0,0 @@
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIGHAoGBAP3V8IHq3H2DUlYywsvjYNuS17eCdt0mJo6/os6PHqdhgkMrPxF9u4Gr
|
||||
qKXq9e6GqmZYdjta30N3FkXaV924BJ0xOqb2TntiKg4u50/l6hSUneWt6UFBaizd
|
||||
XrqjNFIme/5RXMZ7RglXliBpCepAaFLMcKhOS4ulUyYYHSy+oqRjAgEC
|
||||
-----END DH PARAMETERS-----
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Example application showing how EAP peer and server code from
|
||||
* wpa_supplicant/hostapd can be used as a library. This example program
|
||||
* initializes both an EAP server and an EAP peer entities and then runs
|
||||
* through an EAP-PEAP/MSCHAPv2 authentication.
|
||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
int eap_example_peer_init(void);
|
||||
void eap_example_peer_deinit(void);
|
||||
int eap_example_peer_step(void);
|
||||
|
||||
int eap_example_server_init(void);
|
||||
void eap_example_server_deinit(void);
|
||||
int eap_example_server_step(void);
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int res_s, res_p;
|
||||
|
||||
wpa_debug_level = 0;
|
||||
|
||||
if (eap_example_peer_init() < 0 ||
|
||||
eap_example_server_init() < 0)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
printf("---[ server ]--------------------------------\n");
|
||||
res_s = eap_example_server_step();
|
||||
printf("---[ peer ]----------------------------------\n");
|
||||
res_p = eap_example_peer_step();
|
||||
} while (res_s || res_p);
|
||||
|
||||
eap_example_peer_deinit();
|
||||
eap_example_server_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,377 +0,0 @@
|
||||
/*
|
||||
* Example application showing how EAP peer code from wpa_supplicant can be
|
||||
* used as a library.
|
||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_peer/eap.h"
|
||||
#include "eap_peer/eap_config.h"
|
||||
#include "wpabuf.h"
|
||||
|
||||
void eap_example_server_rx(const u8 *data, size_t data_len);
|
||||
|
||||
|
||||
struct eap_peer_ctx {
|
||||
bool eapSuccess;
|
||||
bool eapRestart;
|
||||
bool eapFail;
|
||||
bool eapResp;
|
||||
bool eapNoResp;
|
||||
bool eapReq;
|
||||
bool portEnabled;
|
||||
bool altAccept; /* for EAP */
|
||||
bool altReject; /* for EAP */
|
||||
bool eapTriggerStart;
|
||||
|
||||
struct wpabuf *eapReqData; /* for EAP */
|
||||
|
||||
unsigned int idleWhile; /* for EAP state machine */
|
||||
|
||||
struct eap_peer_config eap_config;
|
||||
struct eap_sm *eap;
|
||||
};
|
||||
|
||||
|
||||
static struct eap_peer_ctx eap_ctx;
|
||||
|
||||
|
||||
static struct eap_peer_config * peer_get_config(void *ctx)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
return &peer->eap_config;
|
||||
}
|
||||
|
||||
|
||||
static bool peer_get_bool(void *ctx, enum eapol_bool_var variable)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return false;
|
||||
switch (variable) {
|
||||
case EAPOL_eapSuccess:
|
||||
return peer->eapSuccess;
|
||||
case EAPOL_eapRestart:
|
||||
return peer->eapRestart;
|
||||
case EAPOL_eapFail:
|
||||
return peer->eapFail;
|
||||
case EAPOL_eapResp:
|
||||
return peer->eapResp;
|
||||
case EAPOL_eapNoResp:
|
||||
return peer->eapNoResp;
|
||||
case EAPOL_eapReq:
|
||||
return peer->eapReq;
|
||||
case EAPOL_portEnabled:
|
||||
return peer->portEnabled;
|
||||
case EAPOL_altAccept:
|
||||
return peer->altAccept;
|
||||
case EAPOL_altReject:
|
||||
return peer->altReject;
|
||||
case EAPOL_eapTriggerStart:
|
||||
return peer->eapTriggerStart;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void peer_set_bool(void *ctx, enum eapol_bool_var variable, bool value)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return;
|
||||
switch (variable) {
|
||||
case EAPOL_eapSuccess:
|
||||
peer->eapSuccess = value;
|
||||
break;
|
||||
case EAPOL_eapRestart:
|
||||
peer->eapRestart = value;
|
||||
break;
|
||||
case EAPOL_eapFail:
|
||||
peer->eapFail = value;
|
||||
break;
|
||||
case EAPOL_eapResp:
|
||||
peer->eapResp = value;
|
||||
break;
|
||||
case EAPOL_eapNoResp:
|
||||
peer->eapNoResp = value;
|
||||
break;
|
||||
case EAPOL_eapReq:
|
||||
peer->eapReq = value;
|
||||
break;
|
||||
case EAPOL_portEnabled:
|
||||
peer->portEnabled = value;
|
||||
break;
|
||||
case EAPOL_altAccept:
|
||||
peer->altAccept = value;
|
||||
break;
|
||||
case EAPOL_altReject:
|
||||
peer->altReject = value;
|
||||
break;
|
||||
case EAPOL_eapTriggerStart:
|
||||
peer->eapTriggerStart = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned int peer_get_int(void *ctx, enum eapol_int_var variable)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return 0;
|
||||
switch (variable) {
|
||||
case EAPOL_idleWhile:
|
||||
return peer->idleWhile;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void peer_set_int(void *ctx, enum eapol_int_var variable,
|
||||
unsigned int value)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return;
|
||||
switch (variable) {
|
||||
case EAPOL_idleWhile:
|
||||
peer->idleWhile = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * peer_get_eapReqData(void *ctx)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL || peer->eapReqData == NULL)
|
||||
return NULL;
|
||||
|
||||
return peer->eapReqData;
|
||||
}
|
||||
|
||||
|
||||
static void peer_set_config_blob(void *ctx, struct wpa_config_blob *blob)
|
||||
{
|
||||
printf("TODO: %s\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
static const struct wpa_config_blob *
|
||||
peer_get_config_blob(void *ctx, const char *name)
|
||||
{
|
||||
printf("TODO: %s\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void peer_notify_pending(void *ctx)
|
||||
{
|
||||
printf("TODO: %s\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
static int eap_peer_register_methods(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef EAP_MD5
|
||||
if (ret == 0)
|
||||
ret = eap_peer_md5_register();
|
||||
#endif /* EAP_MD5 */
|
||||
|
||||
#ifdef EAP_TLS
|
||||
if (ret == 0)
|
||||
ret = eap_peer_tls_register();
|
||||
#endif /* EAP_TLS */
|
||||
|
||||
#ifdef EAP_MSCHAPv2
|
||||
if (ret == 0)
|
||||
ret = eap_peer_mschapv2_register();
|
||||
#endif /* EAP_MSCHAPv2 */
|
||||
|
||||
#ifdef EAP_PEAP
|
||||
if (ret == 0)
|
||||
ret = eap_peer_peap_register();
|
||||
#endif /* EAP_PEAP */
|
||||
|
||||
#ifdef EAP_TTLS
|
||||
if (ret == 0)
|
||||
ret = eap_peer_ttls_register();
|
||||
#endif /* EAP_TTLS */
|
||||
|
||||
#ifdef EAP_GTC
|
||||
if (ret == 0)
|
||||
ret = eap_peer_gtc_register();
|
||||
#endif /* EAP_GTC */
|
||||
|
||||
#ifdef EAP_OTP
|
||||
if (ret == 0)
|
||||
ret = eap_peer_otp_register();
|
||||
#endif /* EAP_OTP */
|
||||
|
||||
#ifdef EAP_SIM
|
||||
if (ret == 0)
|
||||
ret = eap_peer_sim_register();
|
||||
#endif /* EAP_SIM */
|
||||
|
||||
#ifdef EAP_LEAP
|
||||
if (ret == 0)
|
||||
ret = eap_peer_leap_register();
|
||||
#endif /* EAP_LEAP */
|
||||
|
||||
#ifdef EAP_PSK
|
||||
if (ret == 0)
|
||||
ret = eap_peer_psk_register();
|
||||
#endif /* EAP_PSK */
|
||||
|
||||
#ifdef EAP_AKA
|
||||
if (ret == 0)
|
||||
ret = eap_peer_aka_register();
|
||||
#endif /* EAP_AKA */
|
||||
|
||||
#ifdef EAP_AKA_PRIME
|
||||
if (ret == 0)
|
||||
ret = eap_peer_aka_prime_register();
|
||||
#endif /* EAP_AKA_PRIME */
|
||||
|
||||
#ifdef EAP_FAST
|
||||
if (ret == 0)
|
||||
ret = eap_peer_fast_register();
|
||||
#endif /* EAP_FAST */
|
||||
|
||||
#ifdef EAP_PAX
|
||||
if (ret == 0)
|
||||
ret = eap_peer_pax_register();
|
||||
#endif /* EAP_PAX */
|
||||
|
||||
#ifdef EAP_SAKE
|
||||
if (ret == 0)
|
||||
ret = eap_peer_sake_register();
|
||||
#endif /* EAP_SAKE */
|
||||
|
||||
#ifdef EAP_GPSK
|
||||
if (ret == 0)
|
||||
ret = eap_peer_gpsk_register();
|
||||
#endif /* EAP_GPSK */
|
||||
|
||||
#ifdef EAP_WSC
|
||||
if (ret == 0)
|
||||
ret = eap_peer_wsc_register();
|
||||
#endif /* EAP_WSC */
|
||||
|
||||
#ifdef EAP_IKEV2
|
||||
if (ret == 0)
|
||||
ret = eap_peer_ikev2_register();
|
||||
#endif /* EAP_IKEV2 */
|
||||
|
||||
#ifdef EAP_VENDOR_TEST
|
||||
if (ret == 0)
|
||||
ret = eap_peer_vendor_test_register();
|
||||
#endif /* EAP_VENDOR_TEST */
|
||||
|
||||
#ifdef EAP_TNC
|
||||
if (ret == 0)
|
||||
ret = eap_peer_tnc_register();
|
||||
#endif /* EAP_TNC */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct eapol_callbacks eap_cb;
|
||||
static struct eap_config eap_conf;
|
||||
|
||||
int eap_example_peer_init(void)
|
||||
{
|
||||
if (eap_peer_register_methods() < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&eap_ctx, 0, sizeof(eap_ctx));
|
||||
|
||||
eap_ctx.eap_config.identity = (u8 *) os_strdup("user");
|
||||
eap_ctx.eap_config.identity_len = 4;
|
||||
eap_ctx.eap_config.password = (u8 *) os_strdup("password");
|
||||
eap_ctx.eap_config.password_len = 8;
|
||||
eap_ctx.eap_config.cert.ca_cert = os_strdup("ca.pem");
|
||||
eap_ctx.eap_config.fragment_size = 1398;
|
||||
|
||||
os_memset(&eap_cb, 0, sizeof(eap_cb));
|
||||
eap_cb.get_config = peer_get_config;
|
||||
eap_cb.get_bool = peer_get_bool;
|
||||
eap_cb.set_bool = peer_set_bool;
|
||||
eap_cb.get_int = peer_get_int;
|
||||
eap_cb.set_int = peer_set_int;
|
||||
eap_cb.get_eapReqData = peer_get_eapReqData;
|
||||
eap_cb.set_config_blob = peer_set_config_blob;
|
||||
eap_cb.get_config_blob = peer_get_config_blob;
|
||||
eap_cb.notify_pending = peer_notify_pending;
|
||||
|
||||
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
||||
eap_ctx.eap = eap_peer_sm_init(&eap_ctx, &eap_cb, &eap_ctx, &eap_conf);
|
||||
if (eap_ctx.eap == NULL)
|
||||
return -1;
|
||||
|
||||
/* Enable "port" to allow authentication */
|
||||
eap_ctx.portEnabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_peer_deinit(void)
|
||||
{
|
||||
eap_peer_sm_deinit(eap_ctx.eap);
|
||||
eap_peer_unregister_methods();
|
||||
wpabuf_free(eap_ctx.eapReqData);
|
||||
os_free(eap_ctx.eap_config.identity);
|
||||
os_free(eap_ctx.eap_config.password);
|
||||
os_free(eap_ctx.eap_config.cert.ca_cert);
|
||||
}
|
||||
|
||||
|
||||
int eap_example_peer_step(void)
|
||||
{
|
||||
int res;
|
||||
res = eap_peer_sm_step(eap_ctx.eap);
|
||||
|
||||
if (eap_ctx.eapResp) {
|
||||
struct wpabuf *resp;
|
||||
printf("==> Response\n");
|
||||
eap_ctx.eapResp = false;
|
||||
resp = eap_get_eapRespData(eap_ctx.eap);
|
||||
if (resp) {
|
||||
/* Send EAP response to the server */
|
||||
eap_example_server_rx(wpabuf_head(resp),
|
||||
wpabuf_len(resp));
|
||||
wpabuf_free(resp);
|
||||
}
|
||||
}
|
||||
|
||||
if (eap_ctx.eapSuccess) {
|
||||
res = 0;
|
||||
if (eap_key_available(eap_ctx.eap)) {
|
||||
const u8 *key;
|
||||
size_t key_len;
|
||||
key = eap_get_eapKeyData(eap_ctx.eap, &key_len);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP keying material",
|
||||
key, key_len);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_peer_rx(const u8 *data, size_t data_len)
|
||||
{
|
||||
/* Make received EAP message available to the EAP library */
|
||||
eap_ctx.eapReq = true;
|
||||
wpabuf_free(eap_ctx.eapReqData);
|
||||
eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
|
||||
}
|
@ -1,300 +0,0 @@
|
||||
/*
|
||||
* Example application showing how EAP server code from hostapd can be used as
|
||||
* a library.
|
||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "wpabuf.h"
|
||||
|
||||
void eap_example_peer_rx(const u8 *data, size_t data_len);
|
||||
|
||||
|
||||
struct eap_server_ctx {
|
||||
struct eap_eapol_interface *eap_if;
|
||||
struct eap_sm *eap;
|
||||
void *tls_ctx;
|
||||
};
|
||||
|
||||
static struct eap_server_ctx eap_ctx;
|
||||
|
||||
|
||||
static int server_get_eap_user(void *ctx, const u8 *identity,
|
||||
size_t identity_len, int phase2,
|
||||
struct eap_user *user)
|
||||
{
|
||||
os_memset(user, 0, sizeof(*user));
|
||||
|
||||
if (!phase2) {
|
||||
/* Only allow EAP-PEAP as the Phase 1 method */
|
||||
user->methods[0].vendor = EAP_VENDOR_IETF;
|
||||
user->methods[0].method = EAP_TYPE_PEAP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (identity_len != 4 || identity == NULL ||
|
||||
os_memcmp(identity, "user", 4) != 0) {
|
||||
printf("Unknown user\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Only allow EAP-MSCHAPv2 as the Phase 2 method */
|
||||
user->methods[0].vendor = EAP_VENDOR_IETF;
|
||||
user->methods[0].method = EAP_TYPE_MSCHAPV2;
|
||||
user->password = (u8 *) os_strdup("password");
|
||||
user->password_len = 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
|
||||
{
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct eapol_callbacks eap_cb;
|
||||
static struct eap_config eap_conf;
|
||||
|
||||
static int eap_example_server_init_tls(void)
|
||||
{
|
||||
struct tls_config tconf;
|
||||
struct tls_connection_params tparams;
|
||||
|
||||
os_memset(&tconf, 0, sizeof(tconf));
|
||||
eap_ctx.tls_ctx = tls_init(&tconf);
|
||||
if (eap_ctx.tls_ctx == NULL)
|
||||
return -1;
|
||||
|
||||
os_memset(&tparams, 0, sizeof(tparams));
|
||||
tparams.ca_cert = "ca.pem";
|
||||
tparams.client_cert = "server.pem";
|
||||
/* tparams.private_key = "server.key"; */
|
||||
tparams.private_key = "server-key.pem";
|
||||
/* tparams.private_key_passwd = "whatever"; */
|
||||
tparams.dh_file = "dh.conf";
|
||||
|
||||
if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
|
||||
printf("Failed to set TLS parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tls_global_set_verify(eap_ctx.tls_ctx, 0, 1)) {
|
||||
printf("Failed to set check_crl\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int eap_server_register_methods(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef EAP_SERVER_IDENTITY
|
||||
if (ret == 0)
|
||||
ret = eap_server_identity_register();
|
||||
#endif /* EAP_SERVER_IDENTITY */
|
||||
|
||||
#ifdef EAP_SERVER_MD5
|
||||
if (ret == 0)
|
||||
ret = eap_server_md5_register();
|
||||
#endif /* EAP_SERVER_MD5 */
|
||||
|
||||
#ifdef EAP_SERVER_TLS
|
||||
if (ret == 0)
|
||||
ret = eap_server_tls_register();
|
||||
#endif /* EAP_SERVER_TLS */
|
||||
|
||||
#ifdef EAP_SERVER_MSCHAPV2
|
||||
if (ret == 0)
|
||||
ret = eap_server_mschapv2_register();
|
||||
#endif /* EAP_SERVER_MSCHAPV2 */
|
||||
|
||||
#ifdef EAP_SERVER_PEAP
|
||||
if (ret == 0)
|
||||
ret = eap_server_peap_register();
|
||||
#endif /* EAP_SERVER_PEAP */
|
||||
|
||||
#ifdef EAP_SERVER_TLV
|
||||
if (ret == 0)
|
||||
ret = eap_server_tlv_register();
|
||||
#endif /* EAP_SERVER_TLV */
|
||||
|
||||
#ifdef EAP_SERVER_GTC
|
||||
if (ret == 0)
|
||||
ret = eap_server_gtc_register();
|
||||
#endif /* EAP_SERVER_GTC */
|
||||
|
||||
#ifdef EAP_SERVER_TTLS
|
||||
if (ret == 0)
|
||||
ret = eap_server_ttls_register();
|
||||
#endif /* EAP_SERVER_TTLS */
|
||||
|
||||
#ifdef EAP_SERVER_SIM
|
||||
if (ret == 0)
|
||||
ret = eap_server_sim_register();
|
||||
#endif /* EAP_SERVER_SIM */
|
||||
|
||||
#ifdef EAP_SERVER_AKA
|
||||
if (ret == 0)
|
||||
ret = eap_server_aka_register();
|
||||
#endif /* EAP_SERVER_AKA */
|
||||
|
||||
#ifdef EAP_SERVER_AKA_PRIME
|
||||
if (ret == 0)
|
||||
ret = eap_server_aka_prime_register();
|
||||
#endif /* EAP_SERVER_AKA_PRIME */
|
||||
|
||||
#ifdef EAP_SERVER_PAX
|
||||
if (ret == 0)
|
||||
ret = eap_server_pax_register();
|
||||
#endif /* EAP_SERVER_PAX */
|
||||
|
||||
#ifdef EAP_SERVER_PSK
|
||||
if (ret == 0)
|
||||
ret = eap_server_psk_register();
|
||||
#endif /* EAP_SERVER_PSK */
|
||||
|
||||
#ifdef EAP_SERVER_SAKE
|
||||
if (ret == 0)
|
||||
ret = eap_server_sake_register();
|
||||
#endif /* EAP_SERVER_SAKE */
|
||||
|
||||
#ifdef EAP_SERVER_GPSK
|
||||
if (ret == 0)
|
||||
ret = eap_server_gpsk_register();
|
||||
#endif /* EAP_SERVER_GPSK */
|
||||
|
||||
#ifdef EAP_SERVER_VENDOR_TEST
|
||||
if (ret == 0)
|
||||
ret = eap_server_vendor_test_register();
|
||||
#endif /* EAP_SERVER_VENDOR_TEST */
|
||||
|
||||
#ifdef EAP_SERVER_FAST
|
||||
if (ret == 0)
|
||||
ret = eap_server_fast_register();
|
||||
#endif /* EAP_SERVER_FAST */
|
||||
|
||||
#ifdef EAP_SERVER_WSC
|
||||
if (ret == 0)
|
||||
ret = eap_server_wsc_register();
|
||||
#endif /* EAP_SERVER_WSC */
|
||||
|
||||
#ifdef EAP_SERVER_IKEV2
|
||||
if (ret == 0)
|
||||
ret = eap_server_ikev2_register();
|
||||
#endif /* EAP_SERVER_IKEV2 */
|
||||
|
||||
#ifdef EAP_SERVER_TNC
|
||||
if (ret == 0)
|
||||
ret = eap_server_tnc_register();
|
||||
#endif /* EAP_SERVER_TNC */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int eap_example_server_init(void)
|
||||
{
|
||||
struct eap_session_data eap_sess;
|
||||
|
||||
if (eap_server_register_methods() < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&eap_ctx, 0, sizeof(eap_ctx));
|
||||
|
||||
if (eap_example_server_init_tls() < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&eap_cb, 0, sizeof(eap_cb));
|
||||
eap_cb.get_eap_user = server_get_eap_user;
|
||||
eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
|
||||
|
||||
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
||||
eap_conf.eap_server = 1;
|
||||
eap_conf.ssl_ctx = eap_ctx.tls_ctx;
|
||||
|
||||
os_memset(&eap_sess, 0, sizeof(eap_sess));
|
||||
eap_ctx.eap = eap_server_sm_init(&eap_ctx, &eap_cb, &eap_conf,
|
||||
&eap_sess);
|
||||
if (eap_ctx.eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
|
||||
|
||||
/* Enable "port" and request EAP to start authentication. */
|
||||
eap_ctx.eap_if->portEnabled = true;
|
||||
eap_ctx.eap_if->eapRestart = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_server_deinit(void)
|
||||
{
|
||||
eap_server_sm_deinit(eap_ctx.eap);
|
||||
eap_server_unregister_methods();
|
||||
tls_deinit(eap_ctx.tls_ctx);
|
||||
}
|
||||
|
||||
|
||||
int eap_example_server_step(void)
|
||||
{
|
||||
int res, process = 0;
|
||||
|
||||
res = eap_server_sm_step(eap_ctx.eap);
|
||||
|
||||
if (eap_ctx.eap_if->eapReq) {
|
||||
printf("==> Request\n");
|
||||
process = 1;
|
||||
eap_ctx.eap_if->eapReq = 0;
|
||||
}
|
||||
|
||||
if (eap_ctx.eap_if->eapSuccess) {
|
||||
printf("==> Success\n");
|
||||
process = 1;
|
||||
res = 0;
|
||||
eap_ctx.eap_if->eapSuccess = 0;
|
||||
|
||||
if (eap_ctx.eap_if->eapKeyAvailable) {
|
||||
wpa_hexdump(MSG_DEBUG, "EAP keying material",
|
||||
eap_ctx.eap_if->eapKeyData,
|
||||
eap_ctx.eap_if->eapKeyDataLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (eap_ctx.eap_if->eapFail) {
|
||||
printf("==> Fail\n");
|
||||
process = 1;
|
||||
eap_ctx.eap_if->eapFail = 0;
|
||||
}
|
||||
|
||||
if (process && eap_ctx.eap_if->eapReqData) {
|
||||
/* Send EAP request to the peer */
|
||||
eap_example_peer_rx(wpabuf_head(eap_ctx.eap_if->eapReqData),
|
||||
wpabuf_len(eap_ctx.eap_if->eapReqData));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_server_rx(const u8 *data, size_t data_len)
|
||||
{
|
||||
/* Make received EAP message available to the EAP library */
|
||||
wpabuf_free(eap_ctx.eap_if->eapRespData);
|
||||
eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
|
||||
if (eap_ctx.eap_if->eapRespData)
|
||||
eap_ctx.eap_if->eapResp = true;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQC6oHdVIhSFVWWbZCyt7ZvdZTHJ2mBQzjjWNNzovBueMOcS41Ns
|
||||
ye1IA3mBaZjOirh3RzZFz8bg8XsecYlU9wHMIq2gQrGoNZ5gqjqYUdD/H+6+jQpj
|
||||
+6I5F/JkYfZlAjJ5dOGf0YllVanDIJ6/aVaz908/qVTC2o88r/J1VPp+gQIDAQAB
|
||||
AoGAR/C5b3DOtkMgAtGPw5AXiDWNBsGOZTfJgxEnovN4Nfel64sDyqjgNeVY/kDl
|
||||
baDd0OT7j9ezU1zi1+5uQPlikFSvzgpdLgQhKkvWLzzehafb2uVaJ4VsRqS3WXK8
|
||||
RE06cYx4VQRkvQvMAXWsuua9pw36OrlpQnm3HlAbrks8Mm0CQQDgMEu2WPMWP2wj
|
||||
Q8735zbj7D0AxEFlcegPZr/QZ3qU//G0HL35FG18lsuTbDzesrf7apo3W1BBQLjS
|
||||
ZSNtyNsLAkEA1Ru6aEy/Cj2u1GYHu1u/RcshKC+W7rdVT0wDeiSTUzKafZNiwVhY
|
||||
1Epk4k5HnHB327ysTI1LiOzUMMmuNYUkIwJAKUkbmFAXLCCv5GqnYcXluOGXdl2u
|
||||
AWWRq8xrRJDZ5TihJV8pqQYXB5upj9Od/hEBir5d+hXJ2Mp3ft97P8t+cwJAGeWQ
|
||||
tXP+EySDxlPPxLjVeYnBsbx2vvOQbl5yXblsHcQcef4bFhvCT6nqsIWKtjwElLNM
|
||||
zNCuySjecD9R6DcRuQJBAJWrpgny77wP29x1WQ/29J8ZJfxe4N5wAj1SePBVNgZ3
|
||||
gfm1O+c6niNwe8RnfQimppLrrR+qK33te2SPGXiwi6g=
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1,16 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALqgd1UiFIVVZZtk
|
||||
LK3tm91lMcnaYFDOONY03Oi8G54w5xLjU2zJ7UgDeYFpmM6KuHdHNkXPxuDxex5x
|
||||
iVT3AcwiraBCsag1nmCqOphR0P8f7r6NCmP7ojkX8mRh9mUCMnl04Z/RiWVVqcMg
|
||||
nr9pVrP3Tz+pVMLajzyv8nVU+n6BAgMBAAECgYBH8LlvcM62QyAC0Y/DkBeINY0G
|
||||
wY5lN8mDESei83g196XriwPKqOA15Vj+QOVtoN3Q5PuP17NTXOLX7m5A+WKQVK/O
|
||||
Cl0uBCEqS9YvPN6Fp9va5VonhWxGpLdZcrxETTpxjHhVBGS9C8wBday65r2nDfo6
|
||||
uWlCebceUBuuSzwybQJBAOAwS7ZY8xY/bCNDzvfnNuPsPQDEQWVx6A9mv9BnepT/
|
||||
8bQcvfkUbXyWy5NsPN6yt/tqmjdbUEFAuNJlI23I2wsCQQDVG7poTL8KPa7UZge7
|
||||
W79FyyEoL5but1VPTAN6JJNTMpp9k2LBWFjUSmTiTkeccHfbvKxMjUuI7NQwya41
|
||||
hSQjAkApSRuYUBcsIK/kaqdhxeW44Zd2Xa4BZZGrzGtEkNnlOKElXympBhcHm6mP
|
||||
053+EQGKvl36FcnYynd+33s/y35zAkAZ5ZC1c/4TJIPGU8/EuNV5icGxvHa+85Bu
|
||||
XnJduWwdxBx5/hsWG8JPqeqwhYq2PASUs0zM0K7JKN5wP1HoNxG5AkEAlaumCfLv
|
||||
vA/b3HVZD/b0nxkl/F7g3nACPVJ48FU2BneB+bU75zqeI3B7xGd9CKamkuutH6or
|
||||
fe17ZI8ZeLCLqA==
|
||||
-----END PRIVATE KEY-----
|
@ -1,64 +0,0 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 15624081837803162903 (0xd8d3e3a6cbe3cd17)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C=FI, O=w1.fi, CN=Root CA
|
||||
Validity
|
||||
Not Before: Oct 3 22:13:55 2018 GMT
|
||||
Not After : Oct 3 22:13:55 2019 GMT
|
||||
Subject: C=FI, O=w1.fi, CN=server.w1.fi
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (1024 bit)
|
||||
Modulus:
|
||||
00:ba:a0:77:55:22:14:85:55:65:9b:64:2c:ad:ed:
|
||||
9b:dd:65:31:c9:da:60:50:ce:38:d6:34:dc:e8:bc:
|
||||
1b:9e:30:e7:12:e3:53:6c:c9:ed:48:03:79:81:69:
|
||||
98:ce:8a:b8:77:47:36:45:cf:c6:e0:f1:7b:1e:71:
|
||||
89:54:f7:01:cc:22:ad:a0:42:b1:a8:35:9e:60:aa:
|
||||
3a:98:51:d0:ff:1f:ee:be:8d:0a:63:fb:a2:39:17:
|
||||
f2:64:61:f6:65:02:32:79:74:e1:9f:d1:89:65:55:
|
||||
a9:c3:20:9e:bf:69:56:b3:f7:4f:3f:a9:54:c2:da:
|
||||
8f:3c:af:f2:75:54:fa:7e:81
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
X509v3 Subject Key Identifier:
|
||||
31:4F:10:5C:67:9F:BE:4E:88:D6:DC:C5:AB:9E:12:88:86:69:02:4F
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
|
||||
|
||||
Authority Information Access:
|
||||
OCSP - URI:http://server.w1.fi:8888/
|
||||
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:server.w1.fi
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
b6:98:ae:d9:9b:9a:44:49:b2:06:ee:af:36:83:cb:cd:cb:c9:
|
||||
f3:38:6d:65:cb:e9:81:d2:25:dd:76:12:5c:da:3f:a1:0e:11:
|
||||
a5:04:ed:05:29:2d:66:94:82:a2:80:67:d1:d8:78:71:72:5f:
|
||||
10:c3:51:a2:7b:f5:0b:5f:ec:70:12:99:cb:65:6f:50:7f:2b:
|
||||
05:7c:b4:d7:1b:21:77:66:47:33:f3:a7:d6:fb:ce:97:fe:5f:
|
||||
fd:df:1f:1d:6f:ef:22:5a:c6:78:d2:2b:07:1e:55:ec:80:62:
|
||||
06:7a:be:6a:0d:4d:96:c2:d5:df:76:56:b0:85:6a:f8:a0:27:
|
||||
62:31
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIClTCCAf6gAwIBAgIJANjT46bL480XMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
|
||||
BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xODEw
|
||||
MDMyMjEzNTVaFw0xOTEwMDMyMjEzNTVaMDQxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
|
||||
DAV3MS5maTEVMBMGA1UEAwwMc2VydmVyLncxLmZpMIGfMA0GCSqGSIb3DQEBAQUA
|
||||
A4GNADCBiQKBgQC6oHdVIhSFVWWbZCyt7ZvdZTHJ2mBQzjjWNNzovBueMOcS41Ns
|
||||
ye1IA3mBaZjOirh3RzZFz8bg8XsecYlU9wHMIq2gQrGoNZ5gqjqYUdD/H+6+jQpj
|
||||
+6I5F/JkYfZlAjJ5dOGf0YllVanDIJ6/aVaz908/qVTC2o88r/J1VPp+gQIDAQAB
|
||||
o4GzMIGwMAkGA1UdEwQCMAAwHQYDVR0OBBYEFDFPEFxnn75OiNbcxaueEoiGaQJP
|
||||
MB8GA1UdIwQYMBaAFLiS3v2KGLMww59V8zNdtMgpikEUMDUGCCsGAQUFBwEBBCkw
|
||||
JzAlBggrBgEFBQcwAYYZaHR0cDovL3NlcnZlci53MS5maTo4ODg4LzAXBgNVHREE
|
||||
EDAOggxzZXJ2ZXIudzEuZmkwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcN
|
||||
AQELBQADgYEAtpiu2ZuaREmyBu6vNoPLzcvJ8zhtZcvpgdIl3XYSXNo/oQ4RpQTt
|
||||
BSktZpSCooBn0dh4cXJfEMNRonv1C1/scBKZy2VvUH8rBXy01xshd2ZHM/On1vvO
|
||||
l/5f/d8fHW/vIlrGeNIrBx5V7IBiBnq+ag1NlsLV33ZWsIVq+KAnYjE=
|
||||
-----END CERTIFICATE-----
|
5
contrib/wpa/hostapd/.gitignore
vendored
5
contrib/wpa/hostapd/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
.config
|
||||
hostapd
|
||||
hostapd_cli
|
||||
hlr_auc_gw
|
||||
nt_password_hash
|
@ -1,196 +0,0 @@
|
||||
/*
|
||||
* SAE-PK password/modifier generator
|
||||
* Copyright (c) 2020, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/base64.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "common/sae.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *der = NULL;
|
||||
size_t der_len;
|
||||
struct crypto_ec_key *key = NULL;
|
||||
struct wpabuf *pub = NULL;
|
||||
u8 *data = NULL, *m;
|
||||
size_t data_len;
|
||||
char *b64 = NULL, *pw = NULL, *pos, *src;
|
||||
int sec, j;
|
||||
int ret = -1;
|
||||
u8 hash[SAE_MAX_HASH_LEN];
|
||||
char hash_hex[2 * SAE_MAX_HASH_LEN + 1];
|
||||
u8 pw_base_bin[SAE_MAX_HASH_LEN];
|
||||
u8 *dst;
|
||||
int group;
|
||||
size_t hash_len;
|
||||
unsigned long long i, expected;
|
||||
char m_hex[2 * SAE_PK_M_LEN + 1];
|
||||
u32 sec_1b, val20;
|
||||
|
||||
wpa_debug_level = MSG_INFO;
|
||||
if (os_program_init() < 0)
|
||||
goto fail;
|
||||
|
||||
if (argc != 4) {
|
||||
fprintf(stderr,
|
||||
"usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sec = atoi(argv[2]);
|
||||
if (sec != 3 && sec != 5) {
|
||||
fprintf(stderr,
|
||||
"Invalid Sec value (allowed values: 3 and 5)\n");
|
||||
goto fail;
|
||||
}
|
||||
sec_1b = sec == 3;
|
||||
expected = 1;
|
||||
for (j = 0; j < sec; j++)
|
||||
expected *= 256;
|
||||
|
||||
der = os_readfile(argv[1], &der_len);
|
||||
if (!der) {
|
||||
fprintf(stderr, "Could not read %s: %s\n",
|
||||
argv[1], strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
key = crypto_ec_key_parse_priv((u8 *) der, der_len);
|
||||
if (!key) {
|
||||
fprintf(stderr, "Could not parse ECPrivateKey\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pub = crypto_ec_key_get_subject_public_key(key);
|
||||
if (!pub) {
|
||||
fprintf(stderr, "Failed to build SubjectPublicKey\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
group = crypto_ec_key_group(key);
|
||||
switch (group) {
|
||||
case 19:
|
||||
hash_len = 32;
|
||||
break;
|
||||
case 20:
|
||||
hash_len = 48;
|
||||
break;
|
||||
case 21:
|
||||
hash_len = 64;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported private key group\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data_len = os_strlen(argv[3]) + SAE_PK_M_LEN + wpabuf_len(pub);
|
||||
data = os_malloc(data_len);
|
||||
if (!data) {
|
||||
fprintf(stderr, "No memory for data buffer\n");
|
||||
goto fail;
|
||||
}
|
||||
os_memcpy(data, argv[3], os_strlen(argv[3]));
|
||||
m = data + os_strlen(argv[3]);
|
||||
if (os_get_random(m, SAE_PK_M_LEN) < 0) {
|
||||
fprintf(stderr, "Could not generate random Modifier M\n");
|
||||
goto fail;
|
||||
}
|
||||
os_memcpy(m + SAE_PK_M_LEN, wpabuf_head(pub), wpabuf_len(pub));
|
||||
|
||||
fprintf(stderr, "Searching for a suitable Modifier M value\n");
|
||||
for (i = 0;; i++) {
|
||||
if (sae_hash(hash_len, data, data_len, hash) < 0) {
|
||||
fprintf(stderr, "Hash failed\n");
|
||||
goto fail;
|
||||
}
|
||||
if (hash[0] == 0 && hash[1] == 0) {
|
||||
if ((hash[2] & 0xf0) == 0)
|
||||
fprintf(stderr, "\r%3.2f%%",
|
||||
100.0 * (double) i / (double) expected);
|
||||
for (j = 2; j < sec; j++) {
|
||||
if (hash[j])
|
||||
break;
|
||||
}
|
||||
if (j == sec)
|
||||
break;
|
||||
}
|
||||
inc_byte_array(m, SAE_PK_M_LEN);
|
||||
}
|
||||
|
||||
if (wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0 ||
|
||||
wpa_snprintf_hex(hash_hex, sizeof(hash_hex), hash, hash_len) < 0)
|
||||
goto fail;
|
||||
fprintf(stderr, "\nFound a valid hash in %llu iterations: %s\n",
|
||||
i + 1, hash_hex);
|
||||
|
||||
b64 = base64_encode(der, der_len, NULL);
|
||||
if (!b64)
|
||||
goto fail;
|
||||
src = pos = b64;
|
||||
while (*src) {
|
||||
if (*src != '\n')
|
||||
*pos++ = *src;
|
||||
src++;
|
||||
}
|
||||
*pos = '\0';
|
||||
|
||||
/* Skip 8*Sec bits and add Sec_1b as the every 20th bit starting with
|
||||
* one. */
|
||||
os_memset(pw_base_bin, 0, sizeof(pw_base_bin));
|
||||
dst = pw_base_bin;
|
||||
for (j = 0; j < 8 * (int) hash_len / 20; j++) {
|
||||
val20 = sae_pk_get_be19(hash + sec);
|
||||
val20 |= sec_1b << 19;
|
||||
sae_pk_buf_shift_left_19(hash + sec, hash_len - sec);
|
||||
|
||||
if (j & 1) {
|
||||
*dst |= (val20 >> 16) & 0x0f;
|
||||
dst++;
|
||||
*dst++ = (val20 >> 8) & 0xff;
|
||||
*dst++ = val20 & 0xff;
|
||||
} else {
|
||||
*dst++ = (val20 >> 12) & 0xff;
|
||||
*dst++ = (val20 >> 4) & 0xff;
|
||||
*dst = (val20 << 4) & 0xf0;
|
||||
}
|
||||
}
|
||||
if (wpa_snprintf_hex(hash_hex, sizeof(hash_hex),
|
||||
pw_base_bin, hash_len - sec) >= 0)
|
||||
fprintf(stderr, "PasswordBase binary data for base32: %s",
|
||||
hash_hex);
|
||||
|
||||
pw = sae_pk_base32_encode(pw_base_bin, 20 * 3 - 5);
|
||||
if (!pw)
|
||||
goto fail;
|
||||
|
||||
printf("# SAE-PK password/M/private key for Sec=%d.\n", sec);
|
||||
printf("sae_password=%s|pk=%s:%s\n", pw, m_hex, b64);
|
||||
printf("# Longer passwords can be used for improved security at the cost of usability:\n");
|
||||
for (j = 4; j <= ((int) hash_len * 8 + 5 - 8 * sec) / 19; j++) {
|
||||
os_free(pw);
|
||||
pw = sae_pk_base32_encode(pw_base_bin, 20 * j - 5);
|
||||
if (pw)
|
||||
printf("# %s\n", pw);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
os_free(der);
|
||||
wpabuf_free(pub);
|
||||
crypto_ec_key_deinit(key);
|
||||
os_free(data);
|
||||
os_free(b64);
|
||||
os_free(pw);
|
||||
|
||||
os_program_deinit();
|
||||
|
||||
return ret;
|
||||
}
|
1
contrib/wpa/hs20/server/.gitignore
vendored
1
contrib/wpa/hs20/server/.gitignore
vendored
@ -1 +0,0 @@
|
||||
hs20_spp_server
|
@ -1,42 +0,0 @@
|
||||
ALL=hs20_spp_server
|
||||
|
||||
include ../../src/build.rules
|
||||
|
||||
CFLAGS += -I../../src
|
||||
CFLAGS += -I../../src/utils
|
||||
CFLAGS += -I../../src/crypto
|
||||
|
||||
LIBS += -lsqlite3
|
||||
|
||||
# Using glibc < 2.17 requires -lrt for clock_gettime()
|
||||
LIBS += -lrt
|
||||
|
||||
ifndef CONFIG_NO_GITVER
|
||||
# Add VERSION_STR postfix for builds from a git repository
|
||||
ifeq ($(wildcard ../../.git),../../.git)
|
||||
GITVER := $(shell git describe --dirty=+)
|
||||
ifneq ($(GITVER),)
|
||||
CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
OBJS=spp_server.o
|
||||
OBJS += hs20_spp_server.o
|
||||
OBJS += ../../src/utils/xml-utils.o
|
||||
OBJS += ../../src/utils/base64.o
|
||||
OBJS += ../../src/utils/common.o
|
||||
OBJS += ../../src/utils/os_unix.o
|
||||
OBJS += ../../src/utils/wpa_debug.o
|
||||
OBJS += ../../src/crypto/md5-internal.o
|
||||
CFLAGS += $(shell xml2-config --cflags)
|
||||
LIBS += $(shell xml2-config --libs)
|
||||
OBJS += ../../src/utils/xml_libxml2.o
|
||||
|
||||
_OBJS_VAR := OBJS
|
||||
include ../../src/objs.mk
|
||||
hs20_spp_server: $(OBJS)
|
||||
$(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
|
||||
|
||||
clean: common-clean
|
||||
rm -f core *~
|
@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
for i in server-client server server-revoked user ocsp; do
|
||||
rm -f $i.csr $i.key $i.pem
|
||||
done
|
||||
|
||||
rm -f openssl.cnf.tmp
|
||||
if [ -d demoCA ]; then
|
||||
rm -r demoCA
|
||||
fi
|
||||
rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der
|
||||
rm -f my-openssl.cnf my-openssl-root.cnf
|
||||
#rm -r rootCA
|
@ -1,17 +0,0 @@
|
||||
asn1 = SEQUENCE:attrs
|
||||
|
||||
[attrs]
|
||||
#oid1 = OID:challengePassword
|
||||
attr1 = SEQUENCE:extreq
|
||||
oid2 = OID:sha256WithRSAEncryption
|
||||
|
||||
[extreq]
|
||||
oid = OID:extensionRequest
|
||||
vals = SET:extreqvals
|
||||
|
||||
[extreqvals]
|
||||
|
||||
oid1 = OID:macAddress
|
||||
#oid2 = OID:imei
|
||||
#oid3 = OID:meid
|
||||
#oid4 = OID:DevId
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
openssl asn1parse -genconf est-csrattrs.cnf -out est-csrattrs.der -oid hs20.oid
|
||||
base64 est-csrattrs.der > est-attrs.b64
|
@ -1,7 +0,0 @@
|
||||
1.3.6.1.1.1.1.22 macAddress
|
||||
1.2.840.113549.1.9.14 extensionRequest
|
||||
1.3.6.1.4.1.40808.1.1.1 id-wfa-hotspot-friendlyName
|
||||
1.3.6.1.4.1.40808.1.1.2 id-kp-HS2.0Auth
|
||||
1.3.6.1.4.1.40808.1.1.3 imei
|
||||
1.3.6.1.4.1.40808.1.1.4 meid
|
||||
1.3.6.1.4.1.40808.1.1.5 DevId
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
for i in *.pem; do
|
||||
echo "===[ $i ]==================="
|
||||
openssl ocsp -text -CAfile ca.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
|
||||
|
||||
# openssl ocsp -text -CAfile rootCA/cacert.pem -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
|
||||
|
||||
# openssl ocsp -text -CAfile rootCA/cacert.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
|
||||
# openssl ocsp -text -CAfile rootCA/cacert.pem -VAfile ca.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
|
||||
done
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner demoCA/cacert.pem -rkey demoCA/private/cakey-plain.pem -CA demoCA/cacert.pem -resp_no_certs -text
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
|
||||
openssl ocsp \
|
||||
-no_nonce \
|
||||
-CAfile ca.pem \
|
||||
-verify_other demoCA/cacert.pem \
|
||||
-issuer demoCA/cacert.pem \
|
||||
-cert server.pem \
|
||||
-url http://localhost:8888/ \
|
||||
-respout ocsp-server-cache.der
|
@ -1,125 +0,0 @@
|
||||
# OpenSSL configuration file for Hotspot 2.0 PKI (Root CA)
|
||||
|
||||
HOME = .
|
||||
RANDFILE = $ENV::HOME/.rnd
|
||||
oid_section = new_oids
|
||||
|
||||
[ new_oids ]
|
||||
|
||||
#logotypeoid=1.3.6.1.5.5.7.1.12
|
||||
|
||||
####################################################################
|
||||
[ ca ]
|
||||
default_ca = CA_default # The default ca section
|
||||
|
||||
####################################################################
|
||||
[ CA_default ]
|
||||
|
||||
dir = ./rootCA # Where everything is kept
|
||||
certs = $dir/certs # Where the issued certs are kept
|
||||
crl_dir = $dir/crl # Where the issued crl are kept
|
||||
database = $dir/index.txt # database index file.
|
||||
#unique_subject = no # Set to 'no' to allow creation of
|
||||
# several certificates with same subject
|
||||
new_certs_dir = $dir/newcerts # default place for new certs.
|
||||
|
||||
certificate = $dir/cacert.pem # The CA certificate
|
||||
serial = $dir/serial # The current serial number
|
||||
crlnumber = $dir/crlnumber # the current crl number
|
||||
# must be commented out to leave a V1 CRL
|
||||
crl = $dir/crl.pem # The current CRL
|
||||
private_key = $dir/private/cakey.pem# The private key
|
||||
RANDFILE = $dir/private/.rand # private random number file
|
||||
|
||||
x509_extensions = usr_cert # The extentions to add to the cert
|
||||
|
||||
name_opt = ca_default # Subject Name options
|
||||
cert_opt = ca_default # Certificate field options
|
||||
|
||||
default_days = 365 # how long to certify for
|
||||
default_crl_days= 30 # how long before next CRL
|
||||
default_md = default # use public key default MD
|
||||
preserve = no # keep passed DN ordering
|
||||
|
||||
policy = policy_match
|
||||
|
||||
# For the CA policy
|
||||
[ policy_match ]
|
||||
countryName = match
|
||||
stateOrProvinceName = optional
|
||||
organizationName = match
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[ policy_anything ]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
localityName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
x509_extensions = v3_ca # The extentions to add to the self signed cert
|
||||
|
||||
input_password = @PASSWORD@
|
||||
output_password = @PASSWORD@
|
||||
|
||||
string_mask = utf8only
|
||||
|
||||
[ req_distinguished_name ]
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_default = US
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
|
||||
localityName = Locality Name (eg, city)
|
||||
localityName_default = Tuusula
|
||||
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
0.organizationName_default = WFA Hotspot 2.0
|
||||
|
||||
##organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
#organizationalUnitName_default =
|
||||
#@OU@
|
||||
|
||||
commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
#@CN@
|
||||
commonName_max = 64
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 64
|
||||
|
||||
[ req_attributes ]
|
||||
|
||||
[ v3_req ]
|
||||
|
||||
# Extensions to add to a certificate request
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
subjectAltName=DNS:example.com,DNS:another.example.com
|
||||
|
||||
[ v3_ca ]
|
||||
|
||||
# Hotspot 2.0 PKI requirements
|
||||
subjectKeyIdentifier=hash
|
||||
basicConstraints = critical,CA:true
|
||||
keyUsage = critical, cRLSign, keyCertSign
|
||||
|
||||
[ crl_ext ]
|
||||
|
||||
# issuerAltName=issuer:copy
|
||||
authorityKeyIdentifier=keyid:always
|
||||
|
||||
[ v3_OCSP ]
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = OCSPSigning
|
@ -1,200 +0,0 @@
|
||||
# OpenSSL configuration file for Hotspot 2.0 PKI (Intermediate CA)
|
||||
|
||||
HOME = .
|
||||
RANDFILE = $ENV::HOME/.rnd
|
||||
oid_section = new_oids
|
||||
|
||||
[ new_oids ]
|
||||
|
||||
#logotypeoid=1.3.6.1.5.5.7.1.12
|
||||
|
||||
####################################################################
|
||||
[ ca ]
|
||||
default_ca = CA_default # The default ca section
|
||||
|
||||
####################################################################
|
||||
[ CA_default ]
|
||||
|
||||
dir = ./demoCA # Where everything is kept
|
||||
certs = $dir/certs # Where the issued certs are kept
|
||||
crl_dir = $dir/crl # Where the issued crl are kept
|
||||
database = $dir/index.txt # database index file.
|
||||
#unique_subject = no # Set to 'no' to allow creation of
|
||||
# several certificates with same subject
|
||||
new_certs_dir = $dir/newcerts # default place for new certs.
|
||||
|
||||
certificate = $dir/cacert.pem # The CA certificate
|
||||
serial = $dir/serial # The current serial number
|
||||
crlnumber = $dir/crlnumber # the current crl number
|
||||
# must be commented out to leave a V1 CRL
|
||||
crl = $dir/crl.pem # The current CRL
|
||||
private_key = $dir/private/cakey.pem# The private key
|
||||
RANDFILE = $dir/private/.rand # private random number file
|
||||
|
||||
x509_extensions = ext_client # The extentions to add to the cert
|
||||
|
||||
name_opt = ca_default # Subject Name options
|
||||
cert_opt = ca_default # Certificate field options
|
||||
|
||||
# Extension copying option: use with caution.
|
||||
copy_extensions = copy
|
||||
|
||||
default_days = 365 # how long to certify for
|
||||
default_crl_days= 30 # how long before next CRL
|
||||
default_md = default # use public key default MD
|
||||
preserve = no # keep passed DN ordering
|
||||
|
||||
policy = policy_match
|
||||
|
||||
# For the CA policy
|
||||
[ policy_match ]
|
||||
countryName = supplied
|
||||
stateOrProvinceName = optional
|
||||
organizationName = supplied
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[ policy_osu_server ]
|
||||
countryName = match
|
||||
stateOrProvinceName = optional
|
||||
organizationName = match
|
||||
organizationalUnitName = supplied
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[ policy_anything ]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
localityName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
x509_extensions = v3_ca # The extentions to add to the self signed cert
|
||||
|
||||
input_password = @PASSWORD@
|
||||
output_password = @PASSWORD@
|
||||
|
||||
string_mask = utf8only
|
||||
|
||||
[ req_distinguished_name ]
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_default = FI
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
|
||||
localityName = Locality Name (eg, city)
|
||||
localityName_default = Tuusula
|
||||
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
0.organizationName_default = @DOMAIN@
|
||||
|
||||
##organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
#organizationalUnitName_default =
|
||||
#@OU@
|
||||
|
||||
commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
#@CN@
|
||||
commonName_max = 64
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 64
|
||||
|
||||
[ req_attributes ]
|
||||
|
||||
[ v3_ca ]
|
||||
|
||||
# Hotspot 2.0 PKI requirements
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid:always,issuer
|
||||
basicConstraints = critical, CA:true, pathlen:0
|
||||
keyUsage = critical, cRLSign, keyCertSign
|
||||
authorityInfoAccess = OCSP;URI:@OCSP_URI@
|
||||
# For SP intermediate CA
|
||||
#subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU
|
||||
#nameConstraints=permitted;DNS:.@DOMAIN@
|
||||
#1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
|
||||
|
||||
[ v3_osu_server ]
|
||||
|
||||
basicConstraints = critical, CA:true, pathlen:0
|
||||
keyUsage = critical, keyEncipherment
|
||||
#@ALTNAME@
|
||||
|
||||
#logotypeoid=ASN1:SEQUENCE:LogotypeExtn
|
||||
1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
|
||||
[LogotypeExtn]
|
||||
communityLogos=EXP:0,SEQUENCE:LogotypeInfo
|
||||
[LogotypeInfo]
|
||||
# note: implicit tag converted to explicit for CHOICE
|
||||
direct=EXP:0,SEQUENCE:LogotypeData
|
||||
[LogotypeData]
|
||||
image=SEQUENCE:LogotypeImage
|
||||
[LogotypeImage]
|
||||
imageDetails=SEQUENCE:LogotypeDetails
|
||||
imageInfo=SEQUENCE:LogotypeImageInfo
|
||||
[LogotypeDetails]
|
||||
mediaType=IA5STRING:image/png
|
||||
logotypeHash=SEQUENCE:HashAlgAndValues
|
||||
logotypeURI=SEQUENCE:URI
|
||||
[HashAlgAndValues]
|
||||
value1=SEQUENCE:HashAlgAndValueSHA256
|
||||
#value2=SEQUENCE:HashAlgAndValueSHA1
|
||||
[HashAlgAndValueSHA256]
|
||||
hashAlg=SEQUENCE:sha256_alg
|
||||
hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@
|
||||
[HashAlgAndValueSHA1]
|
||||
hashAlg=SEQUENCE:sha1_alg
|
||||
hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@
|
||||
[sha256_alg]
|
||||
algorithm=OID:sha256
|
||||
[sha1_alg]
|
||||
algorithm=OID:sha1
|
||||
[URI]
|
||||
uri=IA5STRING:@LOGO_URI@
|
||||
[LogotypeImageInfo]
|
||||
# default value color(1), component optional
|
||||
#type=IMP:0,INTEGER:1
|
||||
fileSize=INTEGER:7549
|
||||
xSize=INTEGER:128
|
||||
ySize=INTEGER:80
|
||||
language=IMP:4,IA5STRING:zxx
|
||||
|
||||
[ crl_ext ]
|
||||
|
||||
# issuerAltName=issuer:copy
|
||||
authorityKeyIdentifier=keyid:always
|
||||
|
||||
[ v3_OCSP ]
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = OCSPSigning
|
||||
|
||||
[ ext_client ]
|
||||
|
||||
basicConstraints=CA:FALSE
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
authorityInfoAccess = OCSP;URI:@OCSP_URI@
|
||||
#@ALTNAME@
|
||||
extendedKeyUsage = clientAuth
|
||||
|
||||
[ ext_server ]
|
||||
|
||||
# Hotspot 2.0 PKI requirements
|
||||
basicConstraints=critical, CA:FALSE
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
authorityInfoAccess = OCSP;URI:@OCSP_URI@
|
||||
#@ALTNAME@
|
||||
extendedKeyUsage = critical, serverAuth
|
||||
keyUsage = critical, keyEncipherment
|
@ -1,209 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$OPENSSL" ]; then
|
||||
OPENSSL=openssl
|
||||
fi
|
||||
export OPENSSL_CONF=$PWD/openssl.cnf
|
||||
PASS=whatever
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
DOMAIN=w1.fi
|
||||
fi
|
||||
COMPANY=w1.fi
|
||||
OPER_ENG="engw1.fi TESTING USE"
|
||||
OPER_FI="finw1.fi TESTIKÄYTTÖ"
|
||||
CNR="Hotspot 2.0 Trust Root CA - 99"
|
||||
CNO="ocsp.$DOMAIN"
|
||||
CNV="osu-revoked.$DOMAIN"
|
||||
CNOC="osu-client.$DOMAIN"
|
||||
OSU_SERVER_HOSTNAME="osu.$DOMAIN"
|
||||
DEBUG=0
|
||||
OCSP_URI="http://$CNO:8888/"
|
||||
LOGO_URI="http://osu.w1.fi/w1fi_logo.png"
|
||||
LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d"
|
||||
LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b"
|
||||
|
||||
# Command line overrides
|
||||
USAGE=$( cat <<EOF
|
||||
Usage:\n
|
||||
# -c: Company name, used to generate Subject name CN for Intermediate CA\n
|
||||
# -C: Subject name CN of the Root CA ($CNR)\n
|
||||
# -D: Enable debugging (set -x, etc)\n
|
||||
# -g: Logo sha1 hash ($LOGO_HASH1)\n
|
||||
# -G: Logo sha256 hash ($LOGO_HASH256)\n
|
||||
# -h: Show this help message\n
|
||||
# -l: Logo URI ($LOGO_URI)\n
|
||||
# -m: Domain ($DOMAIN)\n
|
||||
# -o: Subject name CN for OSU-Client Server ($CNOC)\n
|
||||
# -O: Subject name CN for OCSP Server ($CNO)\n
|
||||
# -p: passphrase for private keys ($PASS)\n
|
||||
# -r: Operator-english ($OPER_ENG)\n
|
||||
# -R: Operator-finish ($OPER_FI)\n
|
||||
# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n
|
||||
# -u: OCSP-URI ($OCSP_URI)\n
|
||||
# -V: Subject name CN for OSU-Revoked Server ($CNV)\n
|
||||
EOF
|
||||
)
|
||||
|
||||
while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag
|
||||
do
|
||||
case $flag in
|
||||
c) COMPANY=$OPTARG;;
|
||||
C) CNR=$OPTARG;;
|
||||
D) DEBUG=1;;
|
||||
g) LOGO_HASH1=$OPTARG;;
|
||||
G) LOGO_HASH256=$OPTARG;;
|
||||
h) echo -e $USAGE; exit 0;;
|
||||
l) LOGO_URI=$OPTARG;;
|
||||
m) DOMAIN=$OPTARG;;
|
||||
o) CNOC=$OPTARG;;
|
||||
O) CNO=$OPTARG;;
|
||||
p) PASS=$OPTARG;;
|
||||
r) OPER_ENG=$OPTARG;;
|
||||
R) OPER_FI=$OPTARG;;
|
||||
S) OSU_SERVER_HOSTNAME=$OPTARG;;
|
||||
u) OCSP_URI=$OPTARG;;
|
||||
V) CNV=$OPTARG;;
|
||||
*) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo
|
||||
echo "---[ Root CA ]----------------------------------------------------------"
|
||||
echo
|
||||
|
||||
if [ $DEBUG = 1 ]
|
||||
then
|
||||
set -x
|
||||
fi
|
||||
|
||||
# Set the passphrase and some other common config accordingly.
|
||||
cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \
|
||||
> my-openssl-root.cnf
|
||||
|
||||
cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" |
|
||||
sed "s,@OCSP_URI@,$OCSP_URI," |
|
||||
sed "s,@LOGO_URI@,$LOGO_URI," |
|
||||
sed "s,@LOGO_HASH1@,$LOGO_HASH1," |
|
||||
sed "s,@LOGO_HASH256@,$LOGO_HASH256," |
|
||||
sed "s/@DOMAIN@/$DOMAIN/" \
|
||||
> my-openssl.cnf
|
||||
|
||||
|
||||
cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp
|
||||
mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private
|
||||
touch rootCA/index.txt
|
||||
if [ -e rootCA/private/cakey.pem ]; then
|
||||
echo " * Use existing Root CA"
|
||||
else
|
||||
echo " * Generate Root CA private key"
|
||||
$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key"
|
||||
echo " * Sign Root CA certificate"
|
||||
$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate"
|
||||
$OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER"
|
||||
sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint"
|
||||
fi
|
||||
if [ ! -e rootCA/crlnumber ]; then
|
||||
echo 00 > rootCA/crlnumber
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "---[ Intermediate CA ]--------------------------------------------------"
|
||||
echo
|
||||
|
||||
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
|
||||
mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private
|
||||
touch demoCA/index.txt
|
||||
if [ -e demoCA/private/cakey.pem ]; then
|
||||
echo " * Use existing Intermediate CA"
|
||||
else
|
||||
echo " * Generate Intermediate CA private key"
|
||||
$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -keyout demoCA/private/cakey.pem -out demoCA/careq.pem || fail "Failed to generate Intermediate CA private key"
|
||||
echo " * Sign Intermediate CA certificate"
|
||||
$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate"
|
||||
# horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin
|
||||
openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS
|
||||
$OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER."
|
||||
sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint"
|
||||
fi
|
||||
if [ ! -e demoCA/crlnumber ]; then
|
||||
echo 00 > demoCA/crlnumber
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "OCSP responder"
|
||||
echo
|
||||
|
||||
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp
|
||||
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP
|
||||
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem"
|
||||
|
||||
echo
|
||||
echo "---[ Server - to be revoked ] ------------------------------------------"
|
||||
echo
|
||||
|
||||
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp
|
||||
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key
|
||||
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server
|
||||
$OPENSSL ca -revoke server-revoked.pem -key $PASS
|
||||
|
||||
echo
|
||||
echo "---[ Server - with client ext key use ] ---------------------------------"
|
||||
echo "---[ Only used for negative-testing for OSU-client implementation ] -----"
|
||||
echo
|
||||
|
||||
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp
|
||||
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key"
|
||||
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem"
|
||||
|
||||
echo
|
||||
echo "---[ User ]-------------------------------------------------------------"
|
||||
echo
|
||||
|
||||
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
|
||||
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key"
|
||||
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem"
|
||||
|
||||
echo
|
||||
echo "---[ Server ]-----------------------------------------------------------"
|
||||
echo
|
||||
|
||||
ALT="DNS:$OSU_SERVER_HOSTNAME"
|
||||
ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG"
|
||||
ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI"
|
||||
|
||||
cat my-openssl.cnf |
|
||||
sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" |
|
||||
sed "s/^##organizationalUnitName/organizationalUnitName/" |
|
||||
sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" |
|
||||
sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \
|
||||
> openssl.cnf.tmp
|
||||
echo $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server
|
||||
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server || fail "Failed to generate server request"
|
||||
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server.csr -out server.pem -key $PASS -days 730 -extensions ext_server -policy policy_osu_server || fail "Failed to sign server certificate"
|
||||
|
||||
#dump logotype details for debugging
|
||||
$OPENSSL x509 -in server.pem -out server.der -outform DER
|
||||
openssl asn1parse -in server.der -inform DER | grep HEX | tail -1 | sed 's/.*://' | xxd -r -p > logo.der
|
||||
openssl asn1parse -in logo.der -inform DER > logo.asn1
|
||||
|
||||
|
||||
echo
|
||||
echo "---[ CRL ]---------------------------------------------------------------"
|
||||
echo
|
||||
|
||||
$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
|
||||
|
||||
echo
|
||||
echo "---[ Verify ]------------------------------------------------------------"
|
||||
echo
|
||||
|
||||
$OPENSSL verify -CAfile rootCA/cacert.pem demoCA/cacert.pem
|
||||
$OPENSSL verify -CAfile rootCA/cacert.pem -untrusted demoCA/cacert.pem *.pem
|
||||
|
||||
cat rootCA/cacert.pem demoCA/cacert.pem > ca.pem
|
@ -1,262 +0,0 @@
|
||||
Hotspot 2.0 OSU server
|
||||
======================
|
||||
|
||||
The information in this document is based on the assumption that Ubuntu
|
||||
16.04 server (64-bit) distribution is used and the web server is
|
||||
Apache2. Neither of these are requirements for the installation, but if
|
||||
other combinations are used, the package names and configuration
|
||||
parameters may need to be adjusted.
|
||||
|
||||
NOTE: This implementation and the example configuration here is meant
|
||||
only for testing purposes in a lab environment. This design is not
|
||||
secure to be installed in a publicly available Internet server without
|
||||
considerable amount of modification and review for security issues.
|
||||
|
||||
|
||||
Build dependencies
|
||||
------------------
|
||||
|
||||
Ubuntu 16.04 server
|
||||
- default installation
|
||||
- upgraded to latest package versions
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
|
||||
Packages needed for running the service:
|
||||
sudo apt-get install sqlite3
|
||||
sudo apt-get install apache2
|
||||
sudo apt-get install php-sqlite3 php-xml libapache2-mod-php
|
||||
|
||||
Additional packages needed for building the components:
|
||||
sudo apt-get install build-essential
|
||||
sudo apt-get install libsqlite3-dev
|
||||
sudo apt-get install libssl-dev
|
||||
sudo apt-get install libxml2-dev
|
||||
|
||||
|
||||
Installation location
|
||||
---------------------
|
||||
|
||||
Select a location for the installation root directory. The example here
|
||||
assumes /home/user/hs20-server to be used, but this can be changed by
|
||||
editing couple of files as indicated below.
|
||||
|
||||
sudo mkdir -p /home/user/hs20-server
|
||||
sudo chown $USER /home/user/hs20-server
|
||||
mkdir -p /home/user/hs20-server/spp
|
||||
mkdir -p /home/user/hs20-server/AS
|
||||
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
# hostapd as RADIUS server
|
||||
cd hostapd
|
||||
|
||||
#example build configuration
|
||||
cat > .config <<EOF
|
||||
CONFIG_DRIVER_NONE=y
|
||||
CONFIG_PKCS12=y
|
||||
CONFIG_RADIUS_SERVER=y
|
||||
CONFIG_EAP=y
|
||||
CONFIG_EAP_TLS=y
|
||||
CONFIG_EAP_MSCHAPV2=y
|
||||
CONFIG_EAP_PEAP=y
|
||||
CONFIG_EAP_GTC=y
|
||||
CONFIG_EAP_TTLS=y
|
||||
CONFIG_EAP_SIM=y
|
||||
CONFIG_EAP_AKA=y
|
||||
CONFIG_EAP_AKA_PRIME=y
|
||||
CONFIG_SQLITE=y
|
||||
CONFIG_HS20=y
|
||||
EOF
|
||||
|
||||
make hostapd hlr_auc_gw
|
||||
cp hostapd hlr_auc_gw /home/user/hs20-server/AS
|
||||
|
||||
# build hs20_spp_server
|
||||
cd ../hs20/server
|
||||
make clean
|
||||
make
|
||||
cp hs20_spp_server /home/user/hs20-server/spp
|
||||
# prepare database (web server user/group needs to have write access)
|
||||
mkdir -p /home/user/hs20-server/AS/DB
|
||||
sudo chgrp www-data /home/user/hs20-server/AS/DB
|
||||
sudo chmod g+w /home/user/hs20-server/AS/DB
|
||||
sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql.txt
|
||||
sudo chgrp www-data /home/user/hs20-server/AS/DB/eap_user.db
|
||||
sudo chmod g+w /home/user/hs20-server/AS/DB/eap_user.db
|
||||
# add example configuration (note: need to update URLs to match the system)
|
||||
sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql-example.txt
|
||||
|
||||
# copy PHP scripts
|
||||
# Modify config.php if different installation directory is used.
|
||||
# Modify PHP scripts to get the desired behavior for user interaction (or use
|
||||
# the examples as-is for initial testing).
|
||||
cp -r www /home/user/hs20-server
|
||||
|
||||
# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be
|
||||
# inserted within the BODY section of the page).
|
||||
cat > /home/user/hs20-server/terms-and-conditions <<EOF
|
||||
<P>Terms and conditions..</P>
|
||||
EOF
|
||||
|
||||
# Build local keys and certs
|
||||
cd ca
|
||||
# Display help options.
|
||||
./setup.sh -h
|
||||
|
||||
# Remove old keys, fill in appropriate values, and generate your keys.
|
||||
# For instance:
|
||||
./clean.sh
|
||||
rm -fr rootCA"
|
||||
old_hostname=myserver.local
|
||||
./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \
|
||||
-o $old_hostname-osu-client \
|
||||
-O $old_hostname-oscp -p lanforge -S $old_hostname \
|
||||
-V $old_hostname-osu-revoked \
|
||||
-m local -u http://$old_hostname:8888/
|
||||
|
||||
# Configure subscription policies
|
||||
mkdir -p /home/user/hs20-server/spp/policy
|
||||
cat > /home/user/hs20-server/spp/policy/default.xml <<EOF
|
||||
<Policy>
|
||||
<PolicyUpdate>
|
||||
<UpdateInterval>30</UpdateInterval>
|
||||
<UpdateMethod>ClientInitiated</UpdateMethod>
|
||||
<Restriction>Unrestricted</Restriction>
|
||||
<URI>https://policy-server.osu.example.com/hs20/spp.php</URI>
|
||||
</PolicyUpdate>
|
||||
</Policy>
|
||||
EOF
|
||||
|
||||
|
||||
# Install Hotspot 2.0 SPP and OMA DM XML schema/DTD files
|
||||
|
||||
# XML schema for SPP
|
||||
# Copy the latest XML schema into /home/user/hs20-server/spp/spp.xsd
|
||||
|
||||
# OMA DM Device Description Framework DTD
|
||||
# Copy into /home/user/hs20-server/spp/dm_ddf-v1_2.dtd
|
||||
# http://www.openmobilealliance.org/tech/DTD/dm_ddf-v1_2.dtd
|
||||
|
||||
|
||||
# Configure RADIUS authentication service
|
||||
# Note: Change the URL to match the setup
|
||||
# Note: Install AAA server key/certificate and root CA in Key directory
|
||||
|
||||
cat > /home/user/hs20-server/AS/as-sql.conf <<EOF
|
||||
driver=none
|
||||
radius_server_clients=as.radius_clients
|
||||
eap_server=1
|
||||
eap_user_file=sqlite:DB/eap_user.db
|
||||
ca_cert=Key/ca.pem
|
||||
server_cert=Key/server.pem
|
||||
private_key=Key/server.key
|
||||
private_key_passwd=passphrase
|
||||
eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=eap_sim.db
|
||||
subscr_remediation_url=https://subscription-server.osu.example.com/hs20/spp.php
|
||||
EOF
|
||||
|
||||
# Set RADIUS passphrase for the APs
|
||||
# Note: Modify to match the setup
|
||||
cat > /home/user/hs20-server/AS/as.radius_clients <<EOF
|
||||
0.0.0.0/0 radius
|
||||
EOF
|
||||
|
||||
|
||||
Start RADIUS authentication server
|
||||
----------------------------------
|
||||
|
||||
cd /home/user/hs20-server/AS
|
||||
./hostapd -B as-sql.conf
|
||||
|
||||
|
||||
OSEN RADIUS server configuration notes
|
||||
|
||||
The OSEN RADIUS server config file should have the 'ocsp_stapling_response'
|
||||
configuration in it. For example:
|
||||
|
||||
# hostapd-radius config for the radius used by the OSEN AP
|
||||
interface=eth0#0
|
||||
driver=none
|
||||
logger_syslog=-1
|
||||
logger_syslog_level=2
|
||||
logger_stdout=-1
|
||||
logger_stdout_level=2
|
||||
ctrl_interface=/var/run/hostapd
|
||||
ctrl_interface_group=0
|
||||
eap_server=1
|
||||
eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user
|
||||
server_id=ben-ota-2-osen
|
||||
radius_server_auth_port=1811
|
||||
radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients
|
||||
|
||||
ca_cert=/home/user/hs20-server/ca/ca.pem
|
||||
server_cert=/home/user/hs20-server/ca/server.pem
|
||||
private_key=/home/user/hs20-server/ca/server.key
|
||||
private_key_passwd=whatever
|
||||
|
||||
ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der
|
||||
|
||||
The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look
|
||||
similar to this, and should coorelate with the osu_nai entry in
|
||||
the non-OSEN VAP config file. For instance:
|
||||
|
||||
# cat hostapd-osen.eap_user
|
||||
# For OSEN authentication (Hotspot 2.0 Release 2)
|
||||
"osen@w1.fi" WFA-UNAUTH-TLS
|
||||
|
||||
|
||||
# Run OCSP server:
|
||||
cd /home/user/hs20-server/ca
|
||||
./ocsp-responder.sh&
|
||||
|
||||
# Update cache (This should be run periodically)
|
||||
./ocsp-update-cache.sh
|
||||
|
||||
|
||||
Configure web server
|
||||
--------------------
|
||||
|
||||
Edit /etc/apache2/sites-available/default-ssl
|
||||
|
||||
Add following block just before "SSL Engine Switch" line":
|
||||
|
||||
Alias /hs20/ "/home/user/hs20-server/www/"
|
||||
<Directory "/home/user/hs20-server/www/">
|
||||
Options Indexes MultiViews FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
SSLOptions +StdEnvVars
|
||||
</Directory>
|
||||
|
||||
Update SSL configuration to use the OSU server certificate/key.
|
||||
They keys and certs are called 'server.key' and 'server.pem' from
|
||||
ca/setup.sh.
|
||||
|
||||
To support subscription remediation using client certificates, set
|
||||
"SSLVerifyClient optional" and configure the trust root CA(s) for the
|
||||
client certificates with SSLCACertificateFile.
|
||||
|
||||
Enable default-ssl site and restart Apache2:
|
||||
sudo a2ensite default-ssl
|
||||
sudo a2enmod ssl
|
||||
sudo service apache2 restart
|
||||
|
||||
|
||||
Management UI
|
||||
-------------
|
||||
|
||||
The sample PHP scripts include a management UI for testing
|
||||
purposes. That is available at https://<server>/hs20/users.php
|
||||
|
||||
|
||||
AP configuration
|
||||
----------------
|
||||
|
||||
APs can now be configured to use the OSU server as the RADIUS
|
||||
authentication server. In addition, the OSU Provider List ANQP element
|
||||
should be configured to use the SPP (SOAP+XML) option and with the
|
||||
following Server URL:
|
||||
https://<server>/hs20/spp.php/signup?realm=example.com
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Hotspot 2.0 SPP server - standalone version
|
||||
* Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <time.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "common/version.h"
|
||||
#include "xml-utils.h"
|
||||
#include "spp_server.h"
|
||||
|
||||
|
||||
static void write_timestamp(FILE *f)
|
||||
{
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
|
||||
time(&t);
|
||||
tm = localtime(&t);
|
||||
|
||||
fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ",
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
|
||||
|
||||
void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (ctx->debug_log == NULL)
|
||||
return;
|
||||
|
||||
write_timestamp(ctx->debug_log);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(ctx->debug_log, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(ctx->debug_log, "\n");
|
||||
}
|
||||
|
||||
|
||||
void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node)
|
||||
{
|
||||
char *str;
|
||||
|
||||
if (ctx->debug_log == NULL)
|
||||
return;
|
||||
str = xml_node_to_str(ctx->xml, node);
|
||||
if (str == NULL)
|
||||
return;
|
||||
|
||||
write_timestamp(ctx->debug_log);
|
||||
fprintf(ctx->debug_log, "%s: '%s'\n", title, str);
|
||||
os_free(str);
|
||||
}
|
||||
|
||||
|
||||
static int process(struct hs20_svc *ctx)
|
||||
{
|
||||
int dmacc = 0;
|
||||
xml_node_t *soap, *spp, *resp;
|
||||
char *user, *realm, *post, *str;
|
||||
|
||||
ctx->addr = getenv("HS20ADDR");
|
||||
if (ctx->addr)
|
||||
debug_print(ctx, 1, "Connection from %s", ctx->addr);
|
||||
ctx->test = getenv("HS20TEST");
|
||||
if (ctx->test)
|
||||
debug_print(ctx, 1, "Requested test functionality: %s",
|
||||
ctx->test);
|
||||
|
||||
user = getenv("HS20USER");
|
||||
if (user && strlen(user) == 0)
|
||||
user = NULL;
|
||||
realm = getenv("HS20REALM");
|
||||
if (realm == NULL) {
|
||||
debug_print(ctx, 1, "HS20REALM not set");
|
||||
return -1;
|
||||
}
|
||||
post = getenv("HS20POST");
|
||||
if (post == NULL) {
|
||||
debug_print(ctx, 1, "HS20POST not set");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->imsi = getenv("HS20IMSI");
|
||||
if (ctx->imsi)
|
||||
debug_print(ctx, 1, "IMSI %s", ctx->imsi);
|
||||
|
||||
ctx->eap_method = getenv("HS20EAPMETHOD");
|
||||
if (ctx->eap_method)
|
||||
debug_print(ctx, 1, "EAP method %s", ctx->eap_method);
|
||||
|
||||
ctx->id_hash = getenv("HS20IDHASH");
|
||||
if (ctx->id_hash)
|
||||
debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash);
|
||||
|
||||
soap = xml_node_from_buf(ctx->xml, post);
|
||||
if (soap == NULL) {
|
||||
debug_print(ctx, 1, "Could not parse SOAP data");
|
||||
return -1;
|
||||
}
|
||||
debug_dump_node(ctx, "Received SOAP message", soap);
|
||||
spp = soap_get_body(ctx->xml, soap);
|
||||
if (spp == NULL) {
|
||||
debug_print(ctx, 1, "Could not get SPP message");
|
||||
xml_node_free(ctx->xml, soap);
|
||||
return -1;
|
||||
}
|
||||
debug_dump_node(ctx, "Received SPP message", spp);
|
||||
|
||||
resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc);
|
||||
xml_node_free(ctx->xml, soap);
|
||||
if (resp == NULL && user == NULL) {
|
||||
debug_print(ctx, 1, "Request HTTP authentication");
|
||||
return 2; /* Request authentication */
|
||||
}
|
||||
if (resp == NULL) {
|
||||
debug_print(ctx, 1, "No response");
|
||||
return -1;
|
||||
}
|
||||
|
||||
soap = soap_build_envelope(ctx->xml, resp);
|
||||
if (soap == NULL) {
|
||||
debug_print(ctx, 1, "SOAP envelope building failed");
|
||||
return -1;
|
||||
}
|
||||
str = xml_node_to_str(ctx->xml, soap);
|
||||
xml_node_free(ctx->xml, soap);
|
||||
if (str == NULL) {
|
||||
debug_print(ctx, 1, "Could not get node string");
|
||||
return -1;
|
||||
}
|
||||
printf("%s", str);
|
||||
free(str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("usage:\n"
|
||||
"hs20_spp_server -r<root directory> [-f<debug log>]\n");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct hs20_svc ctx;
|
||||
int ret;
|
||||
|
||||
os_memset(&ctx, 0, sizeof(ctx));
|
||||
for (;;) {
|
||||
int c = getopt(argc, argv, "f:r:v");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'f':
|
||||
if (ctx.debug_log)
|
||||
break;
|
||||
ctx.debug_log = fopen(optarg, "a");
|
||||
if (ctx.debug_log == NULL) {
|
||||
printf("Could not write to %s\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
ctx.root_dir = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
printf("hs20_spp_server v%s\n", VERSION_STR);
|
||||
return 0;
|
||||
default:
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (ctx.root_dir == NULL) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
ctx.xml = xml_node_init_ctx(&ctx, NULL);
|
||||
if (ctx.xml == NULL)
|
||||
return -1;
|
||||
if (hs20_spp_server_init(&ctx) < 0) {
|
||||
xml_node_deinit_ctx(ctx.xml);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = process(&ctx);
|
||||
debug_print(&ctx, 1, "process() --> %d", ret);
|
||||
|
||||
xml_node_deinit_ctx(ctx.xml);
|
||||
hs20_spp_server_deinit(&ctx);
|
||||
if (ctx.debug_log)
|
||||
fclose(ctx.debug_log);
|
||||
|
||||
return ret;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Hotspot 2.0 SPP server
|
||||
* Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef SPP_SERVER_H
|
||||
#define SPP_SERVER_H
|
||||
|
||||
struct hs20_svc {
|
||||
const void *ctx;
|
||||
struct xml_node_ctx *xml;
|
||||
char *root_dir;
|
||||
FILE *debug_log;
|
||||
sqlite3 *db;
|
||||
const char *addr;
|
||||
const char *test;
|
||||
const char *imsi;
|
||||
const char *eap_method;
|
||||
const char *id_hash;
|
||||
};
|
||||
|
||||
|
||||
void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node);
|
||||
|
||||
xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
|
||||
const char *auth_user,
|
||||
const char *auth_realm, int dmacc);
|
||||
int hs20_spp_server_init(struct hs20_svc *ctx);
|
||||
void hs20_spp_server_deinit(struct hs20_svc *ctx);
|
||||
|
||||
#endif /* SPP_SERVER_H */
|
@ -1,17 +0,0 @@
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','fqdn','example.com');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','friendly_name','Example Operator');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','remediation_url','https://subscription-server.osu.example.com/hs20/remediation.php?session_id=');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_remediation_url','https://subscription-server.osu.example.com/hs20/free-remediation.php?session_id=');
|
||||
INSERT INTO osu_config(realm,field,value) VALUES('example.com','signup_url','https://subscription-server.osu.example.com/hs20/signup.php?session_id=');
|
||||
|
||||
|
||||
INSERT INTO users(identity,realm,methods,password,phase2,shared) VALUES('free','example.com','TTLS-MSCHAPV2','free',1,1);
|
||||
|
||||
INSERT INTO wildcards(identity,methods) VALUES('','TTLS,TLS');
|
@ -1,108 +0,0 @@
|
||||
CREATE TABLE eventlog(
|
||||
user TEXT,
|
||||
realm TEXT,
|
||||
sessionid TEXT COLLATE NOCASE,
|
||||
timestamp TEXT,
|
||||
notes TEXT,
|
||||
dump TEXT,
|
||||
addr TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE sessions(
|
||||
timestamp TEXT,
|
||||
id TEXT COLLATE NOCASE,
|
||||
user TEXT,
|
||||
realm TEXT,
|
||||
password TEXT,
|
||||
machine_managed BOOLEAN,
|
||||
operation INTEGER,
|
||||
type TEXT,
|
||||
pps TEXT,
|
||||
redirect_uri TEXT,
|
||||
devinfo TEXT,
|
||||
devdetail TEXT,
|
||||
cert TEXT,
|
||||
cert_pem TEXT,
|
||||
mac_addr TEXT,
|
||||
osu_user TEXT,
|
||||
osu_password TEXT,
|
||||
eap_method TEXT,
|
||||
mobile_identifier_hash TEXT,
|
||||
test TEXT
|
||||
);
|
||||
|
||||
CREATE index sessions_id_index ON sessions(id);
|
||||
|
||||
CREATE TABLE osu_config(
|
||||
realm TEXT,
|
||||
field TEXT,
|
||||
value TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE users(
|
||||
identity TEXT PRIMARY KEY,
|
||||
methods TEXT,
|
||||
password TEXT,
|
||||
machine_managed BOOLEAN,
|
||||
remediation TEXT,
|
||||
phase2 INTEGER,
|
||||
realm TEXT,
|
||||
policy TEXT,
|
||||
devinfo TEXT,
|
||||
devdetail TEXT,
|
||||
pps TEXT,
|
||||
fetch_pps INTEGER,
|
||||
osu_user TEXT,
|
||||
osu_password TEXT,
|
||||
shared INTEGER,
|
||||
cert TEXT,
|
||||
cert_pem TEXT,
|
||||
t_c_timestamp INTEGER,
|
||||
mac_addr TEXT,
|
||||
last_msk TEXT,
|
||||
polupd_done TEXT,
|
||||
subrem TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE wildcards(
|
||||
identity TEXT PRIMARY KEY,
|
||||
methods TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE authlog(
|
||||
timestamp TEXT,
|
||||
session TEXT,
|
||||
nas_ip TEXT,
|
||||
username TEXT,
|
||||
note TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE pending_tc(
|
||||
mac_addr TEXT PRIMARY KEY,
|
||||
identity TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE current_sessions(
|
||||
mac_addr TEXT PRIMARY KEY,
|
||||
identity TEXT,
|
||||
start_time TEXT,
|
||||
nas TEXT,
|
||||
hs20_t_c_filtering BOOLEAN,
|
||||
waiting_coa_ack BOOLEAN,
|
||||
coa_ack_received BOOLEAN
|
||||
);
|
||||
|
||||
CREATE TABLE cert_enroll(
|
||||
mac_addr TEXT PRIMARY KEY,
|
||||
user TEXT,
|
||||
realm TEXT,
|
||||
serialnum TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE sim_provisioning(
|
||||
mobile_identifier_hash TEXT PRIMARY KEY,
|
||||
imsi TEXT,
|
||||
mac_addr TEXT,
|
||||
eap_method TEXT,
|
||||
timestamp TEXT
|
||||
);
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (isset($_POST["id"]))
|
||||
$id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
|
||||
else
|
||||
die("Missing session id");
|
||||
if (strlen($id) < 32)
|
||||
die("Invalid session id");
|
||||
|
||||
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
|
||||
if ($row == false) {
|
||||
die("Session not found");
|
||||
}
|
||||
|
||||
$uri = $row['redirect_uri'];
|
||||
$rowid = $row['rowid'];
|
||||
$realm = $row['realm'];
|
||||
|
||||
$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
|
||||
if (!$row || strlen($row['value']) == 0) {
|
||||
die("Free account disabled");
|
||||
}
|
||||
|
||||
$user = $row['value'];
|
||||
|
||||
$row = $db->query("SELECT password FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
|
||||
if (!$row)
|
||||
die("Free account not found");
|
||||
|
||||
$pw = $row['password'];
|
||||
|
||||
if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', machine_managed='1' WHERE rowid=$rowid")) {
|
||||
die("Failed to update session database");
|
||||
}
|
||||
|
||||
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
|
||||
"VALUES ('$user', '$realm', '$id', " .
|
||||
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
|
||||
"'completed user input response for a new PPS MO')");
|
||||
|
||||
header("Location: $uri", true, 302);
|
||||
|
||||
?>
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (isset($_POST["id"]))
|
||||
$id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
|
||||
else
|
||||
die("Missing session id");
|
||||
|
||||
$user = $_POST["user"];
|
||||
$pw = $_POST["password"];
|
||||
if (strlen($id) < 32 || !isset($user) || !isset($pw)) {
|
||||
die("Invalid POST data");
|
||||
}
|
||||
|
||||
if (strlen($user) < 1 || strncasecmp($user, "cert-", 5) == 0) {
|
||||
echo "<html><body><p><red>Invalid username</red></p>\n";
|
||||
echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
|
||||
echo "</body></html>\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
|
||||
if ($row == false) {
|
||||
die("Session not found");
|
||||
}
|
||||
$realm = $row['realm'];
|
||||
|
||||
$userrow = $db->query("SELECT identity FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
|
||||
if ($userrow) {
|
||||
echo "<html><body><p><red>Selected username is not available</red></p>\n";
|
||||
echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
|
||||
echo "</body></html>\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$uri = $row['redirect_uri'];
|
||||
$rowid = $row['rowid'];
|
||||
|
||||
if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', type='password' WHERE rowid=$rowid")) {
|
||||
die("Failed to update session database");
|
||||
}
|
||||
|
||||
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
|
||||
"VALUES ('$user', '$realm', '$id', " .
|
||||
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
|
||||
"'completed user input response for a new PPS MO')");
|
||||
|
||||
header("Location: $uri", true, 302);
|
||||
|
||||
?>
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (isset($_GET["id"]))
|
||||
$id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
|
||||
else
|
||||
die("Missing session id");
|
||||
if (strlen($id) < 32)
|
||||
die("Invalid session id");
|
||||
|
||||
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
|
||||
if ($row == false) {
|
||||
die("Session not found");
|
||||
}
|
||||
|
||||
$uri = $row['redirect_uri'];
|
||||
$rowid = $row['rowid'];
|
||||
$realm = $row['realm'];
|
||||
|
||||
$user = sha1(mt_rand());
|
||||
|
||||
if (!$db->exec("UPDATE sessions SET user='$user', type='cert' WHERE rowid=$rowid")) {
|
||||
die("Failed to update session database");
|
||||
}
|
||||
|
||||
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
|
||||
"VALUES ('', '$realm', '$id', " .
|
||||
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
|
||||
"'completed user input response for client certificate enrollment')");
|
||||
|
||||
header("Location: $uri", true, 302);
|
||||
|
||||
?>
|
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
$osu_root = "/home/user/hs20-server";
|
||||
$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db";
|
||||
$t_c_file = "$osu_root/terms-and-conditions";
|
||||
$t_c_timestamp = 123456789;
|
||||
$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as"
|
||||
?>
|
@ -1,232 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$params = explode("/", $_SERVER["PATH_INFO"], 3);
|
||||
$realm = $params[1];
|
||||
$cmd = $params[2];
|
||||
$method = $_SERVER["REQUEST_METHOD"];
|
||||
|
||||
unset($user);
|
||||
unset($rowid);
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
error_log("EST: Could not access database");
|
||||
die("Could not access database");
|
||||
}
|
||||
|
||||
if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
|
||||
$needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
|
||||
'uri'=>1, 'response'=>1);
|
||||
$data = array();
|
||||
$keys = implode('|', array_keys($needed));
|
||||
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
|
||||
$_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $m) {
|
||||
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
|
||||
unset($needed[$m[1]]);
|
||||
}
|
||||
if ($needed) {
|
||||
error_log("EST: Missing auth parameter");
|
||||
die('Authentication failed');
|
||||
}
|
||||
$user = $data['username'];
|
||||
if (strlen($user) < 1) {
|
||||
error_log("EST: Empty username");
|
||||
die('Authentication failed');
|
||||
}
|
||||
|
||||
$sql = "SELECT rowid,password,operation FROM sessions " .
|
||||
"WHERE user='$user' AND realm='$realm'";
|
||||
$q = $db->query($sql);
|
||||
if (!$q) {
|
||||
error_log("EST: Session not found for user=$user realm=$realm");
|
||||
die("Session not found");
|
||||
}
|
||||
$row = $q->fetch();
|
||||
if (!$row) {
|
||||
error_log("EST: Session fetch failed for user=$user realm=$realm");
|
||||
die('Session not found');
|
||||
}
|
||||
$rowid = $row['rowid'];
|
||||
|
||||
$oper = $row['operation'];
|
||||
if ($oper != '5') {
|
||||
error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
|
||||
die("Session not found");
|
||||
}
|
||||
$pw = $row['password'];
|
||||
if (strlen($pw) < 1) {
|
||||
error_log("EST: Empty password for user=$user realm=$realm");
|
||||
die('Authentication failed');
|
||||
}
|
||||
|
||||
$A1 = md5($user . ':' . $realm . ':' . $pw);
|
||||
$A2 = md5($method . ':' . $data['uri']);
|
||||
$resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
|
||||
$data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
|
||||
if ($data['response'] != $resp) {
|
||||
error_log("EST: Incorrect authentication response for user=$user realm=$realm");
|
||||
die('Authentication failed');
|
||||
}
|
||||
} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
|
||||
$_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
|
||||
isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
|
||||
$user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
|
||||
$sql = "SELECT rowid,password,operation FROM sessions " .
|
||||
"WHERE user='$user' AND realm='$realm'";
|
||||
$q = $db->query($sql);
|
||||
if (!$q) {
|
||||
error_log("EST: Session not found for user=$user realm=$realm");
|
||||
die("Session not found");
|
||||
}
|
||||
$row = $q->fetch();
|
||||
if (!$row) {
|
||||
error_log("EST: Session fetch failed for user=$user realm=$realm");
|
||||
die('Session not found');
|
||||
}
|
||||
$rowid = $row['rowid'];
|
||||
|
||||
$oper = $row['operation'];
|
||||
if ($oper != '10') {
|
||||
error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
|
||||
die("Session not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($method == "GET" && $cmd == "cacerts") {
|
||||
$fname = "$osu_root/est/$realm-cacerts.pkcs7";
|
||||
if (!file_exists($fname)) {
|
||||
error_log("EST: cacerts - unknown realm $realm");
|
||||
die("Unknown realm");
|
||||
}
|
||||
|
||||
header("Content-Transfer-Encoding: base64");
|
||||
header("Content-Type: application/pkcs7-mime");
|
||||
|
||||
$data = file_get_contents($fname);
|
||||
echo wordwrap(base64_encode($data), 72, "\n", true);
|
||||
echo "\n";
|
||||
error_log("EST: cacerts");
|
||||
} else if ($method == "GET" && $cmd == "csrattrs") {
|
||||
header("Content-Transfer-Encoding: base64");
|
||||
header("Content-Type: application/csrattrs");
|
||||
readfile("$osu_root/est/est-attrs.b64");
|
||||
error_log("EST: csrattrs");
|
||||
} else if ($method == "POST" &&
|
||||
($cmd == "simpleenroll" || $cmd == "simplereenroll")) {
|
||||
$reenroll = $cmd == "simplereenroll";
|
||||
if (!$reenroll && (!isset($user) || strlen($user) == 0)) {
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('WWW-Authenticate: Digest realm="'.$realm.
|
||||
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
|
||||
error_log("EST: simpleenroll - require authentication");
|
||||
die('Authentication required');
|
||||
}
|
||||
if ($reenroll &&
|
||||
(!isset($user) ||
|
||||
!isset($_SERVER["SSL_CLIENT_VERIFY"]) ||
|
||||
$_SERVER["SSL_CLIENT_VERIFY"] != "SUCCESS")) {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
error_log("EST: simplereenroll - require certificate authentication");
|
||||
die('Authentication required');
|
||||
}
|
||||
if (!isset($_SERVER["CONTENT_TYPE"])) {
|
||||
error_log("EST: simpleenroll without Content-Type");
|
||||
die("Missing Content-Type");
|
||||
}
|
||||
if (!stristr($_SERVER["CONTENT_TYPE"], "application/pkcs10")) {
|
||||
error_log("EST: simpleenroll - unexpected Content-Type: " .
|
||||
$_SERVER["CONTENT_TYPE"]);
|
||||
die("Unexpected Content-Type");
|
||||
}
|
||||
|
||||
$data = file_get_contents("php://input");
|
||||
error_log("EST: simpleenroll - POST data from php://input: " . $data);
|
||||
$req = base64_decode($data);
|
||||
if ($req == FALSE) {
|
||||
error_log("EST: simpleenroll - Invalid base64-encoded PKCS#10 data");
|
||||
die("Invalid base64-encoded PKCS#10 data");
|
||||
}
|
||||
$cadir = "$osu_root/est";
|
||||
$reqfile = "$cadir/tmp/cert-req.pkcs10";
|
||||
$f = fopen($reqfile, "wb");
|
||||
fwrite($f, $req);
|
||||
fclose($f);
|
||||
|
||||
$req_pem = "$reqfile.pem";
|
||||
if (file_exists($req_pem))
|
||||
unlink($req_pem);
|
||||
exec("openssl req -in $reqfile -inform DER -out $req_pem -outform PEM");
|
||||
if (!file_exists($req_pem)) {
|
||||
error_log("EST: simpleenroll - Failed to parse certificate request");
|
||||
die("Failed to parse certificate request");
|
||||
}
|
||||
|
||||
/* FIX: validate request and add HS 2.0 extensions to cert */
|
||||
$cert_pem = "$cadir/tmp/req-signed.pem";
|
||||
if (file_exists($cert_pem))
|
||||
unlink($cert_pem);
|
||||
exec("openssl x509 -req -in $req_pem -CAkey $cadir/cakey.pem -out $cert_pem -CA $cadir/cacert.pem -CAserial $cadir/serial -days 365 -text");
|
||||
if (!file_exists($cert_pem)) {
|
||||
error_log("EST: simpleenroll - Failed to sign certificate");
|
||||
die("Failed to sign certificate");
|
||||
}
|
||||
|
||||
$cert = file_get_contents($cert_pem);
|
||||
$handle = popen("openssl x509 -in $cert_pem -serial -noout", "r");
|
||||
$serial = fread($handle, 200);
|
||||
pclose($handle);
|
||||
$pattern = "/serial=(?P<snhex>[0-9a-fA-F:]*)/m";
|
||||
preg_match($pattern, $serial, $matches);
|
||||
if (!isset($matches['snhex']) || strlen($matches['snhex']) < 1) {
|
||||
error_log("EST: simpleenroll - Could not get serial number");
|
||||
die("Could not get serial number");
|
||||
}
|
||||
$sn = str_replace(":", "", strtoupper($matches['snhex']));
|
||||
|
||||
$user = "cert-$sn";
|
||||
error_log("EST: user = $user");
|
||||
|
||||
$cert_der = "$cadir/tmp/req-signed.der";
|
||||
if (file_exists($cert_der))
|
||||
unlink($cert_der);
|
||||
exec("openssl x509 -in $cert_pem -inform PEM -out $cert_der -outform DER");
|
||||
if (!file_exists($cert_der)) {
|
||||
error_log("EST: simpleenroll - Failed to convert certificate");
|
||||
die("Failed to convert certificate");
|
||||
}
|
||||
$der = file_get_contents($cert_der);
|
||||
$fingerprint = hash("sha256", $der);
|
||||
error_log("EST: sha256(DER cert): $fingerprint");
|
||||
|
||||
$pkcs7 = "$cadir/tmp/est-client.pkcs7";
|
||||
if (file_exists($pkcs7))
|
||||
unlink($pkcs7);
|
||||
exec("openssl crl2pkcs7 -nocrl -certfile $cert_pem -out $pkcs7 -outform DER");
|
||||
if (!file_exists($pkcs7)) {
|
||||
error_log("EST: simpleenroll - Failed to prepare PKCS#7 file");
|
||||
die("Failed to prepare PKCS#7 file");
|
||||
}
|
||||
|
||||
if (!$db->exec("UPDATE sessions SET user='$user', cert='$fingerprint', cert_pem='$cert' WHERE rowid=$rowid")) {
|
||||
error_log("EST: simpleenroll - Failed to update session database");
|
||||
die("Failed to update session database");
|
||||
}
|
||||
|
||||
header("Content-Transfer-Encoding: base64");
|
||||
header("Content-Type: application/pkcs7-mime");
|
||||
|
||||
$data = file_get_contents($pkcs7);
|
||||
$resp = wordwrap(base64_encode($data), 72, "\n", true);
|
||||
echo $resp . "\n";
|
||||
error_log("EST: simpleenroll - PKCS#7 response: " . $resp);
|
||||
} else {
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
error_log("EST: Unexpected method or path");
|
||||
die("Unexpected method or path");
|
||||
}
|
||||
|
||||
?>
|
@ -1,19 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hotspot 2.0 - public and free hotspot - remediation</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h3>Hotspot 2.0 - public and free hotspot</h3>
|
||||
|
||||
<p>Terms and conditions have changed. You need to accept the new terms
|
||||
to continue using this network.</p>
|
||||
|
||||
<p>Terms and conditions..</p>
|
||||
|
||||
<?php
|
||||
echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Accept</a><br>\n";
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,23 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hotspot 2.0 - public and free hotspot</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
|
||||
$id = $_GET["session_id"];
|
||||
|
||||
echo "<h3>Hotspot 2.0 - public and free hotspot</h3>\n";
|
||||
|
||||
echo "<form action=\"add-free.php\" method=\"POST\">\n";
|
||||
echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
|
||||
|
||||
?>
|
||||
|
||||
<p>Terms and conditions..</p>
|
||||
<input type="submit" value="Accept">
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (isset($_GET["id"]))
|
||||
$id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
|
||||
else
|
||||
$id = 0;
|
||||
|
||||
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
|
||||
if ($row == false) {
|
||||
die("Session not found");
|
||||
}
|
||||
|
||||
$uri = $row['redirect_uri'];
|
||||
|
||||
header("Location: $uri", true, 302);
|
||||
|
||||
$user = $row['user'];
|
||||
$realm = $row['realm'];
|
||||
|
||||
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
|
||||
"VALUES ('$user', '$realm', '$id', " .
|
||||
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
|
||||
"'redirected after user input')");
|
||||
|
||||
?>
|
@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (isset($_POST["id"]))
|
||||
$id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
|
||||
else
|
||||
die("Missing session id");
|
||||
|
||||
$pw = $_POST["password"];
|
||||
if (strlen($id) < 32 || !isset($pw)) {
|
||||
die("Invalid POST data");
|
||||
}
|
||||
|
||||
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
|
||||
if ($row == false) {
|
||||
die("Session not found");
|
||||
}
|
||||
$user = $row['user'];
|
||||
$realm = $row['realm'];
|
||||
|
||||
$uri = $row['redirect_uri'];
|
||||
$rowid = $row['rowid'];
|
||||
|
||||
if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) {
|
||||
die("Failed to update session database");
|
||||
}
|
||||
|
||||
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
|
||||
"VALUES ('$user', '$realm', '$id', " .
|
||||
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
|
||||
"'completed user input response for subscription remediation')");
|
||||
|
||||
header("Location: $uri", true, 302);
|
||||
|
||||
?>
|
@ -1,55 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hotspot 2.0 subscription remediation</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (isset($_GET["session_id"]))
|
||||
$id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]);
|
||||
else
|
||||
$id = 0;
|
||||
echo "SessionID: " . $id . "<br>\n";
|
||||
|
||||
$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch();
|
||||
if ($row == false) {
|
||||
die("Session not found");
|
||||
}
|
||||
|
||||
$username = $row['user'];
|
||||
echo "User: " . $username . "@" . $row['realm'] . "<br>\n";
|
||||
|
||||
$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch();
|
||||
if ($user == false) {
|
||||
die("User not found");
|
||||
}
|
||||
|
||||
echo "<hr><br>\n";
|
||||
|
||||
$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0;
|
||||
|
||||
if ($cert) {
|
||||
echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
|
||||
} else if ($user['machine_managed'] == "1") {
|
||||
echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
|
||||
echo "This will provide a new machine-generated password.<br>\n";
|
||||
} else {
|
||||
echo "<form action=\"remediation-pw.php\" method=\"POST\">\n";
|
||||
echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
|
||||
echo "New password: <input type=\"password\" name=\"password\"><br>\n";
|
||||
echo "<input type=\"submit\" value=\"Change password\">\n";
|
||||
echo "</form>\n";
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,59 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hotspot 2.0 signup</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
|
||||
$id = $_GET["session_id"];
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch();
|
||||
if ($row == false) {
|
||||
die("Session not found for id: $id");
|
||||
}
|
||||
$realm = $row['realm'];
|
||||
$test = $row['test'];
|
||||
|
||||
if (strlen($test) > 0) {
|
||||
echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n";
|
||||
}
|
||||
|
||||
echo "<h3>Sign up for a subscription - $realm</h3>\n";
|
||||
|
||||
echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n";
|
||||
|
||||
echo "<h4>Option 1 - shared free access credential</h4>\n";
|
||||
|
||||
$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
|
||||
if ($row && strlen($row['value']) > 0) {
|
||||
echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n";
|
||||
}
|
||||
|
||||
echo "<h4>Option 2 - username/password credential</h4>\n";
|
||||
|
||||
echo "<form action=\"add-mo.php\" method=\"POST\">\n";
|
||||
echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
|
||||
?>
|
||||
Select a username and password. Leave password empty to get automatically
|
||||
generated and machine managed password.<br>
|
||||
Username: <input type="text" name="user"><br>
|
||||
Password: <input type="password" name="password"><br>
|
||||
<input type="submit" value="Complete subscription registration">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
echo "<h4>Option 3 - client certificate credential</h4>\n";
|
||||
|
||||
echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n"
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,168 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
if (!stristr($_SERVER["CONTENT_TYPE"], "application/soap+xml")) {
|
||||
error_log("spp.php - Unexpected Content-Type " . $_SERVER["CONTENT_TYPE"]);
|
||||
die("Unexpected Content-Type");
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] != "POST") {
|
||||
error_log("spp.php - Unexpected method " . $_SERVER["REQUEST_METHOD"]);
|
||||
die("Unexpected method");
|
||||
}
|
||||
|
||||
if (isset($_GET["realm"])) {
|
||||
$realm = $_GET["realm"];
|
||||
$realm = PREG_REPLACE("/[^0-9a-zA-Z\.\-]/i", '', $realm);
|
||||
} else {
|
||||
error_log("spp.php - Realm not specified");
|
||||
die("Realm not specified");
|
||||
}
|
||||
|
||||
if (isset($_GET["test"]))
|
||||
$test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]);
|
||||
else
|
||||
$test = "";
|
||||
|
||||
unset($user);
|
||||
putenv("HS20CERT");
|
||||
|
||||
if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
|
||||
$needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
|
||||
'uri'=>1, 'response'=>1);
|
||||
$data = array();
|
||||
$keys = implode('|', array_keys($needed));
|
||||
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
|
||||
$_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $m) {
|
||||
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
|
||||
unset($needed[$m[1]]);
|
||||
}
|
||||
if ($needed) {
|
||||
error_log("spp.php - Authentication failed - missing: " . print_r($needed));
|
||||
die('Authentication failed');
|
||||
}
|
||||
$user = $data['username'];
|
||||
if (strlen($user) < 1) {
|
||||
error_log("spp.php - Authentication failed - empty username");
|
||||
die('Authentication failed');
|
||||
}
|
||||
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
error_log("spp.php - Could not access database");
|
||||
die("Could not access database");
|
||||
}
|
||||
$row = $db->query("SELECT password FROM users " .
|
||||
"WHERE identity='$user' AND realm='$realm'")->fetch();
|
||||
if (!$row) {
|
||||
$row = $db->query("SELECT osu_password FROM users " .
|
||||
"WHERE osu_user='$user' AND realm='$realm'")->fetch();
|
||||
$pw = $row['osu_password'];
|
||||
} else
|
||||
$pw = $row['password'];
|
||||
if (!$row) {
|
||||
error_log("spp.php - Authentication failed - user '$user' not found");
|
||||
die('Authentication failed');
|
||||
}
|
||||
if (strlen($pw) < 1) {
|
||||
error_log("spp.php - Authentication failed - empty password");
|
||||
die('Authentication failed');
|
||||
}
|
||||
|
||||
$A1 = md5($user . ':' . $realm . ':' . $pw);
|
||||
$A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
|
||||
$resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
|
||||
$data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
|
||||
if ($data['response'] != $resp) {
|
||||
error_log("Authentication failure - response mismatch");
|
||||
die('Authentication failed');
|
||||
}
|
||||
} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
|
||||
$_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
|
||||
isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
|
||||
$user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
|
||||
putenv("HS20CERT=yes");
|
||||
} else if (isset($_GET["hotspot2dot0-mobile-identifier-hash"])) {
|
||||
$id_hash = $_GET["hotspot2dot0-mobile-identifier-hash"];
|
||||
$id_hash = PREG_REPLACE("/[^0-9a-h]/i", '', $id_hash);
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
error_log("spp.php - Could not access database");
|
||||
die("Could not access database");
|
||||
}
|
||||
|
||||
$row = $db->query("SELECT * FROM sim_provisioning " .
|
||||
"WHERE mobile_identifier_hash='$id_hash'")->fetch();
|
||||
if (!$row) {
|
||||
error_log("spp.php - SIM provisioning failed - mobile_identifier_hash not found");
|
||||
die('SIM provisioning failed - mobile_identifier_hash not found');
|
||||
}
|
||||
|
||||
$imsi = $row['imsi'];
|
||||
$mac_addr = $row['mac_addr'];
|
||||
$eap_method = $row['eap_method'];
|
||||
|
||||
$row = $db->query("SELECT COUNT(*) FROM osu_config " .
|
||||
"WHERE realm='$realm'")->fetch();
|
||||
if (!$row || intval($row[0]) < 1) {
|
||||
error_log("spp.php - SIM provisioning failed - realm $realm not found");
|
||||
die('SIM provisioning failed');
|
||||
}
|
||||
|
||||
error_log("spp.php - SIM provisioning for IMSI $imsi");
|
||||
putenv("HS20SIMPROV=yes");
|
||||
putenv("HS20IMSI=$imsi");
|
||||
putenv("HS20MACADDR=$mac_addr");
|
||||
putenv("HS20EAPMETHOD=$eap_method");
|
||||
putenv("HS20IDHASH=$id_hash");
|
||||
} else if (!isset($_SERVER["PATH_INFO"]) ||
|
||||
$_SERVER["PATH_INFO"] != "/signup") {
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('WWW-Authenticate: Digest realm="'.$realm.
|
||||
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
|
||||
error_log("spp.php - Authentication required (not signup)");
|
||||
die('Authentication required (not signup)');
|
||||
}
|
||||
|
||||
|
||||
if (isset($user) && strlen($user) > 0)
|
||||
putenv("HS20USER=$user");
|
||||
else
|
||||
putenv("HS20USER");
|
||||
|
||||
putenv("HS20REALM=$realm");
|
||||
$postdata = file_get_contents("php://input");
|
||||
putenv("HS20POST=$postdata");
|
||||
$addr = $_SERVER["REMOTE_ADDR"];
|
||||
putenv("HS20ADDR=$addr");
|
||||
putenv("HS20TEST=$test");
|
||||
|
||||
$last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret);
|
||||
|
||||
if ($ret == 2) {
|
||||
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('WWW-Authenticate: Digest realm="'.$realm.
|
||||
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
|
||||
error_log("spp.php - Authentication required (ret 2)");
|
||||
die('Authentication required');
|
||||
} else {
|
||||
error_log("spp.php - Unexpected authentication error");
|
||||
die("Unexpected authentication error");
|
||||
}
|
||||
}
|
||||
if ($ret != 0) {
|
||||
error_log("spp.php - Failed to process SPP request");
|
||||
die("Failed to process SPP request");
|
||||
}
|
||||
//error_log("spp.php: Response: " . implode($output));
|
||||
|
||||
header("Content-Type: application/soap+xml");
|
||||
|
||||
echo implode($output);
|
||||
|
||||
?>
|
@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
function print_header()
|
||||
{
|
||||
echo "<html>\n";
|
||||
echo "<head><title>HS 2.0 Terms and Conditions</title></head>\n";
|
||||
echo "<body>\n";
|
||||
}
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (!isset($_GET["addr"])) {
|
||||
die("Missing addr parameter");
|
||||
}
|
||||
$addr = $_GET["addr"];
|
||||
|
||||
$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes";
|
||||
|
||||
$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?");
|
||||
$res->execute(array($addr));
|
||||
$row = $res->fetch();
|
||||
if (!$row) {
|
||||
die("No pending session for the specified MAC address");
|
||||
}
|
||||
$identity = $row[0];
|
||||
|
||||
if (!$accept) {
|
||||
print_header();
|
||||
|
||||
echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n";
|
||||
readfile($t_c_file);
|
||||
} else {
|
||||
$res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?");
|
||||
if (!$res->execute(array($t_c_timestamp, $identity))) {
|
||||
die("Failed to update user account.");
|
||||
}
|
||||
|
||||
$res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?");
|
||||
$res->execute(array($addr));
|
||||
|
||||
$fp = fsockopen($hostapd_ctrl);
|
||||
if (!$fp) {
|
||||
die("Could not connect to hostapd(AS)");
|
||||
}
|
||||
|
||||
fwrite($fp, "DAC_REQUEST coa $addr t_c_clear");
|
||||
fclose($fp);
|
||||
|
||||
$waiting = true;
|
||||
$ack = false;
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?");
|
||||
$res->execute(array($addr));
|
||||
$row = $res->fetch();
|
||||
if (!$row) {
|
||||
die("No current session for the specified MAC address");
|
||||
}
|
||||
if (strlen($row[0]) > 0)
|
||||
$waiting = $row[0] == 1;
|
||||
if (strlen($row[1]) > 0)
|
||||
$ack = $row[1] == 1;
|
||||
$res->closeCursor();
|
||||
if (!$waiting)
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
if ($ack) {
|
||||
header('X-WFA-Hotspot20-Filtering: removed');
|
||||
print_header();
|
||||
echo "<p>Terms and conditions were accepted.</p>\n";
|
||||
|
||||
echo "<P>Filtering disabled.</P>\n";
|
||||
} else {
|
||||
print_header();
|
||||
echo "<P>Failed to disable filtering.</P>\n";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,377 +0,0 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
$db = new PDO($osu_db);
|
||||
if (!$db) {
|
||||
die($sqliteerror);
|
||||
}
|
||||
|
||||
if (isset($_GET["id"])) {
|
||||
$id = $_GET["id"];
|
||||
if (!is_numeric($id))
|
||||
$id = 0;
|
||||
} else
|
||||
$id = 0;
|
||||
if (isset($_GET["cmd"]))
|
||||
$cmd = $_GET["cmd"];
|
||||
else
|
||||
$cmd = '';
|
||||
|
||||
if ($cmd == 'eventlog' && $id > 0) {
|
||||
$row = $db->query("SELECT dump FROM eventlog WHERE rowid=$id")->fetch();
|
||||
$dump = $row['dump'];
|
||||
if ($dump[0] == '<') {
|
||||
header("Content-type: text/xml");
|
||||
echo "<?xml version=\"1.0\"?>\n";
|
||||
echo $dump;
|
||||
} else {
|
||||
header("Content-type: text/plain");
|
||||
echo $dump;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($cmd == 'mo' && $id > 0) {
|
||||
$mo = $_GET["mo"];
|
||||
if (!isset($mo))
|
||||
exit;
|
||||
if ($mo != "devinfo" && $mo != "devdetail" && $mo != "pps")
|
||||
exit;
|
||||
$row = $db->query("SELECT $mo FROM users WHERE rowid=$id")->fetch();
|
||||
header("Content-type: text/xml");
|
||||
echo "<?xml version=\"1.0\"?>\n";
|
||||
echo $row[$mo];
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($cmd == 'cert' && $id > 0) {
|
||||
$row = $db->query("SELECT cert_pem FROM users WHERE rowid=$id")->fetch();
|
||||
header("Content-type: text/plain");
|
||||
echo $row['cert_pem'];
|
||||
exit;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<html>
|
||||
<head><title>HS 2.0 users</title></head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
|
||||
if ($cmd == 'subrem-clear' && $id > 0) {
|
||||
$db->exec("UPDATE users SET remediation='' WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'subrem-add-user' && $id > 0) {
|
||||
$db->exec("UPDATE users SET remediation='user' WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'subrem-add-machine' && $id > 0) {
|
||||
$db->exec("UPDATE users SET remediation='machine' WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'subrem-add-reenroll' && $id > 0) {
|
||||
$db->exec("UPDATE users SET remediation='reenroll' WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'subrem-add-policy' && $id > 0) {
|
||||
$db->exec("UPDATE users SET remediation='policy' WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'subrem-add-free' && $id > 0) {
|
||||
$db->exec("UPDATE users SET remediation='free' WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'fetch-pps-on' && $id > 0) {
|
||||
$db->exec("UPDATE users SET fetch_pps=1 WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'fetch-pps-off' && $id > 0) {
|
||||
$db->exec("UPDATE users SET fetch_pps=0 WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == 'reset-pw' && $id > 0) {
|
||||
$db->exec("UPDATE users SET password='ChangeMe' WHERE rowid=$id");
|
||||
}
|
||||
if ($cmd == "policy" && $id > 0 && isset($_GET["policy"])) {
|
||||
$policy = $_GET["policy"];
|
||||
if ($policy == "no-policy" ||
|
||||
is_readable("$osu_root/spp/policy/$policy.xml")) {
|
||||
$db->exec("UPDATE users SET policy='$policy' WHERE rowid=$id");
|
||||
}
|
||||
}
|
||||
if ($cmd == "account-type" && $id > 0 && isset($_GET["type"])) {
|
||||
$type = $_GET["type"];
|
||||
if ($type == "shared")
|
||||
$db->exec("UPDATE users SET shared=1 WHERE rowid=$id");
|
||||
if ($type == "default")
|
||||
$db->exec("UPDATE users SET shared=0 WHERE rowid=$id");
|
||||
}
|
||||
|
||||
if ($cmd == "set-osu-cred" && $id > 0) {
|
||||
$osu_user = $_POST["osu_user"];
|
||||
$osu_password = $_POST["osu_password"];
|
||||
if (strlen($osu_user) == 0)
|
||||
$osu_password = "";
|
||||
$db->exec("UPDATE users SET osu_user='$osu_user', osu_password='$osu_password' WHERE rowid=$id");
|
||||
}
|
||||
|
||||
if ($cmd == 'clear-t-c' && $id > 0) {
|
||||
$db->exec("UPDATE users SET t_c_timestamp=NULL WHERE rowid=$id");
|
||||
}
|
||||
|
||||
$dump = 0;
|
||||
|
||||
if ($id > 0) {
|
||||
|
||||
if (isset($_GET["dump"])) {
|
||||
$dump = $_GET["dump"];
|
||||
if (!is_numeric($dump))
|
||||
$dump = 0;
|
||||
} else
|
||||
$dump = 0;
|
||||
|
||||
echo "[<a href=\"users.php\">All users</a>] ";
|
||||
if ($dump == 0)
|
||||
echo "[<a href=\"users.php?id=$id&dump=1\">Include debug dump</a>] ";
|
||||
else
|
||||
echo "[<a href=\"users.php?id=$id\">Without debug dump</a>] ";
|
||||
echo "<br>\n";
|
||||
|
||||
$row = $db->query("SELECT rowid,* FROM users WHERE rowid=$id")->fetch();
|
||||
|
||||
echo "<H3>" . $row['identity'] . "@" . $row['realm'] . "</H3>\n";
|
||||
|
||||
echo "MO: ";
|
||||
if (strlen($row['devinfo']) > 0) {
|
||||
echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devinfo\">DevInfo</a>]\n";
|
||||
}
|
||||
if (strlen($row['devdetail']) > 0) {
|
||||
echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devdetail\">DevDetail</a>]\n";
|
||||
}
|
||||
if (strlen($row['pps']) > 0) {
|
||||
echo "[<a href=\"users.php?cmd=mo&id=$id&mo=pps\">PPS</a>]\n";
|
||||
}
|
||||
if (strlen($row['cert_pem']) > 0) {
|
||||
echo "[<a href=\"users.php?cmd=cert&id=$id\">Certificate</a>]\n";
|
||||
}
|
||||
echo "<BR>\n";
|
||||
|
||||
echo "Fetch PPS MO: ";
|
||||
if ($row['fetch_pps'] == "1") {
|
||||
echo "On next connection " .
|
||||
"[<a href=\"users.php?cmd=fetch-pps-off&id=$id\">" .
|
||||
"do not fetch</a>]<br>\n";
|
||||
} else {
|
||||
echo "Do not fetch " .
|
||||
"[<a href=\"users.php?cmd=fetch-pps-on&id=$id\">" .
|
||||
"request fetch</a>]<br>\n";
|
||||
}
|
||||
|
||||
$cert = $row['cert'];
|
||||
if (strlen($cert) > 0) {
|
||||
echo "Certificate fingerprint: $cert<br>\n";
|
||||
}
|
||||
|
||||
echo "Remediation: ";
|
||||
$rem = $row['remediation'];
|
||||
if ($rem == "") {
|
||||
echo "Not required";
|
||||
echo " [<a href=\"users.php?cmd=subrem-add-user&id=" .
|
||||
$row['rowid'] . "\">add:user</a>]";
|
||||
echo " [<a href=\"users.php?cmd=subrem-add-machine&id=" .
|
||||
$row['rowid'] . "\">add:machine</a>]";
|
||||
if ($row['methods'] == 'TLS') {
|
||||
echo " [<a href=\"users.php?cmd=subrem-add-reenroll&id=" .
|
||||
$row['rowid'] . "\">add:reenroll</a>]";
|
||||
}
|
||||
echo " [<a href=\"users.php?cmd=subrem-add-policy&id=" .
|
||||
$row['rowid'] . "\">add:policy</a>]";
|
||||
echo " [<a href=\"users.php?cmd=subrem-add-free&id=" .
|
||||
$row['rowid'] . "\">add:free</a>]";
|
||||
} else if ($rem == "user") {
|
||||
echo "User [<a href=\"users.php?cmd=subrem-clear&id=" .
|
||||
$row['rowid'] . "\">clear</a>]";
|
||||
} else if ($rem == "policy") {
|
||||
echo "Policy [<a href=\"users.php?cmd=subrem-clear&id=" .
|
||||
$row['rowid'] . "\">clear</a>]";
|
||||
} else if ($rem == "free") {
|
||||
echo "Free [<a href=\"users.php?cmd=subrem-clear&id=" .
|
||||
$row['rowid'] . "\">clear</a>]";
|
||||
} else if ($rem == "reenroll") {
|
||||
echo "Reenroll [<a href=\"users.php?cmd=subrem-clear&id=" .
|
||||
$row['rowid'] . "\">clear</a>]";
|
||||
} else {
|
||||
echo "Machine [<a href=\"users.php?cmd=subrem-clear&id=" .
|
||||
$row['rowid'] . "\">clear</a>]";
|
||||
}
|
||||
echo "<br>\n";
|
||||
|
||||
if (strncmp($row['identity'], "cert-", 5) != 0)
|
||||
echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n";
|
||||
|
||||
echo "<form>Policy: <select name=\"policy\" " .
|
||||
"onChange=\"window.location='users.php?cmd=policy&id=" .
|
||||
$row['rowid'] . "&policy=' + this.value;\">\n";
|
||||
echo "<option value=\"" . $row['policy'] . "\" selected>" . $row['policy'] .
|
||||
"</option>\n";
|
||||
$files = scandir("$osu_root/spp/policy");
|
||||
foreach ($files as $file) {
|
||||
if (!preg_match("/.xml$/", $file))
|
||||
continue;
|
||||
if ($file == $row['policy'] . ".xml")
|
||||
continue;
|
||||
$p = substr($file, 0, -4);
|
||||
echo "<option value=\"$p\">$p</option>\n";
|
||||
}
|
||||
echo "<option value=\"no-policy\">no policy</option>\n";
|
||||
echo "</select></form>\n";
|
||||
|
||||
echo "<form>Account type: <select name=\"type\" " .
|
||||
"onChange=\"window.location='users.php?cmd=account-type&id=" .
|
||||
$row['rowid'] . "&type=' + this.value;\">\n";
|
||||
if ($row['shared'] > 0) {
|
||||
$default_sel = "";
|
||||
$shared_sel = " selected";
|
||||
} else {
|
||||
$default_sel = " selected";
|
||||
$shared_sel = "";
|
||||
}
|
||||
echo "<option value=\"default\"$default_sel>default</option>\n";
|
||||
echo "<option value=\"shared\"$shared_sel>shared</option>\n";
|
||||
echo "</select></form>\n";
|
||||
|
||||
echo "Phase 2 method(s): " . $row['methods'] . "<br>\n";
|
||||
|
||||
echo "<br>\n";
|
||||
echo "<a href=\"users.php?cmd=reset-pw&id=" .
|
||||
$row['rowid'] . "\">Reset AAA password</a><br>\n";
|
||||
|
||||
echo "<br>\n";
|
||||
echo "<form action=\"users.php?cmd=set-osu-cred&id=" . $row['rowid'] .
|
||||
"\" method=\"POST\">\n";
|
||||
echo "OSU credentials (if username empty, AAA credentials are used):<br>\n";
|
||||
echo "username: <input type=\"text\" name=\"osu_user\" value=\"" .
|
||||
$row['osu_user'] . "\">\n";
|
||||
echo "password: <input type=\"password\" name=\"osu_password\">\n";
|
||||
echo "<input type=\"submit\" value=\"Set OSU credentials\">\n";
|
||||
echo "</form>\n";
|
||||
|
||||
if (strlen($row['t_c_timestamp']) > 0) {
|
||||
echo "<br>\n";
|
||||
echo "<a href=\"users.php?cmd=clear-t-c&id=" .
|
||||
$row['rowid'] .
|
||||
"\">Clear Terms and Conditions acceptance</a><br>\n";
|
||||
}
|
||||
|
||||
echo "<hr>\n";
|
||||
|
||||
$user = $row['identity'];
|
||||
$osu_user = $row['osu_user'];
|
||||
$realm = $row['realm'];
|
||||
}
|
||||
|
||||
if ($id > 0 || ($id == 0 && $cmd == 'eventlog')) {
|
||||
|
||||
if ($id == 0) {
|
||||
echo "[<a href=\"users.php\">All users</a>] ";
|
||||
echo "<br>\n";
|
||||
}
|
||||
|
||||
echo "<table border=1>\n";
|
||||
echo "<tr>";
|
||||
if ($id == 0) {
|
||||
echo "<th>user<th>realm";
|
||||
}
|
||||
echo "<th>time<th>address<th>sessionID<th>notes";
|
||||
if ($dump > 0)
|
||||
echo "<th>dump";
|
||||
echo "\n";
|
||||
if (isset($_GET["limit"])) {
|
||||
$limit = $_GET["limit"];
|
||||
if (!is_numeric($limit))
|
||||
$limit = 20;
|
||||
} else
|
||||
$limit = 20;
|
||||
if ($id == 0)
|
||||
$res = $db->query("SELECT rowid,* FROM eventlog ORDER BY timestamp DESC LIMIT $limit");
|
||||
else if (strlen($osu_user) > 0)
|
||||
$res = $db->query("SELECT rowid,* FROM eventlog WHERE (user='$user' OR user='$osu_user') AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
|
||||
else
|
||||
$res = $db->query("SELECT rowid,* FROM eventlog WHERE user='$user' AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
|
||||
foreach ($res as $row) {
|
||||
echo "<tr>";
|
||||
if ($id == 0) {
|
||||
echo "<td>" . $row['user'] . "\n";
|
||||
echo "<td>" . $row['realm'] . "\n";
|
||||
}
|
||||
echo "<td>" . $row['timestamp'] . "\n";
|
||||
echo "<td>" . $row['addr'] . "\n";
|
||||
echo "<td>" . $row['sessionid'] . "\n";
|
||||
echo "<td>" . $row['notes'] . "\n";
|
||||
$d = $row['dump'];
|
||||
if (strlen($d) > 0) {
|
||||
echo "[<a href=\"users.php?cmd=eventlog&id=" . $row['rowid'] .
|
||||
"\">";
|
||||
if ($d[0] == '<')
|
||||
echo "XML";
|
||||
else
|
||||
echo "txt";
|
||||
echo "</a>]\n";
|
||||
if ($dump > 0)
|
||||
echo "<td>" . htmlspecialchars($d) . "\n";
|
||||
}
|
||||
}
|
||||
echo "</table>\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ($id == 0 && $cmd != 'eventlog') {
|
||||
|
||||
echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] ";
|
||||
echo "<br>\n";
|
||||
|
||||
echo "<table border=1 cellspacing=0 cellpadding=0>\n";
|
||||
echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n";
|
||||
|
||||
$res = $db->query('SELECT rowid,* FROM users WHERE (phase2=1 OR methods=\'TLS\') ORDER BY identity');
|
||||
foreach ($res as $row) {
|
||||
echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " .
|
||||
$row['identity'] . " </a>";
|
||||
echo "<td>" . $row['realm'];
|
||||
$rem = $row['remediation'];
|
||||
echo "<td>";
|
||||
if ($rem == "") {
|
||||
echo "-";
|
||||
} else if ($rem == "user") {
|
||||
echo "User";
|
||||
} else if ($rem == "policy") {
|
||||
echo "Policy";
|
||||
} else if ($rem == "free") {
|
||||
echo "Free";
|
||||
} else if ($rem == "reenroll") {
|
||||
echo "Reenroll";
|
||||
} else {
|
||||
echo "Machine";
|
||||
}
|
||||
echo "<td>" . $row['policy'];
|
||||
if ($row['shared'] > 0)
|
||||
echo "<td>shared";
|
||||
else
|
||||
echo "<td>default";
|
||||
echo "<td><small>" . $row['methods'] . "</small>";
|
||||
echo "<td>";
|
||||
$xml = xml_parser_create();
|
||||
xml_parse_into_struct($xml, $row['devinfo'], $devinfo);
|
||||
foreach($devinfo as $k) {
|
||||
if ($k['tag'] == 'DEVID') {
|
||||
echo "<small>" . $k['value'] . "</small>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
echo "<td><small>" . $row['mac_addr'] . "</small>";
|
||||
echo "<td><small>" . $row['t_c_timestamp'] . "</small>";
|
||||
echo "\n";
|
||||
}
|
||||
echo "</table>\n";
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</html>
|
2
contrib/wpa/radius_example/.gitignore
vendored
2
contrib/wpa/radius_example/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
*.d
|
||||
radius_example
|
@ -1,28 +0,0 @@
|
||||
ALL=radius_example
|
||||
|
||||
include ../src/build.rules
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../src
|
||||
CFLAGS += -I../src/utils
|
||||
|
||||
LIBS = ../src/radius/libradius.a
|
||||
LIBS += ../src/crypto/libcrypto.a
|
||||
LIBS += ../src/utils/libutils.a
|
||||
LLIBS = -lrt
|
||||
|
||||
#CLAGS += -DCONFIG_IPV6
|
||||
|
||||
OBJS_ex = radius_example.o
|
||||
|
||||
_OBJS_VAR := OBJS_ex
|
||||
include ../src/objs.mk
|
||||
|
||||
_OBJS_VAR := LIBS
|
||||
include ../src/objs.mk
|
||||
|
||||
radius_example: $(OBJS_ex) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o radius_example $(OBJS_ex) $(LIBS) $(LLIBS)
|
||||
|
||||
clean: common-clean
|
||||
rm -f core *~ *.o *.d
|
@ -1,35 +0,0 @@
|
||||
Example application using RADIUS client as a library
|
||||
Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||
|
||||
This software may be distributed under the terms of the BSD license.
|
||||
See the parent directory README for more details.
|
||||
|
||||
|
||||
This directory contains an example showing how the RADIUS client
|
||||
functionality from hostapd can be used as a library in another
|
||||
program. The example program initializes the RADIUS client and send a
|
||||
Access-Request using User-Name and User-Password attributes. A reply
|
||||
from the RADIUS authentication server will be processed and it is used
|
||||
as a trigger to terminate the example program.
|
||||
|
||||
The RADIUS library links in couple of helper functions from src/utils and
|
||||
src/crypto directories. Most of these are suitable as-is, but it may
|
||||
be desirable to replace the debug output code in src/utils/wpa_debug.c
|
||||
by dropping this file from the library and re-implementing the
|
||||
functions there in a way that better fits in with the main
|
||||
application.
|
||||
|
||||
RADIUS client implementation takes care of receiving messages,
|
||||
timeouts, and retransmissions of packets. Consequently, it requires
|
||||
functionality for registering timeouts and received packet
|
||||
notifications. This is implemented using the generic event loop
|
||||
implementation (see src/utils/eloop.h).
|
||||
|
||||
The main application may either use the included event loop
|
||||
implementation or alternatively, implement eloop_* wrapper functions
|
||||
to use whatever event loop design is used in the main program. This
|
||||
would involve removing src/utils/eloop.o from the library and
|
||||
implementing following functions defines in src/utils/eloop.h:
|
||||
eloop_register_timeout(), eloop_cancel_timeout(),
|
||||
eloop_register_read_sock(), eloop_unregister_read_sock(), and
|
||||
eloop_terminated().
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Example application using RADIUS client as a library
|
||||
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eloop.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
|
||||
struct radius_ctx {
|
||||
struct radius_client_data *radius;
|
||||
struct hostapd_radius_servers conf;
|
||||
u8 radius_identifier;
|
||||
struct in_addr own_ip_addr;
|
||||
};
|
||||
|
||||
|
||||
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
|
||||
int level, const char *txt, size_t len)
|
||||
{
|
||||
printf("%s\n", txt);
|
||||
}
|
||||
|
||||
|
||||
/* Process the RADIUS frames from Authentication Server */
|
||||
static RadiusRxResult receive_auth(struct radius_msg *msg,
|
||||
struct radius_msg *req,
|
||||
const u8 *shared_secret,
|
||||
size_t shared_secret_len,
|
||||
void *data)
|
||||
{
|
||||
/* struct radius_ctx *ctx = data; */
|
||||
printf("Received RADIUS Authentication message; code=%d\n",
|
||||
radius_msg_get_hdr(msg)->code);
|
||||
|
||||
/* We're done for this example, so request eloop to terminate. */
|
||||
eloop_terminate();
|
||||
|
||||
return RADIUS_RX_PROCESSED;
|
||||
}
|
||||
|
||||
|
||||
static void start_example(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct radius_ctx *ctx = eloop_ctx;
|
||||
struct radius_msg *msg;
|
||||
|
||||
printf("Sending a RADIUS authentication message\n");
|
||||
|
||||
ctx->radius_identifier = radius_client_get_id(ctx->radius);
|
||||
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
|
||||
ctx->radius_identifier);
|
||||
if (msg == NULL) {
|
||||
printf("Could not create net RADIUS packet\n");
|
||||
return;
|
||||
}
|
||||
|
||||
radius_msg_make_authenticator(msg);
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
|
||||
(u8 *) "user", 4)) {
|
||||
printf("Could not add User-Name\n");
|
||||
radius_msg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_user_password(
|
||||
msg, (u8 *) "password", 8,
|
||||
ctx->conf.auth_server->shared_secret,
|
||||
ctx->conf.auth_server->shared_secret_len)) {
|
||||
printf("Could not add User-Password\n");
|
||||
radius_msg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &ctx->own_ip_addr, 4)) {
|
||||
printf("Could not add NAS-IP-Address\n");
|
||||
radius_msg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (radius_client_send(ctx->radius, msg, RADIUS_AUTH, NULL) < 0)
|
||||
radius_msg_free(msg);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct radius_ctx ctx;
|
||||
struct hostapd_radius_server *srv;
|
||||
|
||||
if (os_program_init())
|
||||
return -1;
|
||||
|
||||
hostapd_logger_register_cb(hostapd_logger_cb);
|
||||
|
||||
os_memset(&ctx, 0, sizeof(ctx));
|
||||
inet_aton("127.0.0.1", &ctx.own_ip_addr);
|
||||
|
||||
if (eloop_init()) {
|
||||
printf("Failed to initialize event loop\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
srv = os_zalloc(sizeof(*srv));
|
||||
if (srv == NULL)
|
||||
return -1;
|
||||
|
||||
srv->addr.af = AF_INET;
|
||||
srv->port = 1812;
|
||||
if (hostapd_parse_ip_addr("127.0.0.1", &srv->addr) < 0) {
|
||||
printf("Failed to parse IP address\n");
|
||||
return -1;
|
||||
}
|
||||
srv->shared_secret = (u8 *) os_strdup("radius");
|
||||
srv->shared_secret_len = 6;
|
||||
|
||||
ctx.conf.auth_server = ctx.conf.auth_servers = srv;
|
||||
ctx.conf.num_auth_servers = 1;
|
||||
ctx.conf.msg_dumps = 1;
|
||||
|
||||
ctx.radius = radius_client_init(&ctx, &ctx.conf);
|
||||
if (ctx.radius == NULL) {
|
||||
printf("Failed to initialize RADIUS client\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (radius_client_register(ctx.radius, RADIUS_AUTH, receive_auth,
|
||||
&ctx) < 0) {
|
||||
printf("Failed to register RADIUS authentication handler\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
eloop_register_timeout(0, 0, start_example, &ctx, NULL);
|
||||
|
||||
eloop_run();
|
||||
|
||||
radius_client_deinit(ctx.radius);
|
||||
os_free(srv->shared_secret);
|
||||
os_free(srv);
|
||||
|
||||
eloop_destroy();
|
||||
os_program_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
.PHONY: all
|
||||
all: _all
|
||||
|
||||
# disable built-in rules
|
||||
.SUFFIXES:
|
||||
|
||||
# setup some variables
|
||||
ROOTDIR := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||
ROOTDIR := $(dir $(ROOTDIR:%../src/=%))../
|
||||
BUILDDIR ?= $(abspath $(ROOTDIR)build)
|
||||
BUILDDIR := $(BUILDDIR:%/=%)
|
||||
ABSROOT := $(abspath $(ROOTDIR))
|
||||
ifeq ($(origin OUT),command line)
|
||||
_PROJ := $(OUT:%/=%)
|
||||
_PROJ := $(_PROJ:$(BUILDDIR)/%=%)
|
||||
else
|
||||
_PROJ := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
|
||||
_PROJ := $(_PROJ:$(ABSROOT)/%=%)
|
||||
endif
|
||||
|
||||
ifndef CC
|
||||
CC=gcc
|
||||
endif
|
||||
|
||||
ifndef RANLIB
|
||||
RANLIB=ranlib
|
||||
endif
|
||||
|
||||
ifndef LDO
|
||||
LDO=$(CC)
|
||||
endif
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_FILE),)
|
||||
-include $(CONFIG_FILE)
|
||||
|
||||
# export for sub-makefiles
|
||||
export CONFIG_CODE_COVERAGE
|
||||
|
||||
.PHONY: verify_config
|
||||
verify_config:
|
||||
@if [ ! -r $(CONFIG_FILE) ]; then \
|
||||
echo 'Building $(firstword $(ALL)) 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
|
||||
VERIFY := verify_config
|
||||
else
|
||||
VERIFY :=
|
||||
endif
|
||||
|
||||
# default target
|
||||
.PHONY: _all
|
||||
_all: $(VERIFY) $(ALL) $(EXTRA_TARGETS)
|
||||
|
||||
# continue setup
|
||||
COVSUFFIX := $(if $(CONFIG_CODE_COVERAGE),-cov,)
|
||||
PROJ := $(_PROJ)$(COVSUFFIX)
|
||||
|
||||
Q=@
|
||||
E=echo
|
||||
ifeq ($(V), 1)
|
||||
Q=
|
||||
E=true
|
||||
endif
|
||||
ifeq ($(QUIET), 1)
|
||||
Q=@
|
||||
E=true
|
||||
endif
|
||||
|
||||
ifeq ($(Q),@)
|
||||
MAKEFLAGS += --no-print-directory
|
||||
endif
|
||||
|
||||
_DIRS := $(BUILDDIR)/$(PROJ)
|
||||
.PHONY: _make_dirs
|
||||
_make_dirs:
|
||||
@mkdir -p $(_DIRS)
|
||||
|
||||
$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
@$(E) " CC " $<
|
||||
$(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
@$(E) " CC " $<
|
||||
# for the fuzzing tests
|
||||
$(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
@$(E) " CC " $<
|
||||
|
||||
# libraries - they know how to build themselves
|
||||
# (lib_phony so we recurse all the time)
|
||||
.PHONY: lib_phony
|
||||
lib_phony:
|
||||
# nothing
|
||||
|
||||
$(BUILDDIR)/$(PROJ)/%.a: $(CONFIG_FILE) lib_phony
|
||||
$(Q)$(MAKE) -C $(ROOTDIR)$(dir $(@:$(BUILDDIR)/$(PROJ)/%=%)) OUT=$(abspath $(dir $@))/
|
||||
|
||||
BUILDOBJ = $(patsubst %,$(BUILDDIR)/$(PROJ)/%,$(patsubst $(ROOTDIR)%,%,$(1)))
|
||||
|
||||
.PHONY: common-clean
|
||||
common-clean:
|
||||
$(Q)rm -rf $(ALL) $(BUILDDIR)/$(PROJ)
|
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Broadcom Corporation OUI and vendor specific assignments
|
||||
* Copyright (c) 2020, Broadcom Corporation.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef BRCM_VENDOR_H
|
||||
#define BRCM_VENDOR_H
|
||||
|
||||
/*
|
||||
* This file is a registry of identifier assignments from the Broadcom
|
||||
* OUI 00:10:18 for purposes other than MAC address assignment. New identifiers
|
||||
* can be assigned through normal review process for changes to the upstream
|
||||
* hostap.git repository.
|
||||
*/
|
||||
|
||||
#define OUI_BRCM 0x001018
|
||||
|
||||
/**
|
||||
* enum brcm_nl80211_vendor_subcmds - BRCM nl80211 vendor command identifiers
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_UNSPEC: Reserved value 0
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_PRIV_STR: Provide vendor private cmds to send to FW.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_BCM_STR: Provide vendor cmds to BCMDHD driver.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_BCM_PSK: Used to set SAE password.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_SET_PMK: Command to check driver support
|
||||
* for DFS offloading.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_GET_FEATURES: Command to get the features
|
||||
* supported by the driver.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_SET_MAC: Set random mac address for P2P interface.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters.
|
||||
* Used for the case that FW handle SAE.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters.
|
||||
* Used for the case that FW handle SAE.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to
|
||||
* invoke the ACS function in device and pass selected channels to
|
||||
* hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
|
||||
*
|
||||
* @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list.
|
||||
* Make sure it located at the end of the list.
|
||||
*
|
||||
*/
|
||||
enum brcm_nl80211_vendor_subcmds {
|
||||
BRCM_VENDOR_SCMD_UNSPEC = 0,
|
||||
BRCM_VENDOR_SCMD_PRIV_STR = 1,
|
||||
BRCM_VENDOR_SCMD_BCM_STR = 2,
|
||||
BRCM_VENDOR_SCMD_BCM_PSK = 3,
|
||||
BRCM_VENDOR_SCMD_SET_PMK = 4,
|
||||
BRCM_VENDOR_SCMD_GET_FEATURES = 5,
|
||||
BRCM_VENDOR_SCMD_SET_MAC = 6,
|
||||
BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS = 7,
|
||||
BRCM_VENDOR_SCMD_SET_START_AP_PARAMS = 8,
|
||||
BRCM_VENDOR_SCMD_ACS = 9,
|
||||
BRCM_VENDOR_SCMD_MAX = 10
|
||||
};
|
||||
|
||||
/**
|
||||
* enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers
|
||||
*
|
||||
* @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0
|
||||
*
|
||||
* @BRCM_VENDOR_EVENT_PRIV_STR: String command/event
|
||||
*/
|
||||
enum brcm_nl80211_vendor_events {
|
||||
BRCM_VENDOR_EVENT_UNSPEC = 0,
|
||||
BRCM_VENDOR_EVENT_PRIV_STR = 1,
|
||||
GOOGLE_GSCAN_SIGNIFICANT_EVENT = 2,
|
||||
GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT = 3,
|
||||
GOOGLE_GSCAN_BATCH_SCAN_EVENT = 4,
|
||||
GOOGLE_SCAN_FULL_RESULTS_EVENT = 5,
|
||||
GOOGLE_RTT_COMPLETE_EVENT = 6,
|
||||
GOOGLE_SCAN_COMPLETE_EVENT = 7,
|
||||
GOOGLE_GSCAN_GEOFENCE_LOST_EVENT = 8,
|
||||
GOOGLE_SCAN_EPNO_EVENT = 9,
|
||||
GOOGLE_DEBUG_RING_EVENT = 10,
|
||||
GOOGLE_FW_DUMP_EVENT = 11,
|
||||
GOOGLE_PNO_HOTSPOT_FOUND_EVENT = 12,
|
||||
GOOGLE_RSSI_MONITOR_EVENT = 13,
|
||||
GOOGLE_MKEEP_ALIVE_EVENT = 14,
|
||||
|
||||
/*
|
||||
* BRCM specific events should be placed after
|
||||
* the Generic events so that enums don't mismatch
|
||||
* between the DHD and HAL
|
||||
*/
|
||||
GOOGLE_NAN_EVENT_ENABLED = 15,
|
||||
GOOGLE_NAN_EVENT_DISABLED = 16,
|
||||
GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH = 17,
|
||||
GOOGLE_NAN_EVENT_REPLIED = 18,
|
||||
GOOGLE_NAN_EVENT_PUBLISH_TERMINATED = 19,
|
||||
GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED = 20,
|
||||
GOOGLE_NAN_EVENT_DE_EVENT = 21,
|
||||
GOOGLE_NAN_EVENT_FOLLOWUP = 22,
|
||||
GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND = 23,
|
||||
GOOGLE_NAN_EVENT_DATA_REQUEST = 24,
|
||||
GOOGLE_NAN_EVENT_DATA_CONFIRMATION = 25,
|
||||
GOOGLE_NAN_EVENT_DATA_END = 26,
|
||||
GOOGLE_NAN_EVENT_BEACON = 27,
|
||||
GOOGLE_NAN_EVENT_SDF = 28,
|
||||
GOOGLE_NAN_EVENT_TCA = 29,
|
||||
GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH = 30,
|
||||
GOOGLE_NAN_EVENT_UNKNOWN = 31,
|
||||
GOOGLE_ROAM_EVENT_START = 32,
|
||||
BRCM_VENDOR_EVENT_HANGED = 33,
|
||||
BRCM_VENDOR_EVENT_SAE_KEY = 34,
|
||||
BRCM_VENDOR_EVENT_BEACON_RECV = 35,
|
||||
BRCM_VENDOR_EVENT_PORT_AUTHORIZED = 36,
|
||||
GOOGLE_FILE_DUMP_EVENT = 37,
|
||||
BRCM_VENDOR_EVENT_CU = 38,
|
||||
BRCM_VENDOR_EVENT_WIPS = 39,
|
||||
NAN_ASYNC_RESPONSE_DISABLED = 40,
|
||||
BRCM_VENDOR_EVENT_RCC_INFO = 41,
|
||||
BRCM_VENDOR_EVENT_ACS = 42,
|
||||
BRCM_VENDOR_EVENT_LAST
|
||||
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BRCM_SAE
|
||||
enum wifi_sae_key_attr {
|
||||
BRCM_SAE_KEY_ATTR_BSSID,
|
||||
BRCM_SAE_KEY_ATTR_PMK,
|
||||
BRCM_SAE_KEY_ATTR_PMKID
|
||||
};
|
||||
#endif /* CONFIG_BRCM_SAE */
|
||||
|
||||
enum wl_vendor_attr_acs_offload {
|
||||
BRCM_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
|
||||
BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ,
|
||||
BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ,
|
||||
BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
|
||||
BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
|
||||
|
||||
BRCM_VENDOR_ATTR_ACS_HW_MODE,
|
||||
BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
|
||||
BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
|
||||
BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
|
||||
BRCM_VENDOR_ATTR_ACS_CHWIDTH,
|
||||
BRCM_VENDOR_ATTR_ACS_CH_LIST,
|
||||
BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
|
||||
|
||||
BRCM_VENDOR_ATTR_ACS_LAST
|
||||
};
|
||||
|
||||
|
||||
#endif /* BRCM_VENDOR_H */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,160 +0,0 @@
|
||||
/*
|
||||
* DPP module internal definitions
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2020, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef DPP_I_H
|
||||
#define DPP_I_H
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
|
||||
struct dpp_global {
|
||||
void *msg_ctx;
|
||||
struct dl_list bootstrap; /* struct dpp_bootstrap_info */
|
||||
struct dl_list configurator; /* struct dpp_configurator */
|
||||
#ifdef CONFIG_DPP2
|
||||
struct dl_list controllers; /* struct dpp_relay_controller */
|
||||
struct dpp_controller *controller;
|
||||
struct dl_list tcp_init; /* struct dpp_connection */
|
||||
void *cb_ctx;
|
||||
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
|
||||
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
};
|
||||
|
||||
/* dpp.c */
|
||||
|
||||
void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status);
|
||||
void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash);
|
||||
unsigned int dpp_next_id(struct dpp_global *dpp);
|
||||
struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const char *channel_list);
|
||||
struct json_token * dpp_parse_own_connector(const char *own_connector);
|
||||
int dpp_connector_match_groups(struct json_token *own_root,
|
||||
struct json_token *peer_root, bool reconfig);
|
||||
int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
|
||||
const char *kid, const struct dpp_curve_params *curve);
|
||||
EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
|
||||
const struct dpp_curve_params **key_curve);
|
||||
int dpp_prepare_channel_list(struct dpp_authentication *auth,
|
||||
unsigned int neg_freq,
|
||||
struct hostapd_hw_modes *own_modes, u16 num_modes);
|
||||
void dpp_auth_fail(struct dpp_authentication *auth, const char *txt);
|
||||
int dpp_gen_uri(struct dpp_bootstrap_info *bi);
|
||||
void dpp_write_adv_proto(struct wpabuf *buf);
|
||||
void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query);
|
||||
|
||||
/* dpp_backup.c */
|
||||
|
||||
void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key);
|
||||
struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth);
|
||||
int dpp_conf_resp_env_data(struct dpp_authentication *auth,
|
||||
const u8 *env_data, size_t env_data_len);
|
||||
|
||||
/* dpp_crypto.c */
|
||||
|
||||
struct dpp_signed_connector_info {
|
||||
unsigned char *payload;
|
||||
size_t payload_len;
|
||||
};
|
||||
|
||||
enum dpp_status_error
|
||||
dpp_process_signed_connector(struct dpp_signed_connector_info *info,
|
||||
EVP_PKEY *csign_pub, const char *connector);
|
||||
enum dpp_status_error
|
||||
dpp_check_signed_connector(struct dpp_signed_connector_info *info,
|
||||
const u8 *csign_key, size_t csign_key_len,
|
||||
const u8 *peer_connector, size_t peer_connector_len);
|
||||
const struct dpp_curve_params * dpp_get_curve_name(const char *name);
|
||||
const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name);
|
||||
const struct dpp_curve_params * dpp_get_curve_nid(int nid);
|
||||
const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group);
|
||||
int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
|
||||
const u8 *data, size_t data_len);
|
||||
struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix);
|
||||
EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
|
||||
const u8 *buf_x, const u8 *buf_y,
|
||||
size_t len);
|
||||
EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len);
|
||||
int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len);
|
||||
int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
|
||||
const char *label, u8 *out, size_t outlen);
|
||||
int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
|
||||
size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *mac);
|
||||
int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, u8 *secret, size_t *secret_len);
|
||||
void dpp_debug_print_point(const char *title, const EC_GROUP *group,
|
||||
const EC_POINT *point);
|
||||
void dpp_debug_print_key(const char *title, EVP_PKEY *key);
|
||||
int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
|
||||
const u8 *salt, size_t salt_len, unsigned int iterations,
|
||||
u8 *buf, size_t buflen);
|
||||
int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
|
||||
const u8 *data, size_t data_len);
|
||||
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
|
||||
int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
|
||||
const u8 *privkey, size_t privkey_len);
|
||||
EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
|
||||
const u8 *privkey, size_t privkey_len);
|
||||
EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve);
|
||||
int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len);
|
||||
int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len);
|
||||
int dpp_derive_bk_ke(struct dpp_authentication *auth);
|
||||
int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth);
|
||||
int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth);
|
||||
int dpp_auth_derive_l_responder(struct dpp_authentication *auth);
|
||||
int dpp_auth_derive_l_initiator(struct dpp_authentication *auth);
|
||||
int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len);
|
||||
int dpp_derive_pmkid(const struct dpp_curve_params *curve,
|
||||
EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid);
|
||||
EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
|
||||
const u8 *mac_init, const char *code,
|
||||
const char *identifier, BN_CTX *bnctx,
|
||||
EC_GROUP **ret_group);
|
||||
EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
|
||||
const u8 *mac_resp, const char *code,
|
||||
const char *identifier, BN_CTX *bnctx,
|
||||
EC_GROUP **ret_group);
|
||||
int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
|
||||
const u8 *Mx, size_t Mx_len,
|
||||
const u8 *Nx, size_t Nx_len,
|
||||
const char *code,
|
||||
const u8 *Kx, size_t Kx_len,
|
||||
u8 *z, unsigned int hash_len);
|
||||
int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
|
||||
const u8 *net_access_key,
|
||||
size_t net_access_key_len,
|
||||
struct json_token *peer_net_access_key);
|
||||
int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
|
||||
const u8 *r_proto, u16 r_proto_len,
|
||||
struct json_token *net_access_key);
|
||||
EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
|
||||
EVP_PKEY *e_prime_id);
|
||||
char * dpp_sign_connector(struct dpp_configurator *conf,
|
||||
const struct wpabuf *dppcon);
|
||||
int dpp_test_gen_invalid_key(struct wpabuf *msg,
|
||||
const struct dpp_curve_params *curve);
|
||||
|
||||
struct dpp_reconfig_id {
|
||||
const EC_GROUP *group;
|
||||
EC_POINT *e_id; /* E-id */
|
||||
EVP_PKEY *csign;
|
||||
EVP_PKEY *a_nonce; /* A-NONCE */
|
||||
EVP_PKEY *e_prime_id; /* E'-id */
|
||||
EVP_PKEY *pp_key;
|
||||
};
|
||||
|
||||
/* dpp_tcp.c */
|
||||
|
||||
void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx);
|
||||
void dpp_tcp_init_flush(struct dpp_global *dpp);
|
||||
void dpp_relay_flush_controllers(struct dpp_global *dpp);
|
||||
|
||||
#endif /* CONFIG_DPP */
|
||||
#endif /* DPP_I_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,958 +0,0 @@
|
||||
/*
|
||||
* DPP reconfiguration
|
||||
* Copyright (c) 2020, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/json.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_siv.h"
|
||||
#include "dpp.h"
|
||||
#include "dpp_i.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
|
||||
static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash)
|
||||
{
|
||||
if (hash) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Configurator C-sign key Hash");
|
||||
wpabuf_put_le16(msg, DPP_ATTR_C_SIGN_KEY_HASH);
|
||||
wpabuf_put_le16(msg, SHA256_MAC_LEN);
|
||||
wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
|
||||
size_t csign_key_len,
|
||||
const u8 *net_access_key,
|
||||
size_t net_access_key_len,
|
||||
struct dpp_reconfig_id *id)
|
||||
{
|
||||
struct wpabuf *msg = NULL;
|
||||
EVP_PKEY *csign = NULL;
|
||||
const unsigned char *p;
|
||||
struct wpabuf *uncomp;
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
const u8 *addr[1];
|
||||
size_t len[1];
|
||||
int res;
|
||||
size_t attr_len;
|
||||
const struct dpp_curve_params *own_curve;
|
||||
EVP_PKEY *own_key;
|
||||
struct wpabuf *a_nonce = NULL, *e_id = NULL;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame");
|
||||
|
||||
own_key = dpp_set_keypair(&own_curve, net_access_key,
|
||||
net_access_key_len);
|
||||
if (!own_key) {
|
||||
wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
p = csign_key;
|
||||
csign = d2i_PUBKEY(NULL, &p, csign_key_len);
|
||||
if (!csign) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"DPP: Failed to parse local C-sign-key information");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
uncomp = dpp_get_pubkey_point(csign, 1);
|
||||
EVP_PKEY_free(csign);
|
||||
if (!uncomp)
|
||||
goto fail;
|
||||
addr[0] = wpabuf_head(uncomp);
|
||||
len[0] = wpabuf_len(uncomp);
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]);
|
||||
res = sha256_vector(1, addr, len, hash);
|
||||
wpabuf_free(uncomp);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)",
|
||||
hash, SHA256_MAC_LEN);
|
||||
|
||||
if (dpp_update_reconfig_id(id) < 0) {
|
||||
wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
a_nonce = dpp_get_pubkey_point(id->a_nonce, 0);
|
||||
e_id = dpp_get_pubkey_point(id->e_prime_id, 0);
|
||||
if (!a_nonce || !e_id)
|
||||
goto fail;
|
||||
|
||||
attr_len = 4 + SHA256_MAC_LEN;
|
||||
attr_len += 4 + 2;
|
||||
attr_len += 4 + wpabuf_len(a_nonce);
|
||||
attr_len += 4 + wpabuf_len(e_id);
|
||||
msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len);
|
||||
if (!msg)
|
||||
goto fail;
|
||||
|
||||
/* Configurator C-sign key Hash */
|
||||
dpp_build_attr_csign_key_hash(msg, hash);
|
||||
|
||||
/* Finite Cyclic Group attribute */
|
||||
wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
|
||||
own_curve->ike_group);
|
||||
wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
|
||||
wpabuf_put_le16(msg, 2);
|
||||
wpabuf_put_le16(msg, own_curve->ike_group);
|
||||
|
||||
/* A-NONCE */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_A_NONCE);
|
||||
wpabuf_put_le16(msg, wpabuf_len(a_nonce));
|
||||
wpabuf_put_buf(msg, a_nonce);
|
||||
|
||||
/* E'-id */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID);
|
||||
wpabuf_put_le16(msg, wpabuf_len(e_id));
|
||||
wpabuf_put_buf(msg, e_id);
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG,
|
||||
"DPP: Reconfig Announcement frame attributes", msg);
|
||||
fail:
|
||||
wpabuf_free(a_nonce);
|
||||
wpabuf_free(e_id);
|
||||
EVP_PKEY_free(own_key);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
size_t attr_len;
|
||||
|
||||
/* Build DPP Reconfig Authentication Request frame attributes */
|
||||
attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) +
|
||||
4 + auth->curve->nonce_len;
|
||||
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_REQ, attr_len);
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
/* Transaction ID */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
|
||||
wpabuf_put_le16(msg, 1);
|
||||
wpabuf_put_u8(msg, auth->transaction_id);
|
||||
|
||||
/* Protocol Version */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
|
||||
wpabuf_put_le16(msg, 1);
|
||||
wpabuf_put_u8(msg, DPP_VERSION);
|
||||
|
||||
/* DPP Connector */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
|
||||
wpabuf_put_le16(msg, os_strlen(auth->conf->connector));
|
||||
wpabuf_put_str(msg, auth->conf->connector);
|
||||
|
||||
/* C-nonce */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
|
||||
wpabuf_put_le16(msg, auth->curve->nonce_len);
|
||||
wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len);
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG,
|
||||
"DPP: Reconfig Authentication Request frame attributes",
|
||||
msg);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dpp_configurator_build_own_connector(struct dpp_configurator *conf,
|
||||
const struct dpp_curve_params *curve)
|
||||
{
|
||||
struct wpabuf *dppcon = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (conf->connector)
|
||||
return 0; /* already generated */
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Sign own Configurator Connector for reconfiguration with curve %s",
|
||||
conf->curve->name);
|
||||
conf->connector_key = dpp_gen_keypair(curve);
|
||||
if (!conf->connector_key)
|
||||
goto fail;
|
||||
|
||||
/* Connector (JSON dppCon object) */
|
||||
dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3);
|
||||
if (!dppcon)
|
||||
goto fail;
|
||||
json_start_object(dppcon, NULL);
|
||||
json_start_array(dppcon, "groups");
|
||||
json_start_object(dppcon, NULL);
|
||||
json_add_string(dppcon, "groupId", "*");
|
||||
json_value_sep(dppcon);
|
||||
json_add_string(dppcon, "netRole", "configurator");
|
||||
json_end_object(dppcon);
|
||||
json_end_array(dppcon);
|
||||
json_value_sep(dppcon);
|
||||
if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL,
|
||||
curve) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
|
||||
goto fail;
|
||||
}
|
||||
json_end_object(dppcon);
|
||||
wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
|
||||
(const char *) wpabuf_head(dppcon));
|
||||
|
||||
conf->connector = dpp_sign_connector(conf, dppcon);
|
||||
if (!conf->connector)
|
||||
goto fail;
|
||||
wpa_printf(MSG_DEBUG, "DPP: signedConnector: %s", conf->connector);
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
wpabuf_free(dppcon);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct dpp_authentication *
|
||||
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
|
||||
struct dpp_configurator *conf, unsigned int freq, u16 group,
|
||||
const u8 *a_nonce_attr, size_t a_nonce_len,
|
||||
const u8 *e_id_attr, size_t e_id_len)
|
||||
{
|
||||
struct dpp_authentication *auth;
|
||||
const struct dpp_curve_params *curve;
|
||||
EVP_PKEY *a_nonce, *e_prime_id;
|
||||
EC_POINT *e_id;
|
||||
|
||||
curve = dpp_get_curve_ike_group(group);
|
||||
if (!curve) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Unsupported group %u - cannot reconfigure",
|
||||
group);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!a_nonce_attr) {
|
||||
wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute");
|
||||
return NULL;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len);
|
||||
a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len);
|
||||
if (!a_nonce) {
|
||||
wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE");
|
||||
return NULL;
|
||||
}
|
||||
dpp_debug_print_key("A-NONCE", a_nonce);
|
||||
|
||||
if (!e_id_attr) {
|
||||
wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute");
|
||||
return NULL;
|
||||
}
|
||||
e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len);
|
||||
if (!e_prime_id) {
|
||||
wpa_printf(MSG_INFO, "DPP: Invalid E'-id");
|
||||
EVP_PKEY_free(a_nonce);
|
||||
return NULL;
|
||||
}
|
||||
dpp_debug_print_key("E'-id", e_prime_id);
|
||||
e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id);
|
||||
EVP_PKEY_free(a_nonce);
|
||||
EVP_PKEY_free(e_prime_id);
|
||||
if (!e_id) {
|
||||
wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id");
|
||||
return NULL;
|
||||
}
|
||||
/* TODO: could use E-id to determine whether reconfiguration with this
|
||||
* Enrollee has already been started and is waiting for updated
|
||||
* configuration instead of replying again before such configuration
|
||||
* becomes available */
|
||||
EC_POINT_clear_free(e_id);
|
||||
|
||||
auth = dpp_alloc_auth(dpp, msg_ctx);
|
||||
if (!auth)
|
||||
return NULL;
|
||||
|
||||
auth->conf = conf;
|
||||
auth->reconfig = 1;
|
||||
auth->initiator = 1;
|
||||
auth->waiting_auth_resp = 1;
|
||||
auth->allowed_roles = DPP_CAPAB_CONFIGURATOR;
|
||||
auth->configurator = 1;
|
||||
auth->curve = curve;
|
||||
auth->transaction_id = 1;
|
||||
if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
|
||||
goto fail;
|
||||
|
||||
if (dpp_configurator_build_own_connector(conf, curve) < 0)
|
||||
goto fail;
|
||||
|
||||
if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) {
|
||||
wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
auth->reconfig_req_msg = dpp_reconfig_build_req(auth);
|
||||
if (!auth->reconfig_req_msg)
|
||||
goto fail;
|
||||
|
||||
out:
|
||||
return auth;
|
||||
fail:
|
||||
dpp_auth_deinit(auth);
|
||||
auth = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
|
||||
const char *own_connector,
|
||||
struct wpabuf *conn_status)
|
||||
{
|
||||
struct wpabuf *msg = NULL, *clear, *pr = NULL;
|
||||
u8 *attr_start, *attr_end;
|
||||
size_t clear_len, attr_len, len[2];
|
||||
const u8 *addr[2];
|
||||
u8 *wrapped;
|
||||
int res = -1;
|
||||
|
||||
/* Build DPP Reconfig Authentication Response frame attributes */
|
||||
clear_len = 4 + auth->curve->nonce_len +
|
||||
4 + wpabuf_len(conn_status);
|
||||
clear = wpabuf_alloc(clear_len);
|
||||
if (!clear)
|
||||
goto fail;
|
||||
|
||||
/* C-nonce (wrapped) */
|
||||
wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
|
||||
wpabuf_put_le16(clear, auth->curve->nonce_len);
|
||||
wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
|
||||
|
||||
/* Connection Status (wrapped) */
|
||||
wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
|
||||
wpabuf_put_le16(clear, wpabuf_len(conn_status));
|
||||
wpabuf_put_buf(clear, conn_status);
|
||||
|
||||
pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
|
||||
if (!pr)
|
||||
goto fail;
|
||||
|
||||
attr_len = 4 + 1 + 4 + 1 +
|
||||
4 + os_strlen(own_connector) +
|
||||
4 + auth->curve->nonce_len +
|
||||
4 + wpabuf_len(pr) +
|
||||
4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
|
||||
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len);
|
||||
if (!msg)
|
||||
goto fail;
|
||||
|
||||
attr_start = wpabuf_put(msg, 0);
|
||||
|
||||
/* Transaction ID */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
|
||||
wpabuf_put_le16(msg, 1);
|
||||
wpabuf_put_u8(msg, auth->transaction_id);
|
||||
|
||||
/* Protocol Version */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
|
||||
wpabuf_put_le16(msg, 1);
|
||||
wpabuf_put_u8(msg, DPP_VERSION);
|
||||
|
||||
/* R-Connector */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
|
||||
wpabuf_put_le16(msg, os_strlen(own_connector));
|
||||
wpabuf_put_str(msg, own_connector);
|
||||
|
||||
/* E-nonce */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE);
|
||||
wpabuf_put_le16(msg, auth->curve->nonce_len);
|
||||
wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len);
|
||||
|
||||
/* Responder Protocol Key (Pr) */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
|
||||
wpabuf_put_le16(msg, wpabuf_len(pr));
|
||||
wpabuf_put_buf(msg, pr);
|
||||
|
||||
attr_end = wpabuf_put(msg, 0);
|
||||
|
||||
/* OUI, OUI type, Crypto Suite, DPP frame type */
|
||||
addr[0] = wpabuf_head_u8(msg) + 2;
|
||||
len[0] = 3 + 1 + 1 + 1;
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
|
||||
|
||||
/* Attributes before Wrapped Data */
|
||||
addr[1] = attr_start;
|
||||
len[1] = attr_end - attr_start;
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
|
||||
|
||||
/* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
|
||||
wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
|
||||
wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
|
||||
if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
|
||||
wpabuf_head(clear), wpabuf_len(clear),
|
||||
2, addr, len, wrapped) < 0)
|
||||
goto fail;
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG,
|
||||
"DPP: Reconfig Authentication Response frame attributes",
|
||||
msg);
|
||||
|
||||
wpabuf_free(auth->reconfig_resp_msg);
|
||||
auth->reconfig_resp_msg = msg;
|
||||
|
||||
res = 0;
|
||||
out:
|
||||
wpabuf_free(clear);
|
||||
wpabuf_free(pr);
|
||||
return res;
|
||||
fail:
|
||||
wpabuf_free(msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
struct dpp_authentication *
|
||||
dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
|
||||
const char *own_connector,
|
||||
const u8 *net_access_key, size_t net_access_key_len,
|
||||
const u8 *csign_key, size_t csign_key_len,
|
||||
unsigned int freq, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len)
|
||||
{
|
||||
struct dpp_authentication *auth = NULL;
|
||||
const u8 *trans_id, *version, *i_connector, *c_nonce;
|
||||
u16 trans_id_len, version_len, i_connector_len, c_nonce_len;
|
||||
struct dpp_signed_connector_info info;
|
||||
enum dpp_status_error res;
|
||||
struct json_token *root = NULL, *own_root = NULL, *token;
|
||||
unsigned char *own_conn = NULL;
|
||||
struct wpabuf *conn_status = NULL;
|
||||
|
||||
os_memset(&info, 0, sizeof(info));
|
||||
|
||||
trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
|
||||
&trans_id_len);
|
||||
if (!trans_id || trans_id_len != 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Peer did not include Transaction ID");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
|
||||
&version_len);
|
||||
if (!version || version_len < 1 || version[0] < 2) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Missing or invalid Protocol Version attribute");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
i_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
|
||||
&i_connector_len);
|
||||
if (!i_connector) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Missing I-Connector attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector",
|
||||
i_connector, i_connector_len);
|
||||
|
||||
c_nonce = dpp_get_attr(attr_start, attr_len,
|
||||
DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
|
||||
if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Missing or invalid C-nonce attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
|
||||
|
||||
res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
|
||||
i_connector, i_connector_len);
|
||||
if (res != DPP_STATUS_OK) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Invalid I-Connector");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
root = json_parse((const char *) info.payload, info.payload_len);
|
||||
own_root = dpp_parse_own_connector(own_connector);
|
||||
if (!root || !own_root ||
|
||||
!dpp_connector_match_groups(own_root, root, true)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: I-Connector does not include compatible group netrole with own connector");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
token = json_get_member(root, "expiry");
|
||||
if (token && token->type == JSON_STRING &&
|
||||
dpp_key_expired(token->string, NULL)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: I-Connector (netAccessKey) has expired");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
token = json_get_member(root, "netAccessKey");
|
||||
if (!token || token->type != JSON_OBJECT) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
auth = dpp_alloc_auth(dpp, msg_ctx);
|
||||
if (!auth)
|
||||
return NULL;
|
||||
|
||||
auth->reconfig = 1;
|
||||
auth->allowed_roles = DPP_CAPAB_ENROLLEE;
|
||||
if (dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
|
||||
goto fail;
|
||||
|
||||
auth->transaction_id = trans_id[0];
|
||||
|
||||
auth->peer_version = version[0];
|
||||
wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
|
||||
auth->peer_version);
|
||||
|
||||
os_memcpy(auth->c_nonce, c_nonce, c_nonce_len);
|
||||
|
||||
if (dpp_reconfig_derive_ke_responder(auth, net_access_key,
|
||||
net_access_key_len, token) < 0)
|
||||
goto fail;
|
||||
|
||||
if (c_nonce_len != auth->curve->nonce_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Unexpected C-nonce length %u (curve nonce len %zu)",
|
||||
c_nonce_len, auth->curve->nonce_len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Build Connection Status object */
|
||||
/* TODO: Get appropriate result value */
|
||||
/* TODO: ssid64 and channelList */
|
||||
conn_status = dpp_build_conn_status(DPP_STATUS_NO_AP, NULL, 0, NULL);
|
||||
if (!conn_status)
|
||||
goto fail;
|
||||
|
||||
if (dpp_reconfig_build_resp(auth, own_connector, conn_status) < 0)
|
||||
goto fail;
|
||||
|
||||
out:
|
||||
os_free(info.payload);
|
||||
os_free(own_conn);
|
||||
json_free(root);
|
||||
json_free(own_root);
|
||||
wpabuf_free(conn_status);
|
||||
return auth;
|
||||
fail:
|
||||
dpp_auth_deinit(auth);
|
||||
auth = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf *
|
||||
dpp_reconfig_build_conf(struct dpp_authentication *auth)
|
||||
{
|
||||
struct wpabuf *msg = NULL, *clear;
|
||||
u8 *attr_start, *attr_end;
|
||||
size_t clear_len, attr_len, len[2];
|
||||
const u8 *addr[2];
|
||||
u8 *wrapped;
|
||||
u8 flags;
|
||||
|
||||
/* Build DPP Reconfig Authentication Confirm frame attributes */
|
||||
clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) +
|
||||
4 + 1;
|
||||
clear = wpabuf_alloc(clear_len);
|
||||
if (!clear)
|
||||
goto fail;
|
||||
|
||||
/* Transaction ID */
|
||||
wpabuf_put_le16(clear, DPP_ATTR_TRANSACTION_ID);
|
||||
wpabuf_put_le16(clear, 1);
|
||||
wpabuf_put_u8(clear, auth->transaction_id);
|
||||
|
||||
/* Protocol Version */
|
||||
wpabuf_put_le16(clear, DPP_ATTR_PROTOCOL_VERSION);
|
||||
wpabuf_put_le16(clear, 1);
|
||||
wpabuf_put_u8(clear, auth->peer_version);
|
||||
|
||||
/* C-nonce (wrapped) */
|
||||
wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
|
||||
wpabuf_put_le16(clear, auth->curve->nonce_len);
|
||||
wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
|
||||
|
||||
/* E-nonce (wrapped) */
|
||||
wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
|
||||
wpabuf_put_le16(clear, auth->curve->nonce_len);
|
||||
wpabuf_put_data(clear, auth->e_nonce, auth->curve->nonce_len);
|
||||
|
||||
/* Reconfig-Flags (wrapped) */
|
||||
flags = DPP_CONFIG_REPLACEKEY;
|
||||
wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS);
|
||||
wpabuf_put_le16(clear, 1);
|
||||
wpabuf_put_u8(clear, flags);
|
||||
|
||||
attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
|
||||
attr_len += 4 + 1;
|
||||
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len);
|
||||
if (!msg)
|
||||
goto fail;
|
||||
|
||||
attr_start = wpabuf_put(msg, 0);
|
||||
|
||||
/* DPP Status */
|
||||
dpp_build_attr_status(msg, DPP_STATUS_OK);
|
||||
|
||||
attr_end = wpabuf_put(msg, 0);
|
||||
|
||||
/* OUI, OUI type, Crypto Suite, DPP frame type */
|
||||
addr[0] = wpabuf_head_u8(msg) + 2;
|
||||
len[0] = 3 + 1 + 1 + 1;
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
|
||||
|
||||
/* Attributes before Wrapped Data */
|
||||
addr[1] = attr_start;
|
||||
len[1] = attr_end - attr_start;
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
|
||||
|
||||
/* Wrapped Data */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
|
||||
wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
|
||||
wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
|
||||
if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
|
||||
wpabuf_head(clear), wpabuf_len(clear),
|
||||
2, addr, len, wrapped) < 0)
|
||||
goto fail;
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG,
|
||||
"DPP: Reconfig Authentication Confirm frame attributes",
|
||||
msg);
|
||||
|
||||
out:
|
||||
wpabuf_free(clear);
|
||||
return msg;
|
||||
fail:
|
||||
wpabuf_free(msg);
|
||||
msg = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf *
|
||||
dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len)
|
||||
{
|
||||
const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data,
|
||||
*c_nonce, *e_nonce, *conn_status;
|
||||
u16 trans_id_len, version_len, r_connector_len, r_proto_len,
|
||||
wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len;
|
||||
struct wpabuf *conf = NULL;
|
||||
char *signed_connector = NULL;
|
||||
struct dpp_signed_connector_info info;
|
||||
enum dpp_status_error res;
|
||||
struct json_token *root = NULL, *token, *conn_status_json = NULL;
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
u8 *unwrapped = NULL;
|
||||
size_t unwrapped_len = 0;
|
||||
|
||||
os_memset(&info, 0, sizeof(info));
|
||||
|
||||
if (!auth->reconfig || !auth->configurator)
|
||||
goto fail;
|
||||
|
||||
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
|
||||
&wrapped_data_len);
|
||||
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
|
||||
dpp_auth_fail(auth,
|
||||
"Missing or invalid required Wrapped Data attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
|
||||
wrapped_data, wrapped_data_len);
|
||||
attr_len = wrapped_data - 4 - attr_start;
|
||||
|
||||
trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
|
||||
&trans_id_len);
|
||||
if (!trans_id || trans_id_len != 1) {
|
||||
dpp_auth_fail(auth, "Peer did not include Transaction ID");
|
||||
goto fail;
|
||||
}
|
||||
if (trans_id[0] != auth->transaction_id) {
|
||||
dpp_auth_fail(auth, "Transaction ID mismatch");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
|
||||
&version_len);
|
||||
if (!version || version_len < 1 || version[0] < 2) {
|
||||
dpp_auth_fail(auth,
|
||||
"Missing or invalid Protocol Version attribute");
|
||||
goto fail;
|
||||
}
|
||||
auth->peer_version = version[0];
|
||||
wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
|
||||
auth->peer_version);
|
||||
|
||||
r_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
|
||||
&r_connector_len);
|
||||
if (!r_connector) {
|
||||
dpp_auth_fail(auth, " Missing R-Connector attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector",
|
||||
r_connector, r_connector_len);
|
||||
|
||||
e_nonce = dpp_get_attr(attr_start, attr_len,
|
||||
DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
|
||||
if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
|
||||
dpp_auth_fail(auth, "Missing or invalid E-nonce");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
|
||||
os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
|
||||
|
||||
r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
|
||||
&r_proto_len);
|
||||
if (!r_proto) {
|
||||
dpp_auth_fail(auth,
|
||||
"Missing required Responder Protocol Key attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
|
||||
r_proto, r_proto_len);
|
||||
|
||||
signed_connector = os_malloc(r_connector_len + 1);
|
||||
if (!signed_connector)
|
||||
goto fail;
|
||||
os_memcpy(signed_connector, r_connector, r_connector_len);
|
||||
signed_connector[r_connector_len] = '\0';
|
||||
|
||||
res = dpp_process_signed_connector(&info, auth->conf->csign,
|
||||
signed_connector);
|
||||
if (res != DPP_STATUS_OK) {
|
||||
dpp_auth_fail(auth, "Invalid R-Connector");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
root = json_parse((const char *) info.payload, info.payload_len);
|
||||
if (!root) {
|
||||
dpp_auth_fail(auth, "Invalid Connector payload");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Do not check netAccessKey expiration for reconfiguration to allow
|
||||
* expired Connector to be updated. */
|
||||
|
||||
token = json_get_member(root, "netAccessKey");
|
||||
if (!token || token->type != JSON_OBJECT) {
|
||||
dpp_auth_fail(auth, "No netAccessKey object found");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (dpp_reconfig_derive_ke_initiator(auth, r_proto, r_proto_len,
|
||||
token) < 0)
|
||||
goto fail;
|
||||
|
||||
addr[0] = hdr;
|
||||
len[0] = DPP_HDR_LEN;
|
||||
addr[1] = attr_start;
|
||||
len[1] = attr_len;
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
|
||||
wrapped_data, wrapped_data_len);
|
||||
unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
|
||||
unwrapped = os_malloc(unwrapped_len);
|
||||
if (!unwrapped)
|
||||
goto fail;
|
||||
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
|
||||
wrapped_data, wrapped_data_len,
|
||||
2, addr, len, unwrapped) < 0) {
|
||||
dpp_auth_fail(auth, "AES-SIV decryption failed");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
|
||||
unwrapped, unwrapped_len);
|
||||
|
||||
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
|
||||
dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
|
||||
DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
|
||||
if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
|
||||
os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
|
||||
dpp_auth_fail(auth, "Missing or invalid C-nonce");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
|
||||
|
||||
conn_status = dpp_get_attr(unwrapped, unwrapped_len,
|
||||
DPP_ATTR_CONN_STATUS, &conn_status_len);
|
||||
if (!conn_status) {
|
||||
dpp_auth_fail(auth, "Missing Connection Status attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus",
|
||||
conn_status, conn_status_len);
|
||||
|
||||
conn_status_json = json_parse((const char *) conn_status,
|
||||
conn_status_len);
|
||||
if (!conn_status_json) {
|
||||
dpp_auth_fail(auth, "Could not parse connStatus");
|
||||
goto fail;
|
||||
}
|
||||
/* TODO: use connStatus information */
|
||||
|
||||
conf = dpp_reconfig_build_conf(auth);
|
||||
if (conf)
|
||||
auth->reconfig_success = true;
|
||||
|
||||
out:
|
||||
json_free(root);
|
||||
json_free(conn_status_json);
|
||||
bin_clear_free(unwrapped, unwrapped_len);
|
||||
os_free(info.payload);
|
||||
os_free(signed_connector);
|
||||
return conf;
|
||||
fail:
|
||||
wpabuf_free(conf);
|
||||
conf = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len)
|
||||
{
|
||||
const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce,
|
||||
*reconfig_flags, *status;
|
||||
u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len,
|
||||
e_nonce_len, reconfig_flags_len, status_len;
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
u8 *unwrapped = NULL;
|
||||
size_t unwrapped_len = 0;
|
||||
int res = -1;
|
||||
u8 flags;
|
||||
|
||||
if (!auth->reconfig || auth->configurator)
|
||||
goto fail;
|
||||
|
||||
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
|
||||
&wrapped_data_len);
|
||||
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
|
||||
dpp_auth_fail(auth,
|
||||
"Missing or invalid required Wrapped Data attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
|
||||
wrapped_data, wrapped_data_len);
|
||||
attr_len = wrapped_data - 4 - attr_start;
|
||||
|
||||
status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
|
||||
&status_len);
|
||||
if (!status || status_len < 1) {
|
||||
dpp_auth_fail(auth,
|
||||
"Missing or invalid required DPP Status attribute");
|
||||
goto fail;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
|
||||
if (status[0] != DPP_STATUS_OK) {
|
||||
dpp_auth_fail(auth,
|
||||
"Reconfiguration did not complete successfully");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
addr[0] = hdr;
|
||||
len[0] = DPP_HDR_LEN;
|
||||
addr[1] = attr_start;
|
||||
len[1] = attr_len;
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
|
||||
wrapped_data, wrapped_data_len);
|
||||
unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
|
||||
unwrapped = os_malloc(unwrapped_len);
|
||||
if (!unwrapped)
|
||||
goto fail;
|
||||
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
|
||||
wrapped_data, wrapped_data_len,
|
||||
2, addr, len, unwrapped) < 0) {
|
||||
dpp_auth_fail(auth, "AES-SIV decryption failed");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
|
||||
unwrapped, unwrapped_len);
|
||||
|
||||
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
|
||||
dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
trans_id = dpp_get_attr(unwrapped, unwrapped_len,
|
||||
DPP_ATTR_TRANSACTION_ID, &trans_id_len);
|
||||
if (!trans_id || trans_id_len != 1 ||
|
||||
trans_id[0] != auth->transaction_id) {
|
||||
dpp_auth_fail(auth,
|
||||
"Peer did not include valid Transaction ID");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
version = dpp_get_attr(unwrapped, unwrapped_len,
|
||||
DPP_ATTR_PROTOCOL_VERSION, &version_len);
|
||||
if (!version || version_len < 1 || version[0] != DPP_VERSION) {
|
||||
dpp_auth_fail(auth,
|
||||
"Missing or invalid Protocol Version attribute");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
|
||||
DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
|
||||
if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
|
||||
os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
|
||||
dpp_auth_fail(auth, "Missing or invalid C-nonce");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
|
||||
|
||||
e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
|
||||
DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
|
||||
if (!e_nonce || e_nonce_len != auth->curve->nonce_len ||
|
||||
os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
|
||||
dpp_auth_fail(auth, "Missing or invalid E-nonce");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
|
||||
|
||||
reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len,
|
||||
DPP_ATTR_RECONFIG_FLAGS,
|
||||
&reconfig_flags_len);
|
||||
if (!reconfig_flags || reconfig_flags_len < 1) {
|
||||
dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags");
|
||||
goto fail;
|
||||
}
|
||||
flags = reconfig_flags[0] & BIT(0);
|
||||
wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags);
|
||||
auth->reconfig_connector_key = flags;
|
||||
|
||||
auth->reconfig_success = true;
|
||||
res = 0;
|
||||
fail:
|
||||
bin_clear_free(unwrapped, unwrapped_len);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP2 */
|
File diff suppressed because it is too large
Load Diff
@ -1,321 +0,0 @@
|
||||
/*
|
||||
* RSN PTKSA cache implementation
|
||||
*
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "eloop.h"
|
||||
#include "common/ptksa_cache.h"
|
||||
|
||||
#define PTKSA_CACHE_MAX_ENTRIES 16
|
||||
|
||||
struct ptksa_cache {
|
||||
struct dl_list ptksa;
|
||||
unsigned int n_ptksa;
|
||||
};
|
||||
|
||||
static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa);
|
||||
|
||||
|
||||
static void ptksa_cache_free_entry(struct ptksa_cache *ptksa,
|
||||
struct ptksa_cache_entry *entry)
|
||||
{
|
||||
ptksa->n_ptksa--;
|
||||
|
||||
dl_list_del(&entry->list);
|
||||
bin_clear_free(entry, sizeof(*entry));
|
||||
}
|
||||
|
||||
|
||||
static void ptksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct ptksa_cache *ptksa = eloop_ctx;
|
||||
struct ptksa_cache_entry *e, *next;
|
||||
struct os_reltime now;
|
||||
|
||||
if (!ptksa)
|
||||
return;
|
||||
|
||||
os_get_reltime(&now);
|
||||
|
||||
dl_list_for_each_safe(e, next, &ptksa->ptksa,
|
||||
struct ptksa_cache_entry, list) {
|
||||
if (e->expiration > now.sec)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Expired PTKSA cache entry for " MACSTR,
|
||||
MAC2STR(e->addr));
|
||||
|
||||
ptksa_cache_free_entry(ptksa, e);
|
||||
}
|
||||
|
||||
ptksa_cache_set_expiration(ptksa);
|
||||
}
|
||||
|
||||
|
||||
static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa)
|
||||
{
|
||||
struct ptksa_cache_entry *e;
|
||||
int sec;
|
||||
struct os_reltime now;
|
||||
|
||||
eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
|
||||
|
||||
if (!ptksa || !ptksa->n_ptksa)
|
||||
return;
|
||||
|
||||
e = dl_list_first(&ptksa->ptksa, struct ptksa_cache_entry, list);
|
||||
if (!e)
|
||||
return;
|
||||
|
||||
os_get_reltime(&now);
|
||||
sec = e->expiration - now.sec;
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
|
||||
eloop_register_timeout(sec + 1, 0, ptksa_cache_expire, ptksa, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ptksa_cache_init - Initialize PTKSA cache
|
||||
*
|
||||
* Returns: Pointer to PTKSA cache data or %NULL on failure
|
||||
*/
|
||||
struct ptksa_cache * ptksa_cache_init(void)
|
||||
{
|
||||
struct ptksa_cache *ptksa = os_zalloc(sizeof(struct ptksa_cache));
|
||||
|
||||
wpa_printf(MSG_DEBUG, "PTKSA: Initializing");
|
||||
|
||||
if (ptksa)
|
||||
dl_list_init(&ptksa->ptksa);
|
||||
|
||||
return ptksa;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ptksa_cache_deinit - Free all entries in PTKSA cache
|
||||
* @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
|
||||
*/
|
||||
void ptksa_cache_deinit(struct ptksa_cache *ptksa)
|
||||
{
|
||||
struct ptksa_cache_entry *e, *next;
|
||||
|
||||
if (!ptksa)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "PTKSA: Deinit. n_ptksa=%u", ptksa->n_ptksa);
|
||||
|
||||
dl_list_for_each_safe(e, next, &ptksa->ptksa,
|
||||
struct ptksa_cache_entry, list)
|
||||
ptksa_cache_free_entry(ptksa, e);
|
||||
|
||||
eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
|
||||
os_free(ptksa);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ptksa_cache_get - Fetch a PTKSA cache entry
|
||||
* @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
|
||||
* @addr: Peer address or %NULL to match any
|
||||
* @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
|
||||
* Returns: Pointer to PTKSA cache entry or %NULL if no match was found
|
||||
*/
|
||||
struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
|
||||
const u8 *addr, u32 cipher)
|
||||
{
|
||||
struct ptksa_cache_entry *e;
|
||||
|
||||
if (!ptksa)
|
||||
return NULL;
|
||||
|
||||
dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
|
||||
if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
|
||||
(cipher == WPA_CIPHER_NONE || cipher == e->cipher))
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ptksa_cache_list - Dump text list of entries in PTKSA cache
|
||||
* @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
|
||||
* @buf: Buffer for the list
|
||||
* @len: Length of the buffer
|
||||
* Returns: Number of bytes written to buffer
|
||||
*
|
||||
* This function is used to generate a text format representation of the
|
||||
* current PTKSA cache contents for the ctrl_iface PTKSA command.
|
||||
*/
|
||||
int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len)
|
||||
{
|
||||
struct ptksa_cache_entry *e;
|
||||
int i = 0, ret;
|
||||
char *pos = buf;
|
||||
struct os_reltime now;
|
||||
|
||||
if (!ptksa)
|
||||
return 0;
|
||||
|
||||
os_get_reltime(&now);
|
||||
|
||||
ret = os_snprintf(pos, buf + len - pos,
|
||||
"Index / ADDR / Cipher / expiration (secs) / TK / KDK\n");
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
|
||||
ret = os_snprintf(pos, buf + len - pos, "%u " MACSTR,
|
||||
i, MAC2STR(e->addr));
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
ret = os_snprintf(pos, buf + len - pos, " %s %lu ",
|
||||
wpa_cipher_txt(e->cipher),
|
||||
e->expiration - now.sec);
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.tk,
|
||||
e->ptk.tk_len);
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
ret = os_snprintf(pos, buf + len - pos, " ");
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.kdk,
|
||||
e->ptk.kdk_len);
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
ret = os_snprintf(pos, buf + len - pos, "\n");
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ptksa_cache_flush - Flush PTKSA cache entries
|
||||
*
|
||||
* @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
|
||||
* @addr: Peer address or %NULL to match any
|
||||
* @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
|
||||
*/
|
||||
void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
|
||||
{
|
||||
struct ptksa_cache_entry *e, *next;
|
||||
bool removed = false;
|
||||
|
||||
if (!ptksa)
|
||||
return;
|
||||
|
||||
dl_list_for_each_safe(e, next, &ptksa->ptksa, struct ptksa_cache_entry,
|
||||
list) {
|
||||
if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
|
||||
(cipher == WPA_CIPHER_NONE || cipher == e->cipher)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Flush PTKSA cache entry for " MACSTR,
|
||||
MAC2STR(e->addr));
|
||||
|
||||
ptksa_cache_free_entry(ptksa, e);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
ptksa_cache_set_expiration(ptksa);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ptksa_cache_add - Add a PTKSA cache entry
|
||||
* @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
|
||||
* @addr: Peer address
|
||||
* @cipher: The cipher used
|
||||
* @life_time: The PTK life time in seconds
|
||||
* @ptk: The PTK
|
||||
* Returns: Pointer to the added PTKSA cache entry or %NULL on error
|
||||
*
|
||||
* This function creates a PTKSA entry and adds it to the PTKSA cache.
|
||||
* If an old entry is already in the cache for the same peer and cipher
|
||||
* this entry will be replaced with the new entry.
|
||||
*/
|
||||
struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
|
||||
const u8 *addr, u32 cipher,
|
||||
u32 life_time,
|
||||
const struct wpa_ptk *ptk)
|
||||
{
|
||||
struct ptksa_cache_entry *entry, *tmp;
|
||||
struct os_reltime now;
|
||||
|
||||
if (!ptksa || !ptk || !addr || !life_time || cipher == WPA_CIPHER_NONE)
|
||||
return NULL;
|
||||
|
||||
/* remove a previous entry if present */
|
||||
ptksa_cache_flush(ptksa, addr, cipher);
|
||||
|
||||
/* no place to add another entry */
|
||||
if (ptksa->n_ptksa >= PTKSA_CACHE_MAX_ENTRIES)
|
||||
return NULL;
|
||||
|
||||
entry = os_zalloc(sizeof(*entry));
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
dl_list_init(&entry->list);
|
||||
os_memcpy(entry->addr, addr, ETH_ALEN);
|
||||
entry->cipher = cipher;
|
||||
|
||||
os_memcpy(&entry->ptk, ptk, sizeof(entry->ptk));
|
||||
|
||||
os_get_reltime(&now);
|
||||
entry->expiration = now.sec + life_time;
|
||||
|
||||
dl_list_for_each(tmp, &ptksa->ptksa, struct ptksa_cache_entry, list) {
|
||||
if (tmp->expiration > entry->expiration)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the list was empty add to the head; otherwise if the expiration is
|
||||
* later then all other entries, add it to the end of the list;
|
||||
* otherwise add it before the relevant entry.
|
||||
*/
|
||||
if (!tmp)
|
||||
dl_list_add(&ptksa->ptksa, &entry->list);
|
||||
else if (tmp->expiration < entry->expiration)
|
||||
dl_list_add(&tmp->list, &entry->list);
|
||||
else
|
||||
dl_list_add_tail(&tmp->list, &entry->list);
|
||||
|
||||
ptksa->n_ptksa++;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Added PTKSA cache entry addr=" MACSTR " cipher=%u",
|
||||
MAC2STR(addr), cipher);
|
||||
|
||||
return entry;
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* RSN PTKSA cache interface
|
||||
*
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef PTKSA_CACHE_H
|
||||
#define PTKSA_CACHE_H
|
||||
|
||||
#include "wpa_common.h"
|
||||
#include "defs.h"
|
||||
#include "list.h"
|
||||
|
||||
/**
|
||||
* struct ptksa_cache_entry - PTKSA cache entry
|
||||
*/
|
||||
struct ptksa_cache_entry {
|
||||
struct dl_list list;
|
||||
struct wpa_ptk ptk;
|
||||
os_time_t expiration;
|
||||
u32 cipher;
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PTKSA_CACHE
|
||||
|
||||
struct ptksa_cache;
|
||||
|
||||
struct ptksa_cache * ptksa_cache_init(void);
|
||||
void ptksa_cache_deinit(struct ptksa_cache *ptksa);
|
||||
struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
|
||||
const u8 *addr, u32 cipher);
|
||||
int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len);
|
||||
struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
|
||||
const u8 *addr, u32 cipher,
|
||||
u32 life_time,
|
||||
const struct wpa_ptk *ptk);
|
||||
void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher);
|
||||
|
||||
#else /* CONFIG_PTKSA_CACHE */
|
||||
|
||||
static inline struct ptksa_cache * ptksa_cache_init(void)
|
||||
{
|
||||
return (struct ptksa_cache *) 1;
|
||||
}
|
||||
|
||||
static inline void ptksa_cache_deinit(struct ptksa_cache *ptksa)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct ptksa_cache_entry *
|
||||
ptksa_cache_get(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int ptksa_cache_list(struct ptksa_cache *ptksa,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline struct ptksa_cache_entry *
|
||||
ptksa_cache_add(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher,
|
||||
u32 life_time, const struct wpa_ptk *ptk)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void ptksa_cache_flush(struct ptksa_cache *ptksa,
|
||||
const u8 *addr, u32 cipher)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PTKSA_CACHE */
|
||||
#endif /* PTKSA_CACHE_H */
|
@ -1,884 +0,0 @@
|
||||
/*
|
||||
* SAE-PK
|
||||
* Copyright (c) 2020, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/base64.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_siv.h"
|
||||
#include "sae.h"
|
||||
|
||||
|
||||
/* RFC 4648 base 32 alphabet with lowercase characters */
|
||||
static const char *sae_pk_base32_table = "abcdefghijklmnopqrstuvwxyz234567";
|
||||
|
||||
|
||||
static const u8 d_mult_table[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16,
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17,
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18,
|
||||
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19,
|
||||
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4,
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20,
|
||||
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5,
|
||||
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6,
|
||||
23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22,
|
||||
8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
||||
12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||
13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
||||
29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
||||
14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
|
||||
0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
|
||||
17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
|
||||
1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
|
||||
18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
|
||||
2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
|
||||
19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
|
||||
3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
|
||||
20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
|
||||
4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
|
||||
21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
|
||||
5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
|
||||
22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23,
|
||||
6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7,
|
||||
23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24,
|
||||
7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
|
||||
24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25,
|
||||
8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9,
|
||||
25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26,
|
||||
9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,
|
||||
26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27,
|
||||
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11,
|
||||
27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28,
|
||||
11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12,
|
||||
28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29,
|
||||
12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13,
|
||||
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30,
|
||||
13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
|
||||
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31,
|
||||
14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15,
|
||||
31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
|
||||
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
};
|
||||
|
||||
static const u8 d_perm_table[] = {
|
||||
7, 2, 1, 30, 16, 20, 27, 11, 31, 6, 8, 13, 29, 5, 10, 21,
|
||||
22, 3, 24, 0, 23, 25, 12, 9, 28, 14, 4, 15, 17, 18, 19, 26
|
||||
};
|
||||
|
||||
|
||||
static u8 d_permute(u8 val, unsigned int iter)
|
||||
{
|
||||
if (iter == 0)
|
||||
return val;
|
||||
return d_permute(d_perm_table[val], iter - 1);
|
||||
}
|
||||
|
||||
|
||||
static u8 d_invert(u8 val)
|
||||
{
|
||||
if (val > 0 && val < 16)
|
||||
return 16 - val;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static char d_check_char(const char *str, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
u8 val = 0;
|
||||
u8 dtable[256];
|
||||
unsigned int iter = 1;
|
||||
int j;
|
||||
|
||||
os_memset(dtable, 0x80, 256);
|
||||
for (i = 0; sae_pk_base32_table[i]; i++)
|
||||
dtable[(u8) sae_pk_base32_table[i]] = i;
|
||||
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
u8 c, p;
|
||||
|
||||
c = dtable[(u8) str[j]];
|
||||
if (c == 0x80)
|
||||
continue;
|
||||
p = d_permute(c, iter);
|
||||
iter++;
|
||||
val = d_mult_table[val * 32 + p];
|
||||
}
|
||||
|
||||
return sae_pk_base32_table[d_invert(val)];
|
||||
}
|
||||
|
||||
|
||||
bool sae_pk_valid_password(const char *pw)
|
||||
{
|
||||
int pos;
|
||||
size_t i, pw_len = os_strlen(pw);
|
||||
u8 sec_1b;
|
||||
u8 dtable[256];
|
||||
|
||||
os_memset(dtable, 0x80, 256);
|
||||
for (i = 0; sae_pk_base32_table[i]; i++)
|
||||
dtable[(u8) sae_pk_base32_table[i]] = i;
|
||||
|
||||
/* SAE-PK password has at least three four character components
|
||||
* separated by hyphens. */
|
||||
if (pw_len < 14 || pw_len % 5 != 4) {
|
||||
wpa_printf(MSG_DEBUG, "SAE-PK: Not a valid password (length)");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (pos = 0; pw[pos]; pos++) {
|
||||
if (pos && pos % 5 == 4) {
|
||||
if (pw[pos] != '-') {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE-PK: Not a valid password (separator)");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (dtable[(u8) pw[pos]] == 0x80) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE-PK: Not a valid password (character)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that the checksum character is valid */
|
||||
if (pw[pw_len - 1] != d_check_char(pw, pw_len - 1)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE-PK: Not a valid password (checksum)");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Verify that Sec_1b bits match */
|
||||
sec_1b = dtable[(u8) pw[0]] & BIT(4);
|
||||
for (i = 5; i < pw_len; i += 5) {
|
||||
if (sec_1b != (dtable[(u8) pw[i]] & BIT(4))) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE-PK: Not a valid password (Sec_1b)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static char * add_char(const char *start, char *pos, u8 idx, size_t *bits)
|
||||
{
|
||||
if (*bits == 0)
|
||||
return pos;
|
||||
if (*bits > 5)
|
||||
*bits -= 5;
|
||||
else
|
||||
*bits = 0;
|
||||
|
||||
if ((pos - start) % 5 == 4)
|
||||
*pos++ = '-';
|
||||
*pos++ = sae_pk_base32_table[idx];
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/* Base32 encode a password and add hyper separators and checksum */
|
||||
char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
|
||||
{
|
||||
char *out, *pos;
|
||||
size_t olen, extra_pad, i;
|
||||
u64 block = 0;
|
||||
u8 val;
|
||||
size_t len = (len_bits + 7) / 8;
|
||||
size_t left = len_bits;
|
||||
int j;
|
||||
|
||||
if (len == 0 || len >= SIZE_MAX / 8)
|
||||
return NULL;
|
||||
olen = len * 8 / 5 + 1;
|
||||
olen += olen / 4; /* hyphen separators */
|
||||
pos = out = os_zalloc(olen + 2); /* include room for ChkSum and nul */
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
extra_pad = (5 - len % 5) % 5;
|
||||
for (i = 0; i < len + extra_pad; i++) {
|
||||
val = i < len ? src[i] : 0;
|
||||
block <<= 8;
|
||||
block |= val;
|
||||
if (i % 5 == 4) {
|
||||
for (j = 7; j >= 0; j--)
|
||||
pos = add_char(out, pos,
|
||||
(block >> j * 5) & 0x1f, &left);
|
||||
block = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*pos = d_check_char(out, os_strlen(out));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len)
|
||||
{
|
||||
u8 dtable[256], *out, *pos, tmp;
|
||||
u64 block = 0;
|
||||
size_t i, count, olen;
|
||||
int pad = 0;
|
||||
size_t extra_pad;
|
||||
|
||||
os_memset(dtable, 0x80, 256);
|
||||
for (i = 0; sae_pk_base32_table[i]; i++)
|
||||
dtable[(u8) sae_pk_base32_table[i]] = i;
|
||||
dtable['='] = 0;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (dtable[(u8) src[i]] != 0x80)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
extra_pad = (8 - count % 8) % 8;
|
||||
|
||||
olen = (count + extra_pad) / 8 * 5;
|
||||
pos = out = os_malloc(olen);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len + extra_pad; i++) {
|
||||
u8 val;
|
||||
|
||||
if (i >= len)
|
||||
val = '=';
|
||||
else
|
||||
val = src[i];
|
||||
tmp = dtable[val];
|
||||
if (tmp == 0x80)
|
||||
continue;
|
||||
|
||||
if (val == '=')
|
||||
pad++;
|
||||
block <<= 5;
|
||||
block |= tmp;
|
||||
count++;
|
||||
if (count == 8) {
|
||||
*pos++ = (block >> 32) & 0xff;
|
||||
*pos++ = (block >> 24) & 0xff;
|
||||
*pos++ = (block >> 16) & 0xff;
|
||||
*pos++ = (block >> 8) & 0xff;
|
||||
*pos++ = block & 0xff;
|
||||
count = 0;
|
||||
block = 0;
|
||||
if (pad) {
|
||||
/* Leave in all the available bits with zero
|
||||
* padding to full octets from right. */
|
||||
pos -= pad * 5 / 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out_len = pos - out;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
u32 sae_pk_get_be19(const u8 *buf)
|
||||
{
|
||||
return (buf[0] << 11) | (buf[1] << 3) | (buf[2] >> 5);
|
||||
}
|
||||
|
||||
|
||||
/* shift left by two octets and three bits; fill in zeros from right;
|
||||
* len must be at least three */
|
||||
void sae_pk_buf_shift_left_19(u8 *buf, size_t len)
|
||||
{
|
||||
u8 *dst, *src, *end;
|
||||
|
||||
dst = buf;
|
||||
src = buf + 2;
|
||||
end = buf + len;
|
||||
|
||||
while (src + 1 < end) {
|
||||
*dst++ = (src[0] << 3) | (src[1] >> 5);
|
||||
src++;
|
||||
}
|
||||
*dst++ = *src << 3;
|
||||
*dst++ = 0;
|
||||
*dst++ = 0;
|
||||
}
|
||||
|
||||
|
||||
static void sae_pk_buf_shift_left_1(u8 *buf, size_t len)
|
||||
{
|
||||
u8 *dst, *src, *end;
|
||||
|
||||
dst = buf;
|
||||
src = buf;
|
||||
end = buf + len;
|
||||
|
||||
while (src + 1 < end) {
|
||||
*dst++ = (src[0] << 1) | (src[1] >> 7);
|
||||
src++;
|
||||
}
|
||||
*dst++ = *src << 1;
|
||||
}
|
||||
|
||||
|
||||
int sae_pk_set_password(struct sae_data *sae, const char *password)
|
||||
{
|
||||
struct sae_temporary_data *tmp = sae->tmp;
|
||||
size_t len, pw_len;
|
||||
u8 *pw, *pos;
|
||||
int bits;
|
||||
u32 val = 0, val19;
|
||||
unsigned int val_bits = 0;
|
||||
|
||||
if (!tmp)
|
||||
return -1;
|
||||
|
||||
os_memset(tmp->fingerprint, 0, sizeof(tmp->fingerprint));
|
||||
tmp->fingerprint_bytes = tmp->fingerprint_bits = 0;
|
||||
|
||||
len = os_strlen(password);
|
||||
if (len < 1 || !sae_pk_valid_password(password))
|
||||
return -1;
|
||||
|
||||
pw = sae_pk_base32_decode(password, len, &pw_len);
|
||||
if (!pw)
|
||||
return -1;
|
||||
|
||||
tmp->sec = (pw[0] & BIT(7)) ? 3 : 5;
|
||||
tmp->lambda = len - len / 5;
|
||||
tmp->fingerprint_bits = 8 * tmp->sec + 19 * tmp->lambda / 4 - 5;
|
||||
wpa_printf(MSG_DEBUG, "SAE-PK: Sec=%u Lambda=%zu fingerprint_bits=%zu",
|
||||
tmp->sec, tmp->lambda, tmp->fingerprint_bits);
|
||||
|
||||
/* Construct Fingerprint from PasswordBase by prefixing with Sec zero
|
||||
* octets and skipping the Sec_1b bits */
|
||||
pos = &tmp->fingerprint[tmp->sec];
|
||||
bits = tmp->fingerprint_bits - 8 * tmp->sec;
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE-PK: PasswordBase", pw, pw_len);
|
||||
while (bits > 0) {
|
||||
if (val_bits < 8) {
|
||||
sae_pk_buf_shift_left_1(pw, pw_len); /* Sec_1b */
|
||||
val19 = sae_pk_get_be19(pw);
|
||||
sae_pk_buf_shift_left_19(pw, pw_len);
|
||||
val = (val << 19) | val19;
|
||||
val_bits += 19;
|
||||
}
|
||||
if (val_bits >= 8) {
|
||||
if (bits < 8)
|
||||
break;
|
||||
*pos++ = (val >> (val_bits - 8)) & 0xff;
|
||||
val_bits -= 8;
|
||||
bits -= 8;
|
||||
}
|
||||
}
|
||||
if (bits > 0) {
|
||||
val >>= val_bits - bits;
|
||||
*pos++ = val << (8 - bits);
|
||||
}
|
||||
tmp->fingerprint_bytes = pos - tmp->fingerprint;
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Fingerprint",
|
||||
tmp->fingerprint, tmp->fingerprint_bytes);
|
||||
bin_clear_free(pw, pw_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t sae_group_2_hash_len(int group)
|
||||
{
|
||||
switch (group) {
|
||||
case 19:
|
||||
return 32;
|
||||
case 20:
|
||||
return 48;
|
||||
case 21:
|
||||
return 64;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sae_deinit_pk(struct sae_pk *pk)
|
||||
{
|
||||
if (pk) {
|
||||
wpabuf_free(pk->m);
|
||||
crypto_ec_key_deinit(pk->key);
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
crypto_ec_key_deinit(pk->sign_key_override);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
wpabuf_free(pk->pubkey);
|
||||
os_free(pk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct sae_pk * sae_parse_pk(const char *val)
|
||||
{
|
||||
struct sae_pk *pk;
|
||||
const char *pos;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
const char *pos2;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
size_t len;
|
||||
unsigned char *der;
|
||||
size_t der_len, b_len;
|
||||
|
||||
/* <m-as-hexdump>:<base64-encoded-DER-encoded-key> */
|
||||
|
||||
pos = os_strchr(val, ':');
|
||||
if (!pos || (pos - val) & 0x01)
|
||||
return NULL;
|
||||
len = (pos - val) / 2;
|
||||
if (len != SAE_PK_M_LEN) {
|
||||
wpa_printf(MSG_INFO, "SAE: Unexpected Modifier M length %zu",
|
||||
len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pk = os_zalloc(sizeof(*pk));
|
||||
if (!pk)
|
||||
return NULL;
|
||||
pk->m = wpabuf_alloc(len);
|
||||
if (!pk->m || hexstr2bin(val, wpabuf_put(pk->m, len), len)) {
|
||||
wpa_printf(MSG_INFO, "SAE: Failed to parse m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pos++;
|
||||
b_len = os_strlen(pos);
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
pos2 = os_strchr(pos, ':');
|
||||
if (pos2) {
|
||||
b_len = pos2 - pos;
|
||||
pos2++;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
der = base64_decode(pos, b_len, &der_len);
|
||||
if (!der) {
|
||||
wpa_printf(MSG_INFO, "SAE: Failed to base64 decode PK key");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pk->key = crypto_ec_key_parse_priv(der, der_len);
|
||||
bin_clear_free(der, der_len);
|
||||
if (!pk->key)
|
||||
goto fail;
|
||||
pk->group = crypto_ec_key_group(pk->key);
|
||||
pk->pubkey = crypto_ec_key_get_subject_public_key(pk->key);
|
||||
if (!pk->pubkey)
|
||||
goto fail;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (pos2) {
|
||||
der = base64_decode(pos2, os_strlen(pos2), &der_len);
|
||||
if (!der) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE: Failed to base64 decode PK key");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pk->sign_key_override = crypto_ec_key_parse_priv(der, der_len);
|
||||
bin_clear_free(der, der_len);
|
||||
if (!pk->sign_key_override)
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
return pk;
|
||||
fail:
|
||||
sae_deinit_pk(pk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash)
|
||||
{
|
||||
if (hash_len == 32)
|
||||
return sha256_vector(1, &data, &len, hash);
|
||||
#ifdef CONFIG_SHA384
|
||||
if (hash_len == 48)
|
||||
return sha384_vector(1, &data, &len, hash);
|
||||
#endif /* CONFIG_SHA384 */
|
||||
#ifdef CONFIG_SHA512
|
||||
if (hash_len == 64)
|
||||
return sha512_vector(1, &data, &len, hash);
|
||||
#endif /* CONFIG_SHA512 */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int sae_pk_hash_sig_data(struct sae_data *sae, size_t hash_len,
|
||||
bool ap, const u8 *m, size_t m_len,
|
||||
const u8 *pubkey, size_t pubkey_len, u8 *hash)
|
||||
{
|
||||
struct sae_temporary_data *tmp = sae->tmp;
|
||||
struct wpabuf *sig_data;
|
||||
u8 *pos;
|
||||
int ret = -1;
|
||||
|
||||
/* Signed data for KeyAuth: eleAP || eleSTA || scaAP || scaSTA ||
|
||||
* M || K_AP || AP-BSSID || STA-MAC */
|
||||
sig_data = wpabuf_alloc(tmp->prime_len * 6 + m_len + pubkey_len +
|
||||
2 * ETH_ALEN);
|
||||
if (!sig_data)
|
||||
goto fail;
|
||||
pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
|
||||
if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->own_commit_element_ecc :
|
||||
tmp->peer_commit_element_ecc,
|
||||
pos, pos + tmp->prime_len) < 0)
|
||||
goto fail;
|
||||
pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
|
||||
if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->peer_commit_element_ecc :
|
||||
tmp->own_commit_element_ecc,
|
||||
pos, pos + tmp->prime_len) < 0)
|
||||
goto fail;
|
||||
if (crypto_bignum_to_bin(ap ? tmp->own_commit_scalar :
|
||||
sae->peer_commit_scalar,
|
||||
wpabuf_put(sig_data, tmp->prime_len),
|
||||
tmp->prime_len, tmp->prime_len) < 0 ||
|
||||
crypto_bignum_to_bin(ap ? sae->peer_commit_scalar :
|
||||
tmp->own_commit_scalar,
|
||||
wpabuf_put(sig_data, tmp->prime_len),
|
||||
tmp->prime_len, tmp->prime_len) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(sig_data, m, m_len);
|
||||
wpabuf_put_data(sig_data, pubkey, pubkey_len);
|
||||
wpabuf_put_data(sig_data, ap ? tmp->own_addr : tmp->peer_addr,
|
||||
ETH_ALEN);
|
||||
wpabuf_put_data(sig_data, ap ? tmp->peer_addr : tmp->own_addr,
|
||||
ETH_ALEN);
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "SAE-PK: Data to be signed for KeyAuth",
|
||||
sig_data);
|
||||
if (sae_hash(hash_len, wpabuf_head(sig_data), wpabuf_len(sig_data),
|
||||
hash) < 0)
|
||||
goto fail;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: hash(data to be signed)",
|
||||
hash, hash_len);
|
||||
ret = 0;
|
||||
fail:
|
||||
wpabuf_free(sig_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
|
||||
{
|
||||
struct sae_temporary_data *tmp = sae->tmp;
|
||||
struct wpabuf *sig = NULL;
|
||||
size_t need;
|
||||
int ret = -1;
|
||||
u8 *encr_mod;
|
||||
size_t encr_mod_len;
|
||||
const struct sae_pk *pk;
|
||||
u8 hash[SAE_MAX_HASH_LEN];
|
||||
size_t hash_len;
|
||||
struct crypto_ec_key *key;
|
||||
|
||||
if (!tmp)
|
||||
return -1;
|
||||
|
||||
pk = tmp->ap_pk;
|
||||
if (!sae->pk || !pk)
|
||||
return 0;
|
||||
|
||||
key = pk->key;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (tmp->omit_pk_elem)
|
||||
return 0;
|
||||
if (pk->sign_key_override) {
|
||||
wpa_printf(MSG_INFO, "TESTING: Override SAE-PK signing key");
|
||||
key = pk->sign_key_override;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: No KEK available for writing confirm");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!tmp->ec) {
|
||||
/* Only ECC groups are supported for SAE-PK in the current
|
||||
* implementation. */
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: SAE commit did not use an ECC group");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hash_len = sae_group_2_hash_len(pk->group);
|
||||
if (sae_pk_hash_sig_data(sae, hash_len, true, wpabuf_head(pk->m),
|
||||
wpabuf_len(pk->m), wpabuf_head(pk->pubkey),
|
||||
wpabuf_len(pk->pubkey), hash) < 0)
|
||||
goto fail;
|
||||
sig = crypto_ec_key_sign(key, hash, hash_len);
|
||||
if (!sig)
|
||||
goto fail;
|
||||
wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
|
||||
|
||||
/* TODO: fragmentation if any of the elements needs it for a group
|
||||
* using sufficiently large primes (none of the currently supported
|
||||
* ones do) */
|
||||
|
||||
encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
|
||||
need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
|
||||
6 + encr_mod_len;
|
||||
if (wpabuf_tailroom(buf) < need) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: No room in message buffer for SAE-PK elements (%zu < %zu)",
|
||||
wpabuf_tailroom(buf), need);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* FILS Public Key element */
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(buf, 2 + wpabuf_len(pk->pubkey));
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_PUBLIC_KEY);
|
||||
wpabuf_put_u8(buf, 2); /* Key Type: ECDSA public key */
|
||||
wpabuf_put_buf(buf, pk->pubkey);
|
||||
|
||||
/* FILS Key Confirmation element (KeyAuth) */
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(buf, 1 + wpabuf_len(sig));
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
|
||||
/* KeyAuth = Sig_AP(eleAP || eleSTA || scaAP || scaSTA || M || K_AP ||
|
||||
* AP-BSSID || STA-MAC) */
|
||||
wpabuf_put_buf(buf, sig);
|
||||
|
||||
/* SAE-PK element */
|
||||
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(buf, 4 + encr_mod_len);
|
||||
wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
|
||||
/* EncryptedModifier = AES-SIV-Q(M); no AAD */
|
||||
encr_mod = wpabuf_put(buf, encr_mod_len);
|
||||
if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
|
||||
wpabuf_head(pk->m), wpabuf_len(pk->m),
|
||||
0, NULL, NULL, encr_mod) < 0)
|
||||
goto fail;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
|
||||
encr_mod, encr_mod_len);
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
wpabuf_free(sig);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static bool sae_pk_valid_fingerprint(struct sae_data *sae,
|
||||
const u8 *m, size_t m_len,
|
||||
const u8 *k_ap, size_t k_ap_len, int group)
|
||||
{
|
||||
struct sae_temporary_data *tmp = sae->tmp;
|
||||
u8 *hash_data, *pos;
|
||||
size_t hash_len, hash_data_len;
|
||||
u8 hash[SAE_MAX_HASH_LEN];
|
||||
int res;
|
||||
|
||||
if (!tmp->fingerprint_bytes) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE-PK: No PW available for K_AP fingerprint check");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Fingerprint = L(Hash(SSID || M || K_AP), 0, 8*Sec + 19*Lambda/4 - 5)
|
||||
*/
|
||||
|
||||
hash_len = sae_group_2_hash_len(group);
|
||||
hash_data_len = tmp->ssid_len + m_len + k_ap_len;
|
||||
hash_data = os_malloc(hash_data_len);
|
||||
if (!hash_data)
|
||||
return false;
|
||||
pos = hash_data;
|
||||
os_memcpy(pos, tmp->ssid, tmp->ssid_len);
|
||||
pos += tmp->ssid_len;
|
||||
os_memcpy(pos, m, m_len);
|
||||
pos += m_len;
|
||||
os_memcpy(pos, k_ap, k_ap_len);
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE-PK: SSID || M || K_AP",
|
||||
hash_data, hash_data_len);
|
||||
res = sae_hash(hash_len, hash_data, hash_data_len, hash);
|
||||
bin_clear_free(hash_data, hash_data_len);
|
||||
if (res < 0)
|
||||
return false;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: Hash(SSID || M || K_AP)",
|
||||
hash, hash_len);
|
||||
|
||||
if (tmp->fingerprint_bits > hash_len * 8) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: Not enough hash output bits for the fingerprint");
|
||||
return false;
|
||||
}
|
||||
if (tmp->fingerprint_bits % 8) {
|
||||
size_t extra;
|
||||
|
||||
/* Zero out the extra bits in the last octet */
|
||||
extra = 8 - tmp->fingerprint_bits % 8;
|
||||
pos = &hash[tmp->fingerprint_bits / 8];
|
||||
*pos = (*pos >> extra) << extra;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint", hash,
|
||||
tmp->fingerprint_bytes);
|
||||
res = os_memcmp_const(hash, tmp->fingerprint, tmp->fingerprint_bytes);
|
||||
if (res) {
|
||||
wpa_printf(MSG_DEBUG, "SAE-PK: K_AP fingerprint mismatch");
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: Expected fingerprint",
|
||||
tmp->fingerprint, tmp->fingerprint_bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE-PK: Valid K_AP fingerprint");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
|
||||
{
|
||||
struct sae_temporary_data *tmp = sae->tmp;
|
||||
const u8 *k_ap;
|
||||
u8 m[SAE_PK_M_LEN];
|
||||
size_t k_ap_len;
|
||||
struct crypto_ec_key *key;
|
||||
int res;
|
||||
u8 hash[SAE_MAX_HASH_LEN];
|
||||
size_t hash_len;
|
||||
int group;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
if (!tmp)
|
||||
return -1;
|
||||
if (!sae->pk || tmp->ap_pk)
|
||||
return 0;
|
||||
|
||||
if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: No KEK available for checking confirm");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!tmp->ec) {
|
||||
/* Only ECC groups are supported for SAE-PK in the current
|
||||
* implementation. */
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: SAE commit did not use an ECC group");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
|
||||
if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
|
||||
wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
|
||||
return -1;
|
||||
}
|
||||
if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: Not all mandatory IEs included in confirm");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: Fragment reassembly */
|
||||
|
||||
if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: No room for EncryptedModifier in SAE-PK element");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
|
||||
elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
|
||||
|
||||
if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
|
||||
elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE,
|
||||
0, NULL, NULL, m) < 0) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: Failed to decrypt EncryptedModifier");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN);
|
||||
|
||||
if (elems.fils_pk[0] != 2) {
|
||||
wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
|
||||
elems.fils_pk[0]);
|
||||
return -1;
|
||||
}
|
||||
k_ap_len = elems.fils_pk_len - 1;
|
||||
k_ap = elems.fils_pk + 1;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: Received K_AP", k_ap, k_ap_len);
|
||||
/* TODO: Check against the public key, if one is stored in the network
|
||||
* profile */
|
||||
|
||||
key = crypto_ec_key_parse_pub(k_ap, k_ap_len);
|
||||
if (!key) {
|
||||
wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP");
|
||||
return -1;
|
||||
}
|
||||
|
||||
group = crypto_ec_key_group(key);
|
||||
if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len,
|
||||
group)) {
|
||||
crypto_ec_key_deinit(key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth",
|
||||
elems.fils_key_confirm, elems.fils_key_confirm_len);
|
||||
|
||||
hash_len = sae_group_2_hash_len(group);
|
||||
if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN,
|
||||
k_ap, k_ap_len, hash) < 0) {
|
||||
crypto_ec_key_deinit(key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = crypto_ec_key_verify_signature(key, hash, hash_len,
|
||||
elems.fils_key_confirm,
|
||||
elems.fils_key_confirm_len);
|
||||
crypto_ec_key_deinit(key);
|
||||
|
||||
if (res != 1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"SAE-PK: Invalid or incorrect signature in KeyAuth");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE-PK: Valid KeyAuth signature received");
|
||||
|
||||
/* TODO: Store validated public key into network profile */
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* TLS PRF P_SHA384
|
||||
* Copyright (c) 2011-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "sha384.h"
|
||||
|
||||
|
||||
/**
|
||||
* tls_prf_sha384 - Pseudo-Random Function for TLS v1.2 (P_SHA384, RFC 5246)
|
||||
* @secret: Key for PRF
|
||||
* @secret_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the PRF
|
||||
* @seed: Seed value to bind into the key
|
||||
* @seed_len: Length of the seed
|
||||
* @out: Buffer for the generated pseudo-random key
|
||||
* @outlen: Number of bytes of key to generate
|
||||
* Returns: 0 on success, -1 on failure.
|
||||
*
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key in TLS. This PRF is defined in RFC 5246, Chapter 5.
|
||||
*/
|
||||
int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
|
||||
{
|
||||
size_t clen;
|
||||
u8 A[SHA384_MAC_LEN];
|
||||
u8 P[SHA384_MAC_LEN];
|
||||
size_t pos;
|
||||
const unsigned char *addr[3];
|
||||
size_t len[3];
|
||||
|
||||
addr[0] = A;
|
||||
len[0] = SHA384_MAC_LEN;
|
||||
addr[1] = (unsigned char *) label;
|
||||
len[1] = os_strlen(label);
|
||||
addr[2] = seed;
|
||||
len[2] = seed_len;
|
||||
|
||||
/*
|
||||
* RFC 5246, Chapter 5
|
||||
* A(0) = seed, A(i) = HMAC(secret, A(i-1))
|
||||
* P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
|
||||
* PRF(secret, label, seed) = P_SHA384(secret, label + seed)
|
||||
*/
|
||||
|
||||
if (hmac_sha384_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
|
||||
return -1;
|
||||
|
||||
pos = 0;
|
||||
while (pos < outlen) {
|
||||
if (hmac_sha384_vector(secret, secret_len, 3, addr, len, P) <
|
||||
0 ||
|
||||
hmac_sha384(secret, secret_len, A, SHA384_MAC_LEN, A) < 0)
|
||||
return -1;
|
||||
|
||||
clen = outlen - pos;
|
||||
if (clen > SHA384_MAC_LEN)
|
||||
clen = SHA384_MAC_LEN;
|
||||
os_memcpy(out + pos, P, clen);
|
||||
pos += clen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
1
contrib/wpa/src/eap_peer/.gitignore
vendored
1
contrib/wpa/src/eap_peer/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.so
|
@ -1,3 +0,0 @@
|
||||
$(_OBJS_VAR) := $(call BUILDOBJ,$($(_OBJS_VAR)))
|
||||
-include $(filter-out %.a,$($(_OBJS_VAR):%.o=%.d))
|
||||
_DIRS += $(dir $($(_OBJS_VAR)))
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Configuration parsing
|
||||
* Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "utils/config.h"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
static int newline_terminated(const char *buf, size_t buflen)
|
||||
{
|
||||
size_t len = os_strlen(buf);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
|
||||
buf[len - 1] != '\n')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void skip_line_end(FILE *stream)
|
||||
{
|
||||
char buf[100];
|
||||
while (fgets(buf, sizeof(buf), stream)) {
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (newline_terminated(buf, sizeof(buf)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
|
||||
char **_pos)
|
||||
{
|
||||
char *pos, *end, *sstart;
|
||||
|
||||
while (fgets(s, size, stream)) {
|
||||
(*line)++;
|
||||
s[size - 1] = '\0';
|
||||
if (!newline_terminated(s, size)) {
|
||||
/*
|
||||
* The line was truncated - skip rest of it to avoid
|
||||
* confusing error messages.
|
||||
*/
|
||||
wpa_printf(MSG_INFO, "Long line in configuration file "
|
||||
"truncated");
|
||||
skip_line_end(stream);
|
||||
}
|
||||
pos = s;
|
||||
|
||||
/* Skip white space from the beginning of line. */
|
||||
while (*pos == ' ' || *pos == '\t' || *pos == '\r')
|
||||
pos++;
|
||||
|
||||
/* Skip comment lines and empty lines */
|
||||
if (*pos == '#' || *pos == '\n' || *pos == '\0')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Remove # comments unless they are within a double quoted
|
||||
* string.
|
||||
*/
|
||||
sstart = os_strchr(pos, '"');
|
||||
if (sstart)
|
||||
sstart = os_strrchr(sstart + 1, '"');
|
||||
if (!sstart)
|
||||
sstart = pos;
|
||||
end = os_strchr(sstart, '#');
|
||||
if (end)
|
||||
*end-- = '\0';
|
||||
else
|
||||
end = pos + os_strlen(pos) - 1;
|
||||
|
||||
/* Remove trailing white space. */
|
||||
while (end > pos &&
|
||||
(*end == '\n' || *end == ' ' || *end == '\t' ||
|
||||
*end == '\r'))
|
||||
*end-- = '\0';
|
||||
|
||||
if (*pos == '\0')
|
||||
continue;
|
||||
|
||||
if (_pos)
|
||||
*_pos = pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
if (_pos)
|
||||
*_pos = NULL;
|
||||
return NULL;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Configuration parsing
|
||||
* Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_CONFIG_H
|
||||
#define UTILS_CONFIG_H
|
||||
|
||||
/**
|
||||
* wpa_config_get_line - Read the next configuration file line
|
||||
* @s: Buffer for the line
|
||||
* @size: The buffer length
|
||||
* @stream: File stream to read from
|
||||
* @line: Pointer to a variable storing the file line number
|
||||
* @_pos: Buffer for the pointer to the beginning of data on the text line or
|
||||
* %NULL if not needed (returned value used instead)
|
||||
* Returns: Pointer to the beginning of data on the text line or %NULL if no
|
||||
* more text lines are available.
|
||||
*
|
||||
* This function reads the next non-empty line from the configuration file and
|
||||
* removes comments. The returned string is guaranteed to be null-terminated.
|
||||
*/
|
||||
char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
|
||||
char **_pos);
|
||||
|
||||
#endif /* UTILS_CONFIG_H */
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* External backend for file-backed passwords
|
||||
* Copyright (c) 2021, Patrick Steinhardt <ps@pks.im>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/config.h"
|
||||
#include "ext_password_i.h"
|
||||
|
||||
|
||||
/**
|
||||
* Data structure for the file-backed password backend.
|
||||
*/
|
||||
struct ext_password_file_data {
|
||||
char *path; /* path of the password file */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ext_password_file_init - Initialize file-backed password backend
|
||||
* @params: Parameters passed by the user.
|
||||
* Returns: Pointer to the initialized backend.
|
||||
*
|
||||
* This function initializes a new file-backed password backend. The user is
|
||||
* expected to initialize this backend with the parameters being the path of
|
||||
* the file that contains the passwords.
|
||||
*/
|
||||
static void * ext_password_file_init(const char *params)
|
||||
{
|
||||
struct ext_password_file_data *data;
|
||||
|
||||
if (!params) {
|
||||
wpa_printf(MSG_ERROR, "EXT PW FILE: no path given");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
data->path = os_strdup(params);
|
||||
if (!data->path) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ext_password_file_deinit - Deinitialize file-backed password backend
|
||||
* @ctx: The file-backed password backend
|
||||
*
|
||||
* This function frees all data associated with the file-backed password
|
||||
* backend.
|
||||
*/
|
||||
static void ext_password_file_deinit(void *ctx)
|
||||
{
|
||||
struct ext_password_file_data *data = ctx;
|
||||
|
||||
str_clear_free(data->path);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* ext_password_file_get - Retrieve password from the file-backed password backend
|
||||
* @ctx: The file-backed password backend
|
||||
* @name: Name of the password to retrieve
|
||||
* Returns: Buffer containing the password if one was found or %NULL.
|
||||
*
|
||||
* This function tries to find a password identified by name in the password
|
||||
* file. The password is expected to be stored in `NAME=PASSWORD` format.
|
||||
* Comments and empty lines in the file are ignored. Invalid lines will cause
|
||||
* an error message, but will not cause the function to fail.
|
||||
*/
|
||||
static struct wpabuf * ext_password_file_get(void *ctx, const char *name)
|
||||
{
|
||||
struct ext_password_file_data *data = ctx;
|
||||
struct wpabuf *password = NULL;
|
||||
char buf[512], *pos;
|
||||
int line = 0;
|
||||
FILE *f;
|
||||
|
||||
f = fopen(data->path, "r");
|
||||
if (!f) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"EXT PW FILE: could not open file '%s': %s",
|
||||
data->path, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
|
||||
|
||||
while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
|
||||
char *sep = os_strchr(pos, '=');
|
||||
|
||||
if (!sep) {
|
||||
wpa_printf(MSG_ERROR, "Invalid password line %d.",
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sep[1]) {
|
||||
wpa_printf(MSG_ERROR, "No password for line %d.", line);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (os_strncmp(name, pos, sep - pos) != 0)
|
||||
continue;
|
||||
|
||||
password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
|
||||
goto done;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_ERROR, "Password for '%s' was not found.", name);
|
||||
|
||||
done:
|
||||
forced_memzero(buf, sizeof(buf));
|
||||
fclose(f);
|
||||
return password;
|
||||
}
|
||||
|
||||
|
||||
const struct ext_password_backend ext_password_file = {
|
||||
.name = "file",
|
||||
.init = ext_password_file_init,
|
||||
.deinit = ext_password_file_deinit,
|
||||
.get = ext_password_file_get,
|
||||
};
|
3
contrib/wpa/tests/.gitignore
vendored
3
contrib/wpa/tests/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
test-*
|
||||
!test-*.[ch]
|
||||
!test-*.sh
|
@ -1,99 +0,0 @@
|
||||
ALL=test-base64 test-md4 test-milenage \
|
||||
test-rsa-sig-ver \
|
||||
test-sha1 \
|
||||
test-https test-https_server \
|
||||
test-sha256 test-aes test-x509v3 test-list test-rc4
|
||||
|
||||
include ../src/build.rules
|
||||
|
||||
ifdef LIBFUZZER
|
||||
CC=clang
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
CFLAGS += -fsanitize=fuzzer,address,signed-integer-overflow,unsigned-integer-overflow
|
||||
CFLAGS += -DTEST_LIBFUZZER
|
||||
LDFLAGS += -fsanitize=fuzzer,address,signed-integer-overflow,unsigned-integer-overflow
|
||||
TEST_FUZZ=y
|
||||
endif
|
||||
|
||||
ifdef TEST_FUZZ
|
||||
CFLAGS += -DCONFIG_NO_RANDOM_POOL
|
||||
CFLAGS += -DTEST_FUZZ
|
||||
endif
|
||||
|
||||
CFLAGS += -DCONFIG_IEEE80211R_AP
|
||||
CFLAGS += -DCONFIG_IEEE80211R
|
||||
CFLAGS += -DCONFIG_TDLS
|
||||
|
||||
CFLAGS += -I../src
|
||||
CFLAGS += -I../src/utils
|
||||
|
||||
SLIBS = ../src/utils/libutils.a
|
||||
|
||||
DLIBS = ../src/crypto/libcrypto.a \
|
||||
../src/tls/libtls.a
|
||||
|
||||
_OBJS_VAR := LLIBS
|
||||
include ../src/objs.mk
|
||||
_OBJS_VAR := SLIBS
|
||||
include ../src/objs.mk
|
||||
_OBJS_VAR := DLIBS
|
||||
include ../src/objs.mk
|
||||
|
||||
LIBS = $(SLIBS) $(DLIBS)
|
||||
LLIBS = -Wl,--start-group $(DLIBS) -Wl,--end-group $(SLIBS)
|
||||
|
||||
# glibc < 2.17 needs -lrt for clock_gettime()
|
||||
LLIBS += -lrt
|
||||
|
||||
test-aes: $(call BUILDOBJ,test-aes.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-base64: $(call BUILDOBJ,test-base64.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-https: $(call BUILDOBJ,test-https.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
|
||||
|
||||
test-https_server: $(call BUILDOBJ,test-https_server.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
|
||||
|
||||
test-list: $(call BUILDOBJ,test-list.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-md4: $(call BUILDOBJ,test-md4.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-milenage: $(call BUILDOBJ,test-milenage.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-rc4: $(call BUILDOBJ,test-rc4.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-rsa-sig-ver: $(call BUILDOBJ,test-rsa-sig-ver.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
|
||||
|
||||
test-sha1: $(call BUILDOBJ,test-sha1.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-sha256: $(call BUILDOBJ,test-sha256.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
|
||||
|
||||
test-x509v3: $(call BUILDOBJ,test-x509v3.o) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $< $(LLIBS)
|
||||
|
||||
|
||||
run-tests: $(ALL)
|
||||
./test-aes
|
||||
./test-list
|
||||
./test-md4
|
||||
./test-milenage
|
||||
./test-rsa-sig-ver
|
||||
./test-sha1
|
||||
./test-sha256
|
||||
@echo
|
||||
@echo All tests completed successfully.
|
||||
|
||||
clean: common-clean
|
||||
rm -f *~
|
||||
rm -f test_x509v3_nist.out.*
|
||||
rm -f test_x509v3_nist2.out.*
|
@ -1,123 +0,0 @@
|
||||
hostap.git test tools
|
||||
---------------------
|
||||
|
||||
The tests directory with its subdirectories contain number of tools used
|
||||
for testing wpa_supplicant and hostapd implementations.
|
||||
|
||||
hwsim directory contains the test setup for full system testing of
|
||||
wpa_supplicant and hostapd with a simulated radio (mac80211_hwsim). See
|
||||
hwsim/READM and hwsim/vm/README for more details.
|
||||
|
||||
|
||||
Build testing
|
||||
-------------
|
||||
|
||||
wpa_supplicant and hostapd support number of build option
|
||||
combinations. The test scripts in the build subdirectory can be used to
|
||||
verify that various combinations do not break the builds. More
|
||||
configuration examples can be added there
|
||||
(build-{hostapd,wpa_supplicant}-*.config) to get them included in test
|
||||
builds.
|
||||
|
||||
# Example
|
||||
cd build
|
||||
./run-build-tests.h
|
||||
|
||||
|
||||
Fuzz testing
|
||||
------------
|
||||
|
||||
Newer fuzz testing tools are under the fuzzing directory. See
|
||||
fuzzing/README for more details on them. The following text describes
|
||||
the older fuzz testing tools that are subject to removal once the same
|
||||
newer tools have the same coverage available.
|
||||
|
||||
Number of the test tools here can be used for fuzz testing with tools
|
||||
like American fuzzy lop (afl-fuzz) that are designed to modify an
|
||||
external file for program input. ap-mgmt-fuzzer, eapol-fuzzer,
|
||||
test-eapol, test-json, test-tls, and test-x509 are examples of such
|
||||
tools that expose hostap.git module functionality with input from a file
|
||||
specified on the command line.
|
||||
|
||||
Here are some examples of how fuzzing can be performed:
|
||||
|
||||
##### JSON parser
|
||||
make clean
|
||||
CC=afl-gcc make test-json
|
||||
mkdir json-examples
|
||||
cat > json-examples/1.json <<EOF
|
||||
{"a":[[]],"b":1,"c":"q","d":{"e":[{}]}}
|
||||
EOF
|
||||
afl-fuzz -i json-examples -o json-findings -- $PWD/test-json @@
|
||||
|
||||
Alternatively, using libFuzzer from LLVM:
|
||||
make clean
|
||||
make test-json LIBFUZZER=y
|
||||
mkdir json-examples
|
||||
cat > json-examples/1.json <<EOF
|
||||
{"a":[[]],"b":1,"c":"q","d":{"e":[{}]}}
|
||||
EOF
|
||||
./test-json json-examples
|
||||
|
||||
##### EAPOL-Key Supplicant
|
||||
make clean
|
||||
CC=afl-gcc make test-eapol TEST_FUZZ=y
|
||||
mkdir eapol-auth-examples
|
||||
./test-eapol auth write eapol-auth-examples/auth.msg
|
||||
afl-fuzz -i eapol-auth-examples -o eapol-auth-findings -- $PWD/test-eapol auth read @@
|
||||
|
||||
##### EAPOL-Key Authenticator
|
||||
make clean
|
||||
CC=afl-gcc make test-eapol TEST_FUZZ=y
|
||||
mkdir eapol-supp-examples
|
||||
./test-eapol supp write eapol-supp-examples/supp.msg
|
||||
afl-fuzz -i eapol-supp-examples -o eapol-supp-findings -- $PWD/test-eapol supp read @@
|
||||
|
||||
##### TLS client
|
||||
make clean
|
||||
CC=afl-gcc make test-tls TEST_FUZZ=y
|
||||
mkdir tls-server-examples
|
||||
./test-tls server write tls-server-examples/server.msg
|
||||
afl-fuzz -i tls-server-examples -o tls-server-findings -- $PWD/test-tls server read @@
|
||||
|
||||
##### TLS server
|
||||
make clean
|
||||
CC=afl-gcc make test-tls TEST_FUZZ=y
|
||||
mkdir tls-client-examples
|
||||
./test-tls client write tls-client-examples/client.msg
|
||||
afl-fuzz -i tls-client-examples -o tls-client-findings -- $PWD/test-tls client read @@
|
||||
|
||||
##### AP management frame processing
|
||||
cd ap-mgmt-fuzzer
|
||||
make clean
|
||||
CC=afl-gcc make
|
||||
mkdir multi-examples
|
||||
cp multi.dat multi-examples
|
||||
afl-fuzz -i multi-examples -o multi-findings -- $PWD/ap-mgmt-fuzzer -m @@
|
||||
|
||||
##### EAPOL-Key Supplicant (separate)
|
||||
cd eapol-fuzzer
|
||||
make clean
|
||||
CC=afl-gcc make
|
||||
mkdir eapol-examples
|
||||
cp *.dat eapol-examples
|
||||
afl-fuzz -i eapol-examples -o eapol-findings -- $PWD/eapol-fuzzer @@
|
||||
|
||||
##### P2P
|
||||
cd p2p-fuzzer
|
||||
make clean
|
||||
CC=afl-gcc make
|
||||
mkdir p2p-proberesp-examples
|
||||
cp proberesp*.dat p2p-proberesp-examples
|
||||
afl-fuzz -i p2p-proberesp-examples -o p2p-proberesp-findings -- $PWD/p2p-fuzzer proberesp @@
|
||||
mkdir p2p-action-examples
|
||||
cp go*.dat inv*.dat p2ps*.dat p2p-action-examples
|
||||
afl-fuzz -i p2p-action-examples -o p2p-action-findings -- $PWD/p2p-fuzzer action @@
|
||||
|
||||
##### WNM
|
||||
cd wnm-fuzzer
|
||||
make clean
|
||||
CC=afl-gcc make
|
||||
mkdir wnm-examples
|
||||
cp *.dat wnm-examples
|
||||
afl-fuzz -i wnm-examples -o wnm-findings -- $PWD/wnm-fuzzer @@
|
@ -1,377 +0,0 @@
|
||||
Cipher suite (CCMP, TKIP, GCMP, ..) and key management testing
|
||||
==============================================================
|
||||
|
||||
wpa_supplicant and hostapd include number of extensions that allow
|
||||
special test builds to be used for testing functionality related to
|
||||
correct implementation of IEEE 802.11. These extensions allow behavior
|
||||
to be modified and invalid operations to be performed to verify behavior
|
||||
of other devices in unexpected situations. While most of the testing
|
||||
extensions are focused on the fully automated testing framework with
|
||||
mac80211_hwsim (see tests/hwsim subdirectory), many of these can be used
|
||||
for over-the-air testing of the protocol as well.
|
||||
|
||||
Since some of the testing extensions can result in exposing key
|
||||
information or allowing non-compliant behavior, these changes are
|
||||
disabled in default wpa_supplicant and hostapd builds for production
|
||||
purposes. Testing functionality can be enabled by adding
|
||||
CONFIG_TESTING_OPTIONS=y into build configuration (hostapd/.config and
|
||||
wpa_supplicant/.config).
|
||||
|
||||
|
||||
Testing setup
|
||||
-------------
|
||||
|
||||
These tests can be run as black-box testing without having to modify the
|
||||
tested device at all or without knowing details of its
|
||||
functionality. The test commands in wpa_supplicant/hostapd control
|
||||
interfaces are used to perform unexpected operations and normal data
|
||||
traffic is used to verify reaction of the tested device to such
|
||||
operations.
|
||||
|
||||
In theory, the test functionality is available with most drivers
|
||||
supported by wpa_supplicant/hostapd, but the most reliable results are
|
||||
likely available through ath9k-based devices. If you are using something
|
||||
else, it is strongly recommended that you'll run the first tests with
|
||||
sniffer captures and verify that the test tools are behaving correctly.
|
||||
|
||||
wpa_supplicant is used to control a test device in station mode to test
|
||||
an AP and hostapd is similarly used to control a test device in AP mode
|
||||
to test a station.
|
||||
|
||||
Various data traffic generators could be used to test the behavior, but
|
||||
this document focuses on using ping to test unicast traffic and arping
|
||||
to test broadcast traffic. To keep things simple and to reduce
|
||||
interference from unrelated traffic, the steps here assume static IPv4
|
||||
addresses are used and IPv6 is disabled.
|
||||
|
||||
The tests here use WPA2-Personal for simplicity. WPA2-Enterprise and
|
||||
other cipher suites can also be tested for more complete coverage.
|
||||
|
||||
Example hostapd.conf for the test tool in AP mode:
|
||||
|
||||
driver=nl80211
|
||||
hw_mode=g
|
||||
channel=1
|
||||
ieee80211n=1
|
||||
interface=wlan0
|
||||
ctrl_interface=/var/run/hostapd
|
||||
ctrl_interface_group=adm
|
||||
ssid=test-psk
|
||||
wpa=2
|
||||
wpa_key_mgmt=WPA-PSK
|
||||
wpa_pairwise=CCMP
|
||||
wpa_passphrase=12345678
|
||||
|
||||
Example wpa_supplicant.conf for the test tool in station mode:
|
||||
|
||||
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=adm
|
||||
|
||||
network={
|
||||
ssid="test-psk"
|
||||
key_mgmt=WPA-PSK
|
||||
psk="12345678"
|
||||
}
|
||||
|
||||
The examples in this document assume following IPv4 address
|
||||
configuration:
|
||||
|
||||
Test tool (either AP or station mode): 192.168.1.1/24
|
||||
Device under test: 192.168.1.2/24
|
||||
|
||||
|
||||
Data traffic tests
|
||||
------------------
|
||||
|
||||
ping is used to test whether unicast frames go through on the data
|
||||
link. It should be noted that ping may need to use broadcast ARP at the
|
||||
beginning if the other device is not yet in the ARP table, so working
|
||||
broadcast and unicast connectivity may be needed to get this started.
|
||||
|
||||
Example:
|
||||
|
||||
$ ping -n -c 5 192.168.1.2
|
||||
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
|
||||
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=43.7 ms
|
||||
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=67.9 ms
|
||||
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=900 ms
|
||||
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=5.81 ms
|
||||
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=135 ms
|
||||
|
||||
--- 192.168.1.2 ping statistics ---
|
||||
5 packets transmitted, 5 received, 0% packet loss, time 4004ms
|
||||
rtt min/avg/max/mdev = 5.811/230.605/900.223/337.451 ms
|
||||
|
||||
This shows working unicast data connectivity.
|
||||
|
||||
$ ping -n -c 5 192.168.1.2
|
||||
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
|
||||
|
||||
--- 192.168.1.2 ping statistics ---
|
||||
5 packets transmitted, 0 received, 100% packet loss, time 4033ms
|
||||
|
||||
This shows not working unicast data connectivity.
|
||||
|
||||
|
||||
arping is used to test broadcast connectivity.
|
||||
|
||||
Example:
|
||||
|
||||
$ arping -b -I wlan0 192.168.1.2 -c 5
|
||||
ARPING 192.168.1.2 from 192.168.1.1 wlan0
|
||||
Unicast reply from 192.168.1.2 [<DUT MAC address>] 119.695ms
|
||||
Unicast reply from 192.168.1.2 [<DUT MAC address>] 144.496ms
|
||||
Unicast reply from 192.168.1.2 [<DUT MAC address>] 166.788ms
|
||||
Unicast reply from 192.168.1.2 [<DUT MAC address>] 2.283ms
|
||||
Unicast reply from 192.168.1.2 [<DUT MAC address>] 2.234ms
|
||||
Sent 5 probes (5 broadcast(s))
|
||||
Received 5 response(s)
|
||||
|
||||
This shows working broadcast data connectivity.
|
||||
|
||||
$ arping -b -I wlan0 192.168.1.2 -c 5
|
||||
ARPING 192.168.1.2 from 192.168.1.1 wlan0
|
||||
Sent 5 probes (5 broadcast(s))
|
||||
Received 0 response(s)
|
||||
|
||||
This shows not working broadcast data connectivity.
|
||||
|
||||
If testing results do not look consistent, the testing state can be
|
||||
cleared by disconnection and reconnecting the station (the test tool or
|
||||
the DUT) to the network.
|
||||
|
||||
|
||||
Sniffer and wlantest
|
||||
--------------------
|
||||
|
||||
It is useful to get a wireless sniffer capture from the operating
|
||||
channel of the AP to be able to confirm DUT behavior if any of the data
|
||||
tests indicate reason to believe something is not working as expected.
|
||||
|
||||
wlantest (from the wlantest directory of hostap.git) can be used to
|
||||
decrypt and analyze a sniffer capture. For example:
|
||||
|
||||
wlantest -r wlan0.pcap -n decrypted.pcap -p 12345678
|
||||
|
||||
The debug prints and comments in the generated file indicate where
|
||||
unexpected behavior has been detected, e.g., when the test tool ends up
|
||||
clearing its packet number to test replay protection. That can help in
|
||||
checking whether the DUT actually replies to a frame that it was
|
||||
supposed to drop due replay.
|
||||
|
||||
|
||||
Testing replay protection on a station device
|
||||
---------------------------------------------
|
||||
|
||||
Start hostapd and use hostapd_cli on the test device to control testing
|
||||
operations. Connect the DUT to the network.
|
||||
|
||||
<3>AP-STA-CONNECTED <DUT MAC address>
|
||||
|
||||
This indicates that the connection was completed successfully.
|
||||
|
||||
Verify that broadcast and unicast traffic works correctly (if not,
|
||||
something is wrong in the test setup and that needs to be resolved
|
||||
before being able to run any tests).
|
||||
|
||||
Verify that unicast traffic works and issue the following command in
|
||||
hostapd_cli:
|
||||
|
||||
> raw RESET_PN <DUT MAC address>
|
||||
OK
|
||||
|
||||
Verify that unicast traffic does not work anymore. If it does, the DUT
|
||||
does not implement replay protection correctly for unicast frames. Note
|
||||
that unicast traffic can recover once the packet number from the test
|
||||
device increases beyond the value used prior to that RESET_PN command.
|
||||
|
||||
|
||||
Verify that broadcast traffic works and issue the following command in
|
||||
hostapd_cli:
|
||||
|
||||
> raw RESET_PN ff:ff:ff:ff:ff:ff
|
||||
OK
|
||||
|
||||
Verify that broadcast traffic does not work anymore. If it does, the DUT
|
||||
does not implement replay protection correctly for broadcast
|
||||
frames. Note that broadcast traffic can recover once the packet number
|
||||
from the test device increases beyond the value used prior to that
|
||||
RESET_PN command.
|
||||
|
||||
|
||||
Testing replay protection on an AP device
|
||||
-----------------------------------------
|
||||
|
||||
Start the AP (DUT) and start wpa_supplicant on the test device to
|
||||
connect to the network. Use wpa_cli to control the test device.
|
||||
|
||||
<3>SME: Trying to authenticate with <DUT MAC address> (SSID='test-psk' freq=5240 MHz)
|
||||
<3>CTRL-EVENT-REGDOM-CHANGE init=CORE type=WORLD
|
||||
<3>Trying to associate with <DUT MAC address> (SSID='test-psk' freq=5240 MHz)
|
||||
<3>Associated with <DUT MAC address>
|
||||
<3>WPA: Key negotiation completed with <DUT MAC address> [PTK=CCMP GTK=CCMP]
|
||||
<3>CTRL-EVENT-CONNECTED - Connection to <DUT MAC address> completed [id=0 id_str=]
|
||||
|
||||
Verify that unicast traffic works and issue the following command in
|
||||
wpa_cli:
|
||||
|
||||
> raw RESET_PN
|
||||
OK
|
||||
|
||||
Verify that unicast traffic does not work anymore. If it does, the DUT
|
||||
does not implement replay protection correctly. Note that unicast
|
||||
traffic can recover once the packet number from the test device
|
||||
increases beyond the value used prior to that RESET_PN command.
|
||||
|
||||
IEEE 802.11 protocol uses unicast frames in station-to-AP direction, so
|
||||
there is no need to test AP replay protection behavior separately with
|
||||
the broadcast IPv4 traffic (which would be converted to unicast frames
|
||||
on the link layer).
|
||||
|
||||
|
||||
Testing GTK reinstallation protection on a station device (group handshake)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Use the procedure describe above for testing replay protection, but with
|
||||
the following hostapd_cli commands:
|
||||
|
||||
Test broadcast connectivity; should work
|
||||
|
||||
> raw RESEND_GROUP_M1 <DUT MAC address>
|
||||
OK
|
||||
> raw RESET_PN ff:ff:ff:ff:ff:ff
|
||||
OK
|
||||
|
||||
Test broadcast connectivity; should not work; if it does, the device
|
||||
does not implement protection for delayed retransmission of Group Key
|
||||
Message 1/2.
|
||||
|
||||
|
||||
Testing GTK reinstallation protection on a station device (4-way handshake)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Use the procedure described above for testing replay protection for
|
||||
broadcast traffic, but with the following hostapd_cli commands:
|
||||
|
||||
Test broadcast connectivity; should work
|
||||
|
||||
> raw RESEND_M3 <DUT MAC address>
|
||||
OK
|
||||
> raw RESET_PN ff:ff:ff:ff:ff:ff
|
||||
OK
|
||||
|
||||
Test broadcast connectivity; should not work; if it does, the device
|
||||
does not implement protection for delayed retransmission of 4-way
|
||||
handshake EAPOL-Key Message 3/4.
|
||||
|
||||
Variant 1: Include extra Message 1/4
|
||||
|
||||
Otherwise same as above, but replace RESEND_M3 command with:
|
||||
|
||||
> raw RESEND_M1 <DUT MAC address>
|
||||
OK
|
||||
> raw RESEND_M3 <DUT MAC address>
|
||||
OK
|
||||
|
||||
Variant 2: Include two extra Message 1/4
|
||||
|
||||
Otherwise same as above, but replace RESEND_M3 command with:
|
||||
|
||||
> raw RESEND_M1 <DUT MAC address> change-anonce
|
||||
OK
|
||||
> raw RESEND_M1 <DUT MAC address>
|
||||
OK
|
||||
> raw RESEND_M3 <DUT MAC address>
|
||||
OK
|
||||
|
||||
|
||||
Testing TK reinstallation protection on a station device (4-way handshake)
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Use the procedure described above for testing replay protection for
|
||||
unicast traffic, but with the following hostapd_cli commands:
|
||||
|
||||
Test unicast connectivity; should work
|
||||
|
||||
> raw RESEND_M3 <DUT MAC address>
|
||||
OK
|
||||
> raw RESET_PN <DUT MAC address>
|
||||
OK
|
||||
|
||||
Test unicast connectivity; should not work; if it does, the device
|
||||
does not implement protection for delayed retransmission of 4-way
|
||||
handshake EAPOL-Key Message 3/4.
|
||||
|
||||
Variant 1: Include extra Message 1/4
|
||||
|
||||
Otherwise same as above, but replace RESEND_M3 command with:
|
||||
|
||||
> raw RESEND_M1 <DUT MAC address>
|
||||
OK
|
||||
> raw RESEND_M3 <DUT MAC address>
|
||||
OK
|
||||
|
||||
Variant 2: Include two extra Message 1/4
|
||||
|
||||
Otherwise same as above, but replace RESEND_M3 command with:
|
||||
|
||||
> raw RESEND_M1 <DUT MAC address> change-anonce
|
||||
OK
|
||||
> raw RESEND_M1 <DUT MAC address>
|
||||
OK
|
||||
> raw RESEND_M3 <DUT MAC address>
|
||||
OK
|
||||
|
||||
|
||||
Testing ANonce generation on an AP device
|
||||
-----------------------------------------
|
||||
|
||||
Start the AP (DUT) and start wpa_supplicant on the test device to
|
||||
connect to the network. Use wpa_cli to control the test device.
|
||||
|
||||
<3>SME: Trying to authenticate with <DUT MAC address> (SSID='test-psk' freq=5240 MHz)
|
||||
<3>CTRL-EVENT-REGDOM-CHANGE init=CORE type=WORLD
|
||||
<3>Trying to associate with <DUT MAC address> (SSID='test-psk' freq=5240 MHz)
|
||||
<3>Associated with <DUT MAC address>
|
||||
<3>WPA: Key negotiation completed with <DUT MAC address> [PTK=CCMP GTK=CCMP]
|
||||
<3>CTRL-EVENT-CONNECTED - Connection to <DUT MAC address> completed [id=0 id_str=]
|
||||
|
||||
Show the ANonce from the first 4-way handshake, request PTK rekeying,
|
||||
and show the ANonce from the second 4-way handshake:
|
||||
|
||||
> GET anonce
|
||||
df8c61d1f1f7aca9f1739dd888199547f4af2b8b07f8bf15b45ea271da0072b2
|
||||
> raw KEY_REQUEST 0 1
|
||||
OK
|
||||
> GET anonce
|
||||
d8ddcb716f28abfdf1352a05d51e7a70f58802122e99d13c730c3c0f09594aac
|
||||
|
||||
If the ANonce values are same, the AP did not update the ANonce for
|
||||
rekeying (it should have as shown in the example above).
|
||||
|
||||
|
||||
Testing FT Reassociation Request frame retransmission on an AP device
|
||||
---------------------------------------------------------------------
|
||||
|
||||
This test case requires a sniffer to be used and manually analyzed.
|
||||
|
||||
Enable FT on the DUT AP (likely two AP devices needed), connect test
|
||||
tool to the AP using FT protocol (e.g., connect to another AP first and
|
||||
then use the "ROAM <BSSID>" command), and do the following steps:
|
||||
|
||||
- verify unicast traffic from the AP to test station (either ping from
|
||||
the AP or from a device behind the AP); this needs to work
|
||||
- wpa_cli "raw RESEND_ASSOC"
|
||||
- verify unicast traffic from the AP to test station (either ping from
|
||||
the AP or from a device behind the AP); this is likely to fail, but
|
||||
the real analysis is done based on the sniffer capture
|
||||
|
||||
In the sniffer capture, find the last Reassociation Request frame from
|
||||
the test station (this is more or less identical to the previous one and
|
||||
the only one that should not have Authentication frame exchange before
|
||||
it). Look at the last used PN in a unicast Data frame from the AP to the
|
||||
test station before the last Reassociation Request frame and the PN in
|
||||
the following unicast Data frame after the last Reassociation Request
|
||||
frame. If the PN goes down (e.g., is reset to 1), this would be a sign
|
||||
of a likely security vulnerability. The AP's TK configuration should be
|
||||
verified (i.e., whether it is configuring the same TK again and then
|
||||
allowing it to be used with reused PN values).
|
@ -1,23 +0,0 @@
|
||||
hostap.git fuzz testing
|
||||
-----------------------
|
||||
|
||||
These tools can be used for fuzz testing of various components used
|
||||
within wpa_supplicant and hostapd. Each directory contains a fuzzing
|
||||
tool that focuses on one input handler. Each tool can be compiled either
|
||||
to work with the libFuzzer or as a separate tool that reads the input
|
||||
from a file specified on the command line, e.g., for American fuzzy lop
|
||||
(afl-fuzz). Example test corpus is included in */corpus directory.
|
||||
|
||||
Example fuzzing with libFuzzer
|
||||
|
||||
cd @TOOL@
|
||||
make clean
|
||||
make LIBFUZZER=y
|
||||
./@TOOL@ corpus
|
||||
|
||||
Example fuzzing with afl-fuzz
|
||||
|
||||
cd @TOOL@
|
||||
make clean
|
||||
CC=afl-gcc make
|
||||
afl-fuzz -i corpus -o findings -- $PWD/@TOOL@ @@
|
1
contrib/wpa/tests/fuzzing/ap-mgmt/.gitignore
vendored
1
contrib/wpa/tests/fuzzing/ap-mgmt/.gitignore
vendored
@ -1 +0,0 @@
|
||||
ap-mgmt
|
@ -1,44 +0,0 @@
|
||||
ALL=ap-mgmt
|
||||
include ../rules.include
|
||||
|
||||
CFLAGS += -DCONFIG_WNM
|
||||
CFLAGS += -DCONFIG_INTERWORKING
|
||||
CFLAGS += -DCONFIG_GAS
|
||||
CFLAGS += -DCONFIG_HS20
|
||||
CFLAGS += -DIEEE8021X_EAPOL
|
||||
CFLAGS += -DNEED_AP_MLME
|
||||
CFLAGS += -DCONFIG_AIRTIME_POLICY
|
||||
|
||||
LIBS += $(SRC)/common/libcommon.a
|
||||
LIBS += $(SRC)/crypto/libcrypto.a
|
||||
LIBS += $(SRC)/tls/libtls.a
|
||||
LIBS += $(SRC)/wps/libwps.a
|
||||
LIBS += $(SRC)/eap_server/libeap_server.a
|
||||
LIBS += $(SRC)/eap_common/libeap_common.a
|
||||
LIBS += $(SRC)/l2_packet/libl2_packet.a
|
||||
LIBS += $(SRC)/ap/libap.a
|
||||
LIBS += $(SRC)/eapol_auth/libeapol_auth.a
|
||||
LIBS += $(SRC)/radius/libradius.a
|
||||
LIBS += $(SRC)/utils/libutils.a
|
||||
|
||||
ELIBS += $(SRC)/crypto/libcrypto.a
|
||||
ELIBS += $(SRC)/tls/libtls.a
|
||||
|
||||
OBJS += $(SRC)/drivers/driver_common.o
|
||||
|
||||
OBJS += ap-mgmt.o
|
||||
|
||||
_OBJS_VAR := OBJS
|
||||
include ../../../src/objs.mk
|
||||
|
||||
_OBJS_VAR := LIBS
|
||||
include ../../../src/objs.mk
|
||||
|
||||
_OBJS_VAR := ELIBS
|
||||
include ../../../src/objs.mk
|
||||
|
||||
ap-mgmt: $(OBJS) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
|
||||
|
||||
clean: common-clean
|
||||
rm -f ap-mgmt *~ *.o *.d ../*~ ../*.o ../*.d
|
@ -1,167 +0,0 @@
|
||||
/*
|
||||
* hostapd - Management frame fuzzer
|
||||
* Copyright (c) 2015-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "ap/hostapd.h"
|
||||
#include "ap/hw_features.h"
|
||||
#include "ap/ieee802_11.h"
|
||||
#include "ap/sta_info.h"
|
||||
#include "ap/ap_list.h"
|
||||
#include "../fuzzer-common.h"
|
||||
|
||||
|
||||
const struct wpa_driver_ops *const wpa_drivers[] =
|
||||
{
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
struct arg_ctx {
|
||||
const u8 *data;
|
||||
size_t data_len;
|
||||
struct hostapd_iface iface;
|
||||
struct hostapd_data hapd;
|
||||
struct wpa_driver_ops driver;
|
||||
struct hostapd_config iconf;
|
||||
struct hostapd_bss_config conf;
|
||||
};
|
||||
|
||||
|
||||
static void test_send_mgmt(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct arg_ctx *ctx = eloop_data;
|
||||
struct hostapd_frame_info fi;
|
||||
const u8 *pos, *end;
|
||||
|
||||
os_memset(&fi, 0, sizeof(fi));
|
||||
|
||||
pos = ctx->data;
|
||||
end = pos + ctx->data_len;
|
||||
|
||||
while (end - pos > 2) {
|
||||
u16 flen;
|
||||
|
||||
flen = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (end - pos < flen)
|
||||
break;
|
||||
wpa_hexdump(MSG_MSGDUMP, "fuzzer - frame", pos, flen);
|
||||
ieee802_11_mgmt(&ctx->hapd, pos, flen, &fi);
|
||||
pos += flen;
|
||||
}
|
||||
|
||||
eloop_terminate();
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_hw_modes * gen_modes(void)
|
||||
{
|
||||
struct hostapd_hw_modes *mode;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
mode = os_zalloc(sizeof(struct hostapd_hw_modes));
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
mode->mode = HOSTAPD_MODE_IEEE80211G;
|
||||
chan = os_zalloc(sizeof(struct hostapd_channel_data));
|
||||
if (!chan) {
|
||||
os_free(mode);
|
||||
return NULL;
|
||||
}
|
||||
chan->chan = 1;
|
||||
chan->freq = 2412;
|
||||
mode->channels = chan;
|
||||
mode->num_channels = 1;
|
||||
|
||||
mode->rates = os_zalloc(sizeof(int));
|
||||
if (!mode->rates) {
|
||||
os_free(chan);
|
||||
os_free(mode);
|
||||
return NULL;
|
||||
}
|
||||
mode->rates[0] = 10;
|
||||
mode->num_rates = 1;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
static int init_hapd(struct arg_ctx *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = &ctx->hapd;
|
||||
struct sta_info *sta;
|
||||
struct hostapd_bss_config *bss;
|
||||
|
||||
hapd->driver = &ctx->driver;
|
||||
os_memcpy(hapd->own_addr, "\x02\x00\x00\x00\x03\x00", ETH_ALEN);
|
||||
hapd->iface = &ctx->iface;
|
||||
hapd->iface->conf = hostapd_config_defaults();
|
||||
if (!hapd->iface->conf)
|
||||
return -1;
|
||||
hapd->iface->hw_features = gen_modes();
|
||||
hapd->iface->num_hw_features = 1;
|
||||
hapd->iface->current_mode = hapd->iface->hw_features;
|
||||
hapd->iconf = hapd->iface->conf;
|
||||
hapd->iconf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
||||
hapd->iconf->channel = 1;
|
||||
bss = hapd->conf = hapd->iconf->bss[0];
|
||||
hostapd_config_defaults_bss(hapd->conf);
|
||||
os_memcpy(bss->ssid.ssid, "test", 4);
|
||||
bss->ssid.ssid_len = 4;
|
||||
bss->ssid.ssid_set = 1;
|
||||
|
||||
sta = ap_sta_add(hapd, (u8 *) "\x02\x00\x00\x00\x00\x00");
|
||||
if (sta)
|
||||
sta->flags |= WLAN_STA_ASSOC | WLAN_STA_WMM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
struct arg_ctx ctx;
|
||||
|
||||
wpa_fuzzer_set_debug_level();
|
||||
|
||||
if (os_program_init())
|
||||
return 0;
|
||||
|
||||
if (eloop_init()) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
|
||||
return 0;
|
||||
}
|
||||
|
||||
os_memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.data = data;
|
||||
ctx.data_len = size;
|
||||
|
||||
if (init_hapd(&ctx))
|
||||
goto fail;
|
||||
|
||||
eloop_register_timeout(0, 0, test_send_mgmt, &ctx, NULL);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Starting eloop");
|
||||
eloop_run();
|
||||
wpa_printf(MSG_DEBUG, "eloop done");
|
||||
hostapd_free_stas(&ctx.hapd);
|
||||
hostapd_free_hw_features(ctx.hapd.iface->hw_features,
|
||||
ctx.hapd.iface->num_hw_features);
|
||||
|
||||
fail:
|
||||
hostapd_config_free(ctx.hapd.iconf);
|
||||
ap_list_deinit(&ctx.iface);
|
||||
eloop_destroy();
|
||||
os_program_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
1
contrib/wpa/tests/fuzzing/asn1/.gitignore
vendored
1
contrib/wpa/tests/fuzzing/asn1/.gitignore
vendored
@ -1 +0,0 @@
|
||||
asn1
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user