From: Dan Breslau Date: Fri, 2 Sep 2016 17:02:24 +0000 (-0400) Subject: Updated through tag hostap_2_5 from git://w1.fi/hostap.git X-Git-Tag: v0.9.6~2^2~11 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.git;a=commitdiff_plain;h=4f319dde67a76fe0aaf33f6d2788968012584ada;hp=1f344cd7b4461c8bae31abc3fc450407782282e2 Updated through tag hostap_2_5 from git://w1.fi/hostap.git --- diff --git a/.gitignore b/.gitignore index ae624c9..2089b08 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,25 @@ +Makefile.in +aclocal.m4 +autom4te.cache +configure +config.* +ltmain.sh +libtool +depcomp +m4 +!m4/minuso.m4 +build-aux +!build-aux/compile +mech_eap.spec +mech_eap*tar* +*.lo *.o *.d *.gcno *.gcda *.gcov *.pyc +*# *~ .config tests/hwsim/logs diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..0165219 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,4 @@ +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = libeap mech_eap +EXTRA_DIST = mech_eap.spec diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..9da57ed --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,402 @@ +dnl Based on the one from the Boinc project by Reinhard + +AC_DEFUN([AX_CHECK_WINDOWS], +[AC_MSG_CHECKING(for windows) +target_windows="no" +AC_CHECK_HEADER(windows.h,[target_windows="yes"],[target_windows="no"]) +AC_MSG_RESULT($target_windows) +AM_CONDITIONAL(TARGET_WINDOWS,test "x$target_windows" = "xyes") +])dnl + +AC_DEFUN([AX_CHECK_KRB5], +[AC_MSG_CHECKING(for GSS-API and Kerberos implementation) +KRB5_DIR= +found_krb5="no" +AC_ARG_WITH(krb5, + AC_HELP_STRING([--with-krb5], + [Use krb5 (in specified installation directory)]), + [check_krb5_dir="$withval"], + [check_krb5_dir=]) +for dir in $check_krb5_dir $prefix /usr/local /usr ; do + krb5dir="$dir" + if test -x "$dir/bin/krb5-config"; then + found_krb5="yes"; + if test "x$target_windows" = "xyes"; then + KRB5_CFLAGS=-I"$check_krb5_dir/include"; + KRB5_LDFLAGS="-L$check_krb5_dir/lib/"; + KRB5_LIBS="-lkrb5_32 -lgssapi32"; + COMPILE_ET="$check_krb5_dir/bin/compile_et"; + AC_MSG_RESULT([yes]) + else + KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`; + KRB5_LDFLAGS="-L$dir/lib"; + KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs` +AC_MSG_RESULT([yes]) + AC_PATH_PROG(COMPILE_ET, [compile_et], [compile_et], [$dir/bin$PATH_SEPARATOr]) + fi + break; + fi +done +if test x_$found_krb5 != x_yes; then + AC_MSG_RESULT($found_krb5) + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find GSS-API/Kerberos libraries. + + Please install MIT or Heimdal or specify installation directory with + --with-krb5=(dir). +---------------------------------------------------------------------- +]) +else + printf "Kerberos found in $krb5dir\n"; + AC_SUBST(KRB5_CFLAGS) + AC_SUBST(KRB5_LDFLAGS) + AC_SUBST(KRB5_LIBS) + AC_SUBST(COMPILE_ET) + AC_CHECK_LIB(krb5, GSS_C_NT_COMPOSITE_EXPORT, [AC_DEFINE_UNQUOTED([HAVE_GSS_C_NT_COMPOSITE_EXPORT], 1, [Define if GSS-API library supports recent naming extensions draft])], [], "$KRB5_LIBS") + AC_CHECK_LIB(krb5, gss_inquire_attrs_for_mech, [AC_DEFINE_UNQUOTED([HAVE_GSS_INQUIRE_ATTRS_FOR_MECH], 1, [Define if GSS-API library supports RFC 5587])], [], "$KRB5_LIBS") + AC_CHECK_LIB(krb5, gss_krb5_import_cred, [AC_DEFINE_UNQUOTED([HAVE_GSS_KRB5_IMPORT_CRED], 1, [Define if GSS-API library supports gss_krb5_import_cred])], [], "$KRB5_LIBS") + AC_CHECK_LIB(krb5, heimdal_version, [AC_DEFINE_UNQUOTED([HAVE_HEIMDAL_VERSION], 1, [Define if building against Heimdal Kerberos implementation]), heimdal=yes], [heimdal=no], "$KRB5_LIBS") + AM_CONDITIONAL(HEIMDAL, test "x$heimdal" != "xno") +fi +])dnl + +AC_DEFUN([AX_CHECK_EAP], +[AC_MSG_CHECKING(for EAP implementation) +EAP_DIR= +found_eap="no" +AC_ARG_WITH(eap, + AC_HELP_STRING([--with-eap], + [Use eap (in specified installation directory)]), + [check_eap_dir="$withval"], + [check_eap_dir=]) +for dir in $check_eap_dir $prefix /usr /usr/local ../libeap ; do + eapdir="$dir" + if test -f "$dir/src/eap_peer/eap.h"; then + found_eap="yes"; + EAP_DIR="${eapdir}" + EAP_CFLAGS="-I$eapdir/src/common -I$eapdir/src -I$eapdir/src/utils"; + break; + fi +done +AC_MSG_RESULT($found_eap) +if test x_$found_eap != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find EAP libraries. + + Please install wpa_supplicant or specify installation directory with + --with-eap=(dir). +---------------------------------------------------------------------- +]) +else + printf "EAP found in $eapdir\n"; + EAP_CFLAGS="$EAP_CFLAGS \ +-DEAP_TLS \ +-DEAP_PEAP \ +-DEAP_TTLS \ +-DEAP_MD5 \ +-DEAP_MSCHAPv2 \ +-DEAP_GTC \ +-DEAP_OTP \ +-DEAP_LEAP \ +-DEAP_PSK \ +-DEAP_PAX \ +-DEAP_SAKE \ +-DEAP_GPSK \ +-DEAP_GPSK_SHA256 \ +-DEAP_SERVER_IDENTITY \ +-DEAP_SERVER_TLS \ +-DEAP_SERVER_PEAP \ +-DEAP_SERVER_TTLS \ +-DEAP_SERVER_MD5 \ +-DEAP_SERVER_MSCHAPV2 \ +-DEAP_SERVER_GTC \ +-DEAP_SERVER_PSK \ +-DEAP_SERVER_PAX \ +-DEAP_SERVER_SAKE \ +-DEAP_SERVER_GPSK \ +-DEAP_SERVER_GPSK_SHA256 \ +-DIEEE8021X_EAPOL"; + EAP_LIBS="-leap -lutils -lcrypto -ltls -lssl"; + EAP_LDFLAGS="-L$eapdir/eap_example -L$eapdir/src/utils -L$eapdir/src/crypto -L$eapdir/src/tls"; + AC_SUBST(EAP_CFLAGS) + AC_SUBST(EAP_LDFLAGS) + AC_SUBST(EAP_LIBS) +fi +])dnl + +AC_DEFUN([AX_CHECK_SHIBSP], +[AC_MSG_CHECKING(for Shibboleth implementation) +SHIBSP_DIR= +found_shibsp="no" +AC_ARG_WITH(shibsp, + AC_HELP_STRING([--with-shibsp], + [Use shibspboleth (in specified installation directory)]), + [check_shibsp_dir="$withval"], + [check_shibsp_dir=]) +for dir in $check_shibsp_dir $prefix /usr /usr/local ; do + shibspdir="$dir" + if test -f "$dir/include/shibsp/SPConfig.h"; then + found_shibsp="yes"; + SHIBSP_DIR="${shibspdir}" + SHIBSP_CXXFLAGS="-I$shibspdir/include"; + break; + fi +done +AC_MSG_RESULT($found_shibsp) +if test x_$found_shibsp != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find Shibboleth libraries. + + Please install Shibboleth or specify installation directory with + --with-shibsp=(dir). +---------------------------------------------------------------------- +]) +else + printf "Shibboleth found in $shibspdir\n"; + SHIBSP_LIBS="-lshibsp -lsaml -lxml-security-c -lxmltooling -lxerces-c"; + SHIBSP_LDFLAGS="-L$shibspdir/lib"; + AC_SUBST(SHIBSP_CXXFLAGS) + AC_SUBST(SHIBSP_LDFLAGS) + AC_SUBST(SHIBSP_LIBS) + AC_DEFINE_UNQUOTED([HAVE_SHIBSP], 1, [Define is Shibboleth SP is available]) +fi +])dnl + +AC_DEFUN([AX_CHECK_SHIBRESOLVER], +[AC_MSG_CHECKING(for Shibboleth resolver implementation) +SHIBRESOLVER_DIR= +found_shibresolver="no" +AC_ARG_WITH(shibresolver, + AC_HELP_STRING([--with-shibresolver], + [Use Shibboleth resolver (in specified installation directory)]), + [check_shibresolver_dir="$withval"], + [check_shibresolver_dir=]) +if test x_$check_shibresolver_dir != x_no; then +for dir in $check_shibresolver_dir $prefix /usr /usr/local ; do + shibresolverdir="$dir" + if test -f "$dir/include/shibresolver/resolver.h"; then + found_shibresolver="yes"; + SHIBRESOLVER_DIR="${shibresolverdir}" + SHIBRESOLVER_CXXFLAGS="-I$shibresolverdir/include"; + break; + fi +done +fi +AC_MSG_RESULT($found_shibresolver) +if test x_$check_shibresolver_dir != x_no; then +if test x_$found_shibresolver != x_yes; then + AC_MSG_WARN([ +---------------------------------------------------------------------- + Cannot find Shibboleth resolver libraries, building without + Shibboleth support. + + Please install Shibboleth or specify installation directory with + --with-shibresolver=(dir). +---------------------------------------------------------------------- +]) +else + printf "Shibboleth resolver found in $shibresolverdir\n"; + SHIBRESOLVER_LIBS="-lshibresolver"; + SHIBRESOLVER_LDFLAGS="-L$shibresolverdir/lib"; + AC_SUBST(SHIBRESOLVER_CXXFLAGS) + AC_SUBST(SHIBRESOLVER_LDFLAGS) + AC_SUBST(SHIBRESOLVER_LIBS) + AC_DEFINE_UNQUOTED([HAVE_SHIBRESOLVER], 1, [Define is Shibboleth resolver is available]) +fi +fi +])dnl + +AC_DEFUN([AX_CHECK_OPENSAML], +[AC_MSG_CHECKING(for OpenSAML implementation) +OPENSAML_DIR= +found_opensaml="no" +AC_ARG_WITH(opensaml, + AC_HELP_STRING([--with-opensaml], + [Use OpenSAML (in specified installation directory)]), + [check_opensaml_dir="$withval"], + [check_opensaml_dir=]) +if test x_$check_opensaml_dir != x_no; then +for dir in $check_opensaml_dir $prefix /usr /usr/local ; do + opensamldir="$dir" + if test -f "$dir/include/saml/Assertion.h"; then + found_opensaml="yes"; + OPENSAML_DIR="${opensamldir}" + OPENSAML_CXXFLAGS="-I$opensamldir/include"; + break; + fi +done +fi +AC_MSG_RESULT($found_opensaml) +if test x_$check_opensaml_dir != x_no; then +if test x_$found_opensaml != x_yes; then + AC_MSG_WARN([ +---------------------------------------------------------------------- + Cannot find OpenSAML libraries, building without OpenSAML support. + + Please install OpenSAML or specify installation directory with + --with-opensaml=(dir). +---------------------------------------------------------------------- +]) +else + printf "OpenSAML found in $opensamldir\n"; + OPENSAML_LIBS="-lsaml -lxml-security-c -lxmltooling -lxerces-c"; + OPENSAML_LDFLAGS="-L$opensamldir/lib"; + AC_SUBST(OPENSAML_CXXFLAGS) + AC_SUBST(OPENSAML_LDFLAGS) + AC_SUBST(OPENSAML_LIBS) + AC_DEFINE_UNQUOTED([HAVE_OPENSAML], 1, [Define is OpenSAML is available]) +fi +fi +])dnl + +AC_DEFUN([AX_CHECK_OPENSSL], +[AC_MSG_CHECKING(for OpenSSL) +OPENSSL_DIR= +found_openssl="no" +AC_ARG_WITH(openssl, + AC_HELP_STRING([--with-openssl], + [Use OpenSSL (in specified installation directory)]), + [check_openssl_dir="$withval"], + [check_openssl_dir=]) +for dir in $check_openssl_dir $prefix /usr /usr/local ; do + openssldir="$dir" + if test -f "$dir/include/openssl/opensslv.h"; then + found_openssl="yes"; + OPENSSL_DIR="${openssldir}" + OPENSSL_CFLAGS="-I$openssldir/include"; + break; + fi +done +AC_MSG_RESULT($found_openssl) +if test x_$found_openssl != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find OpenSSL libraries. + + Please install libssl or specify installation directory with + --with-openssl=(dir). +---------------------------------------------------------------------- +]) +else + printf "OpenSSL found in $openssldir\n"; + OPENSSL_LIBS="-lssl -lcrypto"; + OPENSSL_LDFLAGS="-L$openssldir/lib"; + AC_SUBST(OPENSSL_CFLAGS) + AC_SUBST(OPENSSL_LDFLAGS) + AC_SUBST(OPENSSL_LIBS) +fi +])dnl + +AC_DEFUN([AX_CHECK_RADSEC], +[AC_MSG_CHECKING(for radsec) +RADSEC_DIR= +found_radsec="no" +AC_ARG_WITH(radsec, + AC_HELP_STRING([--with-radsec], + [Use radsec (in specified installation directory)]), + [check_radsec_dir="$withval"], + [check_radsec_dir=]) +for dir in $check_radsec_dir $prefix /usr /usr/local ; do + radsecdir="$dir" + if test -f "$dir/include/radsec/radsec.h"; then + found_radsec="yes"; + RADSEC_DIR="${radsecdir}" + RADSEC_CFLAGS="-I$radsecdir/include"; + break; + fi +done +AC_MSG_RESULT($found_radsec) +if test x_$found_radsec != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find radsec libraries. + + Please install libradsec or specify installation directory with + --with-radsec=(dir). +---------------------------------------------------------------------- +]) +else + printf "radsec found in $radsecdir\n"; + RADSEC_LIBS="-lradsec"; + RADSEC_LDFLAGS="-L$radsecdir/lib"; + AC_SUBST(RADSEC_CFLAGS) + AC_SUBST(RADSEC_LDFLAGS) + AC_SUBST(RADSEC_LIBS) +fi +])dnl + +AC_DEFUN([AX_CHECK_JANSSON], +[AC_MSG_CHECKING(for jansson) +JANSSON_DIR= +found_jansson="no" +AC_ARG_WITH(jansson, + AC_HELP_STRING([--with-jansson], + [Use jansson (in specified installation directory)]), + [check_jansson_dir="$withval"], + [check_jansson_dir=]) +for dir in $check_jansson_dir $prefix /usr /usr/local ; do + janssondir="$dir" + if test -f "$dir/include/jansson.h"; then + found_jansson="yes"; + JANSSON_DIR="${janssondir}" + JANSSON_CFLAGS="-I$janssondir/include"; + break; + fi +done +AC_MSG_RESULT($found_jansson) +if test x_$found_jansson != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find jansson libraries. + + Please install libjansson or specify installation directory with + --with-jansson=(dir). +---------------------------------------------------------------------- +]) +else + printf "jansson found in $janssondir\n"; + JANSSON_LIBS="-ljansson"; + JANSSON_LDFLAGS="-L$janssondir/lib"; + AC_SUBST(JANSSON_CFLAGS) + AC_SUBST(JANSSON_LDFLAGS) + AC_SUBST(JANSSON_LIBS) +fi +])dnl + +AC_DEFUN([AX_CHECK_LIBMOONSHOT], +[AC_MSG_CHECKING(for Moonshot identity selector implementation) +LIBMOONSHOT_DIR= +LIBMOONSHOT_CFLAGS= +LIBMOONSHOT_LDFLAGS= +LIBMOONSHOT_LIBS= +found_libmoonshot="no" +AC_ARG_WITH(libmoonshot, + AC_HELP_STRING([--with-libmoonshot], + [Use libmoonshot (in specified installation directory)]), + [check_libmoonshot_dir="$withval"], + [check_libmoonshot_dir=]) +for dir in $check_libmoonshot_dir $prefix /usr /usr/local ; do + libmoonshotdir="$dir" + if test -f "$dir/include/libmoonshot.h"; then + found_libmoonshot="yes"; + LIBMOONSHOT_DIR="${libmoonshotdir}" + LIBMOONSHOT_CFLAGS="-I$libmoonshotdir/include"; + break; + fi +done +AC_MSG_RESULT($found_libmoonshot) +if test x_$found_libmoonshot = x_yes; then + printf "libmoonshot found in $libmoonshotdir\n"; + LIBMOONSHOT_LIBS="-lmoonshot"; + LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib"; + AC_CHECK_LIB(moonshot, moonshot_get_identity, [AC_DEFINE_UNQUOTED([HAVE_MOONSHOT_GET_IDENTITY], 1, [Define if Moonshot identity selector is available])], [], "$LIBMOONSHOT_LIBS") +fi + AC_SUBST(LIBMOONSHOT_CFLAGS) + AC_SUBST(LIBMOONSHOT_LDFLAGS) + AC_SUBST(LIBMOONSHOT_LIBS) + AM_CONDITIONAL(LIBMOONSHOT, test "x$found_libmoonshot" != "xno") +])dnl + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..13432d0 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Regenerate autotools files. +# + +PATH=/usr/local/bin:$PATH + +if [ -x "`which autoreconf 2>/dev/null`" ] ; then + exec autoreconf -ivf +fi + +aclocal -I . -I m4 && \ + autoheader && \ + libtoolize --automake -c && \ + autoconf && \ + automake --add-missing --copy diff --git a/build-aux/compile b/build-aux/compile new file mode 100755 index 0000000..531136b --- /dev/null +++ b/build-aux/compile @@ -0,0 +1,347 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-10-14.11; # UTC + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..a58e724 --- /dev/null +++ b/configure.ac @@ -0,0 +1,95 @@ +AC_PREREQ([2.61]) +AC_INIT([mech_eap], [0.9.5], [bugs@project-moonshot.org]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) + +dnl AM_INIT_AUTOMAKE([silent-rules]) +AC_USE_SYSTEM_EXTENSIONS +AM_INIT_AUTOMAKE +AM_PROG_CC_C_O +AM_MAINTAINER_MODE() +LT_PREREQ([2.2]) +LT_INIT([dlopen disable-static win32-dll]) + +dnl AC_PROG_CC +AC_PROG_CXX +AC_CONFIG_HEADERS([config.h]) +AC_CHECK_HEADERS(stdarg.h stdio.h stdint.h sys/param.h stdlib.h) +AC_REPLACE_FUNCS(vasprintf) +AC_CHECK_FUNCS([ secure_getenv]) + +dnl Check if we're on Solaris and set CFLAGS accordingly +dnl AC_CANONICAL_TARGET +dnl case "${target_os}" in +dnl solaris*) +dnl TARGET_CFLAGS="-DSYS_SOLARIS9 -D_POSIX_PTHREAD_SEMANTICS" +dnl if test "$GCC" != yes ; then +dnl TARGET_CFLAGS="$TARGET_CFLAGS -mt" +dnl else +dnl TARGET_CFLAGS="$TARGET_CFLAGS -pthreads" +dnl fi +dnl TARGET_LDFLAGS="-lpthread -lsocket -lnsl" +dnl ;; +dnl *) +dnl TARGET_CFLAGS="-Wall -pedantic -pthread" +dnl TARGET_LDFLAGS="" +dnl esac + +reauth=no +AC_ARG_ENABLE(reauth, + [ --enable-reauth whether to enable fast reauthentication protocol: yes/no; default no ], + [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then + reauth=$enableval + else + echo "--enable-reauth argument must be yes or no" + exit -1 + fi + ]) + +if test "x$reauth" = "xyes" ; then + echo "Fast reauthentication protocol enabled" + TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_REAUTH" +fi +AM_CONDITIONAL(GSSEAP_ENABLE_REAUTH, test "x$reauth" != "xno") + +acceptor=yes +AC_ARG_ENABLE(acceptor, + [ --enable-acceptor whether to enable acceptor codepaths: yes/no; default yes ], + [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then + acceptor=$enableval + else + echo "--enable-acceptor argument must be yes or no" + exit -1 + fi + ]) + +if test "x$acceptor" = "xyes" ; then + echo "acceptor enabled" + TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_ACCEPTOR" +fi +AM_CONDITIONAL(GSSEAP_ENABLE_ACCEPTOR, test "x$acceptor" != "xno") + +AC_SUBST(TARGET_CFLAGS) +AC_SUBST(TARGET_LDFLAGS) +AX_CHECK_WINDOWS +AX_CHECK_KRB5 +AX_CHECK_OPENSAML +AM_CONDITIONAL(OPENSAML, test "x_$check_opensaml_dir" != "x_no") + +AX_CHECK_SHIBRESOLVER +AM_CONDITIONAL(SHIBRESOLVER, test "x_$check_shibresolver_dir" != "x_no") +if test x_$found_shibresolver = x_yes; then + AX_CHECK_SHIBSP +fi + +AX_CHECK_OPENSSL + +if test "x$acceptor" = "xyes" ; then + AX_CHECK_RADSEC + AX_CHECK_JANSSON +fi + +AX_CHECK_LIBMOONSHOT +AC_CONFIG_FILES([Makefile libeap/Makefile mech_eap/Makefile + mech_eap.spec]) +AC_OUTPUT diff --git a/eap_example/Makefile b/eap_example/Makefile deleted file mode 100644 index 0cc19bd..0000000 --- a/eap_example/Makefile +++ /dev/null @@ -1,152 +0,0 @@ -ALL=eap_example - -all: $(ALL) - -ifndef CC -CC=gcc -endif - -ifndef RANLIB -RANLIB=ranlib -endif - -ifndef CFLAGS -CFLAGS = -MMD -O2 -Wall -g -endif - - -CFLAGS += -I. -CFLAGS += -I../src -CFLAGS += -I../src/utils - - -OBJS_both += ../src/utils/libutils.a -OBJS_both += ../src/crypto/libcrypto.a -OBJS_both += ../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 - - -ifndef LDO -LDO=$(CC) -endif - -Q=@ -E=echo -ifeq ($(V), 1) -Q= -E=true -endif - -%.o: %.c - $(Q)$(CC) -c -o $@ $(CFLAGS) $< - @$(E) " CC " $< - - -OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server) - -OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o - - -../src/utils/libutils.a: - $(MAKE) -C ../src/utils - -../src/crypto/libcrypto.a: - $(MAKE) -C ../src/crypto - -../src/tls/libtls.a: - $(MAKE) -C ../src/tls - - -ifneq ($(CONFIG_SOLIB), yes) -LIBEAP = libeap.a -libeap.a: $(OBJS_lib) - $(AR) crT libeap.a $(OBJS_lib) - $(RANLIB) libeap.a - -else -CFLAGS += -fPIC -DPIC -LDFLAGS += -shared - -LIBEAP = libeap.so -libeap.so: $(OBJS_lib) - $(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP) - -endif - -eap_example: $(OBJS_ex) $(LIBEAP) - $(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS) - -clean: - $(MAKE) -C ../src clean - rm -f core *~ *.o *.d libeap.a libeap.so $(ALL) - --include $(OBJS:%.o=%.d) diff --git a/libeap/.gitignore b/libeap/.gitignore new file mode 100644 index 0000000..4a1ad86 --- /dev/null +++ b/libeap/.gitignore @@ -0,0 +1,17 @@ +*.o +*.d +*~ +wpa_supplicant/eapol_test +wpa_supplicant/preauth_test +wpa_supplicant/wpa_cli +wpa_supplicant/wpa_passphrase +wpa_supplicant/wpa_supplicant +wpa_supplicant/wpa_priv +wpa_supplicant/wpa_gui/Makefile +wpa_supplicant/wpa_gui/wpa_gui +wpa_supplicant/wpa_gui-qt4/Makefile +wpa_supplicant/wpa_gui-qt4/wpa_gui +hostapd/hostapd +hostapd/hostapd_cli +hostapd/hlr_auc_gw +hostapd/nt_password_hash diff --git a/Android.mk b/libeap/Android.mk similarity index 100% rename from Android.mk rename to libeap/Android.mk diff --git a/COPYING b/libeap/COPYING similarity index 100% rename from COPYING rename to libeap/COPYING diff --git a/libeap/Makefile.am b/libeap/Makefile.am new file mode 100644 index 0000000..890a9ea --- /dev/null +++ b/libeap/Makefile.am @@ -0,0 +1,212 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils @OPENSSL_CFLAGS@ +noinst_HEADERS = \ + src/common/defs.h \ + src/common/eapol_common.h \ + src/common/ieee802_11_common.h \ + src/common/ieee802_11_defs.h \ + src/common/privsep_commands.h \ + src/common/version.h \ + src/common/wpa_common.h \ + src/common/wpa_ctrl.h + +EXTRA_DIST = src/tls/libtommath.c \ + wpa_supplicant/README + +SOURCES_BOTH = src/eap_common/eap_peap_common.c +SOURCES_BOTH += src/eap_common/eap_psk_common.c +SOURCES_BOTH += src/eap_common/eap_pax_common.c +SOURCES_BOTH += src/eap_common/eap_sake_common.c +SOURCES_BOTH += src/eap_common/eap_gpsk_common.c +SOURCES_BOTH += src/eap_common/chap.c \ + src/eap_common/chap.h \ + src/eap_common/eap_common.h \ + src/eap_common/eap_defs.h \ + src/eap_common/eap_fast_common.h \ + src/eap_common/eap_gpsk_common.h \ + src/eap_common/eap_ikev2_common.h \ + src/eap_common/eap_pax_common.h \ + src/eap_common/eap_peap_common.h \ + src/eap_common/eap_psk_common.h \ + src/eap_common/eap_pwd_common.h \ + src/eap_common/eap_sake_common.h \ + src/eap_common/eap_sim_common.h \ + src/eap_common/eap_tlv_common.h \ + src/eap_common/eap_ttls.h \ + src/eap_common/eap_wsc_common.h \ + src/eap_common/ikev2_common.h + + +SOURCES_peer = src/eap_peer/eap_tls.c +SOURCES_peer += src/eap_peer/eap_peap.c +SOURCES_peer += src/eap_peer/eap_ttls.c +SOURCES_peer += src/eap_peer/eap_md5.c +SOURCES_peer += src/eap_peer/eap_mschapv2.c +SOURCES_peer += src/eap_peer/mschapv2.c +SOURCES_peer += src/eap_peer/eap_otp.c +SOURCES_peer += src/eap_peer/eap_gtc.c +SOURCES_peer += src/eap_peer/eap_leap.c +SOURCES_peer += src/eap_peer/eap_psk.c +SOURCES_peer += src/eap_peer/eap_pax.c +SOURCES_peer += src/eap_peer/eap_sake.c +SOURCES_peer += src/eap_peer/eap_gpsk.c +SOURCES_peer += src/eap_peer/eap.c +SOURCES_peer += src/eap_common/eap_common.c +SOURCES_peer += src/eap_peer/eap_methods.c +SOURCES_peer += src/eap_peer/eap_tls_common.c \ + src/eap_peer/eap_config.h \ + src/eap_peer/eap_fast_pac.h \ + src/eap_peer/eap.h \ + src/eap_peer/eap_i.h \ + src/eap_peer/eap_methods.h \ + src/eap_peer/eap_tls_common.h \ + src/eap_peer/ikev2.h \ + src/eap_peer/mschapv2.h \ + src/eap_peer/tncc.h \ + src/radius/radius.h + + +AM_CFLAGS = -DEAP_TLS +AM_CFLAGS += -DEAP_PEAP +AM_CFLAGS += -DEAP_TTLS +AM_CFLAGS += -DEAP_MD5 +AM_CFLAGS += -DEAP_MSCHAPv2 +AM_CFLAGS += -DEAP_GTC +AM_CFLAGS += -DEAP_OTP +AM_CFLAGS += -DEAP_LEAP +AM_CFLAGS += -DEAP_PSK +AM_CFLAGS += -DEAP_PAX +AM_CFLAGS += -DEAP_SAKE +AM_CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256 + +AM_CFLAGS += -DEAP_SERVER_IDENTITY +AM_CFLAGS += -DEAP_SERVER_TLS +AM_CFLAGS += -DEAP_SERVER_PEAP +AM_CFLAGS += -DEAP_SERVER_TTLS +AM_CFLAGS += -DEAP_SERVER_MD5 +AM_CFLAGS += -DEAP_SERVER_MSCHAPV2 +AM_CFLAGS += -DEAP_SERVER_GTC +AM_CFLAGS += -DEAP_SERVER_PSK +AM_CFLAGS += -DEAP_SERVER_PAX +AM_CFLAGS += -DEAP_SERVER_SAKE +AM_CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256 + +AM_CFLAGS += -DIEEE8021X_EAPOL +AM_CFLAGS += -DCONFIG_IPV6 +AM_CFLAGS += -DCONFIG_DEBUG_FILE +AM_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +AM_CFLAGS += -DCONFIG_INTERNAL_SHA1 +AM_CFLAGS += -DEAP_TLS_OPENSSL +AM_CFLAGS += -DPKCS12_FUNCS +AM_CFLAGS += -DCONFIG_SHA256 + +UTILS_SRCS = src/utils/base64.c \ + src/utils/common.c \ + src/utils/ip_addr.c \ + src/utils/radiotap.c \ + src/utils/trace.c \ + src/utils/uuid.c \ + src/utils/wpa_debug.c \ + src/utils/wpabuf.c \ + src/utils/os_unix.c \ + src/utils/radius_utils.c \ +src/utils/radius_utils.h \ + src/utils/base64.h \ + src/utils/build_config.h \ + src/utils/common.h \ + src/utils/eloop.h \ + src/utils/includes.h \ + src/utils/ip_addr.h \ + src/utils/list.h \ + src/utils/os.h \ + src/utils/pcsc_funcs.h \ + src/utils/radiotap.h \ + src/utils/radiotap_iter.h \ + src/utils/state_machine.h \ + src/utils/trace.h \ + src/utils/uuid.h \ + src/utils/wpabuf.h \ + src/utils/wpa_debug.h + + +CRYPTO_SRCS = \ + src/crypto/aes-cbc.c \ + src/crypto/aes-ccm.c \ + src/crypto/aes-ctr.c \ + src/crypto/aes-eax.c \ + src/crypto/aes-encblock.c \ + src/crypto/aes-gcm.c \ + src/crypto/aes-internal.c \ + src/crypto/aes-internal-dec.c \ + src/crypto/aes-internal-enc.c \ + src/crypto/aes-omac1.c \ + src/crypto/aes-siv.c \ + src/crypto/aes-siv.h \ + src/crypto/aes-unwrap.c \ + src/crypto/aes-wrap.c \ + src/crypto/aes.h \ + src/crypto/aes_i.h \ + src/crypto/aes_wrap.h \ + src/crypto/crypto.h \ + src/crypto/des-internal.c \ + src/crypto/dh_group5.h \ + src/crypto/dh_groups.h \ + src/crypto/md4-internal.c \ + src/crypto/md5.c \ + src/crypto/md5-internal.c \ + src/crypto/md5.h \ + src/crypto/milenage.c \ + src/crypto/milenage.h \ + src/crypto/ms_funcs.c \ + src/crypto/ms_funcs.h \ + src/crypto/rc4.c \ + src/crypto/sha1.c \ + src/crypto/sha1-internal.c \ + src/crypto/sha1-pbkdf2.c \ + src/crypto/sha1-prf.c \ + src/crypto/sha1-tlsprf.c \ + src/crypto/sha1-tprf.c \ + src/crypto/sha256-prf.c \ + src/crypto/sha256-tlsprf.c \ + src/crypto/sha256.c \ + src/crypto/sha256.h \ + src/crypto/sha256_i.h \ + src/crypto/tls.h + + +TLS_SRCS = \ + src/tls/asn1.c \ + src/tls/bignum.c \ + src/tls/pkcs1.c \ + src/tls/pkcs5.c \ + src/tls/pkcs8.c \ + src/tls/rsa.c \ + src/tls/tlsv1_client.c \ + src/tls/tlsv1_client_read.c \ + src/tls/tlsv1_client_write.c \ + src/tls/tlsv1_common.c \ + src/tls/tlsv1_cred.c \ + src/tls/tlsv1_record.c \ + src/tls/tlsv1_server.c \ + src/tls/tlsv1_server_read.c \ + src/tls/tlsv1_server_write.c \ + src/tls/x509v3.c \ + src/tls/asn1.h \ + src/tls/bignum.h \ + src/tls/pkcs1.h \ + src/tls/pkcs5.h \ + src/tls/pkcs8.h \ + src/tls/rsa.h \ + src/tls/tlsv1_client.h \ + src/tls/tlsv1_client_i.h \ + src/tls/tlsv1_common.h \ + src/tls/tlsv1_cred.h \ + src/tls/tlsv1_record.h \ + src/tls/tlsv1_server.h \ + src/tls/tlsv1_server_i.h \ + src/tls/x509v3.h + +libeap_la_SOURCES = $(SOURCES_BOTH) $(SOURCES_peer) $(UTILS_SRCS) $(CRYPTO_SRCS) + +noinst_LTLIBRARIES = libeap.la diff --git a/README b/libeap/README similarity index 100% rename from README rename to libeap/README diff --git a/build_release b/libeap/build_release similarity index 100% rename from build_release rename to libeap/build_release diff --git a/doc/.gitignore b/libeap/doc/.gitignore similarity index 100% rename from doc/.gitignore rename to libeap/doc/.gitignore diff --git a/doc/Makefile b/libeap/doc/Makefile similarity index 100% rename from doc/Makefile rename to libeap/doc/Makefile diff --git a/doc/code_structure.doxygen b/libeap/doc/code_structure.doxygen similarity index 100% rename from doc/code_structure.doxygen rename to libeap/doc/code_structure.doxygen diff --git a/doc/ctrl_iface.doxygen b/libeap/doc/ctrl_iface.doxygen similarity index 100% rename from doc/ctrl_iface.doxygen rename to libeap/doc/ctrl_iface.doxygen diff --git a/doc/dbus.doxygen b/libeap/doc/dbus.doxygen similarity index 100% rename from doc/dbus.doxygen rename to libeap/doc/dbus.doxygen diff --git a/doc/directories.doxygen b/libeap/doc/directories.doxygen similarity index 100% rename from doc/directories.doxygen rename to libeap/doc/directories.doxygen diff --git a/doc/doxygen.conf b/libeap/doc/doxygen.conf similarity index 100% rename from doc/doxygen.conf rename to libeap/doc/doxygen.conf diff --git a/doc/driver_wrapper.doxygen b/libeap/doc/driver_wrapper.doxygen similarity index 100% rename from doc/driver_wrapper.doxygen rename to libeap/doc/driver_wrapper.doxygen diff --git a/doc/eap.doxygen b/libeap/doc/eap.doxygen similarity index 100% rename from doc/eap.doxygen rename to libeap/doc/eap.doxygen diff --git a/doc/eap_server.doxygen b/libeap/doc/eap_server.doxygen similarity index 100% rename from doc/eap_server.doxygen rename to libeap/doc/eap_server.doxygen diff --git a/doc/hostapd.fig b/libeap/doc/hostapd.fig similarity index 100% rename from doc/hostapd.fig rename to libeap/doc/hostapd.fig diff --git a/doc/hostapd_ctrl_iface.doxygen b/libeap/doc/hostapd_ctrl_iface.doxygen similarity index 100% rename from doc/hostapd_ctrl_iface.doxygen rename to libeap/doc/hostapd_ctrl_iface.doxygen diff --git a/doc/mainpage.doxygen b/libeap/doc/mainpage.doxygen similarity index 100% rename from doc/mainpage.doxygen rename to libeap/doc/mainpage.doxygen diff --git a/doc/p2p.doxygen b/libeap/doc/p2p.doxygen similarity index 100% rename from doc/p2p.doxygen rename to libeap/doc/p2p.doxygen diff --git a/doc/p2p_arch.dot b/libeap/doc/p2p_arch.dot similarity index 100% rename from doc/p2p_arch.dot rename to libeap/doc/p2p_arch.dot diff --git a/doc/p2p_arch2.dot b/libeap/doc/p2p_arch2.dot similarity index 100% rename from doc/p2p_arch2.dot rename to libeap/doc/p2p_arch2.dot diff --git a/doc/p2p_sm.dot b/libeap/doc/p2p_sm.dot similarity index 100% rename from doc/p2p_sm.dot rename to libeap/doc/p2p_sm.dot diff --git a/doc/porting.doxygen b/libeap/doc/porting.doxygen similarity index 100% rename from doc/porting.doxygen rename to libeap/doc/porting.doxygen diff --git a/doc/testing_tools.doxygen b/libeap/doc/testing_tools.doxygen similarity index 100% rename from doc/testing_tools.doxygen rename to libeap/doc/testing_tools.doxygen diff --git a/doc/wpa_supplicant.fig b/libeap/doc/wpa_supplicant.fig similarity index 100% rename from doc/wpa_supplicant.fig rename to libeap/doc/wpa_supplicant.fig diff --git a/eap_example/.gitignore b/libeap/eap_example/.gitignore similarity index 100% rename from eap_example/.gitignore rename to libeap/eap_example/.gitignore diff --git a/libeap/eap_example/Makefile b/libeap/eap_example/Makefile new file mode 100644 index 0000000..4edfee1 --- /dev/null +++ b/libeap/eap_example/Makefile @@ -0,0 +1,152 @@ +ALL=eap_example + +all: $(ALL) + + +CC=gcc -fPIC + + +ifndef RANLIB +RANLIB=ranlib +endif + +ifndef CFLAGS +CFLAGS = -MMD -O2 -Wall -g -fPIC +endif + + +CFLAGS += -I. +CFLAGS += -I../src +CFLAGS += -I../src/utils + + +OBJS_both += ../src/utils/libutils.a +OBJS_both += ../src/crypto/libcrypto.a +OBJS_both += ../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 + + +ifndef LDO +LDO=$(CC) +endif + +Q=@ +E=echo +ifeq ($(V), 1) +Q= +E=true +endif + +%.o: %.c + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + @$(E) " CC " $< + + +OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server) + +OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o + + +../src/utils/libutils.a: + $(MAKE) -C ../src/utils + +../src/crypto/libcrypto.a: + $(MAKE) -C ../src/crypto + +../src/tls/libtls.a: + $(MAKE) -C ../src/tls + + +ifneq ($(CONFIG_SOLIB), yes) +LIBEAP = libeap.a +libeap.a: $(OBJS_lib) + $(AR) crT libeap.a $(OBJS_lib) + $(RANLIB) libeap.a + +else +CFLAGS += -fPIC -DPIC +LDFLAGS += -shared + +LIBEAP = libeap.so +libeap.so: $(OBJS_lib) + $(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP) + +endif + +eap_example: $(OBJS_ex) $(LIBEAP) + $(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS) + +clean: + $(MAKE) -C ../src clean + rm -f core *~ *.o *.d libeap.a libeap.so $(ALL) + +-include $(OBJS:%.o=%.d) diff --git a/eap_example/README b/libeap/eap_example/README similarity index 100% rename from eap_example/README rename to libeap/eap_example/README diff --git a/eap_example/ca.pem b/libeap/eap_example/ca.pem similarity index 100% rename from eap_example/ca.pem rename to libeap/eap_example/ca.pem diff --git a/tests/hwsim/auth_serv/dh.conf b/libeap/eap_example/dh.conf similarity index 100% rename from tests/hwsim/auth_serv/dh.conf rename to libeap/eap_example/dh.conf diff --git a/eap_example/eap_example.c b/libeap/eap_example/eap_example.c similarity index 100% rename from eap_example/eap_example.c rename to libeap/eap_example/eap_example.c diff --git a/eap_example/eap_example_peer.c b/libeap/eap_example/eap_example_peer.c similarity index 100% rename from eap_example/eap_example_peer.c rename to libeap/eap_example/eap_example_peer.c diff --git a/eap_example/eap_example_server.c b/libeap/eap_example/eap_example_server.c similarity index 100% rename from eap_example/eap_example_server.c rename to libeap/eap_example/eap_example_server.c diff --git a/eap_example/server-key.pem b/libeap/eap_example/server-key.pem similarity index 100% rename from eap_example/server-key.pem rename to libeap/eap_example/server-key.pem diff --git a/eap_example/server.key b/libeap/eap_example/server.key similarity index 100% rename from eap_example/server.key rename to libeap/eap_example/server.key diff --git a/eap_example/server.pem b/libeap/eap_example/server.pem similarity index 100% rename from eap_example/server.pem rename to libeap/eap_example/server.pem diff --git a/hostapd/Android.mk b/libeap/hostapd/Android.mk similarity index 100% rename from hostapd/Android.mk rename to libeap/hostapd/Android.mk diff --git a/hostapd/ChangeLog b/libeap/hostapd/ChangeLog similarity index 100% rename from hostapd/ChangeLog rename to libeap/hostapd/ChangeLog diff --git a/hostapd/Makefile b/libeap/hostapd/Makefile similarity index 100% rename from hostapd/Makefile rename to libeap/hostapd/Makefile diff --git a/hostapd/README b/libeap/hostapd/README similarity index 100% rename from hostapd/README rename to libeap/hostapd/README diff --git a/hostapd/README-WPS b/libeap/hostapd/README-WPS similarity index 100% rename from hostapd/README-WPS rename to libeap/hostapd/README-WPS diff --git a/hostapd/android.config b/libeap/hostapd/android.config similarity index 100% rename from hostapd/android.config rename to libeap/hostapd/android.config diff --git a/hostapd/config_file.c b/libeap/hostapd/config_file.c similarity index 100% rename from hostapd/config_file.c rename to libeap/hostapd/config_file.c diff --git a/hostapd/config_file.h b/libeap/hostapd/config_file.h similarity index 100% rename from hostapd/config_file.h rename to libeap/hostapd/config_file.h diff --git a/hostapd/ctrl_iface.c b/libeap/hostapd/ctrl_iface.c similarity index 100% rename from hostapd/ctrl_iface.c rename to libeap/hostapd/ctrl_iface.c diff --git a/hostapd/ctrl_iface.h b/libeap/hostapd/ctrl_iface.h similarity index 100% rename from hostapd/ctrl_iface.h rename to libeap/hostapd/ctrl_iface.h diff --git a/hostapd/defconfig b/libeap/hostapd/defconfig similarity index 100% rename from hostapd/defconfig rename to libeap/hostapd/defconfig diff --git a/hostapd/eap_register.c b/libeap/hostapd/eap_register.c similarity index 100% rename from hostapd/eap_register.c rename to libeap/hostapd/eap_register.c diff --git a/hostapd/eap_register.h b/libeap/hostapd/eap_register.h similarity index 100% rename from hostapd/eap_register.h rename to libeap/hostapd/eap_register.h diff --git a/hostapd/eap_testing.txt b/libeap/hostapd/eap_testing.txt similarity index 100% rename from hostapd/eap_testing.txt rename to libeap/hostapd/eap_testing.txt diff --git a/hostapd/hapd_module_tests.c b/libeap/hostapd/hapd_module_tests.c similarity index 100% rename from hostapd/hapd_module_tests.c rename to libeap/hostapd/hapd_module_tests.c diff --git a/hostapd/hlr_auc_gw.c b/libeap/hostapd/hlr_auc_gw.c similarity index 100% rename from hostapd/hlr_auc_gw.c rename to libeap/hostapd/hlr_auc_gw.c diff --git a/hostapd/hlr_auc_gw.milenage_db b/libeap/hostapd/hlr_auc_gw.milenage_db similarity index 100% rename from hostapd/hlr_auc_gw.milenage_db rename to libeap/hostapd/hlr_auc_gw.milenage_db diff --git a/hostapd/hlr_auc_gw.txt b/libeap/hostapd/hlr_auc_gw.txt similarity index 100% rename from hostapd/hlr_auc_gw.txt rename to libeap/hostapd/hlr_auc_gw.txt diff --git a/hostapd/hostapd.8 b/libeap/hostapd/hostapd.8 similarity index 100% rename from hostapd/hostapd.8 rename to libeap/hostapd/hostapd.8 diff --git a/hostapd/hostapd.accept b/libeap/hostapd/hostapd.accept similarity index 100% rename from hostapd/hostapd.accept rename to libeap/hostapd/hostapd.accept diff --git a/hostapd/hostapd.conf b/libeap/hostapd/hostapd.conf similarity index 100% rename from hostapd/hostapd.conf rename to libeap/hostapd/hostapd.conf diff --git a/hostapd/hostapd.deny b/libeap/hostapd/hostapd.deny similarity index 100% rename from hostapd/hostapd.deny rename to libeap/hostapd/hostapd.deny diff --git a/hostapd/hostapd.eap_user b/libeap/hostapd/hostapd.eap_user similarity index 100% rename from hostapd/hostapd.eap_user rename to libeap/hostapd/hostapd.eap_user diff --git a/hostapd/hostapd.eap_user_sqlite b/libeap/hostapd/hostapd.eap_user_sqlite similarity index 100% rename from hostapd/hostapd.eap_user_sqlite rename to libeap/hostapd/hostapd.eap_user_sqlite diff --git a/hostapd/hostapd.radius_clients b/libeap/hostapd/hostapd.radius_clients similarity index 100% rename from hostapd/hostapd.radius_clients rename to libeap/hostapd/hostapd.radius_clients diff --git a/hostapd/hostapd.sim_db b/libeap/hostapd/hostapd.sim_db similarity index 100% rename from hostapd/hostapd.sim_db rename to libeap/hostapd/hostapd.sim_db diff --git a/hostapd/hostapd.vlan b/libeap/hostapd/hostapd.vlan similarity index 100% rename from hostapd/hostapd.vlan rename to libeap/hostapd/hostapd.vlan diff --git a/hostapd/hostapd.wpa_psk b/libeap/hostapd/hostapd.wpa_psk similarity index 100% rename from hostapd/hostapd.wpa_psk rename to libeap/hostapd/hostapd.wpa_psk diff --git a/hostapd/hostapd_cli.1 b/libeap/hostapd/hostapd_cli.1 similarity index 100% rename from hostapd/hostapd_cli.1 rename to libeap/hostapd/hostapd_cli.1 diff --git a/hostapd/hostapd_cli.c b/libeap/hostapd/hostapd_cli.c similarity index 100% rename from hostapd/hostapd_cli.c rename to libeap/hostapd/hostapd_cli.c diff --git a/hostapd/logwatch/README b/libeap/hostapd/logwatch/README similarity index 100% rename from hostapd/logwatch/README rename to libeap/hostapd/logwatch/README diff --git a/hostapd/logwatch/hostapd b/libeap/hostapd/logwatch/hostapd similarity index 100% rename from hostapd/logwatch/hostapd rename to libeap/hostapd/logwatch/hostapd diff --git a/hostapd/logwatch/hostapd.conf b/libeap/hostapd/logwatch/hostapd.conf similarity index 100% rename from hostapd/logwatch/hostapd.conf rename to libeap/hostapd/logwatch/hostapd.conf diff --git a/hostapd/main.c b/libeap/hostapd/main.c similarity index 100% rename from hostapd/main.c rename to libeap/hostapd/main.c diff --git a/hostapd/nt_password_hash.c b/libeap/hostapd/nt_password_hash.c similarity index 100% rename from hostapd/nt_password_hash.c rename to libeap/hostapd/nt_password_hash.c diff --git a/hostapd/wired.conf b/libeap/hostapd/wired.conf similarity index 100% rename from hostapd/wired.conf rename to libeap/hostapd/wired.conf diff --git a/hostapd/wps-ap-nfc.py b/libeap/hostapd/wps-ap-nfc.py similarity index 100% rename from hostapd/wps-ap-nfc.py rename to libeap/hostapd/wps-ap-nfc.py diff --git a/hs20/client/Android.mk b/libeap/hs20/client/Android.mk similarity index 100% rename from hs20/client/Android.mk rename to libeap/hs20/client/Android.mk diff --git a/hs20/client/Makefile b/libeap/hs20/client/Makefile similarity index 100% rename from hs20/client/Makefile rename to libeap/hs20/client/Makefile diff --git a/hs20/client/devdetail.xml b/libeap/hs20/client/devdetail.xml similarity index 100% rename from hs20/client/devdetail.xml rename to libeap/hs20/client/devdetail.xml diff --git a/hs20/client/devinfo.xml b/libeap/hs20/client/devinfo.xml similarity index 100% rename from hs20/client/devinfo.xml rename to libeap/hs20/client/devinfo.xml diff --git a/hs20/client/est.c b/libeap/hs20/client/est.c similarity index 100% rename from hs20/client/est.c rename to libeap/hs20/client/est.c diff --git a/hs20/client/oma_dm_client.c b/libeap/hs20/client/oma_dm_client.c similarity index 100% rename from hs20/client/oma_dm_client.c rename to libeap/hs20/client/oma_dm_client.c diff --git a/hs20/client/osu_client.c b/libeap/hs20/client/osu_client.c similarity index 100% rename from hs20/client/osu_client.c rename to libeap/hs20/client/osu_client.c diff --git a/hs20/client/osu_client.h b/libeap/hs20/client/osu_client.h similarity index 100% rename from hs20/client/osu_client.h rename to libeap/hs20/client/osu_client.h diff --git a/hs20/client/spp_client.c b/libeap/hs20/client/spp_client.c similarity index 100% rename from hs20/client/spp_client.c rename to libeap/hs20/client/spp_client.c diff --git a/hs20/server/Makefile b/libeap/hs20/server/Makefile similarity index 100% rename from hs20/server/Makefile rename to libeap/hs20/server/Makefile diff --git a/hs20/server/ca/clean.sh b/libeap/hs20/server/ca/clean.sh similarity index 100% rename from hs20/server/ca/clean.sh rename to libeap/hs20/server/ca/clean.sh diff --git a/hs20/server/ca/est-csrattrs.cnf b/libeap/hs20/server/ca/est-csrattrs.cnf similarity index 100% rename from hs20/server/ca/est-csrattrs.cnf rename to libeap/hs20/server/ca/est-csrattrs.cnf diff --git a/hs20/server/ca/est-csrattrs.sh b/libeap/hs20/server/ca/est-csrattrs.sh similarity index 100% rename from hs20/server/ca/est-csrattrs.sh rename to libeap/hs20/server/ca/est-csrattrs.sh diff --git a/hs20/server/ca/hs20.oid b/libeap/hs20/server/ca/hs20.oid similarity index 100% rename from hs20/server/ca/hs20.oid rename to libeap/hs20/server/ca/hs20.oid diff --git a/hs20/server/ca/ocsp-req.sh b/libeap/hs20/server/ca/ocsp-req.sh similarity index 100% rename from hs20/server/ca/ocsp-req.sh rename to libeap/hs20/server/ca/ocsp-req.sh diff --git a/hs20/server/ca/ocsp-responder-ica.sh b/libeap/hs20/server/ca/ocsp-responder-ica.sh similarity index 100% rename from hs20/server/ca/ocsp-responder-ica.sh rename to libeap/hs20/server/ca/ocsp-responder-ica.sh diff --git a/hs20/server/ca/ocsp-responder.sh b/libeap/hs20/server/ca/ocsp-responder.sh similarity index 100% rename from hs20/server/ca/ocsp-responder.sh rename to libeap/hs20/server/ca/ocsp-responder.sh diff --git a/hs20/server/ca/ocsp-update-cache.sh b/libeap/hs20/server/ca/ocsp-update-cache.sh similarity index 100% rename from hs20/server/ca/ocsp-update-cache.sh rename to libeap/hs20/server/ca/ocsp-update-cache.sh diff --git a/hs20/server/ca/openssl-root.cnf b/libeap/hs20/server/ca/openssl-root.cnf similarity index 100% rename from hs20/server/ca/openssl-root.cnf rename to libeap/hs20/server/ca/openssl-root.cnf diff --git a/hs20/server/ca/openssl.cnf b/libeap/hs20/server/ca/openssl.cnf similarity index 100% rename from hs20/server/ca/openssl.cnf rename to libeap/hs20/server/ca/openssl.cnf diff --git a/hs20/server/ca/setup.sh b/libeap/hs20/server/ca/setup.sh similarity index 100% rename from hs20/server/ca/setup.sh rename to libeap/hs20/server/ca/setup.sh diff --git a/tests/hwsim/w1fi_logo.png b/libeap/hs20/server/ca/w1fi_logo.png similarity index 100% rename from tests/hwsim/w1fi_logo.png rename to libeap/hs20/server/ca/w1fi_logo.png diff --git a/hs20/server/hs20-osu-server.txt b/libeap/hs20/server/hs20-osu-server.txt similarity index 100% rename from hs20/server/hs20-osu-server.txt rename to libeap/hs20/server/hs20-osu-server.txt diff --git a/hs20/server/hs20_spp_server.c b/libeap/hs20/server/hs20_spp_server.c similarity index 100% rename from hs20/server/hs20_spp_server.c rename to libeap/hs20/server/hs20_spp_server.c diff --git a/hs20/server/spp_server.c b/libeap/hs20/server/spp_server.c similarity index 100% rename from hs20/server/spp_server.c rename to libeap/hs20/server/spp_server.c diff --git a/hs20/server/spp_server.h b/libeap/hs20/server/spp_server.h similarity index 100% rename from hs20/server/spp_server.h rename to libeap/hs20/server/spp_server.h diff --git a/hs20/server/sql-example.txt b/libeap/hs20/server/sql-example.txt similarity index 100% rename from hs20/server/sql-example.txt rename to libeap/hs20/server/sql-example.txt diff --git a/hs20/server/sql.txt b/libeap/hs20/server/sql.txt similarity index 100% rename from hs20/server/sql.txt rename to libeap/hs20/server/sql.txt diff --git a/hs20/server/www/add-free.php b/libeap/hs20/server/www/add-free.php similarity index 100% rename from hs20/server/www/add-free.php rename to libeap/hs20/server/www/add-free.php diff --git a/hs20/server/www/add-mo.php b/libeap/hs20/server/www/add-mo.php similarity index 100% rename from hs20/server/www/add-mo.php rename to libeap/hs20/server/www/add-mo.php diff --git a/hs20/server/www/cert-enroll.php b/libeap/hs20/server/www/cert-enroll.php similarity index 100% rename from hs20/server/www/cert-enroll.php rename to libeap/hs20/server/www/cert-enroll.php diff --git a/hs20/server/www/config.php b/libeap/hs20/server/www/config.php similarity index 100% rename from hs20/server/www/config.php rename to libeap/hs20/server/www/config.php diff --git a/hs20/server/www/est.php b/libeap/hs20/server/www/est.php similarity index 100% rename from hs20/server/www/est.php rename to libeap/hs20/server/www/est.php diff --git a/hs20/server/www/free-remediation.php b/libeap/hs20/server/www/free-remediation.php similarity index 100% rename from hs20/server/www/free-remediation.php rename to libeap/hs20/server/www/free-remediation.php diff --git a/hs20/server/www/free.php b/libeap/hs20/server/www/free.php similarity index 100% rename from hs20/server/www/free.php rename to libeap/hs20/server/www/free.php diff --git a/hs20/server/www/redirect.php b/libeap/hs20/server/www/redirect.php similarity index 100% rename from hs20/server/www/redirect.php rename to libeap/hs20/server/www/redirect.php diff --git a/hs20/server/www/remediation.php b/libeap/hs20/server/www/remediation.php similarity index 100% rename from hs20/server/www/remediation.php rename to libeap/hs20/server/www/remediation.php diff --git a/hs20/server/www/signup.php b/libeap/hs20/server/www/signup.php similarity index 100% rename from hs20/server/www/signup.php rename to libeap/hs20/server/www/signup.php diff --git a/hs20/server/www/spp.php b/libeap/hs20/server/www/spp.php similarity index 100% rename from hs20/server/www/spp.php rename to libeap/hs20/server/www/spp.php diff --git a/hs20/server/www/users.php b/libeap/hs20/server/www/users.php similarity index 100% rename from hs20/server/www/users.php rename to libeap/hs20/server/www/users.php diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf similarity index 100% rename from mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf rename to libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/test.txt b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt similarity index 100% rename from mac80211_hwsim/tests/0001-wpa2-psk/test.txt rename to libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt diff --git a/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf similarity index 100% rename from mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf rename to libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.accept b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/hostapd.accept rename to libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.conf b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/hostapd.conf rename to libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf diff --git a/mac80211_hwsim/tests/0002-vlan/hostapd.vlan b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/hostapd.vlan rename to libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan diff --git a/mac80211_hwsim/tests/0002-vlan/test.txt b/libeap/mac80211_hwsim/tests/0002-vlan/test.txt similarity index 100% rename from mac80211_hwsim/tests/0002-vlan/test.txt rename to libeap/mac80211_hwsim/tests/0002-vlan/test.txt diff --git a/mac80211_hwsim/tools/Makefile b/libeap/mac80211_hwsim/tools/Makefile similarity index 100% rename from mac80211_hwsim/tools/Makefile rename to libeap/mac80211_hwsim/tools/Makefile diff --git a/mac80211_hwsim/tools/hwsim_test.c b/libeap/mac80211_hwsim/tools/hwsim_test.c similarity index 100% rename from mac80211_hwsim/tools/hwsim_test.c rename to libeap/mac80211_hwsim/tools/hwsim_test.c diff --git a/patches/openssl-0.9.8za-tls-extensions.patch b/libeap/patches/openssl-0.9.8za-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8za-tls-extensions.patch rename to libeap/patches/openssl-0.9.8za-tls-extensions.patch diff --git a/patches/openssl-0.9.8zf-tls-extensions.patch b/libeap/patches/openssl-0.9.8zf-tls-extensions.patch similarity index 100% rename from patches/openssl-0.9.8zf-tls-extensions.patch rename to libeap/patches/openssl-0.9.8zf-tls-extensions.patch diff --git a/radius_example/.gitignore b/libeap/radius_example/.gitignore similarity index 100% rename from radius_example/.gitignore rename to libeap/radius_example/.gitignore diff --git a/radius_example/Makefile b/libeap/radius_example/Makefile similarity index 100% rename from radius_example/Makefile rename to libeap/radius_example/Makefile diff --git a/radius_example/README b/libeap/radius_example/README similarity index 100% rename from radius_example/README rename to libeap/radius_example/README diff --git a/radius_example/radius_example.c b/libeap/radius_example/radius_example.c similarity index 100% rename from radius_example/radius_example.c rename to libeap/radius_example/radius_example.c diff --git a/src/Makefile b/libeap/src/Makefile similarity index 100% rename from src/Makefile rename to libeap/src/Makefile diff --git a/src/ap/Makefile b/libeap/src/ap/Makefile similarity index 100% rename from src/ap/Makefile rename to libeap/src/ap/Makefile diff --git a/src/ap/accounting.c b/libeap/src/ap/accounting.c similarity index 100% rename from src/ap/accounting.c rename to libeap/src/ap/accounting.c diff --git a/src/ap/accounting.h b/libeap/src/ap/accounting.h similarity index 100% rename from src/ap/accounting.h rename to libeap/src/ap/accounting.h diff --git a/src/ap/acs.c b/libeap/src/ap/acs.c similarity index 100% rename from src/ap/acs.c rename to libeap/src/ap/acs.c diff --git a/src/ap/acs.h b/libeap/src/ap/acs.h similarity index 100% rename from src/ap/acs.h rename to libeap/src/ap/acs.h diff --git a/src/ap/ap_config.c b/libeap/src/ap/ap_config.c similarity index 100% rename from src/ap/ap_config.c rename to libeap/src/ap/ap_config.c diff --git a/src/ap/ap_config.h b/libeap/src/ap/ap_config.h similarity index 100% rename from src/ap/ap_config.h rename to libeap/src/ap/ap_config.h diff --git a/src/ap/ap_drv_ops.c b/libeap/src/ap/ap_drv_ops.c similarity index 100% rename from src/ap/ap_drv_ops.c rename to libeap/src/ap/ap_drv_ops.c diff --git a/src/ap/ap_drv_ops.h b/libeap/src/ap/ap_drv_ops.h similarity index 100% rename from src/ap/ap_drv_ops.h rename to libeap/src/ap/ap_drv_ops.h diff --git a/src/ap/ap_list.c b/libeap/src/ap/ap_list.c similarity index 100% rename from src/ap/ap_list.c rename to libeap/src/ap/ap_list.c diff --git a/src/ap/ap_list.h b/libeap/src/ap/ap_list.h similarity index 100% rename from src/ap/ap_list.h rename to libeap/src/ap/ap_list.h diff --git a/src/ap/ap_mlme.c b/libeap/src/ap/ap_mlme.c similarity index 100% rename from src/ap/ap_mlme.c rename to libeap/src/ap/ap_mlme.c diff --git a/src/ap/ap_mlme.h b/libeap/src/ap/ap_mlme.h similarity index 100% rename from src/ap/ap_mlme.h rename to libeap/src/ap/ap_mlme.h diff --git a/src/ap/authsrv.c b/libeap/src/ap/authsrv.c similarity index 100% rename from src/ap/authsrv.c rename to libeap/src/ap/authsrv.c diff --git a/src/ap/authsrv.h b/libeap/src/ap/authsrv.h similarity index 100% rename from src/ap/authsrv.h rename to libeap/src/ap/authsrv.h diff --git a/src/ap/beacon.c b/libeap/src/ap/beacon.c similarity index 100% rename from src/ap/beacon.c rename to libeap/src/ap/beacon.c diff --git a/src/ap/beacon.h b/libeap/src/ap/beacon.h similarity index 100% rename from src/ap/beacon.h rename to libeap/src/ap/beacon.h diff --git a/src/ap/bss_load.c b/libeap/src/ap/bss_load.c similarity index 100% rename from src/ap/bss_load.c rename to libeap/src/ap/bss_load.c diff --git a/src/ap/bss_load.h b/libeap/src/ap/bss_load.h similarity index 100% rename from src/ap/bss_load.h rename to libeap/src/ap/bss_load.h diff --git a/src/ap/ctrl_iface_ap.c b/libeap/src/ap/ctrl_iface_ap.c similarity index 100% rename from src/ap/ctrl_iface_ap.c rename to libeap/src/ap/ctrl_iface_ap.c diff --git a/src/ap/ctrl_iface_ap.h b/libeap/src/ap/ctrl_iface_ap.h similarity index 100% rename from src/ap/ctrl_iface_ap.h rename to libeap/src/ap/ctrl_iface_ap.h diff --git a/src/ap/dfs.c b/libeap/src/ap/dfs.c similarity index 100% rename from src/ap/dfs.c rename to libeap/src/ap/dfs.c diff --git a/src/ap/dfs.h b/libeap/src/ap/dfs.h similarity index 100% rename from src/ap/dfs.h rename to libeap/src/ap/dfs.h diff --git a/src/ap/dhcp_snoop.c b/libeap/src/ap/dhcp_snoop.c similarity index 100% rename from src/ap/dhcp_snoop.c rename to libeap/src/ap/dhcp_snoop.c diff --git a/src/ap/dhcp_snoop.h b/libeap/src/ap/dhcp_snoop.h similarity index 100% rename from src/ap/dhcp_snoop.h rename to libeap/src/ap/dhcp_snoop.h diff --git a/src/ap/drv_callbacks.c b/libeap/src/ap/drv_callbacks.c similarity index 100% rename from src/ap/drv_callbacks.c rename to libeap/src/ap/drv_callbacks.c diff --git a/src/ap/eap_user_db.c b/libeap/src/ap/eap_user_db.c similarity index 100% rename from src/ap/eap_user_db.c rename to libeap/src/ap/eap_user_db.c diff --git a/src/ap/gas_serv.c b/libeap/src/ap/gas_serv.c similarity index 100% rename from src/ap/gas_serv.c rename to libeap/src/ap/gas_serv.c diff --git a/src/ap/gas_serv.h b/libeap/src/ap/gas_serv.h similarity index 100% rename from src/ap/gas_serv.h rename to libeap/src/ap/gas_serv.h diff --git a/src/ap/hostapd.c b/libeap/src/ap/hostapd.c similarity index 100% rename from src/ap/hostapd.c rename to libeap/src/ap/hostapd.c diff --git a/src/ap/hostapd.h b/libeap/src/ap/hostapd.h similarity index 100% rename from src/ap/hostapd.h rename to libeap/src/ap/hostapd.h diff --git a/src/ap/hs20.c b/libeap/src/ap/hs20.c similarity index 100% rename from src/ap/hs20.c rename to libeap/src/ap/hs20.c diff --git a/src/ap/hs20.h b/libeap/src/ap/hs20.h similarity index 100% rename from src/ap/hs20.h rename to libeap/src/ap/hs20.h diff --git a/src/ap/hw_features.c b/libeap/src/ap/hw_features.c similarity index 100% rename from src/ap/hw_features.c rename to libeap/src/ap/hw_features.c diff --git a/src/ap/hw_features.h b/libeap/src/ap/hw_features.h similarity index 100% rename from src/ap/hw_features.h rename to libeap/src/ap/hw_features.h diff --git a/src/ap/iapp.c b/libeap/src/ap/iapp.c similarity index 100% rename from src/ap/iapp.c rename to libeap/src/ap/iapp.c diff --git a/src/ap/iapp.h b/libeap/src/ap/iapp.h similarity index 100% rename from src/ap/iapp.h rename to libeap/src/ap/iapp.h diff --git a/src/ap/ieee802_11.c b/libeap/src/ap/ieee802_11.c similarity index 100% rename from src/ap/ieee802_11.c rename to libeap/src/ap/ieee802_11.c diff --git a/src/ap/ieee802_11.h b/libeap/src/ap/ieee802_11.h similarity index 100% rename from src/ap/ieee802_11.h rename to libeap/src/ap/ieee802_11.h diff --git a/src/ap/ieee802_11_auth.c b/libeap/src/ap/ieee802_11_auth.c similarity index 100% rename from src/ap/ieee802_11_auth.c rename to libeap/src/ap/ieee802_11_auth.c diff --git a/src/ap/ieee802_11_auth.h b/libeap/src/ap/ieee802_11_auth.h similarity index 100% rename from src/ap/ieee802_11_auth.h rename to libeap/src/ap/ieee802_11_auth.h diff --git a/src/ap/ieee802_11_ht.c b/libeap/src/ap/ieee802_11_ht.c similarity index 100% rename from src/ap/ieee802_11_ht.c rename to libeap/src/ap/ieee802_11_ht.c diff --git a/src/ap/ieee802_11_shared.c b/libeap/src/ap/ieee802_11_shared.c similarity index 100% rename from src/ap/ieee802_11_shared.c rename to libeap/src/ap/ieee802_11_shared.c diff --git a/src/ap/ieee802_11_vht.c b/libeap/src/ap/ieee802_11_vht.c similarity index 100% rename from src/ap/ieee802_11_vht.c rename to libeap/src/ap/ieee802_11_vht.c diff --git a/src/ap/ieee802_1x.c b/libeap/src/ap/ieee802_1x.c similarity index 100% rename from src/ap/ieee802_1x.c rename to libeap/src/ap/ieee802_1x.c diff --git a/src/ap/ieee802_1x.h b/libeap/src/ap/ieee802_1x.h similarity index 100% rename from src/ap/ieee802_1x.h rename to libeap/src/ap/ieee802_1x.h diff --git a/src/ap/ndisc_snoop.c b/libeap/src/ap/ndisc_snoop.c similarity index 100% rename from src/ap/ndisc_snoop.c rename to libeap/src/ap/ndisc_snoop.c diff --git a/src/ap/ndisc_snoop.h b/libeap/src/ap/ndisc_snoop.h similarity index 100% rename from src/ap/ndisc_snoop.h rename to libeap/src/ap/ndisc_snoop.h diff --git a/src/ap/p2p_hostapd.c b/libeap/src/ap/p2p_hostapd.c similarity index 100% rename from src/ap/p2p_hostapd.c rename to libeap/src/ap/p2p_hostapd.c diff --git a/src/ap/p2p_hostapd.h b/libeap/src/ap/p2p_hostapd.h similarity index 100% rename from src/ap/p2p_hostapd.h rename to libeap/src/ap/p2p_hostapd.h diff --git a/src/ap/peerkey_auth.c b/libeap/src/ap/peerkey_auth.c similarity index 100% rename from src/ap/peerkey_auth.c rename to libeap/src/ap/peerkey_auth.c diff --git a/src/ap/pmksa_cache_auth.c b/libeap/src/ap/pmksa_cache_auth.c similarity index 100% rename from src/ap/pmksa_cache_auth.c rename to libeap/src/ap/pmksa_cache_auth.c diff --git a/src/ap/pmksa_cache_auth.h b/libeap/src/ap/pmksa_cache_auth.h similarity index 100% rename from src/ap/pmksa_cache_auth.h rename to libeap/src/ap/pmksa_cache_auth.h diff --git a/src/ap/preauth_auth.c b/libeap/src/ap/preauth_auth.c similarity index 100% rename from src/ap/preauth_auth.c rename to libeap/src/ap/preauth_auth.c diff --git a/src/ap/preauth_auth.h b/libeap/src/ap/preauth_auth.h similarity index 100% rename from src/ap/preauth_auth.h rename to libeap/src/ap/preauth_auth.h diff --git a/src/ap/sta_info.c b/libeap/src/ap/sta_info.c similarity index 100% rename from src/ap/sta_info.c rename to libeap/src/ap/sta_info.c diff --git a/src/ap/sta_info.h b/libeap/src/ap/sta_info.h similarity index 100% rename from src/ap/sta_info.h rename to libeap/src/ap/sta_info.h diff --git a/src/ap/tkip_countermeasures.c b/libeap/src/ap/tkip_countermeasures.c similarity index 100% rename from src/ap/tkip_countermeasures.c rename to libeap/src/ap/tkip_countermeasures.c diff --git a/src/ap/tkip_countermeasures.h b/libeap/src/ap/tkip_countermeasures.h similarity index 100% rename from src/ap/tkip_countermeasures.h rename to libeap/src/ap/tkip_countermeasures.h diff --git a/src/ap/utils.c b/libeap/src/ap/utils.c similarity index 100% rename from src/ap/utils.c rename to libeap/src/ap/utils.c diff --git a/src/ap/vlan_init.c b/libeap/src/ap/vlan_init.c similarity index 100% rename from src/ap/vlan_init.c rename to libeap/src/ap/vlan_init.c diff --git a/src/ap/vlan_init.h b/libeap/src/ap/vlan_init.h similarity index 100% rename from src/ap/vlan_init.h rename to libeap/src/ap/vlan_init.h diff --git a/src/ap/vlan_util.c b/libeap/src/ap/vlan_util.c similarity index 100% rename from src/ap/vlan_util.c rename to libeap/src/ap/vlan_util.c diff --git a/src/ap/vlan_util.h b/libeap/src/ap/vlan_util.h similarity index 100% rename from src/ap/vlan_util.h rename to libeap/src/ap/vlan_util.h diff --git a/src/ap/wmm.c b/libeap/src/ap/wmm.c similarity index 100% rename from src/ap/wmm.c rename to libeap/src/ap/wmm.c diff --git a/src/ap/wmm.h b/libeap/src/ap/wmm.h similarity index 100% rename from src/ap/wmm.h rename to libeap/src/ap/wmm.h diff --git a/src/ap/wnm_ap.c b/libeap/src/ap/wnm_ap.c similarity index 100% rename from src/ap/wnm_ap.c rename to libeap/src/ap/wnm_ap.c diff --git a/src/ap/wnm_ap.h b/libeap/src/ap/wnm_ap.h similarity index 100% rename from src/ap/wnm_ap.h rename to libeap/src/ap/wnm_ap.h diff --git a/src/ap/wpa_auth.c b/libeap/src/ap/wpa_auth.c similarity index 100% rename from src/ap/wpa_auth.c rename to libeap/src/ap/wpa_auth.c diff --git a/src/ap/wpa_auth.h b/libeap/src/ap/wpa_auth.h similarity index 100% rename from src/ap/wpa_auth.h rename to libeap/src/ap/wpa_auth.h diff --git a/src/ap/wpa_auth_ft.c b/libeap/src/ap/wpa_auth_ft.c similarity index 100% rename from src/ap/wpa_auth_ft.c rename to libeap/src/ap/wpa_auth_ft.c diff --git a/src/ap/wpa_auth_glue.c b/libeap/src/ap/wpa_auth_glue.c similarity index 100% rename from src/ap/wpa_auth_glue.c rename to libeap/src/ap/wpa_auth_glue.c diff --git a/src/ap/wpa_auth_glue.h b/libeap/src/ap/wpa_auth_glue.h similarity index 100% rename from src/ap/wpa_auth_glue.h rename to libeap/src/ap/wpa_auth_glue.h diff --git a/src/ap/wpa_auth_i.h b/libeap/src/ap/wpa_auth_i.h similarity index 100% rename from src/ap/wpa_auth_i.h rename to libeap/src/ap/wpa_auth_i.h diff --git a/src/ap/wpa_auth_ie.c b/libeap/src/ap/wpa_auth_ie.c similarity index 100% rename from src/ap/wpa_auth_ie.c rename to libeap/src/ap/wpa_auth_ie.c diff --git a/src/ap/wpa_auth_ie.h b/libeap/src/ap/wpa_auth_ie.h similarity index 100% rename from src/ap/wpa_auth_ie.h rename to libeap/src/ap/wpa_auth_ie.h diff --git a/src/ap/wps_hostapd.c b/libeap/src/ap/wps_hostapd.c similarity index 100% rename from src/ap/wps_hostapd.c rename to libeap/src/ap/wps_hostapd.c diff --git a/src/ap/wps_hostapd.h b/libeap/src/ap/wps_hostapd.h similarity index 100% rename from src/ap/wps_hostapd.h rename to libeap/src/ap/wps_hostapd.h diff --git a/src/ap/x_snoop.c b/libeap/src/ap/x_snoop.c similarity index 100% rename from src/ap/x_snoop.c rename to libeap/src/ap/x_snoop.c diff --git a/src/ap/x_snoop.h b/libeap/src/ap/x_snoop.h similarity index 100% rename from src/ap/x_snoop.h rename to libeap/src/ap/x_snoop.h diff --git a/src/common/Makefile b/libeap/src/common/Makefile similarity index 100% rename from src/common/Makefile rename to libeap/src/common/Makefile diff --git a/src/common/common_module_tests.c b/libeap/src/common/common_module_tests.c similarity index 100% rename from src/common/common_module_tests.c rename to libeap/src/common/common_module_tests.c diff --git a/src/common/defs.h b/libeap/src/common/defs.h similarity index 100% rename from src/common/defs.h rename to libeap/src/common/defs.h diff --git a/src/common/eapol_common.h b/libeap/src/common/eapol_common.h similarity index 100% rename from src/common/eapol_common.h rename to libeap/src/common/eapol_common.h diff --git a/src/common/gas.c b/libeap/src/common/gas.c similarity index 100% rename from src/common/gas.c rename to libeap/src/common/gas.c diff --git a/src/common/gas.h b/libeap/src/common/gas.h similarity index 100% rename from src/common/gas.h rename to libeap/src/common/gas.h diff --git a/src/common/hw_features_common.c b/libeap/src/common/hw_features_common.c similarity index 100% rename from src/common/hw_features_common.c rename to libeap/src/common/hw_features_common.c diff --git a/src/common/hw_features_common.h b/libeap/src/common/hw_features_common.h similarity index 100% rename from src/common/hw_features_common.h rename to libeap/src/common/hw_features_common.h diff --git a/src/common/ieee802_11_common.c b/libeap/src/common/ieee802_11_common.c similarity index 100% rename from src/common/ieee802_11_common.c rename to libeap/src/common/ieee802_11_common.c diff --git a/src/common/ieee802_11_common.h b/libeap/src/common/ieee802_11_common.h similarity index 100% rename from src/common/ieee802_11_common.h rename to libeap/src/common/ieee802_11_common.h diff --git a/src/common/ieee802_11_defs.h b/libeap/src/common/ieee802_11_defs.h similarity index 100% rename from src/common/ieee802_11_defs.h rename to libeap/src/common/ieee802_11_defs.h diff --git a/src/common/ieee802_1x_defs.h b/libeap/src/common/ieee802_1x_defs.h similarity index 100% rename from src/common/ieee802_1x_defs.h rename to libeap/src/common/ieee802_1x_defs.h diff --git a/src/common/privsep_commands.h b/libeap/src/common/privsep_commands.h similarity index 100% rename from src/common/privsep_commands.h rename to libeap/src/common/privsep_commands.h diff --git a/src/common/qca-vendor-attr.h b/libeap/src/common/qca-vendor-attr.h similarity index 100% rename from src/common/qca-vendor-attr.h rename to libeap/src/common/qca-vendor-attr.h diff --git a/src/common/qca-vendor.h b/libeap/src/common/qca-vendor.h similarity index 100% rename from src/common/qca-vendor.h rename to libeap/src/common/qca-vendor.h diff --git a/src/common/sae.c b/libeap/src/common/sae.c similarity index 100% rename from src/common/sae.c rename to libeap/src/common/sae.c diff --git a/src/common/sae.h b/libeap/src/common/sae.h similarity index 100% rename from src/common/sae.h rename to libeap/src/common/sae.h diff --git a/src/common/tnc.h b/libeap/src/common/tnc.h similarity index 100% rename from src/common/tnc.h rename to libeap/src/common/tnc.h diff --git a/src/common/version.h b/libeap/src/common/version.h similarity index 100% rename from src/common/version.h rename to libeap/src/common/version.h diff --git a/src/common/wpa_common.c b/libeap/src/common/wpa_common.c similarity index 100% rename from src/common/wpa_common.c rename to libeap/src/common/wpa_common.c diff --git a/src/common/wpa_common.h b/libeap/src/common/wpa_common.h similarity index 100% rename from src/common/wpa_common.h rename to libeap/src/common/wpa_common.h diff --git a/src/common/wpa_ctrl.c b/libeap/src/common/wpa_ctrl.c similarity index 100% rename from src/common/wpa_ctrl.c rename to libeap/src/common/wpa_ctrl.c diff --git a/src/common/wpa_ctrl.h b/libeap/src/common/wpa_ctrl.h similarity index 100% rename from src/common/wpa_ctrl.h rename to libeap/src/common/wpa_ctrl.h diff --git a/src/common/wpa_helpers.c b/libeap/src/common/wpa_helpers.c similarity index 100% rename from src/common/wpa_helpers.c rename to libeap/src/common/wpa_helpers.c diff --git a/src/common/wpa_helpers.h b/libeap/src/common/wpa_helpers.h similarity index 100% rename from src/common/wpa_helpers.h rename to libeap/src/common/wpa_helpers.h diff --git a/src/crypto/.gitignore b/libeap/src/crypto/.gitignore similarity index 100% rename from src/crypto/.gitignore rename to libeap/src/crypto/.gitignore diff --git a/src/crypto/Makefile b/libeap/src/crypto/Makefile similarity index 100% rename from src/crypto/Makefile rename to libeap/src/crypto/Makefile diff --git a/src/crypto/aes-cbc.c b/libeap/src/crypto/aes-cbc.c similarity index 100% rename from src/crypto/aes-cbc.c rename to libeap/src/crypto/aes-cbc.c diff --git a/src/crypto/aes-ccm.c b/libeap/src/crypto/aes-ccm.c similarity index 100% rename from src/crypto/aes-ccm.c rename to libeap/src/crypto/aes-ccm.c diff --git a/src/crypto/aes-ctr.c b/libeap/src/crypto/aes-ctr.c similarity index 100% rename from src/crypto/aes-ctr.c rename to libeap/src/crypto/aes-ctr.c diff --git a/src/crypto/aes-eax.c b/libeap/src/crypto/aes-eax.c similarity index 100% rename from src/crypto/aes-eax.c rename to libeap/src/crypto/aes-eax.c diff --git a/src/crypto/aes-encblock.c b/libeap/src/crypto/aes-encblock.c similarity index 100% rename from src/crypto/aes-encblock.c rename to libeap/src/crypto/aes-encblock.c diff --git a/src/crypto/aes-gcm.c b/libeap/src/crypto/aes-gcm.c similarity index 100% rename from src/crypto/aes-gcm.c rename to libeap/src/crypto/aes-gcm.c diff --git a/src/crypto/aes-internal-dec.c b/libeap/src/crypto/aes-internal-dec.c similarity index 100% rename from src/crypto/aes-internal-dec.c rename to libeap/src/crypto/aes-internal-dec.c diff --git a/src/crypto/aes-internal-enc.c b/libeap/src/crypto/aes-internal-enc.c similarity index 100% rename from src/crypto/aes-internal-enc.c rename to libeap/src/crypto/aes-internal-enc.c diff --git a/src/crypto/aes-internal.c b/libeap/src/crypto/aes-internal.c similarity index 100% rename from src/crypto/aes-internal.c rename to libeap/src/crypto/aes-internal.c diff --git a/src/crypto/aes-omac1.c b/libeap/src/crypto/aes-omac1.c similarity index 100% rename from src/crypto/aes-omac1.c rename to libeap/src/crypto/aes-omac1.c diff --git a/src/crypto/aes-siv.c b/libeap/src/crypto/aes-siv.c similarity index 100% rename from src/crypto/aes-siv.c rename to libeap/src/crypto/aes-siv.c diff --git a/src/crypto/aes-unwrap.c b/libeap/src/crypto/aes-unwrap.c similarity index 100% rename from src/crypto/aes-unwrap.c rename to libeap/src/crypto/aes-unwrap.c diff --git a/src/crypto/aes-wrap.c b/libeap/src/crypto/aes-wrap.c similarity index 100% rename from src/crypto/aes-wrap.c rename to libeap/src/crypto/aes-wrap.c diff --git a/src/crypto/aes.h b/libeap/src/crypto/aes.h similarity index 100% rename from src/crypto/aes.h rename to libeap/src/crypto/aes.h diff --git a/src/crypto/aes_i.h b/libeap/src/crypto/aes_i.h similarity index 100% rename from src/crypto/aes_i.h rename to libeap/src/crypto/aes_i.h diff --git a/src/crypto/aes_siv.h b/libeap/src/crypto/aes_siv.h similarity index 100% rename from src/crypto/aes_siv.h rename to libeap/src/crypto/aes_siv.h diff --git a/src/crypto/aes_wrap.h b/libeap/src/crypto/aes_wrap.h similarity index 100% rename from src/crypto/aes_wrap.h rename to libeap/src/crypto/aes_wrap.h diff --git a/src/crypto/crypto.h b/libeap/src/crypto/crypto.h similarity index 100% rename from src/crypto/crypto.h rename to libeap/src/crypto/crypto.h diff --git a/src/crypto/crypto_gnutls.c b/libeap/src/crypto/crypto_gnutls.c similarity index 100% rename from src/crypto/crypto_gnutls.c rename to libeap/src/crypto/crypto_gnutls.c diff --git a/src/crypto/crypto_internal-cipher.c b/libeap/src/crypto/crypto_internal-cipher.c similarity index 100% rename from src/crypto/crypto_internal-cipher.c rename to libeap/src/crypto/crypto_internal-cipher.c diff --git a/src/crypto/crypto_internal-modexp.c b/libeap/src/crypto/crypto_internal-modexp.c similarity index 100% rename from src/crypto/crypto_internal-modexp.c rename to libeap/src/crypto/crypto_internal-modexp.c diff --git a/src/crypto/crypto_internal-rsa.c b/libeap/src/crypto/crypto_internal-rsa.c similarity index 100% rename from src/crypto/crypto_internal-rsa.c rename to libeap/src/crypto/crypto_internal-rsa.c diff --git a/src/crypto/crypto_internal.c b/libeap/src/crypto/crypto_internal.c similarity index 100% rename from src/crypto/crypto_internal.c rename to libeap/src/crypto/crypto_internal.c diff --git a/src/crypto/crypto_libtomcrypt.c b/libeap/src/crypto/crypto_libtomcrypt.c similarity index 100% rename from src/crypto/crypto_libtomcrypt.c rename to libeap/src/crypto/crypto_libtomcrypt.c diff --git a/src/crypto/crypto_module_tests.c b/libeap/src/crypto/crypto_module_tests.c similarity index 100% rename from src/crypto/crypto_module_tests.c rename to libeap/src/crypto/crypto_module_tests.c diff --git a/src/crypto/crypto_none.c b/libeap/src/crypto/crypto_none.c similarity index 100% rename from src/crypto/crypto_none.c rename to libeap/src/crypto/crypto_none.c diff --git a/src/crypto/crypto_openssl.c b/libeap/src/crypto/crypto_openssl.c similarity index 100% rename from src/crypto/crypto_openssl.c rename to libeap/src/crypto/crypto_openssl.c diff --git a/src/crypto/des-internal.c b/libeap/src/crypto/des-internal.c similarity index 100% rename from src/crypto/des-internal.c rename to libeap/src/crypto/des-internal.c diff --git a/src/crypto/des_i.h b/libeap/src/crypto/des_i.h similarity index 100% rename from src/crypto/des_i.h rename to libeap/src/crypto/des_i.h diff --git a/src/crypto/dh_group5.c b/libeap/src/crypto/dh_group5.c similarity index 100% rename from src/crypto/dh_group5.c rename to libeap/src/crypto/dh_group5.c diff --git a/src/crypto/dh_group5.h b/libeap/src/crypto/dh_group5.h similarity index 100% rename from src/crypto/dh_group5.h rename to libeap/src/crypto/dh_group5.h diff --git a/src/crypto/dh_groups.c b/libeap/src/crypto/dh_groups.c similarity index 100% rename from src/crypto/dh_groups.c rename to libeap/src/crypto/dh_groups.c diff --git a/src/crypto/dh_groups.h b/libeap/src/crypto/dh_groups.h similarity index 100% rename from src/crypto/dh_groups.h rename to libeap/src/crypto/dh_groups.h diff --git a/src/crypto/fips_prf_internal.c b/libeap/src/crypto/fips_prf_internal.c similarity index 100% rename from src/crypto/fips_prf_internal.c rename to libeap/src/crypto/fips_prf_internal.c diff --git a/src/crypto/fips_prf_openssl.c b/libeap/src/crypto/fips_prf_openssl.c similarity index 100% rename from src/crypto/fips_prf_openssl.c rename to libeap/src/crypto/fips_prf_openssl.c diff --git a/src/crypto/md4-internal.c b/libeap/src/crypto/md4-internal.c similarity index 100% rename from src/crypto/md4-internal.c rename to libeap/src/crypto/md4-internal.c diff --git a/src/crypto/md5-internal.c b/libeap/src/crypto/md5-internal.c similarity index 100% rename from src/crypto/md5-internal.c rename to libeap/src/crypto/md5-internal.c diff --git a/src/crypto/md5.c b/libeap/src/crypto/md5.c similarity index 100% rename from src/crypto/md5.c rename to libeap/src/crypto/md5.c diff --git a/src/crypto/md5.h b/libeap/src/crypto/md5.h similarity index 100% rename from src/crypto/md5.h rename to libeap/src/crypto/md5.h diff --git a/src/crypto/md5_i.h b/libeap/src/crypto/md5_i.h similarity index 100% rename from src/crypto/md5_i.h rename to libeap/src/crypto/md5_i.h diff --git a/src/crypto/milenage.c b/libeap/src/crypto/milenage.c similarity index 100% rename from src/crypto/milenage.c rename to libeap/src/crypto/milenage.c diff --git a/src/crypto/milenage.h b/libeap/src/crypto/milenage.h similarity index 100% rename from src/crypto/milenage.h rename to libeap/src/crypto/milenage.h diff --git a/src/crypto/ms_funcs.c b/libeap/src/crypto/ms_funcs.c similarity index 100% rename from src/crypto/ms_funcs.c rename to libeap/src/crypto/ms_funcs.c diff --git a/src/crypto/ms_funcs.h b/libeap/src/crypto/ms_funcs.h similarity index 100% rename from src/crypto/ms_funcs.h rename to libeap/src/crypto/ms_funcs.h diff --git a/src/crypto/random.c b/libeap/src/crypto/random.c similarity index 100% rename from src/crypto/random.c rename to libeap/src/crypto/random.c diff --git a/src/crypto/random.h b/libeap/src/crypto/random.h similarity index 100% rename from src/crypto/random.h rename to libeap/src/crypto/random.h diff --git a/src/crypto/rc4.c b/libeap/src/crypto/rc4.c similarity index 100% rename from src/crypto/rc4.c rename to libeap/src/crypto/rc4.c diff --git a/src/crypto/sha1-internal.c b/libeap/src/crypto/sha1-internal.c similarity index 100% rename from src/crypto/sha1-internal.c rename to libeap/src/crypto/sha1-internal.c diff --git a/src/crypto/sha1-pbkdf2.c b/libeap/src/crypto/sha1-pbkdf2.c similarity index 100% rename from src/crypto/sha1-pbkdf2.c rename to libeap/src/crypto/sha1-pbkdf2.c diff --git a/src/crypto/sha1-prf.c b/libeap/src/crypto/sha1-prf.c similarity index 100% rename from src/crypto/sha1-prf.c rename to libeap/src/crypto/sha1-prf.c diff --git a/src/crypto/sha1-tlsprf.c b/libeap/src/crypto/sha1-tlsprf.c similarity index 100% rename from src/crypto/sha1-tlsprf.c rename to libeap/src/crypto/sha1-tlsprf.c diff --git a/src/crypto/sha1-tprf.c b/libeap/src/crypto/sha1-tprf.c similarity index 100% rename from src/crypto/sha1-tprf.c rename to libeap/src/crypto/sha1-tprf.c diff --git a/src/crypto/sha1.c b/libeap/src/crypto/sha1.c similarity index 100% rename from src/crypto/sha1.c rename to libeap/src/crypto/sha1.c diff --git a/src/crypto/sha1.h b/libeap/src/crypto/sha1.h similarity index 100% rename from src/crypto/sha1.h rename to libeap/src/crypto/sha1.h diff --git a/src/crypto/sha1_i.h b/libeap/src/crypto/sha1_i.h similarity index 100% rename from src/crypto/sha1_i.h rename to libeap/src/crypto/sha1_i.h diff --git a/src/crypto/sha256-internal.c b/libeap/src/crypto/sha256-internal.c similarity index 100% rename from src/crypto/sha256-internal.c rename to libeap/src/crypto/sha256-internal.c diff --git a/src/crypto/sha256-kdf.c b/libeap/src/crypto/sha256-kdf.c similarity index 100% rename from src/crypto/sha256-kdf.c rename to libeap/src/crypto/sha256-kdf.c diff --git a/src/crypto/sha256-prf.c b/libeap/src/crypto/sha256-prf.c similarity index 100% rename from src/crypto/sha256-prf.c rename to libeap/src/crypto/sha256-prf.c diff --git a/src/crypto/sha256-tlsprf.c b/libeap/src/crypto/sha256-tlsprf.c similarity index 100% rename from src/crypto/sha256-tlsprf.c rename to libeap/src/crypto/sha256-tlsprf.c diff --git a/src/crypto/sha256.c b/libeap/src/crypto/sha256.c similarity index 100% rename from src/crypto/sha256.c rename to libeap/src/crypto/sha256.c diff --git a/src/crypto/sha256.h b/libeap/src/crypto/sha256.h similarity index 100% rename from src/crypto/sha256.h rename to libeap/src/crypto/sha256.h diff --git a/src/crypto/sha256_i.h b/libeap/src/crypto/sha256_i.h similarity index 100% rename from src/crypto/sha256_i.h rename to libeap/src/crypto/sha256_i.h diff --git a/src/crypto/sha384-prf.c b/libeap/src/crypto/sha384-prf.c similarity index 100% rename from src/crypto/sha384-prf.c rename to libeap/src/crypto/sha384-prf.c diff --git a/src/crypto/sha384.h b/libeap/src/crypto/sha384.h similarity index 100% rename from src/crypto/sha384.h rename to libeap/src/crypto/sha384.h diff --git a/src/crypto/tls.h b/libeap/src/crypto/tls.h similarity index 100% rename from src/crypto/tls.h rename to libeap/src/crypto/tls.h diff --git a/src/crypto/tls_gnutls.c b/libeap/src/crypto/tls_gnutls.c similarity index 100% rename from src/crypto/tls_gnutls.c rename to libeap/src/crypto/tls_gnutls.c diff --git a/src/crypto/tls_internal.c b/libeap/src/crypto/tls_internal.c similarity index 100% rename from src/crypto/tls_internal.c rename to libeap/src/crypto/tls_internal.c diff --git a/src/crypto/tls_none.c b/libeap/src/crypto/tls_none.c similarity index 100% rename from src/crypto/tls_none.c rename to libeap/src/crypto/tls_none.c diff --git a/libeap/src/crypto/tls_openssl.c b/libeap/src/crypto/tls_openssl.c new file mode 100644 index 0000000..0a8ae57 --- /dev/null +++ b/libeap/src/crypto/tls_openssl.c @@ -0,0 +1,4148 @@ +/* + * SSL/TLS interface functions for OpenSSL + * Copyright (c) 2004-2015, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#ifndef CONFIG_SMARTCARD +#ifndef OPENSSL_NO_ENGINE +#ifndef ANDROID +#define OPENSSL_NO_ENGINE +#endif +#endif +#endif + +#include +#include +#include +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif /* OPENSSL_NO_ENGINE */ +#ifndef OPENSSL_NO_DSA +#include +#endif +#ifndef OPENSSL_NO_DH +#include +#endif + +#include "common.h" +#include "crypto.h" +#include "sha1.h" +#include "sha256.h" +#include "tls.h" + +#if OPENSSL_VERSION_NUMBER < 0x10000000L +/* ERR_remove_thread_state replaces ERR_remove_state and the latter is + * deprecated. However, OpenSSL 0.9.8 doesn't include + * ERR_remove_thread_state. */ +#define ERR_remove_thread_state(tid) ERR_remove_state(0) +#endif + +#if defined(OPENSSL_IS_BORINGSSL) +/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */ +typedef size_t stack_index_t; +#else +typedef int stack_index_t; +#endif + +#ifdef SSL_set_tlsext_status_type +#ifndef OPENSSL_NO_TLSEXT +#define HAVE_OCSP +#include +#endif /* OPENSSL_NO_TLSEXT */ +#endif /* SSL_set_tlsext_status_type */ + +#ifdef ANDROID +#include +#include + +static BIO * BIO_from_keystore(const char *key) +{ + BIO *bio = NULL; + uint8_t *value = NULL; + int length = keystore_get(key, strlen(key), &value); + if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) + BIO_write(bio, value, length); + free(value); + return bio; +} +#endif /* ANDROID */ + +static int tls_openssl_ref_count = 0; +static int tls_ex_idx_session = -1; + +struct tls_context { + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data); + void *cb_ctx; + int cert_in_cb; + char *ocsp_stapling_response; +}; + +static struct tls_context *tls_global = NULL; + + +struct tls_data { + SSL_CTX *ssl; + unsigned int tls_session_lifetime; +}; + +struct tls_connection { + struct tls_context *context; + SSL_CTX *ssl_ctx; + SSL *ssl; + BIO *ssl_in, *ssl_out; +#ifndef OPENSSL_NO_ENGINE + ENGINE *engine; /* functional reference to the engine */ + EVP_PKEY *private_key; /* the private key if using engine */ +#endif /* OPENSSL_NO_ENGINE */ + char *subject_match, *altsubject_match, *suffix_match, *domain_match; + int read_alerts, write_alerts, failed; + + tls_session_ticket_cb session_ticket_cb; + void *session_ticket_cb_ctx; + + /* SessionTicket received from OpenSSL hello_extension_cb (server) */ + u8 *session_ticket; + size_t session_ticket_len; + + unsigned int ca_cert_verify:1; + unsigned int cert_probe:1; + unsigned int server_cert_only:1; + unsigned int invalid_hb_used:1; + unsigned int success_data:1; + + u8 srv_cert_hash[32]; + + unsigned int flags; + + X509 *peer_cert; + X509 *peer_issuer; + X509 *peer_issuer_issuer; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + unsigned char client_random[SSL3_RANDOM_SIZE]; + unsigned char server_random[SSL3_RANDOM_SIZE]; +#endif +}; + + +static struct tls_context * tls_context_new(const struct tls_config *conf) +{ + struct tls_context *context = os_zalloc(sizeof(*context)); + if (context == NULL) + return NULL; + if (conf) { + context->event_cb = conf->event_cb; + context->cb_ctx = conf->cb_ctx; + context->cert_in_cb = conf->cert_in_cb; + } + return context; +} + + +#ifdef CONFIG_NO_STDOUT_DEBUG + +static void _tls_show_errors(void) +{ + unsigned long err; + + while ((err = ERR_get_error())) { + /* Just ignore the errors, since stdout is disabled */ + } +} +#define tls_show_errors(l, f, t) _tls_show_errors() + +#else /* CONFIG_NO_STDOUT_DEBUG */ + +static void tls_show_errors(int level, const char *func, const char *txt) +{ + unsigned long err; + + wpa_printf(level, "OpenSSL: %s - %s %s", + func, txt, ERR_error_string(ERR_get_error(), NULL)); + + while ((err = ERR_get_error())) { + wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", + ERR_error_string(err, NULL)); + } +} + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifdef CONFIG_NATIVE_WINDOWS + +/* Windows CryptoAPI and access to certificate stores */ +#include + +#ifdef __MINGW32_VERSION +/* + * MinGW does not yet include all the needed definitions for CryptoAPI, so + * define here whatever extra is needed. + */ +#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) +#define CERT_STORE_READONLY_FLAG 0x00008000 +#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 + +#endif /* __MINGW32_VERSION */ + + +struct cryptoapi_rsa_data { + const CERT_CONTEXT *cert; + HCRYPTPROV crypt_prov; + DWORD key_spec; + BOOL free_crypt_prov; +}; + + +static void cryptoapi_error(const char *msg) +{ + wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", + msg, (unsigned int) GetLastError()); +} + + +static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); + return 0; +} + + +static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); + return 0; +} + + +static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + struct cryptoapi_rsa_data *priv = + (struct cryptoapi_rsa_data *) rsa->meth->app_data; + HCRYPTHASH hash; + DWORD hash_size, len, i; + unsigned char *buf = NULL; + int ret = 0; + + if (priv == NULL) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (padding != RSA_PKCS1_PADDING) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + RSA_R_UNKNOWN_PADDING_TYPE); + return 0; + } + + if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { + wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", + __func__); + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + RSA_R_INVALID_MESSAGE_LENGTH); + return 0; + } + + if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) + { + cryptoapi_error("CryptCreateHash failed"); + return 0; + } + + len = sizeof(hash_size); + if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, + 0)) { + cryptoapi_error("CryptGetHashParam failed"); + goto err; + } + + if ((int) hash_size != flen) { + wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", + (unsigned) hash_size, flen); + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + RSA_R_INVALID_MESSAGE_LENGTH); + goto err; + } + if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { + cryptoapi_error("CryptSetHashParam failed"); + goto err; + } + + len = RSA_size(rsa); + buf = os_malloc(len); + if (buf == NULL) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { + cryptoapi_error("CryptSignHash failed"); + goto err; + } + + for (i = 0; i < len; i++) + to[i] = buf[len - i - 1]; + ret = len; + +err: + os_free(buf); + CryptDestroyHash(hash); + + return ret; +} + + +static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); + return 0; +} + + +static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) +{ + if (priv == NULL) + return; + if (priv->crypt_prov && priv->free_crypt_prov) + CryptReleaseContext(priv->crypt_prov, 0); + if (priv->cert) + CertFreeCertificateContext(priv->cert); + os_free(priv); +} + + +static int cryptoapi_finish(RSA *rsa) +{ + cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); + os_free((void *) rsa->meth); + rsa->meth = NULL; + return 1; +} + + +static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) +{ + HCERTSTORE cs; + const CERT_CONTEXT *ret = NULL; + + cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, + store | CERT_STORE_OPEN_EXISTING_FLAG | + CERT_STORE_READONLY_FLAG, L"MY"); + if (cs == NULL) { + cryptoapi_error("Failed to open 'My system store'"); + return NULL; + } + + if (strncmp(name, "cert://", 7) == 0) { + unsigned short wbuf[255]; + MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); + ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | + PKCS_7_ASN_ENCODING, + 0, CERT_FIND_SUBJECT_STR, + wbuf, NULL); + } else if (strncmp(name, "hash://", 7) == 0) { + CRYPT_HASH_BLOB blob; + int len; + const char *hash = name + 7; + unsigned char *buf; + + len = os_strlen(hash) / 2; + buf = os_malloc(len); + if (buf && hexstr2bin(hash, buf, len) == 0) { + blob.cbData = len; + blob.pbData = buf; + ret = CertFindCertificateInStore(cs, + X509_ASN_ENCODING | + PKCS_7_ASN_ENCODING, + 0, CERT_FIND_HASH, + &blob, NULL); + } + os_free(buf); + } + + CertCloseStore(cs, 0); + + return ret; +} + + +static int tls_cryptoapi_cert(SSL *ssl, const char *name) +{ + X509 *cert = NULL; + RSA *rsa = NULL, *pub_rsa; + struct cryptoapi_rsa_data *priv; + RSA_METHOD *rsa_meth; + + if (name == NULL || + (strncmp(name, "cert://", 7) != 0 && + strncmp(name, "hash://", 7) != 0)) + return -1; + + priv = os_zalloc(sizeof(*priv)); + rsa_meth = os_zalloc(sizeof(*rsa_meth)); + if (priv == NULL || rsa_meth == NULL) { + wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " + "for CryptoAPI RSA method"); + os_free(priv); + os_free(rsa_meth); + return -1; + } + + priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); + if (priv->cert == NULL) { + priv->cert = cryptoapi_find_cert( + name, CERT_SYSTEM_STORE_LOCAL_MACHINE); + } + if (priv->cert == NULL) { + wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " + "'%s'", name); + goto err; + } + + cert = d2i_X509(NULL, + (const unsigned char **) &priv->cert->pbCertEncoded, + priv->cert->cbCertEncoded); + if (cert == NULL) { + wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " + "encoding"); + goto err; + } + + if (!CryptAcquireCertificatePrivateKey(priv->cert, + CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + NULL, &priv->crypt_prov, + &priv->key_spec, + &priv->free_crypt_prov)) { + cryptoapi_error("Failed to acquire a private key for the " + "certificate"); + goto err; + } + + rsa_meth->name = "Microsoft CryptoAPI RSA Method"; + rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; + rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; + rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; + rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; + rsa_meth->finish = cryptoapi_finish; + rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; + rsa_meth->app_data = (char *) priv; + + rsa = RSA_new(); + if (rsa == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!SSL_use_certificate(ssl, cert)) { + RSA_free(rsa); + rsa = NULL; + goto err; + } + pub_rsa = cert->cert_info->key->pkey->pkey.rsa; + X509_free(cert); + cert = NULL; + + rsa->n = BN_dup(pub_rsa->n); + rsa->e = BN_dup(pub_rsa->e); + if (!RSA_set_method(rsa, rsa_meth)) + goto err; + + if (!SSL_use_RSAPrivateKey(ssl, rsa)) + goto err; + RSA_free(rsa); + + return 0; + +err: + if (cert) + X509_free(cert); + if (rsa) + RSA_free(rsa); + else { + os_free(rsa_meth); + cryptoapi_free_data(priv); + } + return -1; +} + + +static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) +{ + HCERTSTORE cs; + PCCERT_CONTEXT ctx = NULL; + X509 *cert; + char buf[128]; + const char *store; +#ifdef UNICODE + WCHAR *wstore; +#endif /* UNICODE */ + + if (name == NULL || strncmp(name, "cert_store://", 13) != 0) + return -1; + + store = name + 13; +#ifdef UNICODE + wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); + if (wstore == NULL) + return -1; + wsprintf(wstore, L"%S", store); + cs = CertOpenSystemStore(0, wstore); + os_free(wstore); +#else /* UNICODE */ + cs = CertOpenSystemStore(0, store); +#endif /* UNICODE */ + if (cs == NULL) { + wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " + "'%s': error=%d", __func__, store, + (int) GetLastError()); + return -1; + } + + while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { + cert = d2i_X509(NULL, + (const unsigned char **) &ctx->pbCertEncoded, + ctx->cbCertEncoded); + if (cert == NULL) { + wpa_printf(MSG_INFO, "CryptoAPI: Could not process " + "X509 DER encoding for CA cert"); + continue; + } + + X509_NAME_oneline(X509_get_subject_name(cert), buf, + sizeof(buf)); + wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " + "system certificate store: subject='%s'", buf); + + if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { + tls_show_errors(MSG_WARNING, __func__, + "Failed to add ca_cert to OpenSSL " + "certificate store"); + } + + X509_free(cert); + } + + if (!CertCloseStore(cs, 0)) { + wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " + "'%s': error=%d", __func__, name + 13, + (int) GetLastError()); + } + + return 0; +} + + +#else /* CONFIG_NATIVE_WINDOWS */ + +static int tls_cryptoapi_cert(SSL *ssl, const char *name) +{ + return -1; +} + +#endif /* CONFIG_NATIVE_WINDOWS */ + + +static void ssl_info_cb(const SSL *ssl, int where, int ret) +{ + const char *str; + int w; + + wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); + w = where & ~SSL_ST_MASK; + if (w & SSL_ST_CONNECT) + str = "SSL_connect"; + else if (w & SSL_ST_ACCEPT) + str = "SSL_accept"; + else + str = "undefined"; + + if (where & SSL_CB_LOOP) { + wpa_printf(MSG_DEBUG, "SSL: %s:%s", + str, SSL_state_string_long(ssl)); + } else if (where & SSL_CB_ALERT) { + struct tls_connection *conn = SSL_get_app_data((SSL *) ssl); + wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", + where & SSL_CB_READ ? + "read (remote end reported an error)" : + "write (local SSL3 detected an error)", + SSL_alert_type_string_long(ret), + SSL_alert_desc_string_long(ret)); + if ((ret >> 8) == SSL3_AL_FATAL) { + if (where & SSL_CB_READ) + conn->read_alerts++; + else + conn->write_alerts++; + } + if (conn->context->event_cb != NULL) { + union tls_event_data ev; + struct tls_context *context = conn->context; + os_memset(&ev, 0, sizeof(ev)); + ev.alert.is_local = !(where & SSL_CB_READ); + ev.alert.type = SSL_alert_type_string_long(ret); + ev.alert.description = SSL_alert_desc_string_long(ret); + context->event_cb(context->cb_ctx, TLS_ALERT, &ev); + } + } else if (where & SSL_CB_EXIT && ret <= 0) { + wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", + str, ret == 0 ? "failed" : "error", + SSL_state_string_long(ssl)); + } +} + + +#ifndef OPENSSL_NO_ENGINE +/** + * tls_engine_load_dynamic_generic - load any openssl engine + * @pre: an array of commands and values that load an engine initialized + * in the engine specific function + * @post: an array of commands and values that initialize an already loaded + * engine (or %NULL if not required) + * @id: the engine id of the engine to load (only required if post is not %NULL + * + * This function is a generic function that loads any openssl engine. + * + * Returns: 0 on success, -1 on failure + */ +static int tls_engine_load_dynamic_generic(const char *pre[], + const char *post[], const char *id) +{ + ENGINE *engine; + const char *dynamic_id = "dynamic"; + + engine = ENGINE_by_id(id); + if (engine) { + ENGINE_free(engine); + wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " + "available", id); + return 0; + } + ERR_clear_error(); + + engine = ENGINE_by_id(dynamic_id); + if (engine == NULL) { + wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", + dynamic_id, + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + /* Perform the pre commands. This will load the engine. */ + while (pre && pre[0]) { + wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); + if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { + wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " + "%s %s [%s]", pre[0], pre[1], + ERR_error_string(ERR_get_error(), NULL)); + ENGINE_free(engine); + return -1; + } + pre += 2; + } + + /* + * Free the reference to the "dynamic" engine. The loaded engine can + * now be looked up using ENGINE_by_id(). + */ + ENGINE_free(engine); + + engine = ENGINE_by_id(id); + if (engine == NULL) { + wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", + id, ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + while (post && post[0]) { + wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); + if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { + wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" + " %s %s [%s]", post[0], post[1], + ERR_error_string(ERR_get_error(), NULL)); + ENGINE_remove(engine); + ENGINE_free(engine); + return -1; + } + post += 2; + } + ENGINE_free(engine); + + return 0; +} + + +/** + * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc + * @pkcs11_so_path: pksc11_so_path from the configuration + * @pcks11_module_path: pkcs11_module_path from the configuration + */ +static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, + const char *pkcs11_module_path) +{ + char *engine_id = "pkcs11"; + const char *pre_cmd[] = { + "SO_PATH", NULL /* pkcs11_so_path */, + "ID", NULL /* engine_id */, + "LIST_ADD", "1", + /* "NO_VCHECK", "1", */ + "LOAD", NULL, + NULL, NULL + }; + const char *post_cmd[] = { + "MODULE_PATH", NULL /* pkcs11_module_path */, + NULL, NULL + }; + + if (!pkcs11_so_path) + return 0; + + pre_cmd[1] = pkcs11_so_path; + pre_cmd[3] = engine_id; + if (pkcs11_module_path) + post_cmd[1] = pkcs11_module_path; + else + post_cmd[0] = NULL; + + wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", + pkcs11_so_path); + + return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); +} + + +/** + * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc + * @opensc_so_path: opensc_so_path from the configuration + */ +static int tls_engine_load_dynamic_opensc(const char *opensc_so_path) +{ + char *engine_id = "opensc"; + const char *pre_cmd[] = { + "SO_PATH", NULL /* opensc_so_path */, + "ID", NULL /* engine_id */, + "LIST_ADD", "1", + "LOAD", NULL, + NULL, NULL + }; + + if (!opensc_so_path) + return 0; + + pre_cmd[1] = opensc_so_path; + pre_cmd[3] = engine_id; + + wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", + opensc_so_path); + + return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); +} +#endif /* OPENSSL_NO_ENGINE */ + + +static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess) +{ + struct wpabuf *buf; + + if (tls_ex_idx_session < 0) + return; + buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); + if (!buf) + return; + wpa_printf(MSG_DEBUG, + "OpenSSL: Free application session data %p (sess %p)", + buf, sess); + wpabuf_free(buf); + + SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL); +} + + +void * tls_init(const struct tls_config *conf) +{ + struct tls_data *data; + SSL_CTX *ssl; + struct tls_context *context; + const char *ciphers; + + if (tls_openssl_ref_count == 0) { + tls_global = context = tls_context_new(conf); + if (context == NULL) + return NULL; +#ifdef CONFIG_FIPS +#ifdef OPENSSL_FIPS + if (conf && conf->fips_mode) { + static int fips_enabled = 0; + + if (!fips_enabled && !FIPS_mode_set(1)) { + wpa_printf(MSG_ERROR, "Failed to enable FIPS " + "mode"); + ERR_load_crypto_strings(); + ERR_print_errors_fp(stderr); + os_free(tls_global); + tls_global = NULL; + return NULL; + } else { + wpa_printf(MSG_INFO, "Running in FIPS mode"); + fips_enabled = 1; + } + } +#else /* OPENSSL_FIPS */ + if (conf && conf->fips_mode) { + wpa_printf(MSG_ERROR, "FIPS mode requested, but not " + "supported"); + os_free(tls_global); + tls_global = NULL; + return NULL; + } +#endif /* OPENSSL_FIPS */ +#endif /* CONFIG_FIPS */ + SSL_load_error_strings(); + SSL_library_init(); +#ifndef OPENSSL_NO_SHA256 + EVP_add_digest(EVP_sha256()); +#endif /* OPENSSL_NO_SHA256 */ + /* TODO: if /dev/urandom is available, PRNG is seeded + * automatically. If this is not the case, random data should + * be added here. */ + +#ifdef PKCS12_FUNCS +#ifndef OPENSSL_NO_RC2 + /* + * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. + * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 + * versions, but it looks like OpenSSL 1.0.0 does not do that + * anymore. + */ + EVP_add_cipher(EVP_rc2_40_cbc()); +#endif /* OPENSSL_NO_RC2 */ + PKCS12_PBE_add(); +#endif /* PKCS12_FUNCS */ + } else { + context = tls_context_new(conf); + if (context == NULL) + return NULL; + } + tls_openssl_ref_count++; + + data = os_zalloc(sizeof(*data)); + if (data) + ssl = SSL_CTX_new(SSLv23_method()); + else + ssl = NULL; + if (ssl == NULL) { + tls_openssl_ref_count--; + if (context != tls_global) + os_free(context); + if (tls_openssl_ref_count == 0) { + os_free(tls_global); + tls_global = NULL; + } + return NULL; + } + data->ssl = ssl; + if (conf) + data->tls_session_lifetime = conf->tls_session_lifetime; + + SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2); + SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3); + + SSL_CTX_set_info_callback(ssl, ssl_info_cb); + SSL_CTX_set_app_data(ssl, context); + if (data->tls_session_lifetime > 0) { + SSL_CTX_set_quiet_shutdown(ssl, 1); + /* + * Set default context here. In practice, this will be replaced + * by the per-EAP method context in tls_connection_set_verify(). + */ + SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7); + SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER); + SSL_CTX_set_timeout(ssl, data->tls_session_lifetime); + SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb); + } else { + SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF); + } + + if (tls_ex_idx_session < 0) { + tls_ex_idx_session = SSL_SESSION_get_ex_new_index( + 0, NULL, NULL, NULL, NULL); + if (tls_ex_idx_session < 0) { + tls_deinit(data); + return NULL; + } + } + +#ifndef OPENSSL_NO_ENGINE + wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); + ERR_load_ENGINE_strings(); + ENGINE_load_dynamic(); + + if (conf && + (conf->opensc_engine_path || conf->pkcs11_engine_path || + conf->pkcs11_module_path)) { + if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || + tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, + conf->pkcs11_module_path)) { + tls_deinit(data); + return NULL; + } + } +#endif /* OPENSSL_NO_ENGINE */ + + if (conf && conf->openssl_ciphers) + ciphers = conf->openssl_ciphers; + else + ciphers = "DEFAULT:!EXP:!LOW"; + if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) { + wpa_printf(MSG_ERROR, + "OpenSSL: Failed to set cipher string '%s'", + ciphers); + tls_deinit(data); + return NULL; + } + + return data; +} + + +void tls_deinit(void *ssl_ctx) +{ + struct tls_data *data = ssl_ctx; + SSL_CTX *ssl = data->ssl; + struct tls_context *context = SSL_CTX_get_app_data(ssl); + if (context != tls_global) + os_free(context); + if (data->tls_session_lifetime > 0) + SSL_CTX_flush_sessions(ssl, 0); + SSL_CTX_free(ssl); + + tls_openssl_ref_count--; + if (tls_openssl_ref_count == 0) { +// The next four lines, and two more just below, deal with de-initializing +// global state in the OpenSSL engine. We (Moonshot) don't want that, since +// we use OpenSSL elsewhere in our apps (i.e., not only via hostap / libeap.) +//// #ifndef OPENSSL_NO_ENGINE +//// ENGINE_cleanup(); +//// #endif /* OPENSSL_NO_ENGINE */ +//// CRYPTO_cleanup_all_ex_data(); + ERR_remove_thread_state(NULL); +//// ERR_free_strings(); +//// EVP_cleanup(); + os_free(tls_global->ocsp_stapling_response); + tls_global->ocsp_stapling_response = NULL; + os_free(tls_global); + tls_global = NULL; + } + + os_free(data); +} + + +#ifndef OPENSSL_NO_ENGINE + +/* Cryptoki return values */ +#define CKR_PIN_INCORRECT 0x000000a0 +#define CKR_PIN_INVALID 0x000000a1 +#define CKR_PIN_LEN_RANGE 0x000000a2 + +/* libp11 */ +#define ERR_LIB_PKCS11 ERR_LIB_USER + +static int tls_is_pin_error(unsigned int err) +{ + return ERR_GET_LIB(err) == ERR_LIB_PKCS11 && + (ERR_GET_REASON(err) == CKR_PIN_INCORRECT || + ERR_GET_REASON(err) == CKR_PIN_INVALID || + ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE); +} + +#endif /* OPENSSL_NO_ENGINE */ + + +static int tls_engine_init(struct tls_connection *conn, const char *engine_id, + const char *pin, const char *key_id, + const char *cert_id, const char *ca_cert_id) +{ +#ifndef OPENSSL_NO_ENGINE + int ret = -1; + if (engine_id == NULL) { + wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); + return -1; + } + + ERR_clear_error(); +#ifdef ANDROID + ENGINE_load_dynamic(); +#endif + conn->engine = ENGINE_by_id(engine_id); + if (!conn->engine) { + wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", + engine_id, ERR_error_string(ERR_get_error(), NULL)); + goto err; + } + if (ENGINE_init(conn->engine) != 1) { + wpa_printf(MSG_ERROR, "ENGINE: engine init failed " + "(engine: %s) [%s]", engine_id, + ERR_error_string(ERR_get_error(), NULL)); + goto err; + } + wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); + +#ifndef ANDROID + if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { + wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", + ERR_error_string(ERR_get_error(), NULL)); + goto err; + } +#endif + if (key_id) { + /* + * Ensure that the ENGINE does not attempt to use the OpenSSL + * UI system to obtain a PIN, if we didn't provide one. + */ + struct { + const void *password; + const char *prompt_info; + } key_cb = { "", NULL }; + + /* load private key first in-case PIN is required for cert */ + conn->private_key = ENGINE_load_private_key(conn->engine, + key_id, NULL, + &key_cb); + if (!conn->private_key) { + unsigned long err = ERR_get_error(); + + wpa_printf(MSG_ERROR, + "ENGINE: cannot load private key with id '%s' [%s]", + key_id, + ERR_error_string(err, NULL)); + if (tls_is_pin_error(err)) + ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN; + else + ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; + goto err; + } + } + + /* handle a certificate and/or CA certificate */ + if (cert_id || ca_cert_id) { + const char *cmd_name = "LOAD_CERT_CTRL"; + + /* test if the engine supports a LOAD_CERT_CTRL */ + if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, + 0, (void *)cmd_name, NULL)) { + wpa_printf(MSG_ERROR, "ENGINE: engine does not support" + " loading certificates"); + ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; + goto err; + } + } + + return 0; + +err: + if (conn->engine) { + ENGINE_free(conn->engine); + conn->engine = NULL; + } + + if (conn->private_key) { + EVP_PKEY_free(conn->private_key); + conn->private_key = NULL; + } + + return ret; +#else /* OPENSSL_NO_ENGINE */ + return 0; +#endif /* OPENSSL_NO_ENGINE */ +} + + +static void tls_engine_deinit(struct tls_connection *conn) +{ +#ifndef OPENSSL_NO_ENGINE + wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); + if (conn->private_key) { + EVP_PKEY_free(conn->private_key); + conn->private_key = NULL; + } + if (conn->engine) { + ENGINE_finish(conn->engine); + conn->engine = NULL; + } +#endif /* OPENSSL_NO_ENGINE */ +} + + +int tls_get_errors(void *ssl_ctx) +{ + int count = 0; + unsigned long err; + + while ((err = ERR_get_error())) { + wpa_printf(MSG_INFO, "TLS - SSL error: %s", + ERR_error_string(err, NULL)); + count++; + } + + return count; +} + + +static void tls_msg_cb(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg) +{ + struct tls_connection *conn = arg; + const u8 *pos = buf; + + wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d", + write_p ? "TX" : "RX", version, content_type); + wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len); + if (content_type == 24 && len >= 3 && pos[0] == 1) { + size_t payload_len = WPA_GET_BE16(pos + 1); + if (payload_len + 3 > len) { + wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected"); + conn->invalid_hb_used = 1; + } + } +} + + +struct tls_connection * tls_connection_init(void *ssl_ctx) +{ + struct tls_data *data = ssl_ctx; + SSL_CTX *ssl = data->ssl; + struct tls_connection *conn; + long options; + struct tls_context *context = SSL_CTX_get_app_data(ssl); + + conn = os_zalloc(sizeof(*conn)); + if (conn == NULL) + return NULL; + conn->ssl_ctx = ssl; + conn->ssl = SSL_new(ssl); + if (conn->ssl == NULL) { + tls_show_errors(MSG_INFO, __func__, + "Failed to initialize new SSL connection"); + os_free(conn); + return NULL; + } + + conn->context = context; + SSL_set_app_data(conn->ssl, conn); + SSL_set_msg_callback(conn->ssl, tls_msg_cb); + SSL_set_msg_callback_arg(conn->ssl, conn); + options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_SINGLE_DH_USE; +#ifdef SSL_OP_NO_COMPRESSION + options |= SSL_OP_NO_COMPRESSION; +#endif /* SSL_OP_NO_COMPRESSION */ + SSL_set_options(conn->ssl, options); + + conn->ssl_in = BIO_new(BIO_s_mem()); + if (!conn->ssl_in) { + tls_show_errors(MSG_INFO, __func__, + "Failed to create a new BIO for ssl_in"); + SSL_free(conn->ssl); + os_free(conn); + return NULL; + } + + conn->ssl_out = BIO_new(BIO_s_mem()); + if (!conn->ssl_out) { + tls_show_errors(MSG_INFO, __func__, + "Failed to create a new BIO for ssl_out"); + SSL_free(conn->ssl); + BIO_free(conn->ssl_in); + os_free(conn); + return NULL; + } + + SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); + + return conn; +} + + +void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return; + if (conn->success_data) { + /* + * Make sure ssl_clear_bad_session() does not remove this + * session. + */ + SSL_set_quiet_shutdown(conn->ssl, 1); + SSL_shutdown(conn->ssl); + } + SSL_free(conn->ssl); + tls_engine_deinit(conn); + os_free(conn->subject_match); + os_free(conn->altsubject_match); + os_free(conn->suffix_match); + os_free(conn->domain_match); + os_free(conn->session_ticket); + os_free(conn); +} + + +int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) +{ + return conn ? SSL_is_init_finished(conn->ssl) : 0; +} + + +int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + + /* Shutdown previous TLS connection without notifying the peer + * because the connection was already terminated in practice + * and "close notify" shutdown alert would confuse AS. */ + SSL_set_quiet_shutdown(conn->ssl, 1); + SSL_shutdown(conn->ssl); + return SSL_clear(conn->ssl) == 1 ? 0 : -1; +} + + +static int tls_match_altsubject_component(X509 *cert, int type, + const char *value, size_t len) +{ + GENERAL_NAME *gen; + void *ext; + int found = 0; + stack_index_t i; + + ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { + gen = sk_GENERAL_NAME_value(ext, i); + if (gen->type != type) + continue; + if (os_strlen((char *) gen->d.ia5->data) == len && + os_memcmp(value, gen->d.ia5->data, len) == 0) + found++; + } + + return found; +} + + +static int tls_match_altsubject(X509 *cert, const char *match) +{ + int type; + const char *pos, *end; + size_t len; + + pos = match; + do { + if (os_strncmp(pos, "EMAIL:", 6) == 0) { + type = GEN_EMAIL; + pos += 6; + } else if (os_strncmp(pos, "DNS:", 4) == 0) { + type = GEN_DNS; + pos += 4; + } else if (os_strncmp(pos, "URI:", 4) == 0) { + type = GEN_URI; + pos += 4; + } else { + wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " + "match '%s'", pos); + return 0; + } + end = os_strchr(pos, ';'); + while (end) { + if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || + os_strncmp(end + 1, "DNS:", 4) == 0 || + os_strncmp(end + 1, "URI:", 4) == 0) + break; + end = os_strchr(end + 1, ';'); + } + if (end) + len = end - pos; + else + len = os_strlen(pos); + if (tls_match_altsubject_component(cert, type, pos, len) > 0) + return 1; + pos = end + 1; + } while (end); + + return 0; +} + + +#ifndef CONFIG_NATIVE_WINDOWS +static int domain_suffix_match(const u8 *val, size_t len, const char *match, + int full) +{ + size_t i, match_len; + + /* Check for embedded nuls that could mess up suffix matching */ + for (i = 0; i < len; i++) { + if (val[i] == '\0') { + wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject"); + return 0; + } + } + + match_len = os_strlen(match); + if (match_len > len || (full && match_len != len)) + return 0; + + if (os_strncasecmp((const char *) val + len - match_len, match, + match_len) != 0) + return 0; /* no match */ + + if (match_len == len) + return 1; /* exact match */ + + if (val[len - match_len - 1] == '.') + return 1; /* full label match completes suffix match */ + + wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match"); + return 0; +} +#endif /* CONFIG_NATIVE_WINDOWS */ + + +static int tls_match_suffix(X509 *cert, const char *match, int full) +{ +#ifdef CONFIG_NATIVE_WINDOWS + /* wincrypt.h has conflicting X509_NAME definition */ + return -1; +#else /* CONFIG_NATIVE_WINDOWS */ + GENERAL_NAME *gen; + void *ext; + int i; + stack_index_t j; + int dns_name = 0; + X509_NAME *name; + + wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s", + full ? "": "suffix ", match); + + ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) { + gen = sk_GENERAL_NAME_value(ext, j); + if (gen->type != GEN_DNS) + continue; + dns_name++; + wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName", + gen->d.dNSName->data, + gen->d.dNSName->length); + if (domain_suffix_match(gen->d.dNSName->data, + gen->d.dNSName->length, match, full) == + 1) { + wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found", + full ? "Match" : "Suffix match"); + return 1; + } + } + + if (dns_name) { + wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched"); + return 0; + } + + name = X509_get_subject_name(cert); + i = -1; + for (;;) { + X509_NAME_ENTRY *e; + ASN1_STRING *cn; + + i = X509_NAME_get_index_by_NID(name, NID_commonName, i); + if (i == -1) + break; + e = X509_NAME_get_entry(name, i); + if (e == NULL) + continue; + cn = X509_NAME_ENTRY_get_data(e); + if (cn == NULL) + continue; + wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName", + cn->data, cn->length); + if (domain_suffix_match(cn->data, cn->length, match, full) == 1) + { + wpa_printf(MSG_DEBUG, "TLS: %s in commonName found", + full ? "Match" : "Suffix match"); + return 1; + } + } + + wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found", + full ? "": "suffix "); + return 0; +#endif /* CONFIG_NATIVE_WINDOWS */ +} + + +static enum tls_fail_reason openssl_tls_fail_reason(int err) +{ + switch (err) { + case X509_V_ERR_CERT_REVOKED: + return TLS_FAIL_REVOKED; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CRL_NOT_YET_VALID: + return TLS_FAIL_NOT_YET_VALID; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CRL_HAS_EXPIRED: + return TLS_FAIL_EXPIRED; + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_UNABLE_TO_GET_CRL: + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_CA: + return TLS_FAIL_UNTRUSTED; + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + case X509_V_ERR_CERT_UNTRUSTED: + case X509_V_ERR_CERT_REJECTED: + return TLS_FAIL_BAD_CERTIFICATE; + default: + return TLS_FAIL_UNSPECIFIED; + } +} + + +static struct wpabuf * get_x509_cert(X509 *cert) +{ + struct wpabuf *buf; + u8 *tmp; + + int cert_len = i2d_X509(cert, NULL); + if (cert_len <= 0) + return NULL; + + buf = wpabuf_alloc(cert_len); + if (buf == NULL) + return NULL; + + tmp = wpabuf_put(buf, cert_len); + i2d_X509(cert, &tmp); + return buf; +} + + +static void openssl_tls_fail_event(struct tls_connection *conn, + X509 *err_cert, int err, int depth, + const char *subject, const char *err_str, + enum tls_fail_reason reason) +{ + union tls_event_data ev; + struct wpabuf *cert = NULL; + struct tls_context *context = conn->context; + + if (context->event_cb == NULL) + return; + + cert = get_x509_cert(err_cert); + os_memset(&ev, 0, sizeof(ev)); + ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? + reason : openssl_tls_fail_reason(err); + ev.cert_fail.depth = depth; + ev.cert_fail.subject = subject; + ev.cert_fail.reason_txt = err_str; + ev.cert_fail.cert = cert; + context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); + wpabuf_free(cert); +} + + +static void openssl_tls_cert_event(struct tls_connection *conn, + X509 *err_cert, int depth, + const char *subject) +{ + struct wpabuf *cert = NULL; + union tls_event_data ev; + struct tls_context *context = conn->context; + char *altsubject[TLS_MAX_ALT_SUBJECT]; + int alt, num_altsubject = 0; + GENERAL_NAME *gen; + void *ext; + stack_index_t i; +#ifdef CONFIG_SHA256 + u8 hash[32]; +#endif /* CONFIG_SHA256 */ + + if (context->event_cb == NULL) + return; + + os_memset(&ev, 0, sizeof(ev)); + if (conn->cert_probe || context->cert_in_cb) { + cert = get_x509_cert(err_cert); + ev.peer_cert.cert = cert; + } +#ifdef CONFIG_SHA256 + if (cert) { + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) == 0) { + ev.peer_cert.hash = hash; + ev.peer_cert.hash_len = sizeof(hash); + } + } +#endif /* CONFIG_SHA256 */ + ev.peer_cert.depth = depth; + ev.peer_cert.subject = subject; + + ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL); + for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { + char *pos; + + if (num_altsubject == TLS_MAX_ALT_SUBJECT) + break; + gen = sk_GENERAL_NAME_value(ext, i); + if (gen->type != GEN_EMAIL && + gen->type != GEN_DNS && + gen->type != GEN_URI) + continue; + + pos = os_malloc(10 + gen->d.ia5->length + 1); + if (pos == NULL) + break; + altsubject[num_altsubject++] = pos; + + switch (gen->type) { + case GEN_EMAIL: + os_memcpy(pos, "EMAIL:", 6); + pos += 6; + break; + case GEN_DNS: + os_memcpy(pos, "DNS:", 4); + pos += 4; + break; + case GEN_URI: + os_memcpy(pos, "URI:", 4); + pos += 4; + break; + } + + os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length); + pos += gen->d.ia5->length; + *pos = '\0'; + } + + for (alt = 0; alt < num_altsubject; alt++) + ev.peer_cert.altsubject[alt] = altsubject[alt]; + ev.peer_cert.num_altsubject = num_altsubject; + + context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev); + wpabuf_free(cert); + for (alt = 0; alt < num_altsubject; alt++) + os_free(altsubject[alt]); +} + + +static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) +{ + char buf[256]; + X509 *err_cert; + int err, depth; + SSL *ssl; + struct tls_connection *conn; + struct tls_context *context; + char *match, *altmatch, *suffix_match, *domain_match; + const char *err_str; + + err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); + if (!err_cert) + return 0; + + err = X509_STORE_CTX_get_error(x509_ctx); + depth = X509_STORE_CTX_get_error_depth(x509_ctx); + ssl = X509_STORE_CTX_get_ex_data(x509_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); + + conn = SSL_get_app_data(ssl); + if (conn == NULL) + return 0; + + if (depth == 0) + conn->peer_cert = err_cert; + else if (depth == 1) + conn->peer_issuer = err_cert; + else if (depth == 2) + conn->peer_issuer_issuer = err_cert; + + context = conn->context; + match = conn->subject_match; + altmatch = conn->altsubject_match; + suffix_match = conn->suffix_match; + domain_match = conn->domain_match; + + if (!preverify_ok && !conn->ca_cert_verify) + preverify_ok = 1; + if (!preverify_ok && depth > 0 && conn->server_cert_only) + preverify_ok = 1; + if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) && + (err == X509_V_ERR_CERT_HAS_EXPIRED || + err == X509_V_ERR_CERT_NOT_YET_VALID)) { + wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity " + "time mismatch"); + preverify_ok = 1; + } + + err_str = X509_verify_cert_error_string(err); + +#ifdef CONFIG_SHA256 + /* + * Do not require preverify_ok so we can explicity allow otherwise + * invalid pinned server certificates. + */ + if (depth == 0 && conn->server_cert_only) { + struct wpabuf *cert; + cert = get_x509_cert(err_cert); + if (!cert) { + wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " + "server certificate data"); + preverify_ok = 0; + } else { + u8 hash[32]; + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) < 0 || + os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { + err_str = "Server certificate mismatch"; + err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; + preverify_ok = 0; + } else if (!preverify_ok) { + /* + * Certificate matches pinned certificate, allow + * regardless of other problems. + */ + wpa_printf(MSG_DEBUG, + "OpenSSL: Ignore validation issues for a pinned server certificate"); + preverify_ok = 1; + } + wpabuf_free(cert); + } + } +#endif /* CONFIG_SHA256 */ + + if (!preverify_ok) { + wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," + " error %d (%s) depth %d for '%s'", err, err_str, + depth, buf); + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + err_str, TLS_FAIL_UNSPECIFIED); + return preverify_ok; + } + + wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " + "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", + preverify_ok, err, err_str, + conn->ca_cert_verify, depth, buf); + if (depth == 0 && match && os_strstr(buf, match) == NULL) { + wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " + "match with '%s'", buf, match); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Subject mismatch", + TLS_FAIL_SUBJECT_MISMATCH); + } else if (depth == 0 && altmatch && + !tls_match_altsubject(err_cert, altmatch)) { + wpa_printf(MSG_WARNING, "TLS: altSubjectName match " + "'%s' not found", altmatch); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "AltSubject mismatch", + TLS_FAIL_ALTSUBJECT_MISMATCH); + } else if (depth == 0 && suffix_match && + !tls_match_suffix(err_cert, suffix_match, 0)) { + wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found", + suffix_match); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Domain suffix mismatch", + TLS_FAIL_DOMAIN_SUFFIX_MISMATCH); + } else if (depth == 0 && domain_match && + !tls_match_suffix(err_cert, domain_match, 1)) { + wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found", + domain_match); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Domain mismatch", + TLS_FAIL_DOMAIN_MISMATCH); + } else + openssl_tls_cert_event(conn, err_cert, depth, buf); + + if (conn->cert_probe && preverify_ok && depth == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " + "on probe-only run"); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Server certificate chain probe", + TLS_FAIL_SERVER_CHAIN_PROBE); + } + + if (preverify_ok && context->event_cb != NULL) + context->event_cb(context->cb_ctx, + TLS_CERT_CHAIN_SUCCESS, NULL); + + return preverify_ok; +} + + +#ifndef OPENSSL_NO_STDIO +static int tls_load_ca_der(struct tls_data *data, const char *ca_cert) +{ + SSL_CTX *ssl_ctx = data->ssl; + X509_LOOKUP *lookup; + int ret = 0; + + lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx), + X509_LOOKUP_file()); + if (lookup == NULL) { + tls_show_errors(MSG_WARNING, __func__, + "Failed add lookup for X509 store"); + return -1; + } + + if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { + unsigned long err = ERR_peek_error(); + tls_show_errors(MSG_WARNING, __func__, + "Failed load CA in DER format"); + if (ERR_GET_LIB(err) == ERR_LIB_X509 && + ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " + "cert already in hash table error", + __func__); + } else + ret = -1; + } + + return ret; +} +#endif /* OPENSSL_NO_STDIO */ + + +static int tls_connection_ca_cert(struct tls_data *data, + struct tls_connection *conn, + const char *ca_cert, const u8 *ca_cert_blob, + size_t ca_cert_blob_len, const char *ca_path) +{ + SSL_CTX *ssl_ctx = data->ssl; + X509_STORE *store; + + /* + * Remove previously configured trusted CA certificates before adding + * new ones. + */ + store = X509_STORE_new(); + if (store == NULL) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " + "certificate store", __func__); + return -1; + } + SSL_CTX_set_cert_store(ssl_ctx, store); + + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); + conn->ca_cert_verify = 1; + + if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " + "chain"); + conn->cert_probe = 1; + conn->ca_cert_verify = 0; + return 0; + } + + if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { +#ifdef CONFIG_SHA256 + const char *pos = ca_cert + 7; + if (os_strncmp(pos, "server/sha256/", 14) != 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " + "hash value '%s'", ca_cert); + return -1; + } + pos += 14; + if (os_strlen(pos) != 32 * 2) { + wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " + "hash length in ca_cert '%s'", ca_cert); + return -1; + } + if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " + "value in ca_cert '%s'", ca_cert); + return -1; + } + conn->server_cert_only = 1; + wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " + "certificate match"); + return 0; +#else /* CONFIG_SHA256 */ + wpa_printf(MSG_INFO, "No SHA256 included in the build - " + "cannot validate server certificate hash"); + return -1; +#endif /* CONFIG_SHA256 */ + } + + if (ca_cert_blob) { + X509 *cert = d2i_X509(NULL, + (const unsigned char **) &ca_cert_blob, + ca_cert_blob_len); + if (cert == NULL) { + tls_show_errors(MSG_WARNING, __func__, + "Failed to parse ca_cert_blob"); + return -1; + } + + if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx), + cert)) { + unsigned long err = ERR_peek_error(); + tls_show_errors(MSG_WARNING, __func__, + "Failed to add ca_cert_blob to " + "certificate store"); + if (ERR_GET_LIB(err) == ERR_LIB_X509 && + ERR_GET_REASON(err) == + X509_R_CERT_ALREADY_IN_HASH_TABLE) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " + "cert already in hash table error", + __func__); + } else { + X509_free(cert); + return -1; + } + } + X509_free(cert); + wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " + "to certificate store", __func__); + return 0; + } + +#ifdef ANDROID + if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) { + BIO *bio = BIO_from_keystore(&ca_cert[11]); + STACK_OF(X509_INFO) *stack = NULL; + stack_index_t i; + + if (bio) { + stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); + BIO_free(bio); + } + if (!stack) + return -1; + + for (i = 0; i < sk_X509_INFO_num(stack); ++i) { + X509_INFO *info = sk_X509_INFO_value(stack, i); + if (info->x509) { + X509_STORE_add_cert(ssl_ctx->cert_store, + info->x509); + } + if (info->crl) { + X509_STORE_add_crl(ssl_ctx->cert_store, + info->crl); + } + } + sk_X509_INFO_pop_free(stack, X509_INFO_free); + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); + return 0; + } +#endif /* ANDROID */ + +#ifdef CONFIG_NATIVE_WINDOWS + if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == + 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " + "system certificate store"); + return 0; + } +#endif /* CONFIG_NATIVE_WINDOWS */ + + if (ca_cert || ca_path) { +#ifndef OPENSSL_NO_STDIO + if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != + 1) { + tls_show_errors(MSG_WARNING, __func__, + "Failed to load root certificates"); + if (ca_cert && + tls_load_ca_der(data, ca_cert) == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " + "DER format CA certificate", + __func__); + } else + return -1; + } else { + wpa_printf(MSG_DEBUG, "TLS: Trusted root " + "certificate(s) loaded"); + tls_get_errors(data); + } +#else /* OPENSSL_NO_STDIO */ + wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", + __func__); + return -1; +#endif /* OPENSSL_NO_STDIO */ + } else { + /* No ca_cert configured - do not try to verify server + * certificate */ + conn->ca_cert_verify = 0; + } + + return 0; +} + + +static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert) +{ + SSL_CTX *ssl_ctx = data->ssl; + + if (ca_cert) { + if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) + { + tls_show_errors(MSG_WARNING, __func__, + "Failed to load root certificates"); + return -1; + } + + wpa_printf(MSG_DEBUG, "TLS: Trusted root " + "certificate(s) loaded"); + +#ifndef OPENSSL_NO_STDIO + /* Add the same CAs to the client certificate requests */ + SSL_CTX_set_client_CA_list(ssl_ctx, + SSL_load_client_CA_file(ca_cert)); +#endif /* OPENSSL_NO_STDIO */ + } + + return 0; +} + + +int tls_global_set_verify(void *ssl_ctx, int check_crl) +{ + int flags; + + if (check_crl) { + struct tls_data *data = ssl_ctx; + X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl); + if (cs == NULL) { + tls_show_errors(MSG_INFO, __func__, "Failed to get " + "certificate store when enabling " + "check_crl"); + return -1; + } + flags = X509_V_FLAG_CRL_CHECK; + if (check_crl == 2) + flags |= X509_V_FLAG_CRL_CHECK_ALL; + X509_STORE_set_flags(cs, flags); + } + return 0; +} + + +static int tls_connection_set_subject_match(struct tls_connection *conn, + const char *subject_match, + const char *altsubject_match, + const char *suffix_match, + const char *domain_match) +{ + os_free(conn->subject_match); + conn->subject_match = NULL; + if (subject_match) { + conn->subject_match = os_strdup(subject_match); + if (conn->subject_match == NULL) + return -1; + } + + os_free(conn->altsubject_match); + conn->altsubject_match = NULL; + if (altsubject_match) { + conn->altsubject_match = os_strdup(altsubject_match); + if (conn->altsubject_match == NULL) + return -1; + } + + os_free(conn->suffix_match); + conn->suffix_match = NULL; + if (suffix_match) { + conn->suffix_match = os_strdup(suffix_match); + if (conn->suffix_match == NULL) + return -1; + } + + os_free(conn->domain_match); + conn->domain_match = NULL; + if (domain_match) { + conn->domain_match = os_strdup(domain_match); + if (conn->domain_match == NULL) + return -1; + } + + return 0; +} + + +static void tls_set_conn_flags(SSL *ssl, unsigned int flags) +{ +#ifdef SSL_OP_NO_TICKET + if (flags & TLS_CONN_DISABLE_SESSION_TICKET) + SSL_set_options(ssl, SSL_OP_NO_TICKET); +#ifdef SSL_clear_options + else + SSL_clear_options(ssl, SSL_OP_NO_TICKET); +#endif /* SSL_clear_options */ +#endif /* SSL_OP_NO_TICKET */ + +#ifdef SSL_OP_NO_TLSv1 + if (flags & TLS_CONN_DISABLE_TLSv1_0) + SSL_set_options(ssl, SSL_OP_NO_TLSv1); + else + SSL_clear_options(ssl, SSL_OP_NO_TLSv1); +#endif /* SSL_OP_NO_TLSv1 */ +#ifdef SSL_OP_NO_TLSv1_1 + if (flags & TLS_CONN_DISABLE_TLSv1_1) + SSL_set_options(ssl, SSL_OP_NO_TLSv1_1); + else + SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1); +#endif /* SSL_OP_NO_TLSv1_1 */ +#ifdef SSL_OP_NO_TLSv1_2 + if (flags & TLS_CONN_DISABLE_TLSv1_2) + SSL_set_options(ssl, SSL_OP_NO_TLSv1_2); + else + SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2); +#endif /* SSL_OP_NO_TLSv1_2 */ +} + + +int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, + int verify_peer, unsigned int flags, + const u8 *session_ctx, size_t session_ctx_len) +{ + static int counter = 0; + struct tls_data *data = ssl_ctx; + + if (conn == NULL) + return -1; + + if (verify_peer) { + conn->ca_cert_verify = 1; + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT | + SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); + } else { + conn->ca_cert_verify = 0; + SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); + } + + tls_set_conn_flags(conn->ssl, flags); + conn->flags = flags; + + SSL_set_accept_state(conn->ssl); + + if (data->tls_session_lifetime == 0) { + /* + * Set session id context to a unique value to make sure + * session resumption cannot be used either through session + * caching or TLS ticket extension. + */ + counter++; + SSL_set_session_id_context(conn->ssl, + (const unsigned char *) &counter, + sizeof(counter)); + } else if (session_ctx) { + SSL_set_session_id_context(conn->ssl, session_ctx, + session_ctx_len); + } + + return 0; +} + + +static int tls_connection_client_cert(struct tls_connection *conn, + const char *client_cert, + const u8 *client_cert_blob, + size_t client_cert_blob_len) +{ + if (client_cert == NULL && client_cert_blob == NULL) + return 0; + + if (client_cert_blob && + SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, + client_cert_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " + "OK"); + return 0; + } else if (client_cert_blob) { + tls_show_errors(MSG_DEBUG, __func__, + "SSL_use_certificate_ASN1 failed"); + } + + if (client_cert == NULL) + return -1; + +#ifdef ANDROID + if (os_strncmp("keystore://", client_cert, 11) == 0) { + BIO *bio = BIO_from_keystore(&client_cert[11]); + X509 *x509 = NULL; + int ret = -1; + if (bio) { + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + } + if (x509) { + if (SSL_use_certificate(conn->ssl, x509) == 1) + ret = 0; + X509_free(x509); + } + return ret; + } +#endif /* ANDROID */ + +#ifndef OPENSSL_NO_STDIO + if (SSL_use_certificate_file(conn->ssl, client_cert, + SSL_FILETYPE_ASN1) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" + " --> OK"); + return 0; + } + + if (SSL_use_certificate_file(conn->ssl, client_cert, + SSL_FILETYPE_PEM) == 1) { + ERR_clear_error(); + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" + " --> OK"); + return 0; + } + + tls_show_errors(MSG_DEBUG, __func__, + "SSL_use_certificate_file failed"); +#else /* OPENSSL_NO_STDIO */ + wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); +#endif /* OPENSSL_NO_STDIO */ + + return -1; +} + + +static int tls_global_client_cert(struct tls_data *data, + const char *client_cert) +{ +#ifndef OPENSSL_NO_STDIO + SSL_CTX *ssl_ctx = data->ssl; + + if (client_cert == NULL) + return 0; + + if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, + SSL_FILETYPE_ASN1) != 1 && + SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 && + SSL_CTX_use_certificate_file(ssl_ctx, client_cert, + SSL_FILETYPE_PEM) != 1) { + tls_show_errors(MSG_INFO, __func__, + "Failed to load client certificate"); + return -1; + } + return 0; +#else /* OPENSSL_NO_STDIO */ + if (client_cert == NULL) + return 0; + wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); + return -1; +#endif /* OPENSSL_NO_STDIO */ +} + + +static int tls_passwd_cb(char *buf, int size, int rwflag, void *password) +{ + if (password == NULL) { + return 0; + } + os_strlcpy(buf, (char *) password, size); + return os_strlen(buf); +} + + +#ifdef PKCS12_FUNCS +static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, + const char *passwd) +{ + EVP_PKEY *pkey; + X509 *cert; + STACK_OF(X509) *certs; + int res = 0; + char buf[256]; + + pkey = NULL; + cert = NULL; + certs = NULL; + if (!passwd) + passwd = ""; + if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { + tls_show_errors(MSG_DEBUG, __func__, + "Failed to parse PKCS12 file"); + PKCS12_free(p12); + return -1; + } + wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); + + if (cert) { + X509_NAME_oneline(X509_get_subject_name(cert), buf, + sizeof(buf)); + wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " + "subject='%s'", buf); + if (ssl) { + if (SSL_use_certificate(ssl, cert) != 1) + res = -1; + } else { + if (SSL_CTX_use_certificate(data->ssl, cert) != 1) + res = -1; + } + X509_free(cert); + } + + if (pkey) { + wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); + if (ssl) { + if (SSL_use_PrivateKey(ssl, pkey) != 1) + res = -1; + } else { + if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1) + res = -1; + } + EVP_PKEY_free(pkey); + } + + if (certs) { +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + SSL_clear_chain_certs(ssl); + while ((cert = sk_X509_pop(certs)) != NULL) { + X509_NAME_oneline(X509_get_subject_name(cert), buf, + sizeof(buf)); + wpa_printf(MSG_DEBUG, "TLS: additional certificate" + " from PKCS12: subject='%s'", buf); + if (SSL_add1_chain_cert(ssl, cert) != 1) { + tls_show_errors(MSG_DEBUG, __func__, + "Failed to add additional certificate"); + res = -1; + break; + } + } + if (!res) { + /* Try to continue anyway */ + } + sk_X509_free(certs); +#ifndef OPENSSL_IS_BORINGSSL + res = SSL_build_cert_chain(ssl, + SSL_BUILD_CHAIN_FLAG_CHECK | + SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR); + if (!res) { + tls_show_errors(MSG_DEBUG, __func__, + "Failed to build certificate chain"); + } else if (res == 2) { + wpa_printf(MSG_DEBUG, + "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates"); + } +#endif /* OPENSSL_IS_BORINGSSL */ + /* + * Try to continue regardless of result since it is possible for + * the extra certificates not to be required. + */ + res = 0; +#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ +#if OPENSSL_VERSION_NUMBER >= 0x10001000L + SSL_CTX_clear_extra_chain_certs(data->ssl); +#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */ + while ((cert = sk_X509_pop(certs)) != NULL) { + X509_NAME_oneline(X509_get_subject_name(cert), buf, + sizeof(buf)); + wpa_printf(MSG_DEBUG, "TLS: additional certificate" + " from PKCS12: subject='%s'", buf); + /* + * There is no SSL equivalent for the chain cert - so + * always add it to the context... + */ + if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1) + { + res = -1; + break; + } + } + sk_X509_free(certs); +#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ + } + + PKCS12_free(p12); + + if (res < 0) + tls_get_errors(data); + + return res; +} +#endif /* PKCS12_FUNCS */ + + +static int tls_read_pkcs12(struct tls_data *data, SSL *ssl, + const char *private_key, const char *passwd) +{ +#ifdef PKCS12_FUNCS + FILE *f; + PKCS12 *p12; + + f = fopen(private_key, "rb"); + if (f == NULL) + return -1; + + p12 = d2i_PKCS12_fp(f, NULL); + fclose(f); + + if (p12 == NULL) { + tls_show_errors(MSG_INFO, __func__, + "Failed to use PKCS#12 file"); + return -1; + } + + return tls_parse_pkcs12(data, ssl, p12, passwd); + +#else /* PKCS12_FUNCS */ + wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " + "p12/pfx files"); + return -1; +#endif /* PKCS12_FUNCS */ +} + + +static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl, + const u8 *blob, size_t len, const char *passwd) +{ +#ifdef PKCS12_FUNCS + PKCS12 *p12; + + p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len); + if (p12 == NULL) { + tls_show_errors(MSG_INFO, __func__, + "Failed to use PKCS#12 blob"); + return -1; + } + + return tls_parse_pkcs12(data, ssl, p12, passwd); + +#else /* PKCS12_FUNCS */ + wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " + "p12/pfx blobs"); + return -1; +#endif /* PKCS12_FUNCS */ +} + + +#ifndef OPENSSL_NO_ENGINE +static int tls_engine_get_cert(struct tls_connection *conn, + const char *cert_id, + X509 **cert) +{ + /* this runs after the private key is loaded so no PIN is required */ + struct { + const char *cert_id; + X509 *cert; + } params; + params.cert_id = cert_id; + params.cert = NULL; + + if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", + 0, ¶ms, NULL, 1)) { + unsigned long err = ERR_get_error(); + + wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" + " '%s' [%s]", cert_id, + ERR_error_string(err, NULL)); + if (tls_is_pin_error(err)) + return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN; + return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; + } + if (!params.cert) { + wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" + " '%s'", cert_id); + return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; + } + *cert = params.cert; + return 0; +} +#endif /* OPENSSL_NO_ENGINE */ + + +static int tls_connection_engine_client_cert(struct tls_connection *conn, + const char *cert_id) +{ +#ifndef OPENSSL_NO_ENGINE + X509 *cert; + + if (tls_engine_get_cert(conn, cert_id, &cert)) + return -1; + + if (!SSL_use_certificate(conn->ssl, cert)) { + tls_show_errors(MSG_ERROR, __func__, + "SSL_use_certificate failed"); + X509_free(cert); + return -1; + } + X509_free(cert); + wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " + "OK"); + return 0; + +#else /* OPENSSL_NO_ENGINE */ + return -1; +#endif /* OPENSSL_NO_ENGINE */ +} + + +static int tls_connection_engine_ca_cert(struct tls_data *data, + struct tls_connection *conn, + const char *ca_cert_id) +{ +#ifndef OPENSSL_NO_ENGINE + X509 *cert; + SSL_CTX *ssl_ctx = data->ssl; + X509_STORE *store; + + if (tls_engine_get_cert(conn, ca_cert_id, &cert)) + return -1; + + /* start off the same as tls_connection_ca_cert */ + store = X509_STORE_new(); + if (store == NULL) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " + "certificate store", __func__); + X509_free(cert); + return -1; + } + SSL_CTX_set_cert_store(ssl_ctx, store); + if (!X509_STORE_add_cert(store, cert)) { + unsigned long err = ERR_peek_error(); + tls_show_errors(MSG_WARNING, __func__, + "Failed to add CA certificate from engine " + "to certificate store"); + if (ERR_GET_LIB(err) == ERR_LIB_X509 && + ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" + " already in hash table error", + __func__); + } else { + X509_free(cert); + return -1; + } + } + X509_free(cert); + wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " + "to certificate store", __func__); + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); + conn->ca_cert_verify = 1; + + return 0; + +#else /* OPENSSL_NO_ENGINE */ + return -1; +#endif /* OPENSSL_NO_ENGINE */ +} + + +static int tls_connection_engine_private_key(struct tls_connection *conn) +{ +#ifndef OPENSSL_NO_ENGINE + if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { + tls_show_errors(MSG_ERROR, __func__, + "ENGINE: cannot use private key for TLS"); + return -1; + } + if (!SSL_check_private_key(conn->ssl)) { + tls_show_errors(MSG_INFO, __func__, + "Private key failed verification"); + return -1; + } + return 0; +#else /* OPENSSL_NO_ENGINE */ + wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " + "engine support was not compiled in"); + return -1; +#endif /* OPENSSL_NO_ENGINE */ +} + + +static int tls_connection_private_key(struct tls_data *data, + struct tls_connection *conn, + const char *private_key, + const char *private_key_passwd, + const u8 *private_key_blob, + size_t private_key_blob_len) +{ + SSL_CTX *ssl_ctx = data->ssl; + char *passwd; + int ok; + + if (private_key == NULL && private_key_blob == NULL) + return 0; + + if (private_key_passwd) { + passwd = os_strdup(private_key_passwd); + if (passwd == NULL) + return -1; + } else + passwd = NULL; + + SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); + + ok = 0; + while (private_key_blob) { + if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, + (u8 *) private_key_blob, + private_key_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" + "ASN1(EVP_PKEY_RSA) --> OK"); + ok = 1; + break; + } + + if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, + (u8 *) private_key_blob, + private_key_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" + "ASN1(EVP_PKEY_DSA) --> OK"); + ok = 1; + break; + } + + if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, + (u8 *) private_key_blob, + private_key_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: " + "SSL_use_RSAPrivateKey_ASN1 --> OK"); + ok = 1; + break; + } + + if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob, + private_key_blob_len, passwd) == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " + "OK"); + ok = 1; + break; + } + + break; + } + + while (!ok && private_key) { +#ifndef OPENSSL_NO_STDIO + if (SSL_use_PrivateKey_file(conn->ssl, private_key, + SSL_FILETYPE_ASN1) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: " + "SSL_use_PrivateKey_File (DER) --> OK"); + ok = 1; + break; + } + + if (SSL_use_PrivateKey_file(conn->ssl, private_key, + SSL_FILETYPE_PEM) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: " + "SSL_use_PrivateKey_File (PEM) --> OK"); + ok = 1; + break; + } +#else /* OPENSSL_NO_STDIO */ + wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", + __func__); +#endif /* OPENSSL_NO_STDIO */ + + if (tls_read_pkcs12(data, conn->ssl, private_key, passwd) + == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " + "--> OK"); + ok = 1; + break; + } + + if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " + "access certificate store --> OK"); + ok = 1; + break; + } + + break; + } + + if (!ok) { + tls_show_errors(MSG_INFO, __func__, + "Failed to load private key"); + os_free(passwd); + return -1; + } + ERR_clear_error(); + SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); + os_free(passwd); + + if (!SSL_check_private_key(conn->ssl)) { + tls_show_errors(MSG_INFO, __func__, "Private key failed " + "verification"); + return -1; + } + + wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); + return 0; +} + + +static int tls_global_private_key(struct tls_data *data, + const char *private_key, + const char *private_key_passwd) +{ + SSL_CTX *ssl_ctx = data->ssl; + char *passwd; + + if (private_key == NULL) + return 0; + + if (private_key_passwd) { + passwd = os_strdup(private_key_passwd); + if (passwd == NULL) + return -1; + } else + passwd = NULL; + + SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); + if ( +#ifndef OPENSSL_NO_STDIO + SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, + SSL_FILETYPE_ASN1) != 1 && + SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, + SSL_FILETYPE_PEM) != 1 && +#endif /* OPENSSL_NO_STDIO */ + tls_read_pkcs12(data, NULL, private_key, passwd)) { + tls_show_errors(MSG_INFO, __func__, + "Failed to load private key"); + os_free(passwd); + ERR_clear_error(); + return -1; + } + os_free(passwd); + ERR_clear_error(); + SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); + + if (!SSL_CTX_check_private_key(ssl_ctx)) { + tls_show_errors(MSG_INFO, __func__, + "Private key failed verification"); + return -1; + } + + return 0; +} + + +static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) +{ +#ifdef OPENSSL_NO_DH + if (dh_file == NULL) + return 0; + wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " + "dh_file specified"); + return -1; +#else /* OPENSSL_NO_DH */ + DH *dh; + BIO *bio; + + /* TODO: add support for dh_blob */ + if (dh_file == NULL) + return 0; + if (conn == NULL) + return -1; + + bio = BIO_new_file(dh_file, "r"); + if (bio == NULL) { + wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", + dh_file, ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + BIO_free(bio); +#ifndef OPENSSL_NO_DSA + while (dh == NULL) { + DSA *dsa; + wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" + " trying to parse as DSA params", dh_file, + ERR_error_string(ERR_get_error(), NULL)); + bio = BIO_new_file(dh_file, "r"); + if (bio == NULL) + break; + dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); + BIO_free(bio); + if (!dsa) { + wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " + "'%s': %s", dh_file, + ERR_error_string(ERR_get_error(), NULL)); + break; + } + + wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); + dh = DSA_dup_DH(dsa); + DSA_free(dsa); + if (dh == NULL) { + wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " + "params into DH params"); + break; + } + break; + } +#endif /* !OPENSSL_NO_DSA */ + if (dh == NULL) { + wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " + "'%s'", dh_file); + return -1; + } + + if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { + wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " + "%s", dh_file, + ERR_error_string(ERR_get_error(), NULL)); + DH_free(dh); + return -1; + } + DH_free(dh); + return 0; +#endif /* OPENSSL_NO_DH */ +} + + +static int tls_global_dh(struct tls_data *data, const char *dh_file) +{ +#ifdef OPENSSL_NO_DH + if (dh_file == NULL) + return 0; + wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " + "dh_file specified"); + return -1; +#else /* OPENSSL_NO_DH */ + SSL_CTX *ssl_ctx = data->ssl; + DH *dh; + BIO *bio; + + /* TODO: add support for dh_blob */ + if (dh_file == NULL) + return 0; + if (ssl_ctx == NULL) + return -1; + + bio = BIO_new_file(dh_file, "r"); + if (bio == NULL) { + wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", + dh_file, ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + BIO_free(bio); +#ifndef OPENSSL_NO_DSA + while (dh == NULL) { + DSA *dsa; + wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" + " trying to parse as DSA params", dh_file, + ERR_error_string(ERR_get_error(), NULL)); + bio = BIO_new_file(dh_file, "r"); + if (bio == NULL) + break; + dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); + BIO_free(bio); + if (!dsa) { + wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " + "'%s': %s", dh_file, + ERR_error_string(ERR_get_error(), NULL)); + break; + } + + wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); + dh = DSA_dup_DH(dsa); + DSA_free(dsa); + if (dh == NULL) { + wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " + "params into DH params"); + break; + } + break; + } +#endif /* !OPENSSL_NO_DSA */ + if (dh == NULL) { + wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " + "'%s'", dh_file); + return -1; + } + + if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { + wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " + "%s", dh_file, + ERR_error_string(ERR_get_error(), NULL)); + DH_free(dh); + return -1; + } + DH_free(dh); + return 0; +#endif /* OPENSSL_NO_DH */ +} + + +int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, + struct tls_random *keys) +{ + SSL *ssl; + + if (conn == NULL || keys == NULL) + return -1; + ssl = conn->ssl; +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) + return -1; + + os_memset(keys, 0, sizeof(*keys)); + keys->client_random = ssl->s3->client_random; + keys->client_random_len = SSL3_RANDOM_SIZE; + keys->server_random = ssl->s3->server_random; + keys->server_random_len = SSL3_RANDOM_SIZE; +#else + if (ssl == NULL) + return -1; + + os_memset(keys, 0, sizeof(*keys)); + keys->client_random = conn->client_random; + keys->client_random_len = SSL_get_client_random( + ssl, conn->client_random, sizeof(conn->client_random)); + keys->server_random = conn->server_random; + keys->server_random_len = SSL_get_server_random( + ssl, conn->server_random, sizeof(conn->server_random)); +#endif + + return 0; +} + + +#ifndef CONFIG_FIPS +static int openssl_get_keyblock_size(SSL *ssl) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + const EVP_CIPHER *c; + const EVP_MD *h; + int md_size; + + if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL || + ssl->read_hash == NULL) + return -1; + + c = ssl->enc_read_ctx->cipher; +#if OPENSSL_VERSION_NUMBER >= 0x00909000L + h = EVP_MD_CTX_md(ssl->read_hash); +#else + h = ssl->read_hash; +#endif + if (h) + md_size = EVP_MD_size(h); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + else if (ssl->s3) + md_size = ssl->s3->tmp.new_mac_secret_size; +#endif + else + return -1; + + wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d " + "IV_len=%d", EVP_CIPHER_key_length(c), md_size, + EVP_CIPHER_iv_length(c)); + return 2 * (EVP_CIPHER_key_length(c) + + md_size + + EVP_CIPHER_iv_length(c)); +#else + const SSL_CIPHER *ssl_cipher; + int cipher, digest; + const EVP_CIPHER *c; + const EVP_MD *h; + + ssl_cipher = SSL_get_current_cipher(ssl); + if (!ssl_cipher) + return -1; + cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher); + digest = SSL_CIPHER_get_digest_nid(ssl_cipher); + wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d", + cipher, digest); + if (cipher < 0 || digest < 0) + return -1; + c = EVP_get_cipherbynid(cipher); + h = EVP_get_digestbynid(digest); + if (!c || !h) + return -1; + + wpa_printf(MSG_DEBUG, + "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d", + EVP_CIPHER_key_length(c), EVP_MD_size(h), + EVP_CIPHER_iv_length(c)); + return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) + + EVP_CIPHER_iv_length(c)); +#endif +} +#endif /* CONFIG_FIPS */ + + +static int openssl_tls_prf(struct tls_connection *conn, + const char *label, int server_random_first, + int skip_keyblock, u8 *out, size_t out_len) +{ +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS " + "mode"); + return -1; +#else /* CONFIG_FIPS */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SSL *ssl; + u8 *rnd; + int ret = -1; + int skip = 0; + u8 *tmp_out = NULL; + u8 *_out = out; + const char *ver; + + /* + * TLS library did not support key generation, so get the needed TLS + * session parameters and use an internal implementation of TLS PRF to + * derive the key. + */ + + if (conn == NULL) + return -1; + ssl = conn->ssl; + if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL || + ssl->session->master_key_length <= 0) + return -1; + ver = SSL_get_version(ssl); + + if (skip_keyblock) { + skip = openssl_get_keyblock_size(ssl); + if (skip < 0) + return -1; + tmp_out = os_malloc(skip + out_len); + if (!tmp_out) + return -1; + _out = tmp_out; + } + + rnd = os_malloc(2 * SSL3_RANDOM_SIZE); + if (!rnd) { + os_free(tmp_out); + return -1; + } + + if (server_random_first) { + os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random, + SSL3_RANDOM_SIZE); + } else { + os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random, + SSL3_RANDOM_SIZE); + } + + if (os_strcmp(ver, "TLSv1.2") == 0) { + tls_prf_sha256(ssl->session->master_key, + ssl->session->master_key_length, + label, rnd, 2 * SSL3_RANDOM_SIZE, + _out, skip + out_len); + ret = 0; + } else if (tls_prf_sha1_md5(ssl->session->master_key, + ssl->session->master_key_length, + label, rnd, 2 * SSL3_RANDOM_SIZE, + _out, skip + out_len) == 0) { + ret = 0; + } + os_free(rnd); + if (ret == 0 && skip_keyblock) + os_memcpy(out, _out + skip, out_len); + bin_clear_free(tmp_out, skip); + + return ret; +#else + SSL *ssl; + SSL_SESSION *sess; + u8 *rnd; + int ret = -1; + int skip = 0; + u8 *tmp_out = NULL; + u8 *_out = out; + unsigned char client_random[SSL3_RANDOM_SIZE]; + unsigned char server_random[SSL3_RANDOM_SIZE]; + unsigned char master_key[64]; + size_t master_key_len; + const char *ver; + + /* + * TLS library did not support key generation, so get the needed TLS + * session parameters and use an internal implementation of TLS PRF to + * derive the key. + */ + + if (conn == NULL) + return -1; + ssl = conn->ssl; + if (ssl == NULL) + return -1; + ver = SSL_get_version(ssl); + sess = SSL_get_session(ssl); + if (!ver || !sess) + return -1; + + if (skip_keyblock) { + skip = openssl_get_keyblock_size(ssl); + if (skip < 0) + return -1; + tmp_out = os_malloc(skip + out_len); + if (!tmp_out) + return -1; + _out = tmp_out; + } + + rnd = os_malloc(2 * SSL3_RANDOM_SIZE); + if (!rnd) { + os_free(tmp_out); + return -1; + } + + SSL_get_client_random(ssl, client_random, sizeof(client_random)); + SSL_get_server_random(ssl, server_random, sizeof(server_random)); + master_key_len = SSL_SESSION_get_master_key(sess, master_key, + sizeof(master_key)); + + if (server_random_first) { + os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, + SSL3_RANDOM_SIZE); + } else { + os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random, + SSL3_RANDOM_SIZE); + } + + if (os_strcmp(ver, "TLSv1.2") == 0) { + tls_prf_sha256(master_key, master_key_len, + label, rnd, 2 * SSL3_RANDOM_SIZE, + _out, skip + out_len); + ret = 0; + } else if (tls_prf_sha1_md5(master_key, master_key_len, + label, rnd, 2 * SSL3_RANDOM_SIZE, + _out, skip + out_len) == 0) { + ret = 0; + } + os_memset(master_key, 0, sizeof(master_key)); + os_free(rnd); + if (ret == 0 && skip_keyblock) + os_memcpy(out, _out + skip, out_len); + bin_clear_free(tmp_out, skip); + + return ret; +#endif +#endif /* CONFIG_FIPS */ +} + + +int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, + const char *label, int server_random_first, + int skip_keyblock, u8 *out, size_t out_len) +{ +#if OPENSSL_VERSION_NUMBER >= 0x10001000L + SSL *ssl; + if (conn == NULL) + return -1; + if (server_random_first || skip_keyblock) + return openssl_tls_prf(conn, label, + server_random_first, skip_keyblock, + out, out_len); + ssl = conn->ssl; + if (SSL_export_keying_material(ssl, out, out_len, label, + os_strlen(label), NULL, 0, 0) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF"); + return 0; + } +#endif + return openssl_tls_prf(conn, label, server_random_first, + skip_keyblock, out, out_len); +} + + +static struct wpabuf * +openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, + int server) +{ + int res; + struct wpabuf *out_data; + + /* + * Give TLS handshake data from the server (if available) to OpenSSL + * for processing. + */ + if (in_data && wpabuf_len(in_data) > 0 && + BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) + < 0) { + tls_show_errors(MSG_INFO, __func__, + "Handshake failed - BIO_write"); + return NULL; + } + + /* Initiate TLS handshake or continue the existing handshake */ + if (server) + res = SSL_accept(conn->ssl); + else + res = SSL_connect(conn->ssl); + if (res != 1) { + int err = SSL_get_error(conn->ssl, res); + if (err == SSL_ERROR_WANT_READ) + wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " + "more data"); + else if (err == SSL_ERROR_WANT_WRITE) + wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " + "write"); + else { + tls_show_errors(MSG_INFO, __func__, "SSL_connect"); + conn->failed++; + } + } + + /* Get the TLS handshake data to be sent to the server */ + res = BIO_ctrl_pending(conn->ssl_out); + wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); + out_data = wpabuf_alloc(res); + if (out_data == NULL) { + wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " + "handshake output (%d bytes)", res); + if (BIO_reset(conn->ssl_out) < 0) { + tls_show_errors(MSG_INFO, __func__, + "BIO_reset failed"); + } + return NULL; + } + res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), + res); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Handshake failed - BIO_read"); + if (BIO_reset(conn->ssl_out) < 0) { + tls_show_errors(MSG_INFO, __func__, + "BIO_reset failed"); + } + wpabuf_free(out_data); + return NULL; + } + wpabuf_put(out_data, res); + + return out_data; +} + + +static struct wpabuf * +openssl_get_appl_data(struct tls_connection *conn, size_t max_len) +{ + struct wpabuf *appl_data; + int res; + + appl_data = wpabuf_alloc(max_len + 100); + if (appl_data == NULL) + return NULL; + + res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), + wpabuf_size(appl_data)); + if (res < 0) { + int err = SSL_get_error(conn->ssl, res); + if (err == SSL_ERROR_WANT_READ || + err == SSL_ERROR_WANT_WRITE) { + wpa_printf(MSG_DEBUG, "SSL: No Application Data " + "included"); + } else { + tls_show_errors(MSG_INFO, __func__, + "Failed to read possible " + "Application Data"); + } + wpabuf_free(appl_data); + return NULL; + } + + wpabuf_put(appl_data, res); + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " + "message", appl_data); + + return appl_data; +} + + +static struct wpabuf * +openssl_connection_handshake(struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data, int server) +{ + struct wpabuf *out_data; + + if (appl_data) + *appl_data = NULL; + + out_data = openssl_handshake(conn, in_data, server); + if (out_data == NULL) + return NULL; + if (conn->invalid_hb_used) { + wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); + wpabuf_free(out_data); + return NULL; + } + + if (SSL_is_init_finished(conn->ssl)) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Handshake finished - resumed=%d", + tls_connection_resumed(conn->ssl_ctx, conn)); + if (appl_data && in_data) + *appl_data = openssl_get_appl_data(conn, + wpabuf_len(in_data)); + } + + if (conn->invalid_hb_used) { + wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); + if (appl_data) { + wpabuf_free(*appl_data); + *appl_data = NULL; + } + wpabuf_free(out_data); + return NULL; + } + + return out_data; +} + + +struct wpabuf * +tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 0); +} + + +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 1); +} + + +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + int res; + struct wpabuf *buf; + + if (conn == NULL) + return NULL; + + /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ + if ((res = BIO_reset(conn->ssl_in)) < 0 || + (res = BIO_reset(conn->ssl_out)) < 0) { + tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); + return NULL; + } + res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Encryption failed - SSL_write"); + return NULL; + } + + /* Read encrypted data to be sent to the server */ + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Encryption failed - BIO_read"); + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + + return buf; +} + + +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + int res; + struct wpabuf *buf; + + /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ + res = BIO_write(conn->ssl_in, wpabuf_head(in_data), + wpabuf_len(in_data)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Decryption failed - BIO_write"); + return NULL; + } + if (BIO_reset(conn->ssl_out) < 0) { + tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); + return NULL; + } + + /* Read decrypted data for further processing */ + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Decryption failed - SSL_read"); + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + + if (conn->invalid_hb_used) { + wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); + wpabuf_free(buf); + return NULL; + } + + return buf; +} + + +int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) +{ +#if OPENSSL_VERSION_NUMBER >= 0x10001000L + return conn ? SSL_cache_hit(conn->ssl) : 0; +#else + return conn ? conn->ssl->hit : 0; +#endif +} + + +int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, + u8 *ciphers) +{ + char buf[100], *pos, *end; + u8 *c; + int ret; + + if (conn == NULL || conn->ssl == NULL || ciphers == NULL) + return -1; + + buf[0] = '\0'; + pos = buf; + end = pos + sizeof(buf); + + c = ciphers; + while (*c != TLS_CIPHER_NONE) { + const char *suite; + + switch (*c) { + case TLS_CIPHER_RC4_SHA: + suite = "RC4-SHA"; + break; + case TLS_CIPHER_AES128_SHA: + suite = "AES128-SHA"; + break; + case TLS_CIPHER_RSA_DHE_AES128_SHA: + suite = "DHE-RSA-AES128-SHA"; + break; + case TLS_CIPHER_ANON_DH_AES128_SHA: + suite = "ADH-AES128-SHA"; + break; + default: + wpa_printf(MSG_DEBUG, "TLS: Unsupported " + "cipher selection: %d", *c); + return -1; + } + ret = os_snprintf(pos, end - pos, ":%s", suite); + if (os_snprintf_error(end - pos, ret)) + break; + pos += ret; + + c++; + } + + wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) + if (os_strstr(buf, ":ADH-")) { + /* + * Need to drop to security level 0 to allow anonymous + * cipher suites for EAP-FAST. + */ + SSL_set_security_level(conn->ssl, 0); + } else if (SSL_get_security_level(conn->ssl) == 0) { + /* Force at least security level 1 */ + SSL_set_security_level(conn->ssl, 1); + } +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ +#endif + + if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { + tls_show_errors(MSG_INFO, __func__, + "Cipher suite configuration failed"); + return -1; + } + + return 0; +} + + +int tls_get_version(void *ssl_ctx, struct tls_connection *conn, + char *buf, size_t buflen) +{ + const char *name; + if (conn == NULL || conn->ssl == NULL) + return -1; + + name = SSL_get_version(conn->ssl); + if (name == NULL) + return -1; + + os_strlcpy(buf, name, buflen); + return 0; +} + + +int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, + char *buf, size_t buflen) +{ + const char *name; + if (conn == NULL || conn->ssl == NULL) + return -1; + + name = SSL_get_cipher(conn->ssl); + if (name == NULL) + return -1; + + os_strlcpy(buf, name, buflen); + return 0; +} + + +int tls_connection_enable_workaround(void *ssl_ctx, + struct tls_connection *conn) +{ + SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + + return 0; +} + + +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) +/* ClientHello TLS extensions require a patch to openssl, so this function is + * commented out unless explicitly needed for EAP-FAST in order to be able to + * build this file with unmodified openssl. */ +int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, + int ext_type, const u8 *data, + size_t data_len) +{ + if (conn == NULL || conn->ssl == NULL || ext_type != 35) + return -1; + + if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, + data_len) != 1) + return -1; + + return 0; +} +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + + +int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + return conn->failed; +} + + +int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + return conn->read_alerts; +} + + +int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + return conn->write_alerts; +} + + +#ifdef HAVE_OCSP + +static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) +{ +#ifndef CONFIG_NO_STDOUT_DEBUG + BIO *out; + size_t rlen; + char *txt; + int res; + + if (wpa_debug_level > MSG_DEBUG) + return; + + out = BIO_new(BIO_s_mem()); + if (!out) + return; + + OCSP_RESPONSE_print(out, rsp, 0); + rlen = BIO_ctrl_pending(out); + txt = os_malloc(rlen + 1); + if (!txt) { + BIO_free(out); + return; + } + + res = BIO_read(out, txt, rlen); + if (res > 0) { + txt[res] = '\0'; + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt); + } + os_free(txt); + BIO_free(out); +#endif /* CONFIG_NO_STDOUT_DEBUG */ +} + + +static void debug_print_cert(X509 *cert, const char *title) +{ +#ifndef CONFIG_NO_STDOUT_DEBUG + BIO *out; + size_t rlen; + char *txt; + int res; + + if (wpa_debug_level > MSG_DEBUG) + return; + + out = BIO_new(BIO_s_mem()); + if (!out) + return; + + X509_print(out, cert); + rlen = BIO_ctrl_pending(out); + txt = os_malloc(rlen + 1); + if (!txt) { + BIO_free(out); + return; + } + + res = BIO_read(out, txt, rlen); + if (res > 0) { + txt[res] = '\0'; + wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt); + } + os_free(txt); + + BIO_free(out); +#endif /* CONFIG_NO_STDOUT_DEBUG */ +} + + +static int ocsp_resp_cb(SSL *s, void *arg) +{ + struct tls_connection *conn = arg; + const unsigned char *p; + int len, status, reason; + OCSP_RESPONSE *rsp; + OCSP_BASICRESP *basic; + OCSP_CERTID *id; + ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; + X509_STORE *store; + STACK_OF(X509) *certs = NULL; + + len = SSL_get_tlsext_status_ocsp_resp(s, &p); + if (!p) { + wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); + return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; + } + + wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); + + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if (!rsp) { + wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); + return 0; + } + + ocsp_debug_print_resp(rsp); + + status = OCSP_response_status(rsp); + if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", + status, OCSP_response_status_str(status)); + return 0; + } + + basic = OCSP_response_get1_basic(rsp); + if (!basic) { + wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); + return 0; + } + + store = SSL_CTX_get_cert_store(conn->ssl_ctx); + if (conn->peer_issuer) { + debug_print_cert(conn->peer_issuer, "Add OCSP issuer"); + + if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) { + tls_show_errors(MSG_INFO, __func__, + "OpenSSL: Could not add issuer to certificate store"); + } + certs = sk_X509_new_null(); + if (certs) { + X509 *cert; + cert = X509_dup(conn->peer_issuer); + if (cert && !sk_X509_push(certs, cert)) { + tls_show_errors( + MSG_INFO, __func__, + "OpenSSL: Could not add issuer to OCSP responder trust store"); + X509_free(cert); + sk_X509_free(certs); + certs = NULL; + } + if (certs && conn->peer_issuer_issuer) { + cert = X509_dup(conn->peer_issuer_issuer); + if (cert && !sk_X509_push(certs, cert)) { + tls_show_errors( + MSG_INFO, __func__, + "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); + X509_free(cert); + } + } + } + } + + status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); + sk_X509_pop_free(certs, X509_free); + if (status <= 0) { + tls_show_errors(MSG_INFO, __func__, + "OpenSSL: OCSP response failed verification"); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + return 0; + } + + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); + + if (!conn->peer_cert) { + wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + return 0; + } + + if (!conn->peer_issuer) { + wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + return 0; + } + + id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer); + if (!id) { + wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier"); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + return 0; + } + + if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, + &this_update, &next_update)) { + wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", + (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" : + " (OCSP not required)"); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; + } + + if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { + tls_show_errors(MSG_INFO, __func__, + "OpenSSL: OCSP status times invalid"); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + return 0; + } + + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", + OCSP_cert_status_str(status)); + + if (status == V_OCSP_CERTSTATUS_GOOD) + return 1; + if (status == V_OCSP_CERTSTATUS_REVOKED) + return 0; + if (conn->flags & TLS_CONN_REQUIRE_OCSP) { + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); + return 0; + } + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); + return 1; +} + + +static int ocsp_status_cb(SSL *s, void *arg) +{ + char *tmp; + char *resp; + size_t len; + + if (tls_global->ocsp_stapling_response == NULL) { + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured"); + return SSL_TLSEXT_ERR_OK; + } + + resp = os_readfile(tls_global->ocsp_stapling_response, &len); + if (resp == NULL) { + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file"); + /* TODO: Build OCSPResponse with responseStatus = internalError + */ + return SSL_TLSEXT_ERR_OK; + } + wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response"); + tmp = OPENSSL_malloc(len); + if (tmp == NULL) { + os_free(resp); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + os_memcpy(tmp, resp, len); + os_free(resp); + SSL_set_tlsext_status_ocsp_resp(s, tmp, len); + + return SSL_TLSEXT_ERR_OK; +} + +#endif /* HAVE_OCSP */ + + +int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, + const struct tls_connection_params *params) +{ + struct tls_data *data = tls_ctx; + int ret; + unsigned long err; + int can_pkcs11 = 0; + const char *key_id = params->key_id; + const char *cert_id = params->cert_id; + const char *ca_cert_id = params->ca_cert_id; + const char *engine_id = params->engine ? params->engine_id : NULL; + + if (conn == NULL) + return -1; + + /* + * If the engine isn't explicitly configured, and any of the + * cert/key fields are actually PKCS#11 URIs, then automatically + * use the PKCS#11 ENGINE. + */ + if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0) + can_pkcs11 = 1; + + if (!key_id && params->private_key && can_pkcs11 && + os_strncmp(params->private_key, "pkcs11:", 7) == 0) { + can_pkcs11 = 2; + key_id = params->private_key; + } + + if (!cert_id && params->client_cert && can_pkcs11 && + os_strncmp(params->client_cert, "pkcs11:", 7) == 0) { + can_pkcs11 = 2; + cert_id = params->client_cert; + } + + if (!ca_cert_id && params->ca_cert && can_pkcs11 && + os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) { + can_pkcs11 = 2; + ca_cert_id = params->ca_cert; + } + + /* If we need to automatically enable the PKCS#11 ENGINE, do so. */ + if (can_pkcs11 == 2 && !engine_id) + engine_id = "pkcs11"; + +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (params->flags & TLS_CONN_EAP_FAST) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Use TLSv1_method() for EAP-FAST"); + if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) { + tls_show_errors(MSG_INFO, __func__, + "Failed to set TLSv1_method() for EAP-FAST"); + return -1; + } + } +#endif +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + + while ((err = ERR_get_error())) { + wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", + __func__, ERR_error_string(err, NULL)); + } + + if (engine_id) { + wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); + ret = tls_engine_init(conn, engine_id, params->pin, + key_id, cert_id, ca_cert_id); + if (ret) + return ret; + } + if (tls_connection_set_subject_match(conn, + params->subject_match, + params->altsubject_match, + params->suffix_match, + params->domain_match)) + return -1; + + if (engine_id && ca_cert_id) { + if (tls_connection_engine_ca_cert(data, conn, ca_cert_id)) + return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; + } else if (tls_connection_ca_cert(data, conn, params->ca_cert, + params->ca_cert_blob, + params->ca_cert_blob_len, + params->ca_path)) + return -1; + + if (engine_id && cert_id) { + if (tls_connection_engine_client_cert(conn, cert_id)) + return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; + } else if (tls_connection_client_cert(conn, params->client_cert, + params->client_cert_blob, + params->client_cert_blob_len)) + return -1; + + if (engine_id && key_id) { + wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); + if (tls_connection_engine_private_key(conn)) + return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; + } else if (tls_connection_private_key(data, conn, + params->private_key, + params->private_key_passwd, + params->private_key_blob, + params->private_key_blob_len)) { + wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", + params->private_key); + return -1; + } + + if (tls_connection_dh(conn, params->dh_file)) { + wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", + params->dh_file); + return -1; + } + + if (params->openssl_ciphers && + SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) { + wpa_printf(MSG_INFO, + "OpenSSL: Failed to set cipher string '%s'", + params->openssl_ciphers); + return -1; + } + + tls_set_conn_flags(conn->ssl, params->flags); + +#ifdef HAVE_OCSP + if (params->flags & TLS_CONN_REQUEST_OCSP) { + SSL_CTX *ssl_ctx = data->ssl; + SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp); + SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb); + SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn); + } +#else /* HAVE_OCSP */ + if (params->flags & TLS_CONN_REQUIRE_OCSP) { + wpa_printf(MSG_INFO, + "OpenSSL: No OCSP support included - reject configuration"); + return -1; + } + if (params->flags & TLS_CONN_REQUEST_OCSP) { + wpa_printf(MSG_DEBUG, + "OpenSSL: No OCSP support included - allow optional OCSP case to continue"); + } +#endif /* HAVE_OCSP */ + + conn->flags = params->flags; + + tls_get_errors(data); + + return 0; +} + + +int tls_global_set_params(void *tls_ctx, + const struct tls_connection_params *params) +{ + struct tls_data *data = tls_ctx; + SSL_CTX *ssl_ctx = data->ssl; + unsigned long err; + + while ((err = ERR_get_error())) { + wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", + __func__, ERR_error_string(err, NULL)); + } + + if (tls_global_ca_cert(data, params->ca_cert) || + tls_global_client_cert(data, params->client_cert) || + tls_global_private_key(data, params->private_key, + params->private_key_passwd) || + tls_global_dh(data, params->dh_file)) { + wpa_printf(MSG_INFO, "TLS: Failed to set global parameters"); + return -1; + } + + if (params->openssl_ciphers && + SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) { + wpa_printf(MSG_INFO, + "OpenSSL: Failed to set cipher string '%s'", + params->openssl_ciphers); + return -1; + } + +#ifdef SSL_OP_NO_TICKET + if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET) + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET); +#ifdef SSL_CTX_clear_options + else + SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET); +#endif /* SSL_clear_options */ +#endif /* SSL_OP_NO_TICKET */ + +#ifdef HAVE_OCSP + SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb); + SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx); + os_free(tls_global->ocsp_stapling_response); + if (params->ocsp_stapling_response) + tls_global->ocsp_stapling_response = + os_strdup(params->ocsp_stapling_response); + else + tls_global->ocsp_stapling_response = NULL; +#endif /* HAVE_OCSP */ + + return 0; +} + + +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) +/* Pre-shared secred requires a patch to openssl, so this function is + * commented out unless explicitly needed for EAP-FAST in order to be able to + * build this file with unmodified openssl. */ + +#ifdef OPENSSL_IS_BORINGSSL +static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, + STACK_OF(SSL_CIPHER) *peer_ciphers, + const SSL_CIPHER **cipher, void *arg) +#else /* OPENSSL_IS_BORINGSSL */ +static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, + STACK_OF(SSL_CIPHER) *peer_ciphers, + SSL_CIPHER **cipher, void *arg) +#endif /* OPENSSL_IS_BORINGSSL */ +{ + struct tls_connection *conn = arg; + int ret; + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (conn == NULL || conn->session_ticket_cb == NULL) + return 0; + + ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, + conn->session_ticket, + conn->session_ticket_len, + s->s3->client_random, + s->s3->server_random, secret); +#else + unsigned char client_random[SSL3_RANDOM_SIZE]; + unsigned char server_random[SSL3_RANDOM_SIZE]; + + if (conn == NULL || conn->session_ticket_cb == NULL) + return 0; + + SSL_get_client_random(s, client_random, sizeof(client_random)); + SSL_get_server_random(s, server_random, sizeof(server_random)); + + ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, + conn->session_ticket, + conn->session_ticket_len, + client_random, + server_random, secret); +#endif + + os_free(conn->session_ticket); + conn->session_ticket = NULL; + + if (ret <= 0) + return 0; + + *secret_len = SSL_MAX_MASTER_KEY_LENGTH; + return 1; +} + + +static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, + int len, void *arg) +{ + struct tls_connection *conn = arg; + + if (conn == NULL || conn->session_ticket_cb == NULL) + return 0; + + wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); + + os_free(conn->session_ticket); + conn->session_ticket = NULL; + + wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " + "extension", data, len); + + conn->session_ticket = os_malloc(len); + if (conn->session_ticket == NULL) + return 0; + + os_memcpy(conn->session_ticket, data, len); + conn->session_ticket_len = len; + + return 1; +} +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + + +int tls_connection_set_session_ticket_cb(void *tls_ctx, + struct tls_connection *conn, + tls_session_ticket_cb cb, + void *ctx) +{ +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) + conn->session_ticket_cb = cb; + conn->session_ticket_cb_ctx = ctx; + + if (cb) { + if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, + conn) != 1) + return -1; + SSL_set_session_ticket_ext_cb(conn->ssl, + tls_session_ticket_ext_cb, conn); + } else { + if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) + return -1; + SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); + } + + return 0; +#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + return -1; +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ +} + + +int tls_get_library_version(char *buf, size_t buf_len) +{ + return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s", + OPENSSL_VERSION_TEXT, + SSLeay_version(SSLEAY_VERSION)); +} + + +void tls_connection_set_success_data(struct tls_connection *conn, + struct wpabuf *data) +{ + SSL_SESSION *sess; + struct wpabuf *old; + + if (tls_ex_idx_session < 0) + goto fail; + sess = SSL_get_session(conn->ssl); + if (!sess) + goto fail; + old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); + if (old) { + wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p", + old); + wpabuf_free(old); + } + if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) + goto fail; + + wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data); + conn->success_data = 1; + return; + +fail: + wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data"); + wpabuf_free(data); +} + + +void tls_connection_set_success_data_resumed(struct tls_connection *conn) +{ + wpa_printf(MSG_DEBUG, + "OpenSSL: Success data accepted for resumed session"); + conn->success_data = 1; +} + + +const struct wpabuf * +tls_connection_get_success_data(struct tls_connection *conn) +{ + SSL_SESSION *sess; + + if (tls_ex_idx_session < 0 || + !(sess = SSL_get_session(conn->ssl))) + return NULL; + return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); +} + + +void tls_connection_remove_session(struct tls_connection *conn) +{ + SSL_SESSION *sess; + + sess = SSL_get_session(conn->ssl); + if (!sess) + return; + + if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1) + wpa_printf(MSG_DEBUG, + "OpenSSL: Session was not cached"); + else + wpa_printf(MSG_DEBUG, + "OpenSSL: Removed cached session to disable session resumption"); +} diff --git a/src/drivers/.gitignore b/libeap/src/drivers/.gitignore similarity index 100% rename from src/drivers/.gitignore rename to libeap/src/drivers/.gitignore diff --git a/src/drivers/Makefile b/libeap/src/drivers/Makefile similarity index 100% rename from src/drivers/Makefile rename to libeap/src/drivers/Makefile diff --git a/src/drivers/android_drv.h b/libeap/src/drivers/android_drv.h similarity index 100% rename from src/drivers/android_drv.h rename to libeap/src/drivers/android_drv.h diff --git a/src/drivers/driver.h b/libeap/src/drivers/driver.h similarity index 100% rename from src/drivers/driver.h rename to libeap/src/drivers/driver.h diff --git a/src/drivers/driver_atheros.c b/libeap/src/drivers/driver_atheros.c similarity index 100% rename from src/drivers/driver_atheros.c rename to libeap/src/drivers/driver_atheros.c diff --git a/src/drivers/driver_bsd.c b/libeap/src/drivers/driver_bsd.c similarity index 100% rename from src/drivers/driver_bsd.c rename to libeap/src/drivers/driver_bsd.c diff --git a/src/drivers/driver_common.c b/libeap/src/drivers/driver_common.c similarity index 100% rename from src/drivers/driver_common.c rename to libeap/src/drivers/driver_common.c diff --git a/src/drivers/driver_hostap.c b/libeap/src/drivers/driver_hostap.c similarity index 100% rename from src/drivers/driver_hostap.c rename to libeap/src/drivers/driver_hostap.c diff --git a/src/drivers/driver_hostap.h b/libeap/src/drivers/driver_hostap.h similarity index 100% rename from src/drivers/driver_hostap.h rename to libeap/src/drivers/driver_hostap.h diff --git a/src/drivers/driver_macsec_qca.c b/libeap/src/drivers/driver_macsec_qca.c similarity index 100% rename from src/drivers/driver_macsec_qca.c rename to libeap/src/drivers/driver_macsec_qca.c diff --git a/src/drivers/driver_ndis.c b/libeap/src/drivers/driver_ndis.c similarity index 100% rename from src/drivers/driver_ndis.c rename to libeap/src/drivers/driver_ndis.c diff --git a/src/drivers/driver_ndis.h b/libeap/src/drivers/driver_ndis.h similarity index 100% rename from src/drivers/driver_ndis.h rename to libeap/src/drivers/driver_ndis.h diff --git a/src/drivers/driver_ndis_.c b/libeap/src/drivers/driver_ndis_.c similarity index 100% rename from src/drivers/driver_ndis_.c rename to libeap/src/drivers/driver_ndis_.c diff --git a/src/drivers/driver_nl80211.c b/libeap/src/drivers/driver_nl80211.c similarity index 100% rename from src/drivers/driver_nl80211.c rename to libeap/src/drivers/driver_nl80211.c diff --git a/src/drivers/driver_nl80211.h b/libeap/src/drivers/driver_nl80211.h similarity index 100% rename from src/drivers/driver_nl80211.h rename to libeap/src/drivers/driver_nl80211.h diff --git a/src/drivers/driver_nl80211_android.c b/libeap/src/drivers/driver_nl80211_android.c similarity index 100% rename from src/drivers/driver_nl80211_android.c rename to libeap/src/drivers/driver_nl80211_android.c diff --git a/src/drivers/driver_nl80211_capa.c b/libeap/src/drivers/driver_nl80211_capa.c similarity index 100% rename from src/drivers/driver_nl80211_capa.c rename to libeap/src/drivers/driver_nl80211_capa.c diff --git a/src/drivers/driver_nl80211_event.c b/libeap/src/drivers/driver_nl80211_event.c similarity index 100% rename from src/drivers/driver_nl80211_event.c rename to libeap/src/drivers/driver_nl80211_event.c diff --git a/src/drivers/driver_nl80211_monitor.c b/libeap/src/drivers/driver_nl80211_monitor.c similarity index 100% rename from src/drivers/driver_nl80211_monitor.c rename to libeap/src/drivers/driver_nl80211_monitor.c diff --git a/src/drivers/driver_nl80211_scan.c b/libeap/src/drivers/driver_nl80211_scan.c similarity index 100% rename from src/drivers/driver_nl80211_scan.c rename to libeap/src/drivers/driver_nl80211_scan.c diff --git a/src/drivers/driver_none.c b/libeap/src/drivers/driver_none.c similarity index 100% rename from src/drivers/driver_none.c rename to libeap/src/drivers/driver_none.c diff --git a/src/drivers/driver_openbsd.c b/libeap/src/drivers/driver_openbsd.c similarity index 100% rename from src/drivers/driver_openbsd.c rename to libeap/src/drivers/driver_openbsd.c diff --git a/src/drivers/driver_privsep.c b/libeap/src/drivers/driver_privsep.c similarity index 100% rename from src/drivers/driver_privsep.c rename to libeap/src/drivers/driver_privsep.c diff --git a/src/drivers/driver_roboswitch.c b/libeap/src/drivers/driver_roboswitch.c similarity index 100% rename from src/drivers/driver_roboswitch.c rename to libeap/src/drivers/driver_roboswitch.c diff --git a/src/drivers/driver_wext.c b/libeap/src/drivers/driver_wext.c similarity index 100% rename from src/drivers/driver_wext.c rename to libeap/src/drivers/driver_wext.c diff --git a/src/drivers/driver_wext.h b/libeap/src/drivers/driver_wext.h similarity index 100% rename from src/drivers/driver_wext.h rename to libeap/src/drivers/driver_wext.h diff --git a/src/drivers/driver_wired.c b/libeap/src/drivers/driver_wired.c similarity index 100% rename from src/drivers/driver_wired.c rename to libeap/src/drivers/driver_wired.c diff --git a/src/drivers/drivers.c b/libeap/src/drivers/drivers.c similarity index 100% rename from src/drivers/drivers.c rename to libeap/src/drivers/drivers.c diff --git a/src/drivers/drivers.mak b/libeap/src/drivers/drivers.mak similarity index 100% rename from src/drivers/drivers.mak rename to libeap/src/drivers/drivers.mak diff --git a/src/drivers/drivers.mk b/libeap/src/drivers/drivers.mk similarity index 100% rename from src/drivers/drivers.mk rename to libeap/src/drivers/drivers.mk diff --git a/src/drivers/linux_defines.h b/libeap/src/drivers/linux_defines.h similarity index 100% rename from src/drivers/linux_defines.h rename to libeap/src/drivers/linux_defines.h diff --git a/src/drivers/linux_ioctl.c b/libeap/src/drivers/linux_ioctl.c similarity index 100% rename from src/drivers/linux_ioctl.c rename to libeap/src/drivers/linux_ioctl.c diff --git a/src/drivers/linux_ioctl.h b/libeap/src/drivers/linux_ioctl.h similarity index 100% rename from src/drivers/linux_ioctl.h rename to libeap/src/drivers/linux_ioctl.h diff --git a/src/drivers/linux_wext.h b/libeap/src/drivers/linux_wext.h similarity index 100% rename from src/drivers/linux_wext.h rename to libeap/src/drivers/linux_wext.h diff --git a/src/drivers/ndis_events.c b/libeap/src/drivers/ndis_events.c similarity index 100% rename from src/drivers/ndis_events.c rename to libeap/src/drivers/ndis_events.c diff --git a/src/drivers/netlink.c b/libeap/src/drivers/netlink.c similarity index 100% rename from src/drivers/netlink.c rename to libeap/src/drivers/netlink.c diff --git a/src/drivers/netlink.h b/libeap/src/drivers/netlink.h similarity index 100% rename from src/drivers/netlink.h rename to libeap/src/drivers/netlink.h diff --git a/src/drivers/nl80211_copy.h b/libeap/src/drivers/nl80211_copy.h similarity index 100% rename from src/drivers/nl80211_copy.h rename to libeap/src/drivers/nl80211_copy.h diff --git a/src/drivers/priv_netlink.h b/libeap/src/drivers/priv_netlink.h similarity index 100% rename from src/drivers/priv_netlink.h rename to libeap/src/drivers/priv_netlink.h diff --git a/src/drivers/rfkill.c b/libeap/src/drivers/rfkill.c similarity index 100% rename from src/drivers/rfkill.c rename to libeap/src/drivers/rfkill.c diff --git a/src/drivers/rfkill.h b/libeap/src/drivers/rfkill.h similarity index 100% rename from src/drivers/rfkill.h rename to libeap/src/drivers/rfkill.h diff --git a/src/eap_common/Makefile b/libeap/src/eap_common/Makefile similarity index 100% rename from src/eap_common/Makefile rename to libeap/src/eap_common/Makefile diff --git a/src/eap_common/chap.c b/libeap/src/eap_common/chap.c similarity index 100% rename from src/eap_common/chap.c rename to libeap/src/eap_common/chap.c diff --git a/src/eap_common/chap.h b/libeap/src/eap_common/chap.h similarity index 100% rename from src/eap_common/chap.h rename to libeap/src/eap_common/chap.h diff --git a/src/eap_common/eap_common.c b/libeap/src/eap_common/eap_common.c similarity index 100% rename from src/eap_common/eap_common.c rename to libeap/src/eap_common/eap_common.c diff --git a/libeap/src/eap_common/eap_common.h b/libeap/src/eap_common/eap_common.h new file mode 100644 index 0000000..91cf7d5 --- /dev/null +++ b/libeap/src/eap_common/eap_common.h @@ -0,0 +1,41 @@ +/* + * EAP common peer/server definitions + * Copyright (c) 2004-2014, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_COMMON_H +#define EAP_COMMON_H + +#include "wpabuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct erp_tlvs { + const u8 *keyname; + const u8 *domain; + u8 keyname_len; + u8 domain_len; +}; + +int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); +const u8 * eap_hdr_validate(int vendor, EapType eap_type, + const struct wpabuf *msg, size_t *plen); +struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, + u8 code, u8 identifier); +void eap_update_len(struct wpabuf *msg); +u8 eap_get_id(const struct wpabuf *msg); +EapType eap_get_type(const struct wpabuf *msg); +int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs, + int stop_at_keyname); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_COMMON_H */ diff --git a/libeap/src/eap_common/eap_defs.h b/libeap/src/eap_common/eap_defs.h new file mode 100644 index 0000000..708e50d --- /dev/null +++ b/libeap/src/eap_common/eap_defs.h @@ -0,0 +1,126 @@ +/* + * EAP server/peer: Shared EAP definitions + * Copyright (c) 2004-2014, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_DEFS_H +#define EAP_DEFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* RFC 3748 - Extensible Authentication Protocol (EAP) */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_hdr { + u8 code; + u8 identifier; + be16 length; /* including code and identifier; network byte order */ + /* followed by length-4 octets of data */ +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, + EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 }; + +/* EAP Request and Response data begins with one octet Type. Success and + * Failure do not have additional data. */ + +/* Type field in EAP-Initiate and EAP-Finish messages */ +enum eap_erp_type { + EAP_ERP_TYPE_REAUTH_START = 1, + EAP_ERP_TYPE_REAUTH = 2, +}; + +/* ERP TV/TLV types */ +enum eap_erp_tlv_type { + EAP_ERP_TLV_KEYNAME_NAI = 1, + EAP_ERP_TV_RRK_LIFETIME = 2, + EAP_ERP_TV_RMSK_LIFETIME = 3, + EAP_ERP_TLV_DOMAIN_NAME = 4, + EAP_ERP_TLV_CRYPTOSUITES = 5, + EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6, + EAP_ERP_TLV_CALLED_STATION_ID = 128, + EAP_ERP_TLV_CALLING_STATION_ID = 129, + EAP_ERP_TLV_NAS_IDENTIFIER = 130, + EAP_ERP_TLV_NAS_IP_ADDRESS = 131, + EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132, +}; + +/* ERP Cryptosuite */ +enum eap_erp_cryptosuite { + EAP_ERP_CS_HMAC_SHA256_64 = 1, + EAP_ERP_CS_HMAC_SHA256_128 = 2, + EAP_ERP_CS_HMAC_SHA256_256 = 3, +}; + +/* + * EAP Method Types as allocated by IANA: + * http://www.iana.org/assignments/eap-numbers + */ +typedef enum { + EAP_TYPE_NONE = 0, + EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, + EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, + EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, + EAP_TYPE_MD5 = 4, /* RFC 3748 */ + EAP_TYPE_OTP = 5 /* RFC 3748 */, + EAP_TYPE_GTC = 6, /* RFC 3748 */ + EAP_TYPE_TLS = 13 /* RFC 2716 */, + EAP_TYPE_LEAP = 17 /* Cisco proprietary */, + EAP_TYPE_SIM = 18 /* RFC 4186 */, + EAP_TYPE_TTLS = 21 /* RFC 5281 */, + EAP_TYPE_AKA = 23 /* RFC 4187 */, + EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */, + EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */, + EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */, + EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment; + * type 38 has previously been allocated for + * EAP-HTTP Digest, (funk.com) */, + EAP_TYPE_FAST = 43 /* RFC 4851 */, + EAP_TYPE_PAX = 46 /* RFC 4746 */, + EAP_TYPE_PSK = 47 /* RFC 4764 */, + EAP_TYPE_SAKE = 48 /* RFC 4763 */, + EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, + EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */, + EAP_TYPE_GPSK = 51 /* RFC 5433 */, + EAP_TYPE_PWD = 52 /* RFC 5931 */, + EAP_TYPE_EKE = 53 /* RFC 6124 */, + EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ +} EapType; + + +/* SMI Network Management Private Enterprise Code for vendor specific types */ +enum { + EAP_VENDOR_IETF = 0, + EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, + EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance (moved to WBA) */, + EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */, + EAP_VENDOR_WFA_NEW = 40808 /* Wi-Fi Alliance */ +}; + +#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP +#define EAP_VENDOR_TYPE_UNAUTH_TLS 1 + +#define EAP_VENDOR_WFA_UNAUTH_TLS 13 + +#define EAP_MSK_LEN 64 +#define EAP_EMSK_LEN 64 +#define EAP_EMSK_NAME_LEN 8 +#define ERP_MAX_KEY_LEN 64 + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_DEFS_H */ diff --git a/src/eap_common/eap_eke_common.c b/libeap/src/eap_common/eap_eke_common.c similarity index 100% rename from src/eap_common/eap_eke_common.c rename to libeap/src/eap_common/eap_eke_common.c diff --git a/src/eap_common/eap_eke_common.h b/libeap/src/eap_common/eap_eke_common.h similarity index 100% rename from src/eap_common/eap_eke_common.h rename to libeap/src/eap_common/eap_eke_common.h diff --git a/src/eap_common/eap_fast_common.c b/libeap/src/eap_common/eap_fast_common.c similarity index 100% rename from src/eap_common/eap_fast_common.c rename to libeap/src/eap_common/eap_fast_common.c diff --git a/libeap/src/eap_common/eap_fast_common.h b/libeap/src/eap_common/eap_fast_common.h new file mode 100644 index 0000000..6d547fb --- /dev/null +++ b/libeap/src/eap_common/eap_fast_common.h @@ -0,0 +1,115 @@ +/* + * EAP-FAST definitions (RFC 4851) + * Copyright (c) 2004-2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_FAST_H +#define EAP_FAST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_FAST_VERSION 1 +#define EAP_FAST_KEY_LEN 64 +#define EAP_FAST_SIMCK_LEN 40 +#define EAP_FAST_SKS_LEN 40 +#define EAP_FAST_CMK_LEN 20 + +#define TLS_EXT_PAC_OPAQUE 35 + +/* + * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field + * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined + * in the general PAC TLV format (Section 4.2). + */ +#define PAC_TYPE_PAC_KEY 1 +#define PAC_TYPE_PAC_OPAQUE 2 +#define PAC_TYPE_CRED_LIFETIME 3 +#define PAC_TYPE_A_ID 4 +#define PAC_TYPE_I_ID 5 +/* + * 6 was previous assigned for SERVER_PROTECTED_DATA, but + * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved. + */ +#define PAC_TYPE_A_ID_INFO 7 +#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8 +#define PAC_TYPE_PAC_INFO 9 +#define PAC_TYPE_PAC_TYPE 10 + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct pac_tlv_hdr { + be16 type; + be16 len; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +#define EAP_FAST_PAC_KEY_LEN 32 + +/* RFC 5422: 4.2.6 PAC-Type TLV */ +#define PAC_TYPE_TUNNEL_PAC 1 +/* Application Specific Short Lived PACs (only in volatile storage) */ +/* User Authorization PAC */ +#define PAC_TYPE_USER_AUTHORIZATION 3 +/* Application Specific Long Lived PACs */ +/* Machine Authentication PAC */ +#define PAC_TYPE_MACHINE_AUTHENTICATION 2 + + +/* + * RFC 5422: + * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange + */ +struct eap_fast_key_block_provisioning { + /* Extra key material after TLS key_block */ + u8 session_key_seed[EAP_FAST_SKS_LEN]; + u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */ + u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */ +}; + + +struct wpabuf; +struct tls_connection; + +struct eap_fast_tlv_parse { + u8 *eap_payload_tlv; + size_t eap_payload_tlv_len; + struct eap_tlv_crypto_binding_tlv *crypto_binding; + size_t crypto_binding_len; + int iresult; + int result; + int request_action; + u8 *pac; + size_t pac_len; +}; + +void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len); +void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, + u16 len); +void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, + const struct wpabuf *data); +struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf); +void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, + const u8 *client_random, u8 *master_secret); +u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, + const char *label, size_t len); +void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk); +void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk); +int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, + int tlv_type, u8 *pos, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_FAST_H */ diff --git a/src/eap_common/eap_gpsk_common.c b/libeap/src/eap_common/eap_gpsk_common.c similarity index 100% rename from src/eap_common/eap_gpsk_common.c rename to libeap/src/eap_common/eap_gpsk_common.c diff --git a/libeap/src/eap_common/eap_gpsk_common.h b/libeap/src/eap_common/eap_gpsk_common.h new file mode 100644 index 0000000..0e18ec2 --- /dev/null +++ b/libeap/src/eap_common/eap_gpsk_common.h @@ -0,0 +1,74 @@ +/* + * EAP server/peer: EAP-GPSK shared routines + * Copyright (c) 2006-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_GPSK_COMMON_H +#define EAP_GPSK_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_GPSK_OPCODE_GPSK_1 1 +#define EAP_GPSK_OPCODE_GPSK_2 2 +#define EAP_GPSK_OPCODE_GPSK_3 3 +#define EAP_GPSK_OPCODE_GPSK_4 4 +#define EAP_GPSK_OPCODE_FAIL 5 +#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6 + +/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */ +#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001 +#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002 +#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003 + +#define EAP_GPSK_RAND_LEN 32 +#define EAP_GPSK_MAX_SK_LEN 32 +#define EAP_GPSK_MAX_PK_LEN 32 +#define EAP_GPSK_MAX_MIC_LEN 32 + +#define EAP_GPSK_VENDOR_IETF 0x00000000 +#define EAP_GPSK_CIPHER_RESERVED 0x000000 +#define EAP_GPSK_CIPHER_AES 0x000001 +#define EAP_GPSK_CIPHER_SHA256 0x000002 + + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_gpsk_csuite { + u8 vendor[4]; + u8 specifier[2]; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +int eap_gpsk_supported_ciphersuite(int vendor, int specifier); +int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, + int specifier, + const u8 *rand_client, const u8 *rand_server, + const u8 *id_client, size_t id_client_len, + const u8 *id_server, size_t id_server_len, + u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, + u8 *pk, size_t *pk_len); +int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, + int specifier, + const u8 *rand_peer, const u8 *rand_server, + const u8 *id_peer, size_t id_peer_len, + const u8 *id_server, size_t id_server_len, + u8 method_type, u8 *sid, size_t *sid_len); +size_t eap_gpsk_mic_len(int vendor, int specifier); +int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, + int specifier, const u8 *data, size_t len, u8 *mic); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_GPSK_COMMON_H */ diff --git a/src/eap_common/eap_ikev2_common.c b/libeap/src/eap_common/eap_ikev2_common.c similarity index 100% rename from src/eap_common/eap_ikev2_common.c rename to libeap/src/eap_common/eap_ikev2_common.c diff --git a/libeap/src/eap_common/eap_ikev2_common.h b/libeap/src/eap_common/eap_ikev2_common.h new file mode 100644 index 0000000..e3bade5 --- /dev/null +++ b/libeap/src/eap_common/eap_ikev2_common.h @@ -0,0 +1,37 @@ +/* + * EAP-IKEv2 definitions + * Copyright (c) 2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_IKEV2_COMMON_H +#define EAP_IKEV2_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80 +#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40 +#define IKEV2_FLAGS_ICV_INCLUDED 0x20 + +#define IKEV2_FRAGMENT_SIZE 1400 + +struct ikev2_keys; + +int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, + const u8 *i_nonce, size_t i_nonce_len, + const u8 *r_nonce, size_t r_nonce_len, + u8 *keymat); +struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code); +int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, + int initiator, const struct wpabuf *msg, + const u8 *pos, const u8 *end); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_IKEV2_COMMON_H */ diff --git a/src/eap_common/eap_pax_common.c b/libeap/src/eap_common/eap_pax_common.c similarity index 100% rename from src/eap_common/eap_pax_common.c rename to libeap/src/eap_common/eap_pax_common.c diff --git a/libeap/src/eap_common/eap_pax_common.h b/libeap/src/eap_common/eap_pax_common.h new file mode 100644 index 0000000..cc38b17 --- /dev/null +++ b/libeap/src/eap_common/eap_pax_common.h @@ -0,0 +1,100 @@ +/* + * EAP server/peer: EAP-PAX shared routines + * Copyright (c) 2005-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_PAX_COMMON_H +#define EAP_PAX_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_pax_hdr { + u8 op_code; + u8 flags; + u8 mac_id; + u8 dh_group_id; + u8 public_key_id; + /* Followed by variable length payload and ICV */ +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +/* op_code: */ +enum { + EAP_PAX_OP_STD_1 = 0x01, + EAP_PAX_OP_STD_2 = 0x02, + EAP_PAX_OP_STD_3 = 0x03, + EAP_PAX_OP_SEC_1 = 0x11, + EAP_PAX_OP_SEC_2 = 0x12, + EAP_PAX_OP_SEC_3 = 0x13, + EAP_PAX_OP_SEC_4 = 0x14, + EAP_PAX_OP_SEC_5 = 0x15, + EAP_PAX_OP_ACK = 0x21 +}; + +/* flags: */ +#define EAP_PAX_FLAGS_MF 0x01 +#define EAP_PAX_FLAGS_CE 0x02 +#define EAP_PAX_FLAGS_AI 0x04 + +/* mac_id: */ +#define EAP_PAX_MAC_HMAC_SHA1_128 0x01 +#define EAP_PAX_HMAC_SHA256_128 0x02 + +/* dh_group_id: */ +#define EAP_PAX_DH_GROUP_NONE 0x00 +#define EAP_PAX_DH_GROUP_2048_MODP 0x01 +#define EAP_PAX_DH_GROUP_3072_MODP 0x02 +#define EAP_PAX_DH_GROUP_NIST_ECC_P_256 0x03 + +/* public_key_id: */ +#define EAP_PAX_PUBLIC_KEY_NONE 0x00 +#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP 0x01 +#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 0x02 +#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC 0x03 + +/* ADE type: */ +#define EAP_PAX_ADE_VENDOR_SPECIFIC 0x01 +#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING 0x02 +#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING 0x03 + + +#define EAP_PAX_RAND_LEN 32 +#define EAP_PAX_MAC_LEN 16 +#define EAP_PAX_ICV_LEN 16 +#define EAP_PAX_AK_LEN 16 +#define EAP_PAX_MK_LEN 16 +#define EAP_PAX_CK_LEN 16 +#define EAP_PAX_ICK_LEN 16 +#define EAP_PAX_MID_LEN 16 + + +int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, + const char *identifier, + const u8 *entropy, size_t entropy_len, + size_t output_len, u8 *output); +int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, + const u8 *data1, size_t data1_len, + const u8 *data2, size_t data2_len, + const u8 *data3, size_t data3_len, + u8 *mac); +int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e, + u8 *mk, u8 *ck, u8 *ick, u8 *mid); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PAX_COMMON_H */ diff --git a/src/eap_common/eap_peap_common.c b/libeap/src/eap_common/eap_peap_common.c similarity index 100% rename from src/eap_common/eap_peap_common.c rename to libeap/src/eap_common/eap_peap_common.c diff --git a/libeap/src/eap_common/eap_peap_common.h b/libeap/src/eap_common/eap_peap_common.h new file mode 100644 index 0000000..069450e --- /dev/null +++ b/libeap/src/eap_common/eap_peap_common.h @@ -0,0 +1,24 @@ +/* + * EAP-PEAP common routines + * Copyright (c) 2008-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_PEAP_COMMON_H +#define EAP_PEAP_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +int peap_prfplus(int version, const u8 *key, size_t key_len, + const char *label, const u8 *seed, size_t seed_len, + u8 *buf, size_t buf_len); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PEAP_COMMON_H */ diff --git a/src/eap_common/eap_psk_common.c b/libeap/src/eap_common/eap_psk_common.c similarity index 100% rename from src/eap_common/eap_psk_common.c rename to libeap/src/eap_common/eap_psk_common.c diff --git a/libeap/src/eap_common/eap_psk_common.h b/libeap/src/eap_common/eap_psk_common.h new file mode 100644 index 0000000..e7c50b9 --- /dev/null +++ b/libeap/src/eap_common/eap_psk_common.h @@ -0,0 +1,79 @@ +/* + * EAP server/peer: EAP-PSK shared routines + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_PSK_COMMON_H +#define EAP_PSK_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_PSK_RAND_LEN 16 +#define EAP_PSK_MAC_LEN 16 +#define EAP_PSK_TEK_LEN 16 +#define EAP_PSK_PSK_LEN 16 +#define EAP_PSK_AK_LEN 16 +#define EAP_PSK_KDK_LEN 16 + +#define EAP_PSK_R_FLAG_CONT 1 +#define EAP_PSK_R_FLAG_DONE_SUCCESS 2 +#define EAP_PSK_R_FLAG_DONE_FAILURE 3 +#define EAP_PSK_E_FLAG 0x20 + +#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6) +#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6) + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +/* EAP-PSK First Message (AS -> Supplicant) */ +struct eap_psk_hdr_1 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + /* Followed by variable length ID_S */ +} STRUCT_PACKED; + +/* EAP-PSK Second Message (Supplicant -> AS) */ +struct eap_psk_hdr_2 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + u8 rand_p[EAP_PSK_RAND_LEN]; + u8 mac_p[EAP_PSK_MAC_LEN]; + /* Followed by variable length ID_P */ +} STRUCT_PACKED; + +/* EAP-PSK Third Message (AS -> Supplicant) */ +struct eap_psk_hdr_3 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + u8 mac_s[EAP_PSK_MAC_LEN]; + /* Followed by variable length PCHANNEL */ +} STRUCT_PACKED; + +/* EAP-PSK Fourth Message (Supplicant -> AS) */ +struct eap_psk_hdr_4 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + /* Followed by variable length PCHANNEL */ +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk); +int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, + u8 *msk, u8 *emsk); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PSK_COMMON_H */ diff --git a/src/eap_common/eap_pwd_common.c b/libeap/src/eap_common/eap_pwd_common.c similarity index 100% rename from src/eap_common/eap_pwd_common.c rename to libeap/src/eap_common/eap_pwd_common.c diff --git a/libeap/src/eap_common/eap_pwd_common.h b/libeap/src/eap_common/eap_pwd_common.h new file mode 100644 index 0000000..6562ea4 --- /dev/null +++ b/libeap/src/eap_common/eap_pwd_common.h @@ -0,0 +1,80 @@ +/* + * EAP server/peer: EAP-pwd shared definitions + * Copyright (c) 2009, Dan Harkins + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_PWD_COMMON_H +#define EAP_PWD_COMMON_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * definition of a finite cyclic group + * TODO: support one based on a prime field + */ +typedef struct group_definition_ { + u16 group_num; + EC_GROUP *group; + EC_POINT *pwe; + BIGNUM *order; + BIGNUM *prime; +} EAP_PWD_group; + +/* + * EAP-pwd header, included on all payloads + * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set) + */ +#define EAP_PWD_HDR_SIZE 1 + +#define EAP_PWD_OPCODE_ID_EXCH 1 +#define EAP_PWD_OPCODE_COMMIT_EXCH 2 +#define EAP_PWD_OPCODE_CONFIRM_EXCH 3 +#define EAP_PWD_GET_LENGTH_BIT(x) ((x) & 0x80) +#define EAP_PWD_SET_LENGTH_BIT(x) ((x) |= 0x80) +#define EAP_PWD_GET_MORE_BIT(x) ((x) & 0x40) +#define EAP_PWD_SET_MORE_BIT(x) ((x) |= 0x40) +#define EAP_PWD_GET_EXCHANGE(x) ((x) & 0x3f) +#define EAP_PWD_SET_EXCHANGE(x,y) ((x) |= (y)) + +/* EAP-pwd-ID payload */ +struct eap_pwd_id { + be16 group_num; + u8 random_function; +#define EAP_PWD_DEFAULT_RAND_FUNC 1 + u8 prf; +#define EAP_PWD_DEFAULT_PRF 1 + u8 token[4]; + u8 prep; +#define EAP_PWD_PREP_NONE 0 +#define EAP_PWD_PREP_MS 1 + u8 identity[0]; /* length inferred from payload */ +} STRUCT_PACKED; + +/* common routines */ +int compute_password_element(EAP_PWD_group *grp, u16 num, + const u8 *password, size_t password_len, + const u8 *id_server, size_t id_server_len, + const u8 *id_peer, size_t id_peer_len, + const u8 *token); +int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k, + const BIGNUM *peer_scalar, const BIGNUM *server_scalar, + const u8 *confirm_peer, const u8 *confirm_server, + const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id); +struct crypto_hash * eap_pwd_h_init(void); +void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len); +void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PWD_COMMON_H */ diff --git a/src/eap_common/eap_sake_common.c b/libeap/src/eap_common/eap_sake_common.c similarity index 100% rename from src/eap_common/eap_sake_common.c rename to libeap/src/eap_common/eap_sake_common.c diff --git a/libeap/src/eap_common/eap_sake_common.h b/libeap/src/eap_common/eap_sake_common.h new file mode 100644 index 0000000..440badc --- /dev/null +++ b/libeap/src/eap_common/eap_sake_common.h @@ -0,0 +1,104 @@ +/* + * EAP server/peer: EAP-SAKE shared routines + * Copyright (c) 2006-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_SAKE_COMMON_H +#define EAP_SAKE_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_SAKE_VERSION 2 + +#define EAP_SAKE_SUBTYPE_CHALLENGE 1 +#define EAP_SAKE_SUBTYPE_CONFIRM 2 +#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3 +#define EAP_SAKE_SUBTYPE_IDENTITY 4 + +#define EAP_SAKE_AT_RAND_S 1 +#define EAP_SAKE_AT_RAND_P 2 +#define EAP_SAKE_AT_MIC_S 3 +#define EAP_SAKE_AT_MIC_P 4 +#define EAP_SAKE_AT_SERVERID 5 +#define EAP_SAKE_AT_PEERID 6 +#define EAP_SAKE_AT_SPI_S 7 +#define EAP_SAKE_AT_SPI_P 8 +#define EAP_SAKE_AT_ANY_ID_REQ 9 +#define EAP_SAKE_AT_PERM_ID_REQ 10 +#define EAP_SAKE_AT_ENCR_DATA 128 +#define EAP_SAKE_AT_IV 129 +#define EAP_SAKE_AT_PADDING 130 +#define EAP_SAKE_AT_NEXT_TMPID 131 +#define EAP_SAKE_AT_MSK_LIFE 132 + +#define EAP_SAKE_RAND_LEN 16 +#define EAP_SAKE_MIC_LEN 16 +#define EAP_SAKE_ROOT_SECRET_LEN 16 +#define EAP_SAKE_SMS_LEN 16 +#define EAP_SAKE_TEK_AUTH_LEN 16 +#define EAP_SAKE_TEK_CIPHER_LEN 16 +#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN) + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_sake_hdr { + u8 version; /* EAP_SAKE_VERSION */ + u8 session_id; + u8 subtype; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +struct eap_sake_parse_attr { + const u8 *rand_s; + const u8 *rand_p; + const u8 *mic_s; + const u8 *mic_p; + const u8 *serverid; + size_t serverid_len; + const u8 *peerid; + size_t peerid_len; + const u8 *spi_s; + size_t spi_s_len; + const u8 *spi_p; + size_t spi_p_len; + const u8 *any_id_req; + const u8 *perm_id_req; + const u8 *encr_data; + size_t encr_data_len; + const u8 *iv; + size_t iv_len; + const u8 *next_tmpid; + size_t next_tmpid_len; + const u8 *msk_life; +}; + +int eap_sake_parse_attributes(const u8 *buf, size_t len, + struct eap_sake_parse_attr *attr); +void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b, + const u8 *rand_s, const u8 *rand_p, + u8 *tek, u8 *msk, u8 *emsk); +int eap_sake_compute_mic(const u8 *tek_auth, + const u8 *rand_s, const u8 *rand_p, + const u8 *serverid, size_t serverid_len, + const u8 *peerid, size_t peerid_len, + int peer, const u8 *eap, size_t eap_len, + const u8 *mic_pos, u8 *mic); +void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data, + size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_SAKE_COMMON_H */ diff --git a/src/eap_common/eap_sim_common.c b/libeap/src/eap_common/eap_sim_common.c similarity index 100% rename from src/eap_common/eap_sim_common.c rename to libeap/src/eap_common/eap_sim_common.c diff --git a/libeap/src/eap_common/eap_sim_common.h b/libeap/src/eap_common/eap_sim_common.h new file mode 100644 index 0000000..7c2cff1 --- /dev/null +++ b/libeap/src/eap_common/eap_sim_common.h @@ -0,0 +1,238 @@ +/* + * EAP peer/server: EAP-SIM/AKA/AKA' shared routines + * Copyright (c) 2004-2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_SIM_COMMON_H +#define EAP_SIM_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_SIM_NONCE_S_LEN 16 +#define EAP_SIM_NONCE_MT_LEN 16 +#define EAP_SIM_MAC_LEN 16 +#define EAP_SIM_MK_LEN 20 +#define EAP_SIM_K_AUT_LEN 16 +#define EAP_SIM_K_ENCR_LEN 16 +#define EAP_SIM_KEYING_DATA_LEN 64 +#define EAP_SIM_IV_LEN 16 +#define EAP_SIM_KC_LEN 8 +#define EAP_SIM_SRES_LEN 4 + +#define GSM_RAND_LEN 16 + +#define EAP_SIM_VERSION 1 + +/* EAP-SIM Subtypes */ +#define EAP_SIM_SUBTYPE_START 10 +#define EAP_SIM_SUBTYPE_CHALLENGE 11 +#define EAP_SIM_SUBTYPE_NOTIFICATION 12 +#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13 +#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14 + +/* AT_CLIENT_ERROR_CODE error codes */ +#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0 +#define EAP_SIM_UNSUPPORTED_VERSION 1 +#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2 +#define EAP_SIM_RAND_NOT_FRESH 3 + +#define EAP_SIM_MAX_FAST_REAUTHS 1000 + +#define EAP_SIM_MAX_CHAL 3 + + +/* EAP-AKA Subtypes */ +#define EAP_AKA_SUBTYPE_CHALLENGE 1 +#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2 +#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4 +#define EAP_AKA_SUBTYPE_IDENTITY 5 +#define EAP_AKA_SUBTYPE_NOTIFICATION 12 +#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13 +#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14 + +/* AT_CLIENT_ERROR_CODE error codes */ +#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0 + +#define EAP_AKA_RAND_LEN 16 +#define EAP_AKA_AUTN_LEN 16 +#define EAP_AKA_AUTS_LEN 14 +#define EAP_AKA_RES_MAX_LEN 16 +#define EAP_AKA_IK_LEN 16 +#define EAP_AKA_CK_LEN 16 +#define EAP_AKA_MAX_FAST_REAUTHS 1000 +#define EAP_AKA_MIN_RES_LEN 4 +#define EAP_AKA_MAX_RES_LEN 16 +#define EAP_AKA_CHECKCODE_LEN 20 + +#define EAP_AKA_PRIME_K_AUT_LEN 32 +#define EAP_AKA_PRIME_CHECKCODE_LEN 32 +#define EAP_AKA_PRIME_K_RE_LEN 32 + +struct wpabuf; + +void eap_sim_derive_mk(const u8 *identity, size_t identity_len, + const u8 *nonce_mt, u16 selected_version, + const u8 *ver_list, size_t ver_list_len, + int num_chal, const u8 *kc, u8 *mk); +void eap_aka_derive_mk(const u8 *identity, size_t identity_len, + const u8 *ik, const u8 *ck, u8 *mk); +int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, + u8 *emsk); +int eap_sim_derive_keys_reauth(u16 _counter, + const u8 *identity, size_t identity_len, + const u8 *nonce_s, const u8 *mk, u8 *msk, + u8 *emsk); +int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, + const u8 *mac, const u8 *extra, size_t extra_len); +void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, + const u8 *extra, size_t extra_len); + +#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) +void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, + const u8 *ik, const u8 *ck, u8 *k_encr, + u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk); +int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, + const u8 *identity, size_t identity_len, + const u8 *nonce_s, u8 *msk, u8 *emsk); +int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, + const u8 *mac, const u8 *extra, + size_t extra_len); +void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, + u8 *mac, const u8 *extra, size_t extra_len); + +void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, + const u8 *network_name, + size_t network_name_len); +#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ +static inline void eap_aka_prime_derive_keys(const u8 *identity, + size_t identity_len, + const u8 *ik, const u8 *ck, + u8 *k_encr, u8 *k_aut, u8 *k_re, + u8 *msk, u8 *emsk) +{ +} + +static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, + const u8 *identity, + size_t identity_len, + const u8 *nonce_s, u8 *msk, + u8 *emsk) +{ + return -1; +} + +static inline int eap_sim_verify_mac_sha256(const u8 *k_aut, + const struct wpabuf *req, + const u8 *mac, const u8 *extra, + size_t extra_len) +{ + return -1; +} +#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ + + +/* EAP-SIM/AKA Attributes (0..127 non-skippable) */ +#define EAP_SIM_AT_RAND 1 +#define EAP_SIM_AT_AUTN 2 /* only AKA */ +#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */ +#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */ +#define EAP_SIM_AT_PADDING 6 /* only encrypted */ +#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */ +#define EAP_SIM_AT_PERMANENT_ID_REQ 10 +#define EAP_SIM_AT_MAC 11 +#define EAP_SIM_AT_NOTIFICATION 12 +#define EAP_SIM_AT_ANY_ID_REQ 13 +#define EAP_SIM_AT_IDENTITY 14 /* only send */ +#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */ +#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */ +#define EAP_SIM_AT_FULLAUTH_ID_REQ 17 +#define EAP_SIM_AT_COUNTER 19 /* only encrypted */ +#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */ +#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */ +#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */ +#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */ +#define EAP_SIM_AT_KDF 24 /* only AKA' */ +#define EAP_SIM_AT_IV 129 +#define EAP_SIM_AT_ENCR_DATA 130 +#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */ +#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */ +#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */ +#define EAP_SIM_AT_RESULT_IND 135 +#define EAP_SIM_AT_BIDDING 136 + +/* AT_NOTIFICATION notification code values */ +#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0 +#define EAP_SIM_TEMPORARILY_DENIED 1026 +#define EAP_SIM_NOT_SUBSCRIBED 1031 +#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384 +#define EAP_SIM_SUCCESS 32768 + +/* EAP-AKA' AT_KDF Key Derivation Function values */ +#define EAP_AKA_PRIME_KDF 1 + +/* AT_BIDDING flags */ +#define EAP_AKA_BIDDING_FLAG_D 0x8000 + + +enum eap_sim_id_req { + NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID +}; + + +struct eap_sim_attrs { + const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s; + const u8 *next_pseudonym, *next_reauth_id; + const u8 *nonce_mt, *identity, *res, *auts; + const u8 *checkcode; + const u8 *kdf_input; + const u8 *bidding; + size_t num_chal, version_list_len, encr_data_len; + size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len; + size_t res_len_bits; + size_t checkcode_len; + size_t kdf_input_len; + enum eap_sim_id_req id_req; + int notification, counter, selected_version, client_error_code; + int counter_too_small; + int result_ind; +#define EAP_AKA_PRIME_KDF_MAX 10 + u16 kdf[EAP_AKA_PRIME_KDF_MAX]; + size_t kdf_count; +}; + +int eap_sim_parse_attr(const u8 *start, const u8 *end, + struct eap_sim_attrs *attr, int aka, int encr); +u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, + size_t encr_data_len, const u8 *iv, + struct eap_sim_attrs *attr, int aka); + + +struct eap_sim_msg; + +struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype); +struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type, + const u8 *k_aut, + const u8 *extra, size_t extra_len); +void eap_sim_msg_free(struct eap_sim_msg *msg); +u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, + const u8 *data, size_t len); +u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, + u16 value, const u8 *data, size_t len); +u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr); +int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, + u8 attr_encr); +int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, + int attr_pad); + +void eap_sim_report_notification(void *msg_ctx, int notification, int aka); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_SIM_COMMON_H */ diff --git a/libeap/src/eap_common/eap_tlv_common.h b/libeap/src/eap_common/eap_tlv_common.h new file mode 100644 index 0000000..fcec4ce --- /dev/null +++ b/libeap/src/eap_common/eap_tlv_common.h @@ -0,0 +1,120 @@ +/* + * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt) + * Copyright (c) 2004-2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_TLV_COMMON_H +#define EAP_TLV_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */ +#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */ +#define EAP_TLV_NAK_TLV 4 +#define EAP_TLV_ERROR_CODE_TLV 5 +#define EAP_TLV_CONNECTION_BINDING_TLV 6 +#define EAP_TLV_VENDOR_SPECIFIC_TLV 7 +#define EAP_TLV_URI_TLV 8 +#define EAP_TLV_EAP_PAYLOAD_TLV 9 +#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10 +#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */ +#define EAP_TLV_CRYPTO_BINDING_TLV 12 +#define EAP_TLV_CALLING_STATION_ID_TLV 13 +#define EAP_TLV_CALLED_STATION_ID_TLV 14 +#define EAP_TLV_NAS_PORT_TYPE_TLV 15 +#define EAP_TLV_SERVER_IDENTIFIER_TLV 16 +#define EAP_TLV_IDENTITY_TYPE_TLV 17 +#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18 +#define EAP_TLV_REQUEST_ACTION_TLV 19 +#define EAP_TLV_PKCS7_TLV 20 + +#define EAP_TLV_RESULT_SUCCESS 1 +#define EAP_TLV_RESULT_FAILURE 2 + +#define EAP_TLV_TYPE_MANDATORY 0x8000 +#define EAP_TLV_TYPE_MASK 0x3fff + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_tlv_hdr { + be16 tlv_type; + be16 length; +} STRUCT_PACKED; + +struct eap_tlv_nak_tlv { + be16 tlv_type; + be16 length; + be32 vendor_id; + be16 nak_type; +} STRUCT_PACKED; + +struct eap_tlv_result_tlv { + be16 tlv_type; + be16 length; + be16 status; +} STRUCT_PACKED; + +/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */ +struct eap_tlv_intermediate_result_tlv { + be16 tlv_type; + be16 length; + be16 status; + /* Followed by optional TLVs */ +} STRUCT_PACKED; + +/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */ +struct eap_tlv_crypto_binding_tlv { + be16 tlv_type; + be16 length; + u8 reserved; + u8 version; + u8 received_version; + u8 subtype; + u8 nonce[32]; + u8 compound_mac[20]; +} STRUCT_PACKED; + +struct eap_tlv_pac_ack_tlv { + be16 tlv_type; + be16 length; + be16 pac_type; + be16 pac_len; + be16 result; +} STRUCT_PACKED; + +/* RFC 4851, Section 4.2.9 - Request-Action TLV */ +struct eap_tlv_request_action_tlv { + be16 tlv_type; + be16 length; + be16 action; +} STRUCT_PACKED; + +/* RFC 5422, Section 4.2.6 - PAC-Type TLV */ +struct eap_tlv_pac_type_tlv { + be16 tlv_type; /* PAC_TYPE_PAC_TYPE */ + be16 length; + be16 pac_type; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0 +#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1 + +#define EAP_TLV_ACTION_PROCESS_TLV 1 +#define EAP_TLV_ACTION_NEGOTIATE_EAP 2 + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_TLV_COMMON_H */ diff --git a/libeap/src/eap_common/eap_ttls.h b/libeap/src/eap_common/eap_ttls.h new file mode 100644 index 0000000..f439da2 --- /dev/null +++ b/libeap/src/eap_common/eap_ttls.h @@ -0,0 +1,78 @@ +/* + * EAP server/peer: EAP-TTLS (RFC 5281) + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_TTLS_H +#define EAP_TTLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct ttls_avp { + be32 avp_code; + be32 avp_length; /* 8-bit flags, 24-bit length; + * length includes AVP header */ + /* optional 32-bit Vendor-ID */ + /* Data */ +}; + +struct ttls_avp_vendor { + be32 avp_code; + be32 avp_length; /* 8-bit flags, 24-bit length; + * length includes AVP header */ + be32 vendor_id; + /* Data */ +}; + + +#define AVP_FLAGS_VENDOR 0x80 +#define AVP_FLAGS_MANDATORY 0x40 + +#define AVP_PAD(start, pos) \ +do { \ + int __pad; \ + __pad = (4 - (((pos) - (start)) & 3)) & 3; \ + os_memset((pos), 0, __pad); \ + pos += __pad; \ +} while (0) + + +/* RFC 2865 */ +#define RADIUS_ATTR_USER_NAME 1 +#define RADIUS_ATTR_USER_PASSWORD 2 +#define RADIUS_ATTR_CHAP_PASSWORD 3 +#define RADIUS_ATTR_REPLY_MESSAGE 18 +#define RADIUS_ATTR_VENDOR_SPECIFIC 26 +#define RADIUS_ATTR_CHAP_CHALLENGE 60 +#define RADIUS_ATTR_EAP_MESSAGE 79 + +/* RFC 2548 */ +#define RADIUS_VENDOR_ID_MICROSOFT 311 +#define RADIUS_ATTR_MS_CHAP_RESPONSE 1 +#define RADIUS_ATTR_MS_CHAP_ERROR 2 +#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6 +#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11 +#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25 +#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26 +#define RADIUS_ATTR_MS_CHAP2_CPW 27 + +#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16 +#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50 +#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8 +#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50 +#define EAP_TTLS_CHAP_CHALLENGE_LEN 16 +#define EAP_TTLS_CHAP_PASSWORD_LEN 16 + +#define RADIUS_VENDOR_ID_UKERNA 25622 +#define RADIUS_ATTR_UKERNA_CHBIND 135 + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_TTLS_H */ diff --git a/src/eap_common/eap_wsc_common.c b/libeap/src/eap_common/eap_wsc_common.c similarity index 100% rename from src/eap_common/eap_wsc_common.c rename to libeap/src/eap_common/eap_wsc_common.c diff --git a/libeap/src/eap_common/eap_wsc_common.h b/libeap/src/eap_common/eap_wsc_common.h new file mode 100644 index 0000000..6914216 --- /dev/null +++ b/libeap/src/eap_common/eap_wsc_common.h @@ -0,0 +1,35 @@ +/* + * EAP-WSC definitions for Wi-Fi Protected Setup + * Copyright (c) 2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_WSC_COMMON_H +#define EAP_WSC_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_VENDOR_TYPE_WSC 1 + +#define WSC_FLAGS_MF 0x01 +#define WSC_FLAGS_LF 0x02 + +#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0" +#define WSC_ID_REGISTRAR_LEN 30 +#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0" +#define WSC_ID_ENROLLEE_LEN 29 + +#define WSC_FRAGMENT_SIZE 1400 + + +struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_WSC_COMMON_H */ diff --git a/src/eap_common/ikev2_common.c b/libeap/src/eap_common/ikev2_common.c similarity index 100% rename from src/eap_common/ikev2_common.c rename to libeap/src/eap_common/ikev2_common.c diff --git a/src/eap_common/ikev2_common.h b/libeap/src/eap_common/ikev2_common.h similarity index 100% rename from src/eap_common/ikev2_common.h rename to libeap/src/eap_common/ikev2_common.h diff --git a/src/eap_peer/Makefile b/libeap/src/eap_peer/Makefile similarity index 100% rename from src/eap_peer/Makefile rename to libeap/src/eap_peer/Makefile diff --git a/src/eap_peer/eap.c b/libeap/src/eap_peer/eap.c similarity index 100% rename from src/eap_peer/eap.c rename to libeap/src/eap_peer/eap.c diff --git a/libeap/src/eap_peer/eap.h b/libeap/src/eap_peer/eap.h new file mode 100644 index 0000000..831db76 --- /dev/null +++ b/libeap/src/eap_peer/eap.h @@ -0,0 +1,362 @@ +/* + * EAP peer state machine functions (RFC 4137) + * Copyright (c) 2004-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_H +#define EAP_H + +#include "common/defs.h" +#include "eap_common/eap_defs.h" +#include "eap_peer/eap_methods.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct eap_sm; +struct wpa_config_blob; +struct wpabuf; + +struct eap_method_type { + int vendor; + u32 method; +}; + +#ifdef IEEE8021X_EAPOL + +/** + * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine + * + * These variables are used in the interface between EAP peer state machine and + * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is + * expected to maintain these variables and register a callback functions for + * EAP state machine to get and set the variables. + */ +enum eapol_bool_var { + /** + * EAPOL_eapSuccess - EAP SUCCESS state reached + * + * EAP state machine reads and writes this value. + */ + EAPOL_eapSuccess, + + /** + * EAPOL_eapRestart - Lower layer request to restart authentication + * + * Set to TRUE in lower layer, FALSE in EAP state machine. + */ + EAPOL_eapRestart, + + /** + * EAPOL_eapFail - EAP FAILURE state reached + * + * EAP state machine writes this value. + */ + EAPOL_eapFail, + + /** + * EAPOL_eapResp - Response to send + * + * Set to TRUE in EAP state machine, FALSE in lower layer. + */ + EAPOL_eapResp, + + /** + * EAPOL_eapNoResp - Request has been process; no response to send + * + * Set to TRUE in EAP state machine, FALSE in lower layer. + */ + EAPOL_eapNoResp, + + /** + * EAPOL_eapReq - EAP request available from lower layer + * + * Set to TRUE in lower layer, FALSE in EAP state machine. + */ + EAPOL_eapReq, + + /** + * EAPOL_portEnabled - Lower layer is ready for communication + * + * EAP state machines reads this value. + */ + EAPOL_portEnabled, + + /** + * EAPOL_altAccept - Alternate indication of success (RFC3748) + * + * EAP state machines reads this value. + */ + EAPOL_altAccept, + + /** + * EAPOL_altReject - Alternate indication of failure (RFC3748) + * + * EAP state machines reads this value. + */ + EAPOL_altReject, + + /** + * EAPOL_eapTriggerStart - EAP-based trigger to send EAPOL-Start + * + * EAP state machine writes this value. + */ + EAPOL_eapTriggerStart +}; + +/** + * enum eapol_int_var - EAPOL integer state variables for EAP state machine + * + * These variables are used in the interface between EAP peer state machine and + * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is + * expected to maintain these variables and register a callback functions for + * EAP state machine to get and set the variables. + */ +enum eapol_int_var { + /** + * EAPOL_idleWhile - Outside time for EAP peer timeout + * + * This integer variable is used to provide an outside timer that the + * external (to EAP state machine) code must decrement by one every + * second until the value reaches zero. This is used in the same way as + * EAPOL state machine timers. EAP state machine reads and writes this + * value. + */ + EAPOL_idleWhile +}; + +/** + * struct eapol_callbacks - Callback functions from EAP to lower layer + * + * This structure defines the callback functions that EAP state machine + * requires from the lower layer (usually EAPOL state machine) for updating + * state variables and requesting information. eapol_ctx from + * eap_peer_sm_init() call will be used as the ctx parameter for these + * callback functions. + */ +struct eapol_callbacks { + /** + * get_config - Get pointer to the current network configuration + * @ctx: eapol_ctx from eap_peer_sm_init() call + */ + struct eap_peer_config * (*get_config)(void *ctx); + + /** + * get_bool - Get a boolean EAPOL state variable + * @variable: EAPOL boolean variable to get + * Returns: Value of the EAPOL variable + */ + Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable); + + /** + * set_bool - Set a boolean EAPOL state variable + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @variable: EAPOL boolean variable to set + * @value: Value for the EAPOL variable + */ + void (*set_bool)(void *ctx, enum eapol_bool_var variable, + Boolean value); + + /** + * get_int - Get an integer EAPOL state variable + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @variable: EAPOL integer variable to get + * Returns: Value of the EAPOL variable + */ + unsigned int (*get_int)(void *ctx, enum eapol_int_var variable); + + /** + * set_int - Set an integer EAPOL state variable + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @variable: EAPOL integer variable to set + * @value: Value for the EAPOL variable + */ + void (*set_int)(void *ctx, enum eapol_int_var variable, + unsigned int value); + + /** + * get_eapReqData - Get EAP-Request data + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @len: Pointer to variable that will be set to eapReqDataLen + * Returns: Reference to eapReqData (EAP state machine will not free + * this) or %NULL if eapReqData not available. + */ + struct wpabuf * (*get_eapReqData)(void *ctx); + + /** + * set_config_blob - Set named configuration blob + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @blob: New value for the blob + * + * Adds a new configuration blob or replaces the current value of an + * existing blob. + */ + void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); + + /** + * get_config_blob - Get a named configuration blob + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @name: Name of the blob + * Returns: Pointer to blob data or %NULL if not found + */ + const struct wpa_config_blob * (*get_config_blob)(void *ctx, + const char *name); + + /** + * notify_pending - Notify that a pending request can be retried + * @ctx: eapol_ctx from eap_peer_sm_init() call + * + * An EAP method can perform a pending operation (e.g., to get a + * response from an external process). Once the response is available, + * this callback function can be used to request EAPOL state machine to + * retry delivering the previously received (and still unanswered) EAP + * request to EAP state machine. + */ + void (*notify_pending)(void *ctx); + + /** + * eap_param_needed - Notify that EAP parameter is needed + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY) + * @txt: User readable text describing the required parameter + */ + void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field, + const char *txt); + + /** + * notify_cert - Notification of a peer certificate + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @depth: Depth in certificate chain (0 = server) + * @subject: Subject of the peer certificate + * @altsubject: Select fields from AltSubject of the peer certificate + * @num_altsubject: Number of altsubject values + * @cert_hash: SHA-256 hash of the certificate + * @cert: Peer certificate + */ + void (*notify_cert)(void *ctx, int depth, const char *subject, + const char *altsubject[], int num_altsubject, + const char *cert_hash, const struct wpabuf *cert); + + /** + * notify_status - Notification of the current EAP state + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @status: Step in the process of EAP authentication + * @parameter: Step-specific parameter, e.g., EAP method name + */ + void (*notify_status)(void *ctx, const char *status, + const char *parameter); + +#ifdef CONFIG_EAP_PROXY + /** + * eap_proxy_cb - Callback signifying any updates from eap_proxy + * @ctx: eapol_ctx from eap_peer_sm_init() call + */ + void (*eap_proxy_cb)(void *ctx); +#endif /* CONFIG_EAP_PROXY */ + + /** + * set_anon_id - Set or add anonymous identity + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear + * @len: Length of anonymous identity in octets + */ + void (*set_anon_id)(void *ctx, const u8 *id, size_t len); +}; + +/** + * struct eap_config - Configuration for EAP state machine + */ +struct eap_config { + /** + * opensc_engine_path - OpenSC engine for OpenSSL engine support + * + * Usually, path to engine_opensc.so. + */ + const char *opensc_engine_path; + /** + * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support + * + * Usually, path to engine_pkcs11.so. + */ + const char *pkcs11_engine_path; + /** + * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine + * + * Usually, path to opensc-pkcs11.so. + */ + const char *pkcs11_module_path; + /** + * openssl_ciphers - OpenSSL cipher string + * + * This is an OpenSSL specific configuration option for configuring the + * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the + * default. + */ + const char *openssl_ciphers; + /** + * wps - WPS context data + * + * This is only used by EAP-WSC and can be left %NULL if not available. + */ + struct wps_context *wps; + + /** + * cert_in_cb - Include server certificates in callback + */ + int cert_in_cb; +}; + +struct eap_sm * eap_peer_sm_init(void *eapol_ctx, + const struct eapol_callbacks *eapol_cb, + void *msg_ctx, struct eap_config *conf); +void eap_peer_sm_deinit(struct eap_sm *sm); +int eap_peer_sm_step(struct eap_sm *sm); +void eap_sm_abort(struct eap_sm *sm); +int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, + int verbose); +const char * eap_sm_get_method_name(struct eap_sm *sm); +struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted); +void eap_sm_request_identity(struct eap_sm *sm); +void eap_sm_request_password(struct eap_sm *sm); +void eap_sm_request_new_password(struct eap_sm *sm); +void eap_sm_request_pin(struct eap_sm *sm); +void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len); +void eap_sm_request_passphrase(struct eap_sm *sm); +void eap_sm_request_sim(struct eap_sm *sm, const char *req); +void eap_sm_notify_ctrl_attached(struct eap_sm *sm); +u32 eap_get_phase2_type(const char *name, int *vendor); +struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config, + size_t *count); +void eap_set_fast_reauth(struct eap_sm *sm, int enabled); +void eap_set_workaround(struct eap_sm *sm, unsigned int workaround); +void eap_set_force_disabled(struct eap_sm *sm, int disabled); +void eap_set_external_sim(struct eap_sm *sm, int external_sim); +int eap_key_available(struct eap_sm *sm); +void eap_notify_success(struct eap_sm *sm); +void eap_notify_lower_layer_success(struct eap_sm *sm); +const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len); +const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); +struct wpabuf * eap_get_eapRespData(struct eap_sm *sm); +void eap_register_scard_ctx(struct eap_sm *sm, void *ctx); +void eap_invalidate_cached_session(struct eap_sm *sm); + +int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf); +int eap_is_wps_pin_enrollee(struct eap_peer_config *conf); + +struct ext_password_data; +void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext); +void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len); +int eap_peer_was_failure_expected(struct eap_sm *sm); +void eap_peer_erp_free_keys(struct eap_sm *sm); + +#endif /* IEEE8021X_EAPOL */ + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_H */ diff --git a/src/eap_peer/eap_aka.c b/libeap/src/eap_peer/eap_aka.c similarity index 100% rename from src/eap_peer/eap_aka.c rename to libeap/src/eap_peer/eap_aka.c diff --git a/libeap/src/eap_peer/eap_config.h b/libeap/src/eap_peer/eap_config.h new file mode 100644 index 0000000..0b0824b --- /dev/null +++ b/libeap/src/eap_peer/eap_config.h @@ -0,0 +1,816 @@ +/* + * EAP peer configuration data + * Copyright (c) 2003-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_CONFIG_H +#define EAP_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3.1 */ +#define CHBIND_CODE_REQUEST 1 +#define CHBIND_CODE_SUCCESS 2 +#define CHBIND_CODE_FAILURE 3 +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3. */ +#define CHBIND_NSID_RADIUS 1 + +struct eap_peer_chbind_config +{ + /* namespace id for this channel binding info */ + int nsid; + + /* data to be sent in channel binding request */ + u8 *req_data; + + size_t req_data_len; + + /* lower level callback invoked when response is received */ + void (*response_cb)(void *ctx, int code, int nsid, u8 *resp_data, size_t resp_data_len); + + /* context for response callback */ + void *ctx; +}; + +/** + * struct eap_peer_config - EAP peer configuration/credentials + */ +struct eap_peer_config { + /** + * identity - EAP Identity + * + * This field is used to set the real user identity or NAI (for + * EAP-PSK/PAX/SAKE/GPSK). + */ + u8 *identity; + + /** + * identity_len - EAP Identity length + */ + size_t identity_len; + + /** + * anonymous_identity - Anonymous EAP Identity + * + * This field is used for unencrypted use with EAP types that support + * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the + * real identity (identity field) only to the authentication server. + * + * If not set, the identity field will be used for both unencrypted and + * protected fields. + * + * This field can also be used with EAP-SIM/AKA/AKA' to store the + * pseudonym identity. + */ + u8 *anonymous_identity; + + /** + * anonymous_identity_len - Length of anonymous_identity + */ + size_t anonymous_identity_len; + + /** + * password - Password string for EAP + * + * This field can include either the plaintext password (default + * option) or a NtPasswordHash (16-byte MD4 hash of the unicode + * presentation of the password) if flags field has + * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can + * only be used with authentication mechanism that use this hash as the + * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2, + * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). + * + * In addition, this field is used to configure a pre-shared key for + * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK + * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length + * PSK. + */ + u8 *password; + + /** + * password_len - Length of password field + */ + size_t password_len; + + /** + * ca_cert - File path to CA certificate file (PEM/DER) + * + * This file can have one or more trusted CA certificates. If ca_cert + * and ca_path are not included, server certificate will not be + * verified. This is insecure and a trusted CA certificate should + * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + * + * Alternatively, this can be used to only perform matching of the + * server certificate (SHA-256 hash of the DER encoded X.509 + * certificate). In this case, the possible CA certificates in the + * server certificate chain are ignored and only the server certificate + * is verified. This is configured with the following format: + * hash:://server/sha256/cert_hash_in_hex + * For example: "hash://server/sha256/ + * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" + * + * On Windows, trusted CA certificates can be loaded from the system + * certificate store by setting this to cert_store://name, e.g., + * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. + */ + u8 *ca_cert; + + /** + * ca_path - Directory path for CA certificate files (PEM) + * + * This path may contain multiple CA certificates in OpenSSL format. + * Common use for this is to point to system trusted CA list which is + * often installed into directory like /etc/ssl/certs. If configured, + * these certificates are added to the list of trusted CAs. ca_cert + * may also be included in that case, but it is not required. + */ + u8 *ca_path; + + /** + * client_cert - File path to client certificate file (PEM/DER) + * + * This field is used with EAP method that use TLS authentication. + * Usually, this is only configured for EAP-TLS, even though this could + * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *client_cert; + + /** + * private_key - File path to client private key file (PEM/DER/PFX) + * + * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be + * commented out. Both the private key and certificate will be read + * from the PKCS#12 file in this case. Full path to the file should be + * used since working directory may change when wpa_supplicant is run + * in the background. + * + * Windows certificate store can be used by leaving client_cert out and + * configuring private_key in one of the following formats: + * + * cert://substring_to_match + * + * hash://certificate_thumbprint_in_hex + * + * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" + * + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *private_key; + + /** + * private_key_passwd - Password for private key file + * + * If left out, this will be asked through control interface. + */ + char *private_key_passwd; + + /** + * dh_file - File path to DH/DSA parameters file (in PEM format) + * + * This is an optional configuration file for setting parameters for an + * ephemeral DH key exchange. In most cases, the default RSA + * authentication does not use this configuration. However, it is + * possible setup RSA to use ephemeral DH key exchange. In addition, + * ciphers with DSA keys always use ephemeral DH keys. This can be used + * to achieve forward secrecy. If the file is in DSA parameters format, + * it will be automatically converted into DH params. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *dh_file; + + /** + * subject_match - Constraint for server certificate subject + * + * This substring is matched against the subject of the authentication + * server certificate. If this string is set, the server sertificate is + * only accepted if it contains this string in the subject. The subject + * string is in following format: + * + * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com + * + * Note: Since this is a substring match, this cannot be used securily + * to do a suffix match against a possible domain name in the CN entry. + * For such a use case, domain_suffix_match should be used instead. + */ + u8 *subject_match; + + /** + * altsubject_match - Constraint for server certificate alt. subject + * + * Semicolon separated string of entries to be matched against the + * alternative subject name of the authentication server certificate. + * If this string is set, the server sertificate is only accepted if it + * contains one of the entries in an alternative subject name + * extension. + * + * altSubjectName string is in following format: TYPE:VALUE + * + * Example: EMAIL:server@example.com + * Example: DNS:server.example.com;DNS:server2.example.com + * + * Following types are supported: EMAIL, DNS, URI + */ + u8 *altsubject_match; + + /** + * domain_suffix_match - Constraint for server domain name + * + * If set, this FQDN is used as a suffix match requirement for the + * server certificate in SubjectAltName dNSName element(s). If a + * matching dNSName is found, this constraint is met. If no dNSName + * values are present, this constraint is matched against SubjectName CN + * using same suffix match comparison. Suffix match here means that the + * host/domain name is compared one label at a time starting from the + * top-level domain and all the labels in domain_suffix_match shall be + * included in the certificate. The certificate may include additional + * sub-level labels in addition to the required labels. + * + * For example, domain_suffix_match=example.com would match + * test.example.com but would not match test-example.com. + */ + char *domain_suffix_match; + + /** + * domain_match - Constraint for server domain name + * + * If set, this FQDN is used as a full match requirement for the + * server certificate in SubjectAltName dNSName element(s). If a + * matching dNSName is found, this constraint is met. If no dNSName + * values are present, this constraint is matched against SubjectName CN + * using same full match comparison. This behavior is similar to + * domain_suffix_match, but has the requirement of a full match, i.e., + * no subdomains or wildcard matches are allowed. Case-insensitive + * comparison is used, so "Example.com" matches "example.com", but would + * not match "test.Example.com". + */ + char *domain_match; + + /** + * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2) + * + * This file can have one or more trusted CA certificates. If ca_cert2 + * and ca_path2 are not included, server certificate will not be + * verified. This is insecure and a trusted CA certificate should + * always be configured. Full path to the file should be used since + * working directory may change when wpa_supplicant is run in the + * background. + * + * This field is like ca_cert, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *ca_cert2; + + /** + * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2) + * + * This path may contain multiple CA certificates in OpenSSL format. + * Common use for this is to point to system trusted CA list which is + * often installed into directory like /etc/ssl/certs. If configured, + * these certificates are added to the list of trusted CAs. ca_cert + * may also be included in that case, but it is not required. + * + * This field is like ca_path, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + u8 *ca_path2; + + /** + * client_cert2 - File path to client certificate file + * + * This field is like client_cert, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *client_cert2; + + /** + * private_key2 - File path to client private key file + * + * This field is like private_key, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *private_key2; + + /** + * private_key2_passwd - Password for private key file + * + * This field is like private_key_passwd, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + char *private_key2_passwd; + + /** + * dh_file2 - File path to DH/DSA parameters file (in PEM format) + * + * This field is like dh_file, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *dh_file2; + + /** + * subject_match2 - Constraint for server certificate subject + * + * This field is like subject_match, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + u8 *subject_match2; + + /** + * altsubject_match2 - Constraint for server certificate alt. subject + * + * This field is like altsubject_match, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + u8 *altsubject_match2; + + /** + * domain_suffix_match2 - Constraint for server domain name + * + * This field is like domain_suffix_match, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + char *domain_suffix_match2; + + /** + * domain_match2 - Constraint for server domain name + * + * This field is like domain_match, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + char *domain_match2; + + /** + * eap_methods - Allowed EAP methods + * + * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of + * allowed EAP methods or %NULL if all methods are accepted. + */ + struct eap_method_type *eap_methods; + + /** + * phase1 - Phase 1 (outer authentication) parameters + * + * String with field-value pairs, e.g., "peapver=0" or + * "peapver=1 peaplabel=1". + * + * 'peapver' can be used to force which PEAP version (0 or 1) is used. + * + * 'peaplabel=1' can be used to force new label, "client PEAP + * encryption", to be used during key derivation when PEAPv1 or newer. + * + * Most existing PEAPv1 implementation seem to be using the old label, + * "client EAP encryption", and wpa_supplicant is now using that as the + * default value. + * + * Some servers, e.g., Radiator, may require peaplabel=1 configuration + * to interoperate with PEAPv1; see eap_testing.txt for more details. + * + * 'peap_outer_success=0' can be used to terminate PEAP authentication + * on tunneled EAP-Success. This is required with some RADIUS servers + * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g., + * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode). + * + * include_tls_length=1 can be used to force wpa_supplicant to include + * TLS Message Length field in all TLS messages even if they are not + * fragmented. + * + * sim_min_num_chal=3 can be used to configure EAP-SIM to require three + * challenges (by default, it accepts 2 or 3). + * + * result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use + * protected result indication. + * + * fast_provisioning option can be used to enable in-line provisioning + * of EAP-FAST credentials (PAC): + * 0 = disabled, + * 1 = allow unauthenticated provisioning, + * 2 = allow authenticated provisioning, + * 3 = allow both unauthenticated and authenticated provisioning + * + * fast_max_pac_list_len=num option can be used to set the maximum + * number of PAC entries to store in a PAC list (default: 10). + * + * fast_pac_format=binary option can be used to select binary format + * for storing PAC entries in order to save some space (the default + * text format uses about 2.5 times the size of minimal binary format). + * + * crypto_binding option can be used to control PEAPv0 cryptobinding + * behavior: + * 0 = do not use cryptobinding (default) + * 1 = use cryptobinding if server supports it + * 2 = require cryptobinding + * + * EAP-WSC (WPS) uses following options: pin=Device_Password and + * uuid=Device_UUID + * + * For wired IEEE 802.1X authentication, "allow_canned_success=1" can be + * used to configure a mode that allows EAP-Success (and EAP-Failure) + * without going through authentication step. Some switches use such + * sequence when forcing the port to be authorized/unauthorized or as a + * fallback option if the authentication server is unreachable. By + * default, wpa_supplicant discards such frames to protect against + * potential attacks by rogue devices, but this option can be used to + * disable that protection for cases where the server/authenticator does + * not need to be authenticated. + */ + char *phase1; + + /** + * phase2 - Phase2 (inner authentication with TLS tunnel) parameters + * + * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or + * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can + * be used to disable MSCHAPv2 password retry in authentication failure + * cases. + */ + char *phase2; + + /** + * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM + * + * This field is used to configure PC/SC smartcard interface. + * Currently, the only configuration is whether this field is %NULL (do + * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC. + * + * This field is used for EAP-SIM and EAP-AKA. + */ + char *pcsc; + + /** + * pin - PIN for USIM, GSM SIM, and smartcards + * + * This field is used to configure PIN for SIM and smartcards for + * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a + * smartcard is used for private key operations. + * + * If left out, this will be asked through control interface. + */ + char *pin; + + /** + * engine - Enable OpenSSL engine (e.g., for smartcard access) + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + int engine; + + /** + * engine_id - Engine ID for OpenSSL engine + * + * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 + * engine. + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + char *engine_id; + + /** + * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2) + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + * + * This field is like engine, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + int engine2; + + + /** + * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2) + * + * This field is used to configure PIN for SIM and smartcards for + * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a + * smartcard is used for private key operations. + * + * This field is like pin2, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + * + * If left out, this will be asked through control interface. + */ + char *pin2; + + /** + * engine2_id - Engine ID for OpenSSL engine (Phase 2) + * + * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 + * engine. + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + * + * This field is like engine_id, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + char *engine2_id; + + + /** + * key_id - Key ID for OpenSSL engine + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + char *key_id; + + /** + * cert_id - Cert ID for OpenSSL engine + * + * This is used if the certificate operations for EAP-TLS are performed + * using a smartcard. + */ + char *cert_id; + + /** + * ca_cert_id - CA Cert ID for OpenSSL engine + * + * This is used if the CA certificate for EAP-TLS is on a smartcard. + */ + char *ca_cert_id; + + /** + * key2_id - Key ID for OpenSSL engine (phase2) + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + char *key2_id; + + /** + * cert2_id - Cert ID for OpenSSL engine (phase2) + * + * This is used if the certificate operations for EAP-TLS are performed + * using a smartcard. + */ + char *cert2_id; + + /** + * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2) + * + * This is used if the CA certificate for EAP-TLS is on a smartcard. + */ + char *ca_cert2_id; + + /** + * otp - One-time-password + * + * This field should not be set in configuration step. It is only used + * internally when OTP is entered through the control interface. + */ + u8 *otp; + + /** + * otp_len - Length of the otp field + */ + size_t otp_len; + + /** + * pending_req_identity - Whether there is a pending identity request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_identity; + + /** + * pending_req_password - Whether there is a pending password request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_password; + + /** + * pending_req_pin - Whether there is a pending PIN request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_pin; + + /** + * pending_req_new_password - Pending password update request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_new_password; + + /** + * pending_req_passphrase - Pending passphrase request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_passphrase; + + /** + * pending_req_otp - Whether there is a pending OTP request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + char *pending_req_otp; + + /** + * pending_req_otp_len - Length of the pending OTP request + */ + size_t pending_req_otp_len; + + /** + * pac_file - File path or blob name for the PAC entries (EAP-FAST) + * + * wpa_supplicant will need to be able to create this file and write + * updates to it when PAC is being provisioned or refreshed. Full path + * to the file should be used since working directory may change when + * wpa_supplicant is run in the background. + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + char *pac_file; + + /** + * mschapv2_retry - MSCHAPv2 retry in progress + * + * This field is used internally by EAP-MSCHAPv2 and should not be set + * as part of configuration. + */ + int mschapv2_retry; + + /** + * new_password - New password for password update + * + * This field is used during MSCHAPv2 password update. This is normally + * requested from the user through the control interface and not set + * from configuration. + */ + u8 *new_password; + + /** + * new_password_len - Length of new_password field + */ + size_t new_password_len; + + /** + * fragment_size - Maximum EAP fragment size in bytes (default 1398) + * + * This value limits the fragment size for EAP methods that support + * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set + * small enough to make the EAP messages fit in MTU of the network + * interface used for EAPOL. The default value is suitable for most + * cases. + */ + int fragment_size; + + /** + * chbind_config - eap channel binding config data + */ + struct eap_peer_chbind_config *chbind_config; + + /** + * chbind_config_len - channel binding config data count + */ + size_t chbind_config_len; + +#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0) +#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1) + /** + * flags - Network configuration flags (bitfield) + * + * This variable is used for internal flags to describe further details + * for the network parameters. + * bit 0 = password is represented as a 16-byte NtPasswordHash value + * instead of plaintext password + * bit 1 = password is stored in external storage; the value in the + * password field is the name of that external entry + */ + u32 flags; + + /** + * ocsp - Whether to use/require OCSP to check server certificate + * + * 0 = do not use OCSP stapling (TLS certificate status extension) + * 1 = try to use OCSP stapling, but not require response + * 2 = require valid OCSP stapling response + */ + int ocsp; + + /** + * external_sim_resp - Response from external SIM processing + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request external + * SIM/USIM processing. + */ + char *external_sim_resp; + + /** + * sim_num - User selected SIM identifier + * + * This variable is used for identifying which SIM is used if the system + * has more than one. + */ + int sim_num; + + /** + * openssl_ciphers - OpenSSL cipher string + * + * This is an OpenSSL specific configuration option for configuring the + * ciphers for this connection. If not set, the default cipher suite + * list is used. + */ + char *openssl_ciphers; + + /** + * erp - Whether EAP Re-authentication Protocol (ERP) is enabled + */ + int erp; +}; + + +/** + * struct wpa_config_blob - Named configuration blob + * + * This data structure is used to provide storage for binary objects to store + * abstract information like certificates and private keys inlined with the + * configuration data. + */ +struct wpa_config_blob { + /** + * name - Blob name + */ + char *name; + + /** + * data - Pointer to binary data + */ + u8 *data; + + /** + * len - Length of binary data + */ + size_t len; + + /** + * next - Pointer to next blob in the configuration + */ + struct wpa_config_blob *next; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_CONFIG_H */ diff --git a/src/eap_peer/eap_eke.c b/libeap/src/eap_peer/eap_eke.c similarity index 100% rename from src/eap_peer/eap_eke.c rename to libeap/src/eap_peer/eap_eke.c diff --git a/src/eap_peer/eap_fast.c b/libeap/src/eap_peer/eap_fast.c similarity index 100% rename from src/eap_peer/eap_fast.c rename to libeap/src/eap_peer/eap_fast.c diff --git a/src/eap_peer/eap_fast_pac.c b/libeap/src/eap_peer/eap_fast_pac.c similarity index 100% rename from src/eap_peer/eap_fast_pac.c rename to libeap/src/eap_peer/eap_fast_pac.c diff --git a/src/eap_peer/eap_fast_pac.h b/libeap/src/eap_peer/eap_fast_pac.h similarity index 100% rename from src/eap_peer/eap_fast_pac.h rename to libeap/src/eap_peer/eap_fast_pac.h diff --git a/src/eap_peer/eap_gpsk.c b/libeap/src/eap_peer/eap_gpsk.c similarity index 100% rename from src/eap_peer/eap_gpsk.c rename to libeap/src/eap_peer/eap_gpsk.c diff --git a/src/eap_peer/eap_gtc.c b/libeap/src/eap_peer/eap_gtc.c similarity index 100% rename from src/eap_peer/eap_gtc.c rename to libeap/src/eap_peer/eap_gtc.c diff --git a/libeap/src/eap_peer/eap_i.h b/libeap/src/eap_peer/eap_i.h new file mode 100644 index 0000000..5d915fa --- /dev/null +++ b/libeap/src/eap_peer/eap_i.h @@ -0,0 +1,397 @@ +/* + * EAP peer state machines internal structures (RFC 4137) + * Copyright (c) 2004-2014, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_I_H +#define EAP_I_H + +#include "wpabuf.h" +#include "utils/list.h" +#include "eap_peer/eap.h" +#include "eap_common/eap_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* RFC 4137 - EAP Peer state machine */ + +typedef enum { + DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC +} EapDecision; + +typedef enum { + METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE +} EapMethodState; + +/** + * struct eap_method_ret - EAP return values from struct eap_method::process() + * + * These structure contains OUT variables for the interface between peer state + * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as + * the return value of struct eap_method::process() so it is not included in + * this structure. + */ +struct eap_method_ret { + /** + * ignore - Whether method decided to drop the current packed (OUT) + */ + Boolean ignore; + + /** + * methodState - Method-specific state (IN/OUT) + */ + EapMethodState methodState; + + /** + * decision - Authentication decision (OUT) + */ + EapDecision decision; + + /** + * allowNotifications - Whether method allows notifications (OUT) + */ + Boolean allowNotifications; +}; + + +/** + * struct eap_method - EAP method interface + * This structure defines the EAP method interface. Each method will need to + * register its own EAP type, EAP name, and set of function pointers for method + * specific operations. This interface is based on section 4.4 of RFC 4137. + */ +struct eap_method { + /** + * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) + */ + int vendor; + + /** + * method - EAP type number (EAP_TYPE_*) + */ + EapType method; + + /** + * name - Name of the method (e.g., "TLS") + */ + const char *name; + + /** + * init - Initialize an EAP method + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * Returns: Pointer to allocated private data, or %NULL on failure + * + * This function is used to initialize the EAP method explicitly + * instead of using METHOD_INIT state as specific in RFC 4137. The + * method is expected to initialize it method-specific state and return + * a pointer that will be used as the priv argument to other calls. + */ + void * (*init)(struct eap_sm *sm); + + /** + * deinit - Deinitialize an EAP method + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * + * Deinitialize the EAP method and free any allocated private data. + */ + void (*deinit)(struct eap_sm *sm, void *priv); + + /** + * process - Process an EAP request + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * @ret: Return values from EAP request validation and processing + * @reqData: EAP request to be processed (eapReqData) + * Returns: Pointer to allocated EAP response packet (eapRespData) + * + * This function is a combination of m.check(), m.process(), and + * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other + * words, this function validates the incoming request, processes it, + * and build a response packet. m.check() and m.process() return values + * are returned through struct eap_method_ret *ret variable. Caller is + * responsible for freeing the returned EAP response packet. + */ + struct wpabuf * (*process)(struct eap_sm *sm, void *priv, + struct eap_method_ret *ret, + const struct wpabuf *reqData); + + /** + * isKeyAvailable - Find out whether EAP method has keying material + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * Returns: %TRUE if key material (eapKeyData) is available + */ + Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv); + + /** + * getKey - Get EAP method specific keying material (eapKeyData) + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * @len: Pointer to variable to store key length (eapKeyDataLen) + * Returns: Keying material (eapKeyData) or %NULL if not available + * + * This function can be used to get the keying material from the EAP + * method. The key may already be stored in the method-specific private + * data or this function may derive the key. + */ + u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len); + + /** + * get_status - Get EAP method status + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * @buf: Buffer for status information + * @buflen: Maximum buffer length + * @verbose: Whether to include verbose status information + * Returns: Number of bytes written to buf + * + * Query EAP method for status information. This function fills in a + * text area with current status information from the EAP method. If + * the buffer (buf) is not large enough, status information will be + * truncated to fit the buffer. + */ + int (*get_status)(struct eap_sm *sm, void *priv, char *buf, + size_t buflen, int verbose); + + /** + * has_reauth_data - Whether method is ready for fast reauthentication + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * Returns: %TRUE or %FALSE based on whether fast reauthentication is + * possible + * + * This function is an optional handler that only EAP methods + * supporting fast re-authentication need to implement. + */ + Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv); + + /** + * deinit_for_reauth - Release data that is not needed for fast re-auth + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * + * This function is an optional handler that only EAP methods + * supporting fast re-authentication need to implement. This is called + * when authentication has been completed and EAP state machine is + * requesting that enough state information is maintained for fast + * re-authentication + */ + void (*deinit_for_reauth)(struct eap_sm *sm, void *priv); + + /** + * init_for_reauth - Prepare for start of fast re-authentication + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * + * This function is an optional handler that only EAP methods + * supporting fast re-authentication need to implement. This is called + * when EAP authentication is started and EAP state machine is + * requesting fast re-authentication to be used. + */ + void * (*init_for_reauth)(struct eap_sm *sm, void *priv); + + /** + * get_identity - Get method specific identity for re-authentication + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * @len: Length of the returned identity + * Returns: Pointer to the method specific identity or %NULL if default + * identity is to be used + * + * This function is an optional handler that only EAP methods + * that use method specific identity need to implement. + */ + const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len); + + /** + * free - Free EAP method data + * @method: Pointer to the method data registered with + * eap_peer_method_register(). + * + * This function will be called when the EAP method is being + * unregistered. If the EAP method allocated resources during + * registration (e.g., allocated struct eap_method), they should be + * freed in this function. No other method functions will be called + * after this call. If this function is not defined (i.e., function + * pointer is %NULL), a default handler is used to release the method + * data with free(method). This is suitable for most cases. + */ + void (*free)(struct eap_method *method); + +#define EAP_PEER_METHOD_INTERFACE_VERSION 1 + /** + * version - Version of the EAP peer method interface + * + * The EAP peer method implementation should set this variable to + * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the + * EAP method is using supported API version when using dynamically + * loadable EAP methods. + */ + int version; + + /** + * next - Pointer to the next EAP method + * + * This variable is used internally in the EAP method registration code + * to create a linked list of registered EAP methods. + */ + struct eap_method *next; + +#ifdef CONFIG_DYNAMIC_EAP_METHODS + /** + * dl_handle - Handle for the dynamic library + * + * This variable is used internally in the EAP method registration code + * to store a handle for the dynamic library. If the method is linked + * in statically, this is %NULL. + */ + void *dl_handle; +#endif /* CONFIG_DYNAMIC_EAP_METHODS */ + + /** + * get_emsk - Get EAP method specific keying extended material (EMSK) + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * @len: Pointer to a variable to store EMSK length + * Returns: EMSK or %NULL if not available + * + * This function can be used to get the extended keying material from + * the EAP method. The key may already be stored in the method-specific + * private data or this function may derive the key. + */ + u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); + + /** + * getSessionId - Get EAP method specific Session-Id + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @priv: Pointer to private EAP method data from eap_method::init() + * @len: Pointer to a variable to store Session-Id length + * Returns: Session-Id or %NULL if not available + * + * This function can be used to get the Session-Id from the EAP method. + * The Session-Id may already be stored in the method-specific private + * data or this function may derive the Session-Id. + */ + u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len); +}; + + +struct eap_erp_key { + struct dl_list list; + size_t rRK_len; + size_t rIK_len; + u8 rRK[ERP_MAX_KEY_LEN]; + u8 rIK[ERP_MAX_KEY_LEN]; + u32 next_seq; + char keyname_nai[]; +}; + +/** + * struct eap_sm - EAP state machine data + */ +struct eap_sm { + enum { + EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED, + EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD, + EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS, + EAP_FAILURE + } EAP_state; + /* Long-term local variables */ + EapType selectedMethod; + EapMethodState methodState; + int lastId; + struct wpabuf *lastRespData; + EapDecision decision; + /* Short-term local variables */ + Boolean rxReq; + Boolean rxSuccess; + Boolean rxFailure; + int reqId; + EapType reqMethod; + int reqVendor; + u32 reqVendorMethod; + Boolean ignore; + /* Constants */ + int ClientTimeout; + + /* Miscellaneous variables */ + Boolean allowNotifications; /* peer state machine <-> methods */ + struct wpabuf *eapRespData; /* peer to lower layer */ + Boolean eapKeyAvailable; /* peer to lower layer */ + u8 *eapKeyData; /* peer to lower layer */ + size_t eapKeyDataLen; /* peer to lower layer */ + u8 *eapSessionId; /* peer to lower layer */ + size_t eapSessionIdLen; /* peer to lower layer */ + const struct eap_method *m; /* selected EAP method */ + /* not defined in RFC 4137 */ + Boolean changed; + void *eapol_ctx; + const struct eapol_callbacks *eapol_cb; + void *eap_method_priv; + int init_phase2; + int fast_reauth; + Boolean reauthInit; /* send EAP-Identity/Re-auth */ + u32 erp_seq; + + Boolean rxResp /* LEAP only */; + Boolean leap_done; + Boolean peap_done; + u8 req_sha1[20]; /* SHA1() of the current EAP packet */ + u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used + * in duplicate request detection. */ + + void *msg_ctx; + void *scard_ctx; + void *ssl_ctx; + void *ssl_ctx2; + + unsigned int workaround; + + /* Optional challenges generated in Phase 1 (EAP-FAST) */ + u8 *peer_challenge, *auth_challenge; + + int num_rounds; + int force_disabled; + + struct wps_context *wps; + + int prev_failure; + struct eap_peer_config *last_config; + + struct ext_password_data *ext_pw; + struct wpabuf *ext_pw_buf; + + int external_sim; + + unsigned int expected_failure:1; + + struct dl_list erp_keys; /* struct eap_erp_key */ +}; + +const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); +const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len); +const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash); +const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len); +const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len); +void eap_clear_config_otp(struct eap_sm *sm); +const char * eap_get_config_phase1(struct eap_sm *sm); +const char * eap_get_config_phase2(struct eap_sm *sm); +int eap_get_config_fragment_size(struct eap_sm *sm); +struct eap_peer_config * eap_get_config(struct eap_sm *sm); +void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob); +const struct wpa_config_blob * +eap_get_config_blob(struct eap_sm *sm, const char *name); +void eap_notify_pending(struct eap_sm *sm); +int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_I_H */ diff --git a/src/eap_peer/eap_ikev2.c b/libeap/src/eap_peer/eap_ikev2.c similarity index 100% rename from src/eap_peer/eap_ikev2.c rename to libeap/src/eap_peer/eap_ikev2.c diff --git a/src/eap_peer/eap_leap.c b/libeap/src/eap_peer/eap_leap.c similarity index 100% rename from src/eap_peer/eap_leap.c rename to libeap/src/eap_peer/eap_leap.c diff --git a/src/eap_peer/eap_md5.c b/libeap/src/eap_peer/eap_md5.c similarity index 100% rename from src/eap_peer/eap_md5.c rename to libeap/src/eap_peer/eap_md5.c diff --git a/src/eap_peer/eap_methods.c b/libeap/src/eap_peer/eap_methods.c similarity index 100% rename from src/eap_peer/eap_methods.c rename to libeap/src/eap_peer/eap_methods.c diff --git a/libeap/src/eap_peer/eap_methods.h b/libeap/src/eap_peer/eap_methods.h new file mode 100644 index 0000000..11c3278 --- /dev/null +++ b/libeap/src/eap_peer/eap_methods.h @@ -0,0 +1,119 @@ +/* + * EAP peer: Method registration + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_METHODS_H +#define EAP_METHODS_H + +#include "eap_common/eap_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method); +const struct eap_method * eap_peer_get_methods(size_t *count); + +struct eap_method * eap_peer_method_alloc(int version, int vendor, + EapType method, const char *name); +void eap_peer_method_free(struct eap_method *method); +int eap_peer_method_register(struct eap_method *method); + + +#ifdef IEEE8021X_EAPOL + +EapType eap_peer_get_type(const char *name, int *vendor); +const char * eap_get_name(int vendor, EapType type); +size_t eap_get_names(char *buf, size_t buflen); +char ** eap_get_names_as_string_array(size_t *num); +void eap_peer_unregister_methods(void); + +#else /* IEEE8021X_EAPOL */ + +static inline EapType eap_peer_get_type(const char *name, int *vendor) +{ + *vendor = EAP_VENDOR_IETF; + return EAP_TYPE_NONE; +} + +static inline const char * eap_get_name(int vendor, EapType type) +{ + return NULL; +} + +static inline size_t eap_get_names(char *buf, size_t buflen) +{ + return 0; +} + +static inline int eap_peer_register_methods(void) +{ + return 0; +} + +static inline void eap_peer_unregister_methods(void) +{ +} + +static inline char ** eap_get_names_as_string_array(size_t *num) +{ + return NULL; +} + +#endif /* IEEE8021X_EAPOL */ + + +#ifdef CONFIG_DYNAMIC_EAP_METHODS + +int eap_peer_method_load(const char *so); +int eap_peer_method_unload(struct eap_method *method); + +#else /* CONFIG_DYNAMIC_EAP_METHODS */ + +static inline int eap_peer_method_load(const char *so UNUSED) +{ + return 0; +} + +static inline int eap_peer_method_unload(struct eap_method *method UNUSED) +{ + return 0; +} + +#endif /* CONFIG_DYNAMIC_EAP_METHODS */ + +/* EAP peer method registration calls for statically linked in methods */ +int eap_peer_md5_register(void); +int eap_peer_tls_register(void); +int eap_peer_unauth_tls_register(void); +int eap_peer_wfa_unauth_tls_register(void); +int eap_peer_mschapv2_register(void); +int eap_peer_peap_register(void); +int eap_peer_ttls_register(void); +int eap_peer_gtc_register(void); +int eap_peer_otp_register(void); +int eap_peer_sim_register(void); +int eap_peer_leap_register(void); +int eap_peer_psk_register(void); +int eap_peer_aka_register(void); +int eap_peer_aka_prime_register(void); +int eap_peer_fast_register(void); +int eap_peer_pax_register(void); +int eap_peer_sake_register(void); +int eap_peer_gpsk_register(void); +int eap_peer_wsc_register(void); +int eap_peer_ikev2_register(void); +int eap_peer_vendor_test_register(void); +int eap_peer_tnc_register(void); +int eap_peer_pwd_register(void); +int eap_peer_eke_register(void); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_METHODS_H */ diff --git a/src/eap_peer/eap_mschapv2.c b/libeap/src/eap_peer/eap_mschapv2.c similarity index 100% rename from src/eap_peer/eap_mschapv2.c rename to libeap/src/eap_peer/eap_mschapv2.c diff --git a/src/eap_peer/eap_otp.c b/libeap/src/eap_peer/eap_otp.c similarity index 100% rename from src/eap_peer/eap_otp.c rename to libeap/src/eap_peer/eap_otp.c diff --git a/src/eap_peer/eap_pax.c b/libeap/src/eap_peer/eap_pax.c similarity index 100% rename from src/eap_peer/eap_pax.c rename to libeap/src/eap_peer/eap_pax.c diff --git a/src/eap_peer/eap_peap.c b/libeap/src/eap_peer/eap_peap.c similarity index 100% rename from src/eap_peer/eap_peap.c rename to libeap/src/eap_peer/eap_peap.c diff --git a/src/eap_peer/eap_proxy.h b/libeap/src/eap_peer/eap_proxy.h similarity index 100% rename from src/eap_peer/eap_proxy.h rename to libeap/src/eap_peer/eap_proxy.h diff --git a/src/eap_peer/eap_proxy_dummy.c b/libeap/src/eap_peer/eap_proxy_dummy.c similarity index 100% rename from src/eap_peer/eap_proxy_dummy.c rename to libeap/src/eap_peer/eap_proxy_dummy.c diff --git a/src/eap_peer/eap_psk.c b/libeap/src/eap_peer/eap_psk.c similarity index 100% rename from src/eap_peer/eap_psk.c rename to libeap/src/eap_peer/eap_psk.c diff --git a/src/eap_peer/eap_pwd.c b/libeap/src/eap_peer/eap_pwd.c similarity index 100% rename from src/eap_peer/eap_pwd.c rename to libeap/src/eap_peer/eap_pwd.c diff --git a/src/eap_peer/eap_sake.c b/libeap/src/eap_peer/eap_sake.c similarity index 100% rename from src/eap_peer/eap_sake.c rename to libeap/src/eap_peer/eap_sake.c diff --git a/src/eap_peer/eap_sim.c b/libeap/src/eap_peer/eap_sim.c similarity index 100% rename from src/eap_peer/eap_sim.c rename to libeap/src/eap_peer/eap_sim.c diff --git a/src/eap_peer/eap_tls.c b/libeap/src/eap_peer/eap_tls.c similarity index 100% rename from src/eap_peer/eap_tls.c rename to libeap/src/eap_peer/eap_tls.c diff --git a/libeap/src/eap_peer/eap_tls_common.c b/libeap/src/eap_peer/eap_tls_common.c new file mode 100644 index 0000000..b1f9300 --- /dev/null +++ b/libeap/src/eap_peer/eap_tls_common.c @@ -0,0 +1,1111 @@ +/* + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions + * Copyright (c) 2004-2013, Jouni Malinen + * + * 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/sha1.h" +#include "crypto/tls.h" +#include "eap_i.h" +#include "eap_tls_common.h" +#include "eap_config.h" + + +static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, + u8 code, u8 identifier) +{ + if (type == EAP_UNAUTH_TLS_TYPE) + return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, + EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, + code, identifier); + if (type == EAP_WFA_UNAUTH_TLS_TYPE) + return eap_msg_alloc(EAP_VENDOR_WFA_NEW, + EAP_VENDOR_WFA_UNAUTH_TLS, payload_len, + code, identifier); + return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, + identifier); +} + + +static int eap_tls_check_blob(struct eap_sm *sm, const char **name, + const u8 **data, size_t *data_len) +{ + const struct wpa_config_blob *blob; + + if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) + return 0; + + blob = eap_get_config_blob(sm, *name + 7); + if (blob == NULL) { + wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " + "found", __func__, *name + 7); + return -1; + } + + *name = NULL; + *data = blob->data; + *data_len = blob->len; + + return 0; +} + + +static void eap_tls_params_flags(struct tls_connection_params *params, + const char *txt) +{ + if (txt == NULL) + return; + if (os_strstr(txt, "tls_allow_md5=1")) + params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; + if (os_strstr(txt, "tls_disable_time_checks=1")) + params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; + if (os_strstr(txt, "tls_disable_session_ticket=1")) + params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; + if (os_strstr(txt, "tls_disable_session_ticket=0")) + params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET; + if (os_strstr(txt, "tls_disable_tlsv1_0=1")) + params->flags |= TLS_CONN_DISABLE_TLSv1_0; + if (os_strstr(txt, "tls_disable_tlsv1_0=0")) + params->flags &= ~TLS_CONN_DISABLE_TLSv1_0; + if (os_strstr(txt, "tls_disable_tlsv1_1=1")) + params->flags |= TLS_CONN_DISABLE_TLSv1_1; + if (os_strstr(txt, "tls_disable_tlsv1_1=0")) + params->flags &= ~TLS_CONN_DISABLE_TLSv1_1; + if (os_strstr(txt, "tls_disable_tlsv1_2=1")) + params->flags |= TLS_CONN_DISABLE_TLSv1_2; + if (os_strstr(txt, "tls_disable_tlsv1_2=0")) + params->flags &= ~TLS_CONN_DISABLE_TLSv1_2; +} + + +static void eap_tls_params_from_conf1(struct tls_connection_params *params, + struct eap_peer_config *config) +{ + params->ca_cert = (char *) config->ca_cert; + params->ca_path = (char *) config->ca_path; + params->client_cert = (char *) config->client_cert; + params->private_key = (char *) config->private_key; + params->private_key_passwd = (char *) config->private_key_passwd; + params->dh_file = (char *) config->dh_file; + params->subject_match = (char *) config->subject_match; + params->altsubject_match = (char *) config->altsubject_match; + params->suffix_match = config->domain_suffix_match; + params->domain_match = config->domain_match; + params->engine = config->engine; + params->engine_id = config->engine_id; + params->pin = config->pin; + params->key_id = config->key_id; + params->cert_id = config->cert_id; + params->ca_cert_id = config->ca_cert_id; + eap_tls_params_flags(params, config->phase1); +} + + +static void eap_tls_params_from_conf2(struct tls_connection_params *params, + struct eap_peer_config *config) +{ + params->ca_cert = (char *) config->ca_cert2; + params->ca_path = (char *) config->ca_path2; + params->client_cert = (char *) config->client_cert2; + params->private_key = (char *) config->private_key2; + params->private_key_passwd = (char *) config->private_key2_passwd; + params->dh_file = (char *) config->dh_file2; + params->subject_match = (char *) config->subject_match2; + params->altsubject_match = (char *) config->altsubject_match2; + params->suffix_match = config->domain_suffix_match2; + params->domain_match = config->domain_match2; + params->engine = config->engine2; + params->engine_id = config->engine2_id; + params->pin = config->pin2; + params->key_id = config->key2_id; + params->cert_id = config->cert2_id; + params->ca_cert_id = config->ca_cert2_id; + eap_tls_params_flags(params, config->phase2); +} + + +static int eap_tls_params_from_conf(struct eap_sm *sm, + struct eap_ssl_data *data, + struct tls_connection_params *params, + struct eap_peer_config *config, int phase2) +{ + os_memset(params, 0, sizeof(*params)); + if (sm->workaround && data->eap_type != EAP_TYPE_FAST) { + /* + * Some deployed authentication servers seem to be unable to + * handle the TLS Session Ticket extension (they are supposed + * to ignore unrecognized TLS extensions, but end up rejecting + * the ClientHello instead). As a workaround, disable use of + * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and + * EAP-TTLS (EAP-FAST uses session ticket, so any server that + * supports EAP-FAST does not need this workaround). + */ + params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; + } + if (phase2) { + wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); + eap_tls_params_from_conf2(params, config); + } else { + wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); + eap_tls_params_from_conf1(params, config); + if (data->eap_type == EAP_TYPE_FAST) + params->flags |= TLS_CONN_EAP_FAST; + } + + /* + * Use blob data, if available. Otherwise, leave reference to external + * file as-is. + */ + if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, + ¶ms->ca_cert_blob_len) || + eap_tls_check_blob(sm, ¶ms->client_cert, + ¶ms->client_cert_blob, + ¶ms->client_cert_blob_len) || + eap_tls_check_blob(sm, ¶ms->private_key, + ¶ms->private_key_blob, + ¶ms->private_key_blob_len) || + eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, + ¶ms->dh_blob_len)) { + wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); + return -1; + } + + params->openssl_ciphers = config->openssl_ciphers; + + return 0; +} + + +static int eap_tls_init_connection(struct eap_sm *sm, + struct eap_ssl_data *data, + struct eap_peer_config *config, + struct tls_connection_params *params) +{ + int res; + + if (config->ocsp) + params->flags |= TLS_CONN_REQUEST_OCSP; + if (config->ocsp == 2) + params->flags |= TLS_CONN_REQUIRE_OCSP; + data->conn = tls_connection_init(data->ssl_ctx); + if (data->conn == NULL) { + wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " + "connection"); + return -1; + } + + res = tls_connection_set_params(data->ssl_ctx, data->conn, params); + if (res == TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN) { + /* + * At this point with the pkcs11 engine the PIN is wrong. We + * reset the PIN in the configuration to be sure to not use it + * again and the calling function must request a new one. + */ + wpa_printf(MSG_INFO, + "TLS: Bad PIN provided, requesting a new one"); + os_free(config->pin); + config->pin = NULL; + eap_sm_request_pin(sm); + sm->ignore = TRUE; + } else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { + wpa_printf(MSG_INFO, "TLS: Failed to initialize engine"); + } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { + wpa_printf(MSG_INFO, "TLS: Failed to load private key"); + sm->ignore = TRUE; + } + if (res) { + wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " + "parameters"); + tls_connection_deinit(data->ssl_ctx, data->conn); + data->conn = NULL; + return -1; + } + + return 0; +} + + +/** + * eap_peer_tls_ssl_init - Initialize shared TLS functionality + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @config: Pointer to the network configuration + * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) + * Returns: 0 on success, -1 on failure + * + * This function is used to initialize shared TLS functionality for EAP-TLS, + * EAP-PEAP, EAP-TTLS, and EAP-FAST. + */ +int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, + struct eap_peer_config *config, u8 eap_type) +{ + struct tls_connection_params params; + + if (config == NULL) + return -1; + + data->eap = sm; + data->eap_type = eap_type; + data->phase2 = sm->init_phase2; + data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : + sm->ssl_ctx; + if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < + 0) + return -1; + + if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) + return -1; + + data->tls_out_limit = config->fragment_size; + if (data->phase2) { + /* Limit the fragment size in the inner TLS authentication + * since the outer authentication with EAP-PEAP does not yet + * support fragmentation */ + if (data->tls_out_limit > 100) + data->tls_out_limit -= 100; + } + + if (config->phase1 && + os_strstr(config->phase1, "include_tls_length=1")) { + wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " + "unfragmented packets"); + data->include_tls_length = 1; + } + + return 0; +} + + +/** + * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * + * This function deinitializes shared TLS functionality that was initialized + * with eap_peer_tls_ssl_init(). + */ +void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) +{ + tls_connection_deinit(data->ssl_ctx, data->conn); + eap_peer_tls_reset_input(data); + eap_peer_tls_reset_output(data); +} + + +/** + * eap_peer_tls_derive_key - Derive a key based on TLS session data + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @label: Label string for deriving the keys, e.g., "client EAP encryption" + * @len: Length of the key material to generate (usually 64 for MSK) + * Returns: Pointer to allocated key on success or %NULL on failure + * + * This function uses TLS-PRF to generate pseudo-random data based on the TLS + * session data (client/server random and master key). Each key type may use a + * different label to bind the key usage into the generated material. + * + * The caller is responsible for freeing the returned buffer. + */ +u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, + const char *label, size_t len) +{ + u8 *out; + + out = os_malloc(len); + if (out == NULL) + return NULL; + + if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0, + out, len)) { + os_free(out); + return NULL; + } + + return out; +} + + +/** + * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) + * @len: Pointer to length of the session ID generated + * Returns: Pointer to allocated Session-Id on success or %NULL on failure + * + * This function derive the Session-Id based on the TLS session data + * (client/server random and method type). + * + * The caller is responsible for freeing the returned buffer. + */ +u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, + struct eap_ssl_data *data, u8 eap_type, + size_t *len) +{ + struct tls_random keys; + u8 *out; + + if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys)) + return NULL; + + if (keys.client_random == NULL || keys.server_random == NULL) + return NULL; + + *len = 1 + keys.client_random_len + keys.server_random_len; + out = os_malloc(*len); + if (out == NULL) + return NULL; + + /* Session-Id = EAP type || client.random || server.random */ + out[0] = eap_type; + os_memcpy(out + 1, keys.client_random, keys.client_random_len); + os_memcpy(out + 1 + keys.client_random_len, keys.server_random, + keys.server_random_len); + + return out; +} + + +/** + * eap_peer_tls_reassemble_fragment - Reassemble a received fragment + * @data: Data for TLS processing + * @in_data: Next incoming TLS segment + * Returns: 0 on success, 1 if more data is needed for the full message, or + * -1 on error + */ +static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, + const struct wpabuf *in_data) +{ + size_t tls_in_len, in_len; + + tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; + in_len = in_data ? wpabuf_len(in_data) : 0; + + if (tls_in_len + in_len == 0) { + /* No message data received?! */ + wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " + "tls_in_left=%lu tls_in_len=%lu in_len=%lu", + (unsigned long) data->tls_in_left, + (unsigned long) tls_in_len, + (unsigned long) in_len); + eap_peer_tls_reset_input(data); + return -1; + } + + if (tls_in_len + in_len > 65536) { + /* + * Limit length to avoid rogue servers from causing large + * memory allocations. + */ + wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " + "64 kB)"); + eap_peer_tls_reset_input(data); + return -1; + } + + if (in_len > data->tls_in_left) { + /* Sender is doing something odd - reject message */ + wpa_printf(MSG_INFO, "SSL: more data than TLS message length " + "indicated"); + eap_peer_tls_reset_input(data); + return -1; + } + + if (wpabuf_resize(&data->tls_in, in_len) < 0) { + wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " + "data"); + eap_peer_tls_reset_input(data); + return -1; + } + if (in_data) + wpabuf_put_buf(data->tls_in, in_data); + data->tls_in_left -= in_len; + + if (data->tls_in_left > 0) { + wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " + "data", (unsigned long) data->tls_in_left); + return 1; + } + + return 0; +} + + +/** + * eap_peer_tls_data_reassemble - Reassemble TLS data + * @data: Data for TLS processing + * @in_data: Next incoming TLS segment + * @need_more_input: Variable for returning whether more input data is needed + * to reassemble this TLS packet + * Returns: Pointer to output data, %NULL on error or when more data is needed + * for the full message (in which case, *need_more_input is also set to 1). + * + * This function reassembles TLS fragments. Caller must not free the returned + * data buffer since an internal pointer to it is maintained. + */ +static const struct wpabuf * eap_peer_tls_data_reassemble( + struct eap_ssl_data *data, const struct wpabuf *in_data, + int *need_more_input) +{ + *need_more_input = 0; + + if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { + /* Message has fragments */ + int res = eap_peer_tls_reassemble_fragment(data, in_data); + if (res) { + if (res == 1) + *need_more_input = 1; + return NULL; + } + + /* Message is now fully reassembled. */ + } else { + /* No fragments in this message, so just make a copy of it. */ + data->tls_in_left = 0; + data->tls_in = wpabuf_dup(in_data); + if (data->tls_in == NULL) + return NULL; + } + + return data->tls_in; +} + + +/** + * eap_tls_process_input - Process incoming TLS message + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @in_data: Message received from the server + * @out_data: Buffer for returning a pointer to application data (if available) + * Returns: 0 on success, 1 if more input data is needed, 2 if application data + * is available, -1 on failure + */ +static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, + const struct wpabuf *in_data, + struct wpabuf **out_data) +{ + const struct wpabuf *msg; + int need_more_input; + struct wpabuf *appl_data; + + msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); + if (msg == NULL) + return need_more_input ? 1 : -1; + + /* Full TLS message reassembled - continue handshake processing */ + if (data->tls_out) { + /* This should not happen.. */ + wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " + "tls_out data even though tls_out_len = 0"); + wpabuf_free(data->tls_out); + WPA_ASSERT(data->tls_out == NULL); + } + appl_data = NULL; + data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn, + msg, &appl_data); + + eap_peer_tls_reset_input(data); + + if (appl_data && + tls_connection_established(data->ssl_ctx, data->conn) && + !tls_connection_get_failed(data->ssl_ctx, data->conn)) { + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", + appl_data); + *out_data = appl_data; + return 2; + } + + wpabuf_free(appl_data); + + return 0; +} + + +/** + * eap_tls_process_output - Process outgoing TLS message + * @data: Data for TLS processing + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) + * @peap_version: Version number for EAP-PEAP/TTLS + * @id: EAP identifier for the response + * @ret: Return value to use on success + * @out_data: Buffer for returning the allocated output buffer + * Returns: ret (0 or 1) on success, -1 on failure + */ +static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, + int peap_version, u8 id, int ret, + struct wpabuf **out_data) +{ + size_t len; + u8 *flags; + int more_fragments, length_included; + + if (data->tls_out == NULL) + return -1; + len = wpabuf_len(data->tls_out) - data->tls_out_pos; + wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " + "%lu bytes)", + (unsigned long) len, + (unsigned long) wpabuf_len(data->tls_out)); + + /* + * Limit outgoing message to the configured maximum size. Fragment + * message if needed. + */ + if (len > data->tls_out_limit) { + more_fragments = 1; + len = data->tls_out_limit; + wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " + "will follow", (unsigned long) len); + } else + more_fragments = 0; + + length_included = data->tls_out_pos == 0 && + (wpabuf_len(data->tls_out) > data->tls_out_limit || + data->include_tls_length); + if (!length_included && + eap_type == EAP_TYPE_PEAP && peap_version == 0 && + !tls_connection_established(data->eap->ssl_ctx, data->conn)) { + /* + * Windows Server 2008 NPS really wants to have the TLS Message + * length included in phase 0 even for unfragmented frames or + * it will get very confused with Compound MAC calculation and + * Outer TLVs. + */ + length_included = 1; + } + + *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len, + EAP_CODE_RESPONSE, id); + if (*out_data == NULL) + return -1; + + flags = wpabuf_put(*out_data, 1); + *flags = peap_version; + if (more_fragments) + *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; + if (length_included) { + *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; + wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); + } + + wpabuf_put_data(*out_data, + wpabuf_head_u8(data->tls_out) + data->tls_out_pos, + len); + data->tls_out_pos += len; + + if (!more_fragments) + eap_peer_tls_reset_output(data); + + return ret; +} + + +/** + * eap_peer_tls_process_helper - Process TLS handshake message + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) + * @peap_version: Version number for EAP-PEAP/TTLS + * @id: EAP identifier for the response + * @in_data: Message received from the server + * @out_data: Buffer for returning a pointer to the response message + * Returns: 0 on success, 1 if more input data is needed, 2 if application data + * is available, or -1 on failure + * + * This function can be used to process TLS handshake messages. It reassembles + * the received fragments and uses a TLS library to process the messages. The + * response data from the TLS library is fragmented to suitable output messages + * that the caller can send out. + * + * out_data is used to return the response message if the return value of this + * function is 0, 2, or -1. In case of failure, the message is likely a TLS + * alarm message. The caller is responsible for freeing the allocated buffer if + * *out_data is not %NULL. + * + * This function is called for each received TLS message during the TLS + * handshake after eap_peer_tls_process_init() call and possible processing of + * TLS Flags field. Once the handshake has been completed, i.e., when + * tls_connection_established() returns 1, EAP method specific decrypting of + * the tunneled data is used. + */ +int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, + u8 id, const struct wpabuf *in_data, + struct wpabuf **out_data) +{ + int ret = 0; + + *out_data = NULL; + + if (data->tls_out && wpabuf_len(data->tls_out) > 0 && + wpabuf_len(in_data) > 0) { + wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " + "fragments are waiting to be sent out"); + return -1; + } + + if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { + /* + * No more data to send out - expect to receive more data from + * the AS. + */ + int res = eap_tls_process_input(sm, data, in_data, out_data); + if (res) { + /* + * Input processing failed (res = -1) or more data is + * needed (res = 1). + */ + return res; + } + + /* + * The incoming message has been reassembled and processed. The + * response was allocated into data->tls_out buffer. + */ + } + + if (data->tls_out == NULL) { + /* + * No outgoing fragments remaining from the previous message + * and no new message generated. This indicates an error in TLS + * processing. + */ + eap_peer_tls_reset_output(data); + return -1; + } + + if (tls_connection_get_failed(data->ssl_ctx, data->conn)) { + /* TLS processing has failed - return error */ + wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " + "report error (len=%u)", + (unsigned int) wpabuf_len(data->tls_out)); + ret = -1; + /* TODO: clean pin if engine used? */ + if (wpabuf_len(data->tls_out) == 0) { + wpabuf_free(data->tls_out); + data->tls_out = NULL; + return -1; + } + } + + if (wpabuf_len(data->tls_out) == 0) { + /* + * TLS negotiation should now be complete since all other cases + * needing more data should have been caught above based on + * the TLS Message Length field. + */ + wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); + wpabuf_free(data->tls_out); + data->tls_out = NULL; + return 1; + } + + /* Send the pending message (in fragments, if needed). */ + return eap_tls_process_output(data, eap_type, peap_version, id, ret, + out_data); +} + + +/** + * eap_peer_tls_build_ack - Build a TLS ACK frame + * @id: EAP identifier for the response + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) + * @peap_version: Version number for EAP-PEAP/TTLS + * Returns: Pointer to the allocated ACK frame or %NULL on failure + */ +struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, + int peap_version) +{ + struct wpabuf *resp; + + resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id); + if (resp == NULL) + return NULL; + wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", + (int) eap_type, id, peap_version); + wpabuf_put_u8(resp, peap_version); /* Flags */ + return resp; +} + + +/** + * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * Returns: 0 on success, -1 on failure + */ +int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) +{ + eap_peer_tls_reset_input(data); + eap_peer_tls_reset_output(data); + return tls_connection_shutdown(data->ssl_ctx, data->conn); +} + + +/** + * eap_peer_tls_status - Get TLS status + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @buf: Buffer for status information + * @buflen: Maximum buffer length + * @verbose: Whether to include verbose status information + * Returns: Number of bytes written to buf. + */ +int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, + char *buf, size_t buflen, int verbose) +{ + char version[20], name[128]; + int len = 0, ret; + + if (tls_get_version(data->ssl_ctx, data->conn, version, + sizeof(version)) < 0) + version[0] = '\0'; + if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) < 0) + name[0] = '\0'; + + ret = os_snprintf(buf + len, buflen - len, + "eap_tls_version=%s\n" + "EAP TLS cipher=%s\n" + "tls_session_reused=%d\n", + version, name, + tls_connection_resumed(data->ssl_ctx, data->conn)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + return len; +} + + +/** + * eap_peer_tls_process_init - Initial validation/processing of EAP requests + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) + * @ret: Return values from EAP request validation and processing + * @reqData: EAP request to be processed (eapReqData) + * @len: Buffer for returning length of the remaining payload + * @flags: Buffer for returning TLS flags + * Returns: Pointer to payload after TLS flags and length or %NULL on failure + * + * This function validates the EAP header and processes the optional TLS + * Message Length field. If this is the first fragment of a TLS message, the + * TLS reassembly code is initialized to receive the indicated number of bytes. + * + * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this + * function as the first step in processing received messages. They will need + * to process the flags (apart from Message Length Included) that are returned + * through the flags pointer and the message payload that will be returned (and + * the length is returned through the len pointer). Return values (ret) are set + * for continuation of EAP method processing. The caller is responsible for + * setting these to indicate completion (either success or failure) based on + * the authentication result. + */ +const u8 * eap_peer_tls_process_init(struct eap_sm *sm, + struct eap_ssl_data *data, + EapType eap_type, + struct eap_method_ret *ret, + const struct wpabuf *reqData, + size_t *len, u8 *flags) +{ + const u8 *pos; + size_t left; + unsigned int tls_msg_len; + + /* Ignore errors before we do anything*/ + (void) tls_get_errors(sm->ssl_ctx); + + //// if (tls_get_errors(data->ssl_ctx)) { + //// wpa_printf(MSG_INFO, "SSL: TLS errors detected"); + //// ret->ignore = TRUE; + //// return NULL; + //// } + + if (eap_type == EAP_UNAUTH_TLS_TYPE) + pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, + EAP_VENDOR_TYPE_UNAUTH_TLS, reqData, + &left); + else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE) + pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW, + EAP_VENDOR_WFA_UNAUTH_TLS, reqData, + &left); + else + pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, + &left); + if (pos == NULL) { + ret->ignore = TRUE; + return NULL; + } + if (left == 0) { + wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags " + "octet included"); + if (!sm->workaround) { + ret->ignore = TRUE; + return NULL; + } + + wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags " + "indicates ACK frame"); + *flags = 0; + } else { + *flags = *pos++; + left--; + } + wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " + "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), + *flags); + if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { + if (left < 4) { + wpa_printf(MSG_INFO, "SSL: Short frame with TLS " + "length"); + ret->ignore = TRUE; + return NULL; + } + tls_msg_len = WPA_GET_BE32(pos); + wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", + tls_msg_len); + if (data->tls_in_left == 0) { + data->tls_in_total = tls_msg_len; + data->tls_in_left = tls_msg_len; + wpabuf_free(data->tls_in); + data->tls_in = NULL; + } + pos += 4; + left -= 4; + + if (left > tls_msg_len) { + wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " + "bytes) smaller than this fragment (%d " + "bytes)", (int) tls_msg_len, (int) left); + ret->ignore = TRUE; + return NULL; + } + } + + ret->ignore = FALSE; + ret->methodState = METHOD_MAY_CONT; + ret->decision = DECISION_FAIL; + ret->allowNotifications = TRUE; + + *len = left; + return pos; +} + + +/** + * eap_peer_tls_reset_input - Reset input buffers + * @data: Data for TLS processing + * + * This function frees any allocated memory for input buffers and resets input + * state. + */ +void eap_peer_tls_reset_input(struct eap_ssl_data *data) +{ + data->tls_in_left = data->tls_in_total = 0; + wpabuf_free(data->tls_in); + data->tls_in = NULL; +} + + +/** + * eap_peer_tls_reset_output - Reset output buffers + * @data: Data for TLS processing + * + * This function frees any allocated memory for output buffers and resets + * output state. + */ +void eap_peer_tls_reset_output(struct eap_ssl_data *data) +{ + data->tls_out_pos = 0; + wpabuf_free(data->tls_out); + data->tls_out = NULL; +} + + +/** + * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @in_data: Message received from the server + * @in_decrypted: Buffer for returning a pointer to the decrypted message + * Returns: 0 on success, 1 if more input data is needed, or -1 on failure + */ +int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, + const struct wpabuf *in_data, + struct wpabuf **in_decrypted) +{ + const struct wpabuf *msg; + int need_more_input; + + msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); + if (msg == NULL) + return need_more_input ? 1 : -1; + + *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg); + eap_peer_tls_reset_input(data); + if (*in_decrypted == NULL) { + wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); + return -1; + } + return 0; +} + + +/** + * eap_peer_tls_encrypt - Encrypt phase 2 TLS message + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) + * @peap_version: Version number for EAP-PEAP/TTLS + * @id: EAP identifier for the response + * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments + * @out_data: Buffer for returning a pointer to the encrypted response message + * Returns: 0 on success, -1 on failure + */ +int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, u8 id, + const struct wpabuf *in_data, + struct wpabuf **out_data) +{ + if (in_data) { + eap_peer_tls_reset_output(data); + data->tls_out = tls_connection_encrypt(data->ssl_ctx, + data->conn, in_data); + if (data->tls_out == NULL) { + wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " + "data (in_len=%lu)", + (unsigned long) wpabuf_len(in_data)); + eap_peer_tls_reset_output(data); + return -1; + } + } + + return eap_tls_process_output(data, eap_type, peap_version, id, 0, + out_data); +} + + +/** + * eap_peer_select_phase2_methods - Select phase 2 EAP method + * @config: Pointer to the network configuration + * @prefix: 'phase2' configuration prefix, e.g., "auth=" + * @types: Buffer for returning allocated list of allowed EAP methods + * @num_types: Buffer for returning number of allocated EAP methods + * Returns: 0 on success, -1 on failure + * + * This function is used to parse EAP method list and select allowed methods + * for Phase2 authentication. + */ +int eap_peer_select_phase2_methods(struct eap_peer_config *config, + const char *prefix, + struct eap_method_type **types, + size_t *num_types) +{ + char *start, *pos, *buf; + struct eap_method_type *methods = NULL, *_methods; + u32 method; + size_t num_methods = 0, prefix_len; + + if (config == NULL || config->phase2 == NULL) + goto get_defaults; + + start = buf = os_strdup(config->phase2); + if (buf == NULL) + return -1; + + prefix_len = os_strlen(prefix); + + while (start && *start != '\0') { + int vendor; + pos = os_strstr(start, prefix); + if (pos == NULL) + break; + if (start != pos && *(pos - 1) != ' ') { + start = pos + prefix_len; + continue; + } + + start = pos + prefix_len; + pos = os_strchr(start, ' '); + if (pos) + *pos++ = '\0'; + method = eap_get_phase2_type(start, &vendor); + if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { + wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " + "method '%s'", start); + } else { + num_methods++; + _methods = os_realloc_array(methods, num_methods, + sizeof(*methods)); + if (_methods == NULL) { + os_free(methods); + os_free(buf); + return -1; + } + methods = _methods; + methods[num_methods - 1].vendor = vendor; + methods[num_methods - 1].method = method; + } + + start = pos; + } + + os_free(buf); + +get_defaults: + if (methods == NULL) + methods = eap_get_phase2_types(config, &num_methods); + + if (methods == NULL) { + wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); + return -1; + } + wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", + (u8 *) methods, + num_methods * sizeof(struct eap_method_type)); + + *types = methods; + *num_types = num_methods; + + return 0; +} + + +/** + * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 + * @types: Buffer for returning allocated list of allowed EAP methods + * @num_types: Buffer for returning number of allocated EAP methods + * @hdr: EAP-Request header (and the following EAP type octet) + * @resp: Buffer for returning the EAP-Nak message + * Returns: 0 on success, -1 on failure + */ +int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, + struct eap_hdr *hdr, struct wpabuf **resp) +{ + u8 *pos = (u8 *) (hdr + 1); + size_t i; + + /* TODO: add support for expanded Nak */ + wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); + wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", + (u8 *) types, num_types * sizeof(struct eap_method_type)); + *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, + EAP_CODE_RESPONSE, hdr->identifier); + if (*resp == NULL) + return -1; + + for (i = 0; i < num_types; i++) { + if (types[i].vendor == EAP_VENDOR_IETF && + types[i].method < 256) + wpabuf_put_u8(*resp, types[i].method); + } + + eap_update_len(*resp); + + return 0; +} diff --git a/libeap/src/eap_peer/eap_tls_common.h b/libeap/src/eap_peer/eap_tls_common.h new file mode 100644 index 0000000..3f7f003 --- /dev/null +++ b/libeap/src/eap_peer/eap_tls_common.h @@ -0,0 +1,140 @@ +/* + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions + * Copyright (c) 2004-2009, 2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_TLS_COMMON_H +#define EAP_TLS_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * struct eap_ssl_data - TLS data for EAP methods + */ +struct eap_ssl_data { + /** + * conn - TLS connection context data from tls_connection_init() + */ + struct tls_connection *conn; + + /** + * tls_out - TLS message to be sent out in fragments + */ + struct wpabuf *tls_out; + + /** + * tls_out_pos - The current position in the outgoing TLS message + */ + size_t tls_out_pos; + + /** + * tls_out_limit - Maximum fragment size for outgoing TLS messages + */ + size_t tls_out_limit; + + /** + * tls_in - Received TLS message buffer for re-assembly + */ + struct wpabuf *tls_in; + + /** + * tls_in_left - Number of remaining bytes in the incoming TLS message + */ + size_t tls_in_left; + + /** + * tls_in_total - Total number of bytes in the incoming TLS message + */ + size_t tls_in_total; + + /** + * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) + */ + int phase2; + + /** + * include_tls_length - Whether the TLS length field is included even + * if the TLS data is not fragmented + */ + int include_tls_length; + + /** + * eap - EAP state machine allocated with eap_peer_sm_init() + */ + struct eap_sm *eap; + + /** + * ssl_ctx - TLS library context to use for the connection + */ + void *ssl_ctx; + + /** + * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) + */ + u8 eap_type; +}; + + +/* EAP TLS Flags */ +#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 +#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 +#define EAP_TLS_FLAGS_START 0x20 +#define EAP_TLS_VERSION_MASK 0x07 + + /* could be up to 128 bytes, but only the first 64 bytes are used */ +#define EAP_TLS_KEY_LEN 64 + +/* dummy type used as a flag for UNAUTH-TLS */ +#define EAP_UNAUTH_TLS_TYPE 255 +#define EAP_WFA_UNAUTH_TLS_TYPE 254 + + +int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, + struct eap_peer_config *config, u8 eap_type); +void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); +u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, + const char *label, size_t len); +u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, + struct eap_ssl_data *data, u8 eap_type, + size_t *len); +int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, + u8 id, const struct wpabuf *in_data, + struct wpabuf **out_data); +struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, + int peap_version); +int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data); +int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, + char *buf, size_t buflen, int verbose); +const u8 * eap_peer_tls_process_init(struct eap_sm *sm, + struct eap_ssl_data *data, + EapType eap_type, + struct eap_method_ret *ret, + const struct wpabuf *reqData, + size_t *len, u8 *flags); +void eap_peer_tls_reset_input(struct eap_ssl_data *data); +void eap_peer_tls_reset_output(struct eap_ssl_data *data); +int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, + const struct wpabuf *in_data, + struct wpabuf **in_decrypted); +int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, u8 id, + const struct wpabuf *in_data, + struct wpabuf **out_data); +int eap_peer_select_phase2_methods(struct eap_peer_config *config, + const char *prefix, + struct eap_method_type **types, + size_t *num_types); +int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, + struct eap_hdr *hdr, struct wpabuf **resp); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_TLS_COMMON_H */ diff --git a/src/eap_peer/eap_tnc.c b/libeap/src/eap_peer/eap_tnc.c similarity index 100% rename from src/eap_peer/eap_tnc.c rename to libeap/src/eap_peer/eap_tnc.c diff --git a/libeap/src/eap_peer/eap_ttls.c b/libeap/src/eap_peer/eap_ttls.c new file mode 100644 index 0000000..c174fe5 --- /dev/null +++ b/libeap/src/eap_peer/eap_ttls.c @@ -0,0 +1,1956 @@ +/* + * EAP peer method: EAP-TTLS (RFC 5281) + * Copyright (c) 2004-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "radius/radius.h" +#include "crypto/ms_funcs.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" +#include "eap_common/chap.h" +#include "eap_common/eap_ttls.h" +#include "mschapv2.h" +#include "eap_i.h" +#include "eap_tls_common.h" +#include "eap_config.h" + + +#define EAP_TTLS_VERSION 0 + + +static void eap_ttls_deinit(struct eap_sm *sm, void *priv); + + +struct eap_ttls_data { + struct eap_ssl_data ssl; + + int ttls_version; + + const struct eap_method *phase2_method; + void *phase2_priv; + int phase2_success; + int phase2_start; + + enum phase2_types { + EAP_TTLS_PHASE2_EAP, + EAP_TTLS_PHASE2_MSCHAPV2, + EAP_TTLS_PHASE2_MSCHAP, + EAP_TTLS_PHASE2_PAP, + EAP_TTLS_PHASE2_CHAP + } phase2_type; + struct eap_method_type phase2_eap_type; + struct eap_method_type *phase2_eap_types; + size_t num_phase2_eap_types; + + u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; + int auth_response_valid; + u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ + u8 ident; + int resuming; /* starting a resumed session */ + int reauth; /* reauthentication */ + u8 *key_data; + u8 *session_id; + size_t id_len; + + struct wpabuf *pending_phase2_req; + int chbind_req_sent; /* channel binding request was sent */ + int done_butfor_cb; /*we turned METHOD_DONE into METHOD_MAY_CONT to receive cb*/ + EapDecision cbDecision; +#ifdef EAP_TNC + int ready_for_tnc; + int tnc_started; +#endif /* EAP_TNC */ +}; + + +/* draft-ietf-emu-chbind-13 section 5.3 */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct chbind_hdr { + u16 len; + u8 nsid; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + + +static void * eap_ttls_init(struct eap_sm *sm) +{ + struct eap_ttls_data *data; + struct eap_peer_config *config = eap_get_config(sm); + char *selected; + + data = os_zalloc(sizeof(*data)); + if (data == NULL) + return NULL; + data->ttls_version = EAP_TTLS_VERSION; + selected = "EAP"; + data->phase2_type = EAP_TTLS_PHASE2_EAP; + + if (config && config->phase2) { + if (os_strstr(config->phase2, "autheap=")) { + selected = "EAP"; + data->phase2_type = EAP_TTLS_PHASE2_EAP; + } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { + selected = "MSCHAPV2"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; + } else if (os_strstr(config->phase2, "auth=MSCHAP")) { + selected = "MSCHAP"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; + } else if (os_strstr(config->phase2, "auth=PAP")) { + selected = "PAP"; + data->phase2_type = EAP_TTLS_PHASE2_PAP; + } else if (os_strstr(config->phase2, "auth=CHAP")) { + selected = "CHAP"; + data->phase2_type = EAP_TTLS_PHASE2_CHAP; + } + } + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); + + if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { + if (eap_peer_select_phase2_methods(config, "autheap=", + &data->phase2_eap_types, + &data->num_phase2_eap_types) + < 0) { + eap_ttls_deinit(sm, data); + return NULL; + } + + data->phase2_eap_type.vendor = EAP_VENDOR_IETF; + data->phase2_eap_type.method = EAP_TYPE_NONE; + } + + if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { + wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); + eap_ttls_deinit(sm, data); + return NULL; + } + + return data; +} + + +static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, + struct eap_ttls_data *data) +{ + if (data->phase2_priv && data->phase2_method) { + data->phase2_method->deinit(sm, data->phase2_priv); + data->phase2_method = NULL; + data->phase2_priv = NULL; + } +} + + +static void eap_ttls_free_key(struct eap_ttls_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); + data->key_data = NULL; + } +} + + +static void eap_ttls_deinit(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + if (data == NULL) + return; + eap_ttls_phase2_eap_deinit(sm, data); + os_free(data->phase2_eap_types); + eap_peer_tls_ssl_deinit(sm, &data->ssl); + eap_ttls_free_key(data); + os_free(data->session_id); + wpabuf_free(data->pending_phase2_req); + os_free(data); +} + + +static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, + int mandatory, size_t len) +{ + struct ttls_avp_vendor *avp; + u8 flags; + size_t hdrlen; + + avp = (struct ttls_avp_vendor *) avphdr; + flags = mandatory ? AVP_FLAGS_MANDATORY : 0; + if (vendor_id) { + flags |= AVP_FLAGS_VENDOR; + hdrlen = sizeof(*avp); + avp->vendor_id = host_to_be32(vendor_id); + } else { + hdrlen = sizeof(struct ttls_avp); + } + + avp->avp_code = host_to_be32(avp_code); + avp->avp_length = host_to_be32(((u32) flags << 24) | + (u32) (hdrlen + len)); + + return avphdr + hdrlen; +} + + +static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, + u32 vendor_id, int mandatory, + const u8 *data, size_t len) +{ + u8 *pos; + pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); + os_memcpy(pos, data, len); + pos += len; + AVP_PAD(start, pos); + return pos; +} + + +static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, + int mandatory) +{ + struct wpabuf *msg; + u8 *avp, *pos; + + msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); + if (msg == NULL) { + wpabuf_free(*resp); + *resp = NULL; + return -1; + } + + avp = wpabuf_mhead(msg); + pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); + os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); + pos += wpabuf_len(*resp); + AVP_PAD(avp, pos); + wpabuf_free(*resp); + wpabuf_put(msg, pos - avp); + *resp = msg; + return 0; +} + +/* chop up resp into multiple vsa's as necessary*/ +static int eap_ttls_avp_radius_vsa_encapsulate(struct wpabuf **resp, u32 vendor, + u8 attr, int mandatory) +{ + struct wpabuf *msg; + u8 *avp, *pos, *src, *final; + size_t size = wpabuf_len(*resp); + size_t num_msgs = 1 + (size / 248); + size_t msg_wrapper_size = sizeof(struct ttls_avp_vendor) + 6; + size_t allocated_total = num_msgs * (4 + msg_wrapper_size) + size; + + msg = wpabuf_alloc(allocated_total); + if (msg == NULL) { + wpabuf_free(*resp); + *resp = NULL; + return -1; + } + src = wpabuf_mhead(*resp); + avp = wpabuf_mhead(msg); + while (size > 0) { + int avp_size = size > 248 ? 248 : size; + size -= avp_size; + pos = eap_ttls_avp_hdr(avp, RADIUS_ATTR_VENDOR_SPECIFIC, 0, mandatory, + avp_size+6); + wpabuf_put(msg, pos-avp); + wpabuf_put_be32(msg, vendor); + wpabuf_put_u8(msg, (u8) attr); + wpabuf_put_u8(msg, (u8) avp_size+2); + wpabuf_put_data(msg, src, avp_size); + src += avp_size; + pos = wpabuf_mhead_u8(msg) + wpabuf_len(msg); + final = pos; /*keep pos so we know how much padding is added*/ + AVP_PAD(avp, final); /*final modified*/ + if (final > pos) + wpabuf_put(msg, final-pos); + avp = final; + } + /* check avp-wpabuf_mhead(msg) < allocated_total */ + wpabuf_free(*resp); + *resp = msg; + return 0; +} + +static int eap_ttls_v0_derive_key(struct eap_sm *sm, + struct eap_ttls_data *data) +{ + eap_ttls_free_key(data); + data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, + "ttls keying material", + EAP_TLS_KEY_LEN + + EAP_EMSK_LEN); + if (!data->key_data) { + wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", + data->key_data, EAP_TLS_KEY_LEN); + wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK", + data->key_data + EAP_TLS_KEY_LEN, + EAP_EMSK_LEN); + + os_free(data->session_id); + data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, + EAP_TYPE_TTLS, + &data->id_len); + if (data->session_id) { + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", + data->session_id, data->id_len); + } else { + wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); + } + + return 0; +} + + +#ifndef CONFIG_FIPS +static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, + struct eap_ttls_data *data, size_t len) +{ + return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); +} +#endif /* CONFIG_FIPS */ + + +static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, + u8 method) +{ + size_t i; + for (i = 0; i < data->num_phase2_eap_types; i++) { + if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || + data->phase2_eap_types[i].method != method) + continue; + + data->phase2_eap_type.vendor = + data->phase2_eap_types[i].vendor; + data->phase2_eap_type.method = + data->phase2_eap_types[i].method; + wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " + "Phase 2 EAP vendor %d method %d", + data->phase2_eap_type.vendor, + data->phase2_eap_type.method); + break; + } +} + + +static int eap_ttls_phase2_eap_process(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct eap_hdr *hdr, size_t len, + struct wpabuf **resp) +{ + struct wpabuf msg; + struct eap_method_ret iret; + + os_memset(&iret, 0, sizeof(iret)); + wpabuf_set(&msg, hdr, len); + *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, + &msg); + if ((iret.methodState == METHOD_DONE || + iret.methodState == METHOD_MAY_CONT) && + (iret.decision == DECISION_UNCOND_SUCC || + iret.decision == DECISION_COND_SUCC || + iret.decision == DECISION_FAIL)) { + ret->methodState = iret.methodState; + ret->decision = iret.decision; + } + + return 0; +} + + +static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct eap_hdr *hdr, size_t len, + u8 method, struct wpabuf **resp) +{ +#ifdef EAP_TNC + if (data->tnc_started && data->phase2_method && + data->phase2_priv && method == EAP_TYPE_TNC && + data->phase2_eap_type.method == EAP_TYPE_TNC) + return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, + resp); + + if (data->ready_for_tnc && !data->tnc_started && + method == EAP_TYPE_TNC) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " + "EAP method"); + data->tnc_started = 1; + } + + if (data->tnc_started) { + if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || + data->phase2_eap_type.method == EAP_TYPE_TNC) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " + "type %d for TNC", method); + return -1; + } + + data->phase2_eap_type.vendor = EAP_VENDOR_IETF; + data->phase2_eap_type.method = method; + wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " + "Phase 2 EAP vendor %d method %d (TNC)", + data->phase2_eap_type.vendor, + data->phase2_eap_type.method); + + if (data->phase2_type == EAP_TTLS_PHASE2_EAP) + eap_ttls_phase2_eap_deinit(sm, data); + } +#endif /* EAP_TNC */ + + if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && + data->phase2_eap_type.method == EAP_TYPE_NONE) + eap_ttls_phase2_select_eap_method(data, method); + + if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) + { + if (eap_peer_tls_phase2_nak(data->phase2_eap_types, + data->num_phase2_eap_types, + hdr, resp)) + return -1; + return 0; + } + + if (data->phase2_priv == NULL) { + data->phase2_method = eap_peer_get_eap_method( + EAP_VENDOR_IETF, method); + if (data->phase2_method) { + sm->init_phase2 = 1; + data->phase2_priv = data->phase2_method->init(sm); + sm->init_phase2 = 0; + } + } + if (data->phase2_priv == NULL || data->phase2_method == NULL) { + wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " + "Phase 2 EAP method %d", method); + return -1; + } + + return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); +} + + +static int eap_ttls_phase2_request_eap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct eap_hdr *hdr, + struct wpabuf **resp) +{ + size_t len = be_to_host16(hdr->length); + u8 *pos; + struct eap_peer_config *config = eap_get_config(sm); + + if (len <= sizeof(struct eap_hdr)) { + wpa_printf(MSG_INFO, "EAP-TTLS: too short " + "Phase 2 request (len=%lu)", (unsigned long) len); + return -1; + } + pos = (u8 *) (hdr + 1); + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); + switch (*pos) { + case EAP_TYPE_IDENTITY: + *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); + break; + default: + if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, + *pos, resp) < 0) + return -1; + break; + } + + if (*resp == NULL && + (config->pending_req_identity || config->pending_req_password || + config->pending_req_otp)) { + return 0; + } + + if (*resp == NULL) + return -1; + + wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", + *resp); + return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); +} + + +static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build"); + return -1; +#else /* CONFIG_FIPS */ +#ifdef EAP_MSCHAPv2 + struct wpabuf *msg; + u8 *buf, *pos, *challenge, *peer_challenge; + const u8 *identity, *password; + size_t identity_len, password_len; + int pwhash; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); + + identity = eap_get_config_identity(sm, &identity_len); + password = eap_get_config_password2(sm, &password_len, &pwhash); + if (identity == NULL || password == NULL) + return -1; + + msg = wpabuf_alloc(identity_len + 1000); + if (msg == NULL) { + wpa_printf(MSG_ERROR, + "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); + return -1; + } + pos = buf = wpabuf_mhead(msg); + + /* User-Name */ + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, + identity, identity_len); + + /* MS-CHAP-Challenge */ + challenge = eap_ttls_implicit_challenge( + sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); + if (challenge == NULL) { + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " + "implicit challenge"); + return -1; + } + + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, + RADIUS_VENDOR_ID_MICROSOFT, 1, + challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); + + /* MS-CHAP2-Response */ + pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, + RADIUS_VENDOR_ID_MICROSOFT, 1, + EAP_TTLS_MSCHAPV2_RESPONSE_LEN); + data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; + *pos++ = data->ident; + *pos++ = 0; /* Flags */ + if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { + os_free(challenge); + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " + "random data for peer challenge"); + return -1; + } + peer_challenge = pos; + pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; + os_memset(pos, 0, 8); /* Reserved, must be zero */ + pos += 8; + if (mschapv2_derive_response(identity, identity_len, password, + password_len, pwhash, challenge, + peer_challenge, pos, data->auth_response, + data->master_key)) { + os_free(challenge); + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " + "response"); + return -1; + } + data->auth_response_valid = 1; + + pos += 24; + os_free(challenge); + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + + return 0; +#else /* EAP_MSCHAPv2 */ + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); + return -1; +#endif /* EAP_MSCHAPv2 */ +#endif /* CONFIG_FIPS */ +} + + +static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build"); + return -1; +#else /* CONFIG_FIPS */ + struct wpabuf *msg; + u8 *buf, *pos, *challenge; + const u8 *identity, *password; + size_t identity_len, password_len; + int pwhash; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); + + identity = eap_get_config_identity(sm, &identity_len); + password = eap_get_config_password2(sm, &password_len, &pwhash); + if (identity == NULL || password == NULL) + return -1; + + msg = wpabuf_alloc(identity_len + 1000); + if (msg == NULL) { + wpa_printf(MSG_ERROR, + "EAP-TTLS/MSCHAP: Failed to allocate memory"); + return -1; + } + pos = buf = wpabuf_mhead(msg); + + /* User-Name */ + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, + identity, identity_len); + + /* MS-CHAP-Challenge */ + challenge = eap_ttls_implicit_challenge( + sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); + if (challenge == NULL) { + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " + "implicit challenge"); + return -1; + } + + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, + RADIUS_VENDOR_ID_MICROSOFT, 1, + challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); + + /* MS-CHAP-Response */ + pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, + RADIUS_VENDOR_ID_MICROSOFT, 1, + EAP_TTLS_MSCHAP_RESPONSE_LEN); + data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; + *pos++ = data->ident; + *pos++ = 1; /* Flags: Use NT style passwords */ + os_memset(pos, 0, 24); /* LM-Response */ + pos += 24; + if (pwhash) { + challenge_response(challenge, password, pos); /* NT-Response */ + wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", + password, 16); + } else { + nt_challenge_response(challenge, password, password_len, + pos); /* NT-Response */ + wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", + password, password_len); + } + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", + challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); + pos += 24; + os_free(challenge); + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + + /* EAP-TTLS/MSCHAP does not provide tunneled success + * notification, so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; + + return 0; +#endif /* CONFIG_FIPS */ +} + + +static int eap_ttls_phase2_request_pap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ + struct wpabuf *msg; + u8 *buf, *pos; + size_t pad; + const u8 *identity, *password; + size_t identity_len, password_len; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); + + identity = eap_get_config_identity(sm, &identity_len); + password = eap_get_config_password(sm, &password_len); + if (identity == NULL || password == NULL) + return -1; + + msg = wpabuf_alloc(identity_len + password_len + 100); + if (msg == NULL) { + wpa_printf(MSG_ERROR, + "EAP-TTLS/PAP: Failed to allocate memory"); + return -1; + } + pos = buf = wpabuf_mhead(msg); + + /* User-Name */ + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, + identity, identity_len); + + /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts + * the data, so no separate encryption is used in the AVP itself. + * However, the password is padded to obfuscate its length. */ + pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; + pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, + password_len + pad); + os_memcpy(pos, password, password_len); + pos += password_len; + os_memset(pos, 0, pad); + pos += pad; + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + + /* EAP-TTLS/PAP does not provide tunneled success notification, + * so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; + + return 0; +} + + +static int eap_ttls_phase2_request_chap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build"); + return -1; +#else /* CONFIG_FIPS */ + struct wpabuf *msg; + u8 *buf, *pos, *challenge; + const u8 *identity, *password; + size_t identity_len, password_len; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); + + identity = eap_get_config_identity(sm, &identity_len); + password = eap_get_config_password(sm, &password_len); + if (identity == NULL || password == NULL) + return -1; + + msg = wpabuf_alloc(identity_len + 1000); + if (msg == NULL) { + wpa_printf(MSG_ERROR, + "EAP-TTLS/CHAP: Failed to allocate memory"); + return -1; + } + pos = buf = wpabuf_mhead(msg); + + /* User-Name */ + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, + identity, identity_len); + + /* CHAP-Challenge */ + challenge = eap_ttls_implicit_challenge( + sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); + if (challenge == NULL) { + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " + "implicit challenge"); + return -1; + } + + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, + challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); + + /* CHAP-Password */ + pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, + 1 + EAP_TTLS_CHAP_PASSWORD_LEN); + data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; + *pos++ = data->ident; + + /* MD5(Ident + Password + Challenge) */ + chap_md5(data->ident, password, password_len, challenge, + EAP_TTLS_CHAP_CHALLENGE_LEN, pos); + + wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", + identity, identity_len); + wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", + password, password_len); + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", + challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", + pos, EAP_TTLS_CHAP_PASSWORD_LEN); + pos += EAP_TTLS_CHAP_PASSWORD_LEN; + os_free(challenge); + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + + /* EAP-TTLS/CHAP does not provide tunneled success + * notification, so assume that Phase2 succeeds. */ + ret->methodState = METHOD_DONE; + ret->decision = DECISION_COND_SUCC; + + return 0; +#endif /* CONFIG_FIPS */ +} + + +static int eap_ttls_phase2_request(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct eap_hdr *hdr, + struct wpabuf **resp) +{ + int res = 0; + size_t len; + enum phase2_types phase2_type = data->phase2_type; + +#ifdef EAP_TNC + if (data->tnc_started) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); + phase2_type = EAP_TTLS_PHASE2_EAP; + } +#endif /* EAP_TNC */ + + if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || + phase2_type == EAP_TTLS_PHASE2_MSCHAP || + phase2_type == EAP_TTLS_PHASE2_PAP || + phase2_type == EAP_TTLS_PHASE2_CHAP) { + if (eap_get_config_identity(sm, &len) == NULL) { + wpa_printf(MSG_INFO, + "EAP-TTLS: Identity not configured"); + eap_sm_request_identity(sm); + if (eap_get_config_password(sm, &len) == NULL) + eap_sm_request_password(sm); + return 0; + } + + if (eap_get_config_password(sm, &len) == NULL) { + wpa_printf(MSG_INFO, + "EAP-TTLS: Password not configured"); + eap_sm_request_password(sm); + return 0; + } + } + + switch (phase2_type) { + case EAP_TTLS_PHASE2_EAP: + res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); + break; + case EAP_TTLS_PHASE2_MSCHAPV2: + res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); + break; + case EAP_TTLS_PHASE2_MSCHAP: + res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); + break; + case EAP_TTLS_PHASE2_PAP: + res = eap_ttls_phase2_request_pap(sm, data, ret, resp); + break; + case EAP_TTLS_PHASE2_CHAP: + res = eap_ttls_phase2_request_chap(sm, data, ret, resp); + break; + default: + wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); + res = -1; + break; + } + + if (res < 0) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + } + + return res; +} + + +struct ttls_parse_avp { + u8 *mschapv2; + u8 *eapdata; + size_t eap_len; + u8 *chbind_data; + size_t chbind_len; + int mschapv2_error; +}; + + +static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, + struct ttls_parse_avp *parse) +{ + wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); + if (parse->eapdata == NULL) { + parse->eapdata = os_malloc(dlen); + if (parse->eapdata == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " + "memory for Phase 2 EAP data"); + return -1; + } + os_memcpy(parse->eapdata, dpos, dlen); + parse->eap_len = dlen; + } else { + u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); + if (neweap == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " + "memory for Phase 2 EAP data"); + return -1; + } + os_memcpy(neweap + parse->eap_len, dpos, dlen); + parse->eapdata = neweap; + parse->eap_len += dlen; + } + + return 0; +} + + +static int eap_ttls_parse_attr_chbind(const u8 *dpos, size_t dlen, + struct ttls_parse_avp *parse) +{ + wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - Channel Binding Message"); + + if (parse->chbind_data == NULL) { + parse->chbind_data = os_malloc(dlen); + if (parse->chbind_data == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " + "memory for Phase 2 channel binding data"); + return -1; + } + os_memcpy(parse->chbind_data, dpos, dlen); + parse->chbind_len = dlen; + } else { + /* TODO: can this really happen? maybe just make this an error? */ + u8 *newchbind = os_realloc(parse->chbind_data, + parse->chbind_len + dlen); + if (newchbind == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " + "memory for Phase 2 channel binding data"); + return -1; + } + os_memcpy(newchbind + parse->chbind_len, dpos, dlen); + parse->chbind_data = newchbind; + parse->chbind_len += dlen; + } + + return 0; +} + + +static int eap_ttls_parse_avp(u8 *pos, size_t left, + struct ttls_parse_avp *parse) +{ + struct ttls_avp *avp; + u32 avp_code, avp_length, vendor_id = 0; + u8 avp_flags, *dpos; + size_t dlen; + + avp = (struct ttls_avp *) pos; + avp_code = be_to_host32(avp->avp_code); + avp_length = be_to_host32(avp->avp_length); + avp_flags = (avp_length >> 24) & 0xff; + avp_length &= 0xffffff; + wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " + "length=%d", (int) avp_code, avp_flags, + (int) avp_length); + + if (avp_length > left) { + wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " + "(len=%d, left=%lu) - dropped", + (int) avp_length, (unsigned long) left); + return -1; + } + + if (avp_length < sizeof(*avp)) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", + avp_length); + return -1; + } + + dpos = (u8 *) (avp + 1); + dlen = avp_length - sizeof(*avp); + if (avp_flags & AVP_FLAGS_VENDOR) { + if (dlen < 4) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " + "underflow"); + return -1; + } + vendor_id = WPA_GET_BE32(dpos); + wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", + (int) vendor_id); + dpos += 4; + dlen -= 4; + } + + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); + + if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { + if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) + return -1; + } else if (vendor_id == RADIUS_VENDOR_ID_UKERNA && + avp_code == RADIUS_ATTR_UKERNA_CHBIND) { + /* message containing channel binding data */ + if (eap_ttls_parse_attr_chbind(dpos, dlen, parse) < 0) + return -1; + } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { + /* This is an optional message that can be displayed to + * the user. */ + wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", + dpos, dlen); + } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && + avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { + wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", + dpos, dlen); + if (dlen != 43) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " + "MS-CHAP2-Success length " + "(len=%lu, expected 43)", + (unsigned long) dlen); + return -1; + } + parse->mschapv2 = dpos; + } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && + avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { + wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", + dpos, dlen); + parse->mschapv2_error = 1; + } else if (avp_flags & AVP_FLAGS_MANDATORY) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " + "code %d vendor_id %d - dropped", + (int) avp_code, (int) vendor_id); + return -1; + } else { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " + "code %d vendor_id %d", + (int) avp_code, (int) vendor_id); + } + + return avp_length; +} + + +static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, + struct ttls_parse_avp *parse) +{ + u8 *pos; + size_t left, pad; + int avp_length; + + pos = wpabuf_mhead(in_decrypted); + left = wpabuf_len(in_decrypted); + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); + if (left < sizeof(struct ttls_avp)) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" + " len=%lu expected %lu or more - dropped", + (unsigned long) left, + (unsigned long) sizeof(struct ttls_avp)); + return -1; + } + + /* Parse AVPs */ + os_memset(parse, 0, sizeof(*parse)); + + while (left > 0) { + avp_length = eap_ttls_parse_avp(pos, left, parse); + if (avp_length < 0) + return -1; + + pad = (4 - (avp_length & 3)) & 3; + pos += avp_length + pad; + if (left < avp_length + pad) + left = 0; + else + left -= avp_length + pad; + } + + return 0; +} + + +static u8 * eap_ttls_fake_identity_request(void) +{ + struct eap_hdr *hdr; + u8 *buf; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " + "Phase 2 - use fake EAP-Request Identity"); + buf = os_malloc(sizeof(*hdr) + 1); + if (buf == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " + "memory for fake EAP-Identity Request"); + return NULL; + } + + hdr = (struct eap_hdr *) buf; + hdr->code = EAP_CODE_REQUEST; + hdr->identifier = 0; + hdr->length = host_to_be16(sizeof(*hdr) + 1); + buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; + + return buf; +} + + +static int eap_ttls_encrypt_response(struct eap_sm *sm, + struct eap_ttls_data *data, + struct wpabuf *resp, u8 identifier, + struct wpabuf **out_data) +{ + if (resp == NULL) + return 0; + + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", + resp); + if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, + data->ttls_version, identifier, + resp, out_data)) { + wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " + "frame"); + wpabuf_free(resp); + return -1; + } + wpabuf_free(resp); + + return 0; +} + +static int eap_ttls_add_chbind_request(struct eap_sm *sm, + struct eap_ttls_data *data, + struct wpabuf **resp) +{ + struct wpabuf *chbind_req, *res; + int length = 1, i; + struct eap_peer_config *config = eap_get_config(sm); + + if (!config->chbind_config || config->chbind_config_len <= 0) + return -1; + + for (i=0; ichbind_config_len; i++) { + length += 3 + config->chbind_config[i].req_data_len; + } + + chbind_req = wpabuf_alloc(length); + if (!chbind_req) + return -1; + + wpabuf_put_u8(chbind_req, CHBIND_CODE_REQUEST); + for (i=0; ichbind_config_len; i++) { + struct eap_peer_chbind_config *chbind_config = + &config->chbind_config[i]; + wpabuf_put_be16(chbind_req, chbind_config->req_data_len); + wpabuf_put_u8(chbind_req, chbind_config->nsid); + wpabuf_put_data(chbind_req, chbind_config->req_data, + chbind_config->req_data_len); + } + if (eap_ttls_avp_radius_vsa_encapsulate(&chbind_req, + RADIUS_VENDOR_ID_UKERNA, + RADIUS_ATTR_UKERNA_CHBIND, 0) < 0) + return -1; + + /* bleh. This will free *resp regardless of whether combined buffer + alloc succeeds, which is not consistent with the other error + condition behavior in this function */ + *resp = wpabuf_concat(chbind_req, *resp); + + return (*resp) ? 0 : -1; +} + + +static int eap_ttls_process_chbind(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse, + struct wpabuf **resp) +{ + size_t pos=0; + u8 code; + u16 len; + struct chbind_hdr *hdr; + struct eap_peer_config *config = eap_get_config(sm); + int i, found; + + + if (parse->chbind_data == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: No channel binding message " + "in the packet - dropped"); + return -1; + } + if (parse->chbind_len < 1 ) { + wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response " + "frame (len=%lu, expected %lu or more) - dropped", + (unsigned long) parse->chbind_len, + (unsigned long) 1); + return -1; + } + code = parse->chbind_data[pos++]; + for (i=0; ichbind_config_len; i++) { + struct eap_peer_chbind_config *chbind_config = + &config->chbind_config[i]; + pos = 1; + found = 0; + while (pos+sizeof(*hdr) < parse->chbind_len) { + hdr = (struct chbind_hdr *)(&parse->chbind_data[pos]); + pos += sizeof(*hdr); + len = be_to_host16(hdr->len); + if (pos + len <= parse->chbind_len) { + if (chbind_config->nsid == hdr->nsid) + chbind_config->response_cb( + chbind_config->ctx, + code, hdr->nsid, + &parse->chbind_data[pos], len); + found = 1; + } + pos += len; + } + if (pos != parse->chbind_len) { + wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response " + "frame (parsed len=%lu, expected %lu) - dropped", + (unsigned long) pos, + (unsigned long) parse->chbind_len); + return -1; + } + if (!found) { + chbind_config->response_cb( + chbind_config->ctx, + code, chbind_config->nsid, + NULL, 0); + } + + } + return 0; +} + +static int eap_ttls_process_phase2_eap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse, + struct wpabuf **resp) +{ + struct eap_hdr *hdr; + size_t len; + + if (parse->eapdata == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " + "packet - dropped"); + return -1; + } + + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", + parse->eapdata, parse->eap_len); + hdr = (struct eap_hdr *) parse->eapdata; + + if (parse->eap_len < sizeof(*hdr)) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " + "frame (len=%lu, expected %lu or more) - dropped", + (unsigned long) parse->eap_len, + (unsigned long) sizeof(*hdr)); + return -1; + } + len = be_to_host16(hdr->length); + if (len > parse->eap_len) { + wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " + "EAP frame (EAP hdr len=%lu, EAP data len in " + "AVP=%lu)", + (unsigned long) len, + (unsigned long) parse->eap_len); + return -1; + } + wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " + "identifier=%d length=%lu", + hdr->code, hdr->identifier, (unsigned long) len); + switch (hdr->code) { + case EAP_CODE_REQUEST: + if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { + wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " + "processing failed"); + return -1; + } + break; + default: + wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " + "Phase 2 EAP header", hdr->code); + return -1; + } + + return 0; +} + + +static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse) +{ +#ifdef EAP_MSCHAPv2 + if (parse->mschapv2_error) { + wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " + "MS-CHAP-Error - failed"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + /* Reply with empty data to ACK error */ + return 1; + } + + if (parse->mschapv2 == NULL) { +#ifdef EAP_TNC + if (data->phase2_success && parse->eapdata) { + /* + * Allow EAP-TNC to be started after successfully + * completed MSCHAPV2. + */ + return 1; + } +#endif /* EAP_TNC */ + wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " + "received for Phase2 MSCHAPV2"); + return -1; + } + if (parse->mschapv2[0] != data->ident) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " + "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", + parse->mschapv2[0], data->ident); + return -1; + } + if (!data->auth_response_valid || + mschapv2_verify_auth_response(data->auth_response, + parse->mschapv2 + 1, 42)) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " + "response in Phase 2 MSCHAPV2 success request"); + return -1; + } + + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " + "authentication succeeded"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_UNCOND_SUCC; + data->phase2_success = 1; + + /* + * Reply with empty data; authentication server will reply + * with EAP-Success after this. + */ + return 1; +#else /* EAP_MSCHAPv2 */ + wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); + return -1; +#endif /* EAP_MSCHAPv2 */ +} + + +#ifdef EAP_TNC +static int eap_ttls_process_tnc_start(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse, + struct wpabuf **resp) +{ + /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ + if (parse->eapdata == NULL) { + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " + "unexpected tunneled data (no EAP)"); + return -1; + } + + if (!data->ready_for_tnc) { + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " + "EAP after non-EAP, but not ready for TNC"); + return -1; + } + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " + "non-EAP method"); + data->tnc_started = 1; + + if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) + return -1; + + return 0; +} +#endif /* EAP_TNC */ + + +static int eap_ttls_process_decrypted(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + u8 identifier, + struct ttls_parse_avp *parse, + struct wpabuf *in_decrypted, + struct wpabuf **out_data) +{ + struct wpabuf *resp = NULL; + struct eap_peer_config *config = eap_get_config(sm); + int res; + enum phase2_types phase2_type = data->phase2_type; + +#ifdef EAP_TNC + if (data->tnc_started) + phase2_type = EAP_TTLS_PHASE2_EAP; +#endif /* EAP_TNC */ + + /* handle channel binding response here */ + if (parse->chbind_data) { + /* received channel binding repsonse */ + if (eap_ttls_process_chbind(sm, data, ret, parse, &resp) < 0) + return -1; + if (data->done_butfor_cb) { + ret->methodState = METHOD_DONE; + ret->decision = data->cbDecision; + data->phase2_success = 1; + return 1; /*request ack*/ + } + } + + switch (phase2_type) { + case EAP_TTLS_PHASE2_EAP: + if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < + 0) + return -1; + break; + case EAP_TTLS_PHASE2_MSCHAPV2: + res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); +#ifdef EAP_TNC + if (res == 1 && parse->eapdata && data->phase2_success) { + /* + * TNC may be required as the next + * authentication method within the tunnel. + */ + ret->methodState = METHOD_MAY_CONT; + data->ready_for_tnc = 1; + if (eap_ttls_process_tnc_start(sm, data, ret, parse, + &resp) == 0) + break; + } +#endif /* EAP_TNC */ + return res; + case EAP_TTLS_PHASE2_MSCHAP: + case EAP_TTLS_PHASE2_PAP: + case EAP_TTLS_PHASE2_CHAP: +#ifdef EAP_TNC + if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < + 0) + return -1; + break; +#else /* EAP_TNC */ + /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled + * requests to the supplicant */ + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " + "tunneled data"); + return -1; +#endif /* EAP_TNC */ + } + + if (!resp && (config->pending_req_identity || + config->pending_req_password || + config->pending_req_otp || + config->pending_req_new_password)) { + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = wpabuf_dup(in_decrypted); + return 0; + } + + /* issue channel binding request when appropriate */ + if (config->chbind_config && config->chbind_config_len > 0 && + !data->chbind_req_sent) { + if (eap_ttls_add_chbind_request(sm, data, &resp) < 0) + return -1; + data->chbind_req_sent = 1; + if (ret->methodState == METHOD_DONE) { + data->done_butfor_cb = 1; + data->cbDecision = ret->decision; + ret->methodState = METHOD_MAY_CONT; + } + } + + if (resp) { + if (eap_ttls_encrypt_response(sm, data, resp, identifier, + out_data) < 0) + return -1; + } + + return 0; +} + + +static int eap_ttls_implicit_identity_request(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + u8 identifier, + struct wpabuf **out_data) +{ + int retval = 0; + struct eap_hdr *hdr; + struct wpabuf *resp; + + hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); + if (hdr == NULL) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return -1; + } + + resp = NULL; + if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { + wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " + "processing failed"); + retval = -1; + } else { + struct eap_peer_config *config = eap_get_config(sm); + if (resp == NULL && + (config->pending_req_identity || + config->pending_req_password || + config->pending_req_otp || + config->pending_req_new_password)) { + /* + * Use empty buffer to force implicit request + * processing when EAP request is re-processed after + * user input. + */ + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = wpabuf_alloc(0); + } + + retval = eap_ttls_encrypt_response(sm, data, resp, identifier, + out_data); + } + + os_free(hdr); + + if (retval < 0) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + } + + return retval; +} + + +static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, + struct eap_method_ret *ret, u8 identifier, + struct wpabuf **out_data) +{ + data->phase2_start = 0; + + /* + * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only + * if TLS part was indeed resuming a previous session. Most + * Authentication Servers terminate EAP-TTLS before reaching this + * point, but some do not. Make wpa_supplicant stop phase 2 here, if + * needed. + */ + if (data->reauth && + tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " + "skip phase 2"); + *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, + data->ttls_version); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_UNCOND_SUCC; + data->phase2_success = 1; + return 0; + } + + return eap_ttls_implicit_identity_request(sm, data, ret, identifier, + out_data); +} + + +static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, + struct eap_method_ret *ret, u8 identifier, + const struct wpabuf *in_data, + struct wpabuf **out_data) +{ + struct wpabuf *in_decrypted = NULL; + int retval = 0; + struct ttls_parse_avp parse; + + os_memset(&parse, 0, sizeof(parse)); + + wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" + " Phase 2", + in_data ? (unsigned long) wpabuf_len(in_data) : 0); + + if (data->pending_phase2_req) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " + "skip decryption and use old data"); + /* Clear TLS reassembly state. */ + eap_peer_tls_reset_input(&data->ssl); + + in_decrypted = data->pending_phase2_req; + data->pending_phase2_req = NULL; + if (wpabuf_len(in_decrypted) == 0) { + wpabuf_free(in_decrypted); + return eap_ttls_implicit_identity_request( + sm, data, ret, identifier, out_data); + } + goto continue_req; + } + + if ((in_data == NULL || wpabuf_len(in_data) == 0) && + data->phase2_start) { + return eap_ttls_phase2_start(sm, data, ret, identifier, + out_data); + } + + if (in_data == NULL || wpabuf_len(in_data) == 0) { + /* Received TLS ACK - requesting more fragments */ + return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, + data->ttls_version, + identifier, NULL, out_data); + } + + retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); + if (retval) + goto done; + +continue_req: + data->phase2_start = 0; + + if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { + retval = -1; + goto done; + } + + retval = eap_ttls_process_decrypted(sm, data, ret, identifier, + &parse, in_decrypted, out_data); + +done: + wpabuf_free(in_decrypted); + os_free(parse.eapdata); + + if (retval < 0) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + } + + return retval; +} + + +static int eap_ttls_process_handshake(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + u8 identifier, + const struct wpabuf *in_data, + struct wpabuf **out_data) +{ + int res; + + res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, + data->ttls_version, identifier, + in_data, out_data); + if (res < 0) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return -1; + } + + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " + "Phase 2"); + if (data->resuming) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " + "skip Phase 2"); + ret->decision = DECISION_COND_SUCC; + ret->methodState = METHOD_MAY_CONT; + } + data->phase2_start = 1; + eap_ttls_v0_derive_key(sm, data); + + if (*out_data == NULL || wpabuf_len(*out_data) == 0) { + if (eap_ttls_decrypt(sm, data, ret, identifier, + NULL, out_data)) { + wpa_printf(MSG_WARNING, "EAP-TTLS: " + "failed to process early " + "start for Phase 2"); + } + res = 0; + } + data->resuming = 0; + } + + if (res == 2) { + /* + * Application data included in the handshake message. + */ + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = *out_data; + *out_data = NULL; + res = eap_ttls_decrypt(sm, data, ret, identifier, in_data, + out_data); + } + + return res; +} + + +static void eap_ttls_check_auth_status(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret) +{ + if (ret->methodState == METHOD_DONE) { + ret->allowNotifications = FALSE; + if (ret->decision == DECISION_UNCOND_SUCC || + ret->decision == DECISION_COND_SUCC) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " + "completed successfully"); + data->phase2_success = 1; +#ifdef EAP_TNC + if (!data->ready_for_tnc && !data->tnc_started) { + /* + * TNC may be required as the next + * authentication method within the tunnel. + */ + ret->methodState = METHOD_MAY_CONT; + data->ready_for_tnc = 1; + } +#endif /* EAP_TNC */ + } + } else if (ret->methodState == METHOD_MAY_CONT && + (ret->decision == DECISION_UNCOND_SUCC || + ret->decision == DECISION_COND_SUCC)) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " + "completed successfully (MAY_CONT)"); + data->phase2_success = 1; + } +} + + +static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, + struct eap_method_ret *ret, + const struct wpabuf *reqData) +{ + size_t left; + int res; + u8 flags, id; + struct wpabuf *resp; + const u8 *pos; + struct eap_ttls_data *data = priv; + struct wpabuf msg; + + pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, + reqData, &left, &flags); + if (pos == NULL) + return NULL; + id = eap_get_id(reqData); + + if (flags & EAP_TLS_FLAGS_START) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " + "ver=%d)", flags & EAP_TLS_VERSION_MASK, + data->ttls_version); + + /* RFC 5281, Ch. 9.2: + * "This packet MAY contain additional information in the form + * of AVPs, which may provide useful hints to the client" + * For now, ignore any potential extra data. + */ + left = 0; + } + + wpabuf_set(&msg, pos, left); + + resp = NULL; + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && + !data->resuming) { + res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); + } else { + res = eap_ttls_process_handshake(sm, data, ret, id, + &msg, &resp); + } + + eap_ttls_check_auth_status(sm, data, ret); + + /* FIX: what about res == -1? Could just move all error processing into + * the other functions and get rid of this res==1 case here. */ + if (res == 1) { + wpabuf_free(resp); + return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, + data->ttls_version); + } + return resp; +} + + +static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && + data->phase2_success; +} + + +static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = NULL; +#ifdef EAP_TNC + data->ready_for_tnc = 0; + data->tnc_started = 0; +#endif /* EAP_TNC */ +} + + +static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + eap_ttls_free_key(data); + os_free(data->session_id); + data->session_id = NULL; + if (eap_peer_tls_reauth_init(sm, &data->ssl)) { + os_free(data); + return NULL; + } + if (data->phase2_priv && data->phase2_method && + data->phase2_method->init_for_reauth) + data->phase2_method->init_for_reauth(sm, data->phase2_priv); + data->phase2_start = 0; + data->phase2_success = 0; + data->resuming = 1; + data->reauth = 1; + return priv; +} + + +static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, + size_t buflen, int verbose) +{ + struct eap_ttls_data *data = priv; + int len, ret; + + len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); + ret = os_snprintf(buf + len, buflen - len, + "EAP-TTLSv%d Phase2 method=", + data->ttls_version); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + switch (data->phase2_type) { + case EAP_TTLS_PHASE2_EAP: + ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", + data->phase2_method ? + data->phase2_method->name : "?"); + break; + case EAP_TTLS_PHASE2_MSCHAPV2: + ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); + break; + case EAP_TTLS_PHASE2_MSCHAP: + ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); + break; + case EAP_TTLS_PHASE2_PAP: + ret = os_snprintf(buf + len, buflen - len, "PAP\n"); + break; + case EAP_TTLS_PHASE2_CHAP: + ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); + break; + default: + ret = 0; + break; + } + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + return len; +} + + +static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + return data->key_data != NULL && data->phase2_success; +} + + +static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ttls_data *data = priv; + u8 *key; + + if (data->key_data == NULL || !data->phase2_success) + return NULL; + + key = os_malloc(EAP_TLS_KEY_LEN); + if (key == NULL) + return NULL; + + *len = EAP_TLS_KEY_LEN; + os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); + + return key; +} + + +static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ttls_data *data = priv; + u8 *id; + + if (data->session_id == NULL || !data->phase2_success) + return NULL; + + id = os_malloc(data->id_len); + if (id == NULL) + return NULL; + + *len = data->id_len; + os_memcpy(id, data->session_id, data->id_len); + + return id; +} + + +static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ttls_data *data = priv; + u8 *key; + + if (data->key_data == NULL) + return NULL; + + key = os_malloc(EAP_EMSK_LEN); + if (key == NULL) + return NULL; + + *len = EAP_EMSK_LEN; + os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); + + return key; +} + + +int eap_peer_ttls_register(void) +{ + struct eap_method *eap; + int ret; + + eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, + EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); + if (eap == NULL) + return -1; + + eap->init = eap_ttls_init; + eap->deinit = eap_ttls_deinit; + eap->process = eap_ttls_process; + eap->isKeyAvailable = eap_ttls_isKeyAvailable; + eap->getKey = eap_ttls_getKey; + eap->getSessionId = eap_ttls_get_session_id; + eap->get_status = eap_ttls_get_status; + eap->has_reauth_data = eap_ttls_has_reauth_data; + eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; + eap->init_for_reauth = eap_ttls_init_for_reauth; + eap->get_emsk = eap_ttls_get_emsk; + + ret = eap_peer_method_register(eap); + if (ret) + eap_peer_method_free(eap); + return ret; +} diff --git a/src/eap_peer/eap_vendor_test.c b/libeap/src/eap_peer/eap_vendor_test.c similarity index 100% rename from src/eap_peer/eap_vendor_test.c rename to libeap/src/eap_peer/eap_vendor_test.c diff --git a/src/eap_peer/eap_wsc.c b/libeap/src/eap_peer/eap_wsc.c similarity index 100% rename from src/eap_peer/eap_wsc.c rename to libeap/src/eap_peer/eap_wsc.c diff --git a/src/eap_peer/ikev2.c b/libeap/src/eap_peer/ikev2.c similarity index 100% rename from src/eap_peer/ikev2.c rename to libeap/src/eap_peer/ikev2.c diff --git a/src/eap_peer/ikev2.h b/libeap/src/eap_peer/ikev2.h similarity index 100% rename from src/eap_peer/ikev2.h rename to libeap/src/eap_peer/ikev2.h diff --git a/src/eap_peer/mschapv2.c b/libeap/src/eap_peer/mschapv2.c similarity index 100% rename from src/eap_peer/mschapv2.c rename to libeap/src/eap_peer/mschapv2.c diff --git a/src/eap_peer/mschapv2.h b/libeap/src/eap_peer/mschapv2.h similarity index 100% rename from src/eap_peer/mschapv2.h rename to libeap/src/eap_peer/mschapv2.h diff --git a/src/eap_peer/tncc.c b/libeap/src/eap_peer/tncc.c similarity index 100% rename from src/eap_peer/tncc.c rename to libeap/src/eap_peer/tncc.c diff --git a/src/eap_peer/tncc.h b/libeap/src/eap_peer/tncc.h similarity index 100% rename from src/eap_peer/tncc.h rename to libeap/src/eap_peer/tncc.h diff --git a/src/eap_server/Makefile b/libeap/src/eap_server/Makefile similarity index 100% rename from src/eap_server/Makefile rename to libeap/src/eap_server/Makefile diff --git a/src/eap_server/eap.h b/libeap/src/eap_server/eap.h similarity index 100% rename from src/eap_server/eap.h rename to libeap/src/eap_server/eap.h diff --git a/src/eap_server/eap_i.h b/libeap/src/eap_server/eap_i.h similarity index 100% rename from src/eap_server/eap_i.h rename to libeap/src/eap_server/eap_i.h diff --git a/src/eap_server/eap_methods.h b/libeap/src/eap_server/eap_methods.h similarity index 100% rename from src/eap_server/eap_methods.h rename to libeap/src/eap_server/eap_methods.h diff --git a/src/eap_server/eap_server.c b/libeap/src/eap_server/eap_server.c similarity index 100% rename from src/eap_server/eap_server.c rename to libeap/src/eap_server/eap_server.c diff --git a/src/eap_server/eap_server_aka.c b/libeap/src/eap_server/eap_server_aka.c similarity index 100% rename from src/eap_server/eap_server_aka.c rename to libeap/src/eap_server/eap_server_aka.c diff --git a/src/eap_server/eap_server_eke.c b/libeap/src/eap_server/eap_server_eke.c similarity index 100% rename from src/eap_server/eap_server_eke.c rename to libeap/src/eap_server/eap_server_eke.c diff --git a/src/eap_server/eap_server_fast.c b/libeap/src/eap_server/eap_server_fast.c similarity index 100% rename from src/eap_server/eap_server_fast.c rename to libeap/src/eap_server/eap_server_fast.c diff --git a/src/eap_server/eap_server_gpsk.c b/libeap/src/eap_server/eap_server_gpsk.c similarity index 100% rename from src/eap_server/eap_server_gpsk.c rename to libeap/src/eap_server/eap_server_gpsk.c diff --git a/src/eap_server/eap_server_gtc.c b/libeap/src/eap_server/eap_server_gtc.c similarity index 100% rename from src/eap_server/eap_server_gtc.c rename to libeap/src/eap_server/eap_server_gtc.c diff --git a/src/eap_server/eap_server_identity.c b/libeap/src/eap_server/eap_server_identity.c similarity index 100% rename from src/eap_server/eap_server_identity.c rename to libeap/src/eap_server/eap_server_identity.c diff --git a/src/eap_server/eap_server_ikev2.c b/libeap/src/eap_server/eap_server_ikev2.c similarity index 100% rename from src/eap_server/eap_server_ikev2.c rename to libeap/src/eap_server/eap_server_ikev2.c diff --git a/src/eap_server/eap_server_md5.c b/libeap/src/eap_server/eap_server_md5.c similarity index 100% rename from src/eap_server/eap_server_md5.c rename to libeap/src/eap_server/eap_server_md5.c diff --git a/src/eap_server/eap_server_methods.c b/libeap/src/eap_server/eap_server_methods.c similarity index 100% rename from src/eap_server/eap_server_methods.c rename to libeap/src/eap_server/eap_server_methods.c diff --git a/src/eap_server/eap_server_mschapv2.c b/libeap/src/eap_server/eap_server_mschapv2.c similarity index 100% rename from src/eap_server/eap_server_mschapv2.c rename to libeap/src/eap_server/eap_server_mschapv2.c diff --git a/src/eap_server/eap_server_pax.c b/libeap/src/eap_server/eap_server_pax.c similarity index 100% rename from src/eap_server/eap_server_pax.c rename to libeap/src/eap_server/eap_server_pax.c diff --git a/src/eap_server/eap_server_peap.c b/libeap/src/eap_server/eap_server_peap.c similarity index 100% rename from src/eap_server/eap_server_peap.c rename to libeap/src/eap_server/eap_server_peap.c diff --git a/src/eap_server/eap_server_psk.c b/libeap/src/eap_server/eap_server_psk.c similarity index 100% rename from src/eap_server/eap_server_psk.c rename to libeap/src/eap_server/eap_server_psk.c diff --git a/src/eap_server/eap_server_pwd.c b/libeap/src/eap_server/eap_server_pwd.c similarity index 100% rename from src/eap_server/eap_server_pwd.c rename to libeap/src/eap_server/eap_server_pwd.c diff --git a/src/eap_server/eap_server_sake.c b/libeap/src/eap_server/eap_server_sake.c similarity index 100% rename from src/eap_server/eap_server_sake.c rename to libeap/src/eap_server/eap_server_sake.c diff --git a/src/eap_server/eap_server_sim.c b/libeap/src/eap_server/eap_server_sim.c similarity index 100% rename from src/eap_server/eap_server_sim.c rename to libeap/src/eap_server/eap_server_sim.c diff --git a/src/eap_server/eap_server_tls.c b/libeap/src/eap_server/eap_server_tls.c similarity index 100% rename from src/eap_server/eap_server_tls.c rename to libeap/src/eap_server/eap_server_tls.c diff --git a/src/eap_server/eap_server_tls_common.c b/libeap/src/eap_server/eap_server_tls_common.c similarity index 100% rename from src/eap_server/eap_server_tls_common.c rename to libeap/src/eap_server/eap_server_tls_common.c diff --git a/src/eap_server/eap_server_tnc.c b/libeap/src/eap_server/eap_server_tnc.c similarity index 100% rename from src/eap_server/eap_server_tnc.c rename to libeap/src/eap_server/eap_server_tnc.c diff --git a/src/eap_server/eap_server_ttls.c b/libeap/src/eap_server/eap_server_ttls.c similarity index 100% rename from src/eap_server/eap_server_ttls.c rename to libeap/src/eap_server/eap_server_ttls.c diff --git a/src/eap_server/eap_server_vendor_test.c b/libeap/src/eap_server/eap_server_vendor_test.c similarity index 100% rename from src/eap_server/eap_server_vendor_test.c rename to libeap/src/eap_server/eap_server_vendor_test.c diff --git a/src/eap_server/eap_server_wsc.c b/libeap/src/eap_server/eap_server_wsc.c similarity index 100% rename from src/eap_server/eap_server_wsc.c rename to libeap/src/eap_server/eap_server_wsc.c diff --git a/src/eap_server/eap_sim_db.c b/libeap/src/eap_server/eap_sim_db.c similarity index 100% rename from src/eap_server/eap_sim_db.c rename to libeap/src/eap_server/eap_sim_db.c diff --git a/src/eap_server/eap_sim_db.h b/libeap/src/eap_server/eap_sim_db.h similarity index 100% rename from src/eap_server/eap_sim_db.h rename to libeap/src/eap_server/eap_sim_db.h diff --git a/src/eap_server/eap_tls_common.h b/libeap/src/eap_server/eap_tls_common.h similarity index 100% rename from src/eap_server/eap_tls_common.h rename to libeap/src/eap_server/eap_tls_common.h diff --git a/src/eap_server/ikev2.c b/libeap/src/eap_server/ikev2.c similarity index 100% rename from src/eap_server/ikev2.c rename to libeap/src/eap_server/ikev2.c diff --git a/src/eap_server/ikev2.h b/libeap/src/eap_server/ikev2.h similarity index 100% rename from src/eap_server/ikev2.h rename to libeap/src/eap_server/ikev2.h diff --git a/src/eap_server/tncs.c b/libeap/src/eap_server/tncs.c similarity index 100% rename from src/eap_server/tncs.c rename to libeap/src/eap_server/tncs.c diff --git a/src/eap_server/tncs.h b/libeap/src/eap_server/tncs.h similarity index 100% rename from src/eap_server/tncs.h rename to libeap/src/eap_server/tncs.h diff --git a/src/eapol_auth/Makefile b/libeap/src/eapol_auth/Makefile similarity index 100% rename from src/eapol_auth/Makefile rename to libeap/src/eapol_auth/Makefile diff --git a/src/eapol_auth/eapol_auth_dump.c b/libeap/src/eapol_auth/eapol_auth_dump.c similarity index 100% rename from src/eapol_auth/eapol_auth_dump.c rename to libeap/src/eapol_auth/eapol_auth_dump.c diff --git a/src/eapol_auth/eapol_auth_sm.c b/libeap/src/eapol_auth/eapol_auth_sm.c similarity index 100% rename from src/eapol_auth/eapol_auth_sm.c rename to libeap/src/eapol_auth/eapol_auth_sm.c diff --git a/src/eapol_auth/eapol_auth_sm.h b/libeap/src/eapol_auth/eapol_auth_sm.h similarity index 100% rename from src/eapol_auth/eapol_auth_sm.h rename to libeap/src/eapol_auth/eapol_auth_sm.h diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/libeap/src/eapol_auth/eapol_auth_sm_i.h similarity index 100% rename from src/eapol_auth/eapol_auth_sm_i.h rename to libeap/src/eapol_auth/eapol_auth_sm_i.h diff --git a/src/eapol_supp/Makefile b/libeap/src/eapol_supp/Makefile similarity index 100% rename from src/eapol_supp/Makefile rename to libeap/src/eapol_supp/Makefile diff --git a/src/eapol_supp/eapol_supp_sm.c b/libeap/src/eapol_supp/eapol_supp_sm.c similarity index 100% rename from src/eapol_supp/eapol_supp_sm.c rename to libeap/src/eapol_supp/eapol_supp_sm.c diff --git a/src/eapol_supp/eapol_supp_sm.h b/libeap/src/eapol_supp/eapol_supp_sm.h similarity index 100% rename from src/eapol_supp/eapol_supp_sm.h rename to libeap/src/eapol_supp/eapol_supp_sm.h diff --git a/src/pae/Makefile b/libeap/src/fst/Makefile similarity index 100% rename from src/pae/Makefile rename to libeap/src/fst/Makefile diff --git a/src/fst/fst.c b/libeap/src/fst/fst.c similarity index 100% rename from src/fst/fst.c rename to libeap/src/fst/fst.c diff --git a/src/fst/fst.h b/libeap/src/fst/fst.h similarity index 100% rename from src/fst/fst.h rename to libeap/src/fst/fst.h diff --git a/src/fst/fst_ctrl_aux.c b/libeap/src/fst/fst_ctrl_aux.c similarity index 100% rename from src/fst/fst_ctrl_aux.c rename to libeap/src/fst/fst_ctrl_aux.c diff --git a/src/fst/fst_ctrl_aux.h b/libeap/src/fst/fst_ctrl_aux.h similarity index 100% rename from src/fst/fst_ctrl_aux.h rename to libeap/src/fst/fst_ctrl_aux.h diff --git a/src/fst/fst_ctrl_defs.h b/libeap/src/fst/fst_ctrl_defs.h similarity index 100% rename from src/fst/fst_ctrl_defs.h rename to libeap/src/fst/fst_ctrl_defs.h diff --git a/src/fst/fst_ctrl_iface.c b/libeap/src/fst/fst_ctrl_iface.c similarity index 100% rename from src/fst/fst_ctrl_iface.c rename to libeap/src/fst/fst_ctrl_iface.c diff --git a/src/fst/fst_ctrl_iface.h b/libeap/src/fst/fst_ctrl_iface.h similarity index 100% rename from src/fst/fst_ctrl_iface.h rename to libeap/src/fst/fst_ctrl_iface.h diff --git a/src/fst/fst_defs.h b/libeap/src/fst/fst_defs.h similarity index 100% rename from src/fst/fst_defs.h rename to libeap/src/fst/fst_defs.h diff --git a/src/fst/fst_group.c b/libeap/src/fst/fst_group.c similarity index 100% rename from src/fst/fst_group.c rename to libeap/src/fst/fst_group.c diff --git a/src/fst/fst_group.h b/libeap/src/fst/fst_group.h similarity index 100% rename from src/fst/fst_group.h rename to libeap/src/fst/fst_group.h diff --git a/src/fst/fst_iface.c b/libeap/src/fst/fst_iface.c similarity index 100% rename from src/fst/fst_iface.c rename to libeap/src/fst/fst_iface.c diff --git a/src/fst/fst_iface.h b/libeap/src/fst/fst_iface.h similarity index 100% rename from src/fst/fst_iface.h rename to libeap/src/fst/fst_iface.h diff --git a/src/fst/fst_internal.h b/libeap/src/fst/fst_internal.h similarity index 100% rename from src/fst/fst_internal.h rename to libeap/src/fst/fst_internal.h diff --git a/src/fst/fst_session.c b/libeap/src/fst/fst_session.c similarity index 100% rename from src/fst/fst_session.c rename to libeap/src/fst/fst_session.c diff --git a/src/fst/fst_session.h b/libeap/src/fst/fst_session.h similarity index 100% rename from src/fst/fst_session.h rename to libeap/src/fst/fst_session.h diff --git a/src/l2_packet/Makefile b/libeap/src/l2_packet/Makefile similarity index 100% rename from src/l2_packet/Makefile rename to libeap/src/l2_packet/Makefile diff --git a/src/l2_packet/l2_packet.h b/libeap/src/l2_packet/l2_packet.h similarity index 100% rename from src/l2_packet/l2_packet.h rename to libeap/src/l2_packet/l2_packet.h diff --git a/src/l2_packet/l2_packet_freebsd.c b/libeap/src/l2_packet/l2_packet_freebsd.c similarity index 100% rename from src/l2_packet/l2_packet_freebsd.c rename to libeap/src/l2_packet/l2_packet_freebsd.c diff --git a/src/l2_packet/l2_packet_linux.c b/libeap/src/l2_packet/l2_packet_linux.c similarity index 100% rename from src/l2_packet/l2_packet_linux.c rename to libeap/src/l2_packet/l2_packet_linux.c diff --git a/src/l2_packet/l2_packet_ndis.c b/libeap/src/l2_packet/l2_packet_ndis.c similarity index 100% rename from src/l2_packet/l2_packet_ndis.c rename to libeap/src/l2_packet/l2_packet_ndis.c diff --git a/src/l2_packet/l2_packet_none.c b/libeap/src/l2_packet/l2_packet_none.c similarity index 100% rename from src/l2_packet/l2_packet_none.c rename to libeap/src/l2_packet/l2_packet_none.c diff --git a/src/l2_packet/l2_packet_pcap.c b/libeap/src/l2_packet/l2_packet_pcap.c similarity index 100% rename from src/l2_packet/l2_packet_pcap.c rename to libeap/src/l2_packet/l2_packet_pcap.c diff --git a/src/l2_packet/l2_packet_privsep.c b/libeap/src/l2_packet/l2_packet_privsep.c similarity index 100% rename from src/l2_packet/l2_packet_privsep.c rename to libeap/src/l2_packet/l2_packet_privsep.c diff --git a/src/l2_packet/l2_packet_winpcap.c b/libeap/src/l2_packet/l2_packet_winpcap.c similarity index 100% rename from src/l2_packet/l2_packet_winpcap.c rename to libeap/src/l2_packet/l2_packet_winpcap.c diff --git a/src/lib.rules b/libeap/src/lib.rules similarity index 100% rename from src/lib.rules rename to libeap/src/lib.rules diff --git a/src/p2p/Makefile b/libeap/src/p2p/Makefile similarity index 100% rename from src/p2p/Makefile rename to libeap/src/p2p/Makefile diff --git a/src/p2p/p2p.c b/libeap/src/p2p/p2p.c similarity index 100% rename from src/p2p/p2p.c rename to libeap/src/p2p/p2p.c diff --git a/src/p2p/p2p.h b/libeap/src/p2p/p2p.h similarity index 100% rename from src/p2p/p2p.h rename to libeap/src/p2p/p2p.h diff --git a/src/p2p/p2p_build.c b/libeap/src/p2p/p2p_build.c similarity index 100% rename from src/p2p/p2p_build.c rename to libeap/src/p2p/p2p_build.c diff --git a/src/p2p/p2p_dev_disc.c b/libeap/src/p2p/p2p_dev_disc.c similarity index 100% rename from src/p2p/p2p_dev_disc.c rename to libeap/src/p2p/p2p_dev_disc.c diff --git a/src/p2p/p2p_go_neg.c b/libeap/src/p2p/p2p_go_neg.c similarity index 100% rename from src/p2p/p2p_go_neg.c rename to libeap/src/p2p/p2p_go_neg.c diff --git a/src/p2p/p2p_group.c b/libeap/src/p2p/p2p_group.c similarity index 100% rename from src/p2p/p2p_group.c rename to libeap/src/p2p/p2p_group.c diff --git a/src/p2p/p2p_i.h b/libeap/src/p2p/p2p_i.h similarity index 100% rename from src/p2p/p2p_i.h rename to libeap/src/p2p/p2p_i.h diff --git a/src/p2p/p2p_invitation.c b/libeap/src/p2p/p2p_invitation.c similarity index 100% rename from src/p2p/p2p_invitation.c rename to libeap/src/p2p/p2p_invitation.c diff --git a/src/p2p/p2p_parse.c b/libeap/src/p2p/p2p_parse.c similarity index 100% rename from src/p2p/p2p_parse.c rename to libeap/src/p2p/p2p_parse.c diff --git a/src/p2p/p2p_pd.c b/libeap/src/p2p/p2p_pd.c similarity index 100% rename from src/p2p/p2p_pd.c rename to libeap/src/p2p/p2p_pd.c diff --git a/src/p2p/p2p_sd.c b/libeap/src/p2p/p2p_sd.c similarity index 100% rename from src/p2p/p2p_sd.c rename to libeap/src/p2p/p2p_sd.c diff --git a/src/p2p/p2p_utils.c b/libeap/src/p2p/p2p_utils.c similarity index 100% rename from src/p2p/p2p_utils.c rename to libeap/src/p2p/p2p_utils.c diff --git a/src/fst/Makefile b/libeap/src/pae/Makefile similarity index 100% rename from src/fst/Makefile rename to libeap/src/pae/Makefile diff --git a/src/pae/ieee802_1x_cp.c b/libeap/src/pae/ieee802_1x_cp.c similarity index 100% rename from src/pae/ieee802_1x_cp.c rename to libeap/src/pae/ieee802_1x_cp.c diff --git a/src/pae/ieee802_1x_cp.h b/libeap/src/pae/ieee802_1x_cp.h similarity index 100% rename from src/pae/ieee802_1x_cp.h rename to libeap/src/pae/ieee802_1x_cp.h diff --git a/src/pae/ieee802_1x_kay.c b/libeap/src/pae/ieee802_1x_kay.c similarity index 100% rename from src/pae/ieee802_1x_kay.c rename to libeap/src/pae/ieee802_1x_kay.c diff --git a/src/pae/ieee802_1x_kay.h b/libeap/src/pae/ieee802_1x_kay.h similarity index 100% rename from src/pae/ieee802_1x_kay.h rename to libeap/src/pae/ieee802_1x_kay.h diff --git a/src/pae/ieee802_1x_kay_i.h b/libeap/src/pae/ieee802_1x_kay_i.h similarity index 100% rename from src/pae/ieee802_1x_kay_i.h rename to libeap/src/pae/ieee802_1x_kay_i.h diff --git a/src/pae/ieee802_1x_key.c b/libeap/src/pae/ieee802_1x_key.c similarity index 100% rename from src/pae/ieee802_1x_key.c rename to libeap/src/pae/ieee802_1x_key.c diff --git a/src/pae/ieee802_1x_key.h b/libeap/src/pae/ieee802_1x_key.h similarity index 100% rename from src/pae/ieee802_1x_key.h rename to libeap/src/pae/ieee802_1x_key.h diff --git a/src/pae/ieee802_1x_secy_ops.c b/libeap/src/pae/ieee802_1x_secy_ops.c similarity index 100% rename from src/pae/ieee802_1x_secy_ops.c rename to libeap/src/pae/ieee802_1x_secy_ops.c diff --git a/src/pae/ieee802_1x_secy_ops.h b/libeap/src/pae/ieee802_1x_secy_ops.h similarity index 100% rename from src/pae/ieee802_1x_secy_ops.h rename to libeap/src/pae/ieee802_1x_secy_ops.h diff --git a/src/radius/.gitignore b/libeap/src/radius/.gitignore similarity index 100% rename from src/radius/.gitignore rename to libeap/src/radius/.gitignore diff --git a/src/radius/Makefile b/libeap/src/radius/Makefile similarity index 100% rename from src/radius/Makefile rename to libeap/src/radius/Makefile diff --git a/src/radius/radius.c b/libeap/src/radius/radius.c similarity index 100% rename from src/radius/radius.c rename to libeap/src/radius/radius.c diff --git a/src/radius/radius.h b/libeap/src/radius/radius.h similarity index 100% rename from src/radius/radius.h rename to libeap/src/radius/radius.h diff --git a/src/radius/radius_client.c b/libeap/src/radius/radius_client.c similarity index 100% rename from src/radius/radius_client.c rename to libeap/src/radius/radius_client.c diff --git a/src/radius/radius_client.h b/libeap/src/radius/radius_client.h similarity index 100% rename from src/radius/radius_client.h rename to libeap/src/radius/radius_client.h diff --git a/src/radius/radius_das.c b/libeap/src/radius/radius_das.c similarity index 100% rename from src/radius/radius_das.c rename to libeap/src/radius/radius_das.c diff --git a/src/radius/radius_das.h b/libeap/src/radius/radius_das.h similarity index 100% rename from src/radius/radius_das.h rename to libeap/src/radius/radius_das.h diff --git a/src/radius/radius_server.c b/libeap/src/radius/radius_server.c similarity index 100% rename from src/radius/radius_server.c rename to libeap/src/radius/radius_server.c diff --git a/src/radius/radius_server.h b/libeap/src/radius/radius_server.h similarity index 100% rename from src/radius/radius_server.h rename to libeap/src/radius/radius_server.h diff --git a/src/rsn_supp/Makefile b/libeap/src/rsn_supp/Makefile similarity index 100% rename from src/rsn_supp/Makefile rename to libeap/src/rsn_supp/Makefile diff --git a/src/rsn_supp/peerkey.c b/libeap/src/rsn_supp/peerkey.c similarity index 100% rename from src/rsn_supp/peerkey.c rename to libeap/src/rsn_supp/peerkey.c diff --git a/src/rsn_supp/peerkey.h b/libeap/src/rsn_supp/peerkey.h similarity index 100% rename from src/rsn_supp/peerkey.h rename to libeap/src/rsn_supp/peerkey.h diff --git a/src/rsn_supp/pmksa_cache.c b/libeap/src/rsn_supp/pmksa_cache.c similarity index 100% rename from src/rsn_supp/pmksa_cache.c rename to libeap/src/rsn_supp/pmksa_cache.c diff --git a/src/rsn_supp/pmksa_cache.h b/libeap/src/rsn_supp/pmksa_cache.h similarity index 100% rename from src/rsn_supp/pmksa_cache.h rename to libeap/src/rsn_supp/pmksa_cache.h diff --git a/src/rsn_supp/preauth.c b/libeap/src/rsn_supp/preauth.c similarity index 100% rename from src/rsn_supp/preauth.c rename to libeap/src/rsn_supp/preauth.c diff --git a/src/rsn_supp/preauth.h b/libeap/src/rsn_supp/preauth.h similarity index 100% rename from src/rsn_supp/preauth.h rename to libeap/src/rsn_supp/preauth.h diff --git a/src/rsn_supp/tdls.c b/libeap/src/rsn_supp/tdls.c similarity index 100% rename from src/rsn_supp/tdls.c rename to libeap/src/rsn_supp/tdls.c diff --git a/src/rsn_supp/wpa.c b/libeap/src/rsn_supp/wpa.c similarity index 100% rename from src/rsn_supp/wpa.c rename to libeap/src/rsn_supp/wpa.c diff --git a/src/rsn_supp/wpa.h b/libeap/src/rsn_supp/wpa.h similarity index 100% rename from src/rsn_supp/wpa.h rename to libeap/src/rsn_supp/wpa.h diff --git a/src/rsn_supp/wpa_ft.c b/libeap/src/rsn_supp/wpa_ft.c similarity index 100% rename from src/rsn_supp/wpa_ft.c rename to libeap/src/rsn_supp/wpa_ft.c diff --git a/src/rsn_supp/wpa_i.h b/libeap/src/rsn_supp/wpa_i.h similarity index 100% rename from src/rsn_supp/wpa_i.h rename to libeap/src/rsn_supp/wpa_i.h diff --git a/src/rsn_supp/wpa_ie.c b/libeap/src/rsn_supp/wpa_ie.c similarity index 100% rename from src/rsn_supp/wpa_ie.c rename to libeap/src/rsn_supp/wpa_ie.c diff --git a/src/rsn_supp/wpa_ie.h b/libeap/src/rsn_supp/wpa_ie.h similarity index 100% rename from src/rsn_supp/wpa_ie.h rename to libeap/src/rsn_supp/wpa_ie.h diff --git a/src/tls/.gitignore b/libeap/src/tls/.gitignore similarity index 100% rename from src/tls/.gitignore rename to libeap/src/tls/.gitignore diff --git a/src/tls/Makefile b/libeap/src/tls/Makefile similarity index 100% rename from src/tls/Makefile rename to libeap/src/tls/Makefile diff --git a/src/tls/asn1.c b/libeap/src/tls/asn1.c similarity index 100% rename from src/tls/asn1.c rename to libeap/src/tls/asn1.c diff --git a/src/tls/asn1.h b/libeap/src/tls/asn1.h similarity index 100% rename from src/tls/asn1.h rename to libeap/src/tls/asn1.h diff --git a/src/tls/bignum.c b/libeap/src/tls/bignum.c similarity index 100% rename from src/tls/bignum.c rename to libeap/src/tls/bignum.c diff --git a/src/tls/bignum.h b/libeap/src/tls/bignum.h similarity index 100% rename from src/tls/bignum.h rename to libeap/src/tls/bignum.h diff --git a/src/tls/libtommath.c b/libeap/src/tls/libtommath.c similarity index 100% rename from src/tls/libtommath.c rename to libeap/src/tls/libtommath.c diff --git a/src/tls/pkcs1.c b/libeap/src/tls/pkcs1.c similarity index 100% rename from src/tls/pkcs1.c rename to libeap/src/tls/pkcs1.c diff --git a/src/tls/pkcs1.h b/libeap/src/tls/pkcs1.h similarity index 100% rename from src/tls/pkcs1.h rename to libeap/src/tls/pkcs1.h diff --git a/src/tls/pkcs5.c b/libeap/src/tls/pkcs5.c similarity index 100% rename from src/tls/pkcs5.c rename to libeap/src/tls/pkcs5.c diff --git a/src/tls/pkcs5.h b/libeap/src/tls/pkcs5.h similarity index 100% rename from src/tls/pkcs5.h rename to libeap/src/tls/pkcs5.h diff --git a/src/tls/pkcs8.c b/libeap/src/tls/pkcs8.c similarity index 100% rename from src/tls/pkcs8.c rename to libeap/src/tls/pkcs8.c diff --git a/src/tls/pkcs8.h b/libeap/src/tls/pkcs8.h similarity index 100% rename from src/tls/pkcs8.h rename to libeap/src/tls/pkcs8.h diff --git a/src/tls/rsa.c b/libeap/src/tls/rsa.c similarity index 100% rename from src/tls/rsa.c rename to libeap/src/tls/rsa.c diff --git a/src/tls/rsa.h b/libeap/src/tls/rsa.h similarity index 100% rename from src/tls/rsa.h rename to libeap/src/tls/rsa.h diff --git a/src/tls/tlsv1_client.c b/libeap/src/tls/tlsv1_client.c similarity index 100% rename from src/tls/tlsv1_client.c rename to libeap/src/tls/tlsv1_client.c diff --git a/src/tls/tlsv1_client.h b/libeap/src/tls/tlsv1_client.h similarity index 100% rename from src/tls/tlsv1_client.h rename to libeap/src/tls/tlsv1_client.h diff --git a/src/tls/tlsv1_client_i.h b/libeap/src/tls/tlsv1_client_i.h similarity index 100% rename from src/tls/tlsv1_client_i.h rename to libeap/src/tls/tlsv1_client_i.h diff --git a/src/tls/tlsv1_client_read.c b/libeap/src/tls/tlsv1_client_read.c similarity index 100% rename from src/tls/tlsv1_client_read.c rename to libeap/src/tls/tlsv1_client_read.c diff --git a/src/tls/tlsv1_client_write.c b/libeap/src/tls/tlsv1_client_write.c similarity index 100% rename from src/tls/tlsv1_client_write.c rename to libeap/src/tls/tlsv1_client_write.c diff --git a/src/tls/tlsv1_common.c b/libeap/src/tls/tlsv1_common.c similarity index 100% rename from src/tls/tlsv1_common.c rename to libeap/src/tls/tlsv1_common.c diff --git a/src/tls/tlsv1_common.h b/libeap/src/tls/tlsv1_common.h similarity index 100% rename from src/tls/tlsv1_common.h rename to libeap/src/tls/tlsv1_common.h diff --git a/src/tls/tlsv1_cred.c b/libeap/src/tls/tlsv1_cred.c similarity index 100% rename from src/tls/tlsv1_cred.c rename to libeap/src/tls/tlsv1_cred.c diff --git a/src/tls/tlsv1_cred.h b/libeap/src/tls/tlsv1_cred.h similarity index 100% rename from src/tls/tlsv1_cred.h rename to libeap/src/tls/tlsv1_cred.h diff --git a/src/tls/tlsv1_record.c b/libeap/src/tls/tlsv1_record.c similarity index 100% rename from src/tls/tlsv1_record.c rename to libeap/src/tls/tlsv1_record.c diff --git a/src/tls/tlsv1_record.h b/libeap/src/tls/tlsv1_record.h similarity index 100% rename from src/tls/tlsv1_record.h rename to libeap/src/tls/tlsv1_record.h diff --git a/src/tls/tlsv1_server.c b/libeap/src/tls/tlsv1_server.c similarity index 100% rename from src/tls/tlsv1_server.c rename to libeap/src/tls/tlsv1_server.c diff --git a/src/tls/tlsv1_server.h b/libeap/src/tls/tlsv1_server.h similarity index 100% rename from src/tls/tlsv1_server.h rename to libeap/src/tls/tlsv1_server.h diff --git a/src/tls/tlsv1_server_i.h b/libeap/src/tls/tlsv1_server_i.h similarity index 100% rename from src/tls/tlsv1_server_i.h rename to libeap/src/tls/tlsv1_server_i.h diff --git a/src/tls/tlsv1_server_read.c b/libeap/src/tls/tlsv1_server_read.c similarity index 100% rename from src/tls/tlsv1_server_read.c rename to libeap/src/tls/tlsv1_server_read.c diff --git a/src/tls/tlsv1_server_write.c b/libeap/src/tls/tlsv1_server_write.c similarity index 100% rename from src/tls/tlsv1_server_write.c rename to libeap/src/tls/tlsv1_server_write.c diff --git a/src/tls/x509v3.c b/libeap/src/tls/x509v3.c similarity index 100% rename from src/tls/x509v3.c rename to libeap/src/tls/x509v3.c diff --git a/src/tls/x509v3.h b/libeap/src/tls/x509v3.h similarity index 100% rename from src/tls/x509v3.h rename to libeap/src/tls/x509v3.h diff --git a/src/utils/.gitignore b/libeap/src/utils/.gitignore similarity index 100% rename from src/utils/.gitignore rename to libeap/src/utils/.gitignore diff --git a/src/utils/Makefile b/libeap/src/utils/Makefile similarity index 100% rename from src/utils/Makefile rename to libeap/src/utils/Makefile diff --git a/src/utils/base64.c b/libeap/src/utils/base64.c similarity index 100% rename from src/utils/base64.c rename to libeap/src/utils/base64.c diff --git a/src/utils/base64.h b/libeap/src/utils/base64.h similarity index 100% rename from src/utils/base64.h rename to libeap/src/utils/base64.h diff --git a/src/utils/bitfield.c b/libeap/src/utils/bitfield.c similarity index 100% rename from src/utils/bitfield.c rename to libeap/src/utils/bitfield.c diff --git a/src/utils/bitfield.h b/libeap/src/utils/bitfield.h similarity index 100% rename from src/utils/bitfield.h rename to libeap/src/utils/bitfield.h diff --git a/src/utils/browser-android.c b/libeap/src/utils/browser-android.c similarity index 100% rename from src/utils/browser-android.c rename to libeap/src/utils/browser-android.c diff --git a/src/utils/browser-system.c b/libeap/src/utils/browser-system.c similarity index 100% rename from src/utils/browser-system.c rename to libeap/src/utils/browser-system.c diff --git a/src/utils/browser-wpadebug.c b/libeap/src/utils/browser-wpadebug.c similarity index 100% rename from src/utils/browser-wpadebug.c rename to libeap/src/utils/browser-wpadebug.c diff --git a/src/utils/browser.c b/libeap/src/utils/browser.c similarity index 100% rename from src/utils/browser.c rename to libeap/src/utils/browser.c diff --git a/src/utils/browser.h b/libeap/src/utils/browser.h similarity index 100% rename from src/utils/browser.h rename to libeap/src/utils/browser.h diff --git a/src/utils/build_config.h b/libeap/src/utils/build_config.h similarity index 100% rename from src/utils/build_config.h rename to libeap/src/utils/build_config.h diff --git a/src/utils/common.c b/libeap/src/utils/common.c similarity index 100% rename from src/utils/common.c rename to libeap/src/utils/common.c diff --git a/libeap/src/utils/common.h b/libeap/src/utils/common.h new file mode 100644 index 0000000..13aa941 --- /dev/null +++ b/libeap/src/utils/common.h @@ -0,0 +1,568 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "os.h" + +#if defined(__linux__) || defined(__GLIBC__) +#include +#include +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__OpenBSD__) +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +#ifdef __OpenBSD__ +#define bswap_16 swap16 +#define bswap_32 swap32 +#define bswap_64 swap64 +#else /* __OpenBSD__ */ +#define bswap_16 bswap16 +#define bswap_32 bswap32 +#define bswap_64 bswap64 +#endif /* __OpenBSD__ */ +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || + * defined(__DragonFly__) || defined(__OpenBSD__) */ + +#ifdef __APPLE__ +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +static inline unsigned short bswap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int bswap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} +#endif /* __APPLE__ */ + +#ifdef CONFIG_NATIVE_WINDOWS +#ifdef CONFIG_IPV6 +#include +#include +#else +#include +#endif + +typedef int socklen_t; + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 /* not supported */ +#endif + +#endif /* CONFIG_NATIVE_WINDOWS */ + +#ifdef _MSC_VER +#ifndef __cplusplus +#define inline __inline +#endif + +#undef vsnprintf +#define vsnprintf _vsnprintf +#undef close +#define close closesocket +#endif /* _MSC_VER */ + + +/* Define platform specific integer types */ + +#ifdef _MSC_VER +typedef UINT64 u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef INT64 s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* _MSC_VER */ + +#ifdef __vxworks +typedef unsigned long long u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef long long s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* __vxworks */ + +#ifndef WPA_TYPES_DEFINED +#ifdef CONFIG_USE_INTTYPES_H +#include +#else +#include +#endif +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; +#define WPA_TYPES_DEFINED +#endif /* !WPA_TYPES_DEFINED */ + + +/* Define platform specific byte swapping macros */ + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) + +static inline unsigned short wpa_swap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int wpa_swap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} + +#define le_to_host16(n) (n) +#define host_to_le16(n) (n) +#define be_to_host16(n) wpa_swap_16(n) +#define host_to_be16(n) wpa_swap_16(n) +#define le_to_host32(n) (n) +#define host_to_le32(n) (n) +#define be_to_host32(n) wpa_swap_32(n) +#define host_to_be32(n) wpa_swap_32(n) + +#define WPA_BYTE_SWAP_DEFINED + +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ + + +#ifndef WPA_BYTE_SWAP_DEFINED + +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le_to_host16(n) ((__force u16) (le16) (n)) +#define host_to_le16(n) ((__force le16) (u16) (n)) +#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) +#define host_to_be16(n) ((__force be16) bswap_16((n))) +#define le_to_host32(n) ((__force u32) (le32) (n)) +#define host_to_le32(n) ((__force le32) (u32) (n)) +#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) +#define host_to_be32(n) ((__force be32) bswap_32((n))) +#define le_to_host64(n) ((__force u64) (le64) (n)) +#define host_to_le64(n) ((__force le64) (u64) (n)) +#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) +#define host_to_be64(n) ((__force be64) bswap_64((n))) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le_to_host16(n) bswap_16(n) +#define host_to_le16(n) bswap_16(n) +#define be_to_host16(n) (n) +#define host_to_be16(n) (n) +#define le_to_host32(n) bswap_32(n) +#define host_to_le32(n) bswap_32(n) +#define be_to_host32(n) (n) +#define host_to_be32(n) (n) +#define le_to_host64(n) bswap_64(n) +#define host_to_le64(n) bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#else +#error Could not determine CPU byte order +#endif + +#define WPA_BYTE_SWAP_DEFINED +#endif /* !WPA_BYTE_SWAP_DEFINED */ + + +/* Macros for handling unaligned memory accesses */ + +static inline u16 WPA_GET_BE16(const u8 *a) +{ + return (a[0] << 8) | a[1]; +} + +static inline void WPA_PUT_BE16(u8 *a, u16 val) +{ + a[0] = val >> 8; + a[1] = val & 0xff; +} + +static inline u16 WPA_GET_LE16(const u8 *a) +{ + return (a[1] << 8) | a[0]; +} + +static inline void WPA_PUT_LE16(u8 *a, u16 val) +{ + a[1] = val >> 8; + a[0] = val & 0xff; +} + +static inline u32 WPA_GET_BE24(const u8 *a) +{ + return (a[0] << 16) | (a[1] << 8) | a[2]; +} + +static inline void WPA_PUT_BE24(u8 *a, u32 val) +{ + a[0] = (val >> 16) & 0xff; + a[1] = (val >> 8) & 0xff; + a[2] = val & 0xff; +} + +static inline u32 WPA_GET_BE32(const u8 *a) +{ + return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; +} + +static inline void WPA_PUT_BE32(u8 *a, u32 val) +{ + a[0] = (val >> 24) & 0xff; + a[1] = (val >> 16) & 0xff; + a[2] = (val >> 8) & 0xff; + a[3] = val & 0xff; +} + +static inline u32 WPA_GET_LE32(const u8 *a) +{ + return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; +} + +static inline void WPA_PUT_LE32(u8 *a, u32 val) +{ + a[3] = (val >> 24) & 0xff; + a[2] = (val >> 16) & 0xff; + a[1] = (val >> 8) & 0xff; + a[0] = val & 0xff; +} + +static inline u64 WPA_GET_BE64(const u8 *a) +{ + return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) | + (((u64) a[2]) << 40) | (((u64) a[3]) << 32) | + (((u64) a[4]) << 24) | (((u64) a[5]) << 16) | + (((u64) a[6]) << 8) | ((u64) a[7]); +} + +static inline void WPA_PUT_BE64(u8 *a, u64 val) +{ + a[0] = val >> 56; + a[1] = val >> 48; + a[2] = val >> 40; + a[3] = val >> 32; + a[4] = val >> 24; + a[5] = val >> 16; + a[6] = val >> 8; + a[7] = val & 0xff; +} + +static inline u64 WPA_GET_LE64(const u8 *a) +{ + return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) | + (((u64) a[5]) << 40) | (((u64) a[4]) << 32) | + (((u64) a[3]) << 24) | (((u64) a[2]) << 16) | + (((u64) a[1]) << 8) | ((u64) a[0]); +} + +static inline void WPA_PUT_LE64(u8 *a, u64 val) +{ + a[7] = val >> 56; + a[6] = val >> 48; + a[5] = val >> 40; + a[4] = val >> 32; + a[3] = val >> 24; + a[2] = val >> 16; + a[1] = val >> 8; + a[0] = val & 0xff; +} + + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +#ifndef ETH_HLEN +#define ETH_HLEN 14 +#endif +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +#ifndef ETH_P_ALL +#define ETH_P_ALL 0x0003 +#endif +#ifndef ETH_P_80211_ENCAP +#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ +#endif +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL ETH_P_PAE +#endif /* ETH_P_EAPOL */ +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#define UNUSED __attribute__ ((unused)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#define UNUSED +#endif + + +#ifdef CONFIG_ANSI_C_EXTRA + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement + * due to possible buffer overflow; see, e.g., + * http://www.ijs.si/software/snprintf/ for portable implementation of + * snprintf. */ +int snprintf(char *str, size_t size, const char *format, ...); + +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ + +/* getopt - only used in main.c */ +int getopt(int argc, char *const argv[], const char *optstring); +extern char *optarg; +extern int optind; + +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF +#ifndef __socklen_t_defined +typedef int socklen_t; +#endif +#endif + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +/* + * Compact form for string representation of MAC address + * To be used, e.g., for constructing dbus paths for P2P Devices + */ +#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x" +#endif + +#ifndef BIT +#define BIT(x) (1U << (x)) +#endif + +/* + * Definitions for sparse validation + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) + */ +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef u16 __bitwise be16; +typedef u16 __bitwise le16; +typedef u32 __bitwise be32; +typedef u32 __bitwise le32; +typedef u64 __bitwise be64; +typedef u64 __bitwise le64; + +#ifndef __must_check +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif /* __GNUC__ */ +#endif /* __must_check */ + +#ifndef __maybe_unused +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __maybe_unused __attribute__((unused)) +#else +#define __maybe_unused +#endif /* __GNUC__ */ +#endif /* __must_check */ + +int hwaddr_aton(const char *txt, u8 *addr); +int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); +int hwaddr_compact_aton(const char *txt, u8 *addr); +int hwaddr_aton2(const char *txt, u8 *addr); +int hex2byte(const char *hex); +int hexstr2bin(const char *hex, u8 *buf, size_t len); +void inc_byte_array(u8 *counter, size_t len); +void wpa_get_ntp_timestamp(u8 *buf); +int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...); +int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, + char sep); +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + +int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask); + +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + +void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len); +size_t printf_decode(u8 *buf, size_t maxlen, const char *str); + +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); + +char * wpa_config_parse_string(const char *value, size_t *len); +int is_hex(const u8 *data, size_t len); +size_t merge_byte_arrays(u8 *res, size_t res_len, + const u8 *src1, size_t src1_len, + const u8 *src2, size_t src2_len); +char * dup_binstr(const void *src, size_t len); + +static inline int is_zero_ether_addr(const u8 *a) +{ + return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); +} + +static inline int is_broadcast_ether_addr(const u8 *a) +{ + return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; +} + +static inline int is_multicast_ether_addr(const u8 *a) +{ + return a[0] & 0x01; +} + +#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" + +#include "wpa_debug.h" + + +struct wpa_freq_range_list { + struct wpa_freq_range { + unsigned int min; + unsigned int max; + } *range; + unsigned int num; +}; + +int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value); +int freq_range_list_includes(const struct wpa_freq_range_list *list, + unsigned int freq); +char * freq_range_list_str(const struct wpa_freq_range_list *list); + +int int_array_len(const int *a); +void int_array_concat(int **res, const int *a); +void int_array_sort_unique(int *a); +void int_array_add_unique(int **res, int a); + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +void str_clear_free(char *str); +void bin_clear_free(void *bin, size_t len); + +int random_mac_addr(u8 *addr); +int random_mac_addr_keep_oui(u8 *addr); + +const char * cstr_token(const char *str, const char *delim, const char **last); +char * str_token(char *str, const char *delim, char **context); +size_t utf8_escape(const char *inp, size_t in_size, + char *outp, size_t out_size); +size_t utf8_unescape(const char *inp, size_t in_size, + char *outp, size_t out_size); +int is_ctrl_char(char c); + + +/* + * gcc 4.4 ends up generating strict-aliasing warnings about some very common + * networking socket uses that do not really result in a real problem and + * cannot be easily avoided with union-based type-punning due to struct + * definitions including another struct in system header files. To avoid having + * to fully disable strict-aliasing warnings, provide a mechanism to hide the + * typecast from aliasing for now. A cleaner solution will hopefully be found + * in the future to handle these cases. + */ +void * __hide_aliasing_typecast(void *foo); +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) + +#ifdef CONFIG_VALGRIND +#include +#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* CONFIG_VALGRIND */ +#define WPA_MEM_DEFINED(ptr, len) do { } while (0) +#endif /* CONFIG_VALGRIND */ + +#endif /* COMMON_H */ diff --git a/src/utils/edit.c b/libeap/src/utils/edit.c similarity index 100% rename from src/utils/edit.c rename to libeap/src/utils/edit.c diff --git a/src/utils/edit.h b/libeap/src/utils/edit.h similarity index 100% rename from src/utils/edit.h rename to libeap/src/utils/edit.h diff --git a/src/utils/edit_readline.c b/libeap/src/utils/edit_readline.c similarity index 100% rename from src/utils/edit_readline.c rename to libeap/src/utils/edit_readline.c diff --git a/src/utils/edit_simple.c b/libeap/src/utils/edit_simple.c similarity index 100% rename from src/utils/edit_simple.c rename to libeap/src/utils/edit_simple.c diff --git a/src/utils/eloop.c b/libeap/src/utils/eloop.c similarity index 100% rename from src/utils/eloop.c rename to libeap/src/utils/eloop.c diff --git a/src/utils/eloop.h b/libeap/src/utils/eloop.h similarity index 100% rename from src/utils/eloop.h rename to libeap/src/utils/eloop.h diff --git a/src/utils/eloop_win.c b/libeap/src/utils/eloop_win.c similarity index 100% rename from src/utils/eloop_win.c rename to libeap/src/utils/eloop_win.c diff --git a/src/utils/ext_password.c b/libeap/src/utils/ext_password.c similarity index 100% rename from src/utils/ext_password.c rename to libeap/src/utils/ext_password.c diff --git a/src/utils/ext_password.h b/libeap/src/utils/ext_password.h similarity index 100% rename from src/utils/ext_password.h rename to libeap/src/utils/ext_password.h diff --git a/src/utils/ext_password_i.h b/libeap/src/utils/ext_password_i.h similarity index 100% rename from src/utils/ext_password_i.h rename to libeap/src/utils/ext_password_i.h diff --git a/src/utils/ext_password_test.c b/libeap/src/utils/ext_password_test.c similarity index 100% rename from src/utils/ext_password_test.c rename to libeap/src/utils/ext_password_test.c diff --git a/src/utils/http-utils.h b/libeap/src/utils/http-utils.h similarity index 100% rename from src/utils/http-utils.h rename to libeap/src/utils/http-utils.h diff --git a/src/utils/http_curl.c b/libeap/src/utils/http_curl.c similarity index 100% rename from src/utils/http_curl.c rename to libeap/src/utils/http_curl.c diff --git a/src/utils/includes.h b/libeap/src/utils/includes.h similarity index 100% rename from src/utils/includes.h rename to libeap/src/utils/includes.h diff --git a/src/utils/ip_addr.c b/libeap/src/utils/ip_addr.c similarity index 100% rename from src/utils/ip_addr.c rename to libeap/src/utils/ip_addr.c diff --git a/src/utils/ip_addr.h b/libeap/src/utils/ip_addr.h similarity index 100% rename from src/utils/ip_addr.h rename to libeap/src/utils/ip_addr.h diff --git a/src/utils/list.h b/libeap/src/utils/list.h similarity index 100% rename from src/utils/list.h rename to libeap/src/utils/list.h diff --git a/src/utils/os.h b/libeap/src/utils/os.h similarity index 100% rename from src/utils/os.h rename to libeap/src/utils/os.h diff --git a/src/utils/os_internal.c b/libeap/src/utils/os_internal.c similarity index 100% rename from src/utils/os_internal.c rename to libeap/src/utils/os_internal.c diff --git a/src/utils/os_none.c b/libeap/src/utils/os_none.c similarity index 100% rename from src/utils/os_none.c rename to libeap/src/utils/os_none.c diff --git a/src/utils/os_unix.c b/libeap/src/utils/os_unix.c similarity index 100% rename from src/utils/os_unix.c rename to libeap/src/utils/os_unix.c diff --git a/src/utils/os_win32.c b/libeap/src/utils/os_win32.c similarity index 100% rename from src/utils/os_win32.c rename to libeap/src/utils/os_win32.c diff --git a/src/utils/pcsc_funcs.c b/libeap/src/utils/pcsc_funcs.c similarity index 100% rename from src/utils/pcsc_funcs.c rename to libeap/src/utils/pcsc_funcs.c diff --git a/src/utils/pcsc_funcs.h b/libeap/src/utils/pcsc_funcs.h similarity index 100% rename from src/utils/pcsc_funcs.h rename to libeap/src/utils/pcsc_funcs.h diff --git a/src/utils/platform.h b/libeap/src/utils/platform.h similarity index 100% rename from src/utils/platform.h rename to libeap/src/utils/platform.h diff --git a/src/utils/radiotap.c b/libeap/src/utils/radiotap.c similarity index 100% rename from src/utils/radiotap.c rename to libeap/src/utils/radiotap.c diff --git a/src/utils/radiotap.h b/libeap/src/utils/radiotap.h similarity index 100% rename from src/utils/radiotap.h rename to libeap/src/utils/radiotap.h diff --git a/src/utils/radiotap_iter.h b/libeap/src/utils/radiotap_iter.h similarity index 100% rename from src/utils/radiotap_iter.h rename to libeap/src/utils/radiotap_iter.h diff --git a/libeap/src/utils/radius_utils.c b/libeap/src/utils/radius_utils.c new file mode 100644 index 0000000..b5b8e80 --- /dev/null +++ b/libeap/src/utils/radius_utils.c @@ -0,0 +1,133 @@ +/* + * RADIUS tlv construction and parsing utilites + * Copyright (c) 2012, Painless Security, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" + +#include "radius/radius.h" +#include "radius_utils.h" +#include "wpabuf.h" + +int radius_add_tlv(struct wpabuf **buf, u32 type, u32 vendor, u8 *data, + size_t len) +{ + u8 base_type; + u8 total; + if (vendor) { + if (len + 6 > RADIUS_MAX_ATTR_LEN) + return -1; + total = len + 2 + 6; + base_type = RADIUS_ATTR_VENDOR_SPECIFIC; + } else { + if (len > RADIUS_MAX_ATTR_LEN) + return -1; + total = len + 2; + base_type = type; + } + + /* ensure buffer has enough space */ + if (wpabuf_resize(buf, total)) + return -1; + + /* write into buffer */ + wpabuf_put_u8(*buf, base_type); + wpabuf_put_u8(*buf, total); + if (vendor) { + wpabuf_put_be32(*buf, vendor); + wpabuf_put_u8(*buf, (u8 )type); + wpabuf_put_u8(*buf, (u8 )len+2); + } + wpabuf_put_data(*buf, data, len); + return 0; +} + +struct radius_parser_struct +{ + u8 *data; + size_t len; + size_t pos; +}; + +radius_parser radius_parser_start(void *tlvdata, size_t len) +{ + radius_parser parser = malloc(sizeof(struct radius_parser_struct)); + if (parser) { + parser->data = (u8 *)tlvdata; + parser->len = len; + parser->pos = 0; + } + return parser; +} + +void radius_parser_finish(radius_parser parser) +{ + free(parser); +} + +int radius_parser_parse_tlv(radius_parser parser, u8 *type, u32 *vendor_id, + void **value, size_t *len) +{ + u8 rawtype, rawlen; + if (!parser) + return -1; + if (parser->len < parser->pos + 3) + return -1; + rawtype = parser->data[parser->pos]; + rawlen = parser->data[parser->pos+1]; + if (parser->len < parser->pos + rawlen) + return -1; + + if (rawtype == RADIUS_ATTR_VENDOR_SPECIFIC) { + if (rawlen < 7) + return -1; + *vendor_id = WPA_GET_BE24(&parser->data[parser->pos + 3]); + *value = &parser->data[parser->pos + 6]; + *len = rawlen - 6; + } else { + if (rawlen < 3) + return -1; + + *value = &parser->data[parser->pos + 2]; + *len = rawlen - 2; + } + *type = rawtype; + + parser->pos += rawlen; + return 0; +} + +int radius_parser_parse_vendor_specific(radius_parser parser, u8 *vendor_type, + void **value, size_t *len) +{ + u8 rawtype, rawlen; + if (!parser) + return -1; + if (parser->len < parser->pos + 3) + return -1; + rawtype = parser->data[parser->pos]; + rawlen = parser->data[parser->pos+1]; + if (parser->len < parser->pos + rawlen) + return -1; + + if (rawlen < 3) + return -1; + + *value = &parser->data[parser->pos + 2]; + *len = rawlen - 2; + *vendor_type = rawtype; + + parser->pos += rawlen; + return 0; +} diff --git a/libeap/src/utils/radius_utils.h b/libeap/src/utils/radius_utils.h new file mode 100644 index 0000000..b0560a4 --- /dev/null +++ b/libeap/src/utils/radius_utils.h @@ -0,0 +1,75 @@ +/* + * RADIUS tlv construction and parsing utilites + * Copyright (c) 2012, Painless Security, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef RADIUS_UTILS_H +#define RADIUS_UTILS_H + +struct wpabuf; +struct radius_parser_struct; +typedef struct radius_parser_struct *radius_parser; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Simple utility to add a single type-length-value attribute to a buffer. + * Currently, there is no dictionary support: 'type' and 'len' are always + * assumed to be octets, and data is placed directly into buf untranslated + * for byte order. If vendor is zero, len should be no greater than 253 + * otherwise, no greater than 247. + * returns 0 on success, -1 on failure (allocation failure or len too large) + */ +int radius_add_tlv(struct wpabuf **buf, u32 type, u32 vendor, u8 *data, + size_t len); + +/* + * simple radius parser + * Could be made considerably simpler by dropping support for parsing multiple + * sub-attributes from a vsa. + */ + +/* + * create parser object + */ +radius_parser radius_parser_start(void *tlvdata, size_t len); + +/* + * parse a single tlv; + * There is no dictionary support; if the tlv is a vsa (attribute 26), + * sub-attributes are not immediately parsed: instead, the raw data is returned + * in 'value'. + * returns 0 on success, -1 on failure (malformed buffer or end of buffer) + */ +int radius_parser_parse_tlv(radius_parser parser, u8 *type, u32 *vendor_id, + void **value, size_t *len); + +/* + * parse a single sub-attribute of a vsa: assumes octets for + * vendor_type and len + * returns 0 on success, -1 on failure (malformed buffer or end of buffer) + */ +int radius_parser_parse_vendor_specific(radius_parser parser, u8 *vendor_type, + void **value, size_t *len); + +/* + * destroy parser object + */ +void radius_parser_finish(radius_parser parser); + +#ifdef __cplusplus +} +#endif + +#endif /* RADIUS_UTILS_H */ \ No newline at end of file diff --git a/src/utils/state_machine.h b/libeap/src/utils/state_machine.h similarity index 100% rename from src/utils/state_machine.h rename to libeap/src/utils/state_machine.h diff --git a/src/utils/trace.c b/libeap/src/utils/trace.c similarity index 100% rename from src/utils/trace.c rename to libeap/src/utils/trace.c diff --git a/src/utils/trace.h b/libeap/src/utils/trace.h similarity index 100% rename from src/utils/trace.h rename to libeap/src/utils/trace.h diff --git a/src/utils/utils_module_tests.c b/libeap/src/utils/utils_module_tests.c similarity index 100% rename from src/utils/utils_module_tests.c rename to libeap/src/utils/utils_module_tests.c diff --git a/src/utils/uuid.c b/libeap/src/utils/uuid.c similarity index 100% rename from src/utils/uuid.c rename to libeap/src/utils/uuid.c diff --git a/src/utils/uuid.h b/libeap/src/utils/uuid.h similarity index 100% rename from src/utils/uuid.h rename to libeap/src/utils/uuid.h diff --git a/src/utils/wpa_debug.c b/libeap/src/utils/wpa_debug.c similarity index 100% rename from src/utils/wpa_debug.c rename to libeap/src/utils/wpa_debug.c diff --git a/libeap/src/utils/wpa_debug.h b/libeap/src/utils/wpa_debug.h new file mode 100644 index 0000000..2dfc388 --- /dev/null +++ b/libeap/src/utils/wpa_debug.h @@ -0,0 +1,383 @@ +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_DEBUG_H +#define WPA_DEBUG_H + +#include "wpabuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + + +/* Debugging function - conditional printf and hex dump. Driver wrappers can + * use these for debugging purposes. */ + +enum { + MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR +}; + +#ifdef CONFIG_NO_STDOUT_DEBUG + +#define wpa_debug_print_timestamp() do { } while (0) +#define wpa_printf(args...) do { } while (0) +#define wpa_hexdump(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf(l,t,b) do { } while (0) +#define wpa_hexdump_key(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf_key(l,t,b) do { } while (0) +#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) +#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) +#define wpa_debug_open_file(p) do { } while (0) +#define wpa_debug_close_file() do { } while (0) +#define wpa_debug_setup_stdout() do { } while (0) +#define wpa_dbg(args...) do { } while (0) + +static inline int wpa_debug_reopen_file(void) +{ + return 0; +} + +#else /* CONFIG_NO_STDOUT_DEBUG */ + +int wpa_debug_open_file(const char *path); +int wpa_debug_reopen_file(void); +void wpa_debug_close_file(void); +void wpa_debug_setup_stdout(void); + +/** + * wpa_debug_printf_timestamp - Print timestamp for debug output + * + * This function prints a timestamp in seconds_from_1970.microsoconds + * format if debug output has been configured to include timestamps in debug + * messages. + */ +void wpa_debug_print_timestamp(void); + +/** + * wpa_printf - conditional printf + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_printf(int level, const char *fmt, ...) +PRINTF_FORMAT(2, 3); + +/** + * wpa_hexdump - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. + */ +void wpa_hexdump(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf(int level, const char *title, + const struct wpabuf *buf) +{ +//!!LOCAL wpa_hexdump(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf)); + + wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL, + buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. This works + * like wpa_hexdump(), but by default, does not include secret keys (passwords, + * etc.) in debug output. + */ +void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf_key(int level, const char *title, + const struct wpabuf *buf) +{ +//!! LOCAL wpa_hexdump_key(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf)); + + wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL, + buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_ascii - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. + */ +void wpa_hexdump_ascii(int level, const char *title, const void *buf, + size_t len); + +/** + * wpa_hexdump_ascii_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by + * default, does not include secret keys (passwords, etc.) in debug output. + */ +void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, + size_t len); + +/* + * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce + * binary size. As such, it should be used with debugging messages that are not + * needed in the control interface while wpa_msg() has to be used for anything + * that needs to shown to control interface monitors. + */ +#define wpa_dbg(args...) wpa_msg(args) + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifdef CONFIG_NO_WPA_MSG +#define wpa_msg(args...) do { } while (0) +#define wpa_msg_ctrl(args...) do { } while (0) +#define wpa_msg_global(args...) do { } while (0) +#define wpa_msg_global_ctrl(args...) do { } while (0) +#define wpa_msg_no_global(args...) do { } while (0) +#define wpa_msg_global_only(args...) do { } while (0) +#define wpa_msg_register_cb(f) do { } while (0) +#define wpa_msg_register_ifname_cb(f) do { } while (0) +#else /* CONFIG_NO_WPA_MSG */ +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. This function is like wpa_printf(), but it also sends the + * same message to all attached ctrl_iface monitors. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output only to the + * attached ctrl_iface monitors. In other words, it can be used for frequent + * events that do not need to be sent to syslog. + */ +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global - Global printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output as a global event, + * i.e., without being specific to an interface. For backwards compatibility, + * an old style event is also delivered on one of the interfaces (the one + * specified by the context data). + */ +void wpa_msg_global(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only to the + * attached global ctrl_iface monitors. In other words, it can be used for + * frequent events that do not need to be sent to syslog. + */ +void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_no_global - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it does not send the output as a global + * event. + */ +void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global_only - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only as a + * global event. + */ +void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +enum wpa_msg_type { + WPA_MSG_PER_INTERFACE, + WPA_MSG_GLOBAL, + WPA_MSG_NO_GLOBAL, + WPA_MSG_ONLY_GLOBAL, +}; + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type, + const char *txt, size_t len); + +/** + * wpa_msg_register_cb - Register callback function for wpa_msg() messages + * @func: Callback function (%NULL to unregister) + */ +void wpa_msg_register_cb(wpa_msg_cb_func func); + +typedef const char * (*wpa_msg_get_ifname_func)(void *ctx); +void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func); + +#endif /* CONFIG_NO_WPA_MSG */ + +#ifdef CONFIG_NO_HOSTAPD_LOGGER +#define hostapd_logger(args...) do { } while (0) +#define hostapd_logger_register_cb(f) do { } while (0) +#else /* CONFIG_NO_HOSTAPD_LOGGER */ +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, + const char *fmt, ...) PRINTF_FORMAT(5, 6); + +typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, + unsigned int module, int level, + const char *txt, size_t len); + +/** + * hostapd_logger_register_cb - Register callback function for hostapd_logger() + * @func: Callback function (%NULL to unregister) + */ +void hostapd_logger_register_cb(hostapd_logger_cb_func func); +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ + +#define HOSTAPD_MODULE_IEEE80211 0x00000001 +#define HOSTAPD_MODULE_IEEE8021X 0x00000002 +#define HOSTAPD_MODULE_RADIUS 0x00000004 +#define HOSTAPD_MODULE_WPA 0x00000008 +#define HOSTAPD_MODULE_DRIVER 0x00000010 +#define HOSTAPD_MODULE_IAPP 0x00000020 +#define HOSTAPD_MODULE_MLME 0x00000040 + +enum hostapd_logger_level { + HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, + HOSTAPD_LEVEL_DEBUG = 1, + HOSTAPD_LEVEL_INFO = 2, + HOSTAPD_LEVEL_NOTICE = 3, + HOSTAPD_LEVEL_WARNING = 4 +}; + + +#ifdef CONFIG_DEBUG_SYSLOG + +void wpa_debug_open_syslog(void); +void wpa_debug_close_syslog(void); + +#else /* CONFIG_DEBUG_SYSLOG */ + +static inline void wpa_debug_open_syslog(void) +{ +} + +static inline void wpa_debug_close_syslog(void) +{ +} + +#endif /* CONFIG_DEBUG_SYSLOG */ + +#ifdef CONFIG_DEBUG_LINUX_TRACING + +int wpa_debug_open_linux_tracing(void); +void wpa_debug_close_linux_tracing(void); + +#else /* CONFIG_DEBUG_LINUX_TRACING */ + +static inline int wpa_debug_open_linux_tracing(void) +{ + return 0; +} + +static inline void wpa_debug_close_linux_tracing(void) +{ +} + +#endif /* CONFIG_DEBUG_LINUX_TRACING */ + + +#ifdef EAPOL_TEST +#define WPA_ASSERT(a) \ + do { \ + if (!(a)) { \ + printf("WPA_ASSERT FAILED '" #a "' " \ + "%s %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + exit(1); \ + } \ + } while (0) +#else +#define WPA_ASSERT(a) do { } while (0) +#endif + +const char * debug_level_str(int level); +int str_to_debug_level(const char *s); + +#ifdef __cplusplus +} +#endif + +#endif /* WPA_DEBUG_H */ diff --git a/src/utils/wpabuf.c b/libeap/src/utils/wpabuf.c similarity index 100% rename from src/utils/wpabuf.c rename to libeap/src/utils/wpabuf.c diff --git a/libeap/src/utils/wpabuf.h b/libeap/src/utils/wpabuf.h new file mode 100644 index 0000000..64b3d8d --- /dev/null +++ b/libeap/src/utils/wpabuf.h @@ -0,0 +1,171 @@ +/* + * Dynamic data buffer + * Copyright (c) 2007-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPABUF_H +#define WPABUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* wpabuf::buf is a pointer to external data */ +#define WPABUF_FLAG_EXT_DATA BIT(0) + +/* + * Internal data structure for wpabuf. Please do not touch this directly from + * elsewhere. This is only defined in header file to allow inline functions + * from this file to access data. + */ +struct wpabuf { + size_t size; /* total size of the allocated buffer */ + size_t used; /* length of data in the buffer */ + u8 *buf; /* pointer to the head of the buffer */ + unsigned int flags; + /* optionally followed by the allocated buffer */ +}; + + +int wpabuf_resize(struct wpabuf **buf, size_t add_len); +struct wpabuf * wpabuf_alloc(size_t len); +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); +struct wpabuf * wpabuf_dup(const struct wpabuf *src); +void wpabuf_free(struct wpabuf *buf); +void wpabuf_clear_free(struct wpabuf *buf); +void * wpabuf_put(struct wpabuf *buf, size_t len); +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); + + +/** + * wpabuf_size - Get the currently allocated size of a wpabuf buffer + * @buf: wpabuf buffer + * Returns: Currently allocated size of the buffer + */ +static inline size_t wpabuf_size(const struct wpabuf *buf) +{ + return buf->size; +} + +/** + * wpabuf_len - Get the current length of a wpabuf buffer data + * @buf: wpabuf buffer + * Returns: Currently used length of the buffer + */ +static inline size_t wpabuf_len(const struct wpabuf *buf) +{ + return buf->used; +} + +/** + * wpabuf_tailroom - Get size of available tail room in the end of the buffer + * @buf: wpabuf buffer + * Returns: Tail room (in bytes) of available space in the end of the buffer + */ +static inline size_t wpabuf_tailroom(const struct wpabuf *buf) +{ + return buf->size - buf->used; +} + +/** + * wpabuf_head - Get pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline const void * wpabuf_head(const struct wpabuf *buf) +{ + return buf->buf; +} + +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) +{ + return (const u8 *)wpabuf_head(buf); +} + +/** + * wpabuf_mhead - Get modifiable pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline void * wpabuf_mhead(struct wpabuf *buf) +{ + return buf->buf; +} + +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) +{ + return (u8 *)wpabuf_mhead(buf); +} + +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 1); + *pos = data; +} + +static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 2); + WPA_PUT_LE16(pos, data); +} + +static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 4); + WPA_PUT_LE32(pos, data); +} + +static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 2); + WPA_PUT_BE16(pos, data); +} + +static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 3); + WPA_PUT_BE24(pos, data); +} + +static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 4); + WPA_PUT_BE32(pos, data); +} + +static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, + size_t len) +{ + if (data) + os_memcpy(wpabuf_put(buf, len), data, len); +} + +static inline void wpabuf_put_buf(struct wpabuf *dst, + const struct wpabuf *src) +{ + wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); +} + +static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) +{ + buf->buf = (u8 *) data; + buf->flags = WPABUF_FLAG_EXT_DATA; + buf->size = buf->used = len; +} + +static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) +{ + wpabuf_put_data(dst, str, os_strlen(str)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* WPABUF_H */ diff --git a/src/utils/xml-utils.c b/libeap/src/utils/xml-utils.c similarity index 100% rename from src/utils/xml-utils.c rename to libeap/src/utils/xml-utils.c diff --git a/src/utils/xml-utils.h b/libeap/src/utils/xml-utils.h similarity index 100% rename from src/utils/xml-utils.h rename to libeap/src/utils/xml-utils.h diff --git a/src/utils/xml_libxml2.c b/libeap/src/utils/xml_libxml2.c similarity index 100% rename from src/utils/xml_libxml2.c rename to libeap/src/utils/xml_libxml2.c diff --git a/src/wps/Makefile b/libeap/src/wps/Makefile similarity index 100% rename from src/wps/Makefile rename to libeap/src/wps/Makefile diff --git a/src/wps/http.h b/libeap/src/wps/http.h similarity index 100% rename from src/wps/http.h rename to libeap/src/wps/http.h diff --git a/src/wps/http_client.c b/libeap/src/wps/http_client.c similarity index 100% rename from src/wps/http_client.c rename to libeap/src/wps/http_client.c diff --git a/src/wps/http_client.h b/libeap/src/wps/http_client.h similarity index 100% rename from src/wps/http_client.h rename to libeap/src/wps/http_client.h diff --git a/src/wps/http_server.c b/libeap/src/wps/http_server.c similarity index 100% rename from src/wps/http_server.c rename to libeap/src/wps/http_server.c diff --git a/src/wps/http_server.h b/libeap/src/wps/http_server.h similarity index 100% rename from src/wps/http_server.h rename to libeap/src/wps/http_server.h diff --git a/src/wps/httpread.c b/libeap/src/wps/httpread.c similarity index 100% rename from src/wps/httpread.c rename to libeap/src/wps/httpread.c diff --git a/src/wps/httpread.h b/libeap/src/wps/httpread.h similarity index 100% rename from src/wps/httpread.h rename to libeap/src/wps/httpread.h diff --git a/src/wps/ndef.c b/libeap/src/wps/ndef.c similarity index 100% rename from src/wps/ndef.c rename to libeap/src/wps/ndef.c diff --git a/src/wps/upnp_xml.c b/libeap/src/wps/upnp_xml.c similarity index 100% rename from src/wps/upnp_xml.c rename to libeap/src/wps/upnp_xml.c diff --git a/src/wps/upnp_xml.h b/libeap/src/wps/upnp_xml.h similarity index 100% rename from src/wps/upnp_xml.h rename to libeap/src/wps/upnp_xml.h diff --git a/src/wps/wps.c b/libeap/src/wps/wps.c similarity index 100% rename from src/wps/wps.c rename to libeap/src/wps/wps.c diff --git a/src/wps/wps.h b/libeap/src/wps/wps.h similarity index 100% rename from src/wps/wps.h rename to libeap/src/wps/wps.h diff --git a/src/wps/wps_attr_build.c b/libeap/src/wps/wps_attr_build.c similarity index 100% rename from src/wps/wps_attr_build.c rename to libeap/src/wps/wps_attr_build.c diff --git a/src/wps/wps_attr_parse.c b/libeap/src/wps/wps_attr_parse.c similarity index 100% rename from src/wps/wps_attr_parse.c rename to libeap/src/wps/wps_attr_parse.c diff --git a/src/wps/wps_attr_parse.h b/libeap/src/wps/wps_attr_parse.h similarity index 100% rename from src/wps/wps_attr_parse.h rename to libeap/src/wps/wps_attr_parse.h diff --git a/src/wps/wps_attr_process.c b/libeap/src/wps/wps_attr_process.c similarity index 100% rename from src/wps/wps_attr_process.c rename to libeap/src/wps/wps_attr_process.c diff --git a/src/wps/wps_common.c b/libeap/src/wps/wps_common.c similarity index 100% rename from src/wps/wps_common.c rename to libeap/src/wps/wps_common.c diff --git a/src/wps/wps_defs.h b/libeap/src/wps/wps_defs.h similarity index 100% rename from src/wps/wps_defs.h rename to libeap/src/wps/wps_defs.h diff --git a/src/wps/wps_dev_attr.c b/libeap/src/wps/wps_dev_attr.c similarity index 100% rename from src/wps/wps_dev_attr.c rename to libeap/src/wps/wps_dev_attr.c diff --git a/src/wps/wps_dev_attr.h b/libeap/src/wps/wps_dev_attr.h similarity index 100% rename from src/wps/wps_dev_attr.h rename to libeap/src/wps/wps_dev_attr.h diff --git a/src/wps/wps_enrollee.c b/libeap/src/wps/wps_enrollee.c similarity index 100% rename from src/wps/wps_enrollee.c rename to libeap/src/wps/wps_enrollee.c diff --git a/src/wps/wps_er.c b/libeap/src/wps/wps_er.c similarity index 100% rename from src/wps/wps_er.c rename to libeap/src/wps/wps_er.c diff --git a/src/wps/wps_er.h b/libeap/src/wps/wps_er.h similarity index 100% rename from src/wps/wps_er.h rename to libeap/src/wps/wps_er.h diff --git a/src/wps/wps_er_ssdp.c b/libeap/src/wps/wps_er_ssdp.c similarity index 100% rename from src/wps/wps_er_ssdp.c rename to libeap/src/wps/wps_er_ssdp.c diff --git a/src/wps/wps_i.h b/libeap/src/wps/wps_i.h similarity index 100% rename from src/wps/wps_i.h rename to libeap/src/wps/wps_i.h diff --git a/src/wps/wps_module_tests.c b/libeap/src/wps/wps_module_tests.c similarity index 100% rename from src/wps/wps_module_tests.c rename to libeap/src/wps/wps_module_tests.c diff --git a/src/wps/wps_registrar.c b/libeap/src/wps/wps_registrar.c similarity index 100% rename from src/wps/wps_registrar.c rename to libeap/src/wps/wps_registrar.c diff --git a/src/wps/wps_upnp.c b/libeap/src/wps/wps_upnp.c similarity index 100% rename from src/wps/wps_upnp.c rename to libeap/src/wps/wps_upnp.c diff --git a/src/wps/wps_upnp.h b/libeap/src/wps/wps_upnp.h similarity index 100% rename from src/wps/wps_upnp.h rename to libeap/src/wps/wps_upnp.h diff --git a/src/wps/wps_upnp_ap.c b/libeap/src/wps/wps_upnp_ap.c similarity index 100% rename from src/wps/wps_upnp_ap.c rename to libeap/src/wps/wps_upnp_ap.c diff --git a/src/wps/wps_upnp_event.c b/libeap/src/wps/wps_upnp_event.c similarity index 100% rename from src/wps/wps_upnp_event.c rename to libeap/src/wps/wps_upnp_event.c diff --git a/src/wps/wps_upnp_i.h b/libeap/src/wps/wps_upnp_i.h similarity index 100% rename from src/wps/wps_upnp_i.h rename to libeap/src/wps/wps_upnp_i.h diff --git a/src/wps/wps_upnp_ssdp.c b/libeap/src/wps/wps_upnp_ssdp.c similarity index 100% rename from src/wps/wps_upnp_ssdp.c rename to libeap/src/wps/wps_upnp_ssdp.c diff --git a/src/wps/wps_upnp_web.c b/libeap/src/wps/wps_upnp_web.c similarity index 100% rename from src/wps/wps_upnp_web.c rename to libeap/src/wps/wps_upnp_web.c diff --git a/src/wps/wps_validate.c b/libeap/src/wps/wps_validate.c similarity index 100% rename from src/wps/wps_validate.c rename to libeap/src/wps/wps_validate.c diff --git a/tests/.gitignore b/libeap/tests/.gitignore similarity index 100% rename from tests/.gitignore rename to libeap/tests/.gitignore diff --git a/tests/Makefile b/libeap/tests/Makefile similarity index 100% rename from tests/Makefile rename to libeap/tests/Makefile diff --git a/tests/ap-mgmt-fuzzer/Makefile b/libeap/tests/ap-mgmt-fuzzer/Makefile similarity index 100% rename from tests/ap-mgmt-fuzzer/Makefile rename to libeap/tests/ap-mgmt-fuzzer/Makefile diff --git a/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c b/libeap/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c similarity index 100% rename from tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c rename to libeap/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c diff --git a/tests/ap-mgmt-fuzzer/auth.dat b/libeap/tests/ap-mgmt-fuzzer/auth.dat similarity index 100% rename from tests/ap-mgmt-fuzzer/auth.dat rename to libeap/tests/ap-mgmt-fuzzer/auth.dat diff --git a/tests/ap-mgmt-fuzzer/probe-req.dat b/libeap/tests/ap-mgmt-fuzzer/probe-req.dat similarity index 100% rename from tests/ap-mgmt-fuzzer/probe-req.dat rename to libeap/tests/ap-mgmt-fuzzer/probe-req.dat diff --git a/tests/eapol-fuzzer/Makefile b/libeap/tests/eapol-fuzzer/Makefile similarity index 100% rename from tests/eapol-fuzzer/Makefile rename to libeap/tests/eapol-fuzzer/Makefile diff --git a/tests/eapol-fuzzer/eap-req-identity.dat b/libeap/tests/eapol-fuzzer/eap-req-identity.dat similarity index 100% rename from tests/eapol-fuzzer/eap-req-identity.dat rename to libeap/tests/eapol-fuzzer/eap-req-identity.dat diff --git a/tests/eapol-fuzzer/eap-req-sim.dat b/libeap/tests/eapol-fuzzer/eap-req-sim.dat similarity index 100% rename from tests/eapol-fuzzer/eap-req-sim.dat rename to libeap/tests/eapol-fuzzer/eap-req-sim.dat diff --git a/tests/eapol-fuzzer/eapol-fuzzer.c b/libeap/tests/eapol-fuzzer/eapol-fuzzer.c similarity index 100% rename from tests/eapol-fuzzer/eapol-fuzzer.c rename to libeap/tests/eapol-fuzzer/eapol-fuzzer.c diff --git a/tests/eapol-fuzzer/eapol-key-m1.dat b/libeap/tests/eapol-fuzzer/eapol-key-m1.dat similarity index 100% rename from tests/eapol-fuzzer/eapol-key-m1.dat rename to libeap/tests/eapol-fuzzer/eapol-key-m1.dat diff --git a/tests/hwsim/README b/libeap/tests/hwsim/README similarity index 100% rename from tests/hwsim/README rename to libeap/tests/hwsim/README diff --git a/tests/hwsim/auth_serv/as.conf b/libeap/tests/hwsim/auth_serv/as.conf similarity index 100% rename from tests/hwsim/auth_serv/as.conf rename to libeap/tests/hwsim/auth_serv/as.conf diff --git a/tests/hwsim/auth_serv/as2.conf b/libeap/tests/hwsim/auth_serv/as2.conf similarity index 100% rename from tests/hwsim/auth_serv/as2.conf rename to libeap/tests/hwsim/auth_serv/as2.conf diff --git a/tests/hwsim/auth_serv/ca-and-crl.pem b/libeap/tests/hwsim/auth_serv/ca-and-crl.pem similarity index 100% rename from tests/hwsim/auth_serv/ca-and-crl.pem rename to libeap/tests/hwsim/auth_serv/ca-and-crl.pem diff --git a/tests/hwsim/auth_serv/ca-incorrect.pem b/libeap/tests/hwsim/auth_serv/ca-incorrect.pem similarity index 100% rename from tests/hwsim/auth_serv/ca-incorrect.pem rename to libeap/tests/hwsim/auth_serv/ca-incorrect.pem diff --git a/tests/hwsim/auth_serv/ca.der b/libeap/tests/hwsim/auth_serv/ca.der similarity index 100% rename from tests/hwsim/auth_serv/ca.der rename to libeap/tests/hwsim/auth_serv/ca.der diff --git a/tests/hwsim/auth_serv/ca.pem b/libeap/tests/hwsim/auth_serv/ca.pem similarity index 100% rename from tests/hwsim/auth_serv/ca.pem rename to libeap/tests/hwsim/auth_serv/ca.pem diff --git a/eap_example/dh.conf b/libeap/tests/hwsim/auth_serv/dh.conf similarity index 100% rename from eap_example/dh.conf rename to libeap/tests/hwsim/auth_serv/dh.conf diff --git a/tests/hwsim/auth_serv/dh2.conf b/libeap/tests/hwsim/auth_serv/dh2.conf similarity index 100% rename from tests/hwsim/auth_serv/dh2.conf rename to libeap/tests/hwsim/auth_serv/dh2.conf diff --git a/tests/hwsim/auth_serv/dsaparam.pem b/libeap/tests/hwsim/auth_serv/dsaparam.pem similarity index 100% rename from tests/hwsim/auth_serv/dsaparam.pem rename to libeap/tests/hwsim/auth_serv/dsaparam.pem diff --git a/tests/hwsim/auth_serv/eap_user.conf b/libeap/tests/hwsim/auth_serv/eap_user.conf similarity index 100% rename from tests/hwsim/auth_serv/eap_user.conf rename to libeap/tests/hwsim/auth_serv/eap_user.conf diff --git a/tests/hwsim/auth_serv/eap_user_vlan.conf b/libeap/tests/hwsim/auth_serv/eap_user_vlan.conf similarity index 100% rename from tests/hwsim/auth_serv/eap_user_vlan.conf rename to libeap/tests/hwsim/auth_serv/eap_user_vlan.conf diff --git a/tests/hwsim/auth_serv/ec-ca-openssl.cnf b/libeap/tests/hwsim/auth_serv/ec-ca-openssl.cnf similarity index 100% rename from tests/hwsim/auth_serv/ec-ca-openssl.cnf rename to libeap/tests/hwsim/auth_serv/ec-ca-openssl.cnf diff --git a/tests/hwsim/auth_serv/ec-ca.pem b/libeap/tests/hwsim/auth_serv/ec-ca.pem similarity index 100% rename from tests/hwsim/auth_serv/ec-ca.pem rename to libeap/tests/hwsim/auth_serv/ec-ca.pem diff --git a/tests/hwsim/auth_serv/ec-generate.sh b/libeap/tests/hwsim/auth_serv/ec-generate.sh similarity index 100% rename from tests/hwsim/auth_serv/ec-generate.sh rename to libeap/tests/hwsim/auth_serv/ec-generate.sh diff --git a/tests/hwsim/auth_serv/ec-server.key b/libeap/tests/hwsim/auth_serv/ec-server.key similarity index 100% rename from tests/hwsim/auth_serv/ec-server.key rename to libeap/tests/hwsim/auth_serv/ec-server.key diff --git a/tests/hwsim/auth_serv/ec-server.pem b/libeap/tests/hwsim/auth_serv/ec-server.pem similarity index 100% rename from tests/hwsim/auth_serv/ec-server.pem rename to libeap/tests/hwsim/auth_serv/ec-server.pem diff --git a/tests/hwsim/auth_serv/ec-user.key b/libeap/tests/hwsim/auth_serv/ec-user.key similarity index 100% rename from tests/hwsim/auth_serv/ec-user.key rename to libeap/tests/hwsim/auth_serv/ec-user.key diff --git a/tests/hwsim/auth_serv/ec-user.pem b/libeap/tests/hwsim/auth_serv/ec-user.pem similarity index 100% rename from tests/hwsim/auth_serv/ec-user.pem rename to libeap/tests/hwsim/auth_serv/ec-user.pem diff --git a/tests/hwsim/auth_serv/ec2-ca.pem b/libeap/tests/hwsim/auth_serv/ec2-ca.pem similarity index 100% rename from tests/hwsim/auth_serv/ec2-ca.pem rename to libeap/tests/hwsim/auth_serv/ec2-ca.pem diff --git a/tests/hwsim/auth_serv/ec2-generate.sh b/libeap/tests/hwsim/auth_serv/ec2-generate.sh similarity index 100% rename from tests/hwsim/auth_serv/ec2-generate.sh rename to libeap/tests/hwsim/auth_serv/ec2-generate.sh diff --git a/tests/hwsim/auth_serv/ec2-server.key b/libeap/tests/hwsim/auth_serv/ec2-server.key similarity index 100% rename from tests/hwsim/auth_serv/ec2-server.key rename to libeap/tests/hwsim/auth_serv/ec2-server.key diff --git a/tests/hwsim/auth_serv/ec2-server.pem b/libeap/tests/hwsim/auth_serv/ec2-server.pem similarity index 100% rename from tests/hwsim/auth_serv/ec2-server.pem rename to libeap/tests/hwsim/auth_serv/ec2-server.pem diff --git a/tests/hwsim/auth_serv/ec2-user.key b/libeap/tests/hwsim/auth_serv/ec2-user.key similarity index 100% rename from tests/hwsim/auth_serv/ec2-user.key rename to libeap/tests/hwsim/auth_serv/ec2-user.key diff --git a/tests/hwsim/auth_serv/ec2-user.pem b/libeap/tests/hwsim/auth_serv/ec2-user.pem similarity index 100% rename from tests/hwsim/auth_serv/ec2-user.pem rename to libeap/tests/hwsim/auth_serv/ec2-user.pem diff --git a/tests/hwsim/auth_serv/hlr_auc_gw.gsm b/libeap/tests/hwsim/auth_serv/hlr_auc_gw.gsm similarity index 100% rename from tests/hwsim/auth_serv/hlr_auc_gw.gsm rename to libeap/tests/hwsim/auth_serv/hlr_auc_gw.gsm diff --git a/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db b/libeap/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db similarity index 100% rename from tests/hwsim/auth_serv/hlr_auc_gw.milenage_db rename to libeap/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db diff --git a/tests/hwsim/auth_serv/index-revoked.txt b/libeap/tests/hwsim/auth_serv/index-revoked.txt similarity index 100% rename from tests/hwsim/auth_serv/index-revoked.txt rename to libeap/tests/hwsim/auth_serv/index-revoked.txt diff --git a/tests/hwsim/auth_serv/index-unknown.txt b/libeap/tests/hwsim/auth_serv/index-unknown.txt similarity index 100% rename from tests/hwsim/auth_serv/index-unknown.txt rename to libeap/tests/hwsim/auth_serv/index-unknown.txt diff --git a/tests/hwsim/auth_serv/index.txt b/libeap/tests/hwsim/auth_serv/index.txt similarity index 100% rename from tests/hwsim/auth_serv/index.txt rename to libeap/tests/hwsim/auth_serv/index.txt diff --git a/tests/hwsim/auth_serv/ocsp-req.der b/libeap/tests/hwsim/auth_serv/ocsp-req.der similarity index 100% rename from tests/hwsim/auth_serv/ocsp-req.der rename to libeap/tests/hwsim/auth_serv/ocsp-req.der diff --git a/tests/hwsim/auth_serv/ocsp-responder.key b/libeap/tests/hwsim/auth_serv/ocsp-responder.key similarity index 100% rename from tests/hwsim/auth_serv/ocsp-responder.key rename to libeap/tests/hwsim/auth_serv/ocsp-responder.key diff --git a/tests/hwsim/auth_serv/ocsp-responder.pem b/libeap/tests/hwsim/auth_serv/ocsp-responder.pem similarity index 100% rename from tests/hwsim/auth_serv/ocsp-responder.pem rename to libeap/tests/hwsim/auth_serv/ocsp-responder.pem diff --git a/tests/hwsim/auth_serv/ocsp-server-cache.der b/libeap/tests/hwsim/auth_serv/ocsp-server-cache.der similarity index 100% rename from tests/hwsim/auth_serv/ocsp-server-cache.der rename to libeap/tests/hwsim/auth_serv/ocsp-server-cache.der diff --git a/tests/hwsim/auth_serv/ocsp-server-cache.der-invalid b/libeap/tests/hwsim/auth_serv/ocsp-server-cache.der-invalid similarity index 100% rename from tests/hwsim/auth_serv/ocsp-server-cache.der-invalid rename to libeap/tests/hwsim/auth_serv/ocsp-server-cache.der-invalid diff --git a/tests/hwsim/auth_serv/radius_clients.conf b/libeap/tests/hwsim/auth_serv/radius_clients.conf similarity index 100% rename from tests/hwsim/auth_serv/radius_clients.conf rename to libeap/tests/hwsim/auth_serv/radius_clients.conf diff --git a/tests/hwsim/auth_serv/radius_clients_ipv6.conf b/libeap/tests/hwsim/auth_serv/radius_clients_ipv6.conf similarity index 100% rename from tests/hwsim/auth_serv/radius_clients_ipv6.conf rename to libeap/tests/hwsim/auth_serv/radius_clients_ipv6.conf diff --git a/tests/hwsim/auth_serv/server-eku-client-server.key b/libeap/tests/hwsim/auth_serv/server-eku-client-server.key similarity index 100% rename from tests/hwsim/auth_serv/server-eku-client-server.key rename to libeap/tests/hwsim/auth_serv/server-eku-client-server.key diff --git a/tests/hwsim/auth_serv/server-eku-client-server.pem b/libeap/tests/hwsim/auth_serv/server-eku-client-server.pem similarity index 100% rename from tests/hwsim/auth_serv/server-eku-client-server.pem rename to libeap/tests/hwsim/auth_serv/server-eku-client-server.pem diff --git a/tests/hwsim/auth_serv/server-eku-client.key b/libeap/tests/hwsim/auth_serv/server-eku-client.key similarity index 100% rename from tests/hwsim/auth_serv/server-eku-client.key rename to libeap/tests/hwsim/auth_serv/server-eku-client.key diff --git a/tests/hwsim/auth_serv/server-eku-client.pem b/libeap/tests/hwsim/auth_serv/server-eku-client.pem similarity index 100% rename from tests/hwsim/auth_serv/server-eku-client.pem rename to libeap/tests/hwsim/auth_serv/server-eku-client.pem diff --git a/tests/hwsim/auth_serv/server-expired.key b/libeap/tests/hwsim/auth_serv/server-expired.key similarity index 100% rename from tests/hwsim/auth_serv/server-expired.key rename to libeap/tests/hwsim/auth_serv/server-expired.key diff --git a/tests/hwsim/auth_serv/server-expired.pem b/libeap/tests/hwsim/auth_serv/server-expired.pem similarity index 100% rename from tests/hwsim/auth_serv/server-expired.pem rename to libeap/tests/hwsim/auth_serv/server-expired.pem diff --git a/tests/hwsim/auth_serv/server-long-duration.key b/libeap/tests/hwsim/auth_serv/server-long-duration.key similarity index 100% rename from tests/hwsim/auth_serv/server-long-duration.key rename to libeap/tests/hwsim/auth_serv/server-long-duration.key diff --git a/tests/hwsim/auth_serv/server-long-duration.pem b/libeap/tests/hwsim/auth_serv/server-long-duration.pem similarity index 100% rename from tests/hwsim/auth_serv/server-long-duration.pem rename to libeap/tests/hwsim/auth_serv/server-long-duration.pem diff --git a/tests/hwsim/auth_serv/server-no-dnsname.key b/libeap/tests/hwsim/auth_serv/server-no-dnsname.key similarity index 100% rename from tests/hwsim/auth_serv/server-no-dnsname.key rename to libeap/tests/hwsim/auth_serv/server-no-dnsname.key diff --git a/tests/hwsim/auth_serv/server-no-dnsname.pem b/libeap/tests/hwsim/auth_serv/server-no-dnsname.pem similarity index 100% rename from tests/hwsim/auth_serv/server-no-dnsname.pem rename to libeap/tests/hwsim/auth_serv/server-no-dnsname.pem diff --git a/tests/hwsim/auth_serv/server.key b/libeap/tests/hwsim/auth_serv/server.key similarity index 100% rename from tests/hwsim/auth_serv/server.key rename to libeap/tests/hwsim/auth_serv/server.key diff --git a/tests/hwsim/auth_serv/server.pem b/libeap/tests/hwsim/auth_serv/server.pem similarity index 100% rename from tests/hwsim/auth_serv/server.pem rename to libeap/tests/hwsim/auth_serv/server.pem diff --git a/tests/hwsim/auth_serv/server.pkcs12 b/libeap/tests/hwsim/auth_serv/server.pkcs12 similarity index 100% rename from tests/hwsim/auth_serv/server.pkcs12 rename to libeap/tests/hwsim/auth_serv/server.pkcs12 diff --git a/tests/hwsim/auth_serv/user.key b/libeap/tests/hwsim/auth_serv/user.key similarity index 100% rename from tests/hwsim/auth_serv/user.key rename to libeap/tests/hwsim/auth_serv/user.key diff --git a/tests/hwsim/auth_serv/user.pem b/libeap/tests/hwsim/auth_serv/user.pem similarity index 100% rename from tests/hwsim/auth_serv/user.pem rename to libeap/tests/hwsim/auth_serv/user.pem diff --git a/tests/hwsim/auth_serv/user.pkcs12 b/libeap/tests/hwsim/auth_serv/user.pkcs12 similarity index 100% rename from tests/hwsim/auth_serv/user.pkcs12 rename to libeap/tests/hwsim/auth_serv/user.pkcs12 diff --git a/tests/hwsim/auth_serv/user.rsa-key b/libeap/tests/hwsim/auth_serv/user.rsa-key similarity index 100% rename from tests/hwsim/auth_serv/user.rsa-key rename to libeap/tests/hwsim/auth_serv/user.rsa-key diff --git a/tests/hwsim/auth_serv/user2.pkcs12 b/libeap/tests/hwsim/auth_serv/user2.pkcs12 similarity index 100% rename from tests/hwsim/auth_serv/user2.pkcs12 rename to libeap/tests/hwsim/auth_serv/user2.pkcs12 diff --git a/tests/hwsim/auth_serv/user3.pkcs12 b/libeap/tests/hwsim/auth_serv/user3.pkcs12 similarity index 100% rename from tests/hwsim/auth_serv/user3.pkcs12 rename to libeap/tests/hwsim/auth_serv/user3.pkcs12 diff --git a/tests/hwsim/bss-1.conf b/libeap/tests/hwsim/bss-1.conf similarity index 100% rename from tests/hwsim/bss-1.conf rename to libeap/tests/hwsim/bss-1.conf diff --git a/tests/hwsim/bss-2.conf b/libeap/tests/hwsim/bss-2.conf similarity index 100% rename from tests/hwsim/bss-2.conf rename to libeap/tests/hwsim/bss-2.conf diff --git a/tests/hwsim/bss-3.conf b/libeap/tests/hwsim/bss-3.conf similarity index 100% rename from tests/hwsim/bss-3.conf rename to libeap/tests/hwsim/bss-3.conf diff --git a/tests/hwsim/bss-ht40-1.conf b/libeap/tests/hwsim/bss-ht40-1.conf similarity index 100% rename from tests/hwsim/bss-ht40-1.conf rename to libeap/tests/hwsim/bss-ht40-1.conf diff --git a/tests/hwsim/bss-ht40-2.conf b/libeap/tests/hwsim/bss-ht40-2.conf similarity index 100% rename from tests/hwsim/bss-ht40-2.conf rename to libeap/tests/hwsim/bss-ht40-2.conf diff --git a/tests/hwsim/build.sh b/libeap/tests/hwsim/build.sh similarity index 100% rename from tests/hwsim/build.sh rename to libeap/tests/hwsim/build.sh diff --git a/tests/hwsim/check_kernel.py b/libeap/tests/hwsim/check_kernel.py similarity index 100% rename from tests/hwsim/check_kernel.py rename to libeap/tests/hwsim/check_kernel.py diff --git a/tests/hwsim/dictionary.radius b/libeap/tests/hwsim/dictionary.radius similarity index 100% rename from tests/hwsim/dictionary.radius rename to libeap/tests/hwsim/dictionary.radius diff --git a/tests/hwsim/example-hostapd.config b/libeap/tests/hwsim/example-hostapd.config similarity index 100% rename from tests/hwsim/example-hostapd.config rename to libeap/tests/hwsim/example-hostapd.config diff --git a/tests/hwsim/example-setup.txt b/libeap/tests/hwsim/example-setup.txt similarity index 100% rename from tests/hwsim/example-setup.txt rename to libeap/tests/hwsim/example-setup.txt diff --git a/tests/hwsim/example-wpa_supplicant.config b/libeap/tests/hwsim/example-wpa_supplicant.config similarity index 100% rename from tests/hwsim/example-wpa_supplicant.config rename to libeap/tests/hwsim/example-wpa_supplicant.config diff --git a/tests/hwsim/fst_module_aux.py b/libeap/tests/hwsim/fst_module_aux.py similarity index 100% rename from tests/hwsim/fst_module_aux.py rename to libeap/tests/hwsim/fst_module_aux.py diff --git a/tests/hwsim/fst_test_common.py b/libeap/tests/hwsim/fst_test_common.py similarity index 100% rename from tests/hwsim/fst_test_common.py rename to libeap/tests/hwsim/fst_test_common.py diff --git a/tests/hwsim/hostapd.accept b/libeap/tests/hwsim/hostapd.accept similarity index 100% rename from tests/hwsim/hostapd.accept rename to libeap/tests/hwsim/hostapd.accept diff --git a/tests/hwsim/hostapd.macaddr b/libeap/tests/hwsim/hostapd.macaddr similarity index 100% rename from tests/hwsim/hostapd.macaddr rename to libeap/tests/hwsim/hostapd.macaddr diff --git a/tests/hwsim/hostapd.py b/libeap/tests/hwsim/hostapd.py similarity index 100% rename from tests/hwsim/hostapd.py rename to libeap/tests/hwsim/hostapd.py diff --git a/tests/hwsim/hostapd.vlan b/libeap/tests/hwsim/hostapd.vlan similarity index 100% rename from tests/hwsim/hostapd.vlan rename to libeap/tests/hwsim/hostapd.vlan diff --git a/tests/hwsim/hostapd.wlan3.vlan b/libeap/tests/hwsim/hostapd.wlan3.vlan similarity index 100% rename from tests/hwsim/hostapd.wlan3.vlan rename to libeap/tests/hwsim/hostapd.wlan3.vlan diff --git a/tests/hwsim/hostapd.wlan4.vlan b/libeap/tests/hwsim/hostapd.wlan4.vlan similarity index 100% rename from tests/hwsim/hostapd.wlan4.vlan rename to libeap/tests/hwsim/hostapd.wlan4.vlan diff --git a/tests/hwsim/hostapd.wpa_psk b/libeap/tests/hwsim/hostapd.wpa_psk similarity index 100% rename from tests/hwsim/hostapd.wpa_psk rename to libeap/tests/hwsim/hostapd.wpa_psk diff --git a/tests/hwsim/hwsim.py b/libeap/tests/hwsim/hwsim.py similarity index 100% rename from tests/hwsim/hwsim.py rename to libeap/tests/hwsim/hwsim.py diff --git a/tests/hwsim/hwsim_utils.py b/libeap/tests/hwsim/hwsim_utils.py similarity index 100% rename from tests/hwsim/hwsim_utils.py rename to libeap/tests/hwsim/hwsim_utils.py diff --git a/tests/hwsim/multi-bss-acs.conf b/libeap/tests/hwsim/multi-bss-acs.conf similarity index 100% rename from tests/hwsim/multi-bss-acs.conf rename to libeap/tests/hwsim/multi-bss-acs.conf diff --git a/tests/hwsim/multi-bss-iface.conf b/libeap/tests/hwsim/multi-bss-iface.conf similarity index 100% rename from tests/hwsim/multi-bss-iface.conf rename to libeap/tests/hwsim/multi-bss-iface.conf diff --git a/tests/hwsim/multi-bss.conf b/libeap/tests/hwsim/multi-bss.conf similarity index 100% rename from tests/hwsim/multi-bss.conf rename to libeap/tests/hwsim/multi-bss.conf diff --git a/tests/hwsim/netlink.py b/libeap/tests/hwsim/netlink.py similarity index 100% rename from tests/hwsim/netlink.py rename to libeap/tests/hwsim/netlink.py diff --git a/tests/hwsim/nl80211.py b/libeap/tests/hwsim/nl80211.py similarity index 100% rename from tests/hwsim/nl80211.py rename to libeap/tests/hwsim/nl80211.py diff --git a/tests/hwsim/p2p0.conf b/libeap/tests/hwsim/p2p0.conf similarity index 100% rename from tests/hwsim/p2p0.conf rename to libeap/tests/hwsim/p2p0.conf diff --git a/tests/hwsim/p2p1.conf b/libeap/tests/hwsim/p2p1.conf similarity index 100% rename from tests/hwsim/p2p1.conf rename to libeap/tests/hwsim/p2p1.conf diff --git a/tests/hwsim/p2p2.conf b/libeap/tests/hwsim/p2p2.conf similarity index 100% rename from tests/hwsim/p2p2.conf rename to libeap/tests/hwsim/p2p2.conf diff --git a/tests/hwsim/radius_das.py b/libeap/tests/hwsim/radius_das.py similarity index 100% rename from tests/hwsim/radius_das.py rename to libeap/tests/hwsim/radius_das.py diff --git a/tests/hwsim/rfkill.py b/libeap/tests/hwsim/rfkill.py similarity index 100% rename from tests/hwsim/rfkill.py rename to libeap/tests/hwsim/rfkill.py diff --git a/tests/hwsim/run-all.sh b/libeap/tests/hwsim/run-all.sh similarity index 100% rename from tests/hwsim/run-all.sh rename to libeap/tests/hwsim/run-all.sh diff --git a/tests/hwsim/run-tests.py b/libeap/tests/hwsim/run-tests.py similarity index 100% rename from tests/hwsim/run-tests.py rename to libeap/tests/hwsim/run-tests.py diff --git a/tests/hwsim/start.sh b/libeap/tests/hwsim/start.sh similarity index 100% rename from tests/hwsim/start.sh rename to libeap/tests/hwsim/start.sh diff --git a/tests/hwsim/stop.sh b/libeap/tests/hwsim/stop.sh similarity index 100% rename from tests/hwsim/stop.sh rename to libeap/tests/hwsim/stop.sh diff --git a/tests/hwsim/test_ap_acs.py b/libeap/tests/hwsim/test_ap_acs.py similarity index 100% rename from tests/hwsim/test_ap_acs.py rename to libeap/tests/hwsim/test_ap_acs.py diff --git a/tests/hwsim/test_ap_ciphers.py b/libeap/tests/hwsim/test_ap_ciphers.py similarity index 100% rename from tests/hwsim/test_ap_ciphers.py rename to libeap/tests/hwsim/test_ap_ciphers.py diff --git a/tests/hwsim/test_ap_config.py b/libeap/tests/hwsim/test_ap_config.py similarity index 100% rename from tests/hwsim/test_ap_config.py rename to libeap/tests/hwsim/test_ap_config.py diff --git a/tests/hwsim/test_ap_csa.py b/libeap/tests/hwsim/test_ap_csa.py similarity index 100% rename from tests/hwsim/test_ap_csa.py rename to libeap/tests/hwsim/test_ap_csa.py diff --git a/tests/hwsim/test_ap_dynamic.py b/libeap/tests/hwsim/test_ap_dynamic.py similarity index 100% rename from tests/hwsim/test_ap_dynamic.py rename to libeap/tests/hwsim/test_ap_dynamic.py diff --git a/tests/hwsim/test_ap_eap.py b/libeap/tests/hwsim/test_ap_eap.py similarity index 100% rename from tests/hwsim/test_ap_eap.py rename to libeap/tests/hwsim/test_ap_eap.py diff --git a/tests/hwsim/test_ap_ft.py b/libeap/tests/hwsim/test_ap_ft.py similarity index 100% rename from tests/hwsim/test_ap_ft.py rename to libeap/tests/hwsim/test_ap_ft.py diff --git a/tests/hwsim/test_ap_hs20.py b/libeap/tests/hwsim/test_ap_hs20.py similarity index 100% rename from tests/hwsim/test_ap_hs20.py rename to libeap/tests/hwsim/test_ap_hs20.py diff --git a/tests/hwsim/test_ap_ht.py b/libeap/tests/hwsim/test_ap_ht.py similarity index 100% rename from tests/hwsim/test_ap_ht.py rename to libeap/tests/hwsim/test_ap_ht.py diff --git a/tests/hwsim/test_ap_mixed.py b/libeap/tests/hwsim/test_ap_mixed.py similarity index 100% rename from tests/hwsim/test_ap_mixed.py rename to libeap/tests/hwsim/test_ap_mixed.py diff --git a/tests/hwsim/test_ap_open.py b/libeap/tests/hwsim/test_ap_open.py similarity index 100% rename from tests/hwsim/test_ap_open.py rename to libeap/tests/hwsim/test_ap_open.py diff --git a/tests/hwsim/test_ap_params.py b/libeap/tests/hwsim/test_ap_params.py similarity index 100% rename from tests/hwsim/test_ap_params.py rename to libeap/tests/hwsim/test_ap_params.py diff --git a/tests/hwsim/test_ap_pmf.py b/libeap/tests/hwsim/test_ap_pmf.py similarity index 100% rename from tests/hwsim/test_ap_pmf.py rename to libeap/tests/hwsim/test_ap_pmf.py diff --git a/tests/hwsim/test_ap_psk.py b/libeap/tests/hwsim/test_ap_psk.py similarity index 100% rename from tests/hwsim/test_ap_psk.py rename to libeap/tests/hwsim/test_ap_psk.py diff --git a/tests/hwsim/test_ap_qosmap.py b/libeap/tests/hwsim/test_ap_qosmap.py similarity index 100% rename from tests/hwsim/test_ap_qosmap.py rename to libeap/tests/hwsim/test_ap_qosmap.py diff --git a/tests/hwsim/test_ap_roam.py b/libeap/tests/hwsim/test_ap_roam.py similarity index 100% rename from tests/hwsim/test_ap_roam.py rename to libeap/tests/hwsim/test_ap_roam.py diff --git a/tests/hwsim/test_ap_tdls.py b/libeap/tests/hwsim/test_ap_tdls.py similarity index 100% rename from tests/hwsim/test_ap_tdls.py rename to libeap/tests/hwsim/test_ap_tdls.py diff --git a/tests/hwsim/test_ap_track.py b/libeap/tests/hwsim/test_ap_track.py similarity index 100% rename from tests/hwsim/test_ap_track.py rename to libeap/tests/hwsim/test_ap_track.py diff --git a/tests/hwsim/test_ap_vht.py b/libeap/tests/hwsim/test_ap_vht.py similarity index 100% rename from tests/hwsim/test_ap_vht.py rename to libeap/tests/hwsim/test_ap_vht.py diff --git a/tests/hwsim/test_ap_vlan.py b/libeap/tests/hwsim/test_ap_vlan.py similarity index 100% rename from tests/hwsim/test_ap_vlan.py rename to libeap/tests/hwsim/test_ap_vlan.py diff --git a/tests/hwsim/test_ap_wps.py b/libeap/tests/hwsim/test_ap_wps.py similarity index 100% rename from tests/hwsim/test_ap_wps.py rename to libeap/tests/hwsim/test_ap_wps.py diff --git a/tests/hwsim/test_autoscan.py b/libeap/tests/hwsim/test_autoscan.py similarity index 100% rename from tests/hwsim/test_autoscan.py rename to libeap/tests/hwsim/test_autoscan.py diff --git a/tests/hwsim/test_bgscan.py b/libeap/tests/hwsim/test_bgscan.py similarity index 100% rename from tests/hwsim/test_bgscan.py rename to libeap/tests/hwsim/test_bgscan.py diff --git a/tests/hwsim/test_cfg80211.py b/libeap/tests/hwsim/test_cfg80211.py similarity index 100% rename from tests/hwsim/test_cfg80211.py rename to libeap/tests/hwsim/test_cfg80211.py diff --git a/tests/hwsim/test_connect_cmd.py b/libeap/tests/hwsim/test_connect_cmd.py similarity index 100% rename from tests/hwsim/test_connect_cmd.py rename to libeap/tests/hwsim/test_connect_cmd.py diff --git a/tests/hwsim/test_dbus.py b/libeap/tests/hwsim/test_dbus.py similarity index 100% rename from tests/hwsim/test_dbus.py rename to libeap/tests/hwsim/test_dbus.py diff --git a/tests/hwsim/test_dbus_old.py b/libeap/tests/hwsim/test_dbus_old.py similarity index 100% rename from tests/hwsim/test_dbus_old.py rename to libeap/tests/hwsim/test_dbus_old.py diff --git a/tests/hwsim/test_dfs.py b/libeap/tests/hwsim/test_dfs.py similarity index 100% rename from tests/hwsim/test_dfs.py rename to libeap/tests/hwsim/test_dfs.py diff --git a/tests/hwsim/test_eap_proto.py b/libeap/tests/hwsim/test_eap_proto.py similarity index 100% rename from tests/hwsim/test_eap_proto.py rename to libeap/tests/hwsim/test_eap_proto.py diff --git a/tests/hwsim/test_erp.py b/libeap/tests/hwsim/test_erp.py similarity index 100% rename from tests/hwsim/test_erp.py rename to libeap/tests/hwsim/test_erp.py diff --git a/tests/hwsim/test_ext_password.py b/libeap/tests/hwsim/test_ext_password.py similarity index 100% rename from tests/hwsim/test_ext_password.py rename to libeap/tests/hwsim/test_ext_password.py diff --git a/tests/hwsim/test_fst_config.py b/libeap/tests/hwsim/test_fst_config.py similarity index 100% rename from tests/hwsim/test_fst_config.py rename to libeap/tests/hwsim/test_fst_config.py diff --git a/tests/hwsim/test_fst_module.py b/libeap/tests/hwsim/test_fst_module.py similarity index 100% rename from tests/hwsim/test_fst_module.py rename to libeap/tests/hwsim/test_fst_module.py diff --git a/tests/hwsim/test_gas.py b/libeap/tests/hwsim/test_gas.py similarity index 100% rename from tests/hwsim/test_gas.py rename to libeap/tests/hwsim/test_gas.py diff --git a/tests/hwsim/test_hapd_ctrl.py b/libeap/tests/hwsim/test_hapd_ctrl.py similarity index 100% rename from tests/hwsim/test_hapd_ctrl.py rename to libeap/tests/hwsim/test_hapd_ctrl.py diff --git a/tests/hwsim/test_hostapd_oom.py b/libeap/tests/hwsim/test_hostapd_oom.py similarity index 100% rename from tests/hwsim/test_hostapd_oom.py rename to libeap/tests/hwsim/test_hostapd_oom.py diff --git a/tests/hwsim/test_ibss.py b/libeap/tests/hwsim/test_ibss.py similarity index 100% rename from tests/hwsim/test_ibss.py rename to libeap/tests/hwsim/test_ibss.py diff --git a/tests/hwsim/test_ieee8021x.py b/libeap/tests/hwsim/test_ieee8021x.py similarity index 100% rename from tests/hwsim/test_ieee8021x.py rename to libeap/tests/hwsim/test_ieee8021x.py diff --git a/tests/hwsim/test_module_tests.py b/libeap/tests/hwsim/test_module_tests.py similarity index 100% rename from tests/hwsim/test_module_tests.py rename to libeap/tests/hwsim/test_module_tests.py diff --git a/tests/hwsim/test_monitor_interface.py b/libeap/tests/hwsim/test_monitor_interface.py similarity index 100% rename from tests/hwsim/test_monitor_interface.py rename to libeap/tests/hwsim/test_monitor_interface.py diff --git a/tests/hwsim/test_nfc_p2p.py b/libeap/tests/hwsim/test_nfc_p2p.py similarity index 100% rename from tests/hwsim/test_nfc_p2p.py rename to libeap/tests/hwsim/test_nfc_p2p.py diff --git a/tests/hwsim/test_nfc_wps.py b/libeap/tests/hwsim/test_nfc_wps.py similarity index 100% rename from tests/hwsim/test_nfc_wps.py rename to libeap/tests/hwsim/test_nfc_wps.py diff --git a/tests/hwsim/test_offchannel_tx.py b/libeap/tests/hwsim/test_offchannel_tx.py similarity index 100% rename from tests/hwsim/test_offchannel_tx.py rename to libeap/tests/hwsim/test_offchannel_tx.py diff --git a/tests/hwsim/test_p2p_autogo.py b/libeap/tests/hwsim/test_p2p_autogo.py similarity index 100% rename from tests/hwsim/test_p2p_autogo.py rename to libeap/tests/hwsim/test_p2p_autogo.py diff --git a/tests/hwsim/test_p2p_channel.py b/libeap/tests/hwsim/test_p2p_channel.py similarity index 100% rename from tests/hwsim/test_p2p_channel.py rename to libeap/tests/hwsim/test_p2p_channel.py diff --git a/tests/hwsim/test_p2p_concurrency.py b/libeap/tests/hwsim/test_p2p_concurrency.py similarity index 100% rename from tests/hwsim/test_p2p_concurrency.py rename to libeap/tests/hwsim/test_p2p_concurrency.py diff --git a/tests/hwsim/test_p2p_device.py b/libeap/tests/hwsim/test_p2p_device.py similarity index 100% rename from tests/hwsim/test_p2p_device.py rename to libeap/tests/hwsim/test_p2p_device.py diff --git a/tests/hwsim/test_p2p_discovery.py b/libeap/tests/hwsim/test_p2p_discovery.py similarity index 100% rename from tests/hwsim/test_p2p_discovery.py rename to libeap/tests/hwsim/test_p2p_discovery.py diff --git a/tests/hwsim/test_p2p_ext.py b/libeap/tests/hwsim/test_p2p_ext.py similarity index 100% rename from tests/hwsim/test_p2p_ext.py rename to libeap/tests/hwsim/test_p2p_ext.py diff --git a/tests/hwsim/test_p2p_grpform.py b/libeap/tests/hwsim/test_p2p_grpform.py similarity index 100% rename from tests/hwsim/test_p2p_grpform.py rename to libeap/tests/hwsim/test_p2p_grpform.py diff --git a/tests/hwsim/test_p2p_invitation.py b/libeap/tests/hwsim/test_p2p_invitation.py similarity index 100% rename from tests/hwsim/test_p2p_invitation.py rename to libeap/tests/hwsim/test_p2p_invitation.py diff --git a/tests/hwsim/test_p2p_messages.py b/libeap/tests/hwsim/test_p2p_messages.py similarity index 100% rename from tests/hwsim/test_p2p_messages.py rename to libeap/tests/hwsim/test_p2p_messages.py diff --git a/tests/hwsim/test_p2p_persistent.py b/libeap/tests/hwsim/test_p2p_persistent.py similarity index 100% rename from tests/hwsim/test_p2p_persistent.py rename to libeap/tests/hwsim/test_p2p_persistent.py diff --git a/tests/hwsim/test_p2p_service.py b/libeap/tests/hwsim/test_p2p_service.py similarity index 100% rename from tests/hwsim/test_p2p_service.py rename to libeap/tests/hwsim/test_p2p_service.py diff --git a/tests/hwsim/test_p2p_set.py b/libeap/tests/hwsim/test_p2p_set.py similarity index 100% rename from tests/hwsim/test_p2p_set.py rename to libeap/tests/hwsim/test_p2p_set.py diff --git a/tests/hwsim/test_p2p_wifi_display.py b/libeap/tests/hwsim/test_p2p_wifi_display.py similarity index 100% rename from tests/hwsim/test_p2p_wifi_display.py rename to libeap/tests/hwsim/test_p2p_wifi_display.py diff --git a/tests/hwsim/test_p2ps.py b/libeap/tests/hwsim/test_p2ps.py similarity index 100% rename from tests/hwsim/test_p2ps.py rename to libeap/tests/hwsim/test_p2ps.py diff --git a/tests/hwsim/test_peerkey.py b/libeap/tests/hwsim/test_peerkey.py similarity index 100% rename from tests/hwsim/test_peerkey.py rename to libeap/tests/hwsim/test_peerkey.py diff --git a/tests/hwsim/test_pmksa_cache.py b/libeap/tests/hwsim/test_pmksa_cache.py similarity index 100% rename from tests/hwsim/test_pmksa_cache.py rename to libeap/tests/hwsim/test_pmksa_cache.py diff --git a/tests/hwsim/test_radio_work.py b/libeap/tests/hwsim/test_radio_work.py similarity index 100% rename from tests/hwsim/test_radio_work.py rename to libeap/tests/hwsim/test_radio_work.py diff --git a/tests/hwsim/test_radius.py b/libeap/tests/hwsim/test_radius.py similarity index 100% rename from tests/hwsim/test_radius.py rename to libeap/tests/hwsim/test_radius.py diff --git a/tests/hwsim/test_rfkill.py b/libeap/tests/hwsim/test_rfkill.py similarity index 100% rename from tests/hwsim/test_rfkill.py rename to libeap/tests/hwsim/test_rfkill.py diff --git a/tests/hwsim/test_sae.py b/libeap/tests/hwsim/test_sae.py similarity index 100% rename from tests/hwsim/test_sae.py rename to libeap/tests/hwsim/test_sae.py diff --git a/tests/hwsim/test_scan.py b/libeap/tests/hwsim/test_scan.py similarity index 100% rename from tests/hwsim/test_scan.py rename to libeap/tests/hwsim/test_scan.py diff --git a/tests/hwsim/test_ssid.py b/libeap/tests/hwsim/test_ssid.py similarity index 100% rename from tests/hwsim/test_ssid.py rename to libeap/tests/hwsim/test_ssid.py diff --git a/tests/hwsim/test_sta_dynamic.py b/libeap/tests/hwsim/test_sta_dynamic.py similarity index 100% rename from tests/hwsim/test_sta_dynamic.py rename to libeap/tests/hwsim/test_sta_dynamic.py diff --git a/tests/hwsim/test_suite_b.py b/libeap/tests/hwsim/test_suite_b.py similarity index 100% rename from tests/hwsim/test_suite_b.py rename to libeap/tests/hwsim/test_suite_b.py diff --git a/tests/hwsim/test_tnc.py b/libeap/tests/hwsim/test_tnc.py similarity index 100% rename from tests/hwsim/test_tnc.py rename to libeap/tests/hwsim/test_tnc.py diff --git a/tests/hwsim/test_wep.py b/libeap/tests/hwsim/test_wep.py similarity index 100% rename from tests/hwsim/test_wep.py rename to libeap/tests/hwsim/test_wep.py diff --git a/tests/hwsim/test_wext.py b/libeap/tests/hwsim/test_wext.py similarity index 100% rename from tests/hwsim/test_wext.py rename to libeap/tests/hwsim/test_wext.py diff --git a/tests/hwsim/test_wnm.py b/libeap/tests/hwsim/test_wnm.py similarity index 100% rename from tests/hwsim/test_wnm.py rename to libeap/tests/hwsim/test_wnm.py diff --git a/tests/hwsim/test_wpas_ap.py b/libeap/tests/hwsim/test_wpas_ap.py similarity index 100% rename from tests/hwsim/test_wpas_ap.py rename to libeap/tests/hwsim/test_wpas_ap.py diff --git a/tests/hwsim/test_wpas_config.py b/libeap/tests/hwsim/test_wpas_config.py similarity index 100% rename from tests/hwsim/test_wpas_config.py rename to libeap/tests/hwsim/test_wpas_config.py diff --git a/tests/hwsim/test_wpas_ctrl.py b/libeap/tests/hwsim/test_wpas_ctrl.py similarity index 100% rename from tests/hwsim/test_wpas_ctrl.py rename to libeap/tests/hwsim/test_wpas_ctrl.py diff --git a/tests/hwsim/test_wpas_mesh.py b/libeap/tests/hwsim/test_wpas_mesh.py similarity index 100% rename from tests/hwsim/test_wpas_mesh.py rename to libeap/tests/hwsim/test_wpas_mesh.py diff --git a/tests/hwsim/test_wpas_wmm_ac.py b/libeap/tests/hwsim/test_wpas_wmm_ac.py similarity index 100% rename from tests/hwsim/test_wpas_wmm_ac.py rename to libeap/tests/hwsim/test_wpas_wmm_ac.py diff --git a/tests/hwsim/tnc/.gitignore b/libeap/tests/hwsim/tnc/.gitignore similarity index 100% rename from tests/hwsim/tnc/.gitignore rename to libeap/tests/hwsim/tnc/.gitignore diff --git a/tests/hwsim/tnc/Makefile b/libeap/tests/hwsim/tnc/Makefile similarity index 100% rename from tests/hwsim/tnc/Makefile rename to libeap/tests/hwsim/tnc/Makefile diff --git a/tests/hwsim/tnc/hostap2_imc.c b/libeap/tests/hwsim/tnc/hostap2_imc.c similarity index 100% rename from tests/hwsim/tnc/hostap2_imc.c rename to libeap/tests/hwsim/tnc/hostap2_imc.c diff --git a/tests/hwsim/tnc/hostap2_imv.c b/libeap/tests/hwsim/tnc/hostap2_imv.c similarity index 100% rename from tests/hwsim/tnc/hostap2_imv.c rename to libeap/tests/hwsim/tnc/hostap2_imv.c diff --git a/tests/hwsim/tnc/hostap_imc.c b/libeap/tests/hwsim/tnc/hostap_imc.c similarity index 100% rename from tests/hwsim/tnc/hostap_imc.c rename to libeap/tests/hwsim/tnc/hostap_imc.c diff --git a/tests/hwsim/tnc/hostap_imv.c b/libeap/tests/hwsim/tnc/hostap_imv.c similarity index 100% rename from tests/hwsim/tnc/hostap_imv.c rename to libeap/tests/hwsim/tnc/hostap_imv.c diff --git a/tests/hwsim/tnc/tnc_config b/libeap/tests/hwsim/tnc/tnc_config similarity index 100% rename from tests/hwsim/tnc/tnc_config rename to libeap/tests/hwsim/tnc/tnc_config diff --git a/tests/hwsim/tshark.py b/libeap/tests/hwsim/tshark.py similarity index 100% rename from tests/hwsim/tshark.py rename to libeap/tests/hwsim/tshark.py diff --git a/tests/hwsim/utils.py b/libeap/tests/hwsim/utils.py similarity index 100% rename from tests/hwsim/utils.py rename to libeap/tests/hwsim/utils.py diff --git a/tests/hwsim/vm/.gitignore b/libeap/tests/hwsim/vm/.gitignore similarity index 100% rename from tests/hwsim/vm/.gitignore rename to libeap/tests/hwsim/vm/.gitignore diff --git a/tests/hwsim/vm/README b/libeap/tests/hwsim/vm/README similarity index 100% rename from tests/hwsim/vm/README rename to libeap/tests/hwsim/vm/README diff --git a/tests/hwsim/vm/build-codecov.sh b/libeap/tests/hwsim/vm/build-codecov.sh similarity index 100% rename from tests/hwsim/vm/build-codecov.sh rename to libeap/tests/hwsim/vm/build-codecov.sh diff --git a/tests/hwsim/vm/combine-codecov.sh b/libeap/tests/hwsim/vm/combine-codecov.sh similarity index 100% rename from tests/hwsim/vm/combine-codecov.sh rename to libeap/tests/hwsim/vm/combine-codecov.sh diff --git a/tests/hwsim/vm/dbus.conf b/libeap/tests/hwsim/vm/dbus.conf similarity index 100% rename from tests/hwsim/vm/dbus.conf rename to libeap/tests/hwsim/vm/dbus.conf diff --git a/tests/hwsim/vm/inside.sh b/libeap/tests/hwsim/vm/inside.sh similarity index 100% rename from tests/hwsim/vm/inside.sh rename to libeap/tests/hwsim/vm/inside.sh diff --git a/tests/hwsim/vm/kernel-config b/libeap/tests/hwsim/vm/kernel-config similarity index 100% rename from tests/hwsim/vm/kernel-config rename to libeap/tests/hwsim/vm/kernel-config diff --git a/tests/hwsim/vm/parallel-vm.py b/libeap/tests/hwsim/vm/parallel-vm.py similarity index 100% rename from tests/hwsim/vm/parallel-vm.py rename to libeap/tests/hwsim/vm/parallel-vm.py diff --git a/tests/hwsim/vm/parallel-vm.sh b/libeap/tests/hwsim/vm/parallel-vm.sh similarity index 100% rename from tests/hwsim/vm/parallel-vm.sh rename to libeap/tests/hwsim/vm/parallel-vm.sh diff --git a/tests/hwsim/vm/process-codecov.sh b/libeap/tests/hwsim/vm/process-codecov.sh similarity index 100% rename from tests/hwsim/vm/process-codecov.sh rename to libeap/tests/hwsim/vm/process-codecov.sh diff --git a/tests/hwsim/vm/uevent.sh b/libeap/tests/hwsim/vm/uevent.sh similarity index 100% rename from tests/hwsim/vm/uevent.sh rename to libeap/tests/hwsim/vm/uevent.sh diff --git a/tests/hwsim/vm/vm-run.sh b/libeap/tests/hwsim/vm/vm-run.sh similarity index 100% rename from tests/hwsim/vm/vm-run.sh rename to libeap/tests/hwsim/vm/vm-run.sh diff --git a/hs20/server/ca/w1fi_logo.png b/libeap/tests/hwsim/w1fi_logo.png similarity index 100% rename from hs20/server/ca/w1fi_logo.png rename to libeap/tests/hwsim/w1fi_logo.png diff --git a/tests/hwsim/wlantest.py b/libeap/tests/hwsim/wlantest.py similarity index 100% rename from tests/hwsim/wlantest.py rename to libeap/tests/hwsim/wlantest.py diff --git a/tests/hwsim/wpasupplicant.py b/libeap/tests/hwsim/wpasupplicant.py similarity index 100% rename from tests/hwsim/wpasupplicant.py rename to libeap/tests/hwsim/wpasupplicant.py diff --git a/tests/hwsim/wps-mixed-cred b/libeap/tests/hwsim/wps-mixed-cred similarity index 100% rename from tests/hwsim/wps-mixed-cred rename to libeap/tests/hwsim/wps-mixed-cred diff --git a/tests/hwsim/wps-wep-cred b/libeap/tests/hwsim/wps-wep-cred similarity index 100% rename from tests/hwsim/wps-wep-cred rename to libeap/tests/hwsim/wps-wep-cred diff --git a/tests/p2p-fuzzer/Makefile b/libeap/tests/p2p-fuzzer/Makefile similarity index 100% rename from tests/p2p-fuzzer/Makefile rename to libeap/tests/p2p-fuzzer/Makefile diff --git a/tests/p2p-fuzzer/go-neg-req.dat b/libeap/tests/p2p-fuzzer/go-neg-req.dat similarity index 100% rename from tests/p2p-fuzzer/go-neg-req.dat rename to libeap/tests/p2p-fuzzer/go-neg-req.dat diff --git a/tests/p2p-fuzzer/invitation-req.dat b/libeap/tests/p2p-fuzzer/invitation-req.dat similarity index 100% rename from tests/p2p-fuzzer/invitation-req.dat rename to libeap/tests/p2p-fuzzer/invitation-req.dat diff --git a/tests/p2p-fuzzer/p2p-fuzzer.c b/libeap/tests/p2p-fuzzer/p2p-fuzzer.c similarity index 100% rename from tests/p2p-fuzzer/p2p-fuzzer.c rename to libeap/tests/p2p-fuzzer/p2p-fuzzer.c diff --git a/tests/p2p-fuzzer/p2ps-pd-req.dat b/libeap/tests/p2p-fuzzer/p2ps-pd-req.dat similarity index 100% rename from tests/p2p-fuzzer/p2ps-pd-req.dat rename to libeap/tests/p2p-fuzzer/p2ps-pd-req.dat diff --git a/tests/p2p-fuzzer/proberesp-go.dat b/libeap/tests/p2p-fuzzer/proberesp-go.dat similarity index 100% rename from tests/p2p-fuzzer/proberesp-go.dat rename to libeap/tests/p2p-fuzzer/proberesp-go.dat diff --git a/tests/p2p-fuzzer/proberesp.dat b/libeap/tests/p2p-fuzzer/proberesp.dat similarity index 100% rename from tests/p2p-fuzzer/proberesp.dat rename to libeap/tests/p2p-fuzzer/proberesp.dat diff --git a/tests/test-aes.c b/libeap/tests/test-aes.c similarity index 100% rename from tests/test-aes.c rename to libeap/tests/test-aes.c diff --git a/tests/test-asn1.c b/libeap/tests/test-asn1.c similarity index 100% rename from tests/test-asn1.c rename to libeap/tests/test-asn1.c diff --git a/tests/test-base64.c b/libeap/tests/test-base64.c similarity index 100% rename from tests/test-base64.c rename to libeap/tests/test-base64.c diff --git a/tests/test-https.c b/libeap/tests/test-https.c similarity index 100% rename from tests/test-https.c rename to libeap/tests/test-https.c diff --git a/tests/test-list.c b/libeap/tests/test-list.c similarity index 100% rename from tests/test-list.c rename to libeap/tests/test-list.c diff --git a/tests/test-md4.c b/libeap/tests/test-md4.c similarity index 100% rename from tests/test-md4.c rename to libeap/tests/test-md4.c diff --git a/tests/test-milenage.c b/libeap/tests/test-milenage.c similarity index 100% rename from tests/test-milenage.c rename to libeap/tests/test-milenage.c diff --git a/tests/test-rc4.c b/libeap/tests/test-rc4.c similarity index 100% rename from tests/test-rc4.c rename to libeap/tests/test-rc4.c diff --git a/tests/test-rsa-sig-ver.c b/libeap/tests/test-rsa-sig-ver.c similarity index 100% rename from tests/test-rsa-sig-ver.c rename to libeap/tests/test-rsa-sig-ver.c diff --git a/tests/test-sha1.c b/libeap/tests/test-sha1.c similarity index 100% rename from tests/test-sha1.c rename to libeap/tests/test-sha1.c diff --git a/tests/test-sha256.c b/libeap/tests/test-sha256.c similarity index 100% rename from tests/test-sha256.c rename to libeap/tests/test-sha256.c diff --git a/tests/test-x509.c b/libeap/tests/test-x509.c similarity index 100% rename from tests/test-x509.c rename to libeap/tests/test-x509.c diff --git a/tests/test-x509v3.c b/libeap/tests/test-x509v3.c similarity index 100% rename from tests/test-x509v3.c rename to libeap/tests/test-x509v3.c diff --git a/tests/test_x509v3_nist.sh b/libeap/tests/test_x509v3_nist.sh similarity index 100% rename from tests/test_x509v3_nist.sh rename to libeap/tests/test_x509v3_nist.sh diff --git a/tests/test_x509v3_nist2.sh b/libeap/tests/test_x509v3_nist2.sh similarity index 100% rename from tests/test_x509v3_nist2.sh rename to libeap/tests/test_x509v3_nist2.sh diff --git a/tests/wnm-fuzzer/Makefile b/libeap/tests/wnm-fuzzer/Makefile similarity index 100% rename from tests/wnm-fuzzer/Makefile rename to libeap/tests/wnm-fuzzer/Makefile diff --git a/tests/wnm-fuzzer/bss-tm-req.dat b/libeap/tests/wnm-fuzzer/bss-tm-req.dat similarity index 100% rename from tests/wnm-fuzzer/bss-tm-req.dat rename to libeap/tests/wnm-fuzzer/bss-tm-req.dat diff --git a/tests/wnm-fuzzer/wnm-fuzzer.c b/libeap/tests/wnm-fuzzer/wnm-fuzzer.c similarity index 100% rename from tests/wnm-fuzzer/wnm-fuzzer.c rename to libeap/tests/wnm-fuzzer/wnm-fuzzer.c diff --git a/tests/wnm-fuzzer/wnm-notif.dat b/libeap/tests/wnm-fuzzer/wnm-notif.dat similarity index 100% rename from tests/wnm-fuzzer/wnm-notif.dat rename to libeap/tests/wnm-fuzzer/wnm-notif.dat diff --git a/wlantest/Makefile b/libeap/wlantest/Makefile similarity index 100% rename from wlantest/Makefile rename to libeap/wlantest/Makefile diff --git a/wlantest/bip.c b/libeap/wlantest/bip.c similarity index 100% rename from wlantest/bip.c rename to libeap/wlantest/bip.c diff --git a/wlantest/bss.c b/libeap/wlantest/bss.c similarity index 100% rename from wlantest/bss.c rename to libeap/wlantest/bss.c diff --git a/wlantest/ccmp.c b/libeap/wlantest/ccmp.c similarity index 100% rename from wlantest/ccmp.c rename to libeap/wlantest/ccmp.c diff --git a/wlantest/crc32.c b/libeap/wlantest/crc32.c similarity index 100% rename from wlantest/crc32.c rename to libeap/wlantest/crc32.c diff --git a/wlantest/ctrl.c b/libeap/wlantest/ctrl.c similarity index 100% rename from wlantest/ctrl.c rename to libeap/wlantest/ctrl.c diff --git a/wlantest/gcmp.c b/libeap/wlantest/gcmp.c similarity index 100% rename from wlantest/gcmp.c rename to libeap/wlantest/gcmp.c diff --git a/wlantest/inject.c b/libeap/wlantest/inject.c similarity index 100% rename from wlantest/inject.c rename to libeap/wlantest/inject.c diff --git a/wlantest/monitor.c b/libeap/wlantest/monitor.c similarity index 100% rename from wlantest/monitor.c rename to libeap/wlantest/monitor.c diff --git a/wlantest/process.c b/libeap/wlantest/process.c similarity index 100% rename from wlantest/process.c rename to libeap/wlantest/process.c diff --git a/wlantest/readpcap.c b/libeap/wlantest/readpcap.c similarity index 100% rename from wlantest/readpcap.c rename to libeap/wlantest/readpcap.c diff --git a/wlantest/rx_data.c b/libeap/wlantest/rx_data.c similarity index 100% rename from wlantest/rx_data.c rename to libeap/wlantest/rx_data.c diff --git a/wlantest/rx_eapol.c b/libeap/wlantest/rx_eapol.c similarity index 100% rename from wlantest/rx_eapol.c rename to libeap/wlantest/rx_eapol.c diff --git a/wlantest/rx_ip.c b/libeap/wlantest/rx_ip.c similarity index 100% rename from wlantest/rx_ip.c rename to libeap/wlantest/rx_ip.c diff --git a/wlantest/rx_mgmt.c b/libeap/wlantest/rx_mgmt.c similarity index 100% rename from wlantest/rx_mgmt.c rename to libeap/wlantest/rx_mgmt.c diff --git a/wlantest/rx_tdls.c b/libeap/wlantest/rx_tdls.c similarity index 100% rename from wlantest/rx_tdls.c rename to libeap/wlantest/rx_tdls.c diff --git a/wlantest/sta.c b/libeap/wlantest/sta.c similarity index 100% rename from wlantest/sta.c rename to libeap/wlantest/sta.c diff --git a/wlantest/test_vectors.c b/libeap/wlantest/test_vectors.c similarity index 100% rename from wlantest/test_vectors.c rename to libeap/wlantest/test_vectors.c diff --git a/wlantest/tkip.c b/libeap/wlantest/tkip.c similarity index 100% rename from wlantest/tkip.c rename to libeap/wlantest/tkip.c diff --git a/wlantest/wep.c b/libeap/wlantest/wep.c similarity index 100% rename from wlantest/wep.c rename to libeap/wlantest/wep.c diff --git a/wlantest/wired.c b/libeap/wlantest/wired.c similarity index 100% rename from wlantest/wired.c rename to libeap/wlantest/wired.c diff --git a/wlantest/wlantest.c b/libeap/wlantest/wlantest.c similarity index 100% rename from wlantest/wlantest.c rename to libeap/wlantest/wlantest.c diff --git a/wlantest/wlantest.h b/libeap/wlantest/wlantest.h similarity index 100% rename from wlantest/wlantest.h rename to libeap/wlantest/wlantest.h diff --git a/wlantest/wlantest_cli.c b/libeap/wlantest/wlantest_cli.c similarity index 100% rename from wlantest/wlantest_cli.c rename to libeap/wlantest/wlantest_cli.c diff --git a/wlantest/wlantest_ctrl.h b/libeap/wlantest/wlantest_ctrl.h similarity index 100% rename from wlantest/wlantest_ctrl.h rename to libeap/wlantest/wlantest_ctrl.h diff --git a/wlantest/writepcap.c b/libeap/wlantest/writepcap.c similarity index 100% rename from wlantest/writepcap.c rename to libeap/wlantest/writepcap.c diff --git a/wpa_supplicant/.gitignore b/libeap/wpa_supplicant/.gitignore similarity index 100% rename from wpa_supplicant/.gitignore rename to libeap/wpa_supplicant/.gitignore diff --git a/wpa_supplicant/Android.mk b/libeap/wpa_supplicant/Android.mk similarity index 100% rename from wpa_supplicant/Android.mk rename to libeap/wpa_supplicant/Android.mk diff --git a/wpa_supplicant/ChangeLog b/libeap/wpa_supplicant/ChangeLog similarity index 100% rename from wpa_supplicant/ChangeLog rename to libeap/wpa_supplicant/ChangeLog diff --git a/wpa_supplicant/Makefile b/libeap/wpa_supplicant/Makefile similarity index 100% rename from wpa_supplicant/Makefile rename to libeap/wpa_supplicant/Makefile diff --git a/wpa_supplicant/README b/libeap/wpa_supplicant/README similarity index 100% rename from wpa_supplicant/README rename to libeap/wpa_supplicant/README diff --git a/wpa_supplicant/README-HS20 b/libeap/wpa_supplicant/README-HS20 similarity index 100% rename from wpa_supplicant/README-HS20 rename to libeap/wpa_supplicant/README-HS20 diff --git a/wpa_supplicant/README-P2P b/libeap/wpa_supplicant/README-P2P similarity index 100% rename from wpa_supplicant/README-P2P rename to libeap/wpa_supplicant/README-P2P diff --git a/wpa_supplicant/README-WPS b/libeap/wpa_supplicant/README-WPS similarity index 100% rename from wpa_supplicant/README-WPS rename to libeap/wpa_supplicant/README-WPS diff --git a/wpa_supplicant/README-Windows.txt b/libeap/wpa_supplicant/README-Windows.txt similarity index 100% rename from wpa_supplicant/README-Windows.txt rename to libeap/wpa_supplicant/README-Windows.txt diff --git a/wpa_supplicant/android.config b/libeap/wpa_supplicant/android.config similarity index 100% rename from wpa_supplicant/android.config rename to libeap/wpa_supplicant/android.config diff --git a/wpa_supplicant/ap.c b/libeap/wpa_supplicant/ap.c similarity index 100% rename from wpa_supplicant/ap.c rename to libeap/wpa_supplicant/ap.c diff --git a/wpa_supplicant/ap.h b/libeap/wpa_supplicant/ap.h similarity index 100% rename from wpa_supplicant/ap.h rename to libeap/wpa_supplicant/ap.h diff --git a/wpa_supplicant/autoscan.c b/libeap/wpa_supplicant/autoscan.c similarity index 100% rename from wpa_supplicant/autoscan.c rename to libeap/wpa_supplicant/autoscan.c diff --git a/wpa_supplicant/autoscan.h b/libeap/wpa_supplicant/autoscan.h similarity index 100% rename from wpa_supplicant/autoscan.h rename to libeap/wpa_supplicant/autoscan.h diff --git a/wpa_supplicant/autoscan_exponential.c b/libeap/wpa_supplicant/autoscan_exponential.c similarity index 100% rename from wpa_supplicant/autoscan_exponential.c rename to libeap/wpa_supplicant/autoscan_exponential.c diff --git a/wpa_supplicant/autoscan_periodic.c b/libeap/wpa_supplicant/autoscan_periodic.c similarity index 100% rename from wpa_supplicant/autoscan_periodic.c rename to libeap/wpa_supplicant/autoscan_periodic.c diff --git a/wpa_supplicant/bgscan.c b/libeap/wpa_supplicant/bgscan.c similarity index 100% rename from wpa_supplicant/bgscan.c rename to libeap/wpa_supplicant/bgscan.c diff --git a/wpa_supplicant/bgscan.h b/libeap/wpa_supplicant/bgscan.h similarity index 100% rename from wpa_supplicant/bgscan.h rename to libeap/wpa_supplicant/bgscan.h diff --git a/wpa_supplicant/bgscan_learn.c b/libeap/wpa_supplicant/bgscan_learn.c similarity index 100% rename from wpa_supplicant/bgscan_learn.c rename to libeap/wpa_supplicant/bgscan_learn.c diff --git a/wpa_supplicant/bgscan_simple.c b/libeap/wpa_supplicant/bgscan_simple.c similarity index 100% rename from wpa_supplicant/bgscan_simple.c rename to libeap/wpa_supplicant/bgscan_simple.c diff --git a/wpa_supplicant/blacklist.c b/libeap/wpa_supplicant/blacklist.c similarity index 100% rename from wpa_supplicant/blacklist.c rename to libeap/wpa_supplicant/blacklist.c diff --git a/wpa_supplicant/blacklist.h b/libeap/wpa_supplicant/blacklist.h similarity index 100% rename from wpa_supplicant/blacklist.h rename to libeap/wpa_supplicant/blacklist.h diff --git a/wpa_supplicant/bss.c b/libeap/wpa_supplicant/bss.c similarity index 100% rename from wpa_supplicant/bss.c rename to libeap/wpa_supplicant/bss.c diff --git a/wpa_supplicant/bss.h b/libeap/wpa_supplicant/bss.h similarity index 100% rename from wpa_supplicant/bss.h rename to libeap/wpa_supplicant/bss.h diff --git a/wpa_supplicant/config.c b/libeap/wpa_supplicant/config.c similarity index 100% rename from wpa_supplicant/config.c rename to libeap/wpa_supplicant/config.c diff --git a/wpa_supplicant/config.h b/libeap/wpa_supplicant/config.h similarity index 100% rename from wpa_supplicant/config.h rename to libeap/wpa_supplicant/config.h diff --git a/wpa_supplicant/config_file.c b/libeap/wpa_supplicant/config_file.c similarity index 100% rename from wpa_supplicant/config_file.c rename to libeap/wpa_supplicant/config_file.c diff --git a/wpa_supplicant/config_none.c b/libeap/wpa_supplicant/config_none.c similarity index 100% rename from wpa_supplicant/config_none.c rename to libeap/wpa_supplicant/config_none.c diff --git a/wpa_supplicant/config_ssid.h b/libeap/wpa_supplicant/config_ssid.h similarity index 100% rename from wpa_supplicant/config_ssid.h rename to libeap/wpa_supplicant/config_ssid.h diff --git a/wpa_supplicant/config_winreg.c b/libeap/wpa_supplicant/config_winreg.c similarity index 100% rename from wpa_supplicant/config_winreg.c rename to libeap/wpa_supplicant/config_winreg.c diff --git a/wpa_supplicant/ctrl_iface.c b/libeap/wpa_supplicant/ctrl_iface.c similarity index 100% rename from wpa_supplicant/ctrl_iface.c rename to libeap/wpa_supplicant/ctrl_iface.c diff --git a/wpa_supplicant/ctrl_iface.h b/libeap/wpa_supplicant/ctrl_iface.h similarity index 100% rename from wpa_supplicant/ctrl_iface.h rename to libeap/wpa_supplicant/ctrl_iface.h diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/libeap/wpa_supplicant/ctrl_iface_named_pipe.c similarity index 100% rename from wpa_supplicant/ctrl_iface_named_pipe.c rename to libeap/wpa_supplicant/ctrl_iface_named_pipe.c diff --git a/wpa_supplicant/ctrl_iface_udp.c b/libeap/wpa_supplicant/ctrl_iface_udp.c similarity index 100% rename from wpa_supplicant/ctrl_iface_udp.c rename to libeap/wpa_supplicant/ctrl_iface_udp.c diff --git a/wpa_supplicant/ctrl_iface_unix.c b/libeap/wpa_supplicant/ctrl_iface_unix.c similarity index 100% rename from wpa_supplicant/ctrl_iface_unix.c rename to libeap/wpa_supplicant/ctrl_iface_unix.c diff --git a/wpa_supplicant/dbus/.gitignore b/libeap/wpa_supplicant/dbus/.gitignore similarity index 100% rename from wpa_supplicant/dbus/.gitignore rename to libeap/wpa_supplicant/dbus/.gitignore diff --git a/wpa_supplicant/dbus/Makefile b/libeap/wpa_supplicant/dbus/Makefile similarity index 100% rename from wpa_supplicant/dbus/Makefile rename to libeap/wpa_supplicant/dbus/Makefile diff --git a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/libeap/wpa_supplicant/dbus/dbus-wpa_supplicant.conf similarity index 100% rename from wpa_supplicant/dbus/dbus-wpa_supplicant.conf rename to libeap/wpa_supplicant/dbus/dbus-wpa_supplicant.conf diff --git a/wpa_supplicant/dbus/dbus_common.c b/libeap/wpa_supplicant/dbus/dbus_common.c similarity index 100% rename from wpa_supplicant/dbus/dbus_common.c rename to libeap/wpa_supplicant/dbus/dbus_common.c diff --git a/wpa_supplicant/dbus/dbus_common.h b/libeap/wpa_supplicant/dbus/dbus_common.h similarity index 100% rename from wpa_supplicant/dbus/dbus_common.h rename to libeap/wpa_supplicant/dbus/dbus_common.h diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/libeap/wpa_supplicant/dbus/dbus_common_i.h similarity index 100% rename from wpa_supplicant/dbus/dbus_common_i.h rename to libeap/wpa_supplicant/dbus/dbus_common_i.h diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/libeap/wpa_supplicant/dbus/dbus_dict_helpers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_dict_helpers.c rename to libeap/wpa_supplicant/dbus/dbus_dict_helpers.c diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/libeap/wpa_supplicant/dbus/dbus_dict_helpers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_dict_helpers.h rename to libeap/wpa_supplicant/dbus/dbus_dict_helpers.h diff --git a/wpa_supplicant/dbus/dbus_new.c b/libeap/wpa_supplicant/dbus/dbus_new.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new.c rename to libeap/wpa_supplicant/dbus/dbus_new.c diff --git a/wpa_supplicant/dbus/dbus_new.h b/libeap/wpa_supplicant/dbus/dbus_new.h similarity index 100% rename from wpa_supplicant/dbus/dbus_new.h rename to libeap/wpa_supplicant/dbus/dbus_new.h diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/libeap/wpa_supplicant/dbus/dbus_new_handlers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers.c rename to libeap/wpa_supplicant/dbus/dbus_new_handlers.c diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/libeap/wpa_supplicant/dbus/dbus_new_handlers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers.h rename to libeap/wpa_supplicant/dbus/dbus_new_handlers.h diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers_p2p.c rename to libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.c diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.h similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers_p2p.h rename to libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.h diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/libeap/wpa_supplicant/dbus/dbus_new_handlers_wps.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_handlers_wps.c rename to libeap/wpa_supplicant/dbus/dbus_new_handlers_wps.c diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/libeap/wpa_supplicant/dbus/dbus_new_helpers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_helpers.c rename to libeap/wpa_supplicant/dbus/dbus_new_helpers.c diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/libeap/wpa_supplicant/dbus/dbus_new_helpers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_new_helpers.h rename to libeap/wpa_supplicant/dbus/dbus_new_helpers.h diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/libeap/wpa_supplicant/dbus/dbus_new_introspect.c similarity index 100% rename from wpa_supplicant/dbus/dbus_new_introspect.c rename to libeap/wpa_supplicant/dbus/dbus_new_introspect.c diff --git a/wpa_supplicant/dbus/dbus_old.c b/libeap/wpa_supplicant/dbus/dbus_old.c similarity index 100% rename from wpa_supplicant/dbus/dbus_old.c rename to libeap/wpa_supplicant/dbus/dbus_old.c diff --git a/wpa_supplicant/dbus/dbus_old.h b/libeap/wpa_supplicant/dbus/dbus_old.h similarity index 100% rename from wpa_supplicant/dbus/dbus_old.h rename to libeap/wpa_supplicant/dbus/dbus_old.h diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/libeap/wpa_supplicant/dbus/dbus_old_handlers.c similarity index 100% rename from wpa_supplicant/dbus/dbus_old_handlers.c rename to libeap/wpa_supplicant/dbus/dbus_old_handlers.c diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/libeap/wpa_supplicant/dbus/dbus_old_handlers.h similarity index 100% rename from wpa_supplicant/dbus/dbus_old_handlers.h rename to libeap/wpa_supplicant/dbus/dbus_old_handlers.h diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/libeap/wpa_supplicant/dbus/dbus_old_handlers_wps.c similarity index 100% rename from wpa_supplicant/dbus/dbus_old_handlers_wps.c rename to libeap/wpa_supplicant/dbus/dbus_old_handlers_wps.c diff --git a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in b/libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in similarity index 100% rename from wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in rename to libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in diff --git a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in b/libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in similarity index 100% rename from wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in rename to libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in diff --git a/wpa_supplicant/defconfig b/libeap/wpa_supplicant/defconfig similarity index 100% rename from wpa_supplicant/defconfig rename to libeap/wpa_supplicant/defconfig diff --git a/wpa_supplicant/doc/docbook/.gitignore b/libeap/wpa_supplicant/doc/docbook/.gitignore similarity index 100% rename from wpa_supplicant/doc/docbook/.gitignore rename to libeap/wpa_supplicant/doc/docbook/.gitignore diff --git a/wpa_supplicant/doc/docbook/Makefile b/libeap/wpa_supplicant/doc/docbook/Makefile similarity index 100% rename from wpa_supplicant/doc/docbook/Makefile rename to libeap/wpa_supplicant/doc/docbook/Makefile diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/libeap/wpa_supplicant/doc/docbook/eapol_test.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/eapol_test.sgml rename to libeap/wpa_supplicant/doc/docbook/eapol_test.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_background.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_background.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_background.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_cli.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_cli.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_cli.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_gui.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_gui.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_gui.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_passphrase.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_passphrase.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_passphrase.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_priv.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_priv.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_priv.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/libeap/wpa_supplicant/doc/docbook/wpa_supplicant.sgml similarity index 100% rename from wpa_supplicant/doc/docbook/wpa_supplicant.sgml rename to libeap/wpa_supplicant/doc/docbook/wpa_supplicant.sgml diff --git a/wpa_supplicant/driver_i.h b/libeap/wpa_supplicant/driver_i.h similarity index 100% rename from wpa_supplicant/driver_i.h rename to libeap/wpa_supplicant/driver_i.h diff --git a/wpa_supplicant/eap_proxy_dummy.mak b/libeap/wpa_supplicant/eap_proxy_dummy.mak similarity index 100% rename from wpa_supplicant/eap_proxy_dummy.mak rename to libeap/wpa_supplicant/eap_proxy_dummy.mak diff --git a/wpa_supplicant/eap_proxy_dummy.mk b/libeap/wpa_supplicant/eap_proxy_dummy.mk similarity index 100% rename from wpa_supplicant/eap_proxy_dummy.mk rename to libeap/wpa_supplicant/eap_proxy_dummy.mk diff --git a/wpa_supplicant/eap_register.c b/libeap/wpa_supplicant/eap_register.c similarity index 100% rename from wpa_supplicant/eap_register.c rename to libeap/wpa_supplicant/eap_register.c diff --git a/wpa_supplicant/eap_testing.txt b/libeap/wpa_supplicant/eap_testing.txt similarity index 100% rename from wpa_supplicant/eap_testing.txt rename to libeap/wpa_supplicant/eap_testing.txt diff --git a/wpa_supplicant/eapol_test.c b/libeap/wpa_supplicant/eapol_test.c similarity index 100% rename from wpa_supplicant/eapol_test.c rename to libeap/wpa_supplicant/eapol_test.c diff --git a/wpa_supplicant/eapol_test.py b/libeap/wpa_supplicant/eapol_test.py similarity index 100% rename from wpa_supplicant/eapol_test.py rename to libeap/wpa_supplicant/eapol_test.py diff --git a/wpa_supplicant/events.c b/libeap/wpa_supplicant/events.c similarity index 100% rename from wpa_supplicant/events.c rename to libeap/wpa_supplicant/events.c diff --git a/wpa_supplicant/examples/60_wpa_supplicant b/libeap/wpa_supplicant/examples/60_wpa_supplicant similarity index 100% rename from wpa_supplicant/examples/60_wpa_supplicant rename to libeap/wpa_supplicant/examples/60_wpa_supplicant diff --git a/wpa_supplicant/examples/dbus-listen-preq.py b/libeap/wpa_supplicant/examples/dbus-listen-preq.py similarity index 100% rename from wpa_supplicant/examples/dbus-listen-preq.py rename to libeap/wpa_supplicant/examples/dbus-listen-preq.py diff --git a/wpa_supplicant/examples/ieee8021x.conf b/libeap/wpa_supplicant/examples/ieee8021x.conf similarity index 100% rename from wpa_supplicant/examples/ieee8021x.conf rename to libeap/wpa_supplicant/examples/ieee8021x.conf diff --git a/wpa_supplicant/examples/openCryptoki.conf b/libeap/wpa_supplicant/examples/openCryptoki.conf similarity index 100% rename from wpa_supplicant/examples/openCryptoki.conf rename to libeap/wpa_supplicant/examples/openCryptoki.conf diff --git a/wpa_supplicant/examples/p2p-action-udhcp.sh b/libeap/wpa_supplicant/examples/p2p-action-udhcp.sh similarity index 100% rename from wpa_supplicant/examples/p2p-action-udhcp.sh rename to libeap/wpa_supplicant/examples/p2p-action-udhcp.sh diff --git a/wpa_supplicant/examples/p2p-action.sh b/libeap/wpa_supplicant/examples/p2p-action.sh similarity index 100% rename from wpa_supplicant/examples/p2p-action.sh rename to libeap/wpa_supplicant/examples/p2p-action.sh diff --git a/wpa_supplicant/examples/p2p-nfc.py b/libeap/wpa_supplicant/examples/p2p-nfc.py similarity index 100% rename from wpa_supplicant/examples/p2p-nfc.py rename to libeap/wpa_supplicant/examples/p2p-nfc.py diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/libeap/wpa_supplicant/examples/p2p/p2p_connect.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_connect.py rename to libeap/wpa_supplicant/examples/p2p/p2p_connect.py diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/libeap/wpa_supplicant/examples/p2p/p2p_disconnect.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_disconnect.py rename to libeap/wpa_supplicant/examples/p2p/p2p_disconnect.py diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/libeap/wpa_supplicant/examples/p2p/p2p_find.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_find.py rename to libeap/wpa_supplicant/examples/p2p/p2p_find.py diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/libeap/wpa_supplicant/examples/p2p/p2p_flush.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_flush.py rename to libeap/wpa_supplicant/examples/p2p/p2p_flush.py diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/libeap/wpa_supplicant/examples/p2p/p2p_group_add.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_group_add.py rename to libeap/wpa_supplicant/examples/p2p/p2p_group_add.py diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/libeap/wpa_supplicant/examples/p2p/p2p_invite.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_invite.py rename to libeap/wpa_supplicant/examples/p2p/p2p_invite.py diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/libeap/wpa_supplicant/examples/p2p/p2p_listen.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_listen.py rename to libeap/wpa_supplicant/examples/p2p/p2p_listen.py diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/libeap/wpa_supplicant/examples/p2p/p2p_stop_find.py similarity index 100% rename from wpa_supplicant/examples/p2p/p2p_stop_find.py rename to libeap/wpa_supplicant/examples/p2p/p2p_stop_find.py diff --git a/wpa_supplicant/examples/plaintext.conf b/libeap/wpa_supplicant/examples/plaintext.conf similarity index 100% rename from wpa_supplicant/examples/plaintext.conf rename to libeap/wpa_supplicant/examples/plaintext.conf diff --git a/wpa_supplicant/examples/udhcpd-p2p.conf b/libeap/wpa_supplicant/examples/udhcpd-p2p.conf similarity index 100% rename from wpa_supplicant/examples/udhcpd-p2p.conf rename to libeap/wpa_supplicant/examples/udhcpd-p2p.conf diff --git a/wpa_supplicant/examples/wep.conf b/libeap/wpa_supplicant/examples/wep.conf similarity index 100% rename from wpa_supplicant/examples/wep.conf rename to libeap/wpa_supplicant/examples/wep.conf diff --git a/wpa_supplicant/examples/wpa-psk-tkip.conf b/libeap/wpa_supplicant/examples/wpa-psk-tkip.conf similarity index 100% rename from wpa_supplicant/examples/wpa-psk-tkip.conf rename to libeap/wpa_supplicant/examples/wpa-psk-tkip.conf diff --git a/wpa_supplicant/examples/wpa2-eap-ccmp.conf b/libeap/wpa_supplicant/examples/wpa2-eap-ccmp.conf similarity index 100% rename from wpa_supplicant/examples/wpa2-eap-ccmp.conf rename to libeap/wpa_supplicant/examples/wpa2-eap-ccmp.conf diff --git a/wpa_supplicant/examples/wpas-dbus-new-getall.py b/libeap/wpa_supplicant/examples/wpas-dbus-new-getall.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new-getall.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new-getall.py diff --git a/wpa_supplicant/examples/wpas-dbus-new-signals.py b/libeap/wpa_supplicant/examples/wpas-dbus-new-signals.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new-signals.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new-signals.py diff --git a/wpa_supplicant/examples/wpas-dbus-new-wps.py b/libeap/wpa_supplicant/examples/wpas-dbus-new-wps.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new-wps.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new-wps.py diff --git a/wpa_supplicant/examples/wpas-dbus-new.py b/libeap/wpa_supplicant/examples/wpas-dbus-new.py similarity index 100% rename from wpa_supplicant/examples/wpas-dbus-new.py rename to libeap/wpa_supplicant/examples/wpas-dbus-new.py diff --git a/wpa_supplicant/examples/wpas-test.py b/libeap/wpa_supplicant/examples/wpas-test.py similarity index 100% rename from wpa_supplicant/examples/wpas-test.py rename to libeap/wpa_supplicant/examples/wpas-test.py diff --git a/wpa_supplicant/examples/wps-ap-cli b/libeap/wpa_supplicant/examples/wps-ap-cli similarity index 100% rename from wpa_supplicant/examples/wps-ap-cli rename to libeap/wpa_supplicant/examples/wps-ap-cli diff --git a/wpa_supplicant/examples/wps-nfc.py b/libeap/wpa_supplicant/examples/wps-nfc.py similarity index 100% rename from wpa_supplicant/examples/wps-nfc.py rename to libeap/wpa_supplicant/examples/wps-nfc.py diff --git a/wpa_supplicant/gas_query.c b/libeap/wpa_supplicant/gas_query.c similarity index 100% rename from wpa_supplicant/gas_query.c rename to libeap/wpa_supplicant/gas_query.c diff --git a/wpa_supplicant/gas_query.h b/libeap/wpa_supplicant/gas_query.h similarity index 100% rename from wpa_supplicant/gas_query.h rename to libeap/wpa_supplicant/gas_query.h diff --git a/wpa_supplicant/hs20_supplicant.c b/libeap/wpa_supplicant/hs20_supplicant.c similarity index 100% rename from wpa_supplicant/hs20_supplicant.c rename to libeap/wpa_supplicant/hs20_supplicant.c diff --git a/wpa_supplicant/hs20_supplicant.h b/libeap/wpa_supplicant/hs20_supplicant.h similarity index 100% rename from wpa_supplicant/hs20_supplicant.h rename to libeap/wpa_supplicant/hs20_supplicant.h diff --git a/wpa_supplicant/ibss_rsn.c b/libeap/wpa_supplicant/ibss_rsn.c similarity index 100% rename from wpa_supplicant/ibss_rsn.c rename to libeap/wpa_supplicant/ibss_rsn.c diff --git a/wpa_supplicant/ibss_rsn.h b/libeap/wpa_supplicant/ibss_rsn.h similarity index 100% rename from wpa_supplicant/ibss_rsn.h rename to libeap/wpa_supplicant/ibss_rsn.h diff --git a/wpa_supplicant/interworking.c b/libeap/wpa_supplicant/interworking.c similarity index 100% rename from wpa_supplicant/interworking.c rename to libeap/wpa_supplicant/interworking.c diff --git a/wpa_supplicant/interworking.h b/libeap/wpa_supplicant/interworking.h similarity index 100% rename from wpa_supplicant/interworking.h rename to libeap/wpa_supplicant/interworking.h diff --git a/wpa_supplicant/main.c b/libeap/wpa_supplicant/main.c similarity index 100% rename from wpa_supplicant/main.c rename to libeap/wpa_supplicant/main.c diff --git a/wpa_supplicant/main_none.c b/libeap/wpa_supplicant/main_none.c similarity index 100% rename from wpa_supplicant/main_none.c rename to libeap/wpa_supplicant/main_none.c diff --git a/wpa_supplicant/main_winmain.c b/libeap/wpa_supplicant/main_winmain.c similarity index 100% rename from wpa_supplicant/main_winmain.c rename to libeap/wpa_supplicant/main_winmain.c diff --git a/wpa_supplicant/main_winsvc.c b/libeap/wpa_supplicant/main_winsvc.c similarity index 100% rename from wpa_supplicant/main_winsvc.c rename to libeap/wpa_supplicant/main_winsvc.c diff --git a/wpa_supplicant/mesh.c b/libeap/wpa_supplicant/mesh.c similarity index 100% rename from wpa_supplicant/mesh.c rename to libeap/wpa_supplicant/mesh.c diff --git a/wpa_supplicant/mesh.h b/libeap/wpa_supplicant/mesh.h similarity index 100% rename from wpa_supplicant/mesh.h rename to libeap/wpa_supplicant/mesh.h diff --git a/wpa_supplicant/mesh_mpm.c b/libeap/wpa_supplicant/mesh_mpm.c similarity index 100% rename from wpa_supplicant/mesh_mpm.c rename to libeap/wpa_supplicant/mesh_mpm.c diff --git a/wpa_supplicant/mesh_mpm.h b/libeap/wpa_supplicant/mesh_mpm.h similarity index 100% rename from wpa_supplicant/mesh_mpm.h rename to libeap/wpa_supplicant/mesh_mpm.h diff --git a/wpa_supplicant/mesh_rsn.c b/libeap/wpa_supplicant/mesh_rsn.c similarity index 100% rename from wpa_supplicant/mesh_rsn.c rename to libeap/wpa_supplicant/mesh_rsn.c diff --git a/wpa_supplicant/mesh_rsn.h b/libeap/wpa_supplicant/mesh_rsn.h similarity index 100% rename from wpa_supplicant/mesh_rsn.h rename to libeap/wpa_supplicant/mesh_rsn.h diff --git a/wpa_supplicant/nfc_pw_token.c b/libeap/wpa_supplicant/nfc_pw_token.c similarity index 100% rename from wpa_supplicant/nfc_pw_token.c rename to libeap/wpa_supplicant/nfc_pw_token.c diff --git a/wpa_supplicant/nmake.mak b/libeap/wpa_supplicant/nmake.mak similarity index 100% rename from wpa_supplicant/nmake.mak rename to libeap/wpa_supplicant/nmake.mak diff --git a/wpa_supplicant/notify.c b/libeap/wpa_supplicant/notify.c similarity index 100% rename from wpa_supplicant/notify.c rename to libeap/wpa_supplicant/notify.c diff --git a/wpa_supplicant/notify.h b/libeap/wpa_supplicant/notify.h similarity index 100% rename from wpa_supplicant/notify.h rename to libeap/wpa_supplicant/notify.h diff --git a/wpa_supplicant/offchannel.c b/libeap/wpa_supplicant/offchannel.c similarity index 100% rename from wpa_supplicant/offchannel.c rename to libeap/wpa_supplicant/offchannel.c diff --git a/wpa_supplicant/offchannel.h b/libeap/wpa_supplicant/offchannel.h similarity index 100% rename from wpa_supplicant/offchannel.h rename to libeap/wpa_supplicant/offchannel.h diff --git a/wpa_supplicant/p2p_supplicant.c b/libeap/wpa_supplicant/p2p_supplicant.c similarity index 100% rename from wpa_supplicant/p2p_supplicant.c rename to libeap/wpa_supplicant/p2p_supplicant.c diff --git a/wpa_supplicant/p2p_supplicant.h b/libeap/wpa_supplicant/p2p_supplicant.h similarity index 100% rename from wpa_supplicant/p2p_supplicant.h rename to libeap/wpa_supplicant/p2p_supplicant.h diff --git a/wpa_supplicant/p2p_supplicant_sd.c b/libeap/wpa_supplicant/p2p_supplicant_sd.c similarity index 100% rename from wpa_supplicant/p2p_supplicant_sd.c rename to libeap/wpa_supplicant/p2p_supplicant_sd.c diff --git a/wpa_supplicant/preauth_test.c b/libeap/wpa_supplicant/preauth_test.c similarity index 100% rename from wpa_supplicant/preauth_test.c rename to libeap/wpa_supplicant/preauth_test.c diff --git a/wpa_supplicant/scan.c b/libeap/wpa_supplicant/scan.c similarity index 100% rename from wpa_supplicant/scan.c rename to libeap/wpa_supplicant/scan.c diff --git a/wpa_supplicant/scan.h b/libeap/wpa_supplicant/scan.h similarity index 100% rename from wpa_supplicant/scan.h rename to libeap/wpa_supplicant/scan.h diff --git a/wpa_supplicant/sme.c b/libeap/wpa_supplicant/sme.c similarity index 100% rename from wpa_supplicant/sme.c rename to libeap/wpa_supplicant/sme.c diff --git a/wpa_supplicant/sme.h b/libeap/wpa_supplicant/sme.h similarity index 100% rename from wpa_supplicant/sme.h rename to libeap/wpa_supplicant/sme.h diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/libeap/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in similarity index 100% rename from wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in rename to libeap/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/libeap/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in similarity index 100% rename from wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in rename to libeap/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/libeap/wpa_supplicant/systemd/wpa_supplicant.service.arg.in similarity index 100% rename from wpa_supplicant/systemd/wpa_supplicant.service.arg.in rename to libeap/wpa_supplicant/systemd/wpa_supplicant.service.arg.in diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/libeap/wpa_supplicant/systemd/wpa_supplicant.service.in similarity index 100% rename from wpa_supplicant/systemd/wpa_supplicant.service.in rename to libeap/wpa_supplicant/systemd/wpa_supplicant.service.in diff --git a/wpa_supplicant/tests/link_test.c b/libeap/wpa_supplicant/tests/link_test.c similarity index 100% rename from wpa_supplicant/tests/link_test.c rename to libeap/wpa_supplicant/tests/link_test.c diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/libeap/wpa_supplicant/tests/test_eap_sim_common.c similarity index 100% rename from wpa_supplicant/tests/test_eap_sim_common.c rename to libeap/wpa_supplicant/tests/test_eap_sim_common.c diff --git a/wpa_supplicant/tests/test_wpa.c b/libeap/wpa_supplicant/tests/test_wpa.c similarity index 100% rename from wpa_supplicant/tests/test_wpa.c rename to libeap/wpa_supplicant/tests/test_wpa.c diff --git a/wpa_supplicant/todo.txt b/libeap/wpa_supplicant/todo.txt similarity index 100% rename from wpa_supplicant/todo.txt rename to libeap/wpa_supplicant/todo.txt diff --git a/wpa_supplicant/utils/log2pcap.py b/libeap/wpa_supplicant/utils/log2pcap.py similarity index 100% rename from wpa_supplicant/utils/log2pcap.py rename to libeap/wpa_supplicant/utils/log2pcap.py diff --git a/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/libeap/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj similarity index 100% rename from wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj rename to libeap/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj diff --git a/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj b/libeap/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj similarity index 100% rename from wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj rename to libeap/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj diff --git a/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj b/libeap/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj rename to libeap/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj diff --git a/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/libeap/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj rename to libeap/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj diff --git a/wpa_supplicant/vs2005/wpa_supplicant.sln b/libeap/wpa_supplicant/vs2005/wpa_supplicant.sln similarity index 100% rename from wpa_supplicant/vs2005/wpa_supplicant.sln rename to libeap/wpa_supplicant/vs2005/wpa_supplicant.sln diff --git a/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/libeap/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj rename to libeap/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj diff --git a/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj b/libeap/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj similarity index 100% rename from wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj rename to libeap/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj diff --git a/wpa_supplicant/wifi_display.c b/libeap/wpa_supplicant/wifi_display.c similarity index 100% rename from wpa_supplicant/wifi_display.c rename to libeap/wpa_supplicant/wifi_display.c diff --git a/wpa_supplicant/wifi_display.h b/libeap/wpa_supplicant/wifi_display.h similarity index 100% rename from wpa_supplicant/wifi_display.h rename to libeap/wpa_supplicant/wifi_display.h diff --git a/wpa_supplicant/win_example.reg b/libeap/wpa_supplicant/win_example.reg similarity index 100% rename from wpa_supplicant/win_example.reg rename to libeap/wpa_supplicant/win_example.reg diff --git a/wpa_supplicant/win_if_list.c b/libeap/wpa_supplicant/win_if_list.c similarity index 100% rename from wpa_supplicant/win_if_list.c rename to libeap/wpa_supplicant/win_if_list.c diff --git a/wpa_supplicant/wmm_ac.c b/libeap/wpa_supplicant/wmm_ac.c similarity index 100% rename from wpa_supplicant/wmm_ac.c rename to libeap/wpa_supplicant/wmm_ac.c diff --git a/wpa_supplicant/wmm_ac.h b/libeap/wpa_supplicant/wmm_ac.h similarity index 100% rename from wpa_supplicant/wmm_ac.h rename to libeap/wpa_supplicant/wmm_ac.h diff --git a/wpa_supplicant/wnm_sta.c b/libeap/wpa_supplicant/wnm_sta.c similarity index 100% rename from wpa_supplicant/wnm_sta.c rename to libeap/wpa_supplicant/wnm_sta.c diff --git a/wpa_supplicant/wnm_sta.h b/libeap/wpa_supplicant/wnm_sta.h similarity index 100% rename from wpa_supplicant/wnm_sta.h rename to libeap/wpa_supplicant/wnm_sta.h diff --git a/wpa_supplicant/wpa_cli.c b/libeap/wpa_supplicant/wpa_cli.c similarity index 100% rename from wpa_supplicant/wpa_cli.c rename to libeap/wpa_supplicant/wpa_cli.c diff --git a/wpa_supplicant/wpa_gui-qt4/.gitignore b/libeap/wpa_supplicant/wpa_gui-qt4/.gitignore similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/.gitignore rename to libeap/wpa_supplicant/wpa_gui-qt4/.gitignore diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/addinterface.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/addinterface.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/addinterface.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.h b/libeap/wpa_supplicant/wpa_gui-qt4/addinterface.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/addinterface.h rename to libeap/wpa_supplicant/wpa_gui-qt4/addinterface.h diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/eventhistory.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/eventhistory.h rename to libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.h diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.ui b/libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/eventhistory.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.ui diff --git a/wpa_supplicant/wpa_gui-qt4/icons.qrc b/libeap/wpa_supplicant/wpa_gui-qt4/icons.qrc similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons.qrc rename to libeap/wpa_supplicant/wpa_gui-qt4/icons.qrc diff --git a/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/libeap/wpa_supplicant/wpa_gui-qt4/icons/Makefile similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/Makefile rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/Makefile diff --git a/wpa_supplicant/wpa_gui-qt4/icons/README b/libeap/wpa_supplicant/wpa_gui-qt4/icons/README similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/README rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/README diff --git a/wpa_supplicant/wpa_gui-qt4/icons/ap.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/ap.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/ap.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/ap.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/group.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/group.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/group.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/group.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/invitation.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/laptop.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg b/libeap/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg rename to libeap/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg diff --git a/wpa_supplicant/wpa_gui-qt4/icons_png.qrc b/libeap/wpa_supplicant/wpa_gui-qt4/icons_png.qrc similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/icons_png.qrc rename to libeap/wpa_supplicant/wpa_gui-qt4/icons_png.qrc diff --git a/wpa_supplicant/wpa_gui-qt4/lang/.gitignore b/libeap/wpa_supplicant/wpa_gui-qt4/lang/.gitignore similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/lang/.gitignore rename to libeap/wpa_supplicant/wpa_gui-qt4/lang/.gitignore diff --git a/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts b/libeap/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts rename to libeap/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts diff --git a/wpa_supplicant/wpa_gui-qt4/main.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/main.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/main.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/main.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/networkconfig.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/networkconfig.h rename to libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.h diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.ui b/libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/networkconfig.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.ui diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/peers.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/peers.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/peers.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/peers.h b/libeap/wpa_supplicant/wpa_gui-qt4/peers.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/peers.h rename to libeap/wpa_supplicant/wpa_gui-qt4/peers.h diff --git a/wpa_supplicant/wpa_gui-qt4/peers.ui b/libeap/wpa_supplicant/wpa_gui-qt4/peers.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/peers.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/peers.ui diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/scanresults.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresults.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresults.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.h b/libeap/wpa_supplicant/wpa_gui-qt4/scanresults.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresults.h rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresults.h diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.ui b/libeap/wpa_supplicant/wpa_gui-qt4/scanresults.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresults.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresults.ui diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h b/libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/scanresultsitem.h rename to libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/signalbar.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/signalbar.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/signalbar.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.h b/libeap/wpa_supplicant/wpa_gui-qt4/signalbar.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/signalbar.h rename to libeap/wpa_supplicant/wpa_gui-qt4/signalbar.h diff --git a/wpa_supplicant/wpa_gui-qt4/stringquery.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/stringquery.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/stringquery.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/stringquery.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/stringquery.h b/libeap/wpa_supplicant/wpa_gui-qt4/stringquery.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/stringquery.h rename to libeap/wpa_supplicant/wpa_gui-qt4/stringquery.h diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/userdatarequest.h rename to libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.h diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui b/libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/userdatarequest.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop b/libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop rename to libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpa_gui.pro rename to libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/libeap/wpa_supplicant/wpa_gui-qt4/wpagui.cpp similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpagui.cpp rename to libeap/wpa_supplicant/wpa_gui-qt4/wpagui.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/libeap/wpa_supplicant/wpa_gui-qt4/wpagui.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpagui.h rename to libeap/wpa_supplicant/wpa_gui-qt4/wpagui.h diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.ui b/libeap/wpa_supplicant/wpa_gui-qt4/wpagui.ui similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpagui.ui rename to libeap/wpa_supplicant/wpa_gui-qt4/wpagui.ui diff --git a/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/libeap/wpa_supplicant/wpa_gui-qt4/wpamsg.h similarity index 100% rename from wpa_supplicant/wpa_gui-qt4/wpamsg.h rename to libeap/wpa_supplicant/wpa_gui-qt4/wpamsg.h diff --git a/wpa_supplicant/wpa_passphrase.c b/libeap/wpa_supplicant/wpa_passphrase.c similarity index 100% rename from wpa_supplicant/wpa_passphrase.c rename to libeap/wpa_supplicant/wpa_passphrase.c diff --git a/wpa_supplicant/wpa_priv.c b/libeap/wpa_supplicant/wpa_priv.c similarity index 100% rename from wpa_supplicant/wpa_priv.c rename to libeap/wpa_supplicant/wpa_priv.c diff --git a/wpa_supplicant/wpa_supplicant.c b/libeap/wpa_supplicant/wpa_supplicant.c similarity index 100% rename from wpa_supplicant/wpa_supplicant.c rename to libeap/wpa_supplicant/wpa_supplicant.c diff --git a/wpa_supplicant/wpa_supplicant.conf b/libeap/wpa_supplicant/wpa_supplicant.conf similarity index 100% rename from wpa_supplicant/wpa_supplicant.conf rename to libeap/wpa_supplicant/wpa_supplicant.conf diff --git a/wpa_supplicant/wpa_supplicant_conf.mk b/libeap/wpa_supplicant/wpa_supplicant_conf.mk similarity index 100% rename from wpa_supplicant/wpa_supplicant_conf.mk rename to libeap/wpa_supplicant/wpa_supplicant_conf.mk diff --git a/wpa_supplicant/wpa_supplicant_conf.sh b/libeap/wpa_supplicant/wpa_supplicant_conf.sh similarity index 100% rename from wpa_supplicant/wpa_supplicant_conf.sh rename to libeap/wpa_supplicant/wpa_supplicant_conf.sh diff --git a/wpa_supplicant/wpa_supplicant_i.h b/libeap/wpa_supplicant/wpa_supplicant_i.h similarity index 100% rename from wpa_supplicant/wpa_supplicant_i.h rename to libeap/wpa_supplicant/wpa_supplicant_i.h diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/libeap/wpa_supplicant/wpa_supplicant_template.conf similarity index 100% rename from wpa_supplicant/wpa_supplicant_template.conf rename to libeap/wpa_supplicant/wpa_supplicant_template.conf diff --git a/wpa_supplicant/wpas_glue.c b/libeap/wpa_supplicant/wpas_glue.c similarity index 100% rename from wpa_supplicant/wpas_glue.c rename to libeap/wpa_supplicant/wpas_glue.c diff --git a/wpa_supplicant/wpas_glue.h b/libeap/wpa_supplicant/wpas_glue.h similarity index 100% rename from wpa_supplicant/wpas_glue.h rename to libeap/wpa_supplicant/wpas_glue.h diff --git a/wpa_supplicant/wpas_kay.c b/libeap/wpa_supplicant/wpas_kay.c similarity index 100% rename from wpa_supplicant/wpas_kay.c rename to libeap/wpa_supplicant/wpas_kay.c diff --git a/wpa_supplicant/wpas_kay.h b/libeap/wpa_supplicant/wpas_kay.h similarity index 100% rename from wpa_supplicant/wpas_kay.h rename to libeap/wpa_supplicant/wpas_kay.h diff --git a/wpa_supplicant/wpas_module_tests.c b/libeap/wpa_supplicant/wpas_module_tests.c similarity index 100% rename from wpa_supplicant/wpas_module_tests.c rename to libeap/wpa_supplicant/wpas_module_tests.c diff --git a/wpa_supplicant/wps_supplicant.c b/libeap/wpa_supplicant/wps_supplicant.c similarity index 100% rename from wpa_supplicant/wps_supplicant.c rename to libeap/wpa_supplicant/wps_supplicant.c diff --git a/wpa_supplicant/wps_supplicant.h b/libeap/wpa_supplicant/wps_supplicant.h similarity index 100% rename from wpa_supplicant/wps_supplicant.h rename to libeap/wpa_supplicant/wps_supplicant.h diff --git a/wpadebug/AndroidManifest.xml b/libeap/wpadebug/AndroidManifest.xml similarity index 100% rename from wpadebug/AndroidManifest.xml rename to libeap/wpadebug/AndroidManifest.xml diff --git a/wpadebug/README b/libeap/wpadebug/README similarity index 100% rename from wpadebug/README rename to libeap/wpadebug/README diff --git a/wpadebug/build.xml b/libeap/wpadebug/build.xml similarity index 100% rename from wpadebug/build.xml rename to libeap/wpadebug/build.xml diff --git a/wpadebug/project.properties b/libeap/wpadebug/project.properties similarity index 100% rename from wpadebug/project.properties rename to libeap/wpadebug/project.properties diff --git a/wpadebug/res/layout/cred_edit.xml b/libeap/wpadebug/res/layout/cred_edit.xml similarity index 100% rename from wpadebug/res/layout/cred_edit.xml rename to libeap/wpadebug/res/layout/cred_edit.xml diff --git a/wpadebug/res/layout/main.xml b/libeap/wpadebug/res/layout/main.xml similarity index 100% rename from wpadebug/res/layout/main.xml rename to libeap/wpadebug/res/layout/main.xml diff --git a/wpadebug/res/raw/shell_commands.txt b/libeap/wpadebug/res/raw/shell_commands.txt similarity index 100% rename from wpadebug/res/raw/shell_commands.txt rename to libeap/wpadebug/res/raw/shell_commands.txt diff --git a/wpadebug/res/raw/wpa_commands.txt b/libeap/wpadebug/res/raw/wpa_commands.txt similarity index 100% rename from wpadebug/res/raw/wpa_commands.txt rename to libeap/wpadebug/res/raw/wpa_commands.txt diff --git a/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/CommandListActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java diff --git a/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java diff --git a/wpadebug/src/w1/fi/wpadebug/MainActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/MainActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/MainActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/MainActivity.java diff --git a/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java b/libeap/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/WifiReceiver.java rename to libeap/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java diff --git a/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java diff --git a/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java diff --git a/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java diff --git a/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java diff --git a/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java b/libeap/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java similarity index 100% rename from wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java rename to libeap/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java diff --git a/wpaspy/Makefile b/libeap/wpaspy/Makefile similarity index 100% rename from wpaspy/Makefile rename to libeap/wpaspy/Makefile diff --git a/wpaspy/setup.py b/libeap/wpaspy/setup.py similarity index 100% rename from wpaspy/setup.py rename to libeap/wpaspy/setup.py diff --git a/wpaspy/test.py b/libeap/wpaspy/test.py similarity index 100% rename from wpaspy/test.py rename to libeap/wpaspy/test.py diff --git a/wpaspy/wpaspy.c b/libeap/wpaspy/wpaspy.c similarity index 100% rename from wpaspy/wpaspy.c rename to libeap/wpaspy/wpaspy.c diff --git a/wpaspy/wpaspy.py b/libeap/wpaspy/wpaspy.py similarity index 100% rename from wpaspy/wpaspy.py rename to libeap/wpaspy/wpaspy.py diff --git a/m4/minuso.m4 b/m4/minuso.m4 new file mode 100644 index 0000000..d8b1620 --- /dev/null +++ b/m4/minuso.m4 @@ -0,0 +1,35 @@ +## -*- Autoconf -*- +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) diff --git a/mech_eap.spec.in b/mech_eap.spec.in new file mode 100644 index 0000000..d2b578c --- /dev/null +++ b/mech_eap.spec.in @@ -0,0 +1,70 @@ +%global _moonshot_krb5 %{!?_moonshot_krb5:krb5-devel}%{?_moonshot_krb5} +Name: moonshot-gss-eap +Version: @VERSION@ +Release: 1%{?dist} +Summary: Moonshot GSS-API Mechanism + +Group: Security Tools +License: BSD +URL: http://www.project-moonshot.org/ +Source0: mech_eap-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root + +BuildRequires: %{_moonshot_krb5} >= 1.9.1 +BuildRequires: moonshot-ui-devel +BuildRequires: jansson-devel +Requires: moonshot-ui +BuildRequires: libradsec-devel >= 0.0.3 +BuildRequires: shibboleth-sp-devel >= 2.5 +BuildRequires: libshibresolver-devel + + + +%description +Project Moonshot provides federated access management. + + +%prep +%setup -q -n mech_eap-%{version} + + +%build +%configure --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --enable-reauth LDFLAGs="${LDFLAGS} -L/opt/shibboleth/%{_lib} -Wl,--rpath=/opt/shibboleth/%{_lib}" CPPFLAGS="${CPPFLAGS} -I/opt/shibboleth/include" +make %{?_smp_mflags} + + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +oid_aes128=1.3.6.1.5.5.15.1.1.17 +oid_aes256=1.3.6.1.5.5.15.1.1.18 +mechfile=%{_sysconfdir}/gss/mech +mkdir -p %{_sysconfdir}/gss +test -e $mechfile |touch $mechfile +fgrep $oid_aes128 $mechfile ||echo eap-aes128 $oid_aes128 mech_eap.so >>$mechfile +fgrep $oid_aes256 $mechfile ||echo eap-aes256 $oid_aes256 mech_eap.so >>$mechfile + + +%files +%defattr(-,root,root,-) +%doc mech_eap/README +%doc mech_eap/LICENSE +%doc mech_eap/AUTHORS +%{_libdir}/gss/mech_eap.so +%exclude %{_libdir}/gss/mech_eap.la +%{_includedir}/gssapi/*.h +%exclude %{_libdir}/krb5/plugins/authdata/* +#%{_libdir}/krb5/plugins/authdata/*.so + + + +%changelog +* Wed Sep 28 2011 - @VERSION@-2 +- Add radius_ad plugin + diff --git a/mech_eap/.gitignore b/mech_eap/.gitignore new file mode 100644 index 0000000..06a3924 --- /dev/null +++ b/mech_eap/.gitignore @@ -0,0 +1,32 @@ +/aclocal.m4 +/autom4te.cache +/compile +/config.guess +/config.log +/config.status +/config.sub +/config.h +/configure +/config.h.in +/depcomp + +/libtool +/ltmain.sh +/missing + +/gsseap_err.[ch] +/radsec_err.[ch] + +.DS_Store + +Makefile.in +Makefile + +*.la +*.lo +*~ + +.deps +.libs +.a.out.dSYM +.dSYM diff --git a/mech_eap/AUTHORS b/mech_eap/AUTHORS new file mode 100644 index 0000000..3007a4b --- /dev/null +++ b/mech_eap/AUTHORS @@ -0,0 +1,6 @@ +The initial implementation of mech_eap was written by PADL Software +under contract to JANET(UK). + +-- +Luke Howard +January, 2011 diff --git a/mech_eap/COPYING b/mech_eap/COPYING new file mode 100644 index 0000000..7554e77 --- /dev/null +++ b/mech_eap/COPYING @@ -0,0 +1,3 @@ +Copyright (c) 2011, JANET(UK) + +See the LICENSE file for licensing terms. diff --git a/mech_eap/LICENSE b/mech_eap/LICENSE new file mode 100644 index 0000000..1b03a95 --- /dev/null +++ b/mech_eap/LICENSE @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/mech_eap/Makefile.am b/mech_eap/Makefile.am new file mode 100644 index 0000000..02dd9f2 --- /dev/null +++ b/mech_eap/Makefile.am @@ -0,0 +1,192 @@ +AUTOMAKE_OPTIONS = foreign + +EXTRA_DIST = gsseap_err.et radsec_err.et \ + mech_eap.exports mech_eap-noacceptor.exports radius_ad.exports \ + LICENSE AUTHORS mech \ + README.samba4 NOTES radsec.conf + + +gssincludedir = $(includedir)/gssapi +gssinclude_HEADERS = gssapi_eap.h + +EAP_CFLAGS = -I$(srcdir)/../libeap/src -I$(srcdir)/../libeap/src/common -I$(srcdir)/../libeap/src/eap_common \ + -I$(srcdir)/../libeap/src/utils + +if GSSEAP_ENABLE_ACCEPTOR +GSSEAP_EXPORTS = $(srcdir)/mech_eap.exports +else +GSSEAP_EXPORTS = $(srcdir)/mech_eap-noacceptor.exports +endif + +gssdir = $(libdir)/gss +gss_LTLIBRARIES = mech_eap.la + +if TARGET_WINDOWS +EAP_CFLAGS += -DCONFIG_WIN32_DEFAULTS -DUSE_INTERNAL_CRYPTO +OS_LIBS = -lshell32 -ladvapi32 -lws2_32 -lcomerr32 +mech_eap_la_CFLAGS = -Zi +mech_eap_la_CXXFLAGS = -Zi +else +EAP_CFLAGS += -DEAP_TLS -DEAP_PEAP -DEAP_TTLS -DEAP_MD5 -DEAP_MSCHAPv2 -DEAP_GTC -DEAP_OTP -DEAP_LEAP -DEAP_PSK -DEAP_PAX -DEAP_SAKE -DEAP_GPSK -DEAP_GPSK_SHA256 -DEAP_SERVER_IDENTITY -DEAP_SERVER_TLS -DEAP_SERVER_PEAP -DEAP_SERVER_TTLS -DEAP_SERVER_MD5 -DEAP_SERVER_MSCHAPV2 -DEAP_SERVER_GTC -DEAP_SERVER_PSK -DEAP_SERVER_PAX -DEAP_SERVER_SAKE -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256 -DIEEE8021X_EAPOL +OS_LIBS = +mech_eap_la_CFLAGS = -Werror -Wall -Wunused-parameter +mech_eap_la_CXXFLAGS = -Werror -Wall -Wunused-parameter +endif +mech_eap_la_DEPENDENCIES = $(GSSEAP_EXPORTS) + +mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -DDATAROOTDIR=\"${datarootdir}\" +mech_eap_la_CFLAGS += \ + @KRB5_CFLAGS@ @RADSEC_CFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS) +mech_eap_la_CXXFLAGS += \ + @KRB5_CFLAGS@ @RADSEC_CFLAGS@ \ + @OPENSAML_CXXFLAGS@ @SHIBRESOLVER_CXXFLAGS@ @SHIBSP_CXXFLAGS@ \ + @TARGET_CFLAGS@ $(EAP_CFLAGS) +mech_eap_la_LDFLAGS = -avoid-version -module \ + -export-symbols $(GSSEAP_EXPORTS) -no-undefined \ + @KRB5_LDFLAGS@ @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@ @OPENSSL_LDFLAGS@ + +if TARGET_WINDOWS +mech_eap_la_LDFLAGS += -debug +endif + +mech_eap_la_LIBADD = @KRB5_LIBS@ ../libeap/libeap.la @RADSEC_LIBS@ \ + @OPENSAML_LIBS@ @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@ \ + @OPENSSL_LIBS@ +mech_eap_la_SOURCES = \ + acquire_cred.c \ + acquire_cred_with_password.c \ + add_cred.c \ + add_cred_with_password.c \ + authorize_localname.c \ + canonicalize_name.c \ + compare_name.c \ + context_time.c \ + delete_sec_context.c \ + display_name.c \ + display_name_ext.c \ + display_status.c \ + duplicate_name.c \ + eap_mech.c \ + exchange_meta_data.c \ + export_name.c \ + export_sec_context.c \ + get_mic.c \ + gsseap_err.c \ + import_name.c \ + import_sec_context.c \ + indicate_mechs.c \ + init_sec_context.c \ + inquire_attrs_for_mech.c \ + inquire_context.c \ + inquire_cred.c \ + inquire_cred_by_mech.c \ + inquire_cred_by_oid.c \ + inquire_mech_for_saslname.c \ + inquire_mechs_for_name.c \ + inquire_names_for_mech.c \ + inquire_saslname_for_mech.c \ + inquire_sec_context_by_oid.c \ + process_context_token.c \ + pseudo_random.c \ + query_mechanism_info.c \ + query_meta_data.c \ + radsec_err.c \ + release_cred.c \ + release_name.c \ + release_oid.c \ + set_cred_option.c \ + set_sec_context_option.c \ + store_cred.c \ + unwrap.c \ + unwrap_iov.c \ + util_buffer.c \ + util_context.c \ + util_cksum.c \ + util_cred.c \ + util_crypt.c \ + util_krb.c \ + util_lucid.c \ + util_mech.c \ + util_name.c \ + util_oid.c \ + util_ordering.c \ + util_radius.cpp \ + util_sm.c \ + util_tld.c \ + util_token.c \ + verify_mic.c \ + wrap.c \ + wrap_iov.c \ + wrap_iov_length.c \ + wrap_size_limit.c \ + gssapiP_eap.h \ + util_attr.h \ + util_base64.h \ + util.h \ + util_json.h \ + util_radius.h \ + util_reauth.h \ + util_saml.h \ + util_shib.h + +if LIBMOONSHOT +mech_eap_la_SOURCES += util_moonshot.c +mech_eap_la_CFLAGS += @LIBMOONSHOT_CFLAGS@ +mech_eap_la_LDFLAGS += @LIBMOONSHOT_LDFLAGS@ +mech_eap_la_LIBADD += @LIBMOONSHOT_LIBS@ +endif + + +if GSSEAP_ENABLE_ACCEPTOR + +mech_eap_la_SOURCES += \ + accept_sec_context.c \ + delete_name_attribute.c \ + export_name_composite.c \ + get_name_attribute.c \ + inquire_name.c \ + map_name_to_any.c \ + release_any_name_mapping.c \ + set_name_attribute.c \ + util_attr.cpp \ + util_base64.c \ + util_json.cpp + +if OPENSAML +mech_eap_la_SOURCES += util_saml.cpp +endif + +if SHIBRESOLVER +mech_eap_la_SOURCES += util_shib.cpp +endif + +endif + +BUILT_SOURCES = gsseap_err.c radsec_err.c gsseap_err.h radsec_err.h + +if GSSEAP_ENABLE_REAUTH +mech_eap_la_SOURCES += util_reauth.c + +if !HEIMDAL +krb5pluginsdir = $(libdir)/krb5/plugins/authdata +krb5plugins_LTLIBRARIES = radius_ad.la + +radius_ad_la_CFLAGS = -Werror -Wall -Wunused-parameter \ + @KRB5_CFLAGS@ $(EAP_CFLAGS) @RADSEC_CFLAGS@ @TARGET_CFLAGS@ +radius_ad_la_LDFLAGS = -avoid-version -module \ + -export-symbols $(srcdir)/radius_ad.exports -no-undefined +radius_ad_la_LIBADD = @KRB5_LIBS@ +radius_ad_la_SOURCES = util_adshim.c authdata_plugin.h +endif +endif + +gsseap_err.h gsseap_err.c: gsseap_err.et + $(COMPILE_ET) $< + +radsec_err.h radsec_err.c: radsec_err.et + $(COMPILE_ET) $< + +radsec_err.c: radsec_err.h + +clean-generic: + rm -f gsseap_err.[ch] radsec_err.[ch] diff --git a/mech_eap/NEWS b/mech_eap/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/mech_eap/NOTES b/mech_eap/NOTES new file mode 100644 index 0000000..849ce4e --- /dev/null +++ b/mech_eap/NOTES @@ -0,0 +1,9 @@ +- gss_xxx routines acquire lock, gssXxx don't + +- git + +If you do want to update with a rebase, deletethe branch from the +server first then push the rebased branch + +to delete a branch from a server git push origin :branch_to_del + diff --git a/mech_eap/README b/mech_eap/README new file mode 100644 index 0000000..c16ef62 --- /dev/null +++ b/mech_eap/README @@ -0,0 +1,147 @@ +Overview +======== + +This is an implementation of the GSS EAP mechanism, as described in +draft-ietf-abfab-gss-eap-01.txt. + +Building +======== + +In order to build this, a recent Kerberos implementation (MIT or +Heimdal), Shibboleth, and EAP libraries are required, along with +all of their dependencies. + +Note: not all SPIs are supported by the Heimdal mechanism glue, +so not all features will be available. + +Installing +========== + +GSS mechglue +------------ + +When installing, be sure to edit $prefix/etc/gss/mech to register +the EAP mechanisms. A sample configuration file is in this directory. +You may need to specify an absolute path. + +RADIUS client library +--------------------- + +Make sure your RADIUS library is configured to talk to the server of +your choice: see the example radsec.conf in this directory. If you +want to use TCP or TLS, you'll need to run radsecproxy in front of +your RADIUS server. + +RADIUS server +------------- + +These instructions apply to FreeRADIUS only, which is downloadable +from http://freeradius.org/. After configure, make, install, do the +following: + +On the RADIUS server side, you need to install dictionary.ukerna to +$prefix/etc/raddb and include it from the main dictionary file, by +adding: + + $INCLUDE dictionary.ukerna + +to $prefix/etc/raddb/dictionary. Make sure these files are world- +readable; they weren't in my installation. + +Edit $prefix/etc/raddb/users to add your test user and password: + + bob@PROJECT-MOONSHOT.ORG Cleartext-Password := secret + +Add an entry for your acceptor to $prefix/etc/raddb/clients.conf: + + client somehost { + ipaddr = 127.0.0.1 + secret = testing123 + require_message_authenticator = yes + } + +Edit $prefix/etc/raddb/eap.conf and set: + + eap { +... + default_eap_type = ttls +... + tls { + certdir = ... + cadir = ... + private_key_file = ... + certificate_file = ... + } + ttls { + default_eap_type = mschapv2 + copy_request_to_tunnel = no + use_tunneled_reply = no + virtual_server = "inner-tunnel" + } +... + } + +to enable EAP-TTLS. + +If you want the acceptor be able to identify the user, the RADIUS +server needs to echo back the EAP username from the inner tunnel; +for privacy, mech_eap only sends the realm in the EAP Identity +response. To configure this with FreeRADIUS, add: + + update outer.reply { + User-Name = "%{request:User-Name}" + } + +If you want to add a SAML assertion, do this with "update reply" +in $prefix/etc/raddb/sites-available/default: + + update reply { + SAML-AAA-Assertion = ', and +appropriately ( is the name of the host running the server, +not the RADIUS server). + +% gss-client -port 5555 -spnego -mech "{1 3 6 1 5 5 15 1 1 18}" \ + -user @ -pass host@ \ + "Testing GSS EAP" +% gss-server -port 5555 -export host@ + +Note: for SASL you will be prompted for a username and password. + +% client -C -p 5556 -s host -m EAP-AES128 +% server -c -p 5556 -s host -h + +To test fast reauthentication support, add the following to +/etc/krb5.conf: + +[appdefaults] + eap_gss = { + reauth_use_ccache = TRUE + } + +This will store a Kerberos ticket for a GSS-EAP authenticated user +in a credentials cache, which can then be used for re-authentication +to the same acceptor. You must have a valid keytab configured. + +In this testing phase of Moonshot, it's also possible to store a +default identity and credential in a file. The format consists of +the string representation of the initiator identity and the password, +separated by newlines. The default location of this file is +.gss_eap_id in the user's home directory, however the GSSEAP_IDENTITY +environment variable can be used to set an alternate location. + +You can also set a default realm in [appdefaults]; the Kerberos +default realm is never used by mech_eap (or at least, that is the +intention), so if unspecified you must always qualify names. It should +generally not be necessary to specify this. + diff --git a/mech_eap/README.samba4 b/mech_eap/README.samba4 new file mode 100644 index 0000000..cf58667 --- /dev/null +++ b/mech_eap/README.samba4 @@ -0,0 +1,52 @@ +Notes on using Moonshot with Samba4. Replace paths as appropriate. + +Samba +----- + +* Download Samba4 and apply patches for mechanism agnosticism which are + available at http://www.padl.com/~lukeh/samba/ +* Join Samba as a member server or domain controller (only tested former) +* Extract local service principal key to keytab (currently there do not + appear to be tools to do this, but you can get the cleartext password + from /usr/local/samba/private/secrets.ldb) + +Shibboleth +---------- + +* Add a mapping from the PAC RADIUS attribute to urn:mspac: in the file + /usr/local/etc/shibboleth/attribute-map.xml: + + + +FreeRADIUS +---------- + +Install the rlm_mspac module and configure per below. + +* Install dictionary.ukerna so MS-Windows-Auth-Data is defined +* Create /usr/local/etc/raddb/modules/mspac with the following: + + mspac { + keytab = /etc/krb5.keytab + spn = host/host.fqdn@KERBEROS.REALM + } + +* Add mspac to instantiate stanza in radiusd.conf +* Add mspac to post-auth stanza in sites-enabled/inner-tunnel + +You will need to have a TGT for the host service principal before starting +radiusd. It's easiest to do this with kinit -k. + +Testing +------- + +The Samba server doesn't require any specific command line arguments, although +on OS X it was necessary to start it with -M single to function under gdb. + +For the client, the GSS EAP mechanism can be specified on the command line: + +smbclient --password samba --mechanism 1.3.6.1.5.5.15.1.1.18 '\\host\share'". + +There is no Moonshot SSPI implementation as yet, so it is not possible to test +with a Windows client. diff --git a/mech_eap/TODO b/mech_eap/TODO new file mode 100644 index 0000000..78d92c8 --- /dev/null +++ b/mech_eap/TODO @@ -0,0 +1,7 @@ +- draft-ietf-radext-radius-extensions +- integration with initiator-side EAP channel bindings +- investigate initiator-side credential locking +- always intern OIDs so they never need to be freed +- handle many-to-many Shibboleth attribute mappings; need to encode both attribute and value index into more +- add --with-xerces option +- proper acquire_cred_ext implementation pending specification diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c new file mode 100644 index 0000000..2b97665 --- /dev/null +++ b/mech_eap/accept_sec_context.c @@ -0,0 +1,1135 @@ +/* + * Copyright (c) 2011, 2013, 2015, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Establish a security context on the acceptor (server). These functions + * wrap around libradsec and (thus) talk to a RADIUS server or proxy. + */ + +#include "gssapiP_eap.h" + +#ifdef GSSEAP_ENABLE_REAUTH +static OM_uint32 +eapGssSmAcceptGssReauth(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech, + OM_uint32 reqFlags, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags); +#endif + +/* + * Mark an acceptor context as ready for cryptographic operations + */ +static OM_uint32 +acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred) +{ + OM_uint32 major, tmpMinor; + rs_const_avp *vp; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + + /* Cache encryption type derived from selected mechanism OID */ + major = gssEapOidToEnctype(minor, ctx->mechanismUsed, + &ctx->encryptionType); + if (GSS_ERROR(major)) + return major; + + gssEapReleaseName(&tmpMinor, &ctx->initiatorName); + + major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps, + PW_USER_NAME, 0, &vp); + if (major == GSS_S_COMPLETE && rs_avp_length(vp) != 0) { + rs_avp_octets_value_byref((rs_avp *)vp, + (unsigned char **)&nameBuf.value, + &nameBuf.length); + } else { + ctx->gssFlags |= GSS_C_ANON_FLAG; + } + + major = gssEapImportName(minor, &nameBuf, + (ctx->gssFlags & GSS_C_ANON_FLAG) ? + GSS_C_NT_ANONYMOUS : GSS_C_NT_USER_NAME, + ctx->mechanismUsed, + &ctx->initiatorName); + if (GSS_ERROR(major)) + return major; + + major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps, + PW_MS_MPPE_SEND_KEY, VENDORPEC_MICROSOFT, &vp); + if (GSS_ERROR(major)) { + *minor = GSSEAP_KEY_UNAVAILABLE; + return GSS_S_UNAVAILABLE; + } + + major = gssEapDeriveRfc3961Key(minor, + rs_avp_octets_value_const_ptr(vp), + rs_avp_length(vp), + ctx->encryptionType, + &ctx->rfc3961Key); + if (GSS_ERROR(major)) + return major; + + major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key, + &ctx->checksumType); + if (GSS_ERROR(major)) + return major; + + major = sequenceInit(minor, + &ctx->seqState, ctx->recvSeq, + ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), + ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), + TRUE); + if (GSS_ERROR(major)) + return major; + + major = gssEapCreateAttrContext(minor, cred, ctx, + &ctx->initiatorName->attrCtx, + &ctx->expiryTime); + if (GSS_ERROR(major)) + return major; + + if (ctx->expiryTime != 0 && ctx->expiryTime < time(NULL)) { + *minor = GSSEAP_CRED_EXPIRED; + return GSS_S_CREDENTIALS_EXPIRED; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +eapGssSmAcceptAcceptorName(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + /* XXX TODO import and validate name from inputToken */ + + if (ctx->acceptorName != GSS_C_NO_NAME) { + /* Send desired target name to acceptor */ + major = gssEapDisplayName(minor, ctx->acceptorName, + outputToken, NULL); + if (GSS_ERROR(major)) + return major; + } + + return GSS_S_CONTINUE_NEEDED; +} + +#ifdef GSSEAP_DEBUG +static OM_uint32 +eapGssSmAcceptVendorInfo(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx GSSEAP_UNUSED, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + fprintf(stderr, "GSS-EAP: vendor: %.*s\n", + (int)inputToken->length, (char *)inputToken->value); + + *minor = 0; + return GSS_S_CONTINUE_NEEDED; +} +#endif + + +/* + * Emit a identity EAP request to force the initiator (peer) to identify + * itself. + */ +static OM_uint32 +eapGssSmAcceptIdentity(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + struct wpabuf *reqData; + gss_buffer_desc pktBuffer; + + if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) { + *minor = GSSEAP_CRED_MECH_MISMATCH; + return GSS_S_BAD_MECH; + } + + if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + reqData = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 0, + EAP_CODE_REQUEST, 0); + if (reqData == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + pktBuffer.length = wpabuf_len(reqData); + pktBuffer.value = (void *)wpabuf_head(reqData); + + major = duplicateBuffer(minor, &pktBuffer, outputToken); + if (GSS_ERROR(major)) + return major; + + wpabuf_free(reqData); + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + return GSS_S_CONTINUE_NEEDED; +} + +/* + * Returns TRUE if the input token contains an EAP identity response. + */ +static int +isIdentityResponseP(gss_buffer_t inputToken) +{ + struct wpabuf respData; + + wpabuf_set(&respData, inputToken->value, inputToken->length); + + return (eap_get_type(&respData) == EAP_TYPE_IDENTITY); +} + +/* + * Save the asserted initiator identity from the EAP identity response. + */ +static OM_uint32 +importInitiatorIdentity(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t inputToken) +{ + OM_uint32 tmpMinor; + struct wpabuf respData; + const unsigned char *pos; + size_t len; + gss_buffer_desc nameBuf; + + wpabuf_set(&respData, inputToken->value, inputToken->length); + + pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, + &respData, &len); + if (pos == NULL) { + *minor = GSSEAP_PEER_BAD_MESSAGE; + return GSS_S_DEFECTIVE_TOKEN; + } + + nameBuf.value = (void *)pos; + nameBuf.length = len; + + gssEapReleaseName(&tmpMinor, &ctx->initiatorName); + + return gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME, + ctx->mechanismUsed, &ctx->initiatorName); +} + +/* + * Pass the asserted initiator identity to the authentication server. + */ +static OM_uint32 +setInitiatorIdentity(OM_uint32 *minor, + gss_ctx_id_t ctx, + struct rs_packet *req) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc nameBuf; + + /* + * We should have got an EAP identity response, but if we didn't, then + * we will just avoid sending User-Name. Note that radsecproxy requires + * User-Name to be sent on every request (presumably so it can remain + * stateless). + */ + if (ctx->initiatorName != GSS_C_NO_NAME) { + major = gssEapDisplayName(minor, ctx->initiatorName, &nameBuf, NULL); + if (GSS_ERROR(major)) + return major; + + major = gssEapRadiusAddAvp(minor, req, PW_USER_NAME, 0, &nameBuf); + if (GSS_ERROR(major)) + return major; + + gss_release_buffer(&tmpMinor, &nameBuf); + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +/* + * Pass the asserted acceptor identity to the authentication server. + */ +static OM_uint32 +setAcceptorIdentity(OM_uint32 *minor, + gss_ctx_id_t ctx, + struct rs_packet *req) +{ + OM_uint32 major; + gss_buffer_desc nameBuf; + krb5_context krbContext = NULL; + krb5_principal krbPrinc; + struct rs_context *rc = ctx->acceptorCtx.radContext; + + GSSEAP_ASSERT(rc != NULL); + + if (ctx->acceptorName == GSS_C_NO_NAME) { + *minor = 0; + return GSS_S_COMPLETE; + } + + if ((ctx->acceptorName->flags & NAME_FLAG_SERVICE) == 0) { + *minor = GSSEAP_BAD_SERVICE_NAME; + return GSS_S_BAD_NAME; + } + + GSSEAP_KRB_INIT(&krbContext); + + krbPrinc = ctx->acceptorName->krbPrincipal; + GSSEAP_ASSERT(krbPrinc != NULL); + GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 1); + + /* Acceptor-Service-Name */ + krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf); + + major = gssEapRadiusAddAvp(minor, req, + PW_GSS_ACCEPTOR_SERVICE_NAME, + 0, + &nameBuf); + if (GSS_ERROR(major)) + return major; + + /* Acceptor-Host-Name */ + if (KRB_PRINC_LENGTH(krbPrinc) >= 2) { + krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf); + + major = gssEapRadiusAddAvp(minor, req, + PW_GSS_ACCEPTOR_HOST_NAME, + 0, + &nameBuf); + if (GSS_ERROR(major)) + return major; + } + if (KRB_PRINC_LENGTH(krbPrinc) > 2) { + /* Acceptor-Service-Specific */ + *minor = krbPrincUnparseServiceSpecifics(krbContext, + krbPrinc, &nameBuf); + if (*minor != 0) + return GSS_S_FAILURE; + + major = gssEapRadiusAddAvp(minor, req, + PW_GSS_ACCEPTOR_SERVICE_SPECIFICS, + 0, + &nameBuf); + krbFreeUnparsedName(krbContext, &nameBuf); + if (GSS_ERROR(major)) + return major; + } + + krbPrincRealmToGssBuffer(krbPrinc, &nameBuf); + if (nameBuf.length != 0) { + /* Acceptor-Realm-Name */ + major = gssEapRadiusAddAvp(minor, req, + PW_GSS_ACCEPTOR_REALM_NAME, + 0, + &nameBuf); + if (GSS_ERROR(major)) + return major; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +/* + * Allocate a RadSec handle + */ +static OM_uint32 +createRadiusHandle(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx) +{ + struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx; + struct rs_error *err; + const char *configStanza = "gss-eap"; + OM_uint32 major; + + GSSEAP_ASSERT(actx->radContext == NULL); + GSSEAP_ASSERT(actx->radConn == NULL); + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + major = gssEapCreateRadiusContext(minor, cred, &actx->radContext); + if (GSS_ERROR(major)) + return major; + + if (cred->radiusConfigStanza.value != NULL) + configStanza = (const char *)cred->radiusConfigStanza.value; + + if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) { + err = rs_err_conn_pop(actx->radConn); + return gssEapRadiusMapError(minor, err); + } + + if (actx->radServer != NULL) { + if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) { + err = rs_err_conn_pop(actx->radConn); + return gssEapRadiusMapError(minor, err); + } + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +/** + * Choose the correct error for an access reject packet. + */ +static OM_uint32 +eapGssAcceptHandleReject( + OM_uint32 *minor, + struct rs_packet *response) +{ + rs_avp **vps; + rs_const_avp *vp = NULL; + OM_uint32 major; + const char * reply_message = NULL; + size_t reply_length = 0; + + rs_packet_avps(response, &vps); + major = gssEapRadiusGetRawAvp(minor, *vps, + PW_REPLY_MESSAGE, 0, &vp); + if (!GSS_ERROR(major)) { + reply_message = rs_avp_string_value(vp); + reply_length = rs_avp_length(vp); + } + + major = gssEapRadiusGetRawAvp(minor, *vps, + PW_ERROR_CAUSE, 0, &vp); + if (!GSS_ERROR(major)) { + switch (rs_avp_integer_value(vp)) { + /* Values from http://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-18 */ + case 502: /*request not routable (proxy)*/ + *minor = GSSEAP_RADIUS_UNROUTABLE; + break; + case 501: /*administratively prohibited*/ + *minor = GSSEAP_RADIUS_ADMIN_PROHIBIT; + break; + + default: + *minor = GSSEAP_RADIUS_AUTH_FAILURE; + break; + } + } else *minor = GSSEAP_RADIUS_AUTH_FAILURE; + + if (reply_message) + gssEapSaveStatusInfo(*minor, "%s: %.*s", error_message(*minor), + reply_length, reply_message); + else gssEapSaveStatusInfo( *minor, "%s", error_message(*minor)); + return GSS_S_DEFECTIVE_CREDENTIAL; +} +/* + * Process a EAP response from the initiator. + */ +static OM_uint32 +eapGssSmAcceptAuthenticate(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major, tmpMinor; + struct rs_connection *rconn; + struct rs_request *request = NULL; + struct rs_packet *req = NULL, *resp = NULL; + int isAccessChallenge; + + if (ctx->acceptorCtx.radContext == NULL) { + /* May be NULL from an imported partial context */ + major = createRadiusHandle(minor, cred, ctx); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (isIdentityResponseP(inputToken)) { + major = importInitiatorIdentity(minor, ctx, inputToken); + if (GSS_ERROR(major)) + return major; + } + + rconn = ctx->acceptorCtx.radConn; + + if (rs_packet_create_authn_request(rconn, &req, NULL, NULL) != 0) { + major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn)); + goto cleanup; + } + + major = setInitiatorIdentity(minor, ctx, req); + if (GSS_ERROR(major)) + goto cleanup; + + major = setAcceptorIdentity(minor, ctx, req); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapRadiusAddAvp(minor, req, + PW_EAP_MESSAGE, 0, inputToken); + if (GSS_ERROR(major)) + goto cleanup; + + if (ctx->acceptorCtx.state.length != 0) { + major = gssEapRadiusAddAvp(minor, req, PW_STATE, 0, + &ctx->acceptorCtx.state); + if (GSS_ERROR(major)) + goto cleanup; + + gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state); + } + + if (rs_request_create(rconn, &request) != 0) { + major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn)); + goto cleanup; + } + + rs_request_add_reqpkt(request, req); + req = NULL; + + if (rs_request_send(request, &resp) != 0) { + major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn)); + goto cleanup; + } + + GSSEAP_ASSERT(resp != NULL); + + isAccessChallenge = 0; + + switch (rs_packet_code(resp)) { + case PW_ACCESS_CHALLENGE: + isAccessChallenge = 1; + break; + case PW_ACCESS_ACCEPT: + break; + case PW_ACCESS_REJECT: + major = eapGssAcceptHandleReject( minor, resp); + goto cleanup; + break; + default: + *minor = GSSEAP_UNKNOWN_RADIUS_CODE; + major = GSS_S_FAILURE; + goto cleanup; + break; + } + + major = gssEapRadiusGetAvp(minor, resp, PW_EAP_MESSAGE, 0, + outputToken, TRUE); + if (major == GSS_S_UNAVAILABLE && isAccessChallenge) { + *minor = GSSEAP_MISSING_EAP_REQUEST; + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + } else if (GSS_ERROR(major)) + goto cleanup; + + if (isAccessChallenge) { + major = gssEapRadiusGetAvp(minor, resp, PW_STATE, 0, + &ctx->acceptorCtx.state, TRUE); + if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR) + goto cleanup; + } else { + rs_avp **vps; + + rs_packet_avps(resp, &vps); + + ctx->acceptorCtx.vps = *vps; + *vps = NULL; + + major = acceptReadyEap(minor, ctx, cred); + if (GSS_ERROR(major)) + goto cleanup; + + GSSEAP_SM_TRANSITION_NEXT(ctx); + } + + major = GSS_S_CONTINUE_NEEDED; + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + +cleanup: + if (request != NULL) + rs_request_destroy(request); + if (req != NULL) + rs_packet_destroy(req); + if (resp != NULL) + rs_packet_destroy(resp); + if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIATOR_EXTS) { + GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED); + + rs_conn_destroy(ctx->acceptorCtx.radConn); + ctx->acceptorCtx.radConn = NULL; + } + + return major; +} + +static OM_uint32 +eapGssSmAcceptGssFlags(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + unsigned char *p; + OM_uint32 initiatorGssFlags; + + GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0); + + if (inputToken->length < 4) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* allow flags to grow for future expansion */ + p = (unsigned char *)inputToken->value + inputToken->length - 4; + + initiatorGssFlags = load_uint32_be(p); + initiatorGssFlags &= GSSEAP_WIRE_FLAGS_MASK; + + ctx->gssFlags |= initiatorGssFlags; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmAcceptGssChannelBindings(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + krb5_error_code code; + krb5_context krbContext; + krb5_data data; + krb5_checksum cksum; + krb5_boolean valid = FALSE; + + if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS || + chanBindings->application_data.length == 0) + return GSS_S_CONTINUE_NEEDED; + + GSSEAP_KRB_INIT(&krbContext); + + KRB_DATA_INIT(&data); + + gssBufferToKrbData(&chanBindings->application_data, &data); + + KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken); + + code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key, + KEY_USAGE_GSSEAP_CHBIND_MIC, + &data, &cksum, &valid); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + + if (valid == FALSE) { + *minor = GSSEAP_BINDINGS_MISMATCH; + return GSS_S_BAD_BINDINGS; + } + + ctx->flags |= CTX_FLAG_CHANNEL_BINDINGS_VERIFIED; + + *minor = 0; + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmAcceptInitiatorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + /* + * The channel binding token is optional, however if the caller indicated + * bindings we must raise an error if it was absent. + * + * In the future, we might use a context option to allow the caller to + * indicate that missing bindings are acceptable. + */ + if (chanBindings != NULL && + chanBindings->application_data.length != 0 && + (ctx->flags & CTX_FLAG_CHANNEL_BINDINGS_VERIFIED) == 0) { + *minor = GSSEAP_MISSING_BINDINGS; + return GSS_S_BAD_BINDINGS; + } + + major = gssEapVerifyTokenMIC(minor, ctx, inputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + return GSS_S_CONTINUE_NEEDED; +} + +#ifdef GSSEAP_ENABLE_REAUTH +static OM_uint32 +eapGssSmAcceptReauthCreds(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + /* + * If we're built with fast reauthentication enabled, then + * fabricate a ticket from the initiator to ourselves. + */ + major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken); + if (major == GSS_S_UNAVAILABLE) + major = GSS_S_COMPLETE; + if (major == GSS_S_COMPLETE) + major = GSS_S_CONTINUE_NEEDED; + + return major; +} +#endif + +static OM_uint32 +eapGssSmAcceptAcceptorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + + major = gssEapMakeTokenMIC(minor, ctx, outputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + return GSS_S_COMPLETE; +} + +static struct gss_eap_sm eapGssAcceptorSm[] = { + { + ITOK_TYPE_ACCEPTOR_NAME_REQ, + ITOK_TYPE_ACCEPTOR_NAME_RESP, + GSSEAP_STATE_INITIAL, + 0, + eapGssSmAcceptAcceptorName + }, +#ifdef GSSEAP_DEBUG + { + ITOK_TYPE_VENDOR_INFO, + ITOK_TYPE_NONE, + GSSEAP_STATE_INITIAL, + 0, + eapGssSmAcceptVendorInfo, + }, +#endif +#ifdef GSSEAP_ENABLE_REAUTH + { + ITOK_TYPE_REAUTH_REQ, + ITOK_TYPE_REAUTH_RESP, + GSSEAP_STATE_INITIAL, + 0, + eapGssSmAcceptGssReauth, + }, +#endif + { + ITOK_TYPE_NONE, + ITOK_TYPE_EAP_REQ, + GSSEAP_STATE_INITIAL, + SM_ITOK_FLAG_REQUIRED, + eapGssSmAcceptIdentity, + }, + { + ITOK_TYPE_EAP_RESP, + ITOK_TYPE_EAP_REQ, + GSSEAP_STATE_AUTHENTICATE, + SM_ITOK_FLAG_REQUIRED, + eapGssSmAcceptAuthenticate + }, + { + ITOK_TYPE_GSS_FLAGS, + ITOK_TYPE_NONE, + GSSEAP_STATE_INITIATOR_EXTS, + 0, + eapGssSmAcceptGssFlags + }, + { + ITOK_TYPE_GSS_CHANNEL_BINDINGS, + ITOK_TYPE_NONE, + GSSEAP_STATE_INITIATOR_EXTS, + 0, + eapGssSmAcceptGssChannelBindings, + }, + { + ITOK_TYPE_INITIATOR_MIC, + ITOK_TYPE_NONE, + GSSEAP_STATE_INITIATOR_EXTS, + SM_ITOK_FLAG_REQUIRED, + eapGssSmAcceptInitiatorMIC, + }, +#ifdef GSSEAP_ENABLE_REAUTH + { + ITOK_TYPE_NONE, + ITOK_TYPE_REAUTH_CREDS, + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmAcceptReauthCreds, + }, +#endif + { + ITOK_TYPE_NONE, + ITOK_TYPE_ACCEPTOR_NAME_RESP, + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmAcceptAcceptorName + }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_ACCEPTOR_MIC, + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmAcceptAcceptorMIC + }, +}; + +OM_uint32 +gssEapAcceptSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 major, tmpMinor; + + if (cred == GSS_C_NO_CREDENTIAL) { + if (ctx->cred == GSS_C_NO_CREDENTIAL) { + major = gssEapAcquireCred(minor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_ACCEPT, + &ctx->cred, + NULL, + NULL); + if (GSS_ERROR(major)) + goto cleanup; + } + + cred = ctx->cred; + } + + /* + * Previously we acquired the credential mutex here, but it should not be + * necessary as the acceptor does not access any mutable elements of the + * credential handle. + */ + + if (cred->name != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName); + if (GSS_ERROR(major)) + goto cleanup; + } + + major = gssEapSmStep(minor, + cred, + ctx, + GSS_C_NO_NAME, + GSS_C_NO_OID, + 0, + GSS_C_INDEFINITE, + input_chan_bindings, + input_token, + output_token, + eapGssAcceptorSm, + sizeof(eapGssAcceptorSm) / sizeof(eapGssAcceptorSm[0])); + if (GSS_ERROR(major)) + goto cleanup; + + if (mech_type != NULL) { + OM_uint32 tmpMajor; + + tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, mech_type); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + goto cleanup; + } + } + if (ret_flags != NULL) + *ret_flags = ctx->gssFlags; + if (delegated_cred_handle != NULL) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + + if (major == GSS_S_COMPLETE) { + if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) { + major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name); + if (GSS_ERROR(major)) + goto cleanup; + } + if (time_rec != NULL) { + major = gssEapContextTime(&tmpMinor, ctx, time_rec); + if (GSS_ERROR(major)) + goto cleanup; + } + } + + GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED); + +cleanup: + return major; +} + +#ifdef GSSEAP_ENABLE_REAUTH +static OM_uint32 +acceptReadyKrb(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + const gss_name_t initiator, + const gss_OID mech, + OM_uint32 timeRec) +{ + OM_uint32 major; + + major = gssEapGlueToMechName(minor, ctx, initiator, &ctx->initiatorName); + if (GSS_ERROR(major)) + return major; + + major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec); + if (GSS_ERROR(major)) + return major; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +eapGssSmAcceptGssReauth(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major, tmpMinor; + gss_name_t krbInitiator = GSS_C_NO_NAME; + OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE; + + /* + * If we're built with fast reauthentication support, it's valid + * for an initiator to send a GSS reauthentication token as its + * initial context token, causing us to short-circuit the state + * machine and process Kerberos GSS messages instead. + */ + + ctx->flags |= CTX_FLAG_KRB_REAUTH; + + major = gssAcceptSecContext(minor, + &ctx->reauthCtx, + cred->reauthCred, + inputToken, + chanBindings, + &krbInitiator, + &mech, + outputToken, + &gssFlags, + &timeRec, + NULL); + if (major == GSS_S_COMPLETE) { + major = acceptReadyKrb(minor, ctx, cred, + krbInitiator, mech, timeRec); + if (major == GSS_S_COMPLETE) { + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); + } + ctx->gssFlags = gssFlags; + } else if (GSS_ERROR(major) && + (*smFlags & SM_FLAG_INPUT_TOKEN_CRITICAL) == 0) { + /* pretend reauthentication attempt never happened */ + gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER); + ctx->flags &= ~(CTX_FLAG_KRB_REAUTH); + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL); + major = GSS_S_CONTINUE_NEEDED; + } + + gssReleaseName(&tmpMinor, &krbInitiator); + + return major; +} +#endif /* GSSEAP_ENABLE_REAUTH */ + +OM_uint32 GSSAPI_CALLCONV +gss_accept_sec_context(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_cred_id_t cred, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 major, tmpMinor; + gss_ctx_id_t ctx = *context_handle; + + *minor = 0; + + output_token->length = 0; + output_token->value = NULL; + + if (src_name != NULL) + *src_name = GSS_C_NO_NAME; + + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx == GSS_C_NO_CONTEXT) { + major = gssEapAllocContext(minor, &ctx); + if (GSS_ERROR(major)) + return major; + + *context_handle = ctx; + } + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapAcceptSecContext(minor, + ctx, + cred, + input_token, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + if (GSS_ERROR(major)) + gssEapReleaseContext(&tmpMinor, context_handle); + + gssEapTraceStatus("gss_accept_sec_context", major, *minor); + return major; +} diff --git a/mech_eap/acquire_cred.c b/mech_eap/acquire_cred.c new file mode 100644 index 0000000..ae2648e --- /dev/null +++ b/mech_eap/acquire_cred.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Wrapper for acquiring a credential handle. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_acquire_cred(OM_uint32 *minor, + gss_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + return gssEapAcquireCred(minor, desired_name, + time_req, desired_mechs, cred_usage, + output_cred_handle, actual_mechs, time_rec); +} diff --git a/mech_eap/acquire_cred_with_password.c b/mech_eap/acquire_cred_with_password.c new file mode 100644 index 0000000..8e08358 --- /dev/null +++ b/mech_eap/acquire_cred_with_password.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Wrapper for acquiring a credential handle using a password. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gssspi_acquire_cred_with_password(OM_uint32 *minor, + const gss_name_t desired_name, + const gss_buffer_t password, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + OM_uint32 major, tmpMinor; + + major = gssEapAcquireCred(minor, desired_name, + time_req, desired_mechs, cred_usage, + output_cred_handle, actual_mechs, time_rec); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapSetCredPassword(minor, *output_cred_handle, password); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + if (GSS_ERROR(major)) + gssEapReleaseCred(&tmpMinor, output_cred_handle); + + return major; +} diff --git a/mech_eap/add_cred.c b/mech_eap/add_cred.c new file mode 100644 index 0000000..64d97c0 --- /dev/null +++ b/mech_eap/add_cred.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Wrapper for acquiring a credential handle. + */ + +#include "gssapiP_eap.h" + +/* + * Note that this shouldn't really be required to be implemented by anything + * apart from the mechanism glue layer. However, Heimdal does call into the + * mechanism here. + */ +OM_uint32 GSSAPI_CALLCONV +gss_add_cred(OM_uint32 *minor, + gss_cred_id_t input_cred_handle GSSEAP_UNUSED, + gss_name_t desired_name, + gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major; + OM_uint32 time_req, time_rec = 0; + gss_OID_set_desc mechs; + + *minor = 0; + *output_cred_handle = GSS_C_NO_CREDENTIAL; + + if (cred_usage == GSS_C_ACCEPT) + time_req = acceptor_time_req; + else + time_req = initiator_time_req; + + mechs.count = 1; + mechs.elements = desired_mech; + + major = gssEapAcquireCred(minor, + desired_name, + time_req, + &mechs, + cred_usage, + output_cred_handle, + actual_mechs, + &time_rec); + + if (initiator_time_rec != NULL) + *initiator_time_rec = time_rec; + if (acceptor_time_rec != NULL) + *acceptor_time_rec = time_rec; + + return major; +} diff --git a/mech_eap/add_cred_with_password.c b/mech_eap/add_cred_with_password.c new file mode 100644 index 0000000..b982f0d --- /dev/null +++ b/mech_eap/add_cred_with_password.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Wrapper for acquiring a credential handle using a password. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_add_cred_with_password(OM_uint32 *minor, + const gss_cred_id_t input_cred_handle GSSEAP_UNUSED, + const gss_name_t desired_name, + const gss_OID desired_mech, + const gss_buffer_t password, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major, tmpMinor; + OM_uint32 time_req, time_rec = 0; + gss_OID_set_desc mechs; + + *minor = 0; + *output_cred_handle = GSS_C_NO_CREDENTIAL; + + if (cred_usage == GSS_C_ACCEPT) + time_req = acceptor_time_req; + else + time_req = initiator_time_req; + + mechs.count = 1; + mechs.elements = desired_mech; + + major = gssEapAcquireCred(minor, + desired_name, + time_req, + &mechs, + cred_usage, + output_cred_handle, + actual_mechs, + &time_rec); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapSetCredPassword(minor, *output_cred_handle, password); + if (GSS_ERROR(major)) + goto cleanup; + + if (initiator_time_rec != NULL) + *initiator_time_rec = time_rec; + if (acceptor_time_rec != NULL) + *acceptor_time_rec = time_rec; + +cleanup: + if (GSS_ERROR(major)) + gssEapReleaseCred(&tmpMinor, output_cred_handle); + + return major; +} diff --git a/mech_eap/authdata_plugin.h b/mech_eap/authdata_plugin.h new file mode 100644 index 0000000..32bff2f --- /dev/null +++ b/mech_eap/authdata_plugin.h @@ -0,0 +1,331 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * krb5/authdata_plugin.h + * + * Copyright (C) 2007 Apple Inc. All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * AuthorizationData plugin definitions for Kerberos 5. + */ + +/* + * This is considered an INTERNAL interface at this time. + * + * Some work is needed before exporting it: + * + * + Documentation. + * + Sample code. + * + Test cases (preferably automated testing under "make check"). + * + Hook into TGS exchange too; will change API. + * + Examine memory management issues, especially for Windows; may + * change API. + * + * Other changes that would be nice to have, but not necessarily + * before making this interface public: + * + * + Library support for AD-IF-RELEVANT and similar wrappers. (We can + * make the plugin construct them if it wants them.) + * + KDC could combine/optimize wrapped AD elements provided by + * multiple plugins, e.g., two IF-RELEVANT sequences could be + * merged. (The preauth plugin API also has this bug, we're going + * to need a general fix.) + */ + +#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED +#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED +#include + +/* + * While arguments of these types are passed-in, for the most part a + * authorization data module can treat them as opaque. If we need + * keying data, we can ask for it directly. + */ +struct _krb5_db_entry_new; + +/* + * The function table / structure which an authdata server module must export as + * "authdata_server_0". NOTE: replace "0" with "1" for the type and + * variable names if this gets picked up by upstream. If the interfaces work + * correctly, future versions of the table will add either more callbacks or + * more arguments to callbacks, and in both cases we'll be able to wrap the v0 + * functions. + */ +/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */ +typedef struct krb5plugin_authdata_server_ftable_v0 { + /* Not-usually-visible name. */ + char *name; + + /* + * Per-plugin initialization/cleanup. The init function is called + * by the KDC when the plugin is loaded, and the fini function is + * called before the plugin is unloaded. Both are optional. + */ + krb5_error_code (*init_proc)(krb5_context, void **); + void (*fini_proc)(krb5_context, void *); + /* + * Actual authorization data handling function. If this field + * holds a null pointer, this mechanism will be skipped, and the + * init/fini functions will not be run. + * + * This function should only modify the field + * enc_tkt_reply->authorization_data. All other values should be + * considered inputs only. And, it should *modify* the field, not + * overwrite it and assume that there are no other authdata + * plugins in use. + * + * Memory management: authorization_data is a malloc-allocated, + * null-terminated sequence of malloc-allocated pointers to + * authorization data structures. This plugin code currently + * assumes the libraries, KDC, and plugin all use the same malloc + * pool, which may be a problem if/when we get the KDC code + * running on Windows. + * + * If this function returns a non-zero error code, a message + * is logged, but no other action is taken. Other authdata + * plugins will be called, and a response will be sent to the + * client (barring other problems). + */ + krb5_error_code (*authdata_proc)(krb5_context, + struct _krb5_db_entry_new *client, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_enc_tkt_part *enc_tkt_reply); +} krb5plugin_server_authdata_ftable_v0; + +typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0; + +typedef struct krb5plugin_authdata_server_ftable_v2 { + /* Not-usually-visible name. */ + char *name; + + /* + * Per-plugin initialization/cleanup. The init function is called + * by the KDC when the plugin is loaded, and the fini function is + * called before the plugin is unloaded. Both are optional. + */ + krb5_error_code (*init_proc)(krb5_context, void **); + void (*fini_proc)(krb5_context, void *); + /* + * Actual authorization data handling function. If this field + * holds a null pointer, this mechanism will be skipped, and the + * init/fini functions will not be run. + * + * This function should only modify the field + * enc_tkt_reply->authorization_data. All other values should be + * considered inputs only. And, it should *modify* the field, not + * overwrite it and assume that there are no other authdata + * plugins in use. + * + * Memory management: authorization_data is a malloc-allocated, + * null-terminated sequence of malloc-allocated pointers to + * authorization data structures. This plugin code currently + * assumes the libraries, KDC, and plugin all use the same malloc + * pool, which may be a problem if/when we get the KDC code + * running on Windows. + * + * If this function returns a non-zero error code, a message + * is logged, but no other action is taken. Other authdata + * plugins will be called, and a response will be sent to the + * client (barring other problems). + */ + krb5_error_code (*authdata_proc)(krb5_context, + unsigned int flags, + struct _krb5_db_entry_new *client, + struct _krb5_db_entry_new *server, + struct _krb5_db_entry_new *tgs, + krb5_keyblock *client_key, + krb5_keyblock *server_key, + krb5_keyblock *tgs_key, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_const_principal for_user_princ, + krb5_enc_tkt_part *enc_tkt_request, + krb5_enc_tkt_part *enc_tkt_reply); +} krb5plugin_authdata_server_ftable_v2; + +typedef krb5plugin_authdata_server_ftable_v2 krb5plugin_authdata_ftable_v2; + +typedef krb5_error_code +(*authdata_client_plugin_init_proc)(krb5_context context, + void **plugin_context); + +#define AD_USAGE_AS_REQ 0x01 +#define AD_USAGE_TGS_REQ 0x02 +#define AD_USAGE_AP_REQ 0x04 +#define AD_USAGE_KDC_ISSUED 0x08 +#define AD_USAGE_MASK 0x0F +#define AD_INFORMATIONAL 0x10 + +struct _krb5_authdata_context; + +typedef void +(*authdata_client_plugin_flags_proc)(krb5_context kcontext, + void *plugin_context, + krb5_authdatatype ad_type, + krb5_flags *flags); + +typedef void +(*authdata_client_plugin_fini_proc)(krb5_context kcontext, + void *plugin_context); + +typedef krb5_error_code +(*authdata_client_request_init_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void **request_context); + +typedef void +(*authdata_client_request_fini_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context); + +typedef krb5_error_code +(*authdata_client_import_authdata_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued_flag, + krb5_const_principal issuer); + +typedef krb5_error_code +(*authdata_client_export_authdata_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_flags usage, + krb5_authdata ***authdata); + +typedef krb5_error_code +(*authdata_client_get_attribute_types_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_data **attrs); + +typedef krb5_error_code +(*authdata_client_get_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more); + +typedef krb5_error_code +(*authdata_client_set_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value); + +typedef krb5_error_code +(*authdata_client_delete_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_data *attribute); + +typedef krb5_error_code +(*authdata_client_export_internal_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_boolean restrict_authenticated, + void **ptr); + +typedef void +(*authdata_client_free_internal_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + void *ptr); + +typedef krb5_error_code +(*authdata_client_verify_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_auth_context *auth_context, + const krb5_keyblock *key, + const krb5_ap_req *req); + +typedef krb5_error_code +(*authdata_client_size_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + size_t *sizep); + +typedef krb5_error_code +(*authdata_client_externalize_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain); + +typedef krb5_error_code +(*authdata_client_internalize_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain); + +typedef krb5_error_code +(*authdata_client_copy_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + void *dst_plugin_context, + void *dst_request_context); + +typedef struct krb5plugin_authdata_client_ftable_v0 { + char *name; + krb5_authdatatype *ad_type_list; + authdata_client_plugin_init_proc init; + authdata_client_plugin_fini_proc fini; + authdata_client_plugin_flags_proc flags; + authdata_client_request_init_proc request_init; + authdata_client_request_fini_proc request_fini; + authdata_client_get_attribute_types_proc get_attribute_types; + authdata_client_get_attribute_proc get_attribute; + authdata_client_set_attribute_proc set_attribute; + authdata_client_delete_attribute_proc delete_attribute; + authdata_client_export_authdata_proc export_authdata; + authdata_client_import_authdata_proc import_authdata; + authdata_client_export_internal_proc export_internal; + authdata_client_free_internal_proc free_internal; + authdata_client_verify_proc verify; + authdata_client_size_proc size; + authdata_client_externalize_proc externalize; + authdata_client_internalize_proc internalize; + authdata_client_copy_proc copy; /* optional */ +} krb5plugin_authdata_client_ftable_v0; + +#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */ diff --git a/mech_eap/authorize_localname.c b/mech_eap/authorize_localname.c new file mode 100644 index 0000000..0037e2b --- /dev/null +++ b/mech_eap/authorize_localname.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Local authorization services. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gssspi_authorize_localname(OM_uint32 *minor, + const gss_name_t name GSSEAP_UNUSED, + gss_const_buffer_t local_user GSSEAP_UNUSED, + gss_const_OID local_nametype GSSEAP_UNUSED) +{ + /* + * The MIT mechglue will fallback to comparing names in the absence + * of a mechanism implementation of gss_userok. To avoid this and + * force the mechglue to use attribute-based authorization, always + * return access denied here. + */ + + *minor = 0; + return GSS_S_UNAUTHORIZED; +} diff --git a/mech_eap/canonicalize_name.c b/mech_eap/canonicalize_name.c new file mode 100644 index 0000000..5e66798 --- /dev/null +++ b/mech_eap/canonicalize_name.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Function for canonicalizing a name; presently just duplicates it. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_canonicalize_name(OM_uint32 *minor, + const gss_name_t input_name, + const gss_OID mech_type, + gss_name_t *output_name) +{ + OM_uint32 major; + + *minor = 0; + + if (!gssEapIsMechanismOid(mech_type)) + return GSS_S_BAD_MECH; + + if (input_name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&input_name->mutex); + + major = gssEapCanonicalizeName(minor, input_name, mech_type, output_name); + + GSSEAP_MUTEX_UNLOCK(&input_name->mutex); + + return major; +} diff --git a/mech_eap/compare_name.c b/mech_eap/compare_name.c new file mode 100644 index 0000000..1da8354 --- /dev/null +++ b/mech_eap/compare_name.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Compare two names. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_compare_name(OM_uint32 *minor, + gss_name_t name1, + gss_name_t name2, + int *name_equal) +{ + return gssEapCompareName(minor, name1, name2, 0, name_equal); +} diff --git a/mech_eap/config.guess b/mech_eap/config.guess new file mode 100755 index 0000000..dc84c68 --- /dev/null +++ b/mech_eap/config.guess @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/mech_eap/config.sub b/mech_eap/config.sub new file mode 100755 index 0000000..2a55a50 --- /dev/null +++ b/mech_eap/config.sub @@ -0,0 +1,1705 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/mech_eap/context_time.c b/mech_eap/context_time.c new file mode 100644 index 0000000..ae47d6c --- /dev/null +++ b/mech_eap/context_time.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Determine remaining lifetime of a context handle. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_context_time(OM_uint32 *minor, + gss_ctx_id_t ctx, + OM_uint32 *time_rec) +{ + OM_uint32 major; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + *minor = GSSEAP_CONTEXT_INCOMPLETE; + major = GSS_S_NO_CONTEXT; + goto cleanup; + } + + major = gssEapContextTime(minor, ctx, time_rec); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/delete_name_attribute.c b/mech_eap/delete_name_attribute.c new file mode 100644 index 0000000..fe0ff8f --- /dev/null +++ b/mech_eap/delete_name_attribute.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Wrapper for removing a name attribute. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_delete_name_attribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr) +{ + OM_uint32 major; + + *minor = 0; + + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&name->mutex); + + major = gssEapDeleteNameAttribute(minor, name, attr); + + GSSEAP_MUTEX_UNLOCK(&name->mutex); + + return major; +} diff --git a/mech_eap/delete_sec_context.c b/mech_eap/delete_sec_context.c new file mode 100644 index 0000000..7913e45 --- /dev/null +++ b/mech_eap/delete_sec_context.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Release a context handle. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_delete_sec_context(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + OM_uint32 major; + gss_ctx_id_t ctx = *context_handle; + + *minor = 0; + + if (output_token != GSS_C_NO_BUFFER) { + output_token->length = 0; + output_token->value = NULL; + } + + if (ctx == GSS_C_NO_CONTEXT) + return GSS_S_COMPLETE; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (output_token != GSS_C_NO_BUFFER) { + gss_iov_buffer_desc iov[2]; + + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[0].buffer.value = NULL; + iov[0].buffer.length = 0; + + iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + iov[1].buffer.value = NULL; + iov[1].buffer.length = 0; + + major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, + iov, 2, TOK_TYPE_DELETE_CONTEXT); + if (GSS_ERROR(major)) { + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + return major; + } + } + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return gssEapReleaseContext(minor, context_handle); +} diff --git a/mech_eap/dictionary.ukerna b/mech_eap/dictionary.ukerna new file mode 100644 index 0000000..335796f --- /dev/null +++ b/mech_eap/dictionary.ukerna @@ -0,0 +1,26 @@ +# -*- text -*- +# +# GSS-EAP VSAs +# +# $Id$ +# + +VENDOR UKERNA 25622 + +BEGIN-VENDOR UKERNA + +ATTRIBUTE GSS-Acceptor-Service-Name-VS 128 string +ATTRIBUTE GSS-Acceptor-Host-Name-VS 129 string +ATTRIBUTE GSS-Acceptor-Service-Specific-VS 130 string +ATTRIBUTE GSS-Acceptor-Realm-Name-VS 131 string +ATTRIBUTE SAML-AAA-Assertion 132 string +ATTRIBUTE MS-Windows-Auth-Data 133 octets +ATTRIBUTE MS-Windows-Group-Sid 134 string +ATTRIBUTE EAP-Channel-Binding-Message 135 octets +ATTRIBUTE Trust-Router-COI 136 string +ATTRIBUTE Trust-Router-APC 137 string +attribute Moonshot-Host-TargetedId 138 string +attribute Moonshot-Realm-TargetedId 139 string +attribute Moonshot-TR-COI-TargetedId 140 string + +END-VENDOR UKERNA diff --git a/mech_eap/display_name.c b/mech_eap/display_name.c new file mode 100644 index 0000000..2d87e66 --- /dev/null +++ b/mech_eap/display_name.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Wrapper for "displaying" (returning string representation of) a name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_display_name(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) +{ + /* Lock not required as long as attributes are not used */ + return gssEapDisplayName(minor, name, output_name_buffer, + output_name_type); +} diff --git a/mech_eap/display_name_ext.c b/mech_eap/display_name_ext.c new file mode 100644 index 0000000..d6791d4 --- /dev/null +++ b/mech_eap/display_name_ext.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Parameterized version of gss_display_name(), currently unimplemented. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_display_name_ext(OM_uint32 *minor, + gss_name_t name GSSEAP_UNUSED, + gss_OID display_as_name_type GSSEAP_UNUSED, + gss_buffer_t display_name) +{ + *minor = 0; + + display_name->length = 0; + display_name->value = NULL; + + return GSS_S_UNAVAILABLE; +} diff --git a/mech_eap/display_status.c b/mech_eap/display_status.c new file mode 100644 index 0000000..fc0d1ab --- /dev/null +++ b/mech_eap/display_status.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Function for converting mechanism error codes to strings. + */ + +#include "gssapiP_eap.h" + +struct gss_eap_status_info { + OM_uint32 code; + char *message; + struct gss_eap_status_info *next; +}; + +void +gssEapDestroyStatusInfo(struct gss_eap_status_info *p) +{ + struct gss_eap_status_info *next; + + for (; p != NULL; p = next) { + next = p->next; + GSSEAP_FREE(p->message); + GSSEAP_FREE(p); + } +} + +/* + * Associate a message with a mechanism (minor) status code. This function + * takes ownership of the message regardless of success. The message must + * be explicitly cleared, if required, so it is suggested that a specific + * minor code is either always or never associated with a message, to avoid + * dangling (and potentially confusing) error messages. + */ +static void +saveStatusInfoNoCopy(OM_uint32 minor, char *message) +{ + struct gss_eap_status_info **next = NULL, *p = NULL; + struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData(); + + if (tld != NULL) { + for (p = tld->statusInfo; p != NULL; p = p->next) { + if (p->code == minor) { + /* Set message in-place */ + if (p->message != NULL) + GSSEAP_FREE(p->message); + p->message = message; + return; + } + next = &p->next; + } + p = GSSEAP_CALLOC(1, sizeof(*p)); + } + + if (p == NULL) { + if (message != NULL) + GSSEAP_FREE(message); + return; + } + + p->code = minor; + p->message = message; + + if (next != NULL) + *next = p; + else + tld->statusInfo = p; +} + +static const char * +getStatusInfo(OM_uint32 minor) +{ + struct gss_eap_status_info *p; + struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData(); + + if (tld != NULL) { + for (p = tld->statusInfo; p != NULL; p = p->next) { + if (p->code == minor) + return p->message; + } + } + return NULL; +} + +void +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...) +{ +#ifdef WIN32 + OM_uint32 tmpMajor, tmpMinor; + char buf[BUFSIZ]; + gss_buffer_desc s = GSS_C_EMPTY_BUFFER; + va_list ap; + + if (format != NULL) { + va_start(ap, format); + snprintf(buf, sizeof(buf), format, ap); + va_end(ap); + } + + tmpMajor = makeStringBuffer(&tmpMinor, buf, &s); + if (!GSS_ERROR(tmpMajor)) + saveStatusInfoNoCopy(minor, (char *)s.value); +#else + char *s = NULL; + int n; + va_list ap; + + if (format != NULL) { + va_start(ap, format); + n = vasprintf(&s, format, ap); + if (n == -1) + s = NULL; + va_end(ap); + } + + saveStatusInfoNoCopy(minor, s); +#endif /* WIN32 */ +} + +OM_uint32 +gssEapDisplayStatus(OM_uint32 *minor, + OM_uint32 status_value, + gss_buffer_t status_string) +{ + OM_uint32 major; + krb5_context krbContext = NULL; + const char *errMsg; + + status_string->length = 0; + status_string->value = NULL; + + errMsg = getStatusInfo(status_value); + if (errMsg == NULL) { + GSSEAP_KRB_INIT(&krbContext); + + /* Try the com_err message */ + errMsg = krb5_get_error_message(krbContext, status_value); + } + + if (errMsg != NULL) { + major = makeStringBuffer(minor, errMsg, status_string); + } else { + major = GSS_S_COMPLETE; + *minor = 0; + } + + if (krbContext != NULL) + krb5_free_error_message(krbContext, errMsg); + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_display_status(OM_uint32 *minor, + OM_uint32 status_value, + int status_type, + gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + if (!gssEapIsMechanismOid(mech_type)) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } + + if (status_type != GSS_C_MECH_CODE || + *message_context != 0) { + /* we rely on the mechglue for GSS_C_GSS_CODE */ + *minor = 0; + return GSS_S_BAD_STATUS; + } + + return gssEapDisplayStatus(minor, status_value, status_string); +} diff --git a/mech_eap/duplicate_name.c b/mech_eap/duplicate_name.c new file mode 100644 index 0000000..303619e --- /dev/null +++ b/mech_eap/duplicate_name.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Duplicate a name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_duplicate_name(OM_uint32 *minor, + const gss_name_t input_name, + gss_name_t *dest_name) +{ + OM_uint32 major; + + *minor = 0; + + if (input_name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&input_name->mutex); + + major = gssEapDuplicateName(minor, input_name, dest_name); + + GSSEAP_MUTEX_UNLOCK(&input_name->mutex); + + return major; +} diff --git a/mech_eap/eap_mech.c b/mech_eap/eap_mech.c new file mode 100644 index 0000000..c88ecf6 --- /dev/null +++ b/mech_eap/eap_mech.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2011, 2015, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Initialisation and finalise functions. + */ + +#include "gssapiP_eap.h" + +extern int wpa_debug_level; + +static OM_uint32 +eapPeerRegisterMethods(OM_uint32 *minor) +{ + OM_uint32 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 */ + + if (ret == 0) + return GSS_S_COMPLETE; + + *minor = GSSEAP_LIBEAP_INIT_FAILURE; + return GSS_S_FAILURE; +} + +static OM_uint32 +gssEapInitLibEap(OM_uint32 *minor) +{ + char *debug_file = NULL; + wpa_debug_level = MSG_ERROR; + if ((debug_file = getenv("GSSEAP_TRACE")) != NULL) { + wpa_debug_open_file(debug_file); + wpa_debug_level = 0; + } + + return eapPeerRegisterMethods(minor); +} + +static OM_uint32 +gssEapInitLibRadsec(OM_uint32 *minor) +{ + if (0) { + *minor = GSSEAP_RADSEC_INIT_FAILURE; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; +} + +void gssEapFinalize(void) GSSEAP_DESTRUCTOR; + +OM_uint32 +gssEapInitiatorInit(OM_uint32 *minor) +{ + OM_uint32 major; + + initialize_eapg_error_table(); + initialize_rse_error_table(); + + major = gssEapInitLibEap(minor); + if (GSS_ERROR(major)) + return major; + + major = gssEapInitLibRadsec(minor); + if (GSS_ERROR(major)) + return major; + +#ifdef GSSEAP_ENABLE_REAUTH + major = gssEapReauthInitialize(minor); + if (GSS_ERROR(major)) + return major; +#endif + + *minor = 0; + return GSS_S_COMPLETE; +} + +void +gssEapFinalize(void) +{ + eap_peer_unregister_methods(); +} + +#ifdef GSSEAP_CONSTRUCTOR +static void gssEapInitiatorInitAssert(void) GSSEAP_CONSTRUCTOR; + +static void +gssEapInitiatorInitAssert(void) +{ + OM_uint32 major, minor; + + major = gssEapInitiatorInit(&minor); + + GSSEAP_ASSERT(!GSS_ERROR(major)); +} +#endif diff --git a/mech_eap/exchange_meta_data.c b/mech_eap/exchange_meta_data.c new file mode 100644 index 0000000..5d56795 --- /dev/null +++ b/mech_eap/exchange_meta_data.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gssEapExchangeMetaData(OM_uint32 *minor, + gss_const_OID mech GSSEAP_UNUSED, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t *ctx GSSEAP_UNUSED, + const gss_name_t name GSSEAP_UNUSED, + OM_uint32 req_flags GSSEAP_UNUSED, + gss_const_buffer_t meta_data GSSEAP_UNUSED) +{ + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_exchange_meta_data(OM_uint32 *minor, + gss_const_OID mech, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data) +{ + gss_ctx_id_t ctx = *context_handle; + OM_uint32 major; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_LOCK(&cred->mutex); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapExchangeMetaData(minor, mech, cred, &ctx, + name, req_flags, meta_data); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + else + *context_handle = ctx; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} diff --git a/mech_eap/export_name.c b/mech_eap/export_name.c new file mode 100644 index 0000000..d91033f --- /dev/null +++ b/mech_eap/export_name.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Serialise a name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_export_name(OM_uint32 *minor, + const gss_name_t input_name, + gss_buffer_t exported_name) +{ + OM_uint32 major; + + *minor = 0; + + if (input_name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&input_name->mutex); + + major = gssEapExportName(minor, input_name, exported_name); + + GSSEAP_MUTEX_UNLOCK(&input_name->mutex); + + return major; +} diff --git a/mech_eap/export_name_composite.c b/mech_eap/export_name_composite.c new file mode 100644 index 0000000..b2a90ae --- /dev/null +++ b/mech_eap/export_name_composite.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Serialise a name and its attributes. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_export_name_composite(OM_uint32 *minor, + gss_name_t input_name, + gss_buffer_t exported_name) +{ + OM_uint32 major; + + *minor = 0; + + if (input_name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&input_name->mutex); + + major = gssEapExportNameInternal(minor, input_name, exported_name, + EXPORT_NAME_FLAG_OID | + EXPORT_NAME_FLAG_COMPOSITE); + + GSSEAP_MUTEX_UNLOCK(&input_name->mutex); + + return major; +} diff --git a/mech_eap/export_sec_context.c b/mech_eap/export_sec_context.c new file mode 100644 index 0000000..3b74366 --- /dev/null +++ b/mech_eap/export_sec_context.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Serialise a security context. On the acceptor, this may be partially + * established. + */ + +#include "gssapiP_eap.h" + +#ifdef GSSEAP_ENABLE_ACCEPTOR +static OM_uint32 +gssEapExportPartialContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t token) +{ + OM_uint32 major, tmpMinor; + size_t length, serverLen = 0; + unsigned char *p; + char serverBuf[MAXHOSTNAMELEN]; + if (ctx->acceptorCtx.radConn != NULL) { + if (rs_conn_get_current_peer(ctx->acceptorCtx.radConn, + serverBuf, sizeof(serverBuf)) != 0) { +#if 0 + return gssEapRadiusMapError(minor, + rs_err_conn_pop(ctx->acceptorCtx.radConn)); +#else + serverBuf[0] = '\0'; /* not implemented yet */ +#endif + } + serverLen = strlen(serverBuf); + } + length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length; + + token->value = GSSEAP_MALLOC(length); + if (token->value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + token->length = length; + + p = (unsigned char *)token->value; + + store_uint32_be(serverLen, p); + p += 4; + if (serverLen != 0) { + memcpy(p, serverBuf, serverLen); + p += serverLen; + } + + store_uint32_be(ctx->acceptorCtx.state.length, p); + p += 4; + if (ctx->acceptorCtx.state.length != 0) { + memcpy(p, ctx->acceptorCtx.state.value, + ctx->acceptorCtx.state.length); + p += ctx->acceptorCtx.state.length; + } + + GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length); + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) + gss_release_buffer(&tmpMinor, token); + + return major; +} +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + +OM_uint32 +gssEapExportSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t token) +{ + OM_uint32 major, tmpMinor; + size_t length; + gss_buffer_desc initiatorName = GSS_C_EMPTY_BUFFER; + gss_buffer_desc acceptorName = GSS_C_EMPTY_BUFFER; + gss_buffer_desc partialCtx = GSS_C_EMPTY_BUFFER; + gss_buffer_desc key; + unsigned char *p; + + if ((CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) || + ctx->mechanismUsed == GSS_C_NO_OID) { + *minor = GSSEAP_CONTEXT_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key); + key.value = KRB_KEY_DATA(&ctx->rfc3961Key); + + /* + * As a shortcut, we omit the mechanism OID of the initiator name because + * we know it will match the context mechanism. The acceptor name mech OID + * is always included. + */ + if (ctx->initiatorName != GSS_C_NO_NAME) { + major = gssEapExportNameInternal(minor, ctx->initiatorName, + &initiatorName, + EXPORT_NAME_FLAG_COMPOSITE); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (ctx->acceptorName != GSS_C_NO_NAME) { + major = gssEapExportNameInternal(minor, ctx->acceptorName, + &acceptorName, + EXPORT_NAME_FLAG_OID | EXPORT_NAME_FLAG_COMPOSITE); + if (GSS_ERROR(major)) + goto cleanup; + } + +#ifdef GSSEAP_ENABLE_ACCEPTOR + /* + * The partial context is only transmitted for unestablished acceptor + * contexts. + */ + if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) && + (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) { + major = gssEapExportPartialContext(minor, ctx, &partialCtx); + if (GSS_ERROR(major)) + goto cleanup; + } +#endif + + length = 16; /* version, state, flags, */ + length += 4 + ctx->mechanismUsed->length; /* mechanismUsed */ + length += 12 + key.length; /* rfc3961Key.value */ + length += 4 + initiatorName.length; /* initiatorName.value */ + length += 4 + acceptorName.length; /* acceptorName.value */ + length += 24 + sequenceSize(ctx->seqState); /* seqState */ + + if (partialCtx.value != NULL) + length += 4 + partialCtx.length; /* partialCtx.value */ + + token->value = GSSEAP_MALLOC(length); + if (token->value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + token->length = length; + + p = (unsigned char *)token->value; + + store_uint32_be(EAP_EXPORT_CONTEXT_V1, &p[0]); /* version */ + store_uint32_be(GSSEAP_SM_STATE(ctx), &p[4]); + store_uint32_be(ctx->flags, &p[8]); + store_uint32_be(ctx->gssFlags, &p[12]); + p = store_oid(ctx->mechanismUsed, &p[16]); + + store_uint32_be(ctx->checksumType, &p[0]); + store_uint32_be(ctx->encryptionType, &p[4]); + p = store_buffer(&key, &p[8], FALSE); + + p = store_buffer(&initiatorName, p, FALSE); + p = store_buffer(&acceptorName, p, FALSE); + + store_uint64_be(ctx->expiryTime, &p[0]); + store_uint64_be(ctx->sendSeq, &p[8]); + store_uint64_be(ctx->recvSeq, &p[16]); + p += 24; + + major = sequenceExternalize(minor, ctx->seqState, &p, &length); + if (GSS_ERROR(major)) + goto cleanup; + + if (partialCtx.value != NULL) + p = store_buffer(&partialCtx, p, FALSE); + + GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length); + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) + gss_release_buffer(&tmpMinor, token); + gss_release_buffer(&tmpMinor, &initiatorName); + gss_release_buffer(&tmpMinor, &acceptorName); + gss_release_buffer(&tmpMinor, &partialCtx); + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_export_sec_context(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token) +{ + OM_uint32 major, tmpMinor; + gss_ctx_id_t ctx = *context_handle; + + interprocess_token->length = 0; + interprocess_token->value = NULL; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapExportSecContext(minor, ctx, interprocess_token); + if (GSS_ERROR(major)) { + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + return major; + } + + *context_handle = GSS_C_NO_CONTEXT; + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + gssEapReleaseContext(&tmpMinor, &ctx); + + return GSS_S_COMPLETE; +} diff --git a/mech_eap/get_mic.c b/mech_eap/get_mic.c new file mode 100644 index 0000000..7161e9c --- /dev/null +++ b/mech_eap/get_mic.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Message protection services: make a message integerity check. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_get_mic(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_qop_t qop_req, + gss_buffer_t message_buffer, + gss_buffer_t message_token) +{ + OM_uint32 major; + gss_iov_buffer_desc iov[2]; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + if (qop_req != GSS_C_QOP_DEFAULT) { + *minor = GSSEAP_UNKNOWN_QOP; + return GSS_S_UNAVAILABLE; + } + + *minor = 0; + + message_token->value = NULL; + message_token->length = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[0].buffer = *message_buffer; + + iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + iov[1].buffer.value = NULL; + iov[1].buffer.length = 0; + + major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC); + if (GSS_ERROR(major)) + goto cleanup; + + *message_token = iov[1].buffer; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/get_name_attribute.c b/mech_eap/get_name_attribute.c new file mode 100644 index 0000000..a885823 --- /dev/null +++ b/mech_eap/get_name_attribute.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +/* + * Wrapper for retrieving a naming attribute. + */ + +OM_uint32 GSSAPI_CALLCONV +gss_get_name_attribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + OM_uint32 major; + + *minor = 0; + + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&name->mutex); + + major = gssEapGetNameAttribute(minor, name, attr, + authenticated, complete, + value, display_value, more); + + GSSEAP_MUTEX_UNLOCK(&name->mutex); + + return major; +} diff --git a/mech_eap/gssapiP_eap.h b/mech_eap/gssapiP_eap.h new file mode 100644 index 0000000..1e8a360 --- /dev/null +++ b/mech_eap/gssapiP_eap.h @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GSSAPIP_EAP_H_ +#define _GSSAPIP_EAP_H_ 1 + +#include "config.h" + +#ifdef HAVE_HEIMDAL_VERSION +#define KRB5_DEPRECATED /* so we can use krb5_free_unparsed_name() */ +#endif + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef WIN32 +#ifndef MAXHOSTNAMELEN +# include +# define MAXHOSTNAMELEN NI_MAXHOST +#endif +#endif + +/* GSS headers */ +#include +#include +#ifdef HAVE_HEIMDAL_VERSION +typedef struct gss_any *gss_any_t; +#else +#include +#endif +#include "gssapi_eap.h" + +#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH +typedef const gss_OID_desc *gss_const_OID; +#endif + +/* Kerberos headers */ +#include + +/* EAP headers */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef GSSEAP_ENABLE_ACCEPTOR +/* libradsec headers */ +#include +#include +#include +#endif + +#include "gsseap_err.h" +#include "radsec_err.h" +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* These name flags are informative and not actually used by anything yet */ +#define NAME_FLAG_NAI 0x00000001 +#define NAME_FLAG_SERVICE 0x00000002 +#define NAME_FLAG_COMPOSITE 0x00000004 + +struct gss_eap_saml_attr_ctx; +struct gss_eap_attr_ctx; + +#ifdef HAVE_HEIMDAL_VERSION +struct gss_name_t_desc_struct +#else +struct gss_name_struct +#endif +{ + GSSEAP_MUTEX mutex; /* mutex protects attrCtx */ + OM_uint32 flags; + gss_OID mechanismUsed; /* this is immutable */ + krb5_principal krbPrincipal; /* this is immutable */ +#ifdef GSSEAP_ENABLE_ACCEPTOR + struct gss_eap_attr_ctx *attrCtx; +#endif +}; + +#define CRED_FLAG_INITIATE 0x00010000 +#define CRED_FLAG_ACCEPT 0x00020000 +#define CRED_FLAG_PASSWORD 0x00040000 +#define CRED_FLAG_DEFAULT_CCACHE 0x00080000 +#define CRED_FLAG_RESOLVED 0x00100000 +#define CRED_FLAG_TARGET 0x00200000 +#define CRED_FLAG_CERTIFICATE 0x00400000 +#define CRED_FLAG_CONFIG_BLOB 0x00800000 +#define CRED_FLAG_PUBLIC_MASK 0x0000FFFF + +#ifdef HAVE_HEIMDAL_VERSION +struct gss_cred_id_t_desc_struct +#else +struct gss_cred_id_struct +#endif +{ + GSSEAP_MUTEX mutex; + OM_uint32 flags; + gss_name_t name; + gss_name_t target; /* for initiator */ + gss_buffer_desc password; + gss_OID_set mechanisms; + time_t expiryTime; + gss_buffer_desc radiusConfigFile; + gss_buffer_desc radiusConfigStanza; + gss_buffer_desc caCertificate; + gss_buffer_desc subjectNameConstraint; + gss_buffer_desc subjectAltNameConstraint; + gss_buffer_desc clientCertificate; + gss_buffer_desc privateKey; + gss_buffer_desc caCertificateBlob; +#ifdef GSSEAP_ENABLE_REAUTH + krb5_ccache krbCredCache; + gss_cred_id_t reauthCred; +#endif +}; + +#define CTX_FLAG_INITIATOR 0x00000001 +#define CTX_FLAG_KRB_REAUTH 0x00000002 +#define CTX_FLAG_CHANNEL_BINDINGS_VERIFIED 0x00000004 + +#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0) + +#define CTX_IS_ESTABLISHED(ctx) ((ctx)->state == GSSEAP_STATE_ESTABLISHED) + +/* Initiator context flags */ +#define CTX_FLAG_EAP_SUCCESS 0x00010000 +#define CTX_FLAG_EAP_RESTART 0x00020000 +#define CTX_FLAG_EAP_FAIL 0x00040000 +#define CTX_FLAG_EAP_RESP 0x00080000 +#define CTX_FLAG_EAP_NO_RESP 0x00100000 +#define CTX_FLAG_EAP_REQ 0x00200000 +#define CTX_FLAG_EAP_PORT_ENABLED 0x00400000 +#define CTX_FLAG_EAP_ALT_ACCEPT 0x00800000 +#define CTX_FLAG_EAP_ALT_REJECT 0x01000000 +#define CTX_FLAG_EAP_CHBIND_ACCEPT 0x02000000 +#define CTX_FLAG_EAP_TRIGGER_START 0x04000000 +#define CTX_FLAG_EAP_MASK 0xFFFF0000 + +#define CONFIG_BLOB_CLIENT_CERT 0 +#define CONFIG_BLOB_PRIVATE_KEY 1 +#define CONFIG_BLOB_CA_CERT 2 +#define CONFIG_BLOB_MAX 3 + +struct gss_eap_initiator_ctx { + unsigned int idleWhile; + struct eap_peer_config eapPeerConfig; + struct eap_sm *eap; + struct wpabuf reqData; + struct wpabuf *chbindData; + unsigned int chbindReqFlags; + struct wpa_config_blob configBlobs[CONFIG_BLOB_MAX]; +}; + +#ifdef GSSEAP_ENABLE_ACCEPTOR +struct gss_eap_acceptor_ctx { + struct rs_context *radContext; + struct rs_connection *radConn; + char *radServer; + gss_buffer_desc state; + rs_avp *vps; +}; +#endif + +#ifdef HAVE_HEIMDAL_VERSION +struct gss_ctx_id_t_desc_struct +#else +struct gss_ctx_id_struct +#endif +{ + GSSEAP_MUTEX mutex; + enum gss_eap_state state; + OM_uint32 flags; + OM_uint32 gssFlags; + gss_OID mechanismUsed; + krb5_cksumtype checksumType; + krb5_enctype encryptionType; + krb5_keyblock rfc3961Key; + gss_name_t initiatorName; + gss_name_t acceptorName; + time_t expiryTime; + uint64_t sendSeq, recvSeq; + void *seqState; + gss_cred_id_t cred; + union { + struct gss_eap_initiator_ctx initiator; + #define initiatorCtx ctxU.initiator +#ifdef GSSEAP_ENABLE_ACCEPTOR + struct gss_eap_acceptor_ctx acceptor; + #define acceptorCtx ctxU.acceptor +#endif +#ifdef GSSEAP_ENABLE_REAUTH + gss_ctx_id_t reauth; + #define reauthCtx ctxU.reauth +#endif + } ctxU; + const struct gss_eap_token_buffer_set *inputTokens; + const struct gss_eap_token_buffer_set *outputTokens; +}; + +#define TOK_FLAG_SENDER_IS_ACCEPTOR 0x01 +#define TOK_FLAG_WRAP_CONFIDENTIAL 0x02 +#define TOK_FLAG_ACCEPTOR_SUBKEY 0x04 + +#define KEY_USAGE_ACCEPTOR_SEAL 22 +#define KEY_USAGE_ACCEPTOR_SIGN 23 +#define KEY_USAGE_INITIATOR_SEAL 24 +#define KEY_USAGE_INITIATOR_SIGN 25 + +#define KEY_USAGE_GSSEAP_CHBIND_MIC 60 +#define KEY_USAGE_GSSEAP_ACCTOKEN_MIC 61 +#define KEY_USAGE_GSSEAP_INITOKEN_MIC 62 + +/* accept_sec_context.c */ +OM_uint32 +gssEapAcceptSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle); + +/* init_sec_context.c */ +OM_uint32 +gssEapInitSecContext(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec); + +/* wrap_iov.c */ +OM_uint32 +gssEapWrapOrGetMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype); + +OM_uint32 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status, + gss_ctx_id_t ctx, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype); + +OM_uint32 +gssEapWrapIovLength(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count); +OM_uint32 +gssEapWrap(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer); + +unsigned char +rfc4121Flags(gss_ctx_id_t ctx, int receiving); + +/* display_status.c */ +void +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...); + +OM_uint32 +gssEapDisplayStatus(OM_uint32 *minor, + OM_uint32 status_value, + gss_buffer_t status_string); + +#define IS_WIRE_ERROR(err) ((err) >= GSSEAP_RESERVED && \ + (err) <= GSSEAP_RADIUS_PROT_FAILURE) + +#ifdef GSSEAP_ENABLE_ACCEPTOR +#define IS_RADIUS_ERROR(err) ((err) >= ERROR_TABLE_BASE_rse && \ + (err) <= ERROR_TABLE_BASE_rse + RSE_MAX) +#else +#define IS_RADIUS_ERROR(err) (0) +#endif + +/* exchange_meta_data.c */ +OM_uint32 GSSAPI_CALLCONV +gssEapExchangeMetaData(OM_uint32 *minor, + gss_const_OID mech, + gss_cred_id_t cred, + gss_ctx_id_t *ctx, + const gss_name_t name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data); + +/* export_sec_context.c */ +OM_uint32 +gssEapExportSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t token); + +/* import_sec_context.c */ +OM_uint32 +gssEapImportContext(OM_uint32 *minor, + gss_buffer_t token, + gss_ctx_id_t ctx); + +/* inquire_sec_context_by_oid.c */ +#define NEGOEX_INITIATOR_SALT "gss-eap-negoex-initiator" +#define NEGOEX_INITIATOR_SALT_LEN (sizeof(NEGOEX_INITIATOR_SALT) - 1) + +#define NEGOEX_ACCEPTOR_SALT "gss-eap-negoex-acceptor" +#define NEGOEX_ACCEPTOR_SALT_LEN (sizeof(NEGOEX_ACCEPTOR_SALT) - 1) + +/* pseudo_random.c */ +OM_uint32 +gssEapPseudoRandom(OM_uint32 *minor, + gss_ctx_id_t ctx, + int prf_key, + const gss_buffer_t prf_in, + gss_buffer_t prf_out); + +/* query_mechanism_info.c */ +OM_uint32 +gssQueryMechanismInfo(OM_uint32 *minor, + gss_const_OID mech_oid, + unsigned char auth_scheme[16]); + +/* query_meta_data.c */ +OM_uint32 +gssEapQueryMetaData(OM_uint32 *minor, + gss_const_OID mech GSSEAP_UNUSED, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags GSSEAP_UNUSED, + gss_buffer_t meta_data); + +/* eap_mech.c */ +OM_uint32 +gssEapInitiatorInit(OM_uint32 *minor); + +void +gssEapFinalize(void); + + /* Debugging and tracing*/ + #define gssEapTrace(_fmt, ...) wpa_printf(MSG_INFO, _fmt, __VA_ARGS__); + +static inline void +gssEapTraceStatus(const char *function, + OM_uint32 major, OM_uint32 minor) +{ + gss_buffer_desc gss_code_buf, mech_buf; + OM_uint32 tmpmaj, tmpmin, ctx = 0; + gss_code_buf.value = NULL; + mech_buf.value = NULL; + tmpmaj = gss_display_status(&tmpmin, major, + GSS_C_GSS_CODE, GSS_C_NO_OID, &ctx, + &gss_code_buf); + if (!GSS_ERROR(tmpmaj)) { +if (minor == 0) + tmpmaj = makeStringBuffer(&tmpmin, "no minor", &mech_buf); +else tmpmaj = gssEapDisplayStatus(&tmpmin, minor, &mech_buf); +} + if (!GSS_ERROR(tmpmaj)) + wpa_printf(MSG_INFO, "%s: %.*s/%.*s", + function, (int) gss_code_buf.length, (char *) gss_code_buf.value, + (int) mech_buf.length, (char *) mech_buf.value); + else wpa_printf(MSG_INFO, "%s: %u/%u", + function, major, minor); + tmpmaj = gss_release_buffer(&tmpmin, &gss_code_buf); + tmpmaj = gss_release_buffer(&tmpmin, &mech_buf); + } + + + /*If built as a library on Linux, don't respect environment when set*uid*/ +#ifdef HAVE_SECURE_GETENV +#define getenv secure_getenv +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _GSSAPIP_EAP_H_ */ diff --git a/mech_eap/gssapi_eap.h b/mech_eap/gssapi_eap.h new file mode 100644 index 0000000..02f132f --- /dev/null +++ b/mech_eap/gssapi_eap.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GSSAPI_EAP_H_ +#define _GSSAPI_EAP_H_ 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * GSS EAP mechanism OIDs. + */ +extern gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM; +extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM; + +/* + * Mechanism name OID. + */ +extern gss_OID GSS_EAP_NT_EAP_NAME; + +/* + * The libradsec configuration file; defaults to radsec.conf + * in the system configuration directory if unspecified. + */ +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE; + +/* + * The stanza in the libradsec configuration file; defaults + * to "gss-eap" if unspecified. + */ +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA; + +/* + * Flags as a 32-bit integer in network byte order, + * followed by a boolean octet indicating whether to + * clear the specified flags (if absent, defaults to + * FALSE, ie. set flags). + */ +extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG; + +/* + * Password; for mechanism glues that do not support + * gss_acquire_cred_with_password(), this can be set + * on an existing credentials handle. + */ +extern gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD; + +/* + * Path to PKCS#12 private key file for use with EAP-TLS + * authentication. + */ +extern gss_OID GSS_EAP_CRED_SET_CRED_PRIVATE_KEY; + + +/* + * Credentials flag indicating the local attributes + * processing should be skipped. + */ +#define GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG 0x00000001 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _GSSAPI_EAP_H_ */ diff --git a/mech_eap/gsseap_err.et b/mech_eap/gsseap_err.et new file mode 100644 index 0000000..5008e1c --- /dev/null +++ b/mech_eap/gsseap_err.et @@ -0,0 +1,172 @@ +# +# Copyright (c) 2011, JANET(UK) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of JANET(UK) nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +error_table eapg + +# +# Standards-track Protocol errors that can be returned in an error token. This should match +# up with makeErrorToken in accept_sec_context.c. +# +error_code GSSEAP_RESERVED, "" +error_code GSSEAP_WRONG_SIZE, "Buffer is incorrect size" +error_code GSSEAP_WRONG_MECH, "Mechanism OID is incorrect" +error_code GSSEAP_BAD_TOK_HEADER, "Token header is malformed or corrupt" +error_code GSSEAP_TOK_TRUNC, "Token is missing data" +error_code GSSEAP_BAD_DIRECTION, "Packet was replayed in wrong direction" +error_code GSSEAP_WRONG_TOK_ID, "Received token ID does not match expected token ID" +error_code GSSEAP_CRIT_ITOK_UNAVAILABLE, "Critical inner token type unavailable" +error_code GSSEAP_MISSING_REQUIRED_ITOK, "Missing required inner token" +error_code GSSEAP_DUPLICATE_ITOK, "Duplicate inner token received" +error_code GSSEAP_WRONG_ITOK, "Recieved invalid inner token for current state" +error_code GSSEAP_KEY_UNAVAILABLE, "EAP key unavailable" +error_code GSSEAP_KEY_TOO_SHORT, "EAP key too short" +error_code GSSEAP_RADIUS_AUTH_FAILURE, "Authentication rejected by RADIUS server" +error_code GSSEAP_UNKNOWN_RADIUS_CODE, "Received unknown response code from RADIUS server" +error_code GSSEAP_MISSING_EAP_REQUEST, "RADIUS response is missing EAP request" +error_code GSSEAP_RADIUS_PROT_FAILURE, "Generic RADIUS failure" + +# Extension errors starting with 128 that can be returned in a +#protocol token; again should match accept_sec_context.c + +error_code GSSEAP_RADIUS_UNROUTABLE, "Proxy had no route to identity provider realm" + +error_code GSSEAP_RADIUS_ADMIN_PROHIBIT, "IDP Administratively Prohibits Request" +# +# Context errors +# +error_code GSSEAP_CONTEXT_ESTABLISHED, "Context is already fully established" +error_code GSSEAP_CONTEXT_INCOMPLETE, "Attempt to use incomplete security context" +error_code GSSEAP_BAD_CONTEXT_TOKEN, "Context token is malformed or corrupt" +error_code GSSEAP_BAD_ERROR_TOKEN, "Error token is malformed or corrupt" +error_code GSSEAP_BAD_CONTEXT_OPTION, "Bad context option" + +# +# Name errors +# +error_code GSSEAP_BAD_SERVICE_NAME, "Name is not a valid service name" +error_code GSSEAP_BAD_INITIATOR_NAME, "Initiator identity must be a valid name" +error_code GSSEAP_NO_HOSTNAME, "Could not determine local host name" +error_code GSSEAP_NO_ACCEPTOR_NAME, "Could not determine acceptor identity" +error_code GSSEAP_WRONG_ACCEPTOR_NAME, "Acceptor identity different than expected" +error_code GSSEAP_BAD_ACCEPTOR_NAME, "Acceptor name is too long or has too many components" +error_code GSSEAP_BAD_NAME_TOKEN, "Name token is malformed or corrupt" +error_code GSSEAP_NO_LOCAL_MAPPING, "Unable to map name to a local identity" + +# +# Credential errors +# +error_code GSSEAP_BAD_USAGE, "Credential usage type is unknown" +error_code GSSEAP_CRED_USAGE_MISMATCH, "Credential usage does not match requested usage" +error_code GSSEAP_CRED_MECH_MISMATCH, "Credential is not usable with this mechanism" +error_code GSSEAP_CRED_EXPIRED, "Attributes indicate credentials have expired" +error_code GSSEAP_BAD_CRED_OPTION, "Bad credential option" +error_code GSSEAP_NO_DEFAULT_IDENTITY, "Default credentials identity unavailable" +error_code GSSEAP_NO_DEFAULT_CRED, "Missing default password or other credentials" +error_code GSSEAP_CRED_RESOLVED, "Credential is already fully resolved" +error_code GSSEAP_BAD_CACERTIFICATE, "CA Certificate blob could not be parsed" + +# +# Local identity service errors +# +error_code GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE, "Unable to start identity service" +error_code GSSEAP_NO_IDENTITY_SELECTED, "No identity selected" +error_code GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR, "Identity service installation error" +error_code GSSEAP_IDENTITY_SERVICE_OS_ERROR, "Identity service OS error" +error_code GSSEAP_IDENTITY_SERVICE_IPC_ERROR, "Identity service IPC error" +error_code GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR, "Unknown identity service error" + +# +# Wrap/unwrap/PRF errors +# +error_code GSSEAP_BAD_WRAP_TOKEN, "Bad RFC 4121 wrap or MIC token" +error_code GSSEAP_MISSING_IOV, "IOV is missing required buffer" +error_code GSSEAP_BAD_STREAM_IOV, "Stream IOV can only contain a single data buffer" +error_code GSSEAP_BAD_PADDING_IOV, "Padding IOV is not permitted for RFC 4121 tokens" +error_code GSSEAP_UNKNOWN_QOP, "Unknown quality of protection specified" +error_code GSSEAP_INPUT_TOO_LONG, "PRF input too long" +error_code GSSEAP_BAD_PRF_KEY, "PRF key usage type is unknown" + +# +# libeap errors +# +error_code GSSEAP_LIBEAP_INIT_FAILURE, "Failed to initialize EAP library" +error_code GSSEAP_PEER_SM_INIT_FAILURE, "Failed to create EAP state machine" +error_code GSSEAP_PEER_SM_STEP_FAILURE, "Failed to step EAP state machine" +error_code GSSEAP_PEER_AUTH_FAILURE, "EAP peer authentication failure" +error_code GSSEAP_PEER_BAD_MESSAGE, "Received bad EAP message" + +# +# RadSec initialisation errors +# +error_code GSSEAP_RADSEC_INIT_FAILURE, "Failed to initialize RadSec library" +error_code GSSEAP_RADSEC_CONTEXT_FAILURE, "Failed to create RadSec context" + +# +# Attribute errors +# +error_code GSSEAP_NO_ATTR_CONTEXT, "Name has no attributes" +error_code GSSEAP_NO_ATTR_PROVIDERS, "Failed to initialize attribute providers" +error_code GSSEAP_NO_SUCH_ATTR, "Unknown naming attribute" +error_code GSSEAP_BAD_ATTR_TOKEN, "Serialised attributes are malformed or corrupt" +error_code GSSEAP_ATTR_CONTEXT_FAILURE, "Failed to initialize attribute context" + +# +# OpenSAML errors +# +error_code GSSEAP_SAML_INIT_FAILURE, "Failed to initialize SAML library" +error_code GSSEAP_SAML_SEC_POLICY_FAILURE, "Failed to process SAML security policy" +error_code GSSEAP_SAML_BINDING_FAILURE, "Failed in SAML binding processing" +error_code GSSEAP_SAML_PROFILE_FAILURE, "Failed to process SAML profile" +error_code GSSEAP_SAML_FATAL_PROFILE_FAILURE, "Non-recoverable failure in SAML profile processing" +error_code GSSEAP_SAML_RETRY_PROFILE_FAILURE, "Temporary failure in SAML profile processing" +error_code GSSEAP_SAML_METADATA_FAILURE, "Failure related to SAML metadata use" + +# +# Shibboleth errors +# +error_code GSSEAP_SHIB_INIT_FAILURE, "Failed to initialize Shibboleth" +error_code GSSEAP_SHIB_ATTR_FAILURE, "Failure during local attribute processing" +error_code GSSEAP_SHIB_ATTR_EXTRACT_FAILURE, "Failed to extract local attributes" +error_code GSSEAP_SHIB_ATTR_FILTER_FAILURE, "Failed to filter local attributes" +error_code GSSEAP_SHIB_ATTR_RESOLVE_FAILURE, "Failed to resolve local attributes" +error_code GSSEAP_SHIB_CONFIG_FAILURE, "Local attribute configuration failure" +error_code GSSEAP_SHIB_LISTENER_FAILURE, "Failed to communicate with local attribute server" + +# +# Extensions +# +error_code GSSEAP_BINDINGS_MISMATCH, "Channel bindings do not match" +error_code GSSEAP_MISSING_BINDINGS, "Channel binding token missing" +error_code GSSEAP_NO_MECHGLUE_SYMBOL, "Could not find symbol in mechanism glue" +error_code GSSEAP_BAD_INVOCATION, "Bad mechanism invoke OID" + +end diff --git a/mech_eap/import_name.c b/mech_eap/import_name.c new file mode 100644 index 0000000..8049e01 --- /dev/null +++ b/mech_eap/import_name.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Deserialise a name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_import_name(OM_uint32 *minor, + gss_buffer_t import_name_buffer, + gss_OID input_name_type, + gss_name_t *output_name) +{ + return gssEapImportName(minor, import_name_buffer, + input_name_type, GSS_C_NO_OID, output_name); +} diff --git a/mech_eap/import_sec_context.c b/mech_eap/import_sec_context.c new file mode 100644 index 0000000..a0ebb8c --- /dev/null +++ b/mech_eap/import_sec_context.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Deserialise a context handle. + */ + +#include "gssapiP_eap.h" + +#define UPDATE_REMAIN(n) do { \ + p += (n); \ + remain -= (n); \ + } while (0) + +#define CHECK_REMAIN(n) do { \ + if (remain < (n)) { \ + *minor = GSSEAP_TOK_TRUNC; \ + return GSS_S_DEFECTIVE_TOKEN; \ + } \ + } while (0) + +#ifdef GSSEAP_ENABLE_ACCEPTOR +static OM_uint32 +gssEapImportPartialContext(OM_uint32 *minor, + unsigned char **pBuf, + size_t *pRemain, + gss_ctx_id_t ctx) +{ + OM_uint32 major; + unsigned char *p = *pBuf; + size_t remain = *pRemain; + gss_buffer_desc buf; + size_t ctxLength, serverLen; + + /* Length of partial RADIUS context */ + CHECK_REMAIN(4); + ctxLength = load_uint32_be(p); + UPDATE_REMAIN(4); + + CHECK_REMAIN(ctxLength); + remain = ctxLength; /* check against partial context length */ + + /* Selected RADIUS server */ + CHECK_REMAIN(4); + serverLen = load_uint32_be(p); + UPDATE_REMAIN(4); + + if (serverLen != 0) { + CHECK_REMAIN(serverLen); + + ctx->acceptorCtx.radServer = GSSEAP_MALLOC(serverLen + 1); + if (ctx->acceptorCtx.radServer == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(ctx->acceptorCtx.radServer, p, serverLen); + ctx->acceptorCtx.radServer[serverLen] = '\0'; + + UPDATE_REMAIN(serverLen); + } + + /* RADIUS state blob */ + CHECK_REMAIN(4); + buf.length = load_uint32_be(p); + UPDATE_REMAIN(4); + + if (buf.length != 0) { + CHECK_REMAIN(buf.length); + + buf.value = p; + + major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state); + if (GSS_ERROR(major)) + return major; + + UPDATE_REMAIN(buf.length); + } + +#ifdef GSSEAP_DEBUG + GSSEAP_ASSERT(remain == 0); +#endif + + *pBuf = p; + *pRemain -= 4 + ctxLength; + + return GSS_S_COMPLETE; +} +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + +static OM_uint32 +importMechanismOid(OM_uint32 *minor, + unsigned char **pBuf, + size_t *pRemain, + gss_OID *pOid) +{ + OM_uint32 major; + unsigned char *p = *pBuf; + size_t remain = *pRemain; + gss_OID_desc oidBuf; + + oidBuf.length = load_uint32_be(p); + if (remain < 4 + oidBuf.length || oidBuf.length == 0) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + oidBuf.elements = &p[4]; + + major = gssEapCanonicalizeOid(minor, &oidBuf, 0, pOid); + if (GSS_ERROR(major)) + return major; + + *pBuf += 4 + oidBuf.length; + *pRemain -= 4 + oidBuf.length; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +importKerberosKey(OM_uint32 *minor, + unsigned char **pBuf, + size_t *pRemain, + krb5_cksumtype *checksumType, + krb5_enctype *pEncryptionType, + krb5_keyblock *pKey) +{ + unsigned char *p = *pBuf; + size_t remain = *pRemain; + OM_uint32 encryptionType; + OM_uint32 length; + krb5_context krbContext; + krb5_keyblock key; + krb5_error_code code; + + GSSEAP_KRB_INIT(&krbContext); + + KRB_KEY_INIT(pKey); + + if (remain < 12) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + *checksumType = load_uint32_be(&p[0]); + encryptionType = load_uint32_be(&p[4]); + length = load_uint32_be(&p[8]); + + if ((length != 0) != (encryptionType != ENCTYPE_NULL)) { + *minor = GSSEAP_BAD_CONTEXT_TOKEN; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (remain - 12 < length) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (encryptionType != ENCTYPE_NULL) { + KRB_KEY_INIT(&key); + + KRB_KEY_TYPE(&key) = encryptionType; + KRB_KEY_LENGTH(&key) = length; + KRB_KEY_DATA(&key) = &p[12]; + + code = krb5_copy_keyblock_contents(krbContext, &key, pKey); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + } + + *pBuf += 12 + length; + *pRemain -= 12 + length; + *pEncryptionType = encryptionType; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +importName(OM_uint32 *minor, + gss_OID mech, + unsigned char **pBuf, + size_t *pRemain, + gss_name_t *pName) +{ + OM_uint32 major, tmpMinor, flags; + unsigned char *p = *pBuf; + size_t remain = *pRemain; + gss_buffer_desc tmp; + + if (remain < 4) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + tmp.length = load_uint32_be(p); + if (tmp.length != 0) { + if (remain - 4 < tmp.length) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + tmp.value = p + 4; + + flags = EXPORT_NAME_FLAG_COMPOSITE; + if (mech == GSS_C_NO_OID) + flags |= EXPORT_NAME_FLAG_OID; + + major = gssEapImportNameInternal(minor, &tmp, pName, flags); + if (GSS_ERROR(major)) + return major; + + if ((flags & EXPORT_NAME_FLAG_OID) == 0) { + major = gssEapCanonicalizeOid(minor, mech, 0, &(*pName)->mechanismUsed); + if (GSS_ERROR(major)) { + gssEapReleaseName(&tmpMinor, pName); + return major; + } + } + } + + *pBuf += 4 + tmp.length; + *pRemain -= 4 + tmp.length; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapImportContext(OM_uint32 *minor, + gss_buffer_t token, + gss_ctx_id_t ctx) +{ + OM_uint32 major; + unsigned char *p = (unsigned char *)token->value; + size_t remain = token->length; + + if (remain < 16) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) { + *minor = GSSEAP_BAD_CONTEXT_TOKEN; + return GSS_S_DEFECTIVE_TOKEN; + } + ctx->state = load_uint32_be(&p[4]); + ctx->flags = load_uint32_be(&p[8]); + ctx->gssFlags = load_uint32_be(&p[12]); + p += 16; + remain -= 16; + + /* Validate state */ + if (GSSEAP_SM_STATE(ctx) < GSSEAP_STATE_INITIAL || + GSSEAP_SM_STATE(ctx) > GSSEAP_STATE_ESTABLISHED) + return GSS_S_DEFECTIVE_TOKEN; + + /* Only acceptor can export partial context tokens */ + if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) + return GSS_S_DEFECTIVE_TOKEN; + + major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed); + if (GSS_ERROR(major)) + return major; + + major = importKerberosKey(minor, &p, &remain, + &ctx->checksumType, + &ctx->encryptionType, + &ctx->rfc3961Key); + if (GSS_ERROR(major)) + return major; + + /* Initiator name OID matches the context mechanism, so it's not encoded */ + major = importName(minor, ctx->mechanismUsed, &p, &remain, &ctx->initiatorName); + if (GSS_ERROR(major)) + return major; + + major = importName(minor, GSS_C_NO_OID, &p, &remain, &ctx->acceptorName); + if (GSS_ERROR(major)) + return major; + + /* Check that, if context is established, names are valid */ + if (CTX_IS_ESTABLISHED(ctx) && + (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME + : ctx->initiatorName == GSS_C_NO_NAME)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + if (remain < 24 + sequenceSize(ctx->seqState)) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + ctx->expiryTime = (time_t)load_uint64_be(&p[0]); + ctx->sendSeq = load_uint64_be(&p[8]); + ctx->recvSeq = load_uint64_be(&p[16]); + p += 24; + remain -= 24; + + major = sequenceInternalize(minor, &ctx->seqState, &p, &remain); + if (GSS_ERROR(major)) + return major; + +#ifdef GSSEAP_ENABLE_ACCEPTOR + /* + * The partial context should only be expected for unestablished + * acceptor contexts. + */ + if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) && + (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) { + major = gssEapImportPartialContext(minor, &p, &remain, ctx); + if (GSS_ERROR(major)) + return major; + } + +#ifdef GSSEAP_DEBUG + GSSEAP_ASSERT(remain == 0); +#endif +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + + major = GSS_S_COMPLETE; + *minor = 0; + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_import_sec_context(OM_uint32 *minor, + gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle) +{ + OM_uint32 major, tmpMinor; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + + *context_handle = GSS_C_NO_CONTEXT; + + if (interprocess_token == GSS_C_NO_BUFFER || + interprocess_token->length == 0) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + major = gssEapAllocContext(minor, &ctx); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapImportContext(minor, interprocess_token, ctx); + if (GSS_ERROR(major)) + goto cleanup; + + *context_handle = ctx; + +cleanup: + if (GSS_ERROR(major)) + gssEapReleaseContext(&tmpMinor, &ctx); + + return major; +} diff --git a/mech_eap/indicate_mechs.c b/mech_eap/indicate_mechs.c new file mode 100644 index 0000000..d4d275e --- /dev/null +++ b/mech_eap/indicate_mechs.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Enumerate the supported mechanism OIDs. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_indicate_mechs(OM_uint32 *minor, + gss_OID_set *mech_set) +{ + return gssEapIndicateMechs(minor, mech_set); +} diff --git a/mech_eap/init_sec_context.c b/mech_eap/init_sec_context.c new file mode 100644 index 0000000..a9d8891 --- /dev/null +++ b/mech_eap/init_sec_context.c @@ -0,0 +1,1370 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Establish a security context on the initiator (client). These functions + * wrap around libeap. + */ + +#include "gssapiP_eap.h" +#include "radius/radius.h" +#include "util_radius.h" +#include "utils/radius_utils.h" + +/* methods allowed for phase1 authentication*/ +static const struct eap_method_type allowed_eap_method_types[] = { + {EAP_VENDOR_IETF, EAP_TYPE_TTLS}, + {EAP_VENDOR_IETF, EAP_TYPE_NONE}}; + +static OM_uint32 +policyVariableToFlag(enum eapol_bool_var variable) +{ + OM_uint32 flag = 0; + + switch (variable) { + case EAPOL_eapSuccess: + flag = CTX_FLAG_EAP_SUCCESS; + break; + case EAPOL_eapRestart: + flag = CTX_FLAG_EAP_RESTART; + break; + case EAPOL_eapFail: + flag = CTX_FLAG_EAP_FAIL; + break; + case EAPOL_eapResp: + flag = CTX_FLAG_EAP_RESP; + break; + case EAPOL_eapNoResp: + flag = CTX_FLAG_EAP_NO_RESP; + break; + case EAPOL_eapReq: + flag = CTX_FLAG_EAP_REQ; + break; + case EAPOL_portEnabled: + flag = CTX_FLAG_EAP_PORT_ENABLED; + break; + case EAPOL_altAccept: + flag = CTX_FLAG_EAP_ALT_ACCEPT; + break; + case EAPOL_altReject: + flag = CTX_FLAG_EAP_ALT_REJECT; + break; + case EAPOL_eapTriggerStart: + flag = CTX_FLAG_EAP_TRIGGER_START; + break; + } + + return flag; +} + +static struct eap_peer_config * +peerGetConfig(void *ctx) +{ + gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx; + + return &gssCtx->initiatorCtx.eapPeerConfig; +} + +static Boolean +peerGetBool(void *data, enum eapol_bool_var variable) +{ + gss_ctx_id_t ctx = data; + OM_uint32 flag; + + if (ctx == GSS_C_NO_CONTEXT) + return FALSE; + + flag = policyVariableToFlag(variable); + + return ((ctx->flags & flag) != 0); +} + +static void +peerSetBool(void *data, enum eapol_bool_var variable, + Boolean value) +{ + gss_ctx_id_t ctx = data; + OM_uint32 flag; + + if (ctx == GSS_C_NO_CONTEXT) + return; + + flag = policyVariableToFlag(variable); + + if (value) + ctx->flags |= flag; + else + ctx->flags &= ~(flag); +} + +static unsigned int +peerGetInt(void *data, enum eapol_int_var variable) +{ + gss_ctx_id_t ctx = data; + + if (ctx == GSS_C_NO_CONTEXT) + return FALSE; + + GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx)); + + switch (variable) { + case EAPOL_idleWhile: + return ctx->initiatorCtx.idleWhile; + break; + } + + return 0; +} + +static void +peerSetInt(void *data, enum eapol_int_var variable, + unsigned int value) +{ + gss_ctx_id_t ctx = data; + + if (ctx == GSS_C_NO_CONTEXT) + return; + + GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx)); + + switch (variable) { + case EAPOL_idleWhile: + ctx->initiatorCtx.idleWhile = value; + break; + } +} + +static struct wpabuf * +peerGetEapReqData(void *ctx) +{ + gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx; + + return &gssCtx->initiatorCtx.reqData; +} + +static void +peerSetConfigBlob(void *ctx GSSEAP_UNUSED, + struct wpa_config_blob *blob GSSEAP_UNUSED) +{ +} + +static const struct wpa_config_blob * +peerGetConfigBlob(void *ctx, + const char *name) +{ + gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx; + size_t index; + + if (strcmp(name, "client-cert") == 0) + index = CONFIG_BLOB_CLIENT_CERT; + else if (strcmp(name, "private-key") == 0) + index = CONFIG_BLOB_PRIVATE_KEY; + else if (strcmp(name, "ca-cert") == 0) + index = CONFIG_BLOB_CA_CERT; + else + return NULL; + + return &gssCtx->initiatorCtx.configBlobs[index]; +} + +static void +peerNotifyPending(void *ctx GSSEAP_UNUSED) +{ +} + +static struct eapol_callbacks gssEapPolicyCallbacks = { + peerGetConfig, + peerGetBool, + peerSetBool, + peerGetInt, + peerSetInt, + peerGetEapReqData, + peerSetConfigBlob, + peerGetConfigBlob, + peerNotifyPending, +}; + + +#define CHBIND_SERVICE_NAME_FLAG 0x01 +#define CHBIND_HOST_NAME_FLAG 0x02 +#define CHBIND_SERVICE_SPECIFIC_FLAG 0x04 +#define CHBIND_REALM_NAME_FLAG 0x08 + +static OM_uint32 +peerInitEapChannelBinding(OM_uint32 *minor, gss_ctx_id_t ctx) +{ + struct wpabuf *buf = NULL; + unsigned int chbindReqFlags = 0; + krb5_principal princ = NULL; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + OM_uint32 major = GSS_S_COMPLETE; + krb5_context krbContext = NULL; + + /* XXX is this check redundant? */ + if (ctx->acceptorName == GSS_C_NO_NAME) { + major = GSS_S_BAD_NAME; + *minor = GSSEAP_NO_ACCEPTOR_NAME; + goto cleanup; + } + + princ = ctx->acceptorName->krbPrincipal; + + krbPrincComponentToGssBuffer(princ, 0, &nameBuf); + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_SERVICE_NAME, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_SERVICE_NAME_FLAG; + } + + krbPrincComponentToGssBuffer(princ, 1, &nameBuf); + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_HOST_NAME, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_HOST_NAME_FLAG; + } + + GSSEAP_KRB_INIT(&krbContext); + + *minor = krbPrincUnparseServiceSpecifics(krbContext, princ, &nameBuf); + if (*minor != 0) + goto cleanup; + + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, + PW_GSS_ACCEPTOR_SERVICE_SPECIFICS, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_SERVICE_SPECIFIC_FLAG; + } + + krbFreeUnparsedName(krbContext, &nameBuf); + krbPrincRealmToGssBuffer(princ, &nameBuf); + + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, + PW_GSS_ACCEPTOR_REALM_NAME, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_REALM_NAME_FLAG; + } + + if (chbindReqFlags == 0) { + major = GSS_S_BAD_NAME; + *minor = GSSEAP_BAD_ACCEPTOR_NAME; + goto cleanup; + } + + ctx->initiatorCtx.chbindData = buf; + ctx->initiatorCtx.chbindReqFlags = chbindReqFlags; + + buf = NULL; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + /*namebuf is freed when used and may be left with a unowned pointer*/ + wpabuf_free(buf); + + return major; +} + +static void +peerProcessChbindResponse(void *context, int code, int nsid, + u8 *data, size_t len) +{ + radius_parser msg; + gss_ctx_id_t ctx = (gss_ctx_id_t )context; + void *vsadata; + u8 type; + u32 vendor_id; + u32 chbindRetFlags = 0; + size_t vsadata_len; + + if (nsid != CHBIND_NSID_RADIUS) + return; + + if (data == NULL) + return; + msg = radius_parser_start(data, len); + if (msg == NULL) + return; + + while (radius_parser_parse_tlv(msg, &type, &vendor_id, &vsadata, + &vsadata_len) == 0) { + switch (type) { + case PW_GSS_ACCEPTOR_SERVICE_NAME: + chbindRetFlags |= CHBIND_SERVICE_NAME_FLAG; + break; + case PW_GSS_ACCEPTOR_HOST_NAME: + chbindRetFlags |= CHBIND_HOST_NAME_FLAG; + break; + case PW_GSS_ACCEPTOR_SERVICE_SPECIFICS: + chbindRetFlags |= CHBIND_SERVICE_SPECIFIC_FLAG; + break; + case PW_GSS_ACCEPTOR_REALM_NAME: + chbindRetFlags |= CHBIND_REALM_NAME_FLAG; + break; + } + } + + radius_parser_finish(msg); + + if (code == CHBIND_CODE_SUCCESS && + ((chbindRetFlags & ctx->initiatorCtx.chbindReqFlags) == ctx->initiatorCtx.chbindReqFlags)) { + ctx->flags |= CTX_FLAG_EAP_CHBIND_ACCEPT; + ctx->gssFlags |= GSS_C_MUTUAL_FLAG; + } /* else log failures? */ +} + +static OM_uint32 +peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx) +{ + OM_uint32 major; + krb5_context krbContext; + struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig; + struct wpa_config_blob *configBlobs = ctx->initiatorCtx.configBlobs; + gss_buffer_desc identity = GSS_C_EMPTY_BUFFER; + gss_buffer_desc realm = GSS_C_EMPTY_BUFFER; + gss_cred_id_t cred = ctx->cred; + + eapPeerConfig->identity = NULL; + eapPeerConfig->identity_len = 0; + eapPeerConfig->anonymous_identity = NULL; + eapPeerConfig->anonymous_identity_len = 0; + eapPeerConfig->password = NULL; + eapPeerConfig->password_len = 0; + eapPeerConfig->eap_methods = (struct eap_method_type *) allowed_eap_method_types; + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + GSSEAP_KRB_INIT(&krbContext); + + eapPeerConfig->fragment_size = 1024; + + GSSEAP_ASSERT(cred->name != GSS_C_NO_NAME); + + if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) { + *minor = GSSEAP_BAD_INITIATOR_NAME; + return GSS_S_BAD_NAME; + } + + /* identity */ + major = gssEapDisplayName(minor, cred->name, &identity, NULL); + if (GSS_ERROR(major)) + return major; + + eapPeerConfig->identity = (unsigned char *)identity.value; + eapPeerConfig->identity_len = identity.length; + + krbPrincRealmToGssBuffer(cred->name->krbPrincipal, &realm); + + /* anonymous_identity */ + eapPeerConfig->anonymous_identity = GSSEAP_MALLOC(realm.length + 2); + if (eapPeerConfig->anonymous_identity == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + eapPeerConfig->anonymous_identity[0] = '@'; + memcpy(eapPeerConfig->anonymous_identity + 1, realm.value, realm.length); + eapPeerConfig->anonymous_identity[1 + realm.length] = '\0'; + eapPeerConfig->anonymous_identity_len = 1 + realm.length; + + /* password */ + if ((cred->flags & CRED_FLAG_CERTIFICATE) == 0) { + eapPeerConfig->password = (unsigned char *)cred->password.value; + eapPeerConfig->password_len = cred->password.length; + } + + /* certs */ + eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value; + eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value; + eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value; + configBlobs[CONFIG_BLOB_CA_CERT].data = cred->caCertificateBlob.value; + configBlobs[CONFIG_BLOB_CA_CERT].len = cred->caCertificateBlob.length; + + /* eap channel binding */ + if (ctx->initiatorCtx.chbindData != NULL) { + struct eap_peer_chbind_config *chbind_config = + (struct eap_peer_chbind_config *)GSSEAP_MALLOC(sizeof(struct eap_peer_chbind_config)); + if (chbind_config == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + chbind_config->req_data = wpabuf_mhead_u8(ctx->initiatorCtx.chbindData); + chbind_config->req_data_len = wpabuf_len(ctx->initiatorCtx.chbindData); + chbind_config->nsid = CHBIND_NSID_RADIUS; + chbind_config->response_cb = &peerProcessChbindResponse; + chbind_config->ctx = ctx; + eapPeerConfig->chbind_config = chbind_config; + eapPeerConfig->chbind_config_len = 1; + } else { + eapPeerConfig->chbind_config = NULL; + eapPeerConfig->chbind_config_len = 0; + } + if (cred->flags & CRED_FLAG_CERTIFICATE) { + /* + * CRED_FLAG_CONFIG_BLOB is an internal flag which will be used in the + * future to directly pass certificate and private key data to the + * EAP implementation, rather than an indirected string pointer. + */ + if (cred->flags & CRED_FLAG_CONFIG_BLOB) { + eapPeerConfig->client_cert = (unsigned char *)"blob://client-cert"; + configBlobs[CONFIG_BLOB_CLIENT_CERT].data = cred->clientCertificate.value; + configBlobs[CONFIG_BLOB_CLIENT_CERT].len = cred->clientCertificate.length; + + eapPeerConfig->client_cert = (unsigned char *)"blob://private-key"; + configBlobs[CONFIG_BLOB_PRIVATE_KEY].data = cred->clientCertificate.value; + configBlobs[CONFIG_BLOB_PRIVATE_KEY].len = cred->privateKey.length; + } else { + eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value; + eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value; + } + eapPeerConfig->private_key_passwd = (char *)cred->password.value; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +peerConfigFree(OM_uint32 *minor, + gss_ctx_id_t ctx) +{ + struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig; + + if (eapPeerConfig->identity != NULL) { + GSSEAP_FREE(eapPeerConfig->identity); + eapPeerConfig->identity = NULL; + eapPeerConfig->identity_len = 0; + } + + if (eapPeerConfig->anonymous_identity != NULL) { + GSSEAP_FREE(eapPeerConfig->anonymous_identity); + eapPeerConfig->anonymous_identity = NULL; + eapPeerConfig->anonymous_identity_len = 0; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +/* + * Mark an initiator context as ready for cryptographic operations + */ +static OM_uint32 +initReady(OM_uint32 *minor, gss_ctx_id_t ctx) +{ + OM_uint32 major; + const unsigned char *key; + size_t keyLength; + + /* Cache encryption type derived from selected mechanism OID */ + major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType); + if (GSS_ERROR(major)) + return major; + + if (!eap_key_available(ctx->initiatorCtx.eap)) { + *minor = GSSEAP_KEY_UNAVAILABLE; + return GSS_S_UNAVAILABLE; + } + + key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength); + + if (keyLength < EAP_EMSK_LEN) { + *minor = GSSEAP_KEY_TOO_SHORT; + return GSS_S_UNAVAILABLE; + } + + major = gssEapDeriveRfc3961Key(minor, + &key[EAP_EMSK_LEN / 2], + EAP_EMSK_LEN / 2, + ctx->encryptionType, + &ctx->rfc3961Key); + if (GSS_ERROR(major)) + return major; + + major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key, + &ctx->checksumType); + if (GSS_ERROR(major)) + return major; + + major = sequenceInit(minor, + &ctx->seqState, + ctx->recvSeq, + ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), + ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), + TRUE); + if (GSS_ERROR(major)) + return major; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +initBegin(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED) +{ + OM_uint32 major; + gss_cred_id_t cred = ctx->cred; + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + if (cred->expiryTime) + ctx->expiryTime = cred->expiryTime; + else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE) + ctx->expiryTime = 0; + else + ctx->expiryTime = time(NULL) + timeReq; + + /* + * The credential mutex protects its name, however we need to + * explicitly lock the acceptor name (unlikely as it may be + * that it has attributes set on it). + */ + major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName); + if (GSS_ERROR(major)) + return major; + + if (target != GSS_C_NO_NAME) { + GSSEAP_MUTEX_LOCK(&target->mutex); + + major = gssEapDuplicateName(minor, target, &ctx->acceptorName); + if (GSS_ERROR(major)) { + GSSEAP_MUTEX_UNLOCK(&target->mutex); + return major; + } + + GSSEAP_MUTEX_UNLOCK(&target->mutex); + } + + major = gssEapCanonicalizeOid(minor, + mech, + OID_FLAG_NULL_VALID | OID_FLAG_MAP_NULL_TO_DEFAULT_MECH, + &ctx->mechanismUsed); + if (GSS_ERROR(major)) + return major; + + /* If credentials were provided, check they're usable with this mech */ + if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) { + *minor = GSSEAP_CRED_MECH_MISMATCH; + return GSS_S_BAD_MECH; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +eapGssSmInitError(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx GSSEAP_UNUSED, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + unsigned char *p; + + if (inputToken->length < 8) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + p = (unsigned char *)inputToken->value; + + major = load_uint32_be(&p[0]); + *minor = load_uint32_be(&p[4]); + if ((*minor >0) && (*minor < 128)) + * minor += ERROR_TABLE_BASE_eapg; + else *minor = 0; + + if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) { + major = GSS_S_FAILURE; + *minor = GSSEAP_BAD_ERROR_TOKEN; + } + + GSSEAP_ASSERT(GSS_ERROR(major)); + + return major; +} + +#ifdef GSSEAP_ENABLE_REAUTH +static OM_uint32 +eapGssSmInitGssReauth(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major, tmpMinor; + gss_name_t mechTarget = GSS_C_NO_NAME; + gss_OID actualMech = GSS_C_NO_OID; + OM_uint32 gssFlags, timeRec; + + /* + * Here we use the passed in credential handle because the resolved + * context credential does not currently have the reauth creds. + */ + if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) { + if (!gssEapCanReauthP(cred, target, timeReq)) + return GSS_S_CONTINUE_NEEDED; + + ctx->flags |= CTX_FLAG_KRB_REAUTH; + } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_WRONG_ITOK; + goto cleanup; + } + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + major = gssEapMechToGlueName(minor, target, &mechTarget); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssInitSecContext(minor, + cred->reauthCred, + &ctx->reauthCtx, + mechTarget, + (gss_OID)gss_mech_krb5, + reqFlags | GSS_C_MUTUAL_FLAG, + timeReq, + chanBindings, + inputToken, + &actualMech, + outputToken, + &gssFlags, + &timeRec); + if (GSS_ERROR(major)) + goto cleanup; + + ctx->gssFlags = gssFlags; + + if (major == GSS_S_COMPLETE) { + GSSEAP_ASSERT(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE); + + major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec); + if (GSS_ERROR(major)) + goto cleanup; + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); + } else { + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE); + } + +cleanup: + gssReleaseName(&tmpMinor, &mechTarget); + + return major; +} +#endif /* GSSEAP_ENABLE_REAUTH */ + +#ifdef GSSEAP_DEBUG +static OM_uint32 +eapGssSmInitVendorInfo(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx GSSEAP_UNUSED, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + major = makeStringBuffer(minor, "JANET(UK)", outputToken); + if (GSS_ERROR(major)) + return major; + + return GSS_S_CONTINUE_NEEDED; +} +#endif + +static OM_uint32 +eapGssSmInitAcceptorName(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL && + ctx->acceptorName != GSS_C_NO_NAME) { + + /* Send desired target name to acceptor */ + major = gssEapDisplayName(minor, ctx->acceptorName, + outputToken, NULL); + if (GSS_ERROR(major)) + return major; + } else if (inputToken != GSS_C_NO_BUFFER) { + OM_uint32 tmpMinor; + gss_name_t nameHint; + int equal; + + /* Accept target name hint from acceptor or verify acceptor */ + major = gssEapImportName(minor, inputToken, + GSS_C_NT_USER_NAME, + ctx->mechanismUsed, + &nameHint); + if (GSS_ERROR(major)) + return major; + + if (ctx->acceptorName != GSS_C_NO_NAME) { + /* verify name hint matched asserted acceptor name */ + major = gssEapCompareName(minor, + nameHint, + ctx->acceptorName, + COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS, + &equal); + if (GSS_ERROR(major)) { + gssEapReleaseName(&tmpMinor, &nameHint); + return major; + } + + gssEapReleaseName(&tmpMinor, &nameHint); + + if (!equal) { + *minor = GSSEAP_WRONG_ACCEPTOR_NAME; + return GSS_S_DEFECTIVE_TOKEN; + } + } else { /* acceptor name is no_name */ + /* accept acceptor name hint */ + ctx->acceptorName = nameHint; + nameHint = GSS_C_NO_NAME; + } + } + + + /* + * Currently, other parts of the code assume that the acceptor name + * is available, hence this check. + */ + if (ctx->acceptorName == GSS_C_NO_NAME) { + *minor = GSSEAP_NO_ACCEPTOR_NAME; + return GSS_S_FAILURE; + } + + /* + * Generate channel binding data + */ + if (ctx->initiatorCtx.chbindData == NULL) { + major = peerInitEapChannelBinding(minor, ctx); + if (GSS_ERROR(major)) + return major; + } + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmInitIdentity(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags) +{ + struct eap_config eapConfig; + +#ifdef GSSEAP_ENABLE_REAUTH + if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) { + OM_uint32 tmpMinor; + + /* server didn't support reauthentication, sent EAP request */ + gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER); + ctx->flags &= ~(CTX_FLAG_KRB_REAUTH); + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL); + } else +#endif + *smFlags |= SM_FLAG_FORCE_SEND_TOKEN; + + GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0); + GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER); + + memset(&eapConfig, 0, sizeof(eapConfig)); + + ctx->initiatorCtx.eap = eap_peer_sm_init(ctx, + &gssEapPolicyCallbacks, + ctx, + &eapConfig); + if (ctx->initiatorCtx.eap == NULL) { + *minor = GSSEAP_PEER_SM_INIT_FAILURE; + return GSS_S_FAILURE; + } + + ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED; + + /* poke EAP state machine */ + if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) { + *minor = GSSEAP_PEER_SM_STEP_FAILURE; + return GSS_S_FAILURE; + } + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmInitAuthenticate(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + OM_uint32 tmpMinor; + struct wpabuf *resp = NULL; + + *minor = 0; + + GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER); + + major = peerConfigInit(minor, ctx); + if (GSS_ERROR(major)) + goto cleanup; + + GSSEAP_ASSERT(ctx->initiatorCtx.eap != NULL); + GSSEAP_ASSERT(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED); + + ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */ + + wpabuf_set(&ctx->initiatorCtx.reqData, + inputToken->value, inputToken->length); + + major = GSS_S_CONTINUE_NEEDED; + + eap_peer_sm_step(ctx->initiatorCtx.eap); + if (ctx->flags & CTX_FLAG_EAP_RESP) { + ctx->flags &= ~(CTX_FLAG_EAP_RESP); + + resp = eap_get_eapRespData(ctx->initiatorCtx.eap); + } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) { + major = initReady(minor, ctx); + if (GSS_ERROR(major)) + goto cleanup; + + ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS); + major = GSS_S_CONTINUE_NEEDED; + GSSEAP_SM_TRANSITION_NEXT(ctx); + } else if (ctx->flags & CTX_FLAG_EAP_FAIL) { + major = GSS_S_DEFECTIVE_CREDENTIAL; + *minor = GSSEAP_PEER_AUTH_FAILURE; + } else { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_PEER_BAD_MESSAGE; + } + +cleanup: + if (resp != NULL) { + OM_uint32 tmpMajor; + gss_buffer_desc respBuf; + + GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED); + + respBuf.length = wpabuf_len(resp); + respBuf.value = (void *)wpabuf_head(resp); + + tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + } + + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + } + + wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0); + peerConfigFree(&tmpMinor, ctx); + + return major; +} + +static OM_uint32 +eapGssSmInitGssFlags(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + unsigned char wireFlags[4]; + gss_buffer_desc flagsBuf; + + /* + * As a temporary measure, force mutual authentication until channel binding is + * more widely deployed. + */ + ctx->gssFlags |= GSS_C_MUTUAL_FLAG; + store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags); + + flagsBuf.length = sizeof(wireFlags); + flagsBuf.value = wireFlags; + + return duplicateBuffer(minor, &flagsBuf, outputToken); +} + +static OM_uint32 +eapGssSmInitGssChannelBindings(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + krb5_error_code code; + krb5_context krbContext; + krb5_data data; + krb5_checksum cksum; + gss_buffer_desc cksumBuffer; + + if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS || + chanBindings->application_data.length == 0) + return GSS_S_CONTINUE_NEEDED; + + GSSEAP_KRB_INIT(&krbContext); + + KRB_DATA_INIT(&data); + + gssBufferToKrbData(&chanBindings->application_data, &data); + + code = krb5_c_make_checksum(krbContext, ctx->checksumType, + &ctx->rfc3961Key, + KEY_USAGE_GSSEAP_CHBIND_MIC, + &data, &cksum); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + + cksumBuffer.length = KRB_CHECKSUM_LENGTH(&cksum); + cksumBuffer.value = KRB_CHECKSUM_DATA(&cksum); + + major = duplicateBuffer(minor, &cksumBuffer, outputToken); + if (GSS_ERROR(major)) { + krb5_free_checksum_contents(krbContext, &cksum); + return major; + } + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + krb5_free_checksum_contents(krbContext, &cksum); + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmInitInitiatorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + + major = gssEapMakeTokenMIC(minor, ctx, outputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + return GSS_S_CONTINUE_NEEDED; +} + +#ifdef GSSEAP_ENABLE_REAUTH +static OM_uint32 +eapGssSmInitReauthCreds(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + if (ctx->gssFlags & GSS_C_MUTUAL_FLAG) { + major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken); + if (GSS_ERROR(major)) + return major; + } + + *minor = 0; + return GSS_S_CONTINUE_NEEDED; +} +#endif /* GSSEAP_ENABLE_REAUTH */ + +static OM_uint32 +eapGssSmInitAcceptorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + major = gssEapVerifyTokenMIC(minor, ctx, inputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); + + *minor = 0; + + return GSS_S_COMPLETE; +} + +static struct gss_eap_sm eapGssInitiatorSm[] = { + { + ITOK_TYPE_CONTEXT_ERR, + ITOK_TYPE_NONE, + GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL), + 0, + eapGssSmInitError + }, + { + ITOK_TYPE_ACCEPTOR_NAME_RESP, + ITOK_TYPE_ACCEPTOR_NAME_REQ, + GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE | + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmInitAcceptorName + }, +#ifdef GSSEAP_DEBUG + { + ITOK_TYPE_NONE, + ITOK_TYPE_VENDOR_INFO, + GSSEAP_STATE_INITIAL, + 0, + eapGssSmInitVendorInfo + }, +#endif +#ifdef GSSEAP_ENABLE_REAUTH + { + ITOK_TYPE_REAUTH_RESP, + ITOK_TYPE_REAUTH_REQ, + GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE, + 0, + eapGssSmInitGssReauth + }, +#endif + { + ITOK_TYPE_NONE, + ITOK_TYPE_NONE, +#ifdef GSSEAP_ENABLE_REAUTH + GSSEAP_STATE_REAUTHENTICATE | +#endif + GSSEAP_STATE_INITIAL, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitIdentity + }, + { + ITOK_TYPE_EAP_REQ, + ITOK_TYPE_EAP_RESP, + GSSEAP_STATE_AUTHENTICATE, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitAuthenticate + }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_GSS_FLAGS, + GSSEAP_STATE_INITIATOR_EXTS, + 0, + eapGssSmInitGssFlags + }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_GSS_CHANNEL_BINDINGS, + GSSEAP_STATE_INITIATOR_EXTS, + 0, + eapGssSmInitGssChannelBindings + }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_INITIATOR_MIC, + GSSEAP_STATE_INITIATOR_EXTS, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitInitiatorMIC + }, +#ifdef GSSEAP_ENABLE_REAUTH + { + ITOK_TYPE_REAUTH_CREDS, + ITOK_TYPE_NONE, + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmInitReauthCreds + }, +#endif + /* other extensions go here */ + { + ITOK_TYPE_ACCEPTOR_MIC, + ITOK_TYPE_NONE, + GSSEAP_STATE_ACCEPTOR_EXTS, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitAcceptorMIC + } +}; + +OM_uint32 +gssEapInitSecContext(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + OM_uint32 major, tmpMinor; + int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID); + + /* + * XXX is acquiring the credential lock here necessary? The password is + * mutable but the contract could specify that this is not updated whilst + * a context is being initialized. + */ + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_LOCK(&cred->mutex); + + if (ctx->cred == GSS_C_NO_CREDENTIAL) { + major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred); + if (GSS_ERROR(major)) + goto cleanup; + + GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL); + } + + GSSEAP_MUTEX_LOCK(&ctx->cred->mutex); + + GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED); + GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE); + + if (initialContextToken) { + major = initBegin(minor, ctx, target_name, mech_type, + req_flags, time_req, input_chan_bindings); + if (GSS_ERROR(major)) + goto cleanup; + } + + major = gssEapSmStep(minor, + cred, + ctx, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + output_token, + eapGssInitiatorSm, + sizeof(eapGssInitiatorSm) / sizeof(eapGssInitiatorSm[0])); + if (GSS_ERROR(major)) + goto cleanup; + + if (actual_mech_type != NULL) { + OM_uint32 tmpMajor; + + tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, actual_mech_type); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + goto cleanup; + } + } + + if (ret_flags != NULL) + *ret_flags = ctx->gssFlags; + + if (time_rec != NULL) + gssEapContextTime(&tmpMinor, ctx, time_rec); + + GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED); + +cleanup: + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + if (ctx->cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex); + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_init_sec_context(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + OM_uint32 major, tmpMinor; + gss_ctx_id_t ctx = *context_handle; + + *minor = 0; + + output_token->length = 0; + output_token->value = NULL; + + if (ctx == GSS_C_NO_CONTEXT) { + if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + major = gssEapAllocContext(minor, &ctx); + if (GSS_ERROR(major)) + return major; + + ctx->flags |= CTX_FLAG_INITIATOR; + + *context_handle = ctx; + } + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapInitSecContext(minor, + cred, + ctx, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + if (GSS_ERROR(major)) + gssEapReleaseContext(&tmpMinor, context_handle); + + gssEapTraceStatus( "gss_init_sec_context", major, *minor); + return major; +} diff --git a/mech_eap/inquire_attrs_for_mech.c b/mech_eap/inquire_attrs_for_mech.c new file mode 100644 index 0000000..a359f68 --- /dev/null +++ b/mech_eap/inquire_attrs_for_mech.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Enumerate the features supported by the GSS EAP mechanism. + */ + +#include "gssapiP_eap.h" + +#define MA_ADD(ma, set) do { \ + major = gss_add_oid_set_member(minor, (gss_OID)(ma), (set)); \ + if (GSS_ERROR(major)) \ + goto cleanup; \ + } while (0) + +#define MA_SUPPORTED(ma) MA_ADD((ma), mech_attrs) +#define MA_KNOWN(ma) MA_ADD((ma), known_mech_attrs) + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_attrs_for_mech(OM_uint32 *minor, + gss_const_OID mech_oid, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs) +{ + OM_uint32 major, tmpMinor; + + if (mech_attrs != NULL) + *mech_attrs = GSS_C_NO_OID_SET; + if (known_mech_attrs != NULL) + *known_mech_attrs = GSS_C_NO_OID_SET; + + if (!gssEapIsConcreteMechanismOid((const gss_OID)mech_oid)) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } + + if (mech_attrs != NULL) { + major = gss_create_empty_oid_set(minor, mech_attrs); + if (GSS_ERROR(major)) + goto cleanup; + +#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH + if (oidEqual(mech_oid, GSS_EAP_MECHANISM)) + MA_SUPPORTED(GSS_C_MA_MECH_PSEUDO); + else + MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE); + MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED); + MA_SUPPORTED(GSS_C_MA_AUTH_INIT); + MA_SUPPORTED(GSS_C_MA_AUTH_TARG); + MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT); + MA_SUPPORTED(GSS_C_MA_INTEG_PROT); + MA_SUPPORTED(GSS_C_MA_CONF_PROT); + MA_SUPPORTED(GSS_C_MA_MIC); + MA_SUPPORTED(GSS_C_MA_WRAP); + MA_SUPPORTED(GSS_C_MA_REPLAY_DET); + MA_SUPPORTED(GSS_C_MA_OOS_DET); + MA_SUPPORTED(GSS_C_MA_CBINDINGS); + MA_SUPPORTED(GSS_C_MA_CTX_TRANS); +#endif + } + + if (known_mech_attrs != NULL) { + major = gss_create_empty_oid_set(minor, known_mech_attrs); + if (GSS_ERROR(major)) + goto cleanup; + +#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH + MA_KNOWN(GSS_C_MA_MECH_CONCRETE); + MA_KNOWN(GSS_C_MA_MECH_PSEUDO); + MA_KNOWN(GSS_C_MA_MECH_COMPOSITE); + MA_KNOWN(GSS_C_MA_MECH_NEGO); + MA_KNOWN(GSS_C_MA_MECH_GLUE); + MA_KNOWN(GSS_C_MA_NOT_MECH); + MA_KNOWN(GSS_C_MA_DEPRECATED); + MA_KNOWN(GSS_C_MA_NOT_DFLT_MECH); + MA_KNOWN(GSS_C_MA_ITOK_FRAMED); + MA_KNOWN(GSS_C_MA_AUTH_INIT); + MA_KNOWN(GSS_C_MA_AUTH_TARG); + MA_KNOWN(GSS_C_MA_AUTH_INIT_INIT); + MA_KNOWN(GSS_C_MA_AUTH_TARG_INIT); + MA_KNOWN(GSS_C_MA_AUTH_INIT_ANON); + MA_KNOWN(GSS_C_MA_AUTH_TARG_ANON); + MA_KNOWN(GSS_C_MA_DELEG_CRED); + MA_KNOWN(GSS_C_MA_INTEG_PROT); + MA_KNOWN(GSS_C_MA_CONF_PROT); + MA_KNOWN(GSS_C_MA_MIC); + MA_KNOWN(GSS_C_MA_WRAP); + MA_KNOWN(GSS_C_MA_PROT_READY); + MA_KNOWN(GSS_C_MA_REPLAY_DET); + MA_KNOWN(GSS_C_MA_OOS_DET); + MA_KNOWN(GSS_C_MA_CBINDINGS); + MA_KNOWN(GSS_C_MA_PFS); + MA_KNOWN(GSS_C_MA_COMPRESS); + MA_KNOWN(GSS_C_MA_CTX_TRANS); +#endif + } + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) { + gss_release_oid_set(&tmpMinor, mech_attrs); + gss_release_oid_set(&tmpMinor, known_mech_attrs); + } + + return major; +} diff --git a/mech_eap/inquire_context.c b/mech_eap/inquire_context.c new file mode 100644 index 0000000..5d0e5b6 --- /dev/null +++ b/mech_eap/inquire_context.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Return context handle properties. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_context(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *open) +{ + OM_uint32 major, tmpMinor; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (src_name != NULL) { + if (ctx->initiatorName != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, ctx->initiatorName, src_name); + if (GSS_ERROR(major)) + goto cleanup; + } else + *src_name = GSS_C_NO_NAME; + } + + if (targ_name != NULL) { + if (ctx->acceptorName != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name); + if (GSS_ERROR(major)) + goto cleanup; + } else + *targ_name = GSS_C_NO_NAME; + } + + if (lifetime_rec != NULL) + gssEapContextTime(&tmpMinor, ctx, lifetime_rec); + + if (mech_type != NULL) { + major = gssEapCanonicalizeOid(minor, ctx->mechanismUsed, 0, mech_type); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (ctx_flags != NULL) { + *ctx_flags = ctx->gssFlags; + } + + if (locally_initiated != NULL) { + *locally_initiated = CTX_IS_INITIATOR(ctx); + } + + if (open != NULL) { + *open = CTX_IS_ESTABLISHED(ctx); + } + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + if (GSS_ERROR(major)) { + gssEapReleaseName(&tmpMinor, src_name); + gssEapReleaseName(&tmpMinor, targ_name); + } + + return major; +} diff --git a/mech_eap/inquire_cred.c b/mech_eap/inquire_cred.c new file mode 100644 index 0000000..227ab16 --- /dev/null +++ b/mech_eap/inquire_cred.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Return credential handle properties. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_cred(OM_uint32 *minor, + gss_cred_id_t cred, + gss_name_t *name, + OM_uint32 *pLifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms) +{ + OM_uint32 major; + + if (cred == NULL) { + *minor = EINVAL; + return GSS_S_NO_CRED; + } + + GSSEAP_MUTEX_LOCK(&cred->mutex); + + major = gssEapInquireCred(minor, cred, name, pLifetime, cred_usage, mechanisms); + + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} diff --git a/mech_eap/inquire_cred_by_mech.c b/mech_eap/inquire_cred_by_mech.c new file mode 100644 index 0000000..191902d --- /dev/null +++ b/mech_eap/inquire_cred_by_mech.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Return credential handle properties. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_cred_by_mech(OM_uint32 *minor, + gss_cred_id_t cred, + gss_OID mech_type, + gss_name_t *name, + OM_uint32 *pInitiatorLifetime, + OM_uint32 *pAcceptorLifetime, + gss_cred_usage_t *cred_usage) +{ + OM_uint32 major, lifetime; + + if (cred == NULL) { + *minor = EINVAL; + return GSS_S_NO_CRED; + } + + GSSEAP_MUTEX_LOCK(&cred->mutex); + + if (!gssEapCredAvailable(cred, mech_type)) { + major = GSS_S_BAD_MECH; + *minor = GSSEAP_CRED_MECH_MISMATCH; + goto cleanup; + } + + major = gssEapInquireCred(minor, cred, name, &lifetime, cred_usage, NULL); + if (GSS_ERROR(major)) + goto cleanup; + + if (pInitiatorLifetime != NULL) + *pInitiatorLifetime = (cred->flags & CRED_FLAG_INITIATE) ? lifetime : 0; + if (pAcceptorLifetime != NULL) + *pAcceptorLifetime = (cred->flags & CRED_FLAG_ACCEPT) ? lifetime : 0; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} diff --git a/mech_eap/inquire_cred_by_oid.c b/mech_eap/inquire_cred_by_oid.c new file mode 100644 index 0000000..2ad34ed --- /dev/null +++ b/mech_eap/inquire_cred_by_oid.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Return extended credential handle properties. + */ + +#include "gssapiP_eap.h" + +#if 0 +static struct { + gss_OID_desc oid; + OM_uint32 (*inquire)(OM_uint32 *, const gss_cred_id_t, + const gss_OID, gss_buffer_set_t *); +} inquireCredOps[] = { +}; +#endif + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_cred_by_oid(OM_uint32 *minor, + const gss_cred_id_t cred_handle, + const gss_OID desired_object GSSEAP_UNUSED, + gss_buffer_set_t *data_set) +{ + OM_uint32 major; +#if 0 + int i; +#endif + *data_set = GSS_C_NO_BUFFER_SET; + + if (cred_handle == GSS_C_NO_CREDENTIAL) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED; + } + + GSSEAP_MUTEX_LOCK(&cred_handle->mutex); + + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_BAD_CRED_OPTION; + +#if 0 + for (i = 0; i < sizeof(inquireCredOps) / sizeof(inquireCredOps[0]); i++) { + if (oidEqual(&inquireCredOps[i].oid, desired_object)) { + major = (*inquireCredOps[i].inquire)(minor, cred_handle, + desired_object, data_set); + break; + } + } +#endif + + GSSEAP_MUTEX_UNLOCK(&cred_handle->mutex); + + return major; +} diff --git a/mech_eap/inquire_mech_for_saslname.c b/mech_eap/inquire_mech_for_saslname.c new file mode 100644 index 0000000..bd518c0 --- /dev/null +++ b/mech_eap/inquire_mech_for_saslname.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Map mechanism OID to a SASL mechanism name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_saslname_for_mech(OM_uint32 *minor, + const gss_OID mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + OM_uint32 major; + gss_buffer_t name; + krb5_enctype etype = ENCTYPE_NULL; + + /* Dynamically construct mechanism name from Kerberos string enctype */ + major = gssEapOidToEnctype(minor, mech, &etype); + if (GSS_ERROR(major)) + return major; + + if (mech_name != GSS_C_NO_BUFFER) { + krb5_context krbContext; + + GSSEAP_KRB_INIT(&krbContext); + + *minor = krbEnctypeToString(krbContext, etype, "eap-", mech_name); + if (*minor != 0) + return GSS_S_FAILURE; + } + + if (mech_description != GSS_C_NO_BUFFER) { + major = makeStringBuffer(minor, + "Extensible Authentication Protocol GSS-API Mechanism", + mech_description); + if (GSS_ERROR(major)) + return major; + } + + if (sasl_mech_name != GSS_C_NO_BUFFER) { + name = gssEapOidToSaslName(mech); + if (name == GSS_C_NO_BUFFER) { + major = GSS_S_BAD_MECH; + *minor = GSSEAP_WRONG_MECH; + } else { + major = duplicateBuffer(minor, name, sasl_mech_name); + } + } + + return major; +} diff --git a/mech_eap/inquire_mechs_for_name.c b/mech_eap/inquire_mechs_for_name.c new file mode 100644 index 0000000..89c869c --- /dev/null +++ b/mech_eap/inquire_mechs_for_name.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Determine mechanism OIDs supported by name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_mechs_for_name(OM_uint32 *minor, + const gss_name_t input_name, + gss_OID_set *mech_types) +{ + OM_uint32 major, tmpMinor; + + *minor = 0; + *mech_types = GSS_C_NO_OID_SET; + + if (input_name != GSS_C_NO_NAME && + input_name->mechanismUsed != GSS_C_NO_OID) { + major = gss_create_empty_oid_set(minor, mech_types); + if (GSS_ERROR(major)) + return major; + + major = gss_add_oid_set_member(minor, + input_name->mechanismUsed, + mech_types); + if (GSS_ERROR(major)) { + gss_release_oid_set(&tmpMinor, mech_types); + return major; + } + } else { + major = gssEapIndicateMechs(minor, mech_types); + if (GSS_ERROR(major)) + return major; + } + + return major; +} diff --git a/mech_eap/inquire_name.c b/mech_eap/inquire_name.c new file mode 100644 index 0000000..78b08a0 --- /dev/null +++ b/mech_eap/inquire_name.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Enumerate name attributes. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_name(OM_uint32 *minor, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + OM_uint32 major, tmpMinor; + + *minor = 0; + + if (name_is_MN != NULL) + *name_is_MN = 0; + if (MN_mech != NULL) + *MN_mech = GSS_C_NO_OID; + if (attrs != NULL) + *attrs = GSS_C_NO_BUFFER_SET; + + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + if (attrs == NULL) + return GSS_S_COMPLETE; + + GSSEAP_MUTEX_LOCK(&name->mutex); + + major = gssEapInquireName(minor, name, name_is_MN, MN_mech, attrs); + + GSSEAP_MUTEX_UNLOCK(&name->mutex); + + if (GSS_ERROR(major)) + gss_release_buffer_set(&tmpMinor, attrs); + + return major; +} diff --git a/mech_eap/inquire_names_for_mech.c b/mech_eap/inquire_names_for_mech.c new file mode 100644 index 0000000..0e60340 --- /dev/null +++ b/mech_eap/inquire_names_for_mech.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Return supported name OID types. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_names_for_mech(OM_uint32 *minor, + gss_OID mechanism, + gss_OID_set *ret_name_types) +{ + OM_uint32 major, tmpMinor; + gss_OID nameTypes[] = { + GSS_C_NT_USER_NAME, + GSS_C_NT_HOSTBASED_SERVICE, + GSS_C_NT_EXPORT_NAME, +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT + GSS_C_NT_COMPOSITE_EXPORT, +#endif + GSS_EAP_NT_EAP_NAME, + GSS_C_NT_ANONYMOUS, + }; + size_t i; + + if (!gssEapIsMechanismOid(mechanism)) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } + + major = gss_create_empty_oid_set(minor, ret_name_types); + if (GSS_ERROR(major)) + goto cleanup; + + for (i = 0; i < sizeof(nameTypes)/sizeof(nameTypes[0]); i++) { + major = gss_add_oid_set_member(minor, nameTypes[i], ret_name_types); + if (GSS_ERROR(major)) + goto cleanup; + } + +cleanup: + if (GSS_ERROR(major)) + gss_release_oid_set(&tmpMinor, ret_name_types); + + return major; +} diff --git a/mech_eap/inquire_saslname_for_mech.c b/mech_eap/inquire_saslname_for_mech.c new file mode 100644 index 0000000..d6d7c14 --- /dev/null +++ b/mech_eap/inquire_saslname_for_mech.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Map SASL mechanism name to a mechanism OID. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_mech_for_saslname(OM_uint32 *minor, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type) +{ + *mech_type = gssEapSaslNameToOid(sasl_mech_name); + if (*mech_type == GSS_C_NO_OID) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } + + return GSS_S_COMPLETE; +} diff --git a/mech_eap/inquire_sec_context_by_oid.c b/mech_eap/inquire_sec_context_by_oid.c new file mode 100644 index 0000000..bde7e1c --- /dev/null +++ b/mech_eap/inquire_sec_context_by_oid.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Return extended properties of a context handle. + */ + +#include "gssapiP_eap.h" + +static OM_uint32 +addEnctypeOidToBufferSet(OM_uint32 *minor, + krb5_enctype encryptionType, + gss_buffer_set_t *dataSet) +{ + OM_uint32 major; + unsigned char oidBuf[16]; + gss_OID_desc oid; + gss_buffer_desc buf; + + oid.length = sizeof(oidBuf); + oid.elements = oidBuf; + + major = composeOid(minor, + "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04", + 10, + encryptionType, + &oid); + if (GSS_ERROR(major)) + return major; + + buf.length = oid.length; + buf.value = oid.elements; + + major = gss_add_buffer_set_member(minor, &buf, dataSet); + + return major; +} + +static void +zeroAndReleaseBufferSet(gss_buffer_set_t *dataSet) +{ + OM_uint32 tmpMinor; + gss_buffer_set_t set = *dataSet; + size_t i; + + if (set == GSS_C_NO_BUFFER_SET) + return; + + for (i = 0; i count; i++) + memset(set->elements[i].value, 0, set->elements[i].length); + + gss_release_buffer_set(&tmpMinor, dataSet); +} + +static OM_uint32 +inquireSessionKey(OM_uint32 *minor, + const gss_ctx_id_t ctx, + const gss_OID desired_object GSSEAP_UNUSED, + gss_buffer_set_t *dataSet) +{ + OM_uint32 major; + gss_buffer_desc buf; + + if (ctx->encryptionType == ENCTYPE_NULL) { + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_KEY_UNAVAILABLE; + goto cleanup; + } + + buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key); + buf.value = KRB_KEY_DATA(&ctx->rfc3961Key); + + major = gss_add_buffer_set_member(minor, &buf, dataSet); + if (GSS_ERROR(major)) + goto cleanup; + + major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet); + if (GSS_ERROR(major)) + goto cleanup; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) + zeroAndReleaseBufferSet(dataSet); + + return major; +} + +static OM_uint32 +inquireNegoExKey(OM_uint32 *minor, + const gss_ctx_id_t ctx, + const gss_OID desired_object, + gss_buffer_set_t *dataSet) +{ + OM_uint32 major, tmpMinor; + int bInitiatorKey; + gss_buffer_desc salt; + gss_buffer_desc key = GSS_C_EMPTY_BUFFER; + size_t keySize; + + bInitiatorKey = CTX_IS_INITIATOR(ctx); + + if (ctx->encryptionType == ENCTYPE_NULL) { + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_KEY_UNAVAILABLE; + goto cleanup; + } + + /* + * If the caller supplied the verify key OID, then we need the acceptor + * key if we are the initiator, and vice versa. + */ + if (desired_object->length == 11 && + memcmp(desired_object->elements, + "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0) + bInitiatorKey ^= 1; + + if (bInitiatorKey) { + salt.length = NEGOEX_INITIATOR_SALT_LEN; + salt.value = NEGOEX_INITIATOR_SALT; + } else { + salt.length = NEGOEX_ACCEPTOR_SALT_LEN; + salt.value = NEGOEX_ACCEPTOR_SALT; + } + + keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key); + + key.value = GSSEAP_MALLOC(keySize); + if (key.value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + key.length = keySize; + + major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt, &key); + if (GSS_ERROR(major)) + goto cleanup; + + major = gss_add_buffer_set_member(minor, &key, dataSet); + if (GSS_ERROR(major)) + goto cleanup; + + major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet); + if (GSS_ERROR(major)) + goto cleanup; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (key.value != NULL) { + memset(key.value, 0, key.length); + gss_release_buffer(&tmpMinor, &key); + } + if (GSS_ERROR(major)) + zeroAndReleaseBufferSet(dataSet); + + return major; +} + +static struct { + gss_OID_desc oid; + OM_uint32 (*inquire)(OM_uint32 *, const gss_ctx_id_t, + const gss_OID, gss_buffer_set_t *); +} inquireCtxOps[] = { + { + /* GSS_C_INQ_SSPI_SESSION_KEY */ + { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" }, + inquireSessionKey + }, + { + /* GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT + v1 */ + { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" }, + gssEapExportLucidSecContext + }, + { + /* GSS_C_INQ_NEGOEX_KEY */ + { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" }, + inquireNegoExKey + }, + { + /* GSS_C_INQ_NEGOEX_VERIFY_KEY */ + { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" }, + inquireNegoExKey + }, +}; + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_sec_context_by_oid(OM_uint32 *minor, + const gss_ctx_id_t ctx, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + OM_uint32 major; + int i; + + *data_set = GSS_C_NO_BUFFER_SET; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + +#if 0 + if (!CTX_IS_ESTABLISHED(ctx)) { + *minor = GSSEAP_CONTEXT_INCOMPLETE; + major = GSS_S_NO_CONTEXT; + goto cleanup; + } +#endif + + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_BAD_CONTEXT_OPTION; + + for (i = 0; i < sizeof(inquireCtxOps) / sizeof(inquireCtxOps[0]); i++) { + if (oidEqual(&inquireCtxOps[i].oid, desired_object)) { + major = (*inquireCtxOps[i].inquire)(minor, ctx, + desired_object, data_set); + break; + } + } + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/install-sh b/mech_eap/install-sh new file mode 100755 index 0000000..6781b98 --- /dev/null +++ b/mech_eap/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/mech_eap/map_name_to_any.c b/mech_eap/map_name_to_any.c new file mode 100644 index 0000000..2a8a96c --- /dev/null +++ b/mech_eap/map_name_to_any.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_map_name_to_any(OM_uint32 *minor, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output) +{ + OM_uint32 major; + + *output = (gss_any_t)NULL; + + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&name->mutex); + + major = gssEapMapNameToAny(minor, name, authenticated, type_id, output); + + GSSEAP_MUTEX_UNLOCK(&name->mutex); + + return major; +} diff --git a/mech_eap/mech b/mech_eap/mech new file mode 100644 index 0000000..3d2a2a8 --- /dev/null +++ b/mech_eap/mech @@ -0,0 +1,8 @@ +# +# Sample mechanism glue configuration for EAP GSS mechanism. +# +# Any encryption type supported by Kerberos can be defined as the +# last element of the OID arc. +# +eap-aes128 1.3.6.1.5.5.15.1.1.17 mech_eap.so +eap-aes256 1.3.6.1.5.5.15.1.1.18 mech_eap.so diff --git a/mech_eap/mech_eap-noacceptor.exports b/mech_eap/mech_eap-noacceptor.exports new file mode 100644 index 0000000..f00df8a --- /dev/null +++ b/mech_eap/mech_eap-noacceptor.exports @@ -0,0 +1,55 @@ +gss_acquire_cred +gss_add_cred +gss_add_cred_with_password +gss_canonicalize_name +gss_compare_name +gss_context_time +gss_delete_sec_context +gss_display_name +gss_display_name_ext +gss_display_status +gss_duplicate_name +gss_exchange_meta_data +gss_export_name +gss_export_sec_context +gss_get_mic +gss_import_name +gss_import_sec_context +gss_indicate_mechs +gss_init_sec_context +gss_inquire_attrs_for_mech +gss_inquire_context +gss_inquire_cred +gss_inquire_cred_by_mech +gss_inquire_cred_by_oid +gss_inquire_mechs_for_name +gss_inquire_mech_for_saslname +gss_inquire_names_for_mech +gss_inquire_saslname_for_mech +gss_inquire_sec_context_by_oid +gss_process_context_token +gss_pseudo_random +gss_query_mechanism_info +gss_query_meta_data +gss_release_cred +gss_release_name +gss_internal_release_oid +gss_set_sec_context_option +gss_store_cred +gss_unwrap +gss_unwrap_iov +gss_verify_mic +gss_wrap +gss_wrap_iov +gss_wrap_iov_length +gss_wrap_size_limit +GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM +GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM +GSS_EAP_NT_EAP_NAME +GSS_EAP_CRED_SET_CRED_FLAG +GSS_EAP_CRED_SET_CRED_PASSWORD +GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE +GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA +gssspi_acquire_cred_with_password +gssspi_authorize_localname +gssspi_set_cred_option diff --git a/mech_eap/mech_eap.exports b/mech_eap/mech_eap.exports new file mode 100644 index 0000000..6a17a17 --- /dev/null +++ b/mech_eap/mech_eap.exports @@ -0,0 +1,63 @@ +gss_accept_sec_context +gss_acquire_cred +gss_add_cred +gss_add_cred_with_password +gss_canonicalize_name +gss_compare_name +gss_context_time +gss_delete_name_attribute +gss_delete_sec_context +gss_display_name +gss_display_name_ext +gss_display_status +gss_duplicate_name +gss_exchange_meta_data +gss_export_name +gss_export_name_composite +gss_export_sec_context +gss_get_mic +gss_get_name_attribute +gss_import_name +gss_import_sec_context +gss_indicate_mechs +gss_init_sec_context +gss_inquire_attrs_for_mech +gss_inquire_context +gss_inquire_cred +gss_inquire_cred_by_mech +gss_inquire_cred_by_oid +gss_inquire_mechs_for_name +gss_inquire_mech_for_saslname +gss_inquire_name +gss_inquire_names_for_mech +gss_inquire_saslname_for_mech +gss_inquire_sec_context_by_oid +gss_map_name_to_any +gss_process_context_token +gss_pseudo_random +gss_query_mechanism_info +gss_query_meta_data +gss_release_any_name_mapping +gss_release_cred +gss_release_name +gss_internal_release_oid +gss_set_name_attribute +gss_set_sec_context_option +gss_store_cred +gss_unwrap +gss_unwrap_iov +gss_verify_mic +gss_wrap +gss_wrap_iov +gss_wrap_iov_length +gss_wrap_size_limit +GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM +GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM +GSS_EAP_NT_EAP_NAME +GSS_EAP_CRED_SET_CRED_FLAG +GSS_EAP_CRED_SET_CRED_PASSWORD +GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE +GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA +gssspi_acquire_cred_with_password +gssspi_authorize_localname +gssspi_set_cred_option diff --git a/mech_eap/mech_invoke.c b/mech_eap/mech_invoke.c new file mode 100644 index 0000000..bc9bba3 --- /dev/null +++ b/mech_eap/mech_invoke.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gssspi_mech_invoke(OM_uint32 *minor, + const gss_OID desired_mech, + const gss_OID desired_object, + gss_buffer_t value) +{ + *minor = GSSEAP_BAD_INVOCATION; + + return GSS_S_UNAVAILABLE; +} diff --git a/mech_eap/process_context_token.c b/mech_eap/process_context_token.c new file mode 100644 index 0000000..02a4b6d --- /dev/null +++ b/mech_eap/process_context_token.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_process_context_token(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t token_buffer) +{ + OM_uint32 major; + gss_iov_buffer_desc iov[1]; + + *minor = 0; + + if (ctx == NULL) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + *minor = GSSEAP_CONTEXT_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer = *token_buffer; + + major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL, + iov, 1, TOK_TYPE_DELETE_CONTEXT); + if (GSS_ERROR(major)) { + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + return major; + } + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return gssEapReleaseContext(minor, &ctx); +} diff --git a/mech_eap/pseudo_random.c b/mech_eap/pseudo_random.c new file mode 100644 index 0000000..ad079b4 --- /dev/null +++ b/mech_eap/pseudo_random.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * PRF + */ + +#include "gssapiP_eap.h" + +OM_uint32 +gssEapPseudoRandom(OM_uint32 *minor, + gss_ctx_id_t ctx, + int prf_key, + const gss_buffer_t prf_in, + gss_buffer_t prf_out) +{ + krb5_error_code code; + int i; + OM_uint32 tmpMinor; + size_t prflen; + krb5_data t, ns; + unsigned char *p; + krb5_context krbContext; + ssize_t desired_output_len = prf_out->length; + + *minor = 0; + + GSSEAP_KRB_INIT(&krbContext); + + KRB_DATA_INIT(&t); + KRB_DATA_INIT(&ns); + + if (prf_key != GSS_C_PRF_KEY_PARTIAL && + prf_key != GSS_C_PRF_KEY_FULL) { + code = GSSEAP_BAD_PRF_KEY; + goto cleanup; + } + + code = krb5_c_prf_length(krbContext, + ctx->encryptionType, + &prflen); + if (code != 0) + goto cleanup; + + ns.length = 4 + prf_in->length; + ns.data = GSSEAP_MALLOC(ns.length); + if (ns.data == NULL) { + code = ENOMEM; + goto cleanup; + } + +#ifndef HAVE_HEIMDAL_VERSION + /* Same API, but different allocation rules, unfortunately. */ + t.length = prflen; + t.data = GSSEAP_MALLOC(t.length); + if (t.data == NULL) { + code = ENOMEM; + goto cleanup; + } +#endif + + memcpy((unsigned char *)ns.data + 4, prf_in->value, prf_in->length); + i = 0; + p = (unsigned char *)prf_out->value; + while (desired_output_len > 0) { + store_uint32_be(i, ns.data); + + code = krb5_c_prf(krbContext, &ctx->rfc3961Key, &ns, &t); + if (code != 0) + goto cleanup; + + memcpy(p, t.data, MIN(t.length, desired_output_len)); + + p += t.length; + desired_output_len -= t.length; + i++; + } + +cleanup: + if (code != 0) + gss_release_buffer(&tmpMinor, prf_out); + if (ns.data != NULL) { + memset(ns.data, 0, ns.length); + GSSEAP_FREE(ns.data); + } +#ifdef HAVE_HEIMDAL_VERSION + krb5_data_free(&t); +#else + if (t.data != NULL) { + memset(t.data, 0, t.length); + GSSEAP_FREE(t.data); + } +#endif + + *minor = code; + + return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_pseudo_random(OM_uint32 *minor, + gss_ctx_id_t ctx, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out) +{ + OM_uint32 major; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + prf_out->length = 0; + prf_out->value = NULL; + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + prf_out->value = GSSEAP_MALLOC(desired_output_len); + if (prf_out->value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + prf_out->length = desired_output_len; + + major = gssEapPseudoRandom(minor, ctx, prf_key, + prf_in, prf_out); + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/query_mechanism_info.c b/mech_eap/query_mechanism_info.c new file mode 100644 index 0000000..acd3115 --- /dev/null +++ b/mech_eap/query_mechanism_info.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * + */ + +#include "gssapiP_eap.h" + +OM_uint32 +gssQueryMechanismInfo(OM_uint32 *minor, + gss_const_OID mech_oid, + unsigned char auth_scheme[16]) +{ + OM_uint32 major; + krb5_enctype enctype; + + major = gssEapOidToEnctype(minor, (const gss_OID)mech_oid, &enctype); + if (GSS_ERROR(major)) + return major; + + /* the enctype is encoded in the increasing part of the GUID */ + memcpy(auth_scheme, + "\x39\xd7\x7d\x00\xe5\x00\x11\xe0\xac\x64\xcd\x53\x46\x50\xac\xb9", 16); + + auth_scheme[3] = (unsigned char)enctype; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_query_mechanism_info(OM_uint32 *minor, + gss_const_OID mech_oid, + unsigned char auth_scheme[16]) +{ + return gssQueryMechanismInfo(minor, mech_oid, auth_scheme); +} diff --git a/mech_eap/query_meta_data.c b/mech_eap/query_meta_data.c new file mode 100644 index 0000000..abc7e71 --- /dev/null +++ b/mech_eap/query_meta_data.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * + */ + +#include "gssapiP_eap.h" + +OM_uint32 +gssEapQueryMetaData(OM_uint32 *minor, + gss_const_OID mech GSSEAP_UNUSED, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags GSSEAP_UNUSED, + gss_buffer_t meta_data) +{ + OM_uint32 major = GSS_S_COMPLETE; + int isInitiator = (name != GSS_C_NO_NAME); + gss_ctx_id_t ctx = *context_handle; + + meta_data->length = 0; + meta_data->value = NULL; + + if (ctx == GSS_C_NO_CONTEXT) { + major = gssEapAllocContext(minor, &ctx); + if (GSS_ERROR(major)) + return major; + + if (isInitiator) + ctx->flags |= CTX_FLAG_INITIATOR; + } + + if (ctx->cred == GSS_C_NO_CREDENTIAL) { + if (isInitiator) { + major = gssEapResolveInitiatorCred(minor, cred, + name, &ctx->cred); + } else { + major = gssEapAcquireCred(minor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_ACCEPT, + &ctx->cred, + NULL, + NULL); + } + } + + if (*context_handle == GSS_C_NO_CONTEXT) + *context_handle = ctx; + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_query_meta_data(OM_uint32 *minor, + gss_const_OID mech, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags, + gss_buffer_t meta_data) +{ + gss_ctx_id_t ctx = *context_handle; + OM_uint32 major; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_LOCK(&cred->mutex); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapQueryMetaData(minor, mech, cred, &ctx, + name, req_flags, meta_data); + + if (*context_handle != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + else + *context_handle = ctx; + + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} diff --git a/mech_eap/radius_ad.exports b/mech_eap/radius_ad.exports new file mode 100644 index 0000000..8d5d5c4 --- /dev/null +++ b/mech_eap/radius_ad.exports @@ -0,0 +1 @@ +authdata_client_0 diff --git a/mech_eap/radsec.conf b/mech_eap/radsec.conf new file mode 100644 index 0000000..cd3a163 --- /dev/null +++ b/mech_eap/radsec.conf @@ -0,0 +1,10 @@ +realm gss-eap { + type = "UDP" + timeout = 5 + retries = 3 + server { + hostname = "localhost" + service = "1812" + secret = "testing123" + } +} diff --git a/mech_eap/radsec_err.et b/mech_eap/radsec_err.et new file mode 100644 index 0000000..3b7fae2 --- /dev/null +++ b/mech_eap/radsec_err.et @@ -0,0 +1,38 @@ +# +# Copyright (c) 2011, JANET(UK) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of JANET(UK) nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# Placeholders only +error_table rse + +error_code GSSEAP_RSE_OK, "" + +end diff --git a/mech_eap/release_any_name_mapping.c b/mech_eap/release_any_name_mapping.c new file mode 100644 index 0000000..d68fb45 --- /dev/null +++ b/mech_eap/release_any_name_mapping.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_release_any_name_mapping(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input) +{ + OM_uint32 major; + + *minor = 0; + + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&name->mutex); + + major = gssEapReleaseAnyNameMapping(minor, name, type_id, input); + + *input = NULL; + + GSSEAP_MUTEX_UNLOCK(&name->mutex); + + return major; +} diff --git a/mech_eap/release_cred.c b/mech_eap/release_cred.c new file mode 100644 index 0000000..8bb7e54 --- /dev/null +++ b/mech_eap/release_cred.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Release a credential handle. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_release_cred(OM_uint32 *minor, + gss_cred_id_t *cred_handle) +{ + return gssEapReleaseCred(minor, cred_handle); +} diff --git a/mech_eap/release_name.c b/mech_eap/release_name.c new file mode 100644 index 0000000..3d527ce --- /dev/null +++ b/mech_eap/release_name.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Release a name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_release_name(OM_uint32 *minor, + gss_name_t *name) +{ + return gssEapReleaseName(minor, name); +} diff --git a/mech_eap/release_oid.c b/mech_eap/release_oid.c new file mode 100644 index 0000000..291da40 --- /dev/null +++ b/mech_eap/release_oid.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Mark an internalized OID as not required to be released. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_internal_release_oid(OM_uint32 *minor, + gss_OID *oid) +{ + return gssEapReleaseOid(minor, oid); +} diff --git a/mech_eap/set_cred_option.c b/mech_eap/set_cred_option.c new file mode 100644 index 0000000..98bb482 --- /dev/null +++ b/mech_eap/set_cred_option.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Set an extended property on a credential handle. + */ + +#include "gssapiP_eap.h" + +static OM_uint32 +setCredRadiusConfigFile(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER; + + if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) { + major = duplicateBuffer(minor, buffer, &configFileBuffer); + if (GSS_ERROR(major)) + return major; + } + + gss_release_buffer(&tmpMinor, &cred->radiusConfigFile); + cred->radiusConfigFile = configFileBuffer; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +setCredRadiusConfigStanza(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER; + + if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) { + major = duplicateBuffer(minor, buffer, &configStanzaBuffer); + if (GSS_ERROR(major)) + return major; + } + + gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza); + cred->radiusConfigStanza = configStanzaBuffer; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +setCredFlag(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + OM_uint32 flags; + unsigned char *p; + + if (buffer == GSS_C_NO_BUFFER) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE; + } + + if (buffer->length < 4) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_FAILURE; + } + + p = (unsigned char *)buffer->value; + + flags = load_uint32_be(buffer->value) & CRED_FLAG_PUBLIC_MASK; + + if (buffer->length > 4 && p[4]) + cred->flags &= ~(flags); + else + cred->flags |= flags; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +setCredPassword(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + return gssEapSetCredPassword(minor, cred, buffer); +} + +static OM_uint32 +setCredPrivateKey(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + return gssEapSetCredClientCertificate(minor, cred, GSS_C_NO_BUFFER, buffer); +} + +static struct { + gss_OID_desc oid; + OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred, + const gss_OID, const gss_buffer_t); +} setCredOps[] = { + /* 1.3.6.1.4.1.5322.22.3.3.1 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x01" }, + setCredRadiusConfigFile, + }, + /* 1.3.6.1.4.1.5322.22.3.3.2 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x02" }, + setCredRadiusConfigStanza, + }, + /* 1.3.6.1.4.1.5322.22.3.3.3 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x03" }, + setCredFlag, + }, + /* 1.3.6.1.4.1.5322.22.3.3.4 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x04" }, + setCredPassword, + }, + /* 1.3.6.1.4.1.5322.22.3.3.5 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x05" }, + setCredPrivateKey, + }, +}; + +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE = &setCredOps[0].oid; +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA = &setCredOps[1].oid; +gss_OID GSS_EAP_CRED_SET_CRED_FLAG = &setCredOps[2].oid; +gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD = &setCredOps[3].oid; +gss_OID GSS_EAP_CRED_SET_CRED_PRIVATE_KEY = &setCredOps[4].oid; + +OM_uint32 GSSAPI_CALLCONV +gssspi_set_cred_option(OM_uint32 *minor, + gss_cred_id_t *pCred, + const gss_OID desired_object, + const gss_buffer_t value) +{ + OM_uint32 major; + gss_cred_id_t cred = *pCred; + int i; + + if (cred == GSS_C_NO_CREDENTIAL) { + *minor = EINVAL; + return GSS_S_UNAVAILABLE; + } + + GSSEAP_MUTEX_LOCK(&cred->mutex); + + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_BAD_CRED_OPTION; + + for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) { + if (oidEqual(&setCredOps[i].oid, desired_object)) { + major = (*setCredOps[i].setOption)(minor, cred, + desired_object, value); + break; + } + } + + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} + +#if 0 +OM_uint32 +gsseap_set_cred_flag(OM_uint32 *minor, + gss_cred_id_t cred, + OM_uint32 flag, + int clear) +{ + unsigned char buf[5]; + gss_buffer_desc value; + + value.length = sizeof(buf); + value.value = buf; + + store_uint32_be(flag, buf); + buf[4] = (clear != 0); + + return gssspi_set_cred_option(minor, &cred, + GSS_EAP_CRED_SET_CRED_FLAG, &value); +} +#endif diff --git a/mech_eap/set_name_attribute.c b/mech_eap/set_name_attribute.c new file mode 100644 index 0000000..2ccf5d7 --- /dev/null +++ b/mech_eap/set_name_attribute.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Set an attribute on a name. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_set_name_attribute(OM_uint32 *minor, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value) +{ + OM_uint32 major; + + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_MUTEX_LOCK(&name->mutex); + + major = gssEapSetNameAttribute(minor, name, complete, attr, value); + + GSSEAP_MUTEX_UNLOCK(&name->mutex); + + return major; +} diff --git a/mech_eap/set_sec_context_option.c b/mech_eap/set_sec_context_option.c new file mode 100644 index 0000000..f9fa3a6 --- /dev/null +++ b/mech_eap/set_sec_context_option.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Set an extended property on a context handle. + */ + +#include "gssapiP_eap.h" + +#if 0 +static struct { + gss_OID_desc oid; + OM_uint32 (*setOption)(OM_uint32 *, gss_ctx_id_t *pCtx, + const gss_OID, const gss_buffer_t); +} setCtxOps[] = { +}; +#endif + +OM_uint32 GSSAPI_CALLCONV +gss_set_sec_context_option(OM_uint32 *minor, + gss_ctx_id_t *pCtx, + const gss_OID desired_object GSSEAP_UNUSED, + const gss_buffer_t value GSSEAP_UNUSED) +{ + OM_uint32 major; + gss_ctx_id_t ctx; +#if 0 + int i; +#endif + + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_BAD_CONTEXT_OPTION; + + if (pCtx == NULL) + ctx = GSS_C_NO_CONTEXT; + else + ctx = *pCtx; + + if (ctx != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_LOCK(&ctx->mutex); + +#if 0 + for (i = 0; i < sizeof(setCtxOps) / sizeof(setCtxOps[0]); i++) { + if (oidEqual(&setCtxOps[i].oid, desired_object)) { + major = (*setCtxOps[i].setOption)(minor, &ctx, + desired_object, value); + break; + } + } +#endif + + if (pCtx != NULL && *pCtx == NULL) + *pCtx = ctx; + else if (ctx != GSS_C_NO_CONTEXT) + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/store_cred.c b/mech_eap/store_cred.c new file mode 100644 index 0000000..d17a3ac --- /dev/null +++ b/mech_eap/store_cred.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_store_cred(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_cred_usage_t input_usage, + const gss_OID desired_mech GSSEAP_UNUSED, +#ifdef GSSEAP_ENABLE_REAUTH + OM_uint32 overwrite_cred, + OM_uint32 default_cred, +#else + OM_uint32 overwrite_cred GSSEAP_UNUSED, + OM_uint32 default_cred GSSEAP_UNUSED, +#endif + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ + OM_uint32 major; + + if (elements_stored != NULL) + *elements_stored = GSS_C_NO_OID_SET; + if (cred_usage_stored != NULL) + *cred_usage_stored = input_usage; + + if (cred == GSS_C_NO_CREDENTIAL) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED; + } + + GSSEAP_MUTEX_LOCK(&cred->mutex); + + major = GSS_S_COMPLETE; + *minor = 0; + +#ifdef GSSEAP_ENABLE_REAUTH + if (cred->reauthCred != GSS_C_NO_CREDENTIAL) { + major = gssStoreCred(minor, + cred->reauthCred, + input_usage, + (gss_OID)gss_mech_krb5, + overwrite_cred, + default_cred, + elements_stored, + cred_usage_stored); + } +#endif + + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} diff --git a/mech_eap/unwrap.c b/mech_eap/unwrap.c new file mode 100644 index 0000000..a185035 --- /dev/null +++ b/mech_eap/unwrap.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Message protection services: unwrap. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_unwrap(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state) +{ + OM_uint32 major, tmpMinor; + gss_iov_buffer_desc iov[2]; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM; + iov[0].buffer = *input_message_buffer; + + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE; + iov[1].buffer.value = NULL; + iov[1].buffer.length = 0; + + major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state, + iov, 2, TOK_TYPE_WRAP); + if (major == GSS_S_COMPLETE) { + *output_message_buffer = iov[1].buffer; + } else { + if (iov[1].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) + gss_release_buffer(&tmpMinor, &iov[1].buffer); + } + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/unwrap_iov.c b/mech_eap/unwrap_iov.c new file mode 100644 index 0000000..39f7f1c --- /dev/null +++ b/mech_eap/unwrap_iov.c @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 2008 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Message protection services: unwrap with scatter-gather API. + */ + +#include "gssapiP_eap.h" + +/* + * Caller must provide TOKEN | DATA | PADDING | TRAILER, except + * for DCE in which case it can just provide TOKEN | DATA (must + * guarantee that DATA is padded) + */ +OM_uint32 +unwrapToken(OM_uint32 *minor, + gss_ctx_id_t ctx, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *unused GSSEAP_UNUSED, +#endif + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype) +{ + OM_uint32 major = GSS_S_FAILURE, code; + gss_iov_buffer_t header; + gss_iov_buffer_t padding; + gss_iov_buffer_t trailer; + unsigned char flags; + unsigned char *ptr = NULL; + int keyUsage; + size_t rrc, ec; + size_t dataLen, assocDataLen; + uint64_t seqnum; + int valid = 0; + int conf_flag = 0; + krb5_context krbContext; +#ifdef HAVE_HEIMDAL_VERSION + int freeCrypto = (krbCrypto == NULL); +#endif + + GSSEAP_KRB_INIT(&krbContext); + + *minor = 0; + + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + + header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + GSSEAP_ASSERT(header != NULL); + + padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL && padding->buffer.length != 0) { + code = GSSEAP_BAD_PADDING_IOV; + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + } + + trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + flags = rfc4121Flags(ctx, TRUE); + + if (toktype == TOK_TYPE_WRAP) { + keyUsage = !CTX_IS_INITIATOR(ctx) + ? KEY_USAGE_INITIATOR_SEAL + : KEY_USAGE_ACCEPTOR_SEAL; + } else { + keyUsage = !CTX_IS_INITIATOR(ctx) + ? KEY_USAGE_INITIATOR_SIGN + : KEY_USAGE_ACCEPTOR_SIGN; + } + + gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen); + + ptr = (unsigned char *)header->buffer.value; + + if (header->buffer.length < 16) { + code = GSSEAP_TOK_TRUNC; + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + } + + if ((ptr[2] & flags) != flags) { + code = GSSEAP_BAD_DIRECTION; + major = GSS_S_BAD_SIG; + goto cleanup; + } + +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto == NULL) { + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, + ETYPE_NULL, &krbCrypto); + if (code != 0) + goto cleanup; + } +#endif + + if (toktype == TOK_TYPE_WRAP) { + size_t krbTrailerLen; + + if (load_uint16_be(ptr) != TOK_TYPE_WRAP) + goto defective; + conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0); + if (ptr[3] != 0xFF) + goto defective; + ec = load_uint16_be(ptr + 4); + rrc = load_uint16_be(ptr + 6); + seqnum = load_uint64_be(ptr + 8); + + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + conf_flag ? KRB5_CRYPTO_TYPE_TRAILER : + KRB5_CRYPTO_TYPE_CHECKSUM, + &krbTrailerLen); + if (code != 0) + goto cleanup; + + /* Deal with RRC */ + if (trailer == NULL) { + size_t desired_rrc = krbTrailerLen; + + if (conf_flag) { + desired_rrc += 16; /* E(Header) */ + + if ((ctx->gssFlags & GSS_C_DCE_STYLE) == 0) + desired_rrc += ec; + } + + /* According to MS, we only need to deal with a fixed RRC for DCE */ + if (rrc != desired_rrc) + goto defective; + } else if (rrc != 0) { + goto defective; + } + + if (conf_flag) { + unsigned char *althdr; + + /* Decrypt */ + code = gssEapDecrypt(krbContext, + ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0), + ec, rrc, KRB_CRYPTO_CONTEXT(ctx), keyUsage, + iov, iov_count); + if (code != 0) { + major = GSS_S_BAD_SIG; + goto cleanup; + } + + /* Validate header integrity */ + if (trailer == NULL) + althdr = (unsigned char *)header->buffer.value + 16 + ec; + else + althdr = (unsigned char *)trailer->buffer.value + ec; + + if (load_uint16_be(althdr) != TOK_TYPE_WRAP + || althdr[2] != ptr[2] + || althdr[3] != ptr[3] + || memcmp(althdr + 8, ptr + 8, 8) != 0) { + code = GSSEAP_BAD_WRAP_TOKEN; + major = GSS_S_BAD_SIG; + goto cleanup; + } + } else { + /* Verify checksum: note EC is checksum size here, not padding */ + if (ec != krbTrailerLen) + goto defective; + + /* Zero EC, RRC before computing checksum */ + store_uint16_be(0, ptr + 4); + store_uint16_be(0, ptr + 6); + + code = gssEapVerify(krbContext, ctx->checksumType, rrc, + KRB_CRYPTO_CONTEXT(ctx), keyUsage, + iov, iov_count, &valid); + if (code != 0 || valid == FALSE) { + major = GSS_S_BAD_SIG; + goto cleanup; + } + } + + major = sequenceCheck(&code, &ctx->seqState, seqnum); + if (GSS_ERROR(major)) + goto cleanup; + } else if (toktype == TOK_TYPE_MIC) { + if (load_uint16_be(ptr) != toktype) + goto defective; + + verify_mic_1: + if (ptr[3] != 0xFF) + goto defective; + seqnum = load_uint64_be(ptr + 8); + + /* + * Although MIC tokens don't have a RRC, they are similarly + * composed of a header and a checksum. So the verify_mic() + * can be implemented with a single header buffer, fake the + * RRC to the putative trailer length if no trailer buffer. + */ + code = gssEapVerify(krbContext, ctx->checksumType, + trailer != NULL ? 0 : header->buffer.length - 16, + KRB_CRYPTO_CONTEXT(ctx), keyUsage, + iov, iov_count, &valid); + if (code != 0 || valid == FALSE) { + major = GSS_S_BAD_SIG; + goto cleanup; + } + major = sequenceCheck(&code, &ctx->seqState, seqnum); + if (GSS_ERROR(major)) + goto cleanup; + } else if (toktype == TOK_TYPE_DELETE_CONTEXT) { + if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT) + goto defective; + goto verify_mic_1; + } else { + goto defective; + } + + if (conf_state != NULL) + *conf_state = conf_flag; + + code = 0; + major = GSS_S_COMPLETE; + goto cleanup; + +defective: + code = GSSEAP_BAD_WRAP_TOKEN; + major = GSS_S_DEFECTIVE_TOKEN; + +cleanup: + *minor = code; +#ifdef HAVE_HEIMDAL_VERSION + if (freeCrypto && krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif + + return major; +} + +int +rotateLeft(void *ptr, size_t bufsiz, size_t rc) +{ + void *tbuf; + + if (bufsiz == 0) + return 0; + rc = rc % bufsiz; + if (rc == 0) + return 0; + + tbuf = GSSEAP_MALLOC(rc); + if (tbuf == NULL) + return ENOMEM; + + memcpy(tbuf, ptr, rc); + memmove(ptr, (char *)ptr + rc, bufsiz - rc); + memcpy((char *)ptr + bufsiz - rc, tbuf, rc); + GSSEAP_FREE(tbuf); + + return 0; +} + +/* + * Split a STREAM | SIGN_DATA | DATA into + * HEADER | SIGN_DATA | DATA | PADDING | TRAILER + */ +static OM_uint32 +unwrapStream(OM_uint32 *minor, + gss_ctx_id_t ctx, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype) +{ + unsigned char *ptr; + OM_uint32 code = 0, major = GSS_S_FAILURE; + krb5_context krbContext; + int conf_req_flag; + int i = 0, j; + gss_iov_buffer_desc *tiov = NULL; + gss_iov_buffer_t stream, data = NULL; + gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer; +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto = NULL; +#endif + + GSSEAP_KRB_INIT(&krbContext); + + GSSEAP_ASSERT(toktype == TOK_TYPE_WRAP); + + if (toktype != TOK_TYPE_WRAP) { + code = GSSEAP_WRONG_TOK_ID; + goto cleanup; + } + + stream = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM); + GSSEAP_ASSERT(stream != NULL); + + if (stream->buffer.length < 16) { + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + } + + ptr = (unsigned char *)stream->buffer.value; + ptr += 2; /* skip token type */ + + tiov = (gss_iov_buffer_desc *)GSSEAP_CALLOC((size_t)iov_count + 2, + sizeof(gss_iov_buffer_desc)); + if (tiov == NULL) { + code = ENOMEM; + goto cleanup; + } + + /* HEADER */ + theader = &tiov[i++]; + theader->type = GSS_IOV_BUFFER_TYPE_HEADER; + theader->buffer.value = stream->buffer.value; + theader->buffer.length = 16; + + /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */ + for (j = 0; j < iov_count; j++) { + OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type); + + if (type == GSS_IOV_BUFFER_TYPE_DATA) { + if (data != NULL) { + /* only a single DATA buffer can appear */ + code = GSSEAP_BAD_STREAM_IOV; + goto cleanup; + } + + data = &iov[j]; + tdata = &tiov[i]; + } + if (type == GSS_IOV_BUFFER_TYPE_DATA || + type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY) + tiov[i++] = iov[j]; + } + + if (data == NULL) { + /* a single DATA buffer must be present */ + code = GSSEAP_BAD_STREAM_IOV; + goto cleanup; + } + + /* PADDING | TRAILER */ + tpadding = &tiov[i++]; + tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING; + tpadding->buffer.length = 0; + tpadding->buffer.value = NULL; + + ttrailer = &tiov[i++]; + ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER; + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto); + if (code != 0) + goto cleanup; +#endif + + { + size_t ec, rrc; + size_t krbHeaderLen = 0; + size_t krbTrailerLen = 0; + + conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0); + ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0; + rrc = load_uint16_be(ptr + 4); + + if (rrc != 0) { + code = rotateLeft((unsigned char *)stream->buffer.value + 16, + stream->buffer.length - 16, rrc); + if (code != 0) + goto cleanup; + store_uint16_be(0, ptr + 4); /* set RRC to zero */ + } + + if (conf_req_flag) { + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen); + if (code != 0) + goto cleanup; + theader->buffer.length += krbHeaderLen; /* length validated later */ + } + + /* no PADDING for CFX, EC is used instead */ + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + conf_req_flag + ? KRB5_CRYPTO_TYPE_TRAILER + : KRB5_CRYPTO_TYPE_CHECKSUM, + &krbTrailerLen); + if (code != 0) + goto cleanup; + + ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) + + krbTrailerLen; + ttrailer->buffer.value = (unsigned char *)stream->buffer.value + + stream->buffer.length - ttrailer->buffer.length; + } + + /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/ + /* CFX: GSS-Header | Kerb-Header | Data | | EC | E(Header) | Kerb-Trailer */ + /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/ + + /* validate lengths */ + if (stream->buffer.length < theader->buffer.length + + tpadding->buffer.length + + ttrailer->buffer.length) { + major = GSS_S_DEFECTIVE_TOKEN; + code = GSSEAP_TOK_TRUNC; + goto cleanup; + } + + /* setup data */ + tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length - + tpadding->buffer.length - theader->buffer.length; + + GSSEAP_ASSERT(data != NULL); + + if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + code = gssEapAllocIov(tdata, tdata->buffer.length); + if (code != 0) + goto cleanup; + + memcpy(tdata->buffer.value, + (unsigned char *)stream->buffer.value + theader->buffer.length, + tdata->buffer.length); + } else { + tdata->buffer.value = (unsigned char *)stream->buffer.value + + theader->buffer.length; + } + + GSSEAP_ASSERT(i <= iov_count + 2); + + major = unwrapToken(&code, ctx, KRB_CRYPTO_CONTEXT(ctx), + conf_state, qop_state, tiov, i, toktype); + if (major == GSS_S_COMPLETE) { + *data = *tdata; + } else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) { + OM_uint32 tmp; + + gss_release_buffer(&tmp, &tdata->buffer); + tdata->type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED); + } + +cleanup: + if (tiov != NULL) + GSSEAP_FREE(tiov); +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif + + *minor = code; + + return major; +} + +OM_uint32 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype) +{ + OM_uint32 major; + + if (ctx->encryptionType == ENCTYPE_NULL) { + *minor = GSSEAP_KEY_UNAVAILABLE; + return GSS_S_UNAVAILABLE; + } + + if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) { + major = unwrapStream(minor, ctx, conf_state, qop_state, + iov, iov_count, toktype); + } else { + major = unwrapToken(minor, ctx, + NULL, /* krbCrypto */ + conf_state, qop_state, + iov, iov_count, toktype); + } + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_unwrap_iov(OM_uint32 *minor, + gss_ctx_id_t ctx, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state, + iov, iov_count, TOK_TYPE_WRAP); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/util.h b/mech_eap/util.h new file mode 100644 index 0000000..62b9f22 --- /dev/null +++ b/mech_eap/util.h @@ -0,0 +1,1117 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Portions Copyright 2003-2010 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * Utility functions. + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ 1 + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#endif +#include +#include + +#include + +#ifdef WIN32 +# ifndef __cplusplus +# define inline __inline +# endif +#define snprintf _snprintf +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIN +#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +#endif + +#if !defined(WIN32) && !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +#define GSSEAP_UNUSED __attribute__ ((__unused__)) +#else +#define GSSEAP_UNUSED +#endif + +/* util_buffer.c */ +OM_uint32 +makeStringBuffer(OM_uint32 *minor, + const char *string, + gss_buffer_t buffer); + +#define makeStringBufferOrCleanup(src, dst) \ + do { \ + major = makeStringBuffer((minor), (src), (dst));\ + if (GSS_ERROR(major)) \ + goto cleanup; \ + } while (0) + +OM_uint32 +bufferToString(OM_uint32 *minor, + const gss_buffer_t buffer, + char **pString); + +OM_uint32 +duplicateBuffer(OM_uint32 *minor, + const gss_buffer_t src, + gss_buffer_t dst); + +#define duplicateBufferOrCleanup(src, dst) \ + do { \ + major = duplicateBuffer((minor), (src), (dst)); \ + if (GSS_ERROR(major)) \ + goto cleanup; \ + } while (0) + +static inline int +bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2) +{ + return (b1->length == b2->length && + memcmp(b1->value, b2->value, b2->length) == 0); +} + +static inline int +bufferEqualString(const gss_buffer_t b1, const char *s) +{ + gss_buffer_desc b2; + + b2.length = strlen(s); + b2.value = (char *)s; + + return bufferEqual(b1, &b2); +} + +/* util_cksum.c */ +int +gssEapSign(krb5_context context, + krb5_cksumtype type, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *key, +#endif + krb5_keyusage sign_usage, + gss_iov_buffer_desc *iov, + int iov_count); + +int +gssEapVerify(krb5_context context, + krb5_cksumtype type, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *key, +#endif + krb5_keyusage sign_usage, + gss_iov_buffer_desc *iov, + int iov_count, + int *valid); + +#if 0 +OM_uint32 +gssEapEncodeGssChannelBindings(OM_uint32 *minor, + gss_channel_bindings_t chanBindings, + gss_buffer_t encodedBindings); +#endif + +/* util_context.c */ +#define EAP_EXPORT_CONTEXT_V1 1 + +enum gss_eap_token_type { + TOK_TYPE_NONE = 0x0000, /* no token */ + TOK_TYPE_MIC = 0x0404, /* RFC 4121 MIC token */ + TOK_TYPE_WRAP = 0x0504, /* RFC 4121 wrap token */ + TOK_TYPE_EXPORT_NAME = 0x0401, /* RFC 2743 exported name */ + TOK_TYPE_EXPORT_NAME_COMPOSITE = 0x0402, /* exported composite name */ + TOK_TYPE_DELETE_CONTEXT = 0x0405, /* RFC 2743 delete context */ + TOK_TYPE_INITIATOR_CONTEXT = 0x0601, /* initiator-sent context token */ + TOK_TYPE_ACCEPTOR_CONTEXT = 0x0602, /* acceptor-sent context token */ +}; + +/* inner token types and flags */ +#define ITOK_TYPE_NONE 0x00000000 +#define ITOK_TYPE_CONTEXT_ERR 0x00000001 /* critical */ +#define ITOK_TYPE_ACCEPTOR_NAME_REQ 0x00000002 /* TBD */ +#define ITOK_TYPE_ACCEPTOR_NAME_RESP 0x00000003 /* TBD */ +#define ITOK_TYPE_EAP_RESP 0x00000004 /* critical, required, if not reauth */ +#define ITOK_TYPE_EAP_REQ 0x00000005 /* critical, required, if not reauth */ +#define ITOK_TYPE_GSS_CHANNEL_BINDINGS 0x00000006 /* critical, required, if not reauth */ +#define ITOK_TYPE_REAUTH_CREDS 0x00000007 /* optional */ +#define ITOK_TYPE_REAUTH_REQ 0x00000008 /* optional */ +#define ITOK_TYPE_REAUTH_RESP 0x00000009 /* optional */ +#define ITOK_TYPE_VERSION_INFO 0x0000000A /* optional */ +#define ITOK_TYPE_VENDOR_INFO 0x0000000B /* optional */ +#define ITOK_TYPE_GSS_FLAGS 0x0000000C /* optional */ +#define ITOK_TYPE_INITIATOR_MIC 0x0000000D /* critical, required, if not reauth */ +#define ITOK_TYPE_ACCEPTOR_MIC 0x0000000E /* TBD */ + +#define ITOK_FLAG_CRITICAL 0x80000000 /* critical, wire flag */ +#define ITOK_FLAG_VERIFIED 0x40000000 /* verified, API flag */ + +#define ITOK_TYPE_MASK (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED)) + +#define GSSEAP_WIRE_FLAGS_MASK ( GSS_C_MUTUAL_FLAG | \ + GSS_C_DCE_STYLE | \ + GSS_C_IDENTIFY_FLAG | \ + GSS_C_EXTENDED_ERROR_FLAG ) + +OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx); +OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx); + +OM_uint32 +gssEapMakeToken(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t innerToken, + enum gss_eap_token_type tokenType, + gss_buffer_t outputToken); + +OM_uint32 +gssEapVerifyToken(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t inputToken, + enum gss_eap_token_type *tokenType, + gss_buffer_t innerInputToken); + +OM_uint32 +gssEapContextTime(OM_uint32 *minor, + gss_ctx_id_t context_handle, + OM_uint32 *time_rec); + +OM_uint32 +gssEapMakeTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t tokenMIC); + +OM_uint32 +gssEapVerifyTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t tokenMIC); + +/* util_cred.c */ +OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred); +OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred); + +gss_OID +gssEapPrimaryMechForCred(gss_cred_id_t cred); + +OM_uint32 +gssEapAcquireCred(OM_uint32 *minor, + const gss_name_t desiredName, + OM_uint32 timeReq, + const gss_OID_set desiredMechs, + int cred_usage, + gss_cred_id_t *pCred, + gss_OID_set *pActualMechs, + OM_uint32 *timeRec); + +OM_uint32 +gssEapSetCredPassword(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t password); + +OM_uint32 +gssEapSetCredClientCertificate(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t clientCert, + const gss_buffer_t privateKey); + +OM_uint32 +gssEapSetCredService(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_name_t target); + +OM_uint32 +gssEapResolveInitiatorCred(OM_uint32 *minor, + const gss_cred_id_t cred, + const gss_name_t target, + gss_cred_id_t *resolvedCred); + +int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech); + +OM_uint32 +gssEapInquireCred(OM_uint32 *minor, + gss_cred_id_t cred, + gss_name_t *name, + OM_uint32 *pLifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms); + +/* util_crypt.c */ +int +gssEapEncrypt(krb5_context context, int dce_style, size_t ec, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *key, +#endif + int usage, + gss_iov_buffer_desc *iov, int iov_count); + +int +gssEapDecrypt(krb5_context context, int dce_style, size_t ec, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *key, +#endif + int usage, + gss_iov_buffer_desc *iov, int iov_count); + +int +gssEapMapCryptoFlag(OM_uint32 type); + +gss_iov_buffer_t +gssEapLocateIov(gss_iov_buffer_desc *iov, + int iov_count, + OM_uint32 type); + +void +gssEapIovMessageLength(gss_iov_buffer_desc *iov, + int iov_count, + size_t *data_length, + size_t *assoc_data_length); + +void +gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count); + +int +gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count); + +int +gssEapAllocIov(gss_iov_buffer_t iov, size_t size); + +OM_uint32 +gssEapDeriveRfc3961Key(OM_uint32 *minor, + const unsigned char *key, + size_t keyLength, + krb5_enctype enctype, + krb5_keyblock *pKey); + +/* util_krb.c */ + +#ifndef KRB_MALLOC +/* + * If your Kerberos library uses a different allocator to your + * GSS mechanism glue, then you might wish to define these in + * config.h or elsewhere. This should eventually go away when + * we no longer need to allocate memory that is freed by the + * Kerberos library. + */ +#define KRB_CALLOC calloc +#define KRB_MALLOC malloc +#define KRB_FREE free +#define KRB_REALLOC realloc +#endif /* KRB_MALLOC */ + +#ifdef HAVE_HEIMDAL_VERSION + +#define KRB_TIME_FOREVER ((time_t)~0L) + +#define KRB_KEY_TYPE(key) ((key)->keytype) +#define KRB_KEY_DATA(key) ((key)->keyvalue.data) +#define KRB_KEY_LENGTH(key) ((key)->keyvalue.length) + +#define KRB_PRINC_LENGTH(princ) ((princ)->name.name_string.len) +#define KRB_PRINC_TYPE(princ) ((princ)->name.name_type) +#define KRB_PRINC_NAME(princ) ((princ)->name.name_string.val) +#define KRB_PRINC_REALM(princ) ((princ)->realm) + +#define KRB_KT_ENT_KEYBLOCK(e) (&(e)->keyblock) +#define KRB_KT_ENT_FREE(c, e) krb5_kt_free_entry((c), (e)) + +#define KRB_CRYPTO_CONTEXT(ctx) (krbCrypto) + +#define KRB_DATA_INIT(d) krb5_data_zero((d)) + +#define KRB_CHECKSUM_TYPE(c) ((c)->cksumtype) +#define KRB_CHECKSUM_LENGTH(c) ((c)->checksum.length) +#define KRB_CHECKSUM_DATA(c) ((c)->checksum.data) + +#define KRB_CHECKSUM_INIT(cksum, type, d) do { \ + (cksum)->cksumtype = (type); \ + (cksum)->checksum.length = (d)->length; \ + (cksum)->checksum.data = (d)->value; \ + } while (0) + +#else + +#define KRB_TIME_FOREVER KRB5_INT32_MAX + +#define KRB_KEY_TYPE(key) ((key)->enctype) +#define KRB_KEY_DATA(key) ((key)->contents) +#define KRB_KEY_LENGTH(key) ((key)->length) + +#define KRB_PRINC_LENGTH(princ) (krb5_princ_size(NULL, (princ))) +#define KRB_PRINC_TYPE(princ) (krb5_princ_type(NULL, (princ))) +#define KRB_PRINC_NAME(princ) (krb5_princ_name(NULL, (princ))) +#define KRB_PRINC_REALM(princ) (krb5_princ_realm(NULL, (princ))) +#define KRB_PRINC_COMPONENT(princ, component) \ + (krb5_princ_component(NULL, (princ), (component))) + +#define KRB_KT_ENT_KEYBLOCK(e) (&(e)->key) +#define KRB_KT_ENT_FREE(c, e) krb5_free_keytab_entry_contents((c), (e)) + +#define KRB_CRYPTO_CONTEXT(ctx) (&(ctx)->rfc3961Key) + +#define KRB_DATA_INIT(d) do { \ + (d)->magic = KV5M_DATA; \ + (d)->length = 0; \ + (d)->data = NULL; \ + } while (0) + +#define KRB_CHECKSUM_TYPE(c) ((c)->checksum_type) +#define KRB_CHECKSUM_LENGTH(c) ((c)->length) +#define KRB_CHECKSUM_DATA(c) ((c)->contents) + +#define KRB_CHECKSUM_INIT(cksum, type, d) do { \ + (cksum)->checksum_type = (type); \ + (cksum)->length = (d)->length; \ + (cksum)->contents = (d)->value; \ + } while (0) + +#endif /* HAVE_HEIMDAL_VERSION */ + +#define KRB_KEY_INIT(key) do { \ + KRB_KEY_TYPE(key) = ENCTYPE_NULL; \ + KRB_KEY_DATA(key) = NULL; \ + KRB_KEY_LENGTH(key) = 0; \ + } while (0) + +#define GSSEAP_KRB_INIT(ctx) do { \ + OM_uint32 tmpMajor; \ + \ + tmpMajor = gssEapKerberosInit(minor, ctx); \ + if (GSS_ERROR(tmpMajor)) { \ + return tmpMajor; \ + } \ + } while (0) + +OM_uint32 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context); + +OM_uint32 +rfc3961ChecksumTypeForKey(OM_uint32 *minor, + krb5_keyblock *key, + krb5_cksumtype *cksumtype); + +krb5_error_code +krbCryptoLength(krb5_context krbContext, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *key, +#endif + int type, + size_t *length); + +krb5_error_code +krbPaddingLength(krb5_context krbContext, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *key, +#endif + size_t dataLength, + size_t *padLength); + +krb5_error_code +krbBlockSize(krb5_context krbContext, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *key, +#endif + size_t *blockSize); + +krb5_error_code +krbEnctypeToString(krb5_context krbContext, + krb5_enctype enctype, + const char *prefix, + gss_buffer_t string); + +krb5_error_code +krbMakeAuthDataKdcIssued(krb5_context context, + const krb5_keyblock *key, + krb5_const_principal issuer, +#ifdef HAVE_HEIMDAL_VERSION + const AuthorizationData *authdata, + AuthorizationData *adKdcIssued +#else + krb5_authdata *const *authdata, + krb5_authdata ***adKdcIssued +#endif + ); + +krb5_error_code +krbMakeCred(krb5_context context, + krb5_auth_context authcontext, + krb5_creds *creds, + krb5_data *data); + +/* util_lucid.c */ +OM_uint32 +gssEapExportLucidSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_OID desiredObject, + gss_buffer_set_t *data_set); + +/* util_mech.c */ +extern gss_OID GSS_EAP_MECHANISM; + +#define OID_FLAG_NULL_VALID 0x00000001 +#define OID_FLAG_FAMILY_MECH_VALID 0x00000002 +#define OID_FLAG_MAP_NULL_TO_DEFAULT_MECH 0x00000004 +#define OID_FLAG_MAP_FAMILY_MECH_TO_NULL 0x00000008 + +OM_uint32 +gssEapCanonicalizeOid(OM_uint32 *minor, + const gss_OID oid, + OM_uint32 flags, + gss_OID *pOid); + +OM_uint32 +gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid); + +OM_uint32 +gssEapDefaultMech(OM_uint32 *minor, + gss_OID *oid); + +OM_uint32 +gssEapIndicateMechs(OM_uint32 *minor, + gss_OID_set *mechs); + +OM_uint32 +gssEapEnctypeToOid(OM_uint32 *minor, + krb5_enctype enctype, + gss_OID *pOid); + +OM_uint32 +gssEapOidToEnctype(OM_uint32 *minor, + const gss_OID oid, + krb5_enctype *enctype); + +int +gssEapIsMechanismOid(const gss_OID oid); + +int +gssEapIsConcreteMechanismOid(const gss_OID oid); + +OM_uint32 +gssEapValidateMechs(OM_uint32 *minor, + const gss_OID_set mechs); + +gss_buffer_t +gssEapOidToSaslName(const gss_OID oid); + +gss_OID +gssEapSaslNameToOid(const gss_buffer_t name); + +/* util_moonshot.c */ +OM_uint32 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_name_t *pName); + +OM_uint32 +libMoonshotResolveInitiatorCred(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_name_t targetName); + +/* util_name.c */ +#define EXPORT_NAME_FLAG_OID 0x1 +#define EXPORT_NAME_FLAG_COMPOSITE 0x2 +#define EXPORT_NAME_FLAG_ALLOW_COMPOSITE 0x4 + +OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName); +OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName); +OM_uint32 gssEapExportName(OM_uint32 *minor, + const gss_name_t name, + gss_buffer_t exportedName); +OM_uint32 gssEapExportNameInternal(OM_uint32 *minor, + const gss_name_t name, + gss_buffer_t exportedName, + OM_uint32 flags); +OM_uint32 gssEapImportName(OM_uint32 *minor, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + const gss_OID input_mech_type, + gss_name_t *output_name); +OM_uint32 gssEapImportNameInternal(OM_uint32 *minor, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name, + OM_uint32 flags); +OM_uint32 +gssEapDuplicateName(OM_uint32 *minor, + const gss_name_t input_name, + gss_name_t *dest_name); + +OM_uint32 +gssEapCanonicalizeName(OM_uint32 *minor, + const gss_name_t input_name, + const gss_OID mech_type, + gss_name_t *dest_name); + +OM_uint32 +gssEapDisplayName(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type); + +#define COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS 0x1 + +OM_uint32 +gssEapCompareName(OM_uint32 *minor, + gss_name_t name1, + gss_name_t name2, + OM_uint32 flags, + int *name_equal); + +/* util_oid.c */ +OM_uint32 +composeOid(OM_uint32 *minor_status, + const char *prefix, + size_t prefix_len, + int suffix, + gss_OID_desc *oid); + +OM_uint32 +decomposeOid(OM_uint32 *minor_status, + const char *prefix, + size_t prefix_len, + gss_OID_desc *oid, + int *suffix) ; + +OM_uint32 +duplicateOid(OM_uint32 *minor_status, + const gss_OID_desc * const oid, + gss_OID *new_oid); + +OM_uint32 +duplicateOidSet(OM_uint32 *minor, + const gss_OID_set src, + gss_OID_set *dst); + +static inline int +oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2) +{ + if (o1 == GSS_C_NO_OID) + return (o2 == GSS_C_NO_OID); + else if (o2 == GSS_C_NO_OID) + return (o1 == GSS_C_NO_OID); + else + return (o1->length == o2->length && + memcmp(o1->elements, o2->elements, o1->length) == 0); +} + +/* util_ordering.c */ +OM_uint32 +sequenceInternalize(OM_uint32 *minor, + void **vqueue, + unsigned char **buf, + size_t *lenremain); + +OM_uint32 +sequenceExternalize(OM_uint32 *minor, + void *vqueue, + unsigned char **buf, + size_t *lenremain); + +size_t +sequenceSize(void *vqueue); + +OM_uint32 +sequenceFree(OM_uint32 *minor, void **vqueue); + +OM_uint32 +sequenceCheck(OM_uint32 *minor, void **vqueue, uint64_t seqnum); + +OM_uint32 +sequenceInit(OM_uint32 *minor, void **vqueue, uint64_t seqnum, + int do_replay, int do_sequence, int wide_nums); + +/* util_sm.c */ +enum gss_eap_state { + GSSEAP_STATE_INITIAL = 0x01, /* initial state */ + GSSEAP_STATE_AUTHENTICATE = 0x02, /* exchange EAP messages */ + GSSEAP_STATE_INITIATOR_EXTS = 0x04, /* initiator extensions */ + GSSEAP_STATE_ACCEPTOR_EXTS = 0x08, /* acceptor extensions */ +#ifdef GSSEAP_ENABLE_REAUTH + GSSEAP_STATE_REAUTHENTICATE = 0x10, /* GSS reauthentication messages */ +#endif + GSSEAP_STATE_ESTABLISHED = 0x20, /* context established */ + GSSEAP_STATE_ALL = 0x3F +}; + +#define GSSEAP_STATE_NEXT(s) ((s) << 1) + +#define GSSEAP_SM_STATE(ctx) ((ctx)->state) + +#ifdef GSSEAP_DEBUG +void gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state); +#define GSSEAP_SM_TRANSITION(ctx, state) gssEapSmTransition((ctx), (state)) +#else +#define GSSEAP_SM_TRANSITION(ctx, newstate) do { (ctx)->state = (newstate); } while (0) +#endif + +#define GSSEAP_SM_TRANSITION_NEXT(ctx) GSSEAP_SM_TRANSITION((ctx), GSSEAP_STATE_NEXT(GSSEAP_SM_STATE((ctx)))) + +/* state machine entry */ +struct gss_eap_sm { + OM_uint32 inputTokenType; + OM_uint32 outputTokenType; + enum gss_eap_state validStates; + OM_uint32 itokFlags; + OM_uint32 (*processToken)(OM_uint32 *, + gss_cred_id_t, + gss_ctx_id_t, + gss_name_t, + gss_OID, + OM_uint32, + OM_uint32, + gss_channel_bindings_t, + gss_buffer_t, + gss_buffer_t, + OM_uint32 *); +}; + +/* state machine flags, set by handler */ +#define SM_FLAG_FORCE_SEND_TOKEN 0x00000001 /* send token even if no inner tokens */ +#define SM_FLAG_OUTPUT_TOKEN_CRITICAL 0x00000002 /* output token is critical */ + +/* state machine flags, set by state machine */ +#define SM_FLAG_INPUT_TOKEN_CRITICAL 0x10000000 /* input token was critical */ + +#define SM_ITOK_FLAG_REQUIRED 0x00000001 /* received tokens must be present */ + +OM_uint32 +gssEapSmStep(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech, + OM_uint32 reqFlags, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + struct gss_eap_sm *sm, + size_t smCount); + +void +gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state); + +/* util_token.c */ +struct gss_eap_token_buffer_set { + gss_buffer_set_desc buffers; /* pointers only */ + OM_uint32 *types; +}; + +OM_uint32 +gssEapEncodeInnerTokens(OM_uint32 *minor, + struct gss_eap_token_buffer_set *tokens, + gss_buffer_t buffer); +OM_uint32 +gssEapDecodeInnerTokens(OM_uint32 *minor, + const gss_buffer_t buffer, + struct gss_eap_token_buffer_set *tokens); + +OM_uint32 +gssEapReleaseInnerTokens(OM_uint32 *minor, + struct gss_eap_token_buffer_set *tokens, + int freeBuffers); + +OM_uint32 +gssEapAllocInnerTokens(OM_uint32 *minor, + size_t count, + struct gss_eap_token_buffer_set *tokens); + +size_t +tokenSize(const gss_OID_desc *mech, size_t body_size); + +void +makeTokenHeader(const gss_OID_desc *mech, + size_t body_size, + unsigned char **buf, + enum gss_eap_token_type tok_type); + +OM_uint32 +verifyTokenHeader(OM_uint32 *minor, + gss_OID mech, + size_t *body_size, + unsigned char **buf_in, + size_t toksize_in, + enum gss_eap_token_type *ret_tok_type); + +/* Helper macros */ +#ifndef GSSEAP_MALLOC +#if _WIN32 +#include +#define GSSEAP_MALLOC gssalloc_malloc +#define GSSEAP_CALLOC gssalloc_calloc +#define GSSEAP_FREE gssalloc_free +#define GSSEAP_REALLOC gssalloc_realloc +#else +#define GSSEAP_CALLOC calloc +#define GSSEAP_MALLOC malloc +#define GSSEAP_FREE free +#define GSSEAP_REALLOC realloc +#endif /* _WIN32 */ +#endif /* !GSSEAP_MALLOC */ + +#ifndef GSSAPI_CALLCONV +#define GSSAPI_CALLCONV KRB5_CALLCONV +#endif + +#ifndef GSSEAP_ASSERT +#include +#define GSSEAP_ASSERT(x) assert((x)) +#endif /* !GSSEAP_ASSERT */ + +#ifdef WIN32 +#define GSSEAP_CONSTRUCTOR +#define GSSEAP_DESTRUCTOR +#else +#define GSSEAP_CONSTRUCTOR __attribute__((constructor)) +#define GSSEAP_DESTRUCTOR __attribute__((destructor)) +#endif + +#define GSSEAP_NOT_IMPLEMENTED do { \ + GSSEAP_ASSERT(0 && "not implemented"); \ + *minor = ENOSYS; \ + return GSS_S_FAILURE; \ + } while (0) + +#ifdef WIN32 + +#include + +#define GSSEAP_GET_LAST_ERROR() (GetLastError()) /* XXX FIXME */ + +#define GSSEAP_MUTEX CRITICAL_SECTION +#define GSSEAP_MUTEX_INIT(m) (InitializeCriticalSection((m)), 0) +#define GSSEAP_MUTEX_DESTROY(m) DeleteCriticalSection((m)) +#define GSSEAP_MUTEX_LOCK(m) EnterCriticalSection((m)) +#define GSSEAP_MUTEX_UNLOCK(m) LeaveCriticalSection((m)) +#define GSSEAP_ONCE_LEAVE do { return TRUE; } while (0) + +/* Thread-local is handled separately */ + +#define GSSEAP_THREAD_ONCE INIT_ONCE +#define GSSEAP_ONCE_CALLBACK(cb) BOOL CALLBACK cb(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) +#define GSSEAP_ONCE(o, i) InitOnceExecuteOnce((o), (i), NULL, NULL) +#define GSSEAP_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT + +#else + +#include + +#define GSSEAP_GET_LAST_ERROR() (errno) + +#define GSSEAP_MUTEX pthread_mutex_t +#define GSSEAP_MUTEX_INIT(m) pthread_mutex_init((m), NULL) +#define GSSEAP_MUTEX_DESTROY(m) pthread_mutex_destroy((m)) +#define GSSEAP_MUTEX_LOCK(m) pthread_mutex_lock((m)) +#define GSSEAP_MUTEX_UNLOCK(m) pthread_mutex_unlock((m)) + +#define GSSEAP_THREAD_KEY pthread_key_t +#define GSSEAP_KEY_CREATE(k, d) pthread_key_create((k), (d)) +#define GSSEAP_GETSPECIFIC(k) pthread_getspecific((k)) +#define GSSEAP_SETSPECIFIC(k, d) pthread_setspecific((k), (d)) + +#define GSSEAP_THREAD_ONCE pthread_once_t +#define GSSEAP_ONCE_CALLBACK(cb) void cb(void) +#define GSSEAP_ONCE(o, i) pthread_once((o), (i)) +#define GSSEAP_ONCE_INITIALIZER PTHREAD_ONCE_INIT +#define GSSEAP_ONCE_LEAVE do { } while (0) + +#endif /* WIN32 */ + +/* Helper functions */ +static inline void +store_uint16_be(uint16_t val, void *vp) +{ + unsigned char *p = (unsigned char *)vp; + + p[0] = (val >> 8) & 0xff; + p[1] = (val ) & 0xff; +} + +static inline uint16_t +load_uint16_be(const void *cvp) +{ + const unsigned char *p = (const unsigned char *)cvp; + + return (p[1] | (p[0] << 8)); +} + +static inline void +store_uint32_be(uint32_t val, void *vp) +{ + unsigned char *p = (unsigned char *)vp; + + p[0] = (val >> 24) & 0xff; + p[1] = (val >> 16) & 0xff; + p[2] = (val >> 8) & 0xff; + p[3] = (val ) & 0xff; +} + +static inline uint32_t +load_uint32_be(const void *cvp) +{ + const unsigned char *p = (const unsigned char *)cvp; + + return (p[3] | (p[2] << 8) + | ((uint32_t) p[1] << 16) + | ((uint32_t) p[0] << 24)); +} + +static inline void +store_uint64_be(uint64_t val, void *vp) +{ + unsigned char *p = (unsigned char *)vp; + + p[0] = (unsigned char)((val >> 56) & 0xff); + p[1] = (unsigned char)((val >> 48) & 0xff); + p[2] = (unsigned char)((val >> 40) & 0xff); + p[3] = (unsigned char)((val >> 32) & 0xff); + p[4] = (unsigned char)((val >> 24) & 0xff); + p[5] = (unsigned char)((val >> 16) & 0xff); + p[6] = (unsigned char)((val >> 8) & 0xff); + p[7] = (unsigned char)((val ) & 0xff); +} + +static inline uint64_t +load_uint64_be(const void *cvp) +{ + const unsigned char *p = (const unsigned char *)cvp; + + return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4); +} + +static inline unsigned char * +store_buffer(gss_buffer_t buffer, void *vp, int wide_nums) +{ + unsigned char *p = (unsigned char *)vp; + + if (wide_nums) { + store_uint64_be(buffer->length, p); + p += 8; + } else { + store_uint32_be(buffer->length, p); + p += 4; + } + + if (buffer->value != NULL) { + memcpy(p, buffer->value, buffer->length); + p += buffer->length; + } + + return p; +} + +static inline unsigned char * +load_buffer(const void *cvp, size_t length, gss_buffer_t buffer) +{ + buffer->length = 0; + buffer->value = GSSEAP_MALLOC(length); + if (buffer->value == NULL) + return NULL; + buffer->length = length; + memcpy(buffer->value, cvp, length); + return (unsigned char *)cvp + length; +} + +static inline unsigned char * +store_oid(gss_OID oid, void *vp) +{ + gss_buffer_desc buf; + + if (oid != GSS_C_NO_OID) { + buf.length = oid->length; + buf.value = oid->elements; + } else { + buf.length = 0; + buf.value = NULL; + } + + return store_buffer(&buf, vp, FALSE); +} + +static inline void +krbDataToGssBuffer(krb5_data *data, gss_buffer_t buffer) +{ + buffer->value = (void *)data->data; + buffer->length = data->length; +} + +static inline void +krbPrincComponentToGssBuffer(krb5_principal krbPrinc, + int index, gss_buffer_t buffer) +{ + if (KRB_PRINC_LENGTH(krbPrinc) <= index) { + buffer->value = NULL; + buffer->length = 0; + } else { +#ifdef HAVE_HEIMDAL_VERSION + buffer->value = (void *)KRB_PRINC_NAME(krbPrinc)[index]; + buffer->length = strlen((char *)buffer->value); +#else + buffer->value = (void *)krb5_princ_component(NULL, krbPrinc, index)->data; + buffer->length = krb5_princ_component(NULL, krbPrinc, index)->length; +#endif /* HAVE_HEIMDAL_VERSION */ + } +} + +static inline krb5_error_code +krbPrincUnparseServiceSpecifics(krb5_context krbContext, krb5_principal krbPrinc, + gss_buffer_t nameBuf) +{ + krb5_error_code result = 0; + if (KRB_PRINC_LENGTH(krbPrinc) > 2) { + /* Acceptor-Service-Specific */ + krb5_principal_data ssiPrinc = *krbPrinc; + char *ssi; + + KRB_PRINC_LENGTH(&ssiPrinc) -= 2; + KRB_PRINC_NAME(&ssiPrinc) += 2; + + result = krb5_unparse_name_flags(krbContext, &ssiPrinc, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi); + if (result != 0) + return result; + + nameBuf->value = ssi; + nameBuf->length = strlen(ssi); + } else { + nameBuf->value = NULL; + nameBuf->length = 0; + } + + return result; +} + +static inline void +krbFreeUnparsedName(krb5_context krbContext, gss_buffer_t nameBuf) +{ +#ifdef HAVE_HEIMDAL_VERSION + krb5_xfree((char *) nameBuf->value); +#else + krb5_free_unparsed_name(krbContext, (char *)(nameBuf->value)); +#endif + nameBuf->value = NULL; + nameBuf->length = 0; +} + +static inline void +krbPrincRealmToGssBuffer(krb5_principal krbPrinc, gss_buffer_t buffer) +{ +#ifdef HAVE_HEIMDAL_VERSION + buffer->value = (void *)KRB_PRINC_REALM(krbPrinc); + buffer->length = strlen((char *)buffer->value); +#else + krbDataToGssBuffer(KRB_PRINC_REALM(krbPrinc), buffer); +#endif +} + +static inline void +gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data) +{ + data->data = (char *)buffer->value; + data->length = buffer->length; +} + +/* util_tld.c */ +struct gss_eap_status_info; + +struct gss_eap_thread_local_data { + krb5_context krbContext; + struct gss_eap_status_info *statusInfo; +}; + +struct gss_eap_thread_local_data * +gssEapGetThreadLocalData(void); + +void +gssEapDestroyStatusInfo(struct gss_eap_status_info *status); + +void +gssEapDestroyKrbContext(krb5_context context); + +#ifdef __cplusplus +} +#endif + +#ifdef GSSEAP_ENABLE_ACCEPTOR +#include "util_json.h" +#include "util_attr.h" +#include "util_base64.h" +#endif /* GSSEAP_ENABLE_ACCEPTOR */ +#ifdef GSSEAP_ENABLE_REAUTH +#include "util_reauth.h" +#endif + +#endif /* _UTIL_H_ */ diff --git a/mech_eap/util_adshim.c b/mech_eap/util_adshim.c new file mode 100644 index 0000000..0dabd55 --- /dev/null +++ b/mech_eap/util_adshim.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" +#include "authdata_plugin.h" + +/* + * This rubbish is necessary because MIT doesn't provide another way + * to access verified AD-KDCIssued elements. We can't verify them + * ourselves because they're signed in the ticket session key, which + * is destroyed immediately after the AP-REQ is processed. + */ + +struct radius_ad_context { + krb5_data avpdata; + krb5_boolean verified; +}; + +static krb5_data radius_ad_attr = { + KV5M_DATA, sizeof("urn:authdata-aaa-radius") - 1, "urn:authdata-aaa-radius" }; + +static krb5_error_code +radius_ad_init(krb5_context kcontext GSSEAP_UNUSED, + void **plugin_context) +{ + *plugin_context = 0; + return 0; +} + +static void +radius_ad_flags(krb5_context kcontext GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED, + krb5_authdatatype ad_type GSSEAP_UNUSED, + krb5_flags *flags) +{ + *flags = AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL; +} + +static void +radius_ad_fini(krb5_context kcontext GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED) +{ + return; +} + +static krb5_error_code +radius_ad_request_init(krb5_context kcontext GSSEAP_UNUSED, + struct _krb5_authdata_context *context GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED, + void **request_context) +{ + struct radius_ad_context *ctx; + + ctx = GSSEAP_CALLOC(1, sizeof(*ctx)); + if (ctx == NULL) + return ENOMEM; + + *request_context = ctx; + + return 0; +} + +static krb5_error_code +radius_ad_export_authdata(krb5_context kcontext, + struct _krb5_authdata_context *context GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED, + void *request_context, + krb5_flags usage GSSEAP_UNUSED, + krb5_authdata ***out_authdata) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + krb5_authdata *data[2]; + krb5_authdata datum; + + datum.ad_type = KRB5_AUTHDATA_RADIUS_AVP; + datum.length = radius_ad->avpdata.length; + datum.contents = (krb5_octet *)radius_ad->avpdata.data; + + data[0] = &datum; + data[1] = NULL; + + return krb5_copy_authdata(kcontext, data, out_authdata); +} + +static krb5_error_code +radius_ad_import_authdata(krb5_context kcontext, + struct _krb5_authdata_context *context GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued_flag, + krb5_const_principal issuer GSSEAP_UNUSED) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + + krb5_free_data_contents(kcontext, &radius_ad->avpdata); + radius_ad->verified = FALSE; + + GSSEAP_ASSERT(authdata[0] != NULL); + + radius_ad->avpdata.data = GSSEAP_MALLOC(authdata[0]->length); + if (radius_ad->avpdata.data == NULL) + return ENOMEM; + + memcpy(radius_ad->avpdata.data, authdata[0]->contents, + authdata[0]->length); + radius_ad->avpdata.length = authdata[0]->length; + + radius_ad->verified = kdc_issued_flag; + + return 0; +} + +static void +radius_ad_request_fini(krb5_context kcontext, + struct _krb5_authdata_context *context GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED, + void *request_context) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + + if (radius_ad != NULL) { + krb5_free_data_contents(kcontext, &radius_ad->avpdata); + GSSEAP_FREE(radius_ad); + } +} + +static krb5_error_code +radius_ad_get_attribute(krb5_context kcontext GSSEAP_UNUSED, + struct _krb5_authdata_context *context GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value GSSEAP_UNUSED, + int *more) +{ + struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context; + + if (attribute->length != radius_ad_attr.length || + memcmp(attribute->data, radius_ad_attr.data, + radius_ad_attr.length) != 0) + return ENOENT; + + if (radius_ad->avpdata.length == 0) + return ENOENT; + + *authenticated = radius_ad->verified; + *complete = TRUE; + *more = 0; + + value->data = GSSEAP_MALLOC(radius_ad->avpdata.length); + if (value->data == NULL) + return ENOMEM; + + memcpy(value->data, radius_ad->avpdata.data, radius_ad->avpdata.length); + value->length = radius_ad->avpdata.length; + + return 0; +} + +static krb5_error_code +radius_ad_copy(krb5_context kcontext GSSEAP_UNUSED, + struct _krb5_authdata_context *context GSSEAP_UNUSED, + void *plugin_context GSSEAP_UNUSED, + void *request_context, + void *dst_plugin_context GSSEAP_UNUSED, + void *dst_request_context) +{ + struct radius_ad_context *radius_ad_src = + (struct radius_ad_context *)request_context; + struct radius_ad_context *radius_ad_dst = + (struct radius_ad_context *)dst_request_context; + + radius_ad_dst->avpdata.data = GSSEAP_MALLOC(radius_ad_src->avpdata.length); + if (radius_ad_dst->avpdata.data == NULL) + return ENOMEM; + + memcpy(radius_ad_dst->avpdata.data, radius_ad_src->avpdata.data, + radius_ad_src->avpdata.length); + radius_ad_dst->avpdata.length = radius_ad_src->avpdata.length; + radius_ad_dst->verified = radius_ad_src->verified; + + return 0; +} + +static krb5_authdatatype radius_ad_ad_types[] = + { KRB5_AUTHDATA_RADIUS_AVP, 0 }; + +krb5plugin_authdata_client_ftable_v0 authdata_client_0 = { + "radius_ad", + radius_ad_ad_types, + radius_ad_init, + radius_ad_fini, + radius_ad_flags, + radius_ad_request_init, + radius_ad_request_fini, + NULL, + radius_ad_get_attribute, + NULL, + NULL, + radius_ad_export_authdata, + radius_ad_import_authdata, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + radius_ad_copy +}; diff --git a/mech_eap/util_attr.cpp b/mech_eap/util_attr.cpp new file mode 100644 index 0000000..6058f36 --- /dev/null +++ b/mech_eap/util_attr.cpp @@ -0,0 +1,1196 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Attribute provider mechanism. + */ + +#include "gssapiP_eap.h" + +#include +#include +#include +#include +#include + +/* lazy initialisation */ +static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER; +static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE; + +GSSEAP_ONCE_CALLBACK(gssEapAttrProvidersInitInternal) +{ + OM_uint32 major, minor; + + GSSEAP_ASSERT(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE); + + json_set_alloc_funcs(GSSEAP_MALLOC, GSSEAP_FREE); + + major = gssEapRadiusAttrProviderInit(&minor); + if (GSS_ERROR(major)) + goto cleanup; + + +#ifdef HAVE_SHIBRESOLVER + /* Allow Shibboleth initialization failure to be non-fatal */ + gssEapLocalAttrProviderInit(&minor); +#endif +#ifdef HAVE_OPENSAML + major = gssEapSamlAttrProvidersInit(&minor); + if (GSS_ERROR(major)) + goto cleanup; +#endif + +cleanup: +#ifdef GSSEAP_DEBUG + GSSEAP_ASSERT(major == GSS_S_COMPLETE); +#endif + + gssEapAttrProvidersInitStatus = major; + + GSSEAP_ONCE_LEAVE; +} + +static OM_uint32 +gssEapAttrProvidersInit(OM_uint32 *minor) +{ + GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal); + + if (GSS_ERROR(gssEapAttrProvidersInitStatus)) + *minor = GSSEAP_NO_ATTR_PROVIDERS; + + return gssEapAttrProvidersInitStatus; +} + +namespace { + class finalize_class { + public: + ~finalize_class() + { + OM_uint32 minor = 0; + if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) { +#ifdef HAVE_SHIBRESOLVER + gssEapLocalAttrProviderFinalize(&minor); +#endif +#ifdef HAVE_OPENSAML + gssEapSamlAttrProvidersFinalize(&minor); +#endif + gssEapRadiusAttrProviderFinalize(&minor); + + gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE; + } + } + } finalizer; +} + + + +static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1]; + +/* + * Register a provider for a particular type and prefix + */ +void +gss_eap_attr_ctx::registerProvider(unsigned int type, + gss_eap_attr_create_provider factory) +{ + GSSEAP_ASSERT(type <= ATTR_TYPE_MAX); + + GSSEAP_ASSERT(gssEapAttrFactories[type] == NULL); + + gssEapAttrFactories[type] = factory; +} + +/* + * Unregister a provider + */ +void +gss_eap_attr_ctx::unregisterProvider(unsigned int type) +{ + GSSEAP_ASSERT(type <= ATTR_TYPE_MAX); + + gssEapAttrFactories[type] = NULL; +} + +/* + * Create an attribute context, that manages instances of providers + */ +gss_eap_attr_ctx::gss_eap_attr_ctx(void) +{ + m_flags = 0; + + for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider; + + if (gssEapAttrFactories[i] != NULL) { + provider = (gssEapAttrFactories[i])(); + } else { + provider = NULL; + } + + m_providers[i] = provider; + } +} + +/* + * Convert an attribute prefix to a type + */ +unsigned int +gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix) const +{ + unsigned int i; + + for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) { + const char *pprefix; + + if (!providerEnabled(i)) + continue; + + pprefix = m_providers[i]->prefix(); + if (pprefix == NULL) + continue; + + if (strlen(pprefix) == prefix->length && + memcmp(pprefix, prefix->value, prefix->length) == 0) + return i; + } + + return ATTR_TYPE_LOCAL; +} + +/* + * Convert a type to an attribute prefix + */ +gss_buffer_desc +gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const +{ + gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER; + + if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX) + return prefix; + + if (!providerEnabled(type)) + return prefix; + + prefix.value = (void *)m_providers[type]->prefix(); + if (prefix.value != NULL) + prefix.length = strlen((char *)prefix.value); + + return prefix; +} + +bool +gss_eap_attr_ctx::providerEnabled(unsigned int type) const +{ + if (type == ATTR_TYPE_LOCAL && + (m_flags & ATTR_FLAG_DISABLE_LOCAL)) + return false; + + if (m_providers[type] == NULL) + return false; + + return true; +} + +void +gss_eap_attr_ctx::releaseProvider(unsigned int type) +{ + delete m_providers[type]; + m_providers[type] = NULL; +} + +/* + * Initialize a context from an existing context. + */ +bool +gss_eap_attr_ctx::initWithExistingContext(const gss_eap_attr_ctx *manager) +{ + bool ret = true; + + m_flags = manager->m_flags; + + for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider; + + if (!providerEnabled(i)) { + releaseProvider(i); + continue; + } + + provider = m_providers[i]; + + ret = provider->initWithExistingContext(this, + manager->m_providers[i]); + if (ret == false) { + releaseProvider(i); + break; + } + } + + return ret; +} + +/* + * Initialize a context from a GSS credential and context. + */ +bool +gss_eap_attr_ctx::initWithGssContext(const gss_cred_id_t cred, + const gss_ctx_id_t ctx) +{ + bool ret = true; + + if (cred != GSS_C_NO_CREDENTIAL && + (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) { + m_flags |= ATTR_FLAG_DISABLE_LOCAL; + } + + for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider; + + if (!providerEnabled(i)) { + releaseProvider(i); + continue; + } + + provider = m_providers[i]; + + ret = provider->initWithGssContext(this, cred, ctx); + if (ret == false) { + releaseProvider(i); + break; + } + } + + return ret; +} + +bool +gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj) +{ + bool ret = false; + bool foundSource[ATTR_TYPE_MAX + 1]; + unsigned int type; + + for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) + foundSource[type] = false; + + if (obj["version"].integer() != 1) + return false; + + m_flags = obj["flags"].integer(); + + JSONObject sources = obj["sources"]; + + /* Initialize providers from serialized state */ + for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) { + gss_eap_attr_provider *provider; + const char *key; + + if (!providerEnabled(type)) { + releaseProvider(type); + continue; + } + + provider = m_providers[type]; + key = provider->name(); + if (key == NULL) + continue; + + JSONObject source = sources.get(key); + if (!source.isNull() && + !provider->initWithJsonObject(this, source)) { + releaseProvider(type); + return false; + } + + foundSource[type] = true; + } + + /* Initialize remaining providers from initialized providers */ + for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) { + gss_eap_attr_provider *provider; + + if (foundSource[type] || !providerEnabled(type)) + continue; + + provider = m_providers[type]; + + ret = provider->initWithGssContext(this, + GSS_C_NO_CREDENTIAL, + GSS_C_NO_CONTEXT); + if (ret == false) { + releaseProvider(type); + return false; + } + } + + return true; +} + +JSONObject +gss_eap_attr_ctx::jsonRepresentation(void) const +{ + JSONObject obj, sources; + unsigned int i; + + obj.set("version", 1); + obj.set("flags", m_flags); + + for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider; + const char *key; + + provider = m_providers[i]; + if (provider == NULL) + continue; /* provider not initialised */ + + key = provider->name(); + if (key == NULL) + continue; /* provider does not have state */ + + JSONObject source = provider->jsonRepresentation(); + sources.set(key, source); + } + + obj.set("sources", sources); + + return obj; +} + +/* + * Initialize a context from an exported context or name token + */ +bool +gss_eap_attr_ctx::initWithBuffer(const gss_buffer_t buffer) +{ + OM_uint32 major, minor; + bool ret; + char *s; + json_error_t error; + + major = bufferToString(&minor, buffer, &s); + if (GSS_ERROR(major)) + return false; + + JSONObject obj = JSONObject::load(s, 0, &error); + if (!obj.isNull()) { + ret = initWithJsonObject(obj); + } else + ret = false; + + GSSEAP_FREE(s); + + return ret; +} + +gss_eap_attr_ctx::~gss_eap_attr_ctx(void) +{ + for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) + delete m_providers[i]; +} + +/* + * Locate provider for a given type + */ +gss_eap_attr_provider * +gss_eap_attr_ctx::getProvider(unsigned int type) const +{ + GSSEAP_ASSERT(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX); + return m_providers[type]; +} + +/* + * Get primary provider. Only the primary provider is serialised when + * gss_export_sec_context() or gss_export_name_composite() is called. + */ +gss_eap_attr_provider * +gss_eap_attr_ctx::getPrimaryProvider(void) const +{ + return m_providers[ATTR_TYPE_MIN]; +} + +/* + * Set an attribute + */ +bool +gss_eap_attr_ctx::setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value) +{ + gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER; + unsigned int type; + gss_eap_attr_provider *provider; + bool ret = false; + + decomposeAttributeName(attr, &type, &suffix); + + provider = m_providers[type]; + if (provider != NULL) { + ret = provider->setAttribute(complete, + (type == ATTR_TYPE_LOCAL) ? attr : &suffix, + value); + } + + return ret; +} + +/* + * Delete an attrbiute + */ +bool +gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr) +{ + gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER; + unsigned int type; + gss_eap_attr_provider *provider; + bool ret = false; + + decomposeAttributeName(attr, &type, &suffix); + + provider = m_providers[type]; + if (provider != NULL) { + ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix); + } + + return ret; +} + +/* + * Enumerate attribute types with callback + */ +bool +gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const +{ + bool ret = false; + size_t i; + + for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider = m_providers[i]; + + if (provider == NULL) + continue; + + ret = provider->getAttributeTypes(cb, data); + if (ret == false) + break; + } + + return ret; +} + +struct eap_gss_get_attr_types_args { + unsigned int type; + gss_buffer_set_t attrs; +}; + +static bool +addAttribute(const gss_eap_attr_ctx *manager, + const gss_eap_attr_provider *provider GSSEAP_UNUSED, + const gss_buffer_t attribute, + void *data) +{ + eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data; + gss_buffer_desc qualified; + OM_uint32 major, minor; + + if (args->type != ATTR_TYPE_LOCAL) { + manager->composeAttributeName(args->type, attribute, &qualified); + major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs); + gss_release_buffer(&minor, &qualified); + } else { + major = gss_add_buffer_set_member(&minor, attribute, &args->attrs); + } + + return GSS_ERROR(major) == false; +} + +/* + * Enumerate attribute types, output is buffer set + */ +bool +gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs) +{ + eap_gss_get_attr_types_args args; + OM_uint32 major, minor; + bool ret = false; + unsigned int i; + + major = gss_create_empty_buffer_set(&minor, attrs); + if (GSS_ERROR(major)) + throw std::bad_alloc(); + + args.attrs = *attrs; + + for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider = m_providers[i]; + + args.type = i; + + if (provider == NULL) + continue; + + ret = provider->getAttributeTypes(addAttribute, (void *)&args); + if (ret == false) + break; + } + + if (ret == false) + gss_release_buffer_set(&minor, attrs); + + return ret; +} + +/* + * Get attribute with given name + */ +bool +gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const +{ + gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER; + unsigned int type; + gss_eap_attr_provider *provider; + bool ret; + + decomposeAttributeName(attr, &type, &suffix); + + provider = m_providers[type]; + if (provider == NULL) + return false; + + ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix, + authenticated, complete, + value, display_value, more); + + return ret; +} + +/* + * Map attribute context to C++ object + */ +gss_any_t +gss_eap_attr_ctx::mapToAny(int authenticated, + gss_buffer_t type_id) const +{ + unsigned int type; + gss_eap_attr_provider *provider; + gss_buffer_desc suffix; + + decomposeAttributeName(type_id, &type, &suffix); + + provider = m_providers[type]; + if (provider == NULL) + return (gss_any_t)NULL; + + return provider->mapToAny(authenticated, &suffix); +} + +/* + * Release mapped context + */ +void +gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id, + gss_any_t input) const +{ + unsigned int type; + gss_eap_attr_provider *provider; + gss_buffer_desc suffix; + + decomposeAttributeName(type_id, &type, &suffix); + + provider = m_providers[type]; + if (provider != NULL) + provider->releaseAnyNameMapping(&suffix, input); +} + +/* + * Export attribute context to buffer + */ +void +gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const +{ + OM_uint32 minor; + char *s; + + JSONObject obj = jsonRepresentation(); + +#if 0 + obj.dump(stdout); +#endif + + s = obj.dump(JSON_COMPACT); + + if (GSS_ERROR(makeStringBuffer(&minor, s, buffer))) + throw std::bad_alloc(); +} + +/* + * Return soonest expiry time of providers + */ +time_t +gss_eap_attr_ctx::getExpiryTime(void) const +{ + unsigned int i; + time_t expiryTime = 0; + + for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider = m_providers[i]; + time_t providerExpiryTime; + + if (provider == NULL) + continue; + + providerExpiryTime = provider->getExpiryTime(); + if (providerExpiryTime == 0) + continue; + + if (expiryTime == 0 || providerExpiryTime < expiryTime) + expiryTime = providerExpiryTime; + } + + return expiryTime; +} + +OM_uint32 +gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const +{ + unsigned int i; + OM_uint32 major; + + /* Errors we handle ourselves */ + if (typeid(e) == typeid(std::bad_alloc)) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } else if (typeid(e) == typeid(JSONException)) { + major = GSS_S_BAD_NAME; + *minor = GSSEAP_BAD_ATTR_TOKEN; + gssEapSaveStatusInfo(*minor, "%s", e.what()); + goto cleanup; + } + + /* Errors we delegate to providers */ + major = GSS_S_CONTINUE_NEEDED; + + for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) { + gss_eap_attr_provider *provider = m_providers[i]; + + if (provider == NULL) + continue; + + major = provider->mapException(minor, e); + if (major != GSS_S_CONTINUE_NEEDED) + break; + } + + if (major == GSS_S_CONTINUE_NEEDED) { + *minor = GSSEAP_ATTR_CONTEXT_FAILURE; + major = GSS_S_FAILURE; + } + +cleanup: + GSSEAP_ASSERT(GSS_ERROR(major)); + + return major; +} + +/* + * Decompose attribute name into prefix and suffix + */ +void +gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute, + gss_buffer_t prefix, + gss_buffer_t suffix) +{ + char *p = NULL; + size_t i; + + for (i = 0; i < attribute->length; i++) { + if (((char *)attribute->value)[i] == ' ') { + p = (char *)attribute->value + i + 1; + break; + } + } + + prefix->value = attribute->value; + prefix->length = i; + + if (p != NULL && *p != '\0') { + suffix->length = attribute->length - 1 - prefix->length; + suffix->value = p; + } else { + suffix->length = 0; + suffix->value = NULL; + } +} + +/* + * Decompose attribute name into type and suffix + */ +void +gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute, + unsigned int *type, + gss_buffer_t suffix) const +{ + gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER; + + decomposeAttributeName(attribute, &prefix, suffix); + *type = attributePrefixToType(&prefix); +} + +/* + * Compose attribute name from prefix, suffix; returns C++ string + */ +std::string +gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix, + const gss_buffer_t suffix) +{ + std::string str; + + if (prefix == GSS_C_NO_BUFFER || prefix->length == 0) + return str; + + str.append((const char *)prefix->value, prefix->length); + + if (suffix != GSS_C_NO_BUFFER) { + str.append(" "); + str.append((const char *)suffix->value, suffix->length); + } + + return str; +} + +/* + * Compose attribute name from type, suffix; returns C++ string + */ +std::string +gss_eap_attr_ctx::composeAttributeName(unsigned int type, + const gss_buffer_t suffix) +{ + gss_buffer_desc prefix = attributeTypeToPrefix(type); + + return composeAttributeName(&prefix, suffix); +} + +/* + * Compose attribute name from prefix, suffix; returns GSS buffer + */ +void +gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix, + const gss_buffer_t suffix, + gss_buffer_t attribute) +{ + std::string str = composeAttributeName(prefix, suffix); + + if (str.length() != 0) { + return duplicateBuffer(str, attribute); + } else { + attribute->length = 0; + attribute->value = NULL; + } +} + +/* + * Compose attribute name from type, suffix; returns GSS buffer + */ +void +gss_eap_attr_ctx::composeAttributeName(unsigned int type, + const gss_buffer_t suffix, + gss_buffer_t attribute) const +{ + gss_buffer_desc prefix = attributeTypeToPrefix(type); + + return composeAttributeName(&prefix, suffix, attribute); +} + +/* + * C wrappers + */ +OM_uint32 +gssEapInquireName(OM_uint32 *minor, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + OM_uint32 major; + + if (name_is_MN != NULL) + *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID); + + if (MN_mech != NULL) { + major = gssEapCanonicalizeOid(minor, name->mechanismUsed, + OID_FLAG_NULL_VALID, MN_mech); + if (GSS_ERROR(major)) + return major; + } + + if (name->attrCtx == NULL) { + *minor = GSSEAP_NO_ATTR_CONTEXT; + return GSS_S_UNAVAILABLE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) { + return GSS_S_UNAVAILABLE; + } + + try { + if (!name->attrCtx->getAttributeTypes(attrs)) { + *minor = GSSEAP_NO_ATTR_CONTEXT; + return GSS_S_UNAVAILABLE; + } + } catch (std::exception &e) { + return name->attrCtx->mapException(minor, e); + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapGetNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + if (authenticated != NULL) + *authenticated = 0; + if (complete != NULL) + *complete = 0; + + if (value != NULL) { + value->length = 0; + value->value = NULL; + } + + if (display_value != NULL) { + display_value->length = 0; + display_value->value = NULL; + } + + if (name->attrCtx == NULL) { + *minor = GSSEAP_NO_ATTR_CONTEXT; + return GSS_S_UNAVAILABLE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) { + return GSS_S_UNAVAILABLE; + } + + try { + if (!name->attrCtx->getAttribute(attr, authenticated, complete, + value, display_value, more)) { + *minor = GSSEAP_NO_SUCH_ATTR; + gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s", + (int)attr->length, (char *)attr->value); + return GSS_S_UNAVAILABLE; + } + } catch (std::exception &e) { + return name->attrCtx->mapException(minor, e); + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapDeleteNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr) +{ + if (name->attrCtx == NULL) { + *minor = GSSEAP_NO_ATTR_CONTEXT; + return GSS_S_UNAVAILABLE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) + return GSS_S_UNAVAILABLE; + + try { + if (!name->attrCtx->deleteAttribute(attr)) { + *minor = GSSEAP_NO_SUCH_ATTR; + gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s", + (int)attr->length, (char *)attr->value); + return GSS_S_UNAVAILABLE; + } + } catch (std::exception &e) { + return name->attrCtx->mapException(minor, e); + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapSetNameAttribute(OM_uint32 *minor, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value) +{ + if (name->attrCtx == NULL) { + *minor = GSSEAP_NO_ATTR_CONTEXT; + return GSS_S_UNAVAILABLE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) + return GSS_S_UNAVAILABLE; + + try { + if (!name->attrCtx->setAttribute(complete, attr, value)) { + *minor = GSSEAP_NO_SUCH_ATTR; + gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s", + (int)attr->length, (char *)attr->value); + return GSS_S_UNAVAILABLE; + } + } catch (std::exception &e) { + return name->attrCtx->mapException(minor, e); + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapExportAttrContext(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t buffer) +{ + if (name->attrCtx == NULL) { + buffer->length = 0; + buffer->value = NULL; + + return GSS_S_COMPLETE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) + return GSS_S_UNAVAILABLE; + + try { + name->attrCtx->exportToBuffer(buffer); + } catch (std::exception &e) { + return name->attrCtx->mapException(minor, e); + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapImportAttrContext(OM_uint32 *minor, + gss_buffer_t buffer, + gss_name_t name) +{ + gss_eap_attr_ctx *ctx = NULL; + OM_uint32 major = GSS_S_FAILURE; + + GSSEAP_ASSERT(name->attrCtx == NULL); + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) + return GSS_S_UNAVAILABLE; + + if (buffer->length == 0) + return GSS_S_COMPLETE; + + try { + ctx = new gss_eap_attr_ctx(); + + if (ctx->initWithBuffer(buffer)) { + name->attrCtx = ctx; + major = GSS_S_COMPLETE; + *minor = 0; + } else { + major = GSS_S_BAD_NAME; + *minor = GSSEAP_ATTR_CONTEXT_FAILURE; + } + } catch (std::exception &e) { + if (ctx != NULL) + major = ctx->mapException(minor, e); + } + + GSSEAP_ASSERT(major == GSS_S_COMPLETE || name->attrCtx == NULL); + + if (GSS_ERROR(major)) + delete ctx; + + return major; +} + +OM_uint32 +gssEapDuplicateAttrContext(OM_uint32 *minor, + gss_name_t in, + gss_name_t out) +{ + gss_eap_attr_ctx *ctx = NULL; + OM_uint32 major = GSS_S_FAILURE; + + GSSEAP_ASSERT(out->attrCtx == NULL); + + if (in->attrCtx == NULL) { + *minor = 0; + return GSS_S_COMPLETE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) + return GSS_S_UNAVAILABLE; + + try { + ctx = new gss_eap_attr_ctx(); + + if (ctx->initWithExistingContext(in->attrCtx)) { + out->attrCtx = ctx; + major = GSS_S_COMPLETE; + *minor = 0; + } else { + major = GSS_S_FAILURE; + *minor = GSSEAP_ATTR_CONTEXT_FAILURE; + } + } catch (std::exception &e) { + major = in->attrCtx->mapException(minor, e); + } + + GSSEAP_ASSERT(major == GSS_S_COMPLETE || out->attrCtx == NULL); + + if (GSS_ERROR(major)) + delete ctx; + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapMapNameToAny(OM_uint32 *minor, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output) +{ + if (name->attrCtx == NULL) { + *minor = GSSEAP_NO_ATTR_CONTEXT; + return GSS_S_UNAVAILABLE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) + return GSS_S_UNAVAILABLE; + + try { + *output = name->attrCtx->mapToAny(authenticated, type_id); + } catch (std::exception &e) { + return name->attrCtx->mapException(minor, e); + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapReleaseAnyNameMapping(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input) +{ + if (name->attrCtx == NULL) { + *minor = GSSEAP_NO_ATTR_CONTEXT; + return GSS_S_UNAVAILABLE; + } + + if (GSS_ERROR(gssEapAttrProvidersInit(minor))) + return GSS_S_UNAVAILABLE; + + try { + if (*input != NULL) + name->attrCtx->releaseAnyNameMapping(type_id, *input); + *input = NULL; + } catch (std::exception &e) { + return name->attrCtx->mapException(minor, e); + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapReleaseAttrContext(OM_uint32 *minor, + gss_name_t name) +{ + if (name->attrCtx != NULL) + delete name->attrCtx; + + *minor = 0; + return GSS_S_COMPLETE; +} + +/* + * Public accessor for initialisng a context from a GSS context. Also + * sets expiry time on GSS context as a side-effect. + */ +OM_uint32 +gssEapCreateAttrContext(OM_uint32 *minor, + gss_cred_id_t gssCred, + gss_ctx_id_t gssCtx, + struct gss_eap_attr_ctx **pAttrContext, + time_t *pExpiryTime) +{ + gss_eap_attr_ctx *ctx = NULL; + OM_uint32 major; + + GSSEAP_ASSERT(gssCtx != GSS_C_NO_CONTEXT); + + *pAttrContext = NULL; + + major = gssEapAttrProvidersInit(minor); + if (GSS_ERROR(major)) + return major; + + try { + /* Set *pAttrContext here to for reentrancy */ + *pAttrContext = ctx = new gss_eap_attr_ctx(); + + if (ctx->initWithGssContext(gssCred, gssCtx)) { + *pExpiryTime = ctx->getExpiryTime(); + major = GSS_S_COMPLETE; + *minor = 0; + } else { + major = GSS_S_FAILURE; + *minor = GSSEAP_ATTR_CONTEXT_FAILURE; + } + } catch (std::exception &e) { + if (ctx != NULL) + major = ctx->mapException(minor, e); + } + + if (GSS_ERROR(major)) { + delete ctx; + *pAttrContext = NULL; + } + + return major; +} diff --git a/mech_eap/util_attr.h b/mech_eap/util_attr.h new file mode 100644 index 0000000..28067a9 --- /dev/null +++ b/mech_eap/util_attr.h @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Attribute provider interface. + */ + +#ifndef _UTIL_ATTR_H_ +#define _UTIL_ATTR_H_ 1 + +#ifdef __cplusplus +#include +#include + +using namespace gss_eap_util; + +struct gss_eap_attr_provider; +struct gss_eap_attr_ctx; + +typedef bool +(*gss_eap_attr_enumeration_cb)(const gss_eap_attr_ctx *ctx, + const gss_eap_attr_provider *source, + const gss_buffer_t attribute, + void *data); + +#define ATTR_TYPE_RADIUS 0U /* RADIUS AVPs */ +#ifdef HAVE_OPENSAML +#define ATTR_TYPE_SAML_ASSERTION 1U /* SAML assertion */ +#define ATTR_TYPE_SAML 2U /* SAML attributes */ +#endif +#define ATTR_TYPE_LOCAL 3U /* Local attributes */ +#define ATTR_TYPE_MIN ATTR_TYPE_RADIUS +#define ATTR_TYPE_MAX ATTR_TYPE_LOCAL + +#define ATTR_FLAG_DISABLE_LOCAL 0x00000001 + +/* + * Attribute provider: this represents a source of attributes derived + * from the security context. + */ +struct gss_eap_attr_provider +{ +public: + gss_eap_attr_provider(void) {} + virtual ~gss_eap_attr_provider(void) {} + + bool initWithManager(const gss_eap_attr_ctx *manager) + { + m_manager = manager; + return true; + } + + virtual bool initWithExistingContext(const gss_eap_attr_ctx *manager, + const gss_eap_attr_provider *ctx GSSEAP_UNUSED) + { + return initWithManager(manager); + } + + virtual bool initWithGssContext(const gss_eap_attr_ctx *manager, + const gss_cred_id_t cred GSSEAP_UNUSED, + const gss_ctx_id_t ctx GSSEAP_UNUSED) + { + return initWithManager(manager); + } + + virtual bool getAttributeTypes(gss_eap_attr_enumeration_cb GSSEAP_UNUSED, + void *data GSSEAP_UNUSED) const + { + return false; + } + + virtual bool setAttribute(int complete GSSEAP_UNUSED, + const gss_buffer_t attr GSSEAP_UNUSED, + const gss_buffer_t value GSSEAP_UNUSED) + { + return false; + } + + virtual bool deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED) + { + return false; + } + + virtual bool getAttribute(const gss_buffer_t attr GSSEAP_UNUSED, + int *authenticated GSSEAP_UNUSED, + int *complete GSSEAP_UNUSED, + gss_buffer_t value GSSEAP_UNUSED, + gss_buffer_t display_value GSSEAP_UNUSED, + int *more GSSEAP_UNUSED) const + { + return false; + } + + virtual gss_any_t mapToAny(int authenticated GSSEAP_UNUSED, + gss_buffer_t type_id GSSEAP_UNUSED) const + { + return NULL; + } + + virtual void releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED, + gss_any_t input GSSEAP_UNUSED) const + { + } + + /* prefix to be prepended to attributes emitted by gss_get_name_attribute */ + virtual const char *prefix(void) const + { + return NULL; + } + + /* optional key for storing JSON dictionary */ + virtual const char *name(void) const + { + return NULL; + } + + virtual bool initWithJsonObject(const gss_eap_attr_ctx *manager, + JSONObject &object GSSEAP_UNUSED) + { + return initWithManager(manager); + } + + + virtual JSONObject jsonRepresentation(void) const + { + return JSONObject::null(); + } + + virtual time_t getExpiryTime(void) const { return 0; } + + virtual OM_uint32 mapException(OM_uint32 *minor GSSEAP_UNUSED, + std::exception &e GSSEAP_UNUSED) const + { + return GSS_S_CONTINUE_NEEDED; + } + + static bool init(void) { return true; } + static void finalize(void) {} + + static gss_eap_attr_provider *createAttrContext(void) { return NULL; } + +protected: + const gss_eap_attr_ctx *m_manager; + +private: + /* make non-copyable */ + gss_eap_attr_provider(const gss_eap_attr_provider&); + gss_eap_attr_provider& operator=(const gss_eap_attr_provider&); +}; + +typedef gss_eap_attr_provider *(*gss_eap_attr_create_provider)(void); + +/* + * Attribute context: this manages a set of providers for a given + * security context. + */ +struct gss_eap_attr_ctx +{ +public: + gss_eap_attr_ctx(void); + ~gss_eap_attr_ctx(void); + + bool initWithExistingContext(const gss_eap_attr_ctx *manager); + bool initWithGssContext(const gss_cred_id_t cred, + const gss_ctx_id_t ctx); + + bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const; + bool getAttributeTypes(gss_buffer_set_t *attrs); + + bool setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value); + bool deleteAttribute(const gss_buffer_t value); + bool getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const; + gss_any_t mapToAny(int authenticated, + gss_buffer_t type_id) const; + void releaseAnyNameMapping(gss_buffer_t type_id, + gss_any_t input) const; + + void exportToBuffer(gss_buffer_t buffer) const; + bool initWithBuffer(const gss_buffer_t buffer); + + static std::string + composeAttributeName(const gss_buffer_t prefix, + const gss_buffer_t suffix); + static void + decomposeAttributeName(const gss_buffer_t attribute, + gss_buffer_t prefix, + gss_buffer_t suffix); + static void + composeAttributeName(const gss_buffer_t prefix, + const gss_buffer_t suffix, + gss_buffer_t attribute); + + std::string + composeAttributeName(unsigned int type, + const gss_buffer_t suffix); + void + decomposeAttributeName(const gss_buffer_t attribute, + unsigned int *type, + gss_buffer_t suffix) const; + void + composeAttributeName(unsigned int type, + const gss_buffer_t suffix, + gss_buffer_t attribute) const; + + gss_eap_attr_provider *getProvider(unsigned int type) const; + + static void + registerProvider(unsigned int type, + gss_eap_attr_create_provider factory); + static void + unregisterProvider(unsigned int type); + + time_t getExpiryTime(void) const; + OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const; + +private: + bool providerEnabled(unsigned int type) const; + void releaseProvider(unsigned int type); + + unsigned int attributePrefixToType(const gss_buffer_t prefix) const; + gss_buffer_desc attributeTypeToPrefix(unsigned int type) const; + + bool initWithJsonObject(JSONObject &object); + JSONObject jsonRepresentation(void) const; + + gss_eap_attr_provider *getPrimaryProvider(void) const; + + /* make non-copyable */ + gss_eap_attr_ctx(const gss_eap_attr_ctx&); + gss_eap_attr_ctx& operator=(const gss_eap_attr_ctx&); + + uint32_t m_flags; + gss_eap_attr_provider *m_providers[ATTR_TYPE_MAX + 1]; +}; + +#endif /* __cplusplus */ + +#include "util_radius.h" +#include "util_saml.h" +#include "util_shib.h" + +#ifdef __cplusplus + +static inline void +duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst) +{ + OM_uint32 minor; + + if (GSS_ERROR(duplicateBuffer(&minor, &src, dst))) + throw std::bad_alloc(); +} + +static inline void +duplicateBuffer(std::string &str, gss_buffer_t buffer) +{ + gss_buffer_desc tmp; + + tmp.length = str.length(); + tmp.value = (char *)str.c_str(); + + duplicateBuffer(tmp, buffer); +} + +#else +struct gss_eap_attr_ctx; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * C wrappers for attribute context functions. These match their + * GSS naming extension equivalents. The caller is required to + * obtain the name mutex. + */ + +OM_uint32 +gssEapCreateAttrContext(OM_uint32 *minor, + gss_cred_id_t acceptorCred, + gss_ctx_id_t acceptorCtx, + struct gss_eap_attr_ctx **pAttrCtx, + time_t *pExpiryTime); + +OM_uint32 +gssEapInquireName(OM_uint32 *minor, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs); + +OM_uint32 +gssEapGetNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more); + +OM_uint32 +gssEapDeleteNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr); + +OM_uint32 +gssEapSetNameAttribute(OM_uint32 *minor, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value); + +OM_uint32 +gssEapExportAttrContext(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t buffer); + +OM_uint32 +gssEapImportAttrContext(OM_uint32 *minor, + gss_buffer_t buffer, + gss_name_t name); + +OM_uint32 +gssEapDuplicateAttrContext(OM_uint32 *minor, + gss_name_t in, + gss_name_t out); + +OM_uint32 +gssEapMapNameToAny(OM_uint32 *minor, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output); + +OM_uint32 +gssEapReleaseAnyNameMapping(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input); + +OM_uint32 +gssEapReleaseAttrContext(OM_uint32 *minor, + gss_name_t name); + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIL_ATTR_H_ */ diff --git a/mech_eap/util_base64.c b/mech_eap/util_base64.c new file mode 100644 index 0000000..0ec1cdc --- /dev/null +++ b/mech_eap/util_base64.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int +pos(char c) +{ + const char *p; + for (p = base64_chars; *p; p++) + if (*p == c) + return p - base64_chars; + return -1; +} + +ssize_t +base64Encode(const void *data, int size, char **str) +{ + char *s, *p; + int i; + int c; + const unsigned char *q; + + if (size > INT_MAX/4 || size < 0) { + *str = NULL; + return -1; + } + + p = s = (char *)GSSEAP_MALLOC(BASE64_EXPAND(size)); + if (p == NULL) { + *str = NULL; + return -1; + } + q = (const unsigned char *) data; + + for (i = 0; i < size;) { + c = q[i++]; + c *= 256; + if (i < size) + c += q[i]; + i++; + c *= 256; + if (i < size) + c += q[i]; + i++; + p[0] = base64_chars[(c & 0x00fc0000) >> 18]; + p[1] = base64_chars[(c & 0x0003f000) >> 12]; + p[2] = base64_chars[(c & 0x00000fc0) >> 6]; + p[3] = base64_chars[(c & 0x0000003f) >> 0]; + if (i > size) + p[3] = '='; + if (i > size + 1) + p[2] = '='; + p += 4; + } + *p = 0; + *str = s; + return strlen(s); +} + +#define DECODE_ERROR 0xffffffff + +static unsigned int +token_decode(const char *token) +{ + int i; + unsigned int val = 0; + int marker = 0; + if (strlen(token) < 4) + return DECODE_ERROR; + for (i = 0; i < 4; i++) { + val *= 64; + if (token[i] == '=') + marker++; + else if (marker > 0) + return DECODE_ERROR; + else + val += pos(token[i]); + } + if (marker > 2) + return DECODE_ERROR; + return (marker << 24) | val; +} + +ssize_t +base64Decode(const char *str, void *data) +{ + const char *p; + unsigned char *q; + + q = data; + p = str; + + while (*p && (*p == '=' || strchr(base64_chars, *p) || isspace(*p))) { + unsigned int val; + unsigned int marker; + if (isspace(*p)) { + p++; + continue; + } + val = token_decode(p); + marker = (val >> 24) & 0xff; + if (val == DECODE_ERROR) + return -1; + *q++ = (val >> 16) & 0xff; + if (marker < 2) + *q++ = (val >> 8) & 0xff; + if (marker < 1) + *q++ = val & 0xff; + p += 4; + } + return q - (unsigned char *) data; +} + +int +base64Valid(const char *str) +{ + const char *p = str; + int valid = 1; + + while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) { + unsigned int val = token_decode(p); + if (val == DECODE_ERROR) { + valid = 0; + break; + } + p += 4; + if (*p == '\n') + p++; + } + return valid; +} diff --git a/mech_eap/util_base64.h b/mech_eap/util_base64.h new file mode 100644 index 0000000..d015efe --- /dev/null +++ b/mech_eap/util_base64.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef _UTIL_BASE64_H_ +#define _UTIL_BASE64_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +ssize_t +base64Encode(const void *, int, char **); + +ssize_t +base64Decode(const char *, void *); + +int +base64Valid(const char *str); + +#define BASE64_EXPAND(n) (n * 4 / 3 + 4) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mech_eap/util_buffer.c b/mech_eap/util_buffer.c new file mode 100644 index 0000000..e135db9 --- /dev/null +++ b/mech_eap/util_buffer.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Buffer handling helpers. + */ + +#include "gssapiP_eap.h" + +OM_uint32 +makeStringBuffer(OM_uint32 *minor, + const char *string, + gss_buffer_t buffer) +{ + size_t len = strlen(string); + + buffer->value = GSSEAP_MALLOC(len + 1); + if (buffer->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(buffer->value, string, len + 1); + buffer->length = len; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +bufferToString(OM_uint32 *minor, + const gss_buffer_t buffer, + char **pString) +{ + char *s; + + s = GSSEAP_MALLOC(buffer->length + 1); + if (s == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(s, buffer->value, buffer->length); + s[buffer->length] = '\0'; + + *pString = s; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +duplicateBuffer(OM_uint32 *minor, + const gss_buffer_t src, + gss_buffer_t dst) +{ + dst->length = 0; + dst->value = NULL; + + if (src == GSS_C_NO_BUFFER) + return GSS_S_COMPLETE; + + dst->value = GSSEAP_MALLOC(src->length + 1); + if (dst->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + dst->length = src->length; + memcpy(dst->value, src->value, dst->length); + + ((unsigned char *)dst->value)[dst->length] = '\0'; + + *minor = 0; + return GSS_S_COMPLETE; +} diff --git a/mech_eap/util_cksum.c b/mech_eap/util_cksum.c new file mode 100644 index 0000000..aedc93e --- /dev/null +++ b/mech_eap/util_cksum.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Message protection services: checksum helpers. + */ + +#include "gssapiP_eap.h" + +static int +gssEapChecksum(krb5_context context, + krb5_cksumtype type, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *crypto, +#endif + krb5_keyusage sign_usage, + gss_iov_buffer_desc *iov, + int iov_count, + int verify, + int *valid) +{ + krb5_error_code code; + gss_iov_buffer_desc *header; + gss_iov_buffer_desc *trailer; + krb5_crypto_iov *kiov; + size_t kiov_count; + int i = 0, j; + size_t k5_checksumlen; + + if (verify) + *valid = FALSE; + + code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen); + if (code != 0) + return code; + + header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + GSSEAP_ASSERT(header != NULL); + + trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + GSSEAP_ASSERT(rrc != 0 || trailer != NULL); + + if (trailer == NULL) { + if (rrc != k5_checksumlen) + return KRB5_BAD_MSIZE; + if (header->buffer.length != 16 + k5_checksumlen) + return KRB5_BAD_MSIZE; + } else if (trailer->buffer.length != k5_checksumlen) + return KRB5_BAD_MSIZE; + + kiov_count = 2 + iov_count; + kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov)); + if (kiov == NULL) + return ENOMEM; + + /* Checksum over ( Data | Header ) */ + + /* Data */ + for (j = 0; j < iov_count; j++) { + kiov[i].flags = gssEapMapCryptoFlag(iov[j].type); + kiov[i].data.length = iov[j].buffer.length; + kiov[i].data.data = (char *)iov[j].buffer.value; + i++; + } + + /* Header */ + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = 16; + kiov[i].data.data = (char *)header->buffer.value; + i++; + + /* Checksum */ + kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (trailer == NULL) { + kiov[i].data.length = header->buffer.length - 16; + kiov[i].data.data = (char *)header->buffer.value + 16; + } else { + kiov[i].data.length = trailer->buffer.length; + kiov[i].data.data = (char *)trailer->buffer.value; + } + i++; + +#ifdef HAVE_HEIMDAL_VERSION + if (verify) { + code = krb5_verify_checksum_iov(context, crypto, sign_usage, + kiov, kiov_count, &type); + *valid = (code == 0); + } else { + code = krb5_create_checksum_iov(context, crypto, sign_usage, + kiov, kiov_count, &type); + } +#else + if (verify) { + krb5_boolean kvalid = FALSE; + + code = krb5_c_verify_checksum_iov(context, type, crypto, + sign_usage, kiov, kiov_count, &kvalid); + + *valid = kvalid; + } else { + code = krb5_c_make_checksum_iov(context, type, crypto, + sign_usage, kiov, kiov_count); + } +#endif /* HAVE_HEIMDAL_VERSION */ + + GSSEAP_FREE(kiov); + + return code; +} + +int +gssEapSign(krb5_context context, + krb5_cksumtype type, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *crypto, +#endif + krb5_keyusage sign_usage, + gss_iov_buffer_desc *iov, + int iov_count) +{ + return gssEapChecksum(context, type, rrc, crypto, + sign_usage, iov, iov_count, 0, NULL); +} + +int +gssEapVerify(krb5_context context, + krb5_cksumtype type, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *crypto, +#endif + krb5_keyusage sign_usage, + gss_iov_buffer_desc *iov, + int iov_count, + int *valid) +{ + return gssEapChecksum(context, type, rrc, crypto, + sign_usage, iov, iov_count, 1, valid); +} + +#if 0 +OM_uint32 +gssEapEncodeGssChannelBindings(OM_uint32 *minor, + gss_channel_bindings_t chanBindings, + gss_buffer_t encodedBindings) +{ + OM_uint32 major, tmpMinor; + size_t length; + unsigned char *p; + + if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) { + length = 24; + length += chanBindings->initiator_address.length; + length += chanBindings->acceptor_address.length; + length += chanBindings->application_data.length; + + encodedBindings->value = GSSEAP_MALLOC(length); + if (encodedBindings->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + encodedBindings->length = length; + p = (unsigned char *)encodedBindings->value; + + store_uint32_be(chanBindings->initiator_addrtype, p); + store_buffer(&chanBindings->initiator_address, p + 4, 0); + p += 4 + chanBindings->initiator_address.length; + + store_uint32_be(chanBindings->acceptor_addrtype, p); + store_buffer(&chanBindings->acceptor_address, p + 4, 0); + p += 4 + chanBindings->acceptor_address.length; + + store_buffer(&chanBindings->application_data, p, 1); + p += chanBindings->application_data.length; + } else { + encodedBindings->length = 0; + encodedBindings->value = NULL; + } + + *minor = 0; + return GSS_S_COMPLETE; +} +#endif diff --git a/mech_eap/util_context.c b/mech_eap/util_context.c new file mode 100644 index 0000000..7663f3d --- /dev/null +++ b/mech_eap/util_context.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Utility routines for context handles. + */ + +#include "gssapiP_eap.h" + +OM_uint32 +gssEapAllocContext(OM_uint32 *minor, + gss_ctx_id_t *pCtx) +{ + OM_uint32 tmpMinor; + gss_ctx_id_t ctx; + + GSSEAP_ASSERT(*pCtx == GSS_C_NO_CONTEXT); + + ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) { + *minor = GSSEAP_GET_LAST_ERROR(); + gssEapReleaseContext(&tmpMinor, &ctx); + return GSS_S_FAILURE; + } + + ctx->state = GSSEAP_STATE_INITIAL; + ctx->mechanismUsed = GSS_C_NO_OID; + + /* + * Integrity, confidentiality, sequencing and replay detection are + * always available. Regardless of what flags are requested in + * GSS_Init_sec_context, implementations MUST set the flag corresponding + * to these services in the output of GSS_Init_sec_context and + * GSS_Accept_sec_context. + */ + ctx->gssFlags = GSS_C_TRANS_FLAG | /* exporting contexts */ + GSS_C_INTEG_FLAG | /* integrity */ + GSS_C_CONF_FLAG | /* confidentiality */ + GSS_C_SEQUENCE_FLAG | /* sequencing */ + GSS_C_REPLAY_FLAG; /* replay detection */ + + *pCtx = ctx; + + return GSS_S_COMPLETE; +} + +static void +releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx) +{ + eap_peer_sm_deinit(ctx->eap); +} + +#ifdef GSSEAP_ENABLE_ACCEPTOR +static void +releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx) +{ + OM_uint32 tmpMinor; + + if (ctx->radConn != NULL) + rs_conn_destroy(ctx->radConn); + if (ctx->radContext != NULL) + rs_context_destroy(ctx->radContext); + if (ctx->radServer != NULL) + GSSEAP_FREE(ctx->radServer); + gss_release_buffer(&tmpMinor, &ctx->state); + if (ctx->vps != NULL) + gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps); +} +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + +OM_uint32 +gssEapReleaseContext(OM_uint32 *minor, + gss_ctx_id_t *pCtx) +{ + OM_uint32 tmpMinor; + gss_ctx_id_t ctx = *pCtx; + krb5_context krbContext = NULL; + + if (ctx == GSS_C_NO_CONTEXT) { + return GSS_S_COMPLETE; + } + + gssEapKerberosInit(&tmpMinor, &krbContext); + +#ifdef GSSEAP_ENABLE_REAUTH + if (ctx->flags & CTX_FLAG_KRB_REAUTH) { + gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER); + } else +#endif /* GSSEAP_ENABLE_REAUTH */ + if (CTX_IS_INITIATOR(ctx)) { + releaseInitiatorContext(&ctx->initiatorCtx); + } +#ifdef GSSEAP_ENABLE_ACCEPTOR + else { + releaseAcceptorContext(&ctx->acceptorCtx); + } +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + + krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key); + gssEapReleaseName(&tmpMinor, &ctx->initiatorName); + gssEapReleaseName(&tmpMinor, &ctx->acceptorName); + gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed); + sequenceFree(&tmpMinor, &ctx->seqState); + gssEapReleaseCred(&tmpMinor, &ctx->cred); + + GSSEAP_MUTEX_DESTROY(&ctx->mutex); + + memset(ctx, 0, sizeof(*ctx)); + GSSEAP_FREE(ctx); + *pCtx = GSS_C_NO_CONTEXT; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapMakeToken(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t innerToken, + enum gss_eap_token_type tokenType, + gss_buffer_t outputToken) +{ + unsigned char *p; + + GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID); + + outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length); + outputToken->value = GSSEAP_MALLOC(outputToken->length); + if (outputToken->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + p = (unsigned char *)outputToken->value; + makeTokenHeader(ctx->mechanismUsed, innerToken->length, &p, tokenType); + memcpy(p, innerToken->value, innerToken->length); + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapVerifyToken(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t inputToken, + enum gss_eap_token_type *actualToken, + gss_buffer_t innerInputToken) +{ + OM_uint32 major; + size_t bodySize; + unsigned char *p = (unsigned char *)inputToken->value; + gss_OID_desc oidBuf; + gss_OID oid; + + if (ctx->mechanismUsed != GSS_C_NO_OID) { + oid = ctx->mechanismUsed; + } else { + oidBuf.elements = NULL; + oidBuf.length = 0; + oid = &oidBuf; + } + + major = verifyTokenHeader(minor, oid, &bodySize, &p, + inputToken->length, actualToken); + if (GSS_ERROR(major)) + return major; + + if (ctx->mechanismUsed == GSS_C_NO_OID) { + major = gssEapCanonicalizeOid(minor, oid, 0, &ctx->mechanismUsed); + if (GSS_ERROR(major)) + return major; + } + + innerInputToken->length = bodySize; + innerInputToken->value = p; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapContextTime(OM_uint32 *minor, + gss_ctx_id_t context_handle, + OM_uint32 *time_rec) +{ + *minor = 0; + + if (context_handle->expiryTime == 0) { + *time_rec = GSS_C_INDEFINITE; + } else { + time_t now, lifetime; + + time(&now); + lifetime = context_handle->expiryTime - now; + if (lifetime <= 0) { + *time_rec = 0; + return GSS_S_CONTEXT_EXPIRED; + } + *time_rec = lifetime; + } + + return GSS_S_COMPLETE; +} + +static OM_uint32 +gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t tokenMIC, + int verifyMIC) +{ + OM_uint32 major; + size_t i = 0, j; + enum gss_eap_token_type tokType; + OM_uint32 micTokType; + unsigned char wireTokType[2]; + unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL; + const struct gss_eap_token_buffer_set *tokens; + ssize_t checksumIndex = -1; + + krb5_keyusage usage; + krb5_error_code code = 0; + krb5_context krbContext; + krb5_crypto_iov *kiov = NULL; +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto = NULL; + krb5_cksumtype cksumType; +#endif + size_t kiovCount; + + GSSEAP_KRB_INIT(&krbContext); + + tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens; + + GSSEAP_ASSERT(tokens != NULL); + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto); + if (code != 0) + goto cleanup; +#endif + + kiovCount = 2 + (3 * tokens->buffers.count) + 1; + + if (verifyMIC) { + assert(tokens->buffers.count != 0); + kiovCount -= 3; + } + + kiov = GSSEAP_CALLOC(kiovCount, sizeof(*kiov)); + if (kiov == NULL) { + *minor = ENOMEM; + goto cleanup; + } + + innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count); + if (innerTokTypes == NULL) { + *minor = ENOMEM; + goto cleanup; + } + + innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count); + if (innerTokLengths == NULL) { + *minor = ENOMEM; + goto cleanup; + } + + /* Mechanism OID */ + GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID); + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = ctx->mechanismUsed->length; + kiov[i].data.data = ctx->mechanismUsed->elements; + i++; + + /* Token type */ + if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) { + tokType = TOK_TYPE_INITIATOR_CONTEXT; + micTokType = ITOK_TYPE_INITIATOR_MIC; + usage = KEY_USAGE_GSSEAP_INITOKEN_MIC; + } else { + tokType = TOK_TYPE_ACCEPTOR_CONTEXT; + micTokType = ITOK_TYPE_ACCEPTOR_MIC; + usage = KEY_USAGE_GSSEAP_ACCTOKEN_MIC; + } + store_uint16_be(tokType, wireTokType); + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = sizeof(wireTokType); + kiov[i].data.data = (char *)wireTokType; + i++; + + for (j = 0; j < tokens->buffers.count; j++) { + if (verifyMIC && + (tokens->types[j] & ITOK_TYPE_MASK) == micTokType) { + continue; + } + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = 4; + kiov[i].data.data = (char *)&innerTokTypes[j * 4]; + store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED), + kiov[i].data.data); + i++; + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + kiov[i].data.length = 4; + kiov[i].data.data = (char *)&innerTokLengths[j * 4]; + store_uint32_be(tokens->buffers.elements[j].length, + kiov[i].data.data); + i++; + + kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + gssBufferToKrbData(&tokens->buffers.elements[j], &kiov[i].data); + i++; + } + + kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (verifyMIC) { + gssBufferToKrbData(tokenMIC, &kiov[i].data); + } else { + size_t checksumSize; + + code = krb5_c_checksum_length(krbContext, ctx->checksumType, + &checksumSize); + if (code != 0) + goto cleanup; + + kiov[i].data.data = GSSEAP_MALLOC(checksumSize); + if (kiov[i].data.data == NULL) { + code = ENOMEM; + goto cleanup; + } + kiov[i].data.length = checksumSize; + checksumIndex = i; + } + i++; + GSSEAP_ASSERT(i == kiovCount); + +#ifdef HAVE_HEIMDAL_VERSION + cksumType = ctx->checksumType; + + if (verifyMIC) { + code = krb5_verify_checksum_iov(krbContext, krbCrypto, usage, + kiov, i, &cksumType); + } else { + code = krb5_create_checksum_iov(krbContext, krbCrypto, usage, + kiov, i, &cksumType); + } +#else + if (verifyMIC) { + krb5_boolean kvalid = FALSE; + + code = krb5_c_verify_checksum_iov(krbContext, ctx->checksumType, + &ctx->rfc3961Key, + usage, kiov, i, &kvalid); + if (code == 0 && !kvalid) { + code = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + } else { + code = krb5_c_make_checksum_iov(krbContext, ctx->checksumType, + &ctx->rfc3961Key, + usage, kiov, i); + } +#endif /* HAVE_HEIMDAL_VERSION */ + + if (code == 0 && !verifyMIC) { + krbDataToGssBuffer(&kiov[checksumIndex].data, tokenMIC); + checksumIndex = -1; + } + +cleanup: + if (checksumIndex != -1) + GSSEAP_FREE(kiov[checksumIndex].data.data); + if (kiov != NULL) + GSSEAP_FREE(kiov); + if (innerTokTypes != NULL) + GSSEAP_FREE(innerTokTypes); + if (innerTokLengths != NULL) + GSSEAP_FREE(innerTokLengths); +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif + + *minor = code; + + switch (code) { + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + major = GSS_S_BAD_SIG; + break; + case 0: + major = GSS_S_COMPLETE; + break; + default: + major = GSS_S_FAILURE; + break; + } + + return major; +} + +OM_uint32 +gssEapMakeTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t tokenMIC) +{ + tokenMIC->length = 0; + tokenMIC->value = NULL; + + return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, FALSE); +} + +OM_uint32 +gssEapVerifyTokenMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_buffer_t tokenMIC) +{ + return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE); +} diff --git a/mech_eap/util_cred.c b/mech_eap/util_cred.c new file mode 100644 index 0000000..cec7e71 --- /dev/null +++ b/mech_eap/util_cred.c @@ -0,0 +1,833 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Utility routines for credential handles. + */ + +#include "gssapiP_eap.h" + +#ifdef WIN32 +# include /* may need to use ShFolder.h instead */ +# include +#else +# include +#endif + +OM_uint32 +gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred) +{ + OM_uint32 tmpMinor; + gss_cred_id_t cred; + + *pCred = GSS_C_NO_CREDENTIAL; + + cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred)); + if (cred == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) { + *minor = GSSEAP_GET_LAST_ERROR(); + gssEapReleaseCred(&tmpMinor, &cred); + return GSS_S_FAILURE; + } + + *pCred = cred; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static void +zeroAndReleasePassword(gss_buffer_t password) +{ + GSSEAP_ASSERT(password != GSS_C_NO_BUFFER); + + if (password->value != NULL) { + memset(password->value, 0, password->length); + GSSEAP_FREE(password->value); + } + + password->value = NULL; + password->length = 0; +} + +OM_uint32 +gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) +{ + OM_uint32 tmpMinor; + gss_cred_id_t cred = *pCred; + krb5_context krbContext = NULL; + + if (cred == GSS_C_NO_CREDENTIAL) { + return GSS_S_COMPLETE; + } + + GSSEAP_KRB_INIT(&krbContext); + + gssEapReleaseName(&tmpMinor, &cred->name); + gssEapReleaseName(&tmpMinor, &cred->target); + + zeroAndReleasePassword(&cred->password); + + gss_release_buffer(&tmpMinor, &cred->radiusConfigFile); + gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza); + gss_release_buffer(&tmpMinor, &cred->caCertificate); + gss_release_buffer(&tmpMinor, &cred->caCertificateBlob); + gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint); + gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint); + gss_release_buffer(&tmpMinor, &cred->clientCertificate); + gss_release_buffer(&tmpMinor, &cred->privateKey); + +#ifdef GSSEAP_ENABLE_REAUTH + if (cred->krbCredCache != NULL) { + if (cred->flags & CRED_FLAG_DEFAULT_CCACHE) + krb5_cc_close(krbContext, cred->krbCredCache); + else + krb5_cc_destroy(krbContext, cred->krbCredCache); + } + if (cred->reauthCred != GSS_C_NO_CREDENTIAL) + gssReleaseCred(&tmpMinor, &cred->reauthCred); +#endif + + GSSEAP_MUTEX_DESTROY(&cred->mutex); + memset(cred, 0, sizeof(*cred)); + GSSEAP_FREE(cred); + *pCred = NULL; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +readStaticIdentityFile(OM_uint32 *minor, + gss_buffer_t defaultIdentity, + gss_buffer_t defaultPassword) +{ + OM_uint32 major, tmpMinor; + FILE *fp = NULL; + char buf[BUFSIZ]; + char *ccacheName; + int i = 0; +#ifndef WIN32 + struct passwd *pw = NULL, pwd; + char pwbuf[BUFSIZ]; +#endif + + defaultIdentity->length = 0; + defaultIdentity->value = NULL; + + if (defaultPassword != GSS_C_NO_BUFFER) { + defaultPassword->length = 0; + defaultPassword->value = NULL; + } + + ccacheName = getenv("GSSEAP_IDENTITY"); + if (ccacheName == NULL) { +#ifdef WIN32 + TCHAR szPath[MAX_PATH]; + + if (!SUCCEEDED(SHGetFolderPath(NULL, + CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */ + NULL, /* User access token */ + 0, /* SHGFP_TYPE_CURRENT */ + szPath))) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */ + goto cleanup; + } + + snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath); +#else + if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 || + pw == NULL || pw->pw_dir == NULL) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_GET_LAST_ERROR(); + goto cleanup; + } + + snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir); +#endif /* WIN32 */ + ccacheName = buf; + } + + fp = fopen(ccacheName, "r"); + if (fp == NULL) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_CRED; + goto cleanup; + } + + while (fgets(buf, sizeof(buf), fp) != NULL) { + gss_buffer_desc src, *dst; + + src.length = strlen(buf); + src.value = buf; + + if (src.length == 0) + break; + + if (buf[src.length - 1] == '\n') { + buf[src.length - 1] = '\0'; + if (--src.length == 0) + break; + } + + if (i == 0) + dst = defaultIdentity; + else if (i == 1) + dst = defaultPassword; + else + break; + + if (dst != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, &src, dst); + if (GSS_ERROR(major)) + goto cleanup; + } + + i++; + } + + if (defaultIdentity->length == 0) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_CRED; + goto cleanup; + } + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (fp != NULL) + fclose(fp); + + if (GSS_ERROR(major)) { + gss_release_buffer(&tmpMinor, defaultIdentity); + zeroAndReleasePassword(defaultPassword); + } + + memset(buf, 0, sizeof(buf)); + + return major; +} + +gss_OID +gssEapPrimaryMechForCred(gss_cred_id_t cred) +{ + gss_OID credMech = GSS_C_NO_OID; + + if (cred != GSS_C_NO_CREDENTIAL && + cred->mechanisms != GSS_C_NO_OID_SET && + cred->mechanisms->count == 1) + credMech = &cred->mechanisms->elements[0]; + + return credMech; +} + +OM_uint32 +gssEapAcquireCred(OM_uint32 *minor, + const gss_name_t desiredName, + OM_uint32 timeReq GSSEAP_UNUSED, + const gss_OID_set desiredMechs, + int credUsage, + gss_cred_id_t *pCred, + gss_OID_set *pActualMechs, + OM_uint32 *timeRec) +{ + OM_uint32 major, tmpMinor; + gss_cred_id_t cred; + + /* XXX TODO validate with changed set_cred_option API */ + *pCred = GSS_C_NO_CREDENTIAL; + + major = gssEapAllocCred(minor, &cred); + if (GSS_ERROR(major)) + goto cleanup; + + switch (credUsage) { + case GSS_C_BOTH: + cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT; + break; + case GSS_C_INITIATE: + cred->flags |= CRED_FLAG_INITIATE; + break; + case GSS_C_ACCEPT: + cred->flags |= CRED_FLAG_ACCEPT; + break; + default: + major = GSS_S_FAILURE; + *minor = GSSEAP_BAD_USAGE; + goto cleanup; + break; + } + + major = gssEapValidateMechs(minor, desiredMechs); + if (GSS_ERROR(major)) + goto cleanup; + + major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms); + if (GSS_ERROR(major)) + goto cleanup; + + if (desiredName != GSS_C_NO_NAME) { + GSSEAP_MUTEX_LOCK(&desiredName->mutex); + + major = gssEapDuplicateName(minor, desiredName, &cred->name); + if (GSS_ERROR(major)) { + GSSEAP_MUTEX_UNLOCK(&desiredName->mutex); + goto cleanup; + } + + GSSEAP_MUTEX_UNLOCK(&desiredName->mutex); + } + +#ifdef GSSEAP_ENABLE_ACCEPTOR + if (cred->flags & CRED_FLAG_ACCEPT) { + struct rs_context *radContext; + + major = gssEapCreateRadiusContext(minor, cred, &radContext); + if (GSS_ERROR(major)) + goto cleanup; + + rs_context_destroy(radContext); + } +#endif + + if (pActualMechs != NULL) { + major = duplicateOidSet(minor, cred->mechanisms, pActualMechs); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (timeRec != NULL) + *timeRec = GSS_C_INDEFINITE; + + *pCred = cred; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) + gssEapReleaseCred(&tmpMinor, &cred); + + gssEapTraceStatus("gss_acquire_cred", major, *minor); + return major; +} + +/* + * Return TRUE if cred available for mechanism. Caller need no acquire + * lock because mechanisms list is immutable. + */ +int +gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech) +{ + OM_uint32 minor; + int present = 0; + + GSSEAP_ASSERT(mech != GSS_C_NO_OID); + + if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET) + return TRUE; + + gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present); + + return present; +} + +static OM_uint32 +staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_name_t *pName) +{ + OM_uint32 major, tmpMinor; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER; + + *pName = GSS_C_NO_NAME; + + major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER); + if (major == GSS_S_COMPLETE) { + major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME, + nameMech, pName); + } + + gss_release_buffer(&tmpMinor, &defaultIdentity); + + return major; +} + +static OM_uint32 +gssEapResolveCredIdentity(OM_uint32 *minor, + gss_cred_id_t cred) +{ + OM_uint32 major; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + + if (cred->name != GSS_C_NO_NAME) { + *minor = 0; + return GSS_S_COMPLETE; + } + + if (cred->flags & CRED_FLAG_ACCEPT) { + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + char serviceName[5 + MAXHOSTNAMELEN]; + + /* default host-based service is host@localhost */ + memcpy(serviceName, "host@", 5); + if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) { + *minor = GSSEAP_NO_HOSTNAME; + return GSS_S_FAILURE; + } + + nameBuf.value = serviceName; + nameBuf.length = strlen((char *)nameBuf.value); + + major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE, + nameMech, &cred->name); + if (GSS_ERROR(major)) + return major; + } else if (cred->flags & CRED_FLAG_INITIATE) { +#ifdef HAVE_MOONSHOT_GET_IDENTITY + major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name); + if (major == GSS_S_CRED_UNAVAIL) +#endif + major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name); + if (major != GSS_S_CRED_UNAVAIL) + return major; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapInquireCred(OM_uint32 *minor, + gss_cred_id_t cred, + gss_name_t *name, + OM_uint32 *pLifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms) +{ + OM_uint32 major; + time_t now, lifetime; + + if (name != NULL) { + major = gssEapResolveCredIdentity(minor, cred); + if (GSS_ERROR(major)) + goto cleanup; + + if (cred->name != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, cred->name, name); + if (GSS_ERROR(major)) + goto cleanup; + } else + *name = GSS_C_NO_NAME; + } + + if (cred_usage != NULL) { + OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT)); + + switch (flags) { + case CRED_FLAG_INITIATE: + *cred_usage = GSS_C_INITIATE; + break; + case CRED_FLAG_ACCEPT: + *cred_usage = GSS_C_ACCEPT; + break; + default: + *cred_usage = GSS_C_BOTH; + break; + } + } + + if (mechanisms != NULL) { + if (cred->mechanisms != GSS_C_NO_OID_SET) + major = duplicateOidSet(minor, cred->mechanisms, mechanisms); + else + major = gssEapIndicateMechs(minor, mechanisms); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (cred->expiryTime == 0) { + lifetime = GSS_C_INDEFINITE; + } else { + now = time(NULL); + lifetime = now - cred->expiryTime; + if (lifetime < 0) + lifetime = 0; + } + + if (pLifetime != NULL) { + *pLifetime = lifetime; + } + + if (lifetime == 0) { + major = GSS_S_CREDENTIALS_EXPIRED; + *minor = GSSEAP_CRED_EXPIRED; + goto cleanup; + } + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + return major; +} + +OM_uint32 +gssEapSetCredPassword(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t password) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER; + + if (cred->flags & CRED_FLAG_RESOLVED) { + major = GSS_S_FAILURE; + *minor = GSSEAP_CRED_RESOLVED; + goto cleanup; + } + + if (password != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, password, &newPassword); + if (GSS_ERROR(major)) + goto cleanup; + + cred->flags |= CRED_FLAG_PASSWORD; + } else { + cred->flags &= ~(CRED_FLAG_PASSWORD); + } + + gss_release_buffer(&tmpMinor, &cred->password); + cred->password = newPassword; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + return major; +} + +/* + * Currently only the privateKey path is exposed to the application + * (via gss_set_cred_option() or the third line in ~/.gss_eap_id). + * At some point in the future we may add support for setting the + * client certificate separately. + */ +OM_uint32 +gssEapSetCredClientCertificate(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t clientCert, + const gss_buffer_t privateKey) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc newClientCert = GSS_C_EMPTY_BUFFER; + gss_buffer_desc newPrivateKey = GSS_C_EMPTY_BUFFER; + + if (cred->flags & CRED_FLAG_RESOLVED) { + major = GSS_S_FAILURE; + *minor = GSSEAP_CRED_RESOLVED; + goto cleanup; + } + + if (clientCert == GSS_C_NO_BUFFER && + privateKey == GSS_C_NO_BUFFER) { + cred->flags &= ~(CRED_FLAG_CERTIFICATE); + major = GSS_S_COMPLETE; + *minor = 0; + goto cleanup; + } + + if (clientCert != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, clientCert, &newClientCert); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (privateKey != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, privateKey, &newPrivateKey); + if (GSS_ERROR(major)) + goto cleanup; + } + + cred->flags |= CRED_FLAG_CERTIFICATE; + + gss_release_buffer(&tmpMinor, &cred->clientCertificate); + cred->clientCertificate = newClientCert; + + gss_release_buffer(&tmpMinor, &cred->privateKey); + cred->privateKey = newPrivateKey; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) { + gss_release_buffer(&tmpMinor, &newClientCert); + gss_release_buffer(&tmpMinor, &newPrivateKey); + } + + return major; +} + +OM_uint32 +gssEapSetCredService(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_name_t target) +{ + OM_uint32 major, tmpMinor; + gss_name_t newTarget = GSS_C_NO_NAME; + + if (cred->flags & CRED_FLAG_RESOLVED) { + major = GSS_S_FAILURE; + *minor = GSSEAP_CRED_RESOLVED; + goto cleanup; + } + + if (target != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, target, &newTarget); + if (GSS_ERROR(major)) + goto cleanup; + + cred->flags |= CRED_FLAG_TARGET; + } else { + cred->flags &= ~(CRED_FLAG_TARGET); + } + + gssEapReleaseName(&tmpMinor, &cred->target); + cred->target = newTarget; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + return major; +} + +static OM_uint32 +gssEapDuplicateCred(OM_uint32 *minor, + const gss_cred_id_t src, + gss_cred_id_t *pDst) +{ + OM_uint32 major, tmpMinor; + gss_cred_id_t dst = GSS_C_NO_CREDENTIAL; + + *pDst = GSS_C_NO_CREDENTIAL; + + major = gssEapAllocCred(minor, &dst); + if (GSS_ERROR(major)) + goto cleanup; + + dst->flags = src->flags; + + if (src->name != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, src->name, &dst->name); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (src->target != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, src->target, &dst->target); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (src->password.value != NULL) { + major = duplicateBuffer(minor, &src->password, &dst->password); + if (GSS_ERROR(major)) + goto cleanup; + } + + major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms); + if (GSS_ERROR(major)) + goto cleanup; + + dst->expiryTime = src->expiryTime; + + if (src->radiusConfigFile.value != NULL) + duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile); + if (src->radiusConfigStanza.value != NULL) + duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza); + if (src->caCertificate.value != NULL) + duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate); + if (src->caCertificateBlob.value != NULL) + duplicateBufferOrCleanup(&src->caCertificateBlob, &dst->caCertificateBlob); + if (src->subjectNameConstraint.value != NULL) + duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint); + if (src->subjectAltNameConstraint.value != NULL) + duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint); + if (src->clientCertificate.value != NULL) + duplicateBufferOrCleanup(&src->clientCertificate, &dst->clientCertificate); + if (src->privateKey.value != NULL) + duplicateBufferOrCleanup(&src->privateKey, &dst->privateKey); + +#ifdef GSSEAP_ENABLE_REAUTH + /* XXX krbCredCache, reauthCred */ +#endif + + *pDst = dst; + dst = GSS_C_NO_CREDENTIAL; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + gssEapReleaseCred(&tmpMinor, &dst); + + return major; +} + +static OM_uint32 +staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER; + gss_name_t defaultIdentityName = GSS_C_NO_NAME; + gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER; + int isDefaultIdentity = FALSE; + + major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME, + gssEapPrimaryMechForCred(cred), &defaultIdentityName); + if (GSS_ERROR(major)) + goto cleanup; + + if (defaultIdentityName == GSS_C_NO_NAME) { + if (cred->name == GSS_C_NO_NAME) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_IDENTITY; + goto cleanup; + } + } else { + if (cred->name == GSS_C_NO_NAME) { + cred->name = defaultIdentityName; + defaultIdentityName = GSS_C_NO_NAME; + isDefaultIdentity = TRUE; + } else { + major = gssEapCompareName(minor, cred->name, + defaultIdentityName, 0, + &isDefaultIdentity); + if (GSS_ERROR(major)) + goto cleanup; + } + } + + if (isDefaultIdentity && + (cred->flags & CRED_FLAG_PASSWORD) == 0) { + major = gssEapSetCredPassword(minor, cred, &defaultPassword); + if (GSS_ERROR(major)) + goto cleanup; + } + +cleanup: + gssEapReleaseName(&tmpMinor, &defaultIdentityName); + zeroAndReleasePassword(&defaultPassword); + gss_release_buffer(&tmpMinor, &defaultIdentity); + + return major; +} + +OM_uint32 +gssEapResolveInitiatorCred(OM_uint32 *minor, + const gss_cred_id_t cred, + const gss_name_t targetName +#ifndef HAVE_MOONSHOT_GET_IDENTITY + GSSEAP_UNUSED +#endif + , + gss_cred_id_t *pResolvedCred) +{ + OM_uint32 major, tmpMinor; + gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL; + + if (cred == GSS_C_NO_CREDENTIAL) { + major = gssEapAcquireCred(minor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + &resolvedCred, + NULL, + NULL); + if (GSS_ERROR(major)) + goto cleanup; + } else { + if ((cred->flags & CRED_FLAG_INITIATE) == 0) { + major = GSS_S_NO_CRED; + *minor = GSSEAP_CRED_USAGE_MISMATCH; + goto cleanup; + } + + major = gssEapDuplicateCred(minor, cred, &resolvedCred); + if (GSS_ERROR(major)) + goto cleanup; + } + + if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) { +#ifdef HAVE_MOONSHOT_GET_IDENTITY + major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName); + if (major == GSS_S_CRED_UNAVAIL) +#endif + major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred); + if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL) + goto cleanup; + + /* If we have a caller-supplied password, the credential is resolved. */ + if ((resolvedCred->flags & + (CRED_FLAG_PASSWORD | CRED_FLAG_CERTIFICATE)) == 0) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_CRED; + goto cleanup; + } + + resolvedCred->flags |= CRED_FLAG_RESOLVED; + } + + *pResolvedCred = resolvedCred; + resolvedCred = GSS_C_NO_CREDENTIAL; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + gssEapReleaseCred(&tmpMinor, &resolvedCred); + + return major; +} diff --git a/mech_eap/util_crypt.c b/mech_eap/util_crypt.c new file mode 100644 index 0000000..7bb35aa --- /dev/null +++ b/mech_eap/util_crypt.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 2001, 2008 by the Massachusetts Institute of Technology. + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Message protection services: cryptography helpers. + */ + +#include "gssapiP_eap.h" + +/* + * DCE_STYLE indicates actual RRC is EC + RRC + * EC is extra rotate count for DCE_STYLE, pad length otherwise + * RRC is rotate count. + */ +static krb5_error_code +mapIov(krb5_context context, int dce_style, size_t ec, size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *crypto, +#endif + gss_iov_buffer_desc *iov, + int iov_count, krb5_crypto_iov **pkiov, + size_t *pkiov_count) +{ + gss_iov_buffer_t header; + gss_iov_buffer_t trailer; + int i = 0, j; + size_t kiov_count; + krb5_crypto_iov *kiov; + size_t k5_headerlen = 0, k5_trailerlen = 0; + size_t gss_headerlen, gss_trailerlen; + krb5_error_code code; + + *pkiov = NULL; + *pkiov_count = 0; + + header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + GSSEAP_ASSERT(header != NULL); + + trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + GSSEAP_ASSERT(trailer == NULL || rrc == 0); + + code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen); + if (code != 0) + return code; + + code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5_trailerlen); + if (code != 0) + return code; + + /* Check header and trailer sizes */ + gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */ + gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */ + + /* If we're caller without a trailer, we must rotate by trailer length */ + if (trailer == NULL) { + size_t actual_rrc = rrc; + + if (dce_style) + actual_rrc += ec; /* compensate for Windows bug */ + + if (actual_rrc != gss_trailerlen) + return KRB5_BAD_MSIZE; + + gss_headerlen += gss_trailerlen; + } else { + if (trailer->buffer.length != gss_trailerlen) + return KRB5_BAD_MSIZE; + } + + if (header->buffer.length != gss_headerlen) + return KRB5_BAD_MSIZE; + + kiov_count = 3 + iov_count; + kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov)); + if (kiov == NULL) + return ENOMEM; + + /* + * The krb5 header is located at the end of the GSS header. + */ + kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER; + kiov[i].data.length = k5_headerlen; + kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen; + i++; + + for (j = 0; j < iov_count; j++) { + kiov[i].flags = gssEapMapCryptoFlag(iov[j].type); + if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY) + continue; + + kiov[i].data.length = iov[j].buffer.length; + kiov[i].data.data = (char *)iov[j].buffer.value; + i++; + } + + /* + * The EC and encrypted GSS header are placed in the trailer, which may + * be rotated directly after the plaintext header if no trailer buffer + * is provided. + */ + kiov[i].flags = KRB5_CRYPTO_TYPE_DATA; + kiov[i].data.length = ec + 16; /* E(Header) */ + if (trailer == NULL) + kiov[i].data.data = (char *)header->buffer.value + 16; + else + kiov[i].data.data = (char *)trailer->buffer.value; + i++; + + /* + * The krb5 trailer is placed after the encrypted copy of the + * krb5 header (which may be in the GSS header or trailer). + */ + kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + kiov[i].data.length = k5_trailerlen; + kiov[i].data.data = (char *)kiov[i - 1].data.data + ec + 16; /* E(Header) */ + i++; + + *pkiov = kiov; + *pkiov_count = i; + + return 0; +} + +int +gssEapEncrypt(krb5_context context, + int dce_style, + size_t ec, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *crypto, +#endif + int usage, + gss_iov_buffer_desc *iov, + int iov_count) +{ + krb5_error_code code; + size_t kiov_count; + krb5_crypto_iov *kiov = NULL; + + code = mapIov(context, dce_style, ec, rrc, crypto, + iov, iov_count, &kiov, &kiov_count); + if (code != 0) + goto cleanup; + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_encrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL); +#else + code = krb5_c_encrypt_iov(context, crypto, usage, NULL, kiov, kiov_count); +#endif + if (code != 0) + goto cleanup; + +cleanup: + if (kiov != NULL) + GSSEAP_FREE(kiov); + + return code; +} + +int +gssEapDecrypt(krb5_context context, + int dce_style, + size_t ec, + size_t rrc, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto crypto, +#else + krb5_keyblock *crypto, +#endif + int usage, + gss_iov_buffer_desc *iov, + int iov_count) +{ + krb5_error_code code; + size_t kiov_count; + krb5_crypto_iov *kiov; + + code = mapIov(context, dce_style, ec, rrc, crypto, + iov, iov_count, &kiov, &kiov_count); + if (code != 0) + goto cleanup; + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_decrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL); +#else + code = krb5_c_decrypt_iov(context, crypto, usage, NULL, kiov, kiov_count); +#endif + +cleanup: + if (kiov != NULL) + GSSEAP_FREE(kiov); + + return code; +} + +int +gssEapMapCryptoFlag(OM_uint32 type) +{ + int ktype; + + switch (GSS_IOV_BUFFER_TYPE(type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_PADDING: + ktype = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + ktype = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + + return ktype; +} + +gss_iov_buffer_t +gssEapLocateIov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type) +{ + int i; + gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER; + + if (iov == GSS_C_NO_IOV_BUFFER) + return GSS_C_NO_IOV_BUFFER; + + for (i = iov_count - 1; i >= 0; i--) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) { + if (p == GSS_C_NO_IOV_BUFFER) + p = &iov[i]; + else + return GSS_C_NO_IOV_BUFFER; + } + } + + return p; +} + +void +gssEapIovMessageLength(gss_iov_buffer_desc *iov, + int iov_count, + size_t *data_length_p, + size_t *assoc_data_length_p) +{ + int i; + size_t data_length = 0, assoc_data_length = 0; + + GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER); + + *data_length_p = *assoc_data_length_p = 0; + + for (i = 0; i < iov_count; i++) { + OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type); + + if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY) + assoc_data_length += iov[i].buffer.length; + + if (type == GSS_IOV_BUFFER_TYPE_DATA || + type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY) + data_length += iov[i].buffer.length; + } + + *data_length_p = data_length; + *assoc_data_length_p = assoc_data_length; +} + +void +gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count) +{ + int i; + OM_uint32 min_stat; + + GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER); + + for (i = 0; i < iov_count; i++) { + if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) { + gss_release_buffer(&min_stat, &iov[i].buffer); + iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED); + } + } +} + +int +gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count) +{ + int i; + krb5_boolean has_conf_data = FALSE; + + GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER); + + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) { + has_conf_data = TRUE; + break; + } + } + + return (has_conf_data == FALSE); +} + +int +gssEapAllocIov(gss_iov_buffer_t iov, size_t size) +{ + GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER); + GSSEAP_ASSERT(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE); + + iov->buffer.length = size; + iov->buffer.value = GSSEAP_MALLOC(size); + if (iov->buffer.value == NULL) { + iov->buffer.length = 0; + return ENOMEM; + } + + iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED; + + return 0; +} diff --git a/mech_eap/util_json.cpp b/mech_eap/util_json.cpp new file mode 100644 index 0000000..97eb1ed --- /dev/null +++ b/mech_eap/util_json.cpp @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * JSONObject utilities. + */ + +#include "gssapiP_eap.h" + +#include +#include +#include +#include +#include + +#define JSON_INIT(obj) do { \ + if ((obj) == NULL) \ + throw std::bad_alloc(); \ + m_obj = (obj); \ + } while (0) + +#define JSON_CHECK_CONTAINER() do { \ + if (!json_is_object(m_obj) && !json_is_array(m_obj)) { \ + std::string s("JSONObject is not a container"); \ + throw JSONException(m_obj); \ + } \ + } while (0) + +#define JSON_CHECK_OBJECT() do { \ + if (!json_is_object(m_obj)) { \ + std::string s("JSONObject is not a dictionary"); \ + throw JSONException(m_obj, JSON_OBJECT); \ + } \ + } while (0) + +#define JSON_CHECK_ARRAY() do { \ + if (!json_is_array(m_obj)) { \ + throw JSONException(m_obj, JSON_ARRAY); \ + } \ + } while (0) + +#define JSON_CHECK(s) do { \ + if ((s) != 0) \ + throw JSONException(); \ + } while (0) + +JSONObject +JSONObject::load(const char *input, size_t flags, json_error_t *error) +{ + json_t *obj; + + obj = json_loads(input, flags, error); + + return JSONObject(obj, false); +} + +JSONObject +JSONObject::load(FILE *fp, size_t flags, json_error_t *error) +{ + json_t *obj; + + obj = json_loadf(fp, flags, error); + + return JSONObject(obj, false); +} + +char * +JSONObject::dump(size_t flags) const +{ + char *s = json_dumps(m_obj, flags); + + if (s == NULL) + throw std::bad_alloc(); + + return s; +} + +void +JSONObject::dump(FILE *fp, size_t flags) const +{ + int r = json_dumpf(m_obj, fp, flags); + + if (r != 0) + throw std::bad_alloc(); +} + +size_t +JSONObject::size(void) const +{ + if (json_is_object(m_obj)) + return json_object_size(m_obj); + else if (json_is_array(m_obj)) + return json_array_size(m_obj); + else + return 0; +} + +JSONObject::JSONObject(json_t *obj, bool retain) +{ + if (retain) + json_incref(obj); + JSON_INIT(obj); +} + +JSONObject::JSONObject(const char *value) +{ + json_t *obj = json_string(value); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(json_int_t value) +{ + json_t *obj = json_integer(value); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(double value) +{ + json_t *obj = json_real(value); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(bool value) +{ + json_t *obj = value ? json_true() : json_false(); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(void) +{ + json_t *obj = json_object(); + + JSON_INIT(obj); +} + +JSONObject +JSONObject::object(void) +{ + return JSONObject(); +} + +JSONObject +JSONObject::null(void) +{ + return JSONObject(json_null(), false); +} + +JSONObject +JSONObject::array(void) +{ + return JSONObject(json_array(), false); +} + +void +JSONObject::set(const char *key, JSONObject &value) +{ + JSON_CHECK_OBJECT(); + JSON_CHECK(json_object_set_new(m_obj, key, value.get())); +} + +void +JSONObject::set(const char *key, const char *value) +{ + JSONObject jobj(value); + set(key, jobj); +} + +void +JSONObject::set(const char *key, json_int_t value) +{ + JSONObject jobj(value); + set(key, jobj); +} + +void +JSONObject::del(const char *key) +{ + json_object_del(m_obj, key); +} + +JSONObject +JSONObject::get(const char *key) const +{ + json_t *obj; + + obj = json_object_get(m_obj, key); + if (obj == NULL) + return JSONObject::null(); + + return JSONObject(obj, true); +} + +JSONObject +JSONObject::get(size_t index) const +{ + json_t *obj; + + obj = json_array_get(m_obj, index); + if (obj == NULL) + return JSONObject::null(); + + return JSONObject(obj, true); +} + +void +JSONObject::update(JSONObject &value) +{ + JSON_CHECK_OBJECT(); + json_t *other = value.get(); + JSON_CHECK(json_object_update(m_obj, other)); + json_decref(other); +} + +JSONObject +JSONObject::operator[](size_t index) const +{ + return get(index); +} + +JSONObject +JSONObject::operator[](const char *key) const +{ + return get(key); +} + +void +JSONObject::append(JSONObject &value) +{ + JSON_CHECK_ARRAY(); + JSON_CHECK(json_array_append_new(m_obj, value.get())); +} + +void +JSONObject::insert(size_t index, JSONObject &value) +{ + JSON_CHECK_ARRAY(); + JSON_CHECK(json_array_insert_new(m_obj, index, value.get())); +} + +void +JSONObject::remove(size_t index) +{ + JSON_CHECK_ARRAY(); + JSON_CHECK(json_array_remove(m_obj, index)); +} + +void +JSONObject::clear(void) +{ + JSON_CHECK_CONTAINER(); + + if (json_is_object(m_obj)) { + JSON_CHECK(json_object_clear(m_obj)); + } else if (json_is_array(m_obj)) { + JSON_CHECK(json_array_clear(m_obj)); + } +} + +void +JSONObject::extend(JSONObject &value) +{ + JSON_CHECK_ARRAY(); + json_t *other = value.get(); + JSON_CHECK(json_array_extend(m_obj, other)); + json_decref(other); +} + +const char * +JSONObject::string(void) const +{ + return json_string_value(m_obj); +} + +json_int_t +JSONObject::integer(void) const +{ + return json_integer_value(m_obj); +} + +double +JSONObject::real(void) const +{ + return json_real_value(m_obj); +} + +double +JSONObject::number(void) const +{ + return json_number_value(m_obj); +} + +#ifdef HAVE_SHIBRESOLVER +JSONObject +JSONObject::ddf(DDF &ddf) +{ + if (ddf.isstruct()) { + DDF elem = ddf.first(); + JSONObject jobj = JSONObject::object(); + + while (!elem.isnull()) { + JSONObject jtmp = JSONObject::ddf(elem); + jobj.set(elem.name(), jtmp); + elem = ddf.next(); + } + + return jobj; + } else if (ddf.islist()) { + DDF elem = ddf.first(); + JSONObject jobj = JSONObject::array(); + + while (!elem.isnull()) { + JSONObject jtmp = JSONObject::ddf(elem); + jobj.append(jtmp); + elem = ddf.next(); + } + + return jobj; + } else if (ddf.isstring()) { + return JSONObject(ddf.string()); + } else if (ddf.isint()) { + return JSONObject((json_int_t)ddf.integer()); + } else if (ddf.isfloat()) { + return JSONObject(ddf.floating()); + } else if (ddf.isempty() || ddf.ispointer()) { + return JSONObject::object(); + } else if (ddf.isnull()) { + return JSONObject::null(); + } + + std::string s("Unbridgeable DDF object"); + throw JSONException(); +} + +DDF +JSONObject::ddf(void) const +{ + DDF ddf(NULL); + + switch (type()) { + case JSON_OBJECT: { + JSONIterator iter = iterator(); + + do { + const char *key = iter.key(); + DDF value = iter.value().ddf(); + ddf.addmember(key).swap(value); + } while (iter.next()); + break; + } + case JSON_ARRAY: { + size_t i, nelems = size(); + + for (i = 0; i < nelems; i++) { + DDF value = get(i).ddf(); + ddf.add(value); + } + break; + } + case JSON_STRING: + ddf.string(string()); + break; + case JSON_INTEGER: + ddf.integer(integer()); + break; + case JSON_REAL: + ddf.floating(real()); + break; + case JSON_TRUE: + ddf.integer(1L); + break; + case JSON_FALSE: + ddf.integer(0L); + break; + case JSON_NULL: + break; + } + + return ddf; +} +#endif /* HAVE_SHIBRESOLVER */ + +bool JSONObject::isObject(void) const +{ + return json_is_object(m_obj); +} + +bool JSONObject::isArray(void) const +{ + return json_is_array(m_obj); +} + +bool JSONObject::isString(void) const +{ + return json_is_string(m_obj); +} + +bool JSONObject::isInteger(void) const +{ + return json_is_integer(m_obj); +} + +bool JSONObject::isNumber(void) const +{ + return json_is_number(m_obj); +} + +bool JSONObject::isBoolean(void) const +{ + return json_is_boolean(m_obj); +} + +bool JSONObject::isNull(void) const +{ + return json_is_null(m_obj); +} + +JSONIterator::JSONIterator(const JSONObject &obj) +{ + m_obj = obj.get(); + m_iter = json_object_iter(m_obj); +} + +JSONIterator::~JSONIterator(void) +{ + json_decref(m_obj); +} + +const char * +JSONIterator::key(void) const +{ + return json_object_iter_key(m_iter); +} + +JSONObject +JSONIterator::value(void) const +{ + return JSONObject(json_object_iter_value(m_iter)); +} + +bool +JSONIterator::next(void) +{ + m_iter = json_object_iter_next(m_obj, m_iter); + return m_iter != NULL; +} + +JSONException::JSONException(json_t *obj, json_type type) +{ + char *s = NULL; + const char *t; + + m_obj = json_incref(obj); + m_type = type; + + if (obj != NULL) + s = json_dumps(m_obj, 0); + + switch (type) { + case JSON_OBJECT: t = "OBJECT"; break; + case JSON_ARRAY: t = "ARRAY"; break; + case JSON_STRING: t = "STRING"; break; + case JSON_INTEGER: t = "INTEGER"; break; + case JSON_REAL: t = "REAL"; break; + case JSON_TRUE: t = "TRUE"; break; + case JSON_FALSE: t = "FALSE"; break; + case JSON_NULL: t = "NULL"; break; + default: t = "UNKNOWN"; break; + } + + if (obj != NULL) { + m_reason = "Invalid JSON object: " + std::string(s); + if (type != JSON_NULL) + m_reason += " (excepted type " + std::string(t) + ")"; + } else { + m_reason = "Internal JSON error"; + } + + if (s != NULL) + GSSEAP_FREE(s); +} diff --git a/mech_eap/util_json.h b/mech_eap/util_json.h new file mode 100644 index 0000000..4ffecc8 --- /dev/null +++ b/mech_eap/util_json.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * JSON object wrapper with not-entirely-toll-free DDF bridging. + */ + +#ifndef _UTIL_JSON_H_ +#define _UTIL_JSON_H_ 1 + +#ifdef __cplusplus +#include +#include + +#include + +#ifdef HAVE_SHIBRESOLVER +#include +using namespace shibsp; +#endif + +namespace gss_eap_util { + class JSONObject; + + class JSONException : public std::exception { + public: + JSONException(json_t *obj = NULL, json_type type = JSON_NULL); + + ~JSONException(void) throw() { + json_decref(m_obj); + } + + virtual const char *what(void) const throw() { + return m_reason.c_str(); + } + + private: + json_t *m_obj; + json_type m_type; + std::string m_reason; + }; + + class JSONIterator { + public: + JSONIterator(const JSONObject &obj); + ~JSONIterator(void); + const char *key(void) const; + JSONObject value(void) const; + bool next(void); + + private: + json_t *m_obj; + void *m_iter; + }; + + class JSONObject { + public: + static JSONObject load(const char *input, size_t flags, json_error_t *error); + static JSONObject load(FILE *, size_t flags, json_error_t *error); + + static JSONObject object(void); + static JSONObject array(void); + static JSONObject null(void); +#ifdef HAVE_SHIBRESOLVER + static JSONObject ddf(DDF &value); +#endif + + char *dump(size_t flags = 0) const; + void dump(FILE *fp, size_t flags = JSON_INDENT(4)) const; + + json_type type(void) const { return json_typeof(m_obj); } + size_t size(void) const; + + JSONObject(void); + JSONObject(const char *value); + JSONObject(json_int_t value); + JSONObject(double value); + JSONObject(bool value); + + void set(const char *key, JSONObject &value); + void set(const char *key, const char *value); + void set(const char *key, json_int_t value); + void del(const char *key); + void update(JSONObject &value); + JSONIterator iterator(void) const { return JSONIterator(*this); } + JSONObject get(const char *key) const; + JSONObject operator[](const char *key) const; + + JSONObject get(size_t index) const; + JSONObject operator[](size_t index) const; + void append(JSONObject &value); + void insert(size_t index, JSONObject &value); + void remove(size_t index); + void clear(void); + void extend(JSONObject &value); + + const char *string(void) const; + json_int_t integer(void) const; + double real(void) const; + double number(void) const; +#ifdef HAVE_SHIBRESOLVER + DDF ddf(void) const; +#endif + + bool isObject(void) const; + bool isArray(void) const; + bool isString(void) const; + bool isInteger(void) const; + bool isNumber(void) const; + bool isBoolean(void) const; + bool isNull(void) const; + + ~JSONObject(void) + { + if (m_obj != NULL) + json_decref(m_obj); + } + + JSONObject(const JSONObject &obj) + { + m_obj = json_incref(obj.m_obj); + } + + JSONObject& operator=(const JSONObject &obj) + { + if (this != &obj) + set(obj.m_obj); + return *this; + } + + private: + friend class JSONIterator; + + json_t *get(void) const { + return json_incref(m_obj); + } + + void set(json_t *obj) { + if (m_obj != obj) { + json_decref(m_obj); + m_obj = json_incref(m_obj); + } + } + + JSONObject(json_t *obj, bool retain = true); + + json_t *m_obj; + }; +} + +#endif /* __cplusplus */ + +#endif /* _UTIL_JSON_H_ */ diff --git a/mech_eap/util_krb.c b/mech_eap/util_krb.c new file mode 100644 index 0000000..78064f3 --- /dev/null +++ b/mech_eap/util_krb.c @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Kerberos 5 helpers. + */ + +#include "gssapiP_eap.h" + +void +gssEapDestroyKrbContext(krb5_context context) +{ + if (context != NULL) + krb5_free_context(context); +} + +static krb5_error_code +initKrbContext(krb5_context *pKrbContext) +{ + krb5_context krbContext; + krb5_error_code code; + char *defaultRealm = NULL; + + *pKrbContext = NULL; + + code = krb5_init_context(&krbContext); + if (code != 0) + goto cleanup; + + krb5_appdefault_string(krbContext, "eap_gss", + NULL, "default_realm", "", &defaultRealm); + + if (defaultRealm != NULL && defaultRealm[0] != '\0') { + code = krb5_set_default_realm(krbContext, defaultRealm); + if (code != 0) + goto cleanup; + } + + *pKrbContext = krbContext; + +cleanup: + krb5_free_default_realm(krbContext, defaultRealm); + + if (code != 0 && krbContext != NULL) + krb5_free_context(krbContext); + + return code; +} + +OM_uint32 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context) +{ + struct gss_eap_thread_local_data *tld; + + *minor = 0; + *context = NULL; + + tld = gssEapGetThreadLocalData(); + if (tld != NULL) { + if (tld->krbContext == NULL) { + *minor = initKrbContext(&tld->krbContext); + if (*minor != 0) + tld->krbContext = NULL; + } + *context = tld->krbContext; + } else { + *minor = GSSEAP_GET_LAST_ERROR(); + } + + GSSEAP_ASSERT(*context != NULL || *minor != 0); + + return (*minor == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +/* + * Derive a key K for RFC 4121 use by using the following + * derivation function (based on RFC 4402); + * + * KMSK = random-to-key(MSK) + * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap") + * L = output key size + * K = truncate(L, T1 || T2 || .. || Tn) + * + * The output must be freed by krb5_free_keyblock_contents(), + * not GSSEAP_FREE(). + */ +OM_uint32 +gssEapDeriveRfc3961Key(OM_uint32 *minor, + const unsigned char *inputKey, + size_t inputKeyLength, + krb5_enctype encryptionType, + krb5_keyblock *pKey) +{ + krb5_context krbContext; +#ifndef HAVE_HEIMDAL_VERSION + krb5_data data; +#endif + krb5_data ns, t, derivedKeyData; + krb5_keyblock kd; + krb5_error_code code; + size_t randomLength, keyLength, prfLength; + unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p; + ssize_t i, remain; + + GSSEAP_KRB_INIT(&krbContext); + GSSEAP_ASSERT(encryptionType != ENCTYPE_NULL); + + KRB_KEY_INIT(pKey); + KRB_KEY_INIT(&kd); + KRB_KEY_TYPE(&kd) = encryptionType; + + KRB_DATA_INIT(&ns); + KRB_DATA_INIT(&t); + KRB_DATA_INIT(&derivedKeyData); + + code = krb5_c_keylengths(krbContext, encryptionType, + &randomLength, &keyLength); + if (code != 0) + goto cleanup; + + /* Convert EAP MSK into a Kerberos key */ + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_random_to_key(krbContext, encryptionType, inputKey, + MIN(inputKeyLength, randomLength), &kd); +#else + data.length = MIN(inputKeyLength, randomLength); + data.data = (char *)inputKey; + + KRB_KEY_DATA(&kd) = KRB_MALLOC(keyLength); + if (KRB_KEY_DATA(&kd) == NULL) { + code = ENOMEM; + goto cleanup; + } + KRB_KEY_LENGTH(&kd) = keyLength; + + code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd); +#endif /* HAVE_HEIMDAL_VERSION */ + if (code != 0) + goto cleanup; + + memset(&constant[0], 0, 4); + memcpy(&constant[4], "rfc4121-gss-eap", sizeof("rfc4121-gss-eap") - 1); + + ns.length = sizeof(constant); + ns.data = (char *)constant; + + /* Plug derivation constant and key into PRF */ + code = krb5_c_prf_length(krbContext, encryptionType, &prfLength); + if (code != 0) + goto cleanup; + +#ifndef HAVE_HEIMDAL_VERSION + /* Same API, but different allocation rules, unfortunately. */ + t.length = prfLength; + t.data = GSSEAP_MALLOC(t.length); + if (t.data == NULL) { + code = ENOMEM; + goto cleanup; + } +#endif + + derivedKeyData.length = randomLength; + derivedKeyData.data = GSSEAP_MALLOC(derivedKeyData.length); + if (derivedKeyData.data == NULL) { + code = ENOMEM; + goto cleanup; + } + + for (i = 0, p = (unsigned char *)derivedKeyData.data, remain = randomLength; + remain > 0; + p += t.length, remain -= t.length, i++) + { + store_uint32_be(i, ns.data); + + code = krb5_c_prf(krbContext, &kd, &ns, &t); + if (code != 0) + goto cleanup; + + memcpy(p, t.data, MIN(t.length, remain)); + } + + /* Finally, convert PRF output into a new key which we will return */ +#ifdef HAVE_HEIMDAL_VERSION + krb5_free_keyblock_contents(krbContext, &kd); + KRB_KEY_INIT(&kd); + + code = krb5_random_to_key(krbContext, encryptionType, + derivedKeyData.data, derivedKeyData.length, &kd); +#else + code = krb5_c_random_to_key(krbContext, encryptionType, + &derivedKeyData, &kd); +#endif + if (code != 0) + goto cleanup; + + *pKey = kd; + +cleanup: + if (code != 0) + krb5_free_keyblock_contents(krbContext, &kd); +#ifdef HAVE_HEIMDAL_VERSION + krb5_data_free(&t); +#else + if (t.data != NULL) { + memset(t.data, 0, t.length); + GSSEAP_FREE(t.data); + } +#endif + if (derivedKeyData.data != NULL) { + memset(derivedKeyData.data, 0, derivedKeyData.length); + GSSEAP_FREE(derivedKeyData.data); + } + + *minor = code; + + return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE +extern krb5_error_code +krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *); +#endif + +OM_uint32 +rfc3961ChecksumTypeForKey(OM_uint32 *minor, + krb5_keyblock *key, + krb5_cksumtype *cksumtype) +{ + krb5_context krbContext; +#ifndef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE + krb5_data data; + krb5_checksum cksum; +#endif + + GSSEAP_KRB_INIT(&krbContext); + +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE + *minor = krb5int_c_mandatory_cksumtype(krbContext, KRB_KEY_TYPE(key), + cksumtype); + if (*minor != 0) + return GSS_S_FAILURE; +#else + KRB_DATA_INIT(&data); + + memset(&cksum, 0, sizeof(cksum)); + + /* + * This is a complete hack but it's the only way to work with + * MIT Kerberos pre-1.9 without using private API, as it does + * not support passing in zero as the checksum type. + */ + *minor = krb5_c_make_checksum(krbContext, 0, key, 0, &data, &cksum); + if (*minor != 0) + return GSS_S_FAILURE; + + *cksumtype = KRB_CHECKSUM_TYPE(&cksum); + + krb5_free_checksum_contents(krbContext, &cksum); +#endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */ + + if (!krb5_c_is_keyed_cksum(*cksumtype)) { + *minor = (OM_uint32)KRB5KRB_AP_ERR_INAPP_CKSUM; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; +} + +krb5_error_code +krbCryptoLength(krb5_context krbContext, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *key, +#endif + int type, + size_t *length) +{ +#ifdef HAVE_HEIMDAL_VERSION + return krb5_crypto_length(krbContext, krbCrypto, type, length); +#else + unsigned int len; + krb5_error_code code; + + code = krb5_c_crypto_length(krbContext, KRB_KEY_TYPE(key), type, &len); + if (code == 0) + *length = (size_t)len; + + return code; +#endif +} + +krb5_error_code +krbPaddingLength(krb5_context krbContext, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *key, +#endif + size_t dataLength, + size_t *padLength) +{ + krb5_error_code code; +#ifdef HAVE_HEIMDAL_VERSION + size_t headerLength, paddingLength; + + code = krbCryptoLength(krbContext, krbCrypto, + KRB5_CRYPTO_TYPE_HEADER, &headerLength); + if (code != 0) + return code; + + dataLength += headerLength; + + code = krb5_crypto_length(krbContext, krbCrypto, + KRB5_CRYPTO_TYPE_PADDING, &paddingLength); + if (code != 0) + return code; + + if (paddingLength != 0 && (dataLength % paddingLength) != 0) + *padLength = paddingLength - (dataLength % paddingLength); + else + *padLength = 0; + + return 0; +#else + unsigned int pad; + + code = krb5_c_padding_length(krbContext, KRB_KEY_TYPE(key), dataLength, &pad); + if (code == 0) + *padLength = (size_t)pad; + + return code; +#endif /* HAVE_HEIMDAL_VERSION */ +} + +krb5_error_code +krbBlockSize(krb5_context krbContext, +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto, +#else + krb5_keyblock *key, +#endif + size_t *blockSize) +{ +#ifdef HAVE_HEIMDAL_VERSION + return krb5_crypto_getblocksize(krbContext, krbCrypto, blockSize); +#else + return krb5_c_block_size(krbContext, KRB_KEY_TYPE(key), blockSize); +#endif +} + +krb5_error_code +krbEnctypeToString( +#ifdef HAVE_HEIMDAL_VERSION + krb5_context krbContext, +#else + krb5_context krbContext GSSEAP_UNUSED, +#endif + krb5_enctype enctype, + const char *prefix, + gss_buffer_t string) +{ + krb5_error_code code; +#ifdef HAVE_HEIMDAL_VERSION + char *enctypeBuf = NULL; +#else + char enctypeBuf[128]; +#endif + size_t prefixLength, enctypeLength; + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_enctype_to_string(krbContext, enctype, &enctypeBuf); +#else + code = krb5_enctype_to_name(enctype, 0, enctypeBuf, sizeof(enctypeBuf)); +#endif + if (code != 0) + return code; + + prefixLength = (prefix != NULL) ? strlen(prefix) : 0; + enctypeLength = strlen(enctypeBuf); + + string->value = GSSEAP_MALLOC(prefixLength + enctypeLength + 1); + if (string->value == NULL) { +#ifdef HAVE_HEIMDAL_VERSION + krb5_xfree(enctypeBuf); +#endif + return ENOMEM; + } + + if (prefixLength != 0) + memcpy(string->value, prefix, prefixLength); + memcpy((char *)string->value + prefixLength, enctypeBuf, enctypeLength); + + string->length = prefixLength + enctypeLength; + ((char *)string->value)[string->length] = '\0'; + +#ifdef HAVE_HEIMDAL_VERSION + krb5_xfree(enctypeBuf); +#endif + + return 0; +} + +krb5_error_code +krbMakeAuthDataKdcIssued(krb5_context context, + const krb5_keyblock *key, + krb5_const_principal issuer, +#ifdef HAVE_HEIMDAL_VERSION + const AuthorizationData *authdata, + AuthorizationData *adKdcIssued +#else + krb5_authdata *const *authdata, + krb5_authdata ***adKdcIssued +#endif + ) +{ +#ifdef HAVE_HEIMDAL_VERSION + krb5_error_code code; + AD_KDCIssued kdcIssued; + AuthorizationDataElement adDatum; + unsigned char *buf; + size_t buf_size, len; + krb5_crypto crypto = NULL; + + memset(&kdcIssued, 0, sizeof(kdcIssued)); + memset(adKdcIssued, 0, sizeof(*adKdcIssued)); + + kdcIssued.i_realm = issuer->realm != NULL ? (Realm *)&issuer->realm : NULL; + kdcIssued.i_sname = (PrincipalName *)&issuer->name; + kdcIssued.elements = *authdata; + + ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, &len, code); + if (code != 0) + goto cleanup; + + code = krb5_crypto_init(context, key, 0, &crypto); + if (code != 0) + goto cleanup; + + code = krb5_create_checksum(context, crypto, KRB5_KU_AD_KDC_ISSUED, + 0, buf, buf_size, &kdcIssued.ad_checksum); + if (code != 0) + goto cleanup; + + free(buf); /* match ASN1_MALLOC_ENCODE */ + buf = NULL; + + ASN1_MALLOC_ENCODE(AD_KDCIssued, buf, buf_size, &kdcIssued, &len, code); + if (code != 0) + goto cleanup; + + adDatum.ad_type = KRB5_AUTHDATA_KDC_ISSUED; + adDatum.ad_data.length = buf_size; + adDatum.ad_data.data = buf; + + code = add_AuthorizationData(adKdcIssued, &adDatum); + if (code != 0) + goto cleanup; + +cleanup: + if (buf != NULL) + free(buf); /* match ASN1_MALLOC_ENCODE */ + if (crypto != NULL) + krb5_crypto_destroy(context, crypto); + free_Checksum(&kdcIssued.ad_checksum); + + return code; +#else + return krb5_make_authdata_kdc_issued(context, key, issuer, authdata, + adKdcIssued); +#endif /* HAVE_HEIMDAL_VERSION */ +} + +krb5_error_code +krbMakeCred(krb5_context krbContext, + krb5_auth_context authContext, + krb5_creds *creds, + krb5_data *data) +{ + krb5_error_code code; +#ifdef HAVE_HEIMDAL_VERSION + KRB_CRED krbCred; + KrbCredInfo krbCredInfo; + EncKrbCredPart encKrbCredPart; + krb5_keyblock *key; + krb5_crypto krbCrypto = NULL; + krb5_data encKrbCredPartData; + krb5_replay_data rdata; + size_t len; +#else + krb5_data *d = NULL; +#endif + + memset(data, 0, sizeof(*data)); +#ifdef HAVE_HEIMDAL_VERSION + memset(&krbCred, 0, sizeof(krbCred)); + memset(&krbCredInfo, 0, sizeof(krbCredInfo)); + memset(&encKrbCredPart, 0, sizeof(encKrbCredPart)); + memset(&rdata, 0, sizeof(rdata)); + + if (authContext->local_subkey) + key = authContext->local_subkey; + else if (authContext->remote_subkey) + key = authContext->remote_subkey; + else + key = authContext->keyblock; + + krbCred.pvno = 5; + krbCred.msg_type = krb_cred; + krbCred.tickets.val = (Ticket *)GSSEAP_CALLOC(1, sizeof(Ticket)); + if (krbCred.tickets.val == NULL) { + code = ENOMEM; + goto cleanup; + } + krbCred.tickets.len = 1; + + code = decode_Ticket(creds->ticket.data, + creds->ticket.length, + krbCred.tickets.val, &len); + if (code != 0) + goto cleanup; + + krbCredInfo.key = creds->session; + krbCredInfo.prealm = &creds->client->realm; + krbCredInfo.pname = &creds->client->name; + krbCredInfo.flags = &creds->flags.b; + krbCredInfo.authtime = &creds->times.authtime; + krbCredInfo.starttime = &creds->times.starttime; + krbCredInfo.endtime = &creds->times.endtime; + krbCredInfo.renew_till = &creds->times.renew_till; + krbCredInfo.srealm = &creds->server->realm; + krbCredInfo.sname = &creds->server->name; + krbCredInfo.caddr = creds->addresses.len ? &creds->addresses : NULL; + + encKrbCredPart.ticket_info.len = 1; + encKrbCredPart.ticket_info.val = &krbCredInfo; + if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { + rdata.seq = authContext->local_seqnumber; + encKrbCredPart.nonce = (int32_t *)&rdata.seq; + } else { + encKrbCredPart.nonce = NULL; + } + if (authContext->flags & KRB5_AUTH_CONTEXT_DO_TIME) { + krb5_us_timeofday(krbContext, &rdata.timestamp, &rdata.usec); + encKrbCredPart.timestamp = &rdata.timestamp; + encKrbCredPart.usec = &rdata.usec; + } else { + encKrbCredPart.timestamp = NULL; + encKrbCredPart.usec = NULL; + } + encKrbCredPart.s_address = authContext->local_address; + encKrbCredPart.r_address = authContext->remote_address; + + ASN1_MALLOC_ENCODE(EncKrbCredPart, encKrbCredPartData.data, + encKrbCredPartData.length, &encKrbCredPart, + &len, code); + if (code != 0) + goto cleanup; + + code = krb5_crypto_init(krbContext, key, 0, &krbCrypto); + if (code != 0) + goto cleanup; + + code = krb5_encrypt_EncryptedData(krbContext, + krbCrypto, + KRB5_KU_KRB_CRED, + encKrbCredPartData.data, + encKrbCredPartData.length, + 0, + &krbCred.enc_part); + if (code != 0) + goto cleanup; + + ASN1_MALLOC_ENCODE(KRB_CRED, data->data, data->length, + &krbCred, &len, code); + if (code != 0) + goto cleanup; + + if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) + authContext->local_seqnumber++; + +cleanup: + if (krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); + free_KRB_CRED(&krbCred); + krb5_data_free(&encKrbCredPartData); + + return code; +#else + code = krb5_mk_1cred(krbContext, authContext, creds, &d, NULL); + if (code == 0) { + *data = *d; + GSSEAP_FREE(d); + } + + return code; +#endif /* HAVE_HEIMDAL_VERSION */ +} diff --git a/mech_eap/util_lucid.c b/mech_eap/util_lucid.c new file mode 100644 index 0000000..f9e9941 --- /dev/null +++ b/mech_eap/util_lucid.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * "Lucid" security context export routine (called by MIT Kerberos mechanism). + */ + +#include "gssapiP_eap.h" + +OM_uint32 +gssEapExportLucidSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + const gss_OID desiredObject GSSEAP_UNUSED, + gss_buffer_set_t *data_set) +{ + OM_uint32 major = GSS_S_COMPLETE; + int haveAcceptorSubkey = + ((rfc4121Flags(ctx, 0) & TOK_FLAG_ACCEPTOR_SUBKEY) != 0); + gss_buffer_desc rep; +#ifdef HAVE_HEIMDAL_VERSION + krb5_error_code code; + krb5_storage *sp; + krb5_data data = { 0 }; + + sp = krb5_storage_emem(); + if (sp == NULL) { + code = ENOMEM; + goto cleanup; + } + + code = krb5_store_int32(sp, 1); /* version */ + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, CTX_IS_INITIATOR(ctx)); + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, ctx->expiryTime); + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, 0); + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, ctx->sendSeq); + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, 0); + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, ctx->recvSeq); + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, 1); /* is_cfx */ + if (code != 0) + goto cleanup; + + code = krb5_store_int32(sp, haveAcceptorSubkey); + if (code != 0) + goto cleanup; + + code = krb5_store_keyblock(sp, ctx->rfc3961Key); + if (code != 0) + goto cleanup; + + if (haveAcceptorSubkey) { + code = krb5_store_keyblock(sp, ctx->rfc3961Key); + if (code != 0) + goto cleanup; + } + + code = krb5_storage_to_data(sp, &data); + if (code != 0) + goto cleanup; + + rep.length = data.length; + rep.value = data.data; + + major = gss_add_buffer_set_member(minor, &rep, data_set); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + krb5_data_free(&data); + + if (major == GSS_S_COMPLETE) { + *minor = code; + major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE; + } + + return major; +#else + gss_krb5_lucid_context_v1_t *lctx; + gss_krb5_lucid_key_t *lkey = NULL; + + lctx = (gss_krb5_lucid_context_v1_t *)GSSEAP_CALLOC(1, sizeof(*lctx)); + if (lctx == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + lctx->version = 1; + lctx->initiate = CTX_IS_INITIATOR(ctx); + if (ctx->expiryTime == 0) + lctx->endtime = KRB_TIME_FOREVER; + else + lctx->endtime = ctx->expiryTime; + lctx->send_seq = ctx->sendSeq; + lctx->recv_seq = ctx->recvSeq; + lctx->protocol = 1; + + lctx->cfx_kd.have_acceptor_subkey = haveAcceptorSubkey; + + lkey = haveAcceptorSubkey + ? &lctx->cfx_kd.acceptor_subkey + : &lctx->cfx_kd.ctx_key; + + lkey->type = KRB_KEY_TYPE(&ctx->rfc3961Key); + lkey->data = GSSEAP_MALLOC(KRB_KEY_LENGTH(&ctx->rfc3961Key)); + if (lkey->data == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + lkey->length = KRB_KEY_LENGTH(&ctx->rfc3961Key); + memcpy(lkey->data, KRB_KEY_DATA(&ctx->rfc3961Key), lkey->length); + + rep.value = &lctx; + rep.length = sizeof(void *); + + major = gss_add_buffer_set_member(minor, &rep, data_set); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + if (GSS_ERROR(major)) { + if (lctx != NULL) { + if (lkey != NULL && lkey->data != NULL) { + memset(lkey->data, 0, lkey->length); + GSSEAP_FREE(lkey->data); + } + GSSEAP_FREE(lctx); + } + } + + return major; +#endif /* HAVE_HEIMDAL_VERSION */ +} diff --git a/mech_eap/util_mech.c b/mech_eap/util_mech.c new file mode 100644 index 0000000..8cb7e74 --- /dev/null +++ b/mech_eap/util_mech.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * General mechanism utility routines. + */ + +#include "gssapiP_eap.h" + +/* + * Mechanism and name types are taken from 1.3.6.1.5.5(mechanisms) + * assigned at http://www.iana.org/assignments/smi-numbers + * + * abfab(15) + * mechanisms(1) + * gss-eap-v1(1) + * eap-aes128-cts-hmac-sha1-96(17) + * eap-aes256-cts-hmac-sha1-96(18) + * nametypes(2) + * GSS_EAP_NT_EAP_NAME(1) + * + * Implementation-internal OIDs are taken from 1.3.6.1.4.1.5322(padl) + * gssEap(22) + * apiExtensions(3) + * inquireSecContextByOid(1) + * inquireCredByOid(2) + * setSecContextOption(3) + * setCredOption(4) + * mechInvoke(5) + */ + +/* + * Note: the enctype-less OID is used as the mechanism OID in non- + * canonicalized exported names. + */ +static gss_OID_desc gssEapMechOids[] = { + /* 1.3.6.1.5.5.15.1.1 */ + { 8, "\x2B\x06\x01\x05\x05\x0f\x01\x01" }, + /* 1.3.6.1.5.5.15.1.1.17 */ + { 9, "\x2B\x06\x01\x05\x05\x0f\x01\x01\x11" }, + /* 1.3.6.1.5.5.15.1.1.18 */ + { 9, "\x2B\x06\x01\x05\x05\x0f\x01\x01\x12" }, +}; + +gss_OID GSS_EAP_MECHANISM = &gssEapMechOids[0]; +gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM = &gssEapMechOids[1]; +gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM = &gssEapMechOids[2]; + +static int +internalizeOid(const gss_OID oid, + gss_OID *const pInternalizedOid); + +/* + * Returns TRUE is the OID is a concrete mechanism OID, that is, one + * with a Kerberos enctype as the last element. + */ +int +gssEapIsConcreteMechanismOid(const gss_OID oid) +{ + return oid->length > GSS_EAP_MECHANISM->length && + memcmp(oid->elements, GSS_EAP_MECHANISM->elements, + GSS_EAP_MECHANISM->length) == 0; +} + +int +gssEapIsMechanismOid(const gss_OID oid) +{ + return oid == GSS_C_NO_OID || + oidEqual(oid, GSS_EAP_MECHANISM) || + gssEapIsConcreteMechanismOid(oid); +} + +/* + * Validate that all elements are concrete mechanism OIDs. + */ +OM_uint32 +gssEapValidateMechs(OM_uint32 *minor, + const gss_OID_set mechs) +{ + int i; + + *minor = 0; + + if (mechs == GSS_C_NO_OID_SET) { + return GSS_S_COMPLETE; + } + + for (i = 0; i < mechs->count; i++) { + gss_OID oid = &mechs->elements[i]; + + if (!gssEapIsConcreteMechanismOid(oid)) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapOidToEnctype(OM_uint32 *minor, + const gss_OID oid, + krb5_enctype *enctype) +{ + OM_uint32 major; + int suffix; + + major = decomposeOid(minor, + GSS_EAP_MECHANISM->elements, + GSS_EAP_MECHANISM->length, + oid, + &suffix); + if (major == GSS_S_COMPLETE) + *enctype = suffix; + + return major; +} + +OM_uint32 +gssEapEnctypeToOid(OM_uint32 *minor, + krb5_enctype enctype, + gss_OID *pOid) +{ + OM_uint32 major; + gss_OID oid; + + *pOid = NULL; + + oid = (gss_OID)GSSEAP_MALLOC(sizeof(*oid)); + if (oid == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + oid->length = GSS_EAP_MECHANISM->length + 1; + oid->elements = GSSEAP_MALLOC(oid->length); + if (oid->elements == NULL) { + *minor = ENOMEM; + GSSEAP_FREE(oid); + return GSS_S_FAILURE; + } + + major = composeOid(minor, + GSS_EAP_MECHANISM->elements, + GSS_EAP_MECHANISM->length, + enctype, + oid); + if (major == GSS_S_COMPLETE) { + internalizeOid(oid, pOid); + *pOid = oid; + } else { + GSSEAP_FREE(oid->elements); + GSSEAP_FREE(oid); + } + + return major; +} + +OM_uint32 +gssEapIndicateMechs(OM_uint32 *minor, + gss_OID_set *mechs) +{ + krb5_context krbContext; + OM_uint32 major; + krb5_enctype *etypes; + int i; + + GSSEAP_KRB_INIT(&krbContext); + + *minor = krb5_get_permitted_enctypes(krbContext, &etypes); + if (*minor != 0) { + return GSS_S_FAILURE; + } + + major = gss_create_empty_oid_set(minor, mechs); + if (GSS_ERROR(major)) { + GSSEAP_FREE(etypes); + return major; + } + + for (i = 0; etypes[i] != ENCTYPE_NULL; i++) { + gss_OID mechOid; +#ifndef HAVE_HEIMDAL_VERSION + OM_uint32 tmpMinor; +#endif + + /* XXX currently we aren't equipped to encode these enctypes */ + if (etypes[i] < 0 || etypes[i] > 127) + continue; + + major = gssEapEnctypeToOid(minor, etypes[i], &mechOid); + if (GSS_ERROR(major)) + break; + + major = gss_add_oid_set_member(minor, mechOid, mechs); + if (GSS_ERROR(major)) + break; + +#ifndef HAVE_HEIMDAL_VERSION + gss_release_oid(&tmpMinor, &mechOid); +#endif + } + + GSSEAP_FREE(etypes); + + *minor = 0; + return major; +} + +OM_uint32 +gssEapDefaultMech(OM_uint32 *minor, + gss_OID *oid) +{ + gss_OID_set mechs; + OM_uint32 major, tmpMinor; + + major = gssEapIndicateMechs(minor, &mechs); + if (GSS_ERROR(major)) { + return major; + } + + if (mechs->count == 0) { + gss_release_oid_set(&tmpMinor, &mechs); + return GSS_S_BAD_MECH; + } + + if (!internalizeOid(&mechs->elements[0], oid)) { + /* don't double-free if we didn't internalize it */ + mechs->elements[0].length = 0; + mechs->elements[0].elements = NULL; + } + + gss_release_oid_set(&tmpMinor, &mechs); + + *minor = 0; + return GSS_S_COMPLETE; +} + +static int +internalizeOid(const gss_OID oid, + gss_OID *const pInternalizedOid) +{ + int i; + + *pInternalizedOid = GSS_C_NO_OID; + + for (i = 0; + i < sizeof(gssEapMechOids) / sizeof(gssEapMechOids[0]); + i++) { + if (oidEqual(oid, &gssEapMechOids[i])) { + *pInternalizedOid = (const gss_OID)&gssEapMechOids[i]; + break; + } + } + + if (*pInternalizedOid == GSS_C_NO_OID) { + if (oidEqual(oid, GSS_EAP_NT_EAP_NAME)) + *pInternalizedOid = (const gss_OID)GSS_EAP_NT_EAP_NAME; + } + + if (*pInternalizedOid == GSS_C_NO_OID) { + *pInternalizedOid = oid; + return 0; + } + + return 1; +} + +OM_uint32 +gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid) +{ + gss_OID internalizedOid = GSS_C_NO_OID; + + *minor = 0; + + if (internalizeOid(*oid, &internalizedOid)) { + /* OID was internalized, so we can mark it as "freed" */ + *oid = GSS_C_NO_OID; + return GSS_S_COMPLETE; + } + + /* we don't know about this OID */ + return GSS_S_CONTINUE_NEEDED; +} + +OM_uint32 +gssEapCanonicalizeOid(OM_uint32 *minor, + const gss_OID oid, + OM_uint32 flags, + gss_OID *pOid) +{ + OM_uint32 major; + int mapToNull = 0; + + major = GSS_S_COMPLETE; + *minor = 0; + *pOid = GSS_C_NULL_OID; + + if (oid == GSS_C_NULL_OID) { + if ((flags & OID_FLAG_NULL_VALID) == 0) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } else if (flags & OID_FLAG_MAP_NULL_TO_DEFAULT_MECH) { + return gssEapDefaultMech(minor, pOid); + } else { + mapToNull = 1; + } + } else if (oidEqual(oid, GSS_EAP_MECHANISM)) { + if ((flags & OID_FLAG_FAMILY_MECH_VALID) == 0) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } else if (flags & OID_FLAG_MAP_FAMILY_MECH_TO_NULL) { + mapToNull = 1; + } + } else if (!gssEapIsConcreteMechanismOid(oid)) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } + + if (!mapToNull) { + if (!internalizeOid(oid, pOid)) + major = duplicateOid(minor, oid, pOid); + } + + return major; +} + +static gss_buffer_desc gssEapSaslMechs[] = { + { sizeof("EAP") - 1, "EAP", }, /* not used */ + { sizeof("EAP-AES128") - 1, "EAP-AES128" }, + { sizeof("EAP-AES256") - 1, "EAP-AES256" }, +}; + +gss_buffer_t +gssEapOidToSaslName(const gss_OID oid) +{ + size_t i; + + for (i = 1; i < sizeof(gssEapMechOids)/sizeof(gssEapMechOids[0]); i++) { + if (oidEqual(&gssEapMechOids[i], oid)) + return &gssEapSaslMechs[i]; + } + + return GSS_C_NO_BUFFER; +} + +gss_OID +gssEapSaslNameToOid(const gss_buffer_t name) +{ + size_t i; + + for (i = 1; i < sizeof(gssEapSaslMechs)/sizeof(gssEapSaslMechs[0]); i++) { + if (bufferEqual(&gssEapSaslMechs[i], name)) + return &gssEapMechOids[i]; + } + + return GSS_C_NO_OID; +} diff --git a/mech_eap/util_moonshot.c b/mech_eap/util_moonshot.c new file mode 100644 index 0000000..68537a3 --- /dev/null +++ b/mech_eap/util_moonshot.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +#ifdef HAVE_MOONSHOT_GET_IDENTITY +#include + +static OM_uint32 +libMoonshotMapError(OM_uint32 *minor, + MoonshotError **pError) +{ + MoonshotError *error = *pError; + + GSSEAP_ASSERT(error != NULL); + + switch (error->code) { + case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE: + *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE; + break; + case MOONSHOT_ERROR_NO_IDENTITY_SELECTED: + *minor = GSSEAP_NO_IDENTITY_SELECTED; + break; + case MOONSHOT_ERROR_INSTALLATION_ERROR: + *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR; + break; + case MOONSHOT_ERROR_OS_ERROR: + *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR; + break; + case MOONSHOT_ERROR_IPC_ERROR: + *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR; + break; + default: + *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR; + break; + } + + gssEapSaveStatusInfo(*minor, error->message); + moonshot_error_free(error); + *pError = NULL; + + return GSS_S_CRED_UNAVAIL; +} + +OM_uint32 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_name_t *pName) +{ + OM_uint32 major, tmpMinor; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + gss_name_t name = GSS_C_NO_NAME; + gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER; + char *nai = NULL; + char *password = NULL; + char *serverCertificateHash = NULL; + char *caCertificate = NULL; + char *subjectNameConstraint = NULL; + char *subjectAltNameConstraint = NULL; + MoonshotError *error = NULL; + + *pName = GSS_C_NO_NAME; + + if (!moonshot_get_default_identity(&nai, + &password, + &serverCertificateHash, + &caCertificate, + &subjectNameConstraint, + &subjectAltNameConstraint, + &error)) { + if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_IDENTITY; + moonshot_error_free(error); + } else + major = libMoonshotMapError(minor, &error); + goto cleanup; + } + + tmpBuffer.value = nai; + tmpBuffer.length = strlen(nai); + + major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name); + if (GSS_ERROR(major)) + goto cleanup; + + *pName = name; + name = GSS_C_NO_NAME; + +cleanup: + moonshot_free(nai); + moonshot_free(password); + moonshot_free(serverCertificateHash); + moonshot_free(caCertificate); + moonshot_free(subjectNameConstraint); + moonshot_free(subjectAltNameConstraint); + + gssEapReleaseName(&tmpMinor, &name); + + return major; +} + +static int stringEmpty(const char * s) +{ + if (s == NULL) + return 1; + if (strlen(s) > 0) + return 0; + return 1; +} + +OM_uint32 +libMoonshotResolveInitiatorCred(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_name_t targetName) +{ + OM_uint32 major, tmpMinor; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER; + gss_buffer_desc target = GSS_C_EMPTY_BUFFER; + gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER; + char *nai = NULL; + char *password = NULL; + char *serverCertificateHash = NULL; + char *caCertificate = NULL; + char *subjectNameConstraint = NULL; + char *subjectAltNameConstraint = NULL; + MoonshotError *error = NULL; + + if (cred->name != GSS_C_NO_NAME) { + major = gssEapDisplayName(minor, cred->name, &initiator, NULL); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (targetName != GSS_C_NO_NAME) { + major = gssEapDisplayName(minor, targetName, &target, NULL); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (!moonshot_get_identity((const char *)initiator.value, + (const char *)cred->password.value, + (const char *)target.value, + &nai, + &password, + &serverCertificateHash, + &caCertificate, + &subjectNameConstraint, + &subjectAltNameConstraint, + &error)) { + major = libMoonshotMapError(minor, &error); + goto cleanup; + } + + gssEapReleaseName(&tmpMinor, &cred->name); + + tmpBuffer.value = nai; + tmpBuffer.length = strlen(nai); + + major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, + nameMech, &cred->name); + if (GSS_ERROR(major)) + goto cleanup; + + tmpBuffer.value = password; + tmpBuffer.length = strlen(password); + + major = gssEapSetCredPassword(minor, cred, &tmpBuffer); + if (GSS_ERROR(major)) + goto cleanup; + + gss_release_buffer(&tmpMinor, &cred->caCertificate); + gss_release_buffer(&tmpMinor, &cred->caCertificateBlob); + gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint); + gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint); + + if (!stringEmpty(serverCertificateHash)) { + size_t len = strlen(serverCertificateHash); + + #define HASH_PREFIX "hash://server/sha256/" + #define HASH_PREFIX_LEN (sizeof(HASH_PREFIX) - 1) + + cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1); + if (cred->caCertificate.value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN); + memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len); + + ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0'; + + cred->caCertificate.length = HASH_PREFIX_LEN + len; + } else if (!stringEmpty(caCertificate)) { + void *blobData; + ssize_t blobLength; + ssize_t maxLength = ((strlen(caCertificate) + 3) / 4) * 3; + if (maxLength < 3) { + major = GSS_S_FAILURE; + *minor = GSSEAP_BAD_CACERTIFICATE; + goto cleanup; + } + blobData = GSSEAP_MALLOC(maxLength); + if (blobData == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + blobLength = base64Decode(caCertificate, blobData); + + if (blobLength <= 0) { + major = GSS_S_DEFECTIVE_CREDENTIAL; + *minor = GSSEAP_BAD_CACERTIFICATE; + GSSEAP_FREE(blobData); + goto cleanup; + } + cred->caCertificateBlob.value = blobData; + cred->caCertificateBlob.length = blobLength; + makeStringBufferOrCleanup("blob://ca-cert", &cred->caCertificate); + } + + if (!stringEmpty(subjectNameConstraint)) + makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint); + if (!stringEmpty(subjectAltNameConstraint)) + makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint); + +cleanup: + moonshot_free(nai); + moonshot_free(password); + moonshot_free(serverCertificateHash); + moonshot_free(caCertificate); + moonshot_free(subjectNameConstraint); + moonshot_free(subjectAltNameConstraint); + + gss_release_buffer(&tmpMinor, &initiator); + gss_release_buffer(&tmpMinor, &target); + + return major; +} +#endif /* HAVE_MOONSHOT_GET_IDENTITY */ diff --git a/mech_eap/util_name.c b/mech_eap/util_name.c new file mode 100644 index 0000000..455e764 --- /dev/null +++ b/mech_eap/util_name.c @@ -0,0 +1,811 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Portions Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Name utility routines. + */ + +#include "gssapiP_eap.h" + +static gss_OID_desc gssEapNtEapName = { + /* 1.3.6.1.5.5.15.2.1 */ + 8, "\x2B\x06\x01\x05\x05\x0f\x02\x01" +}; + +gss_OID GSS_EAP_NT_EAP_NAME = &gssEapNtEapName; + +OM_uint32 +gssEapAllocName(OM_uint32 *minor, gss_name_t *pName) +{ + OM_uint32 tmpMinor; + gss_name_t name; + + *pName = GSS_C_NO_NAME; + + name = (gss_name_t)GSSEAP_CALLOC(1, sizeof(*name)); + if (name == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + if (GSSEAP_MUTEX_INIT(&name->mutex) != 0) { + *minor = GSSEAP_GET_LAST_ERROR(); + gssEapReleaseName(&tmpMinor, &name); + return GSS_S_FAILURE; + } + + *pName = name; + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName) +{ + gss_name_t name; + krb5_context krbContext = NULL; + OM_uint32 tmpMinor; + + *minor = 0; + + if (pName == NULL) { + return GSS_S_COMPLETE; + } + + name = *pName; + if (name == GSS_C_NO_NAME) { + return GSS_S_COMPLETE; + } + + GSSEAP_KRB_INIT(&krbContext); + krb5_free_principal(krbContext, name->krbPrincipal); + gssEapReleaseOid(&tmpMinor, &name->mechanismUsed); +#ifdef GSSEAP_ENABLE_ACCEPTOR + gssEapReleaseAttrContext(&tmpMinor, name); +#endif + + GSSEAP_MUTEX_DESTROY(&name->mutex); + GSSEAP_FREE(name); + *pName = NULL; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +krbPrincipalToName(OM_uint32 *minor, + krb5_principal *principal, + gss_name_t *pName) +{ + OM_uint32 major; + gss_name_t name; + + major = gssEapAllocName(minor, &name); + if (GSS_ERROR(major)) + return major; + + name->krbPrincipal = *principal; + *principal = NULL; + + if (KRB_PRINC_LENGTH(name->krbPrincipal) >= 1) { + name->flags |= NAME_FLAG_SERVICE; + } + if (KRB_PRINC_LENGTH(name->krbPrincipal) == 1) { + name->flags |= NAME_FLAG_NAI; + } + + *pName = name; + *minor = 0; + + return GSS_S_COMPLETE; +} + +static char * +gssEapGetDefaultRealm(krb5_context krbContext) +{ + char *defaultRealm = NULL; + + krb5_appdefault_string(krbContext, "eap_gss", + NULL, "default_realm", "", &defaultRealm); + + return defaultRealm; +} + +static OM_uint32 +importServiceName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *pName) +{ + OM_uint32 major; + krb5_error_code code; + krb5_context krbContext; + krb5_principal krbPrinc; + char *service, *host, *realm = NULL; + + GSSEAP_KRB_INIT(&krbContext); + + major = bufferToString(minor, nameBuffer, &service); + if (GSS_ERROR(major)) + return major; + + host = strchr(service, '@'); + if (host != NULL) { + *host = '\0'; + host++; + } + + realm = gssEapGetDefaultRealm(krbContext); + + code = krb5_build_principal(krbContext, + &krbPrinc, + realm != NULL ? strlen(realm) : 0, + realm != NULL ? realm : "", + service, + host, + NULL); + + if (code == 0) { + KRB_PRINC_TYPE(krbPrinc) = KRB5_NT_SRV_HST; + + major = krbPrincipalToName(minor, &krbPrinc, pName); + if (GSS_ERROR(major)) + krb5_free_principal(krbContext, krbPrinc); + } else { + major = GSS_S_FAILURE; + *minor = GSSEAP_BAD_SERVICE_NAME; + } + + if (realm != NULL) + krb5_free_default_realm(krbContext, realm); + GSSEAP_FREE(service); + + return major; +} + +#define IMPORT_FLAG_DEFAULT_REALM 0x1 + +/* + * Import an EAP name, possibly appending the default GSS EAP realm, + */ +static OM_uint32 +importEapNameFlags(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + OM_uint32 importFlags, + gss_name_t *pName) +{ + OM_uint32 major; + krb5_context krbContext; + krb5_principal krbPrinc = NULL; + krb5_error_code code; + char *nameString; + + GSSEAP_KRB_INIT(&krbContext); + + if (nameBuffer == GSS_C_NO_BUFFER) { + nameString = ""; + code = KRB5_PARSE_MALFORMED; + } else { + major = bufferToString(minor, nameBuffer, &nameString); + if (GSS_ERROR(major)) + return major; + + /* + * First, attempt to parse the name on the assumption that it includes + * a qualifying realm. This allows us to avoid accidentally appending + * the default Kerberos realm to an unqualified name. (A bug in MIT + * Kerberos prevents the default realm being set to an empty value.) + */ + code = krb5_parse_name_flags(krbContext, nameString, + KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &krbPrinc); + } + + if (code == KRB5_PARSE_MALFORMED) { + char *defaultRealm = NULL; + int parseFlags = 0; + + /* Possibly append the default EAP realm if required */ + if (importFlags & IMPORT_FLAG_DEFAULT_REALM) + defaultRealm = gssEapGetDefaultRealm(krbContext); + + /* If no default realm, leave the realm empty in the parsed name */ + if (defaultRealm == NULL || defaultRealm[0] == '\0') + parseFlags |= KRB5_PRINCIPAL_PARSE_NO_REALM; + + code = krb5_parse_name_flags(krbContext, nameString, parseFlags, &krbPrinc); + +#ifdef HAVE_HEIMDAL_VERSION + if (code == 0 && KRB_PRINC_REALM(krbPrinc) == NULL) { + KRB_PRINC_REALM(krbPrinc) = KRB_CALLOC(1, sizeof(char)); + if (KRB_PRINC_REALM(krbPrinc) == NULL) + code = ENOMEM; + } +#endif + + if (defaultRealm != NULL) + krb5_free_default_realm(krbContext, defaultRealm); + } + + if (nameBuffer != GSS_C_NO_BUFFER) + GSSEAP_FREE(nameString); + + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + + GSSEAP_ASSERT(krbPrinc != NULL); + + major = krbPrincipalToName(minor, &krbPrinc, pName); + if (GSS_ERROR(major)) + krb5_free_principal(krbContext, krbPrinc); + + return major; +} + +static OM_uint32 +importEapName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *pName) +{ + return importEapNameFlags(minor, nameBuffer, 0, pName); +} + +static OM_uint32 +importUserName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *pName) +{ + return importEapNameFlags(minor, nameBuffer, IMPORT_FLAG_DEFAULT_REALM, pName); +} + +static OM_uint32 +importAnonymousName(OM_uint32 *minor, + const gss_buffer_t nameBuffer GSSEAP_UNUSED, + gss_name_t *pName) +{ + return importEapNameFlags(minor, GSS_C_NO_BUFFER, 0, pName); +} + +#define UPDATE_REMAIN(n) do { \ + p += (n); \ + remain -= (n); \ + } while (0) + +#define CHECK_REMAIN(n) do { \ + if (remain < (n)) { \ + major = GSS_S_BAD_NAME; \ + *minor = GSSEAP_TOK_TRUNC; \ + goto cleanup; \ + } \ + } while (0) + +OM_uint32 +gssEapImportNameInternal(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *pName, + OM_uint32 flags) +{ + OM_uint32 major, tmpMinor; + krb5_context krbContext; + unsigned char *p; + size_t len, remain; + gss_buffer_desc buf; + gss_name_t name = GSS_C_NO_NAME; + gss_OID mechanismUsed = GSS_C_NO_OID; + + GSSEAP_KRB_INIT(&krbContext); + + p = (unsigned char *)nameBuffer->value; + remain = nameBuffer->length; + + if (flags & EXPORT_NAME_FLAG_OID) { + gss_OID_desc mech; + enum gss_eap_token_type tokType; + uint16_t wireTokType; + + /* TOK_ID || MECH_OID_LEN || MECH_OID */ + if (remain < 6) { + *minor = GSSEAP_BAD_NAME_TOKEN; + return GSS_S_BAD_NAME; + } + + if (flags & EXPORT_NAME_FLAG_COMPOSITE) + tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE; + else + tokType = TOK_TYPE_EXPORT_NAME; + + /* TOK_ID */ + wireTokType = load_uint16_be(p); + + if ((flags & EXPORT_NAME_FLAG_ALLOW_COMPOSITE) && + wireTokType == TOK_TYPE_EXPORT_NAME_COMPOSITE) { + tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE; + flags |= EXPORT_NAME_FLAG_COMPOSITE; + } + + if (wireTokType != tokType) { + *minor = GSSEAP_WRONG_TOK_ID; + return GSS_S_BAD_NAME; + } + UPDATE_REMAIN(2); + + /* MECH_OID_LEN */ + len = load_uint16_be(p); + if (len < 2) { + *minor = GSSEAP_BAD_NAME_TOKEN; + return GSS_S_BAD_NAME; + } + UPDATE_REMAIN(2); + + /* MECH_OID */ + if (p[0] != 0x06) { + *minor = GSSEAP_BAD_NAME_TOKEN; + return GSS_S_BAD_NAME; + } + + mech.length = p[1]; + mech.elements = &p[2]; + + CHECK_REMAIN(mech.length); + + major = gssEapCanonicalizeOid(minor, + &mech, + OID_FLAG_FAMILY_MECH_VALID | + OID_FLAG_MAP_FAMILY_MECH_TO_NULL, + &mechanismUsed); + if (GSS_ERROR(major)) + goto cleanup; + + UPDATE_REMAIN(2 + mech.length); + } + + /* NAME_LEN */ + CHECK_REMAIN(4); + len = load_uint32_be(p); + UPDATE_REMAIN(4); + + /* NAME */ + CHECK_REMAIN(len); + buf.length = len; + buf.value = p; + UPDATE_REMAIN(len); + + major = importEapNameFlags(minor, &buf, 0, &name); + if (GSS_ERROR(major)) + goto cleanup; + + name->mechanismUsed = mechanismUsed; + mechanismUsed = GSS_C_NO_OID; + +#ifdef GSSEAP_ENABLE_ACCEPTOR + if (flags & EXPORT_NAME_FLAG_COMPOSITE) { + gss_buffer_desc buf; + + buf.length = remain; + buf.value = p; + + major = gssEapImportAttrContext(minor, &buf, name); + if (GSS_ERROR(major)) + goto cleanup; + } +#endif + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) { + gssEapReleaseOid(&tmpMinor, &mechanismUsed); + gssEapReleaseName(&tmpMinor, &name); + } else { + *pName = name; + } + + return major; +} + +static OM_uint32 +importExportName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *name) +{ + return gssEapImportNameInternal(minor, nameBuffer, name, + EXPORT_NAME_FLAG_OID | + EXPORT_NAME_FLAG_ALLOW_COMPOSITE); +} + +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT +static OM_uint32 +importCompositeExportName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *name) +{ + return gssEapImportNameInternal(minor, nameBuffer, name, + EXPORT_NAME_FLAG_OID | + EXPORT_NAME_FLAG_COMPOSITE); +} +#endif + +struct gss_eap_name_import_provider { + gss_const_OID oid; + OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *); +}; + +OM_uint32 +gssEapImportName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + const gss_OID nameType, + const gss_OID mechType, + gss_name_t *pName) +{ + struct gss_eap_name_import_provider nameTypes[] = { + { GSS_EAP_NT_EAP_NAME, importEapName }, + { GSS_C_NT_USER_NAME, importUserName }, + { GSS_C_NT_HOSTBASED_SERVICE, importServiceName }, + { GSS_C_NT_HOSTBASED_SERVICE_X, importServiceName }, + { GSS_C_NT_ANONYMOUS, importAnonymousName }, + { GSS_C_NT_EXPORT_NAME, importExportName }, + { GSS_KRB5_NT_PRINCIPAL_NAME, importUserName }, +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT + { GSS_C_NT_COMPOSITE_EXPORT, importCompositeExportName }, +#endif + }; + size_t i; + OM_uint32 major = GSS_S_BAD_NAMETYPE; + OM_uint32 tmpMinor; + gss_name_t name = GSS_C_NO_NAME; + + for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) { + if (oidEqual(nameTypes[i].oid, + nameType == GSS_C_NO_OID ? GSS_EAP_NT_EAP_NAME : nameType)) { + major = nameTypes[i].import(minor, nameBuffer, &name); + break; + } + } + + if (major == GSS_S_COMPLETE && + mechType != GSS_C_NO_OID) { + GSSEAP_ASSERT(gssEapIsConcreteMechanismOid(mechType)); + GSSEAP_ASSERT(name != GSS_C_NO_NAME); + GSSEAP_ASSERT(name->mechanismUsed == GSS_C_NO_OID); + + major = gssEapCanonicalizeOid(minor, mechType, 0, &name->mechanismUsed); + } + + if (GSS_ERROR(major)) + gssEapReleaseName(&tmpMinor, &name); + else + *pName = name; + + return major; +} + +OM_uint32 +gssEapExportName(OM_uint32 *minor, + const gss_name_t name, + gss_buffer_t exportedName) +{ + return gssEapExportNameInternal(minor, name, exportedName, + EXPORT_NAME_FLAG_OID); +} + +OM_uint32 +gssEapExportNameInternal(OM_uint32 *minor, + const gss_name_t name, + gss_buffer_t exportedName, + OM_uint32 flags) +{ + OM_uint32 major = GSS_S_FAILURE, tmpMinor; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + size_t exportedNameLen; + unsigned char *p; + gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER; + gss_OID mech; + + exportedName->length = 0; + exportedName->value = NULL; + + if (name->mechanismUsed != GSS_C_NO_OID) + mech = name->mechanismUsed; + else + mech = GSS_EAP_MECHANISM; + + major = gssEapDisplayName(minor, name, &nameBuf, NULL); + if (GSS_ERROR(major)) + goto cleanup; + + exportedNameLen = 0; + if (flags & EXPORT_NAME_FLAG_OID) { + exportedNameLen += 6 + mech->length; + } + exportedNameLen += 4 + nameBuf.length; +#ifdef GSSEAP_ENABLE_ACCEPTOR + if (flags & EXPORT_NAME_FLAG_COMPOSITE) { + major = gssEapExportAttrContext(minor, name, &attrs); + if (GSS_ERROR(major)) + goto cleanup; + exportedNameLen += attrs.length; + } +#endif + + exportedName->value = GSSEAP_MALLOC(exportedNameLen); + if (exportedName->value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + exportedName->length = exportedNameLen; + + p = (unsigned char *)exportedName->value; + + if (flags & EXPORT_NAME_FLAG_OID) { + /* TOK | MECH_OID_LEN */ + store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE) + ? TOK_TYPE_EXPORT_NAME_COMPOSITE + : TOK_TYPE_EXPORT_NAME, + p); + p += 2; + store_uint16_be(mech->length + 2, p); + p += 2; + + /* MECH_OID */ + *p++ = 0x06; + *p++ = mech->length & 0xff; + memcpy(p, mech->elements, mech->length); + p += mech->length; + } + + /* NAME_LEN */ + store_uint32_be(nameBuf.length, p); + p += 4; + + /* NAME */ + memcpy(p, nameBuf.value, nameBuf.length); + p += nameBuf.length; + + if (flags & EXPORT_NAME_FLAG_COMPOSITE) { + memcpy(p, attrs.value, attrs.length); + p += attrs.length; + } + + GSSEAP_ASSERT(p == (unsigned char *)exportedName->value + exportedNameLen); + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + gss_release_buffer(&tmpMinor, &attrs); + gss_release_buffer(&tmpMinor, &nameBuf); + if (GSS_ERROR(major)) + gss_release_buffer(&tmpMinor, exportedName); + + return major; +} + +OM_uint32 +gssEapCanonicalizeName(OM_uint32 *minor, + const gss_name_t input_name, + const gss_OID mech_type, + gss_name_t *dest_name) +{ + OM_uint32 major, tmpMinor; + krb5_context krbContext; + gss_name_t name; + gss_OID mech_used; + + if (input_name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + GSSEAP_KRB_INIT(&krbContext); + + major = gssEapAllocName(minor, &name); + if (GSS_ERROR(major)) { + return major; + } + + if (mech_type != GSS_C_NO_OID) + mech_used = mech_type; + else + mech_used = input_name->mechanismUsed; + + major = gssEapCanonicalizeOid(minor, + mech_used, + OID_FLAG_NULL_VALID, + &name->mechanismUsed); + if (GSS_ERROR(major)) + goto cleanup; + + name->flags = input_name->flags; + + *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal, + &name->krbPrincipal); + if (*minor != 0) { + major = GSS_S_FAILURE; + goto cleanup; + } + +#ifdef GSSEAP_ENABLE_ACCEPTOR + if (input_name->attrCtx != NULL) { + major = gssEapDuplicateAttrContext(minor, input_name, name); + if (GSS_ERROR(major)) + goto cleanup; + } +#endif + + *dest_name = name; + +cleanup: + if (GSS_ERROR(major)) { + gssEapReleaseName(&tmpMinor, &name); + } + + return major; +} + +OM_uint32 +gssEapDuplicateName(OM_uint32 *minor, + const gss_name_t input_name, + gss_name_t *dest_name) +{ + return gssEapCanonicalizeName(minor, input_name, + GSS_C_NO_OID, dest_name); +} + +static int +hasRealmP(gss_name_t name) +{ +#ifdef HAVE_HEIMDAL_VERSION + if (KRB_PRINC_REALM(name->krbPrincipal) != NULL && + KRB_PRINC_REALM(name->krbPrincipal)[0] != '\0') +#else + if (KRB_PRINC_REALM(name->krbPrincipal)->length != 0) +#endif + return TRUE; + + return FALSE; +} + +OM_uint32 +gssEapDisplayName(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) +{ + OM_uint32 major; + krb5_context krbContext; + char *krbName; + gss_OID name_type; + int flags = 0; + + GSSEAP_KRB_INIT(&krbContext); + + output_name_buffer->length = 0; + output_name_buffer->value = NULL; + + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + } + + /* + * According to draft-ietf-abfab-gss-eap-01, when the realm is + * absent the trailing '@' is not included. + */ + if (!hasRealmP(name)) + flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM; + + *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal, + flags, &krbName); + if (*minor != 0) { + return GSS_S_FAILURE; + } + + major = makeStringBuffer(minor, krbName, output_name_buffer); +#ifdef HAVE_HEIMDAL_VERSION + krb5_xfree(krbName); +#else + krb5_free_unparsed_name(krbContext, krbName); +#endif + if (GSS_ERROR(major)) + return major; + + if (output_name_buffer->length == 0) { + name_type = GSS_C_NT_ANONYMOUS; + } else if (name->flags & NAME_FLAG_NAI) { + name_type = GSS_C_NT_USER_NAME; + } else { + name_type = GSS_EAP_NT_EAP_NAME; + } + + if (output_name_type != NULL) + *output_name_type = name_type; + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapCompareName(OM_uint32 *minor, + gss_name_t name1, + gss_name_t name2, + OM_uint32 flags, + int *name_equal) +{ + krb5_context krbContext; + + *minor = 0; + + if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) { + *name_equal = 1; + } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) { + GSSEAP_KRB_INIT(&krbContext); + + /* krbPrincipal is immutable, so lock not required */ + if ((flags & COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS) && + (hasRealmP(name1) == FALSE || hasRealmP(name2) == FALSE)) { + *name_equal = krb5_principal_compare_any_realm(krbContext, + name1->krbPrincipal, + name2->krbPrincipal); + } else { + *name_equal = krb5_principal_compare(krbContext, + name1->krbPrincipal, + name2->krbPrincipal); + } + } else { + *name_equal = 0; + } + + return GSS_S_COMPLETE; +} diff --git a/mech_eap/util_oid.c b/mech_eap/util_oid.c new file mode 100644 index 0000000..096c9f8 --- /dev/null +++ b/mech_eap/util_oid.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 1995-2010 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * OID utility routines. + */ + +#include "gssapiP_eap.h" + +OM_uint32 +duplicateOid(OM_uint32 *minor, + const gss_OID_desc * const oid, + gss_OID *newOid) +{ + gss_OID p; + + *newOid = GSS_C_NO_OID; + + p = (gss_OID)GSSEAP_MALLOC(sizeof(*p)); + if (p == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + p->length = oid->length; + p->elements = GSSEAP_MALLOC(p->length); + if (p->elements == NULL) { + GSSEAP_FREE(p); + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(p->elements, oid->elements, p->length); + *newOid = p; + + *minor = 0; + return GSS_S_COMPLETE; +} + +/* Compose an OID of a prefix and an integer suffix */ +OM_uint32 +composeOid(OM_uint32 *minor, + const char *prefix, + size_t prefix_len, + int suffix, + gss_OID_desc *oid) +{ + int osuffix, i; + size_t nbytes; + unsigned char *op; + + if (oid == GSS_C_NO_OID) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE; + } + + if (oid->length < prefix_len) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_FAILURE; + } + + memcpy(oid->elements, prefix, prefix_len); + + nbytes = 0; + osuffix = suffix; + while (suffix) { + nbytes++; + suffix >>= 7; + } + suffix = osuffix; + + if (oid->length < prefix_len + nbytes) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_FAILURE; + } + + op = (unsigned char *) oid->elements + prefix_len + nbytes; + i = -1; + while (suffix) { + op[i] = (unsigned char)suffix & 0x7f; + if (i != -1) + op[i] |= 0x80; + i--; + suffix >>= 7; + } + + oid->length = prefix_len + nbytes; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +decomposeOid(OM_uint32 *minor, + const char *prefix, + size_t prefix_len, + gss_OID_desc *oid, + int *suffix) +{ + size_t i, slen; + unsigned char *op; + + if (oid->length < prefix_len || + memcmp(oid->elements, prefix, prefix_len) != 0) { + return GSS_S_BAD_MECH; + } + + op = (unsigned char *) oid->elements + prefix_len; + + *suffix = 0; + + slen = oid->length - prefix_len; + + for (i = 0; i < slen; i++) { + *suffix = (*suffix << 7) | (op[i] & 0x7f); + if (i + 1 != slen && (op[i] & 0x80) == 0) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_FAILURE; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +duplicateOidSet(OM_uint32 *minor, + const gss_OID_set src, + gss_OID_set *dst) +{ + OM_uint32 major, tmpMinor; + int i; + + if (src == GSS_C_NO_OID_SET) { + *dst = GSS_C_NO_OID_SET; + return GSS_S_COMPLETE; + } + + major = gss_create_empty_oid_set(minor, dst); + if (GSS_ERROR(major)) + return major; + + for (i = 0; i < src->count; i++) { + gss_OID oid = &src->elements[i]; + + major = gss_add_oid_set_member(minor, oid, dst); + if (GSS_ERROR(major)) + break; + } + + if (GSS_ERROR(major)) + gss_release_oid_set(&tmpMinor, dst); + + return major; +} diff --git a/mech_eap/util_ordering.c b/mech_eap/util_ordering.c new file mode 100644 index 0000000..bb7e4d5 --- /dev/null +++ b/mech_eap/util_ordering.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Functions to check sequence numbers for replay and sequencing + */ + +#include "gssapiP_eap.h" + +#define QUEUE_LENGTH 20 + +typedef struct _queue { + int do_replay; + int do_sequence; + int start; + int length; + uint64_t firstnum; + /* Stored as deltas from firstnum. This way, the high bit won't + overflow unless we've actually gone through 2**n messages, or + gotten something *way* out of sequence. */ + uint64_t elem[QUEUE_LENGTH]; + /* All ones for 64-bit sequence numbers; 32 ones for 32-bit + sequence numbers. */ + uint64_t mask; +} queue; + +/* rep invariant: + * - the queue is a circular queue. The first element (q->elem[q->start]) + * is the oldest. The last element is the newest. + */ + +#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0])) +#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)]) + +static void +queue_insert(queue *q, int after, uint64_t seqnum) +{ + /* insert. this is not the fastest way, but it's easy, and it's + optimized for insert at end, which is the common case */ + int i; + + /* common case: at end, after == q->start+q->length-1 */ + + /* move all the elements (after,last] up one slot */ + + for (i = q->start + q->length - 1; i > after; i--) + QELEM(q,i+1) = QELEM(q,i); + + /* fill in slot after+1 */ + + QELEM(q,after+1) = seqnum; + + /* Either increase the length by one, or move the starting point up + one (deleting the first element, which got bashed above), as + appropriate. */ + + if (q->length == QSIZE(q)) { + q->start++; + if (q->start == QSIZE(q)) + q->start = 0; + } else { + q->length++; + } +} + +OM_uint32 +sequenceInit(OM_uint32 *minor, + void **vqueue, + uint64_t seqnum, + int do_replay, + int do_sequence, + int wide_nums) +{ + queue *q; + + q = (queue *)GSSEAP_CALLOC(1, sizeof(queue)); + if (q == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + q->do_replay = do_replay; + q->do_sequence = do_sequence; + q->mask = wide_nums ? ~(uint64_t)0 : 0xffffffffUL; + + q->start = 0; + q->length = 1; + q->firstnum = seqnum; + q->elem[q->start] = ((uint64_t)0 - 1) & q->mask; + + *vqueue = (void *)q; + + return GSS_S_COMPLETE; +} + +OM_uint32 +sequenceCheck(OM_uint32 *minor, + void **vqueue, + uint64_t seqnum) +{ + queue *q; + int i; + uint64_t expected; + + *minor = 0; + + q = (queue *) (*vqueue); + + if (!q->do_replay && !q->do_sequence) + return GSS_S_COMPLETE; + + /* All checks are done relative to the initial sequence number, to + avoid (or at least put off) the pain of wrapping. */ + seqnum -= q->firstnum; + /* If we're only doing 32-bit values, adjust for that again. + + Note that this will probably be the wrong thing to if we get + 2**32 messages sent with 32-bit sequence numbers. */ + seqnum &= q->mask; + + /* rule 1: expected sequence number */ + + expected = (QELEM(q,q->start+q->length-1)+1) & q->mask; + if (seqnum == expected) { + queue_insert(q, q->start+q->length-1, seqnum); + return GSS_S_COMPLETE; + } + + /* rule 2: > expected sequence number */ + + if ((seqnum > expected)) { + queue_insert(q, q->start+q->length-1, seqnum); + if (q->do_replay && !q->do_sequence) + return GSS_S_COMPLETE; + else + return GSS_S_GAP_TOKEN; + } + + /* rule 3: seqnum < seqnum(first) */ + + if ((seqnum < QELEM(q,q->start)) && + /* Is top bit of whatever width we're using set? + + We used to check for greater than or equal to firstnum, but + (1) we've since switched to compute values relative to + firstnum, so the lowest we can have is 0, and (2) the effect + of the original scheme was highly dependent on whether + firstnum was close to either side of 0. (Consider + firstnum==0xFFFFFFFE and we miss three packets; the next + packet is *new* but would look old.) + + This check should give us 2**31 or 2**63 messages "new", and + just as many "old". That's not quite right either. */ + (seqnum & (1 + (q->mask >> 1))) + ) { + if (q->do_replay && !q->do_sequence) + return GSS_S_OLD_TOKEN; + else + return GSS_S_UNSEQ_TOKEN; + } + + /* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */ + + else { + if (seqnum == QELEM(q,q->start+q->length - 1)) + return GSS_S_DUPLICATE_TOKEN; + + for (i = q->start; i < q->start + q->length - 1; i++) { + if (seqnum == QELEM(q,i)) + return GSS_S_DUPLICATE_TOKEN; + if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) { + queue_insert(q, i, seqnum); + if (q->do_replay && !q->do_sequence) + return GSS_S_COMPLETE; + else + return GSS_S_UNSEQ_TOKEN; + } + } + } + + /* this should never happen */ + return GSS_S_FAILURE; +} + +OM_uint32 +sequenceFree(OM_uint32 *minor, void **vqueue) +{ + queue *q; + + q = (queue *) (*vqueue); + + GSSEAP_FREE(q); + + *vqueue = NULL; + + *minor = 0; + return GSS_S_COMPLETE; +} + +/* + * These support functions are for the serialization routines + */ +size_t +sequenceSize(void *vqueue GSSEAP_UNUSED) +{ + return sizeof(queue); +} + +OM_uint32 +sequenceExternalize(OM_uint32 *minor, + void *vqueue, + unsigned char **buf, + size_t *lenremain) +{ + if (*lenremain < sizeof(queue)) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_FAILURE; + } + if (vqueue != NULL) + memcpy(*buf, vqueue, sizeof(queue)); + else + memset(*buf, 0, sizeof(queue)); + *buf += sizeof(queue); + *lenremain -= sizeof(queue); + + return 0; +} + +OM_uint32 +sequenceInternalize(OM_uint32 *minor, + void **vqueue, + unsigned char **buf, + size_t *lenremain) +{ + void *q; + + if (*lenremain < sizeof(queue)) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + q = GSSEAP_MALLOC(sizeof(queue)); + if (q == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(q, *buf, sizeof(queue)); + *buf += sizeof(queue); + *lenremain -= sizeof(queue); + *vqueue = q; + + *minor = 0; + return GSS_S_COMPLETE; +} diff --git a/mech_eap/util_radius.cpp b/mech_eap/util_radius.cpp new file mode 100644 index 0000000..d8ec3df --- /dev/null +++ b/mech_eap/util_radius.cpp @@ -0,0 +1,954 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * RADIUS attribute provider implementation. + */ + +#include "gssapiP_eap.h" +#include "util_radius.h" +#include "utils/radius_utils.h" + +#ifdef GSSEAP_ENABLE_ACCEPTOR + +#define RS_MAP_ERROR(code) (ERROR_TABLE_BASE_rse + (code)) + +static rs_avp *copyAvps(rs_const_avp *src); + +static OM_uint32 +gssEapRadiusGetAvp(OM_uint32 *minor, + rs_avp *vps, + const gss_eap_attrid &attrid, + gss_buffer_t buffer, + int concat); + +static OM_uint32 +gssEapRadiusAddAvp(OM_uint32 *minor, + rs_avp **vps, + const gss_eap_attrid &attrid, + const gss_buffer_t buffer); + +static gss_eap_attrid +avpToAttrId(rs_const_avp *vp) +{ + gss_eap_attrid attrid; + + rs_avp_attrid(vp, &attrid.second, &attrid.first); + + return attrid; +} + +gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void) +{ + m_vps = NULL; + m_authenticated = false; +} + +gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void) +{ + if (m_vps != NULL) + rs_avp_free(&m_vps); +} + +bool +gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager, + const gss_eap_attr_provider *ctx) +{ + const gss_eap_radius_attr_provider *radius; + + if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) + return false; + + radius = static_cast(ctx); + + if (radius->m_vps != NULL) + m_vps = copyAvps(radius->getAvps()); + + m_authenticated = radius->m_authenticated; + + return true; +} + +bool +gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager, + const gss_cred_id_t gssCred, + const gss_ctx_id_t gssCtx) +{ + if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx)) + return false; + + if (gssCtx != GSS_C_NO_CONTEXT) { + if (gssCtx->acceptorCtx.vps != NULL) { + m_vps = copyAvps(gssCtx->acceptorCtx.vps); + if (m_vps == NULL) + return false; + + /* We assume libradsec validated this for us */ + GSSEAP_ASSERT(rs_avp_find(m_vps, PW_MESSAGE_AUTHENTICATOR, 0) != NULL); + m_authenticated = true; + } + } + + return true; +} + +static bool +alreadyAddedAttributeP(std::vector &attrs, + gss_eap_attrid &attrid) +{ + for (std::vector::const_iterator a = attrs.begin(); + a != attrs.end(); + ++a) { + if (attrid.first == (*a).first && + attrid.second == (*a).second) + return true; + } + + return false; +} + +static bool +isSecretAttributeP(const gss_eap_attrid &attrid) +{ + bool bSecretAttribute = false; + + switch (attrid.first) { + case VENDORPEC_MICROSOFT: + switch (attrid.second) { + case PW_MS_MPPE_SEND_KEY: + case PW_MS_MPPE_RECV_KEY: + bSecretAttribute = true; + break; + default: + break; + } + default: + break; + } + + return bSecretAttribute; +} + +static bool +isSecretAttributeP(rs_const_avp *vp) +{ + return isSecretAttributeP(avpToAttrId(vp)); +} + +static bool +isInternalAttributeP(const gss_eap_attrid &attrid) +{ + bool bInternalAttribute = false; + + /* should have been filtered */ + GSSEAP_ASSERT(!isSecretAttributeP(attrid)); + + switch (attrid.first) { + case VENDORPEC_UKERNA: + switch (attrid.second) { + case PW_SAML_AAA_ASSERTION: + bInternalAttribute = true; + break; + default: + break; + } + break; + case 0: + switch (attrid.second) { + case PW_GSS_ACCEPTOR_SERVICE_NAME: + case PW_GSS_ACCEPTOR_HOST_NAME: + case PW_GSS_ACCEPTOR_SERVICE_SPECIFICS: + case PW_GSS_ACCEPTOR_REALM_NAME: + bInternalAttribute = true; + break; + default: + break; + } + break; + default: + break; + } + + return bInternalAttribute; +} + +static bool +isInternalAttributeP(rs_const_avp *vp) +{ + return isInternalAttributeP(avpToAttrId(vp)); +} + +static bool +isFragmentedAttributeP(const gss_eap_attrid &attrid) +{ + /* A bit of a hack for the PAC for now. Should be configurable. */ + return (attrid.first == VENDORPEC_UKERNA) && + !isInternalAttributeP(attrid); +} + +/* + * Copy AVP list, same as paircopy except it filters out attributes + * containing keys. + */ +static rs_avp * +copyAvps(rs_const_avp *src) +{ + rs_const_avp *vp; + rs_avp *dst = NULL; + + for (vp = src; vp != NULL; vp = rs_avp_next_const(vp)) { + rs_avp *vpcopy; + + if (isSecretAttributeP(vp)) + continue; + + vpcopy = rs_avp_dup(vp); + if (vpcopy == NULL) { + rs_avp_free(&dst); + throw std::bad_alloc(); + } + + rs_avp_append(&dst, vpcopy); + } + + return dst; +} + +bool +gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, + void *data) const +{ + rs_avp *vp; + std::vector seen; + + for (vp = m_vps; vp != NULL; vp = rs_avp_next(vp)) { + gss_buffer_desc desc; + gss_eap_attrid attrid; + char buf[64]; + + /* Don't advertise attributes that are internal to the GSS-EAP mechanism */ + if (isInternalAttributeP(vp)) + continue; + + rs_avp_attrid(vp, &attrid.second, &attrid.first); + + if (alreadyAddedAttributeP(seen, attrid)) + continue; + + if (rs_attr_display_name(attrid.second, attrid.first, + buf, sizeof(buf), TRUE) != RSE_OK || + strncmp(buf, "Attr-", 5) != 0) + continue; + + desc.value = &buf[5]; + desc.length = strlen((char *)desc.value); + + if (!addAttribute(m_manager, this, &desc, data)) + return false; + + seen.push_back(attrid); + } + + return true; +} + +static bool +getAttributeId(const gss_buffer_t desc, + gss_eap_attrid *attrid) +{ + char *strAttr, *s; + int canon, code; + + if (desc->length == 0) + return false; + + canon = isdigit(*(char *)desc->value); + + /* need to duplicate because attr may not be NUL terminated */ + strAttr = (char *)GSSEAP_MALLOC((canon ? 5 : 0) + desc->length + 1); + if (strAttr == NULL) + throw new std::bad_alloc(); + + s = strAttr; + + if (canon) { + memcpy(s, "Attr-", 5); + s += 5; + } + + memcpy(s, desc->value, desc->length); + s += desc->length; + *s = '\0'; + + code = rs_attr_parse_name(strAttr, &attrid->second, &attrid->first); + + GSSEAP_FREE(strAttr); + + return (code == RSE_OK); +} + +bool +gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED, + const gss_eap_attrid &attrid, + const gss_buffer_t value) +{ + OM_uint32 major = GSS_S_UNAVAILABLE, minor; + + if (!isSecretAttributeP(attrid) && + !isInternalAttributeP(attrid)) { + deleteAttribute(attrid); + + major = gssEapRadiusAddAvp(&minor, &m_vps, attrid, value); + } + + return !GSS_ERROR(major); +} + +bool +gss_eap_radius_attr_provider::setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value) +{ + gss_eap_attrid attrid; + + if (!getAttributeId(attr, &attrid)) + return false; + + return setAttribute(complete, attrid, value); +} + +bool +gss_eap_radius_attr_provider::deleteAttribute(const gss_eap_attrid &attrid) +{ + if (isSecretAttributeP(attrid) || + isInternalAttributeP(attrid) || + rs_avp_find(m_vps, attrid.second, attrid.first) == NULL) + return false; + + return (rs_avp_delete(&m_vps, attrid.second, attrid.first) == RSE_OK); +} + +bool +gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr) +{ + gss_eap_attrid attrid; + + if (!getAttributeId(attr, &attrid)) + return false; + + return deleteAttribute(attrid); +} + +bool +gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const +{ + gss_eap_attrid attrid; + + if (!getAttributeId(attr, &attrid)) + return false; + + return getAttribute(attrid, + authenticated, complete, + value, display_value, more); +} + +bool +gss_eap_radius_attr_provider::getAttribute(const gss_eap_attrid &attrid, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const +{ + rs_const_avp *vp; + int i = *more, count = 0; + + *more = 0; + + if (i == -1) + i = 0; + + if (isSecretAttributeP(attrid) || + isInternalAttributeP(attrid)) { + return false; + } else if (isFragmentedAttributeP(attrid)) { + return getFragmentedAttribute(attrid, + authenticated, + complete, + value); + } + + for (vp = rs_avp_find_const(m_vps, attrid.second, attrid.first); + vp != NULL; + vp = rs_avp_find_const(rs_avp_next_const(vp), attrid.second, attrid.first)) { + if (count++ == i) { + if (rs_avp_find_const(rs_avp_next_const(vp), attrid.second, attrid.first) != NULL) + *more = count; + break; + } + } + + if (vp == NULL && *more == 0) + return false; + + if (value != GSS_C_NO_BUFFER) { + gss_buffer_desc valueBuf; + + rs_avp_octets_value_byref((rs_avp *)vp, + (unsigned char **)&valueBuf.value, + &valueBuf.length); + + duplicateBuffer(valueBuf, value); + } + + if (display_value != GSS_C_NO_BUFFER && + !rs_avp_is_octets(vp)) { + char displayString[RS_MAX_STRING_LEN]; + gss_buffer_desc displayBuf; + + displayBuf.length = rs_avp_display_value(vp, displayString, + sizeof(displayString)); + displayBuf.value = (void *)displayString; + + duplicateBuffer(displayBuf, display_value); + } + + if (authenticated != NULL) + *authenticated = m_authenticated; + if (complete != NULL) + *complete = true; + + return true; +} + +bool +gss_eap_radius_attr_provider::getFragmentedAttribute(const gss_eap_attrid &attrid, + int *authenticated, + int *complete, + gss_buffer_t value) const +{ + OM_uint32 major, minor; + + major = gssEapRadiusGetAvp(&minor, m_vps, attrid, value, TRUE); + + if (authenticated != NULL) + *authenticated = m_authenticated; + if (complete != NULL) + *complete = true; + + return !GSS_ERROR(major); +} + +gss_any_t +gss_eap_radius_attr_provider::mapToAny(int authenticated, + gss_buffer_t type_id GSSEAP_UNUSED) const +{ + if (authenticated && !m_authenticated) + return (gss_any_t)NULL; + + return (gss_any_t)copyAvps(m_vps); +} + +void +gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED, + gss_any_t input) const +{ + rs_avp *vp = (rs_avp *)input; + rs_avp_free(&vp); +} + +bool +gss_eap_radius_attr_provider::init(void) +{ + gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, createAttrContext); + + return true; +} + +void +gss_eap_radius_attr_provider::finalize(void) +{ + gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS); +} + +gss_eap_attr_provider * +gss_eap_radius_attr_provider::createAttrContext(void) +{ + return new gss_eap_radius_attr_provider; +} + +static OM_uint32 +gssEapRadiusAddAvp(OM_uint32 *minor, + rs_avp **vps, + const gss_eap_attrid &attrid, + const gss_buffer_t buffer) +{ + unsigned char *p = (unsigned char *)buffer->value; + size_t remain = buffer->length; + + do { + rs_avp *vp; + size_t n = remain; + + /* + * There's an extra byte of padding; RADIUS AVPs can only + * be 253 octets. + */ + if (n >= RS_MAX_STRING_LEN) + n = RS_MAX_STRING_LEN - 1; + + vp = rs_avp_alloc(attrid.second, attrid.first); + if (vp == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + rs_avp_octets_set(vp, p, n); + + rs_avp_append(vps, vp); + + p += n; + remain -= n; + } while (remain != 0); + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapRadiusAddAvp(OM_uint32 *minor, + struct rs_packet *pkt, + unsigned int attribute, + unsigned int vendor, + const gss_buffer_t buffer) +{ + gss_eap_attrid attrid(vendor, attribute); + int code; + + code = rs_packet_append_avp(pkt, attrid.second, attrid.first, + buffer->value, buffer->length); + if (code != RSE_OK) { + *minor = RS_MAP_ERROR(code); + return GSS_S_FAILURE; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapRadiusGetRawAvp(OM_uint32 *minor, + rs_const_avp *vps, + unsigned int attribute, + unsigned int vendor, + rs_const_avp **vp) +{ + *vp = rs_avp_find_const(vps, attribute, vendor); + if (*vp == NULL) { + *minor = GSSEAP_NO_SUCH_ATTR; + return GSS_S_UNAVAILABLE; + } + + return GSS_S_COMPLETE; +} + +static OM_uint32 +gssEapRadiusGetAvp(OM_uint32 *minor, + rs_avp *vps, + const gss_eap_attrid &attrid, + gss_buffer_t buffer, + int concat) +{ + rs_const_avp *vp; + int err; + + if (buffer != GSS_C_NO_BUFFER) { + buffer->length = 0; + buffer->value = NULL; + } + + vp = rs_avp_find_const(vps, attrid.second, attrid.first); + if (vp == NULL) { + *minor = GSSEAP_NO_SUCH_ATTR; + return GSS_S_UNAVAILABLE; + } + + if (buffer != GSS_C_NO_BUFFER) { + if (concat) + rs_avp_fragmented_value(vp, NULL, &buffer->length); + else + buffer->length = rs_avp_length(vp); + + buffer->value = GSSEAP_MALLOC(buffer->length); + if (buffer->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + if (concat) + err = rs_avp_fragmented_value(vp, (unsigned char *)buffer->value, &buffer->length); + else + err = rs_avp_octets_value(vp, (unsigned char *)buffer->value, &buffer->length); + + if (err != 0) { + *minor = RS_MAP_ERROR(err); + return GSS_S_FAILURE; + } + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapRadiusGetAvp(OM_uint32 *minor, + struct rs_packet *pkt, + unsigned int attribute, + unsigned int vendor, + gss_buffer_t buffer, + int concat) +{ + rs_avp **vps; + gss_eap_attrid attrid(vendor, attribute); + + rs_packet_avps(pkt, &vps); + + return gssEapRadiusGetAvp(minor, *vps, attrid, buffer, concat); +} + +OM_uint32 +gssEapRadiusFreeAvps(OM_uint32 *minor, + rs_avp **vps) +{ + rs_avp_free(vps); + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapRadiusAttrProviderInit(OM_uint32 *minor) +{ + if (!gss_eap_radius_attr_provider::init()) { + *minor = GSSEAP_RADSEC_INIT_FAILURE; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapRadiusAttrProviderFinalize(OM_uint32 *minor) +{ + gss_eap_radius_attr_provider::finalize(); + + *minor = 0; + return GSS_S_COMPLETE; +} + +static JSONObject +avpToJson(rs_const_avp *vp) +{ + JSONObject obj; + gss_eap_attrid attrid; + + GSSEAP_ASSERT(rs_avp_length(vp) <= RS_MAX_STRING_LEN); + + switch (rs_avp_typeof(vp)) { + case RS_TYPE_INTEGER: + obj.set("value", rs_avp_integer_value(vp)); + break; + case RS_TYPE_DATE: + obj.set("value", rs_avp_date_value(vp)); + break; + case RS_TYPE_STRING: + obj.set("value", rs_avp_string_value(vp)); + break; + default: { + char *b64; + + if (base64Encode(rs_avp_octets_value_const_ptr(vp), + rs_avp_length(vp), &b64) < 0) + throw std::bad_alloc(); + + obj.set("value", b64); + GSSEAP_FREE(b64); + break; + } + } + + attrid = avpToAttrId(vp); + + obj.set("type", attrid.second); + if (attrid.first != 0) + obj.set("vendor", attrid.first); + + return obj; +} + +static bool +jsonToAvp(rs_avp **pVp, JSONObject &obj) +{ + rs_avp *vp = NULL; + gss_eap_attrid attrid; + + JSONObject type = obj["type"]; + JSONObject vendor = obj["vendor"]; + JSONObject value = obj["value"]; + + if (!type.isInteger()) + goto fail; + attrid.second = type.integer(); + + if (!vendor.isNull()) { + if (!vendor.isInteger()) + goto fail; + attrid.first = vendor.integer(); + } else { + attrid.first = 0; + } + + vp = rs_avp_alloc(attrid.second, attrid.first); + if (vp == NULL) + throw std::bad_alloc(); + + switch (rs_avp_typeof(vp)) { + case RS_TYPE_INTEGER: + case RS_TYPE_IPADDR: + case RS_TYPE_DATE: + if (!value.isInteger()) + goto fail; + + if (rs_avp_integer_set(vp, value.integer()) != RSE_OK) + goto fail; + + break; + case RS_TYPE_STRING: { + if (!value.isString()) + goto fail; + + if (rs_avp_string_set(vp, value.string()) != RSE_OK) + goto fail; + + break; + } + case RS_TYPE_OCTETS: + default: { + unsigned char buf[RS_MAX_STRING_LEN]; + + if (!value.isString()) + goto fail; + + const char *str = value.string(); + ssize_t len = strlen(str); + + /* this optimization requires base64Decode only understand packed encoding */ + if (len >= BASE64_EXPAND(RS_MAX_STRING_LEN)) + goto fail; + + len = base64Decode(str, buf); + if (len < 0) + goto fail; + + if (rs_avp_octets_set(vp, buf, len) != RSE_OK) + goto fail; + + break; + } + } + + *pVp = vp; + + return true; + +fail: + if (vp != NULL) + rs_avp_free(&vp); + *pVp = NULL; + return false; +} + +const char * +gss_eap_radius_attr_provider::name(void) const +{ + return "radius"; +} + +bool +gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx, + JSONObject &obj) +{ + if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj)) + return false; + + JSONObject attrs = obj["attributes"]; + size_t nelems = attrs.size(); + + for (size_t i = 0; i < nelems; i++) { + JSONObject attr = attrs[i]; + rs_avp *vp; + + if (!jsonToAvp(&vp, attr)) + return false; + + rs_avp_append(&m_vps, vp); + } + + m_authenticated = obj["authenticated"].integer() ? true : false; + + return true; +} + +const char * +gss_eap_radius_attr_provider::prefix(void) const +{ + return "urn:ietf:params:gss:radius-attribute"; +} + +JSONObject +gss_eap_radius_attr_provider::jsonRepresentation(void) const +{ + JSONObject obj, attrs = JSONObject::array(); + + for (rs_avp *vp = m_vps; vp != NULL; vp = rs_avp_next(vp)) { + JSONObject attr = avpToJson(vp); + attrs.append(attr); + } + + obj.set("attributes", attrs); + + obj.set("authenticated", m_authenticated); + + return obj; +} + +time_t +gss_eap_radius_attr_provider::getExpiryTime(void) const +{ + rs_const_avp *vp; + uint32_t value; + + vp = rs_avp_find(m_vps, PW_SESSION_TIMEOUT, 0); + if (vp == NULL) + return 0; + + value = rs_avp_integer_value(vp); + if (value == 0) + return 0; + + return time(NULL) + value; +} + +OM_uint32 +gssEapRadiusMapError(OM_uint32 *minor, + struct rs_error *err) +{ + int code; + + GSSEAP_ASSERT(err != NULL); + + code = rs_err_code(err, 0); + + if (code == RSE_OK) { + *minor = 0; + return GSS_S_COMPLETE; + } + + *minor = RS_MAP_ERROR(code); + + gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err)); + rs_err_free(err); + + return GSS_S_FAILURE; +} + +OM_uint32 +gssEapCreateRadiusContext(OM_uint32 *minor, + gss_cred_id_t cred, + struct rs_context **pRadContext) +{ + const char *configFile = RS_CONFIG_FILE; + struct rs_context *radContext; + struct rs_alloc_scheme ralloc; + struct rs_error *err; + OM_uint32 major; + + *pRadContext = NULL; + + if (rs_context_create(&radContext) != 0) { + *minor = GSSEAP_RADSEC_CONTEXT_FAILURE; + return GSS_S_FAILURE; + } + + if (cred->radiusConfigFile.value != NULL) + configFile = (const char *)cred->radiusConfigFile.value; + + ralloc.calloc = GSSEAP_CALLOC; + ralloc.malloc = GSSEAP_MALLOC; + ralloc.free = GSSEAP_FREE; + ralloc.realloc = GSSEAP_REALLOC; + + rs_context_set_alloc_scheme(radContext, &ralloc); + + if (rs_context_read_config(radContext, configFile) != 0) { + err = rs_err_ctx_pop(radContext); + goto fail; + } + + *pRadContext = radContext; + + *minor = 0; + return GSS_S_COMPLETE; + +fail: + major = gssEapRadiusMapError(minor, err); + rs_context_destroy(radContext); + + return major; +} + +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + +OM_uint32 +gssEapRadiusAddAttr(OM_uint32 *minor, struct wpabuf **buf, uint16_t attr, + uint16_t vendor, gss_buffer_t buffer) +{ + if (radius_add_tlv(buf, attr, vendor, (u8 *)buffer->value, + buffer->length) < 0) { + *minor = ENOMEM; /* could be length too long, though */ + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/mech_eap/util_radius.h b/mech_eap/util_radius.h new file mode 100644 index 0000000..d4f86ec --- /dev/null +++ b/mech_eap/util_radius.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * RADIUS attribute provider. + */ + +#ifndef _UTIL_RADIUS_H_ +#define _UTIL_RADIUS_H_ 1 + +#ifdef __cplusplus + +typedef std::pair gss_eap_attrid; +#ifdef GSSEAP_ENABLE_ACCEPTOR + + +struct gss_eap_radius_attr_provider : gss_eap_attr_provider { +public: + gss_eap_radius_attr_provider(void); + ~gss_eap_radius_attr_provider(void); + + bool initWithExistingContext(const gss_eap_attr_ctx *source, + const gss_eap_attr_provider *ctx); + bool initWithGssContext(const gss_eap_attr_ctx *source, + const gss_cred_id_t cred, + const gss_ctx_id_t ctx); + + bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const; + bool setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value); + bool deleteAttribute(const gss_buffer_t attr); + bool getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const; + gss_any_t mapToAny(int authenticated, + gss_buffer_t type_id) const; + void releaseAnyNameMapping(gss_buffer_t type_id, + gss_any_t input) const; + + const char *prefix(void) const; + const char *name(void) const; + bool initWithJsonObject(const gss_eap_attr_ctx *manager, + JSONObject &obj); + JSONObject jsonRepresentation(void) const; + + bool getAttribute(const gss_eap_attrid &attrid, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const; + bool setAttribute(int complete, + const gss_eap_attrid &attrid, + const gss_buffer_t value); + bool deleteAttribute(const gss_eap_attrid &attrid); + + bool getFragmentedAttribute(const gss_eap_attrid &attrid, + int *authenticated, + int *complete, + gss_buffer_t value) const; + + bool authenticated(void) const { return m_authenticated; } + + time_t getExpiryTime(void) const; + + static bool init(void); + static void finalize(void); + + static gss_eap_attr_provider *createAttrContext(void); + +private: + rs_const_avp *getAvps(void) const { + return m_vps; + } + + rs_avp *m_vps; + bool m_authenticated; +}; + +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + +/* For now */ +extern "C" { +#endif + +#ifdef GSSEAP_ENABLE_ACCEPTOR + +OM_uint32 +gssEapRadiusAddAvp(OM_uint32 *minor, + struct rs_packet *pkt, + unsigned int type, + unsigned int vendor, + const gss_buffer_t buffer); + +OM_uint32 +gssEapRadiusGetAvp(OM_uint32 *minor, + struct rs_packet *pkt, + unsigned int type, + unsigned int vendor, + gss_buffer_t buffer, + int concat); + +OM_uint32 +gssEapRadiusGetRawAvp(OM_uint32 *minor, + rs_const_avp *vps, + unsigned int type, + unsigned int vendor, + rs_const_avp **vp); +OM_uint32 +gssEapRadiusFreeAvps(OM_uint32 *minor, + rs_avp **vps); + +OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor); +OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor); + +OM_uint32 +gssEapRadiusMapError(OM_uint32 *minor, + struct rs_error *err); + +OM_uint32 +gssEapCreateRadiusContext(OM_uint32 *minor, + gss_cred_id_t cred, + struct rs_context **pRadContext); + +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + +/* initiator utilities that require only libeap, and not freeradius */ +struct wpabuf; + +OM_uint32 +gssEapRadiusAddAttr(OM_uint32 *minor, + struct wpabuf **dst, + uint16_t type, + uint16_t vendor, + gss_buffer_t value); + +/* This really needs to be a function call on Windows */ +#define RS_CONFIG_FILE SYSCONFDIR "/radsec.conf" + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIL_RADIUS_H_ */ diff --git a/mech_eap/util_reauth.c b/mech_eap/util_reauth.c new file mode 100644 index 0000000..cd85a53 --- /dev/null +++ b/mech_eap/util_reauth.c @@ -0,0 +1,1201 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Fast reauthentication support. + */ + +#include "gssapiP_eap.h" + +#include + +/* + * Fast reauthentication support for EAP GSS. + */ + +krb5_error_code +krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *); + +krb5_error_code +encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code); + +static OM_uint32 +gssDisplayName(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t buffer, + gss_OID *name_type); + +static OM_uint32 +gssImportName(OM_uint32 *minor, + gss_buffer_t buffer, + gss_OID name_type, + gss_name_t *name); + +static krb5_error_code +getAcceptorKey(krb5_context krbContext, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + krb5_principal *princ, + krb5_keyblock *key) +{ + krb5_error_code code; + krb5_keytab keytab = NULL; + krb5_keytab_entry ktent = { 0 }; + krb5_kt_cursor cursor; + + *princ = NULL; + memset(key, 0, sizeof(*key)); + memset(&cursor, 0, sizeof(cursor)); + + code = krb5_kt_default(krbContext, &keytab); + if (code != 0) + goto cleanup; + + if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) { + code = krb5_kt_get_entry(krbContext, keytab, + cred->name->krbPrincipal, 0, + ctx->encryptionType, &ktent); + if (code != 0) + goto cleanup; + } else { + /* + * It's not clear that looking encrypting the ticket in the + * requested EAP enctype provides any value. + */ + code = krb5_kt_start_seq_get(krbContext, keytab, &cursor); + if (code != 0) + goto cleanup; + + while ((code = krb5_kt_next_entry(krbContext, keytab, + &ktent, &cursor)) == 0) { + if (KRB_KEY_TYPE(KRB_KT_ENT_KEYBLOCK(&ktent)) == ctx->encryptionType) + break; + else + KRB_KT_ENT_FREE(krbContext, &ktent); + } + } + + if (code == 0) { + *princ = ktent.principal; + *key = *KRB_KT_ENT_KEYBLOCK(&ktent); + } + +cleanup: + if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME) + krb5_kt_end_seq_get(krbContext, keytab, &cursor); + krb5_kt_close(krbContext, keytab); + if (code != 0) + KRB_KT_ENT_FREE(krbContext, &ktent); + + return code; +} + +static OM_uint32 +freezeAttrContext(OM_uint32 *minor, + gss_name_t initiatorName, + krb5_const_principal acceptorPrinc, + krb5_keyblock *session, +#ifdef HAVE_HEIMDAL_VERSION + krb5_authdata *kdcIssuedAuthData +#else + krb5_authdata ***kdcIssuedAuthData +#endif + ) +{ + OM_uint32 major, tmpMinor; + krb5_error_code code; + krb5_context krbContext; + gss_buffer_desc attrBuf = GSS_C_EMPTY_BUFFER; +#ifdef HAVE_HEIMDAL_VERSION + krb5_authdata authDataBuf, *authData = &authDataBuf; + AuthorizationDataElement authDatum = { 0 }; +#else + krb5_authdata *authData[2], authDatum = { 0 }; +#endif + + memset(kdcIssuedAuthData, 0, sizeof(*kdcIssuedAuthData)); + + GSSEAP_KRB_INIT(&krbContext); + + major = gssEapExportAttrContext(minor, initiatorName, &attrBuf); + if (GSS_ERROR(major)) + return major; + + authDatum.ad_type = KRB5_AUTHDATA_RADIUS_AVP; +#ifdef HAVE_HEIMDAL_VERSION + authDatum.ad_data.length = attrBuf.length; + authDatum.ad_data.data = attrBuf.value; + authData->len = 1; + authData->val = &authDatum; +#else + authDatum.length = attrBuf.length; + authDatum.contents = attrBuf.value; + authData[0] = &authDatum; + authData[1] = NULL; +#endif + + code = krbMakeAuthDataKdcIssued(krbContext, session, acceptorPrinc, + authData, kdcIssuedAuthData); + if (code != 0) { + major = GSS_S_FAILURE; + *minor = code; + } else { + major = GSS_S_COMPLETE; + } + + gss_release_buffer(&tmpMinor, &attrBuf); + + return major; +} + +/* + * Fabricate a ticket to ourselves given a GSS EAP context. + */ +OM_uint32 +gssEapMakeReauthCreds(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t credBuf) +{ + OM_uint32 major = GSS_S_COMPLETE; + krb5_error_code code; + krb5_context krbContext = NULL; + krb5_keyblock session = { 0 }, acceptorKey = { 0 }; + krb5_principal server = NULL; +#ifdef HAVE_HEIMDAL_VERSION + Ticket ticket; + EncTicketPart enc_part; + AuthorizationData authData = { 0 }; + krb5_crypto krbCrypto = NULL; + krb5_data ticketData = { 0 }; + krb5_data encPartData = { 0 }; + size_t len; +#else + krb5_ticket ticket; + krb5_enc_tkt_part enc_part; + krb5_data *ticketData = NULL; +#endif + krb5_data credsData = { 0 }; + krb5_creds creds = { 0 }; + krb5_auth_context authContext = NULL; + + memset(&ticket, 0, sizeof(ticket)); + memset(&enc_part, 0, sizeof(enc_part)); + + credBuf->length = 0; + credBuf->value = NULL; + + if (ctx->acceptorName == GSS_C_NO_NAME) { + *minor = GSSEAP_NO_ACCEPTOR_NAME; + return GSS_S_UNAVAILABLE; + } + + GSSEAP_KRB_INIT(&krbContext); + + code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey); + if (code != 0) { + *minor = code; + return GSS_S_UNAVAILABLE; + } + + /* + * Generate a random session key to place in the ticket and + * sign the "KDC-Issued" authorization data element. + */ +#ifdef HAVE_HEIMDAL_VERSION + ticket.realm = server->realm; + ticket.sname = server->name; + + code = krb5_generate_random_keyblock(krbContext, ctx->encryptionType, + &session); + if (code != 0) + goto cleanup; + + enc_part.flags.initial = 1; + enc_part.key = session; + enc_part.crealm = ctx->initiatorName->krbPrincipal->realm; + enc_part.cname = ctx->initiatorName->krbPrincipal->name; + enc_part.authtime = time(NULL); + enc_part.starttime = &enc_part.authtime; + enc_part.endtime = (ctx->expiryTime != 0) + ? ctx->expiryTime : KRB_TIME_FOREVER; + enc_part.renew_till = NULL; + enc_part.authorization_data = &authData; + + major = freezeAttrContext(minor, ctx->initiatorName, server, + &session, &authData); + if (GSS_ERROR(major)) + goto cleanup; + + ASN1_MALLOC_ENCODE(EncTicketPart, encPartData.data, encPartData.length, + &enc_part, &len, code); + if (code != 0) + goto cleanup; + + code = krb5_crypto_init(krbContext, &acceptorKey, 0, &krbCrypto); + if (code != 0) + goto cleanup; + + code = krb5_encrypt_EncryptedData(krbContext, + krbCrypto, + KRB5_KU_TICKET, + encPartData.data, + encPartData.length, + 0, + &ticket.enc_part); + if (code != 0) + goto cleanup; + + ASN1_MALLOC_ENCODE(Ticket, ticketData.data, ticketData.length, + &ticket, &len, code); + if (code != 0) + goto cleanup; +#else + ticket.server = server; + + code = krb5_c_make_random_key(krbContext, ctx->encryptionType, + &session); + if (code != 0) + goto cleanup; + + enc_part.flags = TKT_FLG_INITIAL; + enc_part.session = &session; + enc_part.client = ctx->initiatorName->krbPrincipal; + enc_part.times.authtime = time(NULL); + enc_part.times.starttime = enc_part.times.authtime; + enc_part.times.endtime = (ctx->expiryTime != 0) + ? ctx->expiryTime + : KRB_TIME_FOREVER; + enc_part.times.renew_till = 0; + + major = freezeAttrContext(minor, ctx->initiatorName, server, + &session, &enc_part.authorization_data); + if (GSS_ERROR(major)) + goto cleanup; + + ticket.enc_part2 = &enc_part; + + code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket); + if (code != 0) + goto cleanup; + + code = encode_krb5_ticket(&ticket, &ticketData); + if (code != 0) + goto cleanup; +#endif /* HAVE_HEIMDAL_VERSION */ + + creds.client = ctx->initiatorName->krbPrincipal; + creds.server = server; +#ifdef HAVE_HEIMDAL_VERSION + creds.session = session; + creds.times.authtime = enc_part.authtime; + creds.times.starttime = *enc_part.starttime; + creds.times.endtime = enc_part.endtime; + creds.times.renew_till = 0; + creds.flags.b = enc_part.flags; + creds.ticket = ticketData; + creds.authdata = authData; +#else + creds.keyblock = session; + creds.times = enc_part.times; + creds.ticket_flags = enc_part.flags; + creds.ticket = *ticketData; + creds.authdata = enc_part.authorization_data; +#endif + + code = krb5_auth_con_init(krbContext, &authContext); + if (code != 0) + goto cleanup; + + code = krb5_auth_con_setflags(krbContext, authContext, 0); + if (code != 0) + goto cleanup; + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_auth_con_setlocalsubkey(krbContext, authContext, + &ctx->rfc3961Key); +#else + code = krb5_auth_con_setsendsubkey(krbContext, authContext, + &ctx->rfc3961Key); +#endif + if (code != 0) + goto cleanup; + + code = krbMakeCred(krbContext, authContext, &creds, &credsData); + if (code != 0) + goto cleanup; + + krbDataToGssBuffer(&credsData, credBuf); + +cleanup: +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); + free_AuthorizationData(&authData); + free_EncryptedData(&ticket.enc_part); + krb5_data_free(&ticketData); + krb5_data_free(&encPartData); +#else + krb5_free_authdata(krbContext, enc_part.authorization_data); + if (ticket.enc_part.ciphertext.data != NULL) + GSSEAP_FREE(ticket.enc_part.ciphertext.data); + krb5_free_data(krbContext, ticketData); +#endif + krb5_free_keyblock_contents(krbContext, &session); + krb5_free_principal(krbContext, server); + krb5_free_keyblock_contents(krbContext, &acceptorKey); + krb5_auth_con_free(krbContext, authContext); + + if (major == GSS_S_COMPLETE) { + *minor = code; + major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE; + } + + return major; +} + +static int +isTicketGrantingServiceP(krb5_context krbContext GSSEAP_UNUSED, + krb5_const_principal principal) +{ + if (KRB_PRINC_LENGTH(principal) == 2 && +#ifdef HAVE_HEIMDAL_VERSION + strcmp(KRB_PRINC_NAME(principal)[0], "krbtgt") == 0 +#else + krb5_princ_component(krbContext, principal, 0)->length == 6 && + memcmp(krb5_princ_component(krbContext, + principal, 0)->data, "krbtgt", 6) == 0 +#endif + ) + return TRUE; + + return FALSE; +} + +/* + * Returns TRUE if the configuration variable reauth_use_ccache is + * set in krb5.conf for the eap_gss application and the client realm. + */ +static int +reauthUseCredsCache(krb5_context krbContext, + krb5_principal principal) +{ + int reauthUseCCache; + + /* if reauth_use_ccache, use default credentials cache if ticket is for us */ + krb5_appdefault_boolean(krbContext, "eap_gss", + KRB_PRINC_REALM(principal), + "reauth_use_ccache", 0, &reauthUseCCache); + + return reauthUseCCache; +} + +/* + * Look in default credentials cache for reauthentication credentials, + * if policy allows. + */ +static OM_uint32 +getDefaultReauthCredentials(OM_uint32 *minor, + gss_cred_id_t cred, + gss_name_t target, + time_t now, + OM_uint32 timeReq) +{ + OM_uint32 major = GSS_S_CRED_UNAVAIL; + krb5_context krbContext = NULL; + krb5_error_code code = 0; + krb5_ccache ccache = NULL; + krb5_creds match = { 0 }; + krb5_creds creds = { 0 }; + + GSSEAP_KRB_INIT(&krbContext); + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + GSSEAP_ASSERT(target != GSS_C_NO_NAME); + + if (cred->name == GSS_C_NO_NAME || + !reauthUseCredsCache(krbContext, cred->name->krbPrincipal)) + goto cleanup; + + match.client = cred->name->krbPrincipal; + match.server = target->krbPrincipal; + if (timeReq != 0 && timeReq != GSS_C_INDEFINITE) + match.times.endtime = now + timeReq; + + code = krb5_cc_default(krbContext, &ccache); + if (code != 0) + goto cleanup; + + code = krb5_cc_retrieve_cred(krbContext, ccache, 0, &match, &creds); + if (code != 0) + goto cleanup; + + cred->flags |= CRED_FLAG_DEFAULT_CCACHE; + cred->krbCredCache = ccache; + ccache = NULL; + + major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL, + &cred->reauthCred); + +cleanup: + if (major == GSS_S_CRED_UNAVAIL) + *minor = code; + + if (ccache != NULL) + krb5_cc_close(krbContext, ccache); + krb5_free_cred_contents(krbContext, &creds); + + return major; +} + +/* + * Returns TRUE if the credential handle's reauth credentials are + * valid or if we can use the default credentials cache. Credentials + * handle must be locked. + */ +int +gssEapCanReauthP(gss_cred_id_t cred, + gss_name_t target, + OM_uint32 timeReq) +{ + time_t now, expiryReq; + OM_uint32 minor; + + if (cred == GSS_C_NO_CREDENTIAL) + return FALSE; + + now = time(NULL); + expiryReq = now; + if (timeReq != GSS_C_INDEFINITE) + expiryReq += timeReq; + + if (cred->krbCredCache != NULL && cred->expiryTime > expiryReq) + return TRUE; + + if (getDefaultReauthCredentials(&minor, cred, target, + now, timeReq) == GSS_S_COMPLETE) + return TRUE; + + return FALSE; +} + +/* + * Store re-authentication (Kerberos) credentials in a credential handle. + * Credentials handle must be locked. + */ +OM_uint32 +gssEapStoreReauthCreds(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t credBuf) +{ + OM_uint32 major = GSS_S_COMPLETE; + krb5_error_code code; + krb5_context krbContext = NULL; + krb5_auth_context authContext = NULL; + krb5_data credData = { 0 }; + krb5_creds **creds = NULL; + krb5_principal canonPrinc; + krb5_principal ccPrinc = NULL; + int i; + + if (credBuf->length == 0 || cred == GSS_C_NO_CREDENTIAL) + return GSS_S_COMPLETE; + + GSSEAP_KRB_INIT(&krbContext); + + code = krb5_auth_con_init(krbContext, &authContext); + if (code != 0) + goto cleanup; + + code = krb5_auth_con_setflags(krbContext, authContext, 0); + if (code != 0) + goto cleanup; + + code = krb5_auth_con_setrecvsubkey(krbContext, authContext, + &ctx->rfc3961Key); + if (code != 0) + goto cleanup; + + gssBufferToKrbData(credBuf, &credData); + + code = krb5_rd_cred(krbContext, authContext, &credData, &creds, NULL); + if (code != 0) + goto cleanup; + + if (creds == NULL || creds[0] == NULL) + goto cleanup; + + code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc); + if (code != 0) + goto cleanup; + + krb5_free_principal(krbContext, cred->name->krbPrincipal); + cred->name->krbPrincipal = canonPrinc; + + if (creds[0]->times.endtime == KRB_TIME_FOREVER) + cred->expiryTime = 0; + else + cred->expiryTime = creds[0]->times.endtime; + + if (cred->krbCredCache == NULL) { + if (reauthUseCredsCache(krbContext, creds[0]->client) && + krb5_cc_default(krbContext, &cred->krbCredCache) == 0) + cred->flags |= CRED_FLAG_DEFAULT_CCACHE; + } else { + /* + * If we already have an associated credentials cache, possibly from + * the last time we stored a reauthentication credential, then we + * need to clear it out and release the associated GSS credential. + */ + if (cred->flags & CRED_FLAG_DEFAULT_CCACHE) { + krb5_cc_remove_cred(krbContext, cred->krbCredCache, 0, creds[0]); + } else { + krb5_cc_destroy(krbContext, cred->krbCredCache); + cred->krbCredCache = NULL; + } + gssReleaseCred(minor, &cred->reauthCred); + } + + if (cred->krbCredCache == NULL) { + code = krb5_cc_new_unique(krbContext, "MEMORY", NULL, &cred->krbCredCache); + if (code != 0) + goto cleanup; + } + + if ((cred->flags & CRED_FLAG_DEFAULT_CCACHE) == 0 || + krb5_cc_get_principal(krbContext, cred->krbCredCache, &ccPrinc) != 0) { + code = krb5_cc_initialize(krbContext, cred->krbCredCache, + creds[0]->client); + if (code != 0) + goto cleanup; + } + + for (i = 0; creds[i] != NULL; i++) { + krb5_creds kcred = *(creds[i]); + + /* + * Swap in the acceptor name the client asked for so + * get_credentials() works. We're making the assumption that + * any service tickets returned are for us. We'll need to + * reflect some more on whether that is a safe assumption. + */ + if (!isTicketGrantingServiceP(krbContext, kcred.server)) + kcred.server = ctx->acceptorName->krbPrincipal; + + code = krb5_cc_store_cred(krbContext, cred->krbCredCache, &kcred); + if (code != 0) + goto cleanup; + } + + major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL, + &cred->reauthCred); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + *minor = code; + + krb5_free_principal(krbContext, ccPrinc); + krb5_auth_con_free(krbContext, authContext); + if (creds != NULL) { + for (i = 0; creds[i] != NULL; i++) + krb5_free_creds(krbContext, creds[i]); + GSSEAP_FREE(creds); + } + if (major == GSS_S_COMPLETE) + major = *minor ? GSS_S_FAILURE : GSS_S_COMPLETE; + + return major; +} + +#ifndef HAVE_HEIMDAL_VERSION +static gss_buffer_desc radiusAvpKrbAttr = { + sizeof("urn:authdata-aaa-radius") - 1, "urn:authdata-aaa-radius" +}; +#endif + +/* + * Unfortunately extracting an AD-KDCIssued authorization data element + * is pretty implementation-dependent. It's not possible to verify the + * signature ourselves because the ticket session key is not exposed + * outside GSS. In an ideal world, all AD-KDCIssued elements would be + * verified by the Kerberos library and authentication would fail if + * verification failed. We're not quite there yet and as a result have + * to go through some hoops to get this to work. The alternative would + * be to sign the authorization data with our long-term key, but it + * seems a pity to compromise the design because of current implementation + * limitations. + * + * (Specifically, the hoops involve a libkrb5 authorisation data plugin + * that exposes the verified and serialised attribute context through + * the Kerberos GSS mechanism's naming extensions API.) + */ +static OM_uint32 +defrostAttrContext(OM_uint32 *minor, +#ifdef HAVE_HEIMDAL_VERSION + gss_ctx_id_t glueContext, +#else + gss_name_t glueName, +#endif + gss_name_t mechName) +{ + OM_uint32 major, tmpMinor; +#ifdef HAVE_HEIMDAL_VERSION + gss_OID_desc oid = { 0 }; + gss_buffer_set_t authData = GSS_C_NO_BUFFER_SET; +#else + gss_buffer_desc authData = GSS_C_EMPTY_BUFFER; + gss_buffer_desc authDataDisplay = GSS_C_EMPTY_BUFFER; + int more = -1; + int authenticated, complete; +#endif + +#ifdef HAVE_HEIMDAL_VERSION + major = composeOid(minor, + GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements, + GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length, + KRB5_AUTHDATA_RADIUS_AVP, &oid); + if (GSS_ERROR(major)) + return major; + + /* XXX we are assuming that this verifies AD-KDCIssued signature */ + major = gssInquireSecContextByOid(minor, glueContext, + &oid, &authData); + if (major == GSS_S_COMPLETE) { + if (authData == GSS_C_NO_BUFFER_SET || authData->count != 1) + major = GSS_S_FAILURE; + else + major = gssEapImportAttrContext(minor, authData->elements, mechName); + } else if (major == GSS_S_FAILURE && *minor == ENOENT) { + /* This is the equivalent of GSS_S_UNAVAILABLE for MIT attr APIs */ + *minor = 0; + major = GSS_S_COMPLETE; + } + + gss_release_buffer_set(&tmpMinor, &authData); + GSSEAP_FREE(oid.elements); +#else + major = gssGetNameAttribute(minor, glueName, &radiusAvpKrbAttr, + &authenticated, &complete, + &authData, &authDataDisplay, &more); + if (major == GSS_S_COMPLETE) { + if (authenticated == 0) + major = GSS_S_BAD_NAME; + else + major = gssEapImportAttrContext(minor, &authData, mechName); + } else if (major == GSS_S_UNAVAILABLE) { + major = GSS_S_COMPLETE; + } + + gss_release_buffer(&tmpMinor, &authData); + gss_release_buffer(&tmpMinor, &authDataDisplay); +#endif /* HAVE_HEIMDAL_VERSION */ + + return major; +} + +/* + * Convert a mechanism glue to an EAP mechanism name by displaying and + * importing it. This also handles the RADIUS attributes. + */ +OM_uint32 +gssEapGlueToMechName(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_name_t glueName, + gss_name_t *pMechName) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + + *pMechName = GSS_C_NO_NAME; + + major = gssDisplayName(minor, glueName, &nameBuf, NULL); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME, + ctx->mechanismUsed, pMechName); + if (GSS_ERROR(major)) + goto cleanup; + + major = defrostAttrContext(minor, +#ifdef HAVE_HEIMDAL_VERSION + ctx->reauthCtx, +#else + glueName, +#endif + *pMechName); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + if (GSS_ERROR(major)) { + gssReleaseName(&tmpMinor, pMechName); + *pMechName = GSS_C_NO_NAME; + } + + gss_release_buffer(&tmpMinor, &nameBuf); + + return major; +} + +/* + * Convert an EAP mechanism name to a mechanism glue name by displaying + * and importing it. + */ +OM_uint32 +gssEapMechToGlueName(OM_uint32 *minor, + gss_name_t mechName, + gss_name_t *pGlueName) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + + *pGlueName = GSS_C_NO_NAME; + + major = gssEapDisplayName(minor, mechName, &nameBuf, NULL); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssImportName(minor, &nameBuf, GSS_C_NT_USER_NAME, + pGlueName); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + gss_release_buffer(&tmpMinor, &nameBuf); + + return major; +} + +/* + * Suck out the analgous elements of a Kerberos GSS context into an EAP + * one so that the application doesn't know the difference. + */ +OM_uint32 +gssEapReauthComplete(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred GSSEAP_UNUSED, + const gss_OID mech, + OM_uint32 timeRec) +{ + OM_uint32 major, tmpMinor; + gss_buffer_set_t keyData = GSS_C_NO_BUFFER_SET; + krb5_context krbContext = NULL; +#ifdef HAVE_HEIMDAL_VERSION + krb5_storage *sp = NULL; +#endif + + GSSEAP_KRB_INIT(&krbContext); + + if (!oidEqual(mech, gss_mech_krb5)) { + major = GSS_S_BAD_MECH; + goto cleanup; + } + + /* Get the raw subsession key and encryption type */ +#ifdef HAVE_HEIMDAL_VERSION +#define KRB_GSS_SUBKEY_COUNT 1 /* encoded session key */ + major = gssInquireSecContextByOid(minor, ctx->reauthCtx, + GSS_KRB5_GET_SUBKEY_X, &keyData); +#else +#define KRB_GSS_SUBKEY_COUNT 2 /* raw session key, enctype OID */ + major = gssInquireSecContextByOid(minor, ctx->reauthCtx, + GSS_C_INQ_SSPI_SESSION_KEY, &keyData); +#endif + if (GSS_ERROR(major)) + goto cleanup; + + if (keyData == GSS_C_NO_BUFFER_SET || keyData->count < KRB_GSS_SUBKEY_COUNT) { + *minor = GSSEAP_KEY_UNAVAILABLE; + major = GSS_S_FAILURE; + goto cleanup; + } + +#ifdef HAVE_HEIMDAL_VERSION + sp = krb5_storage_from_mem(keyData->elements[0].value, + keyData->elements[0].length); + if (sp == NULL) { + *minor = ENOMEM; + major = GSS_S_FAILURE; + goto cleanup; + } + + *minor = krb5_ret_keyblock(sp, &ctx->rfc3961Key); + if (*minor != 0) { + major = GSS_S_FAILURE; + goto cleanup; + } +#else + { + gss_OID_desc oid; + int suffix; + + oid.length = keyData->elements[1].length; + oid.elements = keyData->elements[1].value; + + /* GSS_KRB5_SESSION_KEY_ENCTYPE_OID */ + major = decomposeOid(minor, + "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04", + 10, &oid, &suffix); + if (GSS_ERROR(major)) + goto cleanup; + + ctx->encryptionType = suffix; + } + + { + krb5_keyblock key; + + KRB_KEY_LENGTH(&key) = keyData->elements[0].length; + KRB_KEY_DATA(&key) = keyData->elements[0].value; + KRB_KEY_TYPE(&key) = ctx->encryptionType; + + *minor = krb5_copy_keyblock_contents(krbContext, + &key, &ctx->rfc3961Key); + if (*minor != 0) { + major = GSS_S_FAILURE; + goto cleanup; + } + } +#endif /* HAVE_HEIMDAL_VERSION */ + + major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key, + &ctx->checksumType); + if (GSS_ERROR(major)) + goto cleanup; + + if (timeRec != GSS_C_INDEFINITE) + ctx->expiryTime = time(NULL) + timeRec; + + /* Initialize our sequence state */ + major = sequenceInit(minor, + &ctx->seqState, ctx->recvSeq, + ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), + ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), + TRUE); + if (GSS_ERROR(major)) + goto cleanup; + + major = GSS_S_COMPLETE; + +cleanup: +#ifdef HAVE_HEIMDAL_VERSION + if (sp != NULL) + krb5_storage_free(sp); +#endif + gss_release_buffer_set(&tmpMinor, &keyData); + + return major; +} + +/* + * The remainder of this file consists of wrappers so we can call into the + * mechanism glue without calling ourselves. + */ +static OM_uint32 +(*gssInitSecContextNext)(OM_uint32 *, + gss_cred_id_t, + gss_ctx_id_t *, + gss_name_t, + gss_OID, + OM_uint32, + OM_uint32, + gss_channel_bindings_t, + gss_buffer_t, + gss_OID *, + gss_buffer_t, + OM_uint32 *, + OM_uint32 *); + +static OM_uint32 +(*gssAcceptSecContextNext)(OM_uint32 *, + gss_ctx_id_t *, + gss_cred_id_t, + gss_buffer_t, + gss_channel_bindings_t, + gss_name_t *, + gss_OID *, + gss_buffer_t, + OM_uint32 *, + OM_uint32 *, + gss_cred_id_t *); + +static OM_uint32 +(*gssReleaseCredNext)(OM_uint32 *, gss_cred_id_t *); + +static OM_uint32 +(*gssReleaseNameNext)(OM_uint32 *, gss_name_t *); + +static OM_uint32 +(*gssInquireSecContextByOidNext)(OM_uint32 *, + const gss_ctx_id_t, + const gss_OID, + gss_buffer_set_t *); + +static OM_uint32 +(*gssDeleteSecContextNext)(OM_uint32 *, + gss_ctx_id_t *, + gss_buffer_t); + +static OM_uint32 +(*gssDisplayNameNext)(OM_uint32 *, + gss_name_t, + gss_buffer_t, + gss_OID *); + +static OM_uint32 +(*gssImportNameNext)(OM_uint32 *, + gss_buffer_t, + gss_OID, + gss_name_t *); + +static OM_uint32 +(*gssStoreCredNext)(OM_uint32 *, + const gss_cred_id_t, + gss_cred_usage_t, + const gss_OID, + OM_uint32, + OM_uint32, + gss_OID_set *, + gss_cred_usage_t *); + +static OM_uint32 +(*gssGetNameAttributeNext)(OM_uint32 *, + gss_name_t, + gss_buffer_t, + int *, + int *, + gss_buffer_t, + gss_buffer_t, + int *); + +#define NEXT_SYMBOL(local, global) do { \ + ((local) = dlsym(RTLD_NEXT, (global))); \ + if ((local) == NULL) { \ + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; \ + major = GSS_S_UNAVAILABLE; \ + /* but continue */ \ + } \ + } while (0) + +OM_uint32 +gssEapReauthInitialize(OM_uint32 *minor) +{ + OM_uint32 major = GSS_S_COMPLETE; + + NEXT_SYMBOL(gssInitSecContextNext, "gss_init_sec_context"); + NEXT_SYMBOL(gssAcceptSecContextNext, "gss_accept_sec_context"); + NEXT_SYMBOL(gssReleaseCredNext, "gss_release_cred"); + NEXT_SYMBOL(gssReleaseNameNext, "gss_release_name"); + NEXT_SYMBOL(gssInquireSecContextByOidNext, "gss_inquire_sec_context_by_oid"); + NEXT_SYMBOL(gssDeleteSecContextNext, "gss_delete_sec_context"); + NEXT_SYMBOL(gssDisplayNameNext, "gss_display_name"); + NEXT_SYMBOL(gssImportNameNext, "gss_import_name"); + NEXT_SYMBOL(gssStoreCredNext, "gss_store_cred"); +#ifndef HAVE_HEIMDAL_VERSION + NEXT_SYMBOL(gssGetNameAttributeNext, "gss_get_name_attribute"); +#endif + + return major; +} + +OM_uint32 +gssInitSecContext(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + if (gssInitSecContextNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssInitSecContextNext(minor, cred, context_handle, + target_name, mech_type, req_flags, + time_req, input_chan_bindings, + input_token, actual_mech_type, + output_token, ret_flags, time_rec); +} + +OM_uint32 +gssAcceptSecContext(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_cred_id_t cred, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + if (gssAcceptSecContextNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssAcceptSecContextNext(minor, context_handle, cred, + input_token, input_chan_bindings, + src_name, mech_type, output_token, + ret_flags, time_rec, delegated_cred_handle); +} + +OM_uint32 +gssReleaseCred(OM_uint32 *minor, + gss_cred_id_t *cred_handle) +{ + if (gssReleaseCredNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssReleaseCredNext(minor, cred_handle); +} + +OM_uint32 +gssReleaseName(OM_uint32 *minor, + gss_name_t *name) +{ + if (gssReleaseNameNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssReleaseNameNext(minor, name); +} + +OM_uint32 +gssDeleteSecContext(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + if (gssDeleteSecContextNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssDeleteSecContextNext(minor, context_handle, output_token); +} + +static OM_uint32 +gssDisplayName(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t buffer, + gss_OID *name_type) +{ + if (gssDisplayNameNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssDisplayNameNext(minor, name, buffer, name_type); +} + +static OM_uint32 +gssImportName(OM_uint32 *minor, + gss_buffer_t buffer, + gss_OID name_type, + gss_name_t *name) +{ + if (gssImportNameNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssImportNameNext(minor, buffer, name_type, name); +} + +OM_uint32 +gssInquireSecContextByOid(OM_uint32 *minor, + const gss_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + if (gssInquireSecContextByOidNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssInquireSecContextByOidNext(minor, context_handle, + desired_object, data_set); +} + +OM_uint32 +gssStoreCred(OM_uint32 *minor, + const gss_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ + if (gssStoreCredNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssStoreCredNext(minor, input_cred_handle, input_usage, + desired_mech, overwrite_cred, default_cred, + elements_stored, cred_usage_stored); +} + +OM_uint32 +gssGetNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + if (gssGetNameAttributeNext == NULL) { + *minor = GSSEAP_NO_MECHGLUE_SYMBOL; + return GSS_S_UNAVAILABLE; + } + + return gssGetNameAttributeNext(minor, name, attr, authenticated, complete, + value, display_value, more); +} diff --git a/mech_eap/util_reauth.h b/mech_eap/util_reauth.h new file mode 100644 index 0000000..9b9f264 --- /dev/null +++ b/mech_eap/util_reauth.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Fast reauthentication support. + */ + +#include "gssapiP_eap.h" + +#ifndef _UTIL_REAUTH_H_ +#define _UTIL_REAUTH_H_ 1 + +/* AD element containing serialised AVPs. */ +#define KRB5_AUTHDATA_RADIUS_AVP 513 + +OM_uint32 +gssInitSecContext(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec); + +OM_uint32 +gssAcceptSecContext(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_cred_id_t cred, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle); + +OM_uint32 +gssReleaseCred(OM_uint32 *minor, + gss_cred_id_t *cred_handle); + +OM_uint32 +gssReleaseName(OM_uint32 *minor, + gss_name_t *name); + +OM_uint32 +gssDeleteSecContext(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token); + +OM_uint32 +gssInquireSecContextByOid(OM_uint32 *minor, + const gss_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set); + +OM_uint32 +gssStoreCred(OM_uint32 *minor, + const gss_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored); + +OM_uint32 +gssGetNameAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more); + +OM_uint32 +gssEapMakeReauthCreds(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t credBuf); + +OM_uint32 +gssEapStoreReauthCreds(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t credBuf); + + +OM_uint32 +gssEapGlueToMechName(OM_uint32 *minor, + gss_ctx_id_t glueContext, + gss_name_t glueName, + gss_name_t *pMechName); + +OM_uint32 +gssEapMechToGlueName(OM_uint32 *minor, + gss_name_t mechName, + gss_name_t *pGlueName); + +OM_uint32 +gssEapReauthComplete(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + const gss_OID mech, + OM_uint32 timeRec); + +OM_uint32 +gssEapReauthInitialize(OM_uint32 *minor); + +int +gssEapCanReauthP(gss_cred_id_t cred, + gss_name_t target, + OM_uint32 timeReq); + +#endif /* _UTIL_REAUTH_H_ */ diff --git a/mech_eap/util_saml.cpp b/mech_eap/util_saml.cpp new file mode 100644 index 0000000..71ad9bd --- /dev/null +++ b/mech_eap/util_saml.cpp @@ -0,0 +1,774 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SAML attribute provider implementation. + */ + +#include "gssapiP_eap.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace xmltooling; +using namespace opensaml::saml2md; +using namespace opensaml; +using namespace xercesc; +using namespace std; + +static const XMLCh +base64Binary[] = {'b','a','s','e','6','4','B','i','n','a','r','y',0}; + +/* + * gss_eap_saml_assertion_provider is for retrieving the underlying + * assertion. + */ +gss_eap_saml_assertion_provider::gss_eap_saml_assertion_provider(void) +{ + m_assertion = NULL; + m_authenticated = false; +} + +gss_eap_saml_assertion_provider::~gss_eap_saml_assertion_provider(void) +{ + delete m_assertion; +} + +bool +gss_eap_saml_assertion_provider::initWithExistingContext(const gss_eap_attr_ctx *manager, + const gss_eap_attr_provider *ctx) +{ + /* Then we may be creating from an existing attribute context */ + const gss_eap_saml_assertion_provider *saml; + + GSSEAP_ASSERT(m_assertion == NULL); + + if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) + return false; + + saml = static_cast(ctx); + setAssertion(saml->getAssertion(), saml->authenticated()); + + return true; +} + +bool +gss_eap_saml_assertion_provider::initWithGssContext(const gss_eap_attr_ctx *manager, + const gss_cred_id_t gssCred, + const gss_ctx_id_t gssCtx) +{ + const gss_eap_radius_attr_provider *radius; + gss_buffer_desc value = GSS_C_EMPTY_BUFFER; + int authenticated, complete; + OM_uint32 minor; + gss_eap_attrid attrid(VENDORPEC_UKERNA, PW_SAML_AAA_ASSERTION); + + GSSEAP_ASSERT(m_assertion == NULL); + + if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx)) + return false; + + /* + * XXX TODO we need to support draft-howlett-radius-saml-attr-00 + */ + radius = static_cast + (m_manager->getProvider(ATTR_TYPE_RADIUS)); + if (radius != NULL && + radius->getFragmentedAttribute(attrid, &authenticated, &complete, &value)) { + setAssertion(&value, authenticated); + gss_release_buffer(&minor, &value); + } else { + m_assertion = NULL; + } + + return true; +} + +void +gss_eap_saml_assertion_provider::setAssertion(const saml2::Assertion *assertion, + bool authenticated) +{ + + delete m_assertion; + + if (assertion != NULL) { +#ifdef __APPLE__ + m_assertion = (saml2::Assertion *)((void *)assertion->clone()); +#else + m_assertion = dynamic_cast(assertion->clone()); +#endif + m_authenticated = authenticated; + } else { + m_assertion = NULL; + m_authenticated = false; + } +} + +void +gss_eap_saml_assertion_provider::setAssertion(const gss_buffer_t buffer, + bool authenticated) +{ + delete m_assertion; + + m_assertion = parseAssertion(buffer); + m_authenticated = (m_assertion != NULL && authenticated); +} + +saml2::Assertion * +gss_eap_saml_assertion_provider::parseAssertion(const gss_buffer_t buffer) +{ + string str((char *)buffer->value, buffer->length); + istringstream istream(str); + DOMDocument *doc; + const XMLObjectBuilder *b; + + try { + doc = XMLToolingConfig::getConfig().getParser().parse(istream); + if (doc == NULL) + return NULL; + + b = XMLObjectBuilder::getBuilder(doc->getDocumentElement()); + +#ifdef __APPLE__ + return (saml2::Assertion *)((void *)b->buildFromDocument(doc)); +#else + return dynamic_cast(b->buildFromDocument(doc)); +#endif + } catch (exception &e) { + return NULL; + } +} + +bool +gss_eap_saml_assertion_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, + void *data) const +{ + bool ret; + + /* just add the prefix */ + if (m_assertion != NULL) + ret = addAttribute(m_manager, this, GSS_C_NO_BUFFER, data); + else + ret = true; + + return ret; +} + +bool +gss_eap_saml_assertion_provider::setAttribute(int complete GSSEAP_UNUSED, + const gss_buffer_t attr, + const gss_buffer_t value) +{ + if (attr == GSS_C_NO_BUFFER || attr->length == 0) { + setAssertion(value); + return true; + } + + return false; +} + +bool +gss_eap_saml_assertion_provider::deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED) +{ + delete m_assertion; + m_assertion = NULL; + m_authenticated = false; + + return true; +} + +time_t +gss_eap_saml_assertion_provider::getExpiryTime(void) const +{ + saml2::Conditions *conditions; + time_t expiryTime = 0; + + if (m_assertion == NULL) + return 0; + + conditions = m_assertion->getConditions(); + + if (conditions != NULL && conditions->getNotOnOrAfter() != NULL) + expiryTime = conditions->getNotOnOrAfter()->getEpoch(); + + return expiryTime; +} + +OM_uint32 +gss_eap_saml_assertion_provider::mapException(OM_uint32 *minor, + std::exception &e) const +{ + if (typeid(e) == typeid(SecurityPolicyException)) + *minor = GSSEAP_SAML_SEC_POLICY_FAILURE; + else if (typeid(e) == typeid(BindingException)) + *minor = GSSEAP_SAML_BINDING_FAILURE; + else if (typeid(e) == typeid(ProfileException)) + *minor = GSSEAP_SAML_PROFILE_FAILURE; + else if (typeid(e) == typeid(FatalProfileException)) + *minor = GSSEAP_SAML_FATAL_PROFILE_FAILURE; + else if (typeid(e) == typeid(RetryableProfileException)) + *minor = GSSEAP_SAML_RETRY_PROFILE_FAILURE; + else if (typeid(e) == typeid(MetadataException)) + *minor = GSSEAP_SAML_METADATA_FAILURE; + else + return GSS_S_CONTINUE_NEEDED; + + gssEapSaveStatusInfo(*minor, "%s", e.what()); + + return GSS_S_FAILURE; +} + +bool +gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value GSSEAP_UNUSED, + int *more) const +{ + string str; + + if (attr != GSS_C_NO_BUFFER && attr->length != 0) + return false; + + if (m_assertion == NULL) + return false; + + if (*more != -1) + return false; + + if (authenticated != NULL) + *authenticated = m_authenticated; + if (complete != NULL) + *complete = true; + + XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str); + + if (value != NULL) + duplicateBuffer(str, value); + if (display_value != NULL) + duplicateBuffer(str, display_value); + + *more = 0; + + return true; +} + +gss_any_t +gss_eap_saml_assertion_provider::mapToAny(int authenticated, + gss_buffer_t type_id GSSEAP_UNUSED) const +{ + if (authenticated && !m_authenticated) + return (gss_any_t)NULL; + + return (gss_any_t)m_assertion; +} + +void +gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED, + gss_any_t input) const +{ + delete ((saml2::Assertion *)input); +} + +const char * +gss_eap_saml_assertion_provider::prefix(void) const +{ + return "urn:ietf:params:gss:federated-saml-assertion"; +} + +bool +gss_eap_saml_assertion_provider::init(void) +{ + bool ret = false; + + try { + ret = SAMLConfig::getConfig().init(); + } catch (exception &e) { + } + + if (ret) + gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML_ASSERTION, createAttrContext); + + return ret; +} + +void +gss_eap_saml_assertion_provider::finalize(void) +{ + gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML_ASSERTION); +} + +gss_eap_attr_provider * +gss_eap_saml_assertion_provider::createAttrContext(void) +{ + return new gss_eap_saml_assertion_provider; +} + +saml2::Assertion * +gss_eap_saml_assertion_provider::initAssertion(void) +{ + delete m_assertion; + m_assertion = saml2::AssertionBuilder::buildAssertion(); + m_authenticated = false; + + return m_assertion; +} + +/* + * gss_eap_saml_attr_provider is for retrieving the underlying attributes. + */ +bool +gss_eap_saml_attr_provider::getAssertion(int *authenticated, + saml2::Assertion **pAssertion, + bool createIfAbsent) const +{ + gss_eap_saml_assertion_provider *saml; + + if (authenticated != NULL) + *authenticated = false; + if (pAssertion != NULL) + *pAssertion = NULL; + + saml = static_cast + (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION)); + if (saml == NULL) + return false; + + if (authenticated != NULL) + *authenticated = saml->authenticated(); + if (pAssertion != NULL) + *pAssertion = saml->getAssertion(); + + if (saml->getAssertion() == NULL) { + if (createIfAbsent) { + if (authenticated != NULL) + *authenticated = false; + if (pAssertion != NULL) + *pAssertion = saml->initAssertion(); + } else + return false; + } + + return true; +} + +bool +gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, + void *data) const +{ + saml2::Assertion *assertion; + int authenticated; + + if (!getAssertion(&authenticated, &assertion)) + return true; + + /* + * Note: the first prefix is added by the attribute provider manager + * + * From draft-hartman-gss-eap-naming-00: + * + * Each attribute carried in the assertion SHOULD also be a GSS name + * attribute. The name of this attribute has three parts, all separated + * by an ASCII space character. The first part is + * urn:ietf:params:gss:federated-saml-attribute. The second part is the URI for + * the SAML attribute name format. The final part is the name of the + * SAML attribute. If the mechanism performs an additional attribute + * query, the retrieved attributes SHOULD be GSS-API name attributes + * using the same name syntax. + */ + /* For each attribute statement, look for an attribute match */ + const vector &statements = + const_cast(assertion)->getAttributeStatements(); + + for (vector::const_iterator s = statements.begin(); + s != statements.end(); + ++s) { + const vector &attrs = + const_cast(*s)->getAttributes(); + + for (vector::const_iterator a = attrs.begin(); a != attrs.end(); ++a) { + const XMLCh *attributeName, *attributeNameFormat; + XMLCh space[2] = { ' ', 0 }; + gss_buffer_desc utf8; + + attributeName = (*a)->getName(); + attributeNameFormat = (*a)->getNameFormat(); + if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0') + attributeNameFormat = saml2::Attribute::UNSPECIFIED; + + XMLCh qualifiedName[XMLString::stringLen(attributeNameFormat) + 1 + + XMLString::stringLen(attributeName) + 1]; + XMLString::copyString(qualifiedName, attributeNameFormat); + XMLString::catString(qualifiedName, space); + XMLString::catString(qualifiedName, attributeName); + + utf8.value = (void *)toUTF8(qualifiedName); + utf8.length = strlen((char *)utf8.value); + + if (!addAttribute(m_manager, this, &utf8, data)) + return false; + } + } + + return true; +} + +static BaseRefVectorOf * +decomposeAttributeName(const gss_buffer_t attr) +{ + BaseRefVectorOf *components; + string str((const char *)attr->value, attr->length); + auto_ptr_XMLCh qualifiedAttr(str.c_str()); + + components = XMLString::tokenizeString(qualifiedAttr.get()); + + if (components->size() != 2) { + delete components; + components = NULL; + } + + return components; +} + +bool +gss_eap_saml_attr_provider::setAttribute(int complete GSSEAP_UNUSED, + const gss_buffer_t attr, + const gss_buffer_t value) +{ + saml2::Assertion *assertion; + saml2::Attribute *attribute; + saml2::AttributeValue *attributeValue; + saml2::AttributeStatement *attributeStatement; + + if (!getAssertion(NULL, &assertion, true)) + return false; + + if (assertion->getAttributeStatements().size() != 0) { + attributeStatement = assertion->getAttributeStatements().front(); + } else { + attributeStatement = saml2::AttributeStatementBuilder::buildAttributeStatement(); + assertion->getAttributeStatements().push_back(attributeStatement); + } + + /* Check the attribute name consists of name format | whsp | name */ + BaseRefVectorOf *components = decomposeAttributeName(attr); + if (components == NULL) + return false; + + attribute = saml2::AttributeBuilder::buildAttribute(); + attribute->setNameFormat(components->elementAt(0)); + attribute->setName(components->elementAt(1)); + + attributeValue = saml2::AttributeValueBuilder::buildAttributeValue(); + auto_ptr_XMLCh unistr((char *)value->value, value->length); + attributeValue->setTextContent(unistr.get()); + + attribute->getAttributeValues().push_back(attributeValue); + + GSSEAP_ASSERT(attributeStatement != NULL); + attributeStatement->getAttributes().push_back(attribute); + + delete components; + + return true; +} + +bool +gss_eap_saml_attr_provider::deleteAttribute(const gss_buffer_t attr) +{ + saml2::Assertion *assertion; + bool ret = false; + + if (!getAssertion(NULL, &assertion) || + assertion->getAttributeStatements().size() == 0) + return false; + + /* Check the attribute name consists of name format | whsp | name */ + BaseRefVectorOf *components = decomposeAttributeName(attr); + if (components == NULL) + return false; + + /* For each attribute statement, look for an attribute match */ + const vector &statements = + const_cast(assertion)->getAttributeStatements(); + + for (vector::const_iterator s = statements.begin(); + s != statements.end(); + ++s) { + const vector &attrs = + const_cast(*s)->getAttributes(); + ssize_t index = -1, i = 0; + + /* There's got to be an easier way to do this */ + for (vector::const_iterator a = attrs.begin(); + a != attrs.end(); + ++a) { + if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) && + XMLString::equals((*a)->getName(), components->elementAt(1))) { + index = i; + break; + } + ++i; + } + if (index != -1) { + (*s)->getAttributes().erase((*s)->getAttributes().begin() + index); + ret = true; + } + } + + delete components; + + return ret; +} + +bool +gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + const saml2::Attribute **pAttribute) const +{ + saml2::Assertion *assertion; + + if (authenticated != NULL) + *authenticated = false; + if (complete != NULL) + *complete = true; + *pAttribute = NULL; + + if (!getAssertion(authenticated, &assertion) || + assertion->getAttributeStatements().size() == 0) + return false; + + /* Check the attribute name consists of name format | whsp | name */ + BaseRefVectorOf *components = decomposeAttributeName(attr); + if (components == NULL) + return false; + + /* For each attribute statement, look for an attribute match */ + const vector &statements = + const_cast(assertion)->getAttributeStatements(); + const saml2::Attribute *ret = NULL; + + for (vector::const_iterator s = statements.begin(); + s != statements.end(); + ++s) { + const vector &attrs = + const_cast(*s)->getAttributes(); + + for (vector::const_iterator a = attrs.begin(); a != attrs.end(); ++a) { + const XMLCh *attributeName, *attributeNameFormat; + + attributeName = (*a)->getName(); + attributeNameFormat = (*a)->getNameFormat(); + if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0') + attributeNameFormat = saml2::Attribute::UNSPECIFIED; + + if (XMLString::equals(attributeNameFormat, components->elementAt(0)) && + XMLString::equals(attributeName, components->elementAt(1))) { + ret = *a; + break; + } + } + + if (ret != NULL) + break; + } + + delete components; + + *pAttribute = ret; + + return (ret != NULL); +} + +static bool +isBase64EncodedAttributeValueP(const saml2::AttributeValue *av) +{ + const xmltooling::QName *type = av->getSchemaType(); + + if (type == NULL) + return false; + + if (!type->hasNamespaceURI() || + !XMLString::equals(type->getNamespaceURI(), xmlconstants::XSD_NS)) + return false; + + if (!type->hasLocalPart() || + !XMLString::equals(type->getLocalPart(), base64Binary)) + return false; + + return true; +} + +bool +gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const +{ + const saml2::Attribute *a; + const saml2::AttributeValue *av; + int nvalues, i = *more; + + *more = 0; + + if (!getAttribute(attr, authenticated, complete, &a)) + return false; + + nvalues = a->getAttributeValues().size(); + + if (i == -1) + i = 0; + if (i >= nvalues) + return false; +#ifdef __APPLE__ + av = (const saml2::AttributeValue *)((void *)(a->getAttributeValues().at(i))); +#else + av = dynamic_cast(a->getAttributeValues().at(i)); +#endif + if (av != NULL) { + bool base64Encoded = isBase64EncodedAttributeValueP(av); + + if (value != NULL) { + char *stringValue = toUTF8(av->getTextContent(), true); + size_t stringValueLen = strlen(stringValue); + + if (base64Encoded) { + ssize_t octetLen; + + value->value = GSSEAP_MALLOC(stringValueLen); + if (value->value == NULL) { + GSSEAP_FREE(stringValue); + throw new std::bad_alloc; + } + + octetLen = base64Decode(stringValue, value->value); + if (octetLen < 0) { + GSSEAP_FREE(value->value); + GSSEAP_FREE(stringValue); + value->value = NULL; + return false; + } + value->length = octetLen; + GSSEAP_FREE(stringValue); + } else { + value->value = stringValue; + value->length = stringValueLen; + } + } + if (display_value != NULL && base64Encoded == false) { + display_value->value = toUTF8(av->getTextContent(), true); + display_value->length = strlen((char *)display_value->value); + } + } + + if (nvalues > ++i) + *more = i; + + return true; +} + +gss_any_t +gss_eap_saml_attr_provider::mapToAny(int authenticated GSSEAP_UNUSED, + gss_buffer_t type_id GSSEAP_UNUSED) const +{ + return (gss_any_t)NULL; +} + +void +gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED, + gss_any_t input GSSEAP_UNUSED) const +{ +} + +const char * +gss_eap_saml_attr_provider::prefix(void) const +{ + return "urn:ietf:params:gss:federated-saml-attribute"; +} + +bool +gss_eap_saml_attr_provider::init(void) +{ + gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML, createAttrContext); + return true; +} + +void +gss_eap_saml_attr_provider::finalize(void) +{ + gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML); +} + +gss_eap_attr_provider * +gss_eap_saml_attr_provider::createAttrContext(void) +{ + return new gss_eap_saml_attr_provider; +} + +OM_uint32 +gssEapSamlAttrProvidersInit(OM_uint32 *minor) +{ + if (!gss_eap_saml_assertion_provider::init() || + !gss_eap_saml_attr_provider::init()) { + *minor = GSSEAP_SAML_INIT_FAILURE; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapSamlAttrProvidersFinalize(OM_uint32 *minor) +{ + gss_eap_saml_attr_provider::finalize(); + gss_eap_saml_assertion_provider::finalize(); + + *minor = 0; + return GSS_S_COMPLETE; +} diff --git a/mech_eap/util_saml.h b/mech_eap/util_saml.h new file mode 100644 index 0000000..9110ad4 --- /dev/null +++ b/mech_eap/util_saml.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SAML attribute provider. + */ + +#ifndef _UTIL_SAML_H_ +#define _UTIL_SAML_H_ 1 + +#ifdef __cplusplus + +namespace opensaml { + namespace saml2 { + class Attribute; + class Assertion; + class NameID; + }; +}; + +struct gss_eap_saml_assertion_provider : gss_eap_attr_provider { +public: + gss_eap_saml_assertion_provider(void); + ~gss_eap_saml_assertion_provider(void); + + bool initWithExistingContext(const gss_eap_attr_ctx *source, + const gss_eap_attr_provider *ctx); + bool initWithGssContext(const gss_eap_attr_ctx *source, + const gss_cred_id_t cred, + const gss_ctx_id_t ctx); + + bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const; + bool setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value); + bool deleteAttribute(const gss_buffer_t value); + bool getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const; + gss_any_t mapToAny(int authenticated, + gss_buffer_t type_id) const; + void releaseAnyNameMapping(gss_buffer_t type_id, + gss_any_t input) const; + + const char *prefix(void) const; + const char *name(void) const { return NULL; } + bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED, + JSONObject &object GSSEAP_UNUSED) { + return false; + } + JSONObject jsonRepresentation(void) const { + return JSONObject::null(); + } + + opensaml::saml2::Assertion *initAssertion(void); + + opensaml::saml2::Assertion *getAssertion(void) const { + return m_assertion; + } + bool authenticated(void) const { + return m_authenticated; + } + + time_t getExpiryTime(void) const; + OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const; + + static bool init(void); + static void finalize(void); + + static gss_eap_attr_provider *createAttrContext(void); + +private: + static opensaml::saml2::Assertion * + parseAssertion(const gss_buffer_t buffer); + + void setAssertion(const opensaml::saml2::Assertion *assertion, + bool authenticated = false); + void setAssertion(const gss_buffer_t buffer, + bool authenticated = false); + + opensaml::saml2::Assertion *m_assertion; + bool m_authenticated; +}; + +struct gss_eap_saml_attr_provider : gss_eap_attr_provider { +public: + gss_eap_saml_attr_provider(void) {} + ~gss_eap_saml_attr_provider(void) {} + + bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const; + bool setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value); + bool deleteAttribute(const gss_buffer_t value); + bool getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const; + gss_any_t mapToAny(int authenticated, + gss_buffer_t type_id) const; + void releaseAnyNameMapping(gss_buffer_t type_id, + gss_any_t input) const; + + const char *prefix(void) const; + const char *name(void) const { + return NULL; + } + bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED, + JSONObject &object GSSEAP_UNUSED) { + return false; + } + JSONObject jsonRepresentation(void) const { + return JSONObject::null(); + } + + bool getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + const opensaml::saml2::Attribute **pAttribute) const; + bool getAssertion(int *authenticated, + opensaml::saml2::Assertion **pAssertion, + bool createIfAbsent = false) const; + + static bool init(void); + static void finalize(void); + + static gss_eap_attr_provider *createAttrContext(void); + +private: +}; + +extern "C" { +#endif + +OM_uint32 gssEapSamlAttrProvidersInit(OM_uint32 *minor); +OM_uint32 gssEapSamlAttrProvidersFinalize(OM_uint32 *minor); + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIL_SAML_H_ */ diff --git a/mech_eap/util_shib.cpp b/mech_eap/util_shib.cpp new file mode 100644 index 0000000..7b62484 --- /dev/null +++ b/mech_eap/util_shib.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 2001-2009 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Local attribute provider implementation. + */ + +#include "gssapiP_eap.h" + +#include +#ifndef HAVE_OPENSAML +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace shibsp; +using namespace shibresolver; +using namespace xmltooling; +using namespace std; +#ifdef HAVE_OPENSAML +using namespace opensaml::saml2md; +using namespace opensaml; +#else +using namespace xercesc; +#endif + +gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void) +{ + m_initialized = false; + m_authenticated = false; +} + +gss_eap_shib_attr_provider::~gss_eap_shib_attr_provider(void) +{ + for_each(m_attributes.begin(), + m_attributes.end(), + xmltooling::cleanup()) + ; +} + +bool +gss_eap_shib_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager, + const gss_eap_attr_provider *ctx) +{ + const gss_eap_shib_attr_provider *shib; + + if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) { + return false; + } + + m_authenticated = false; + + shib = static_cast(ctx); + if (shib != NULL) { + m_attributes = duplicateAttributes(shib->getAttributes()); + m_authenticated = shib->authenticated(); + } + + m_initialized = true; + + return true; +} + +bool +gss_eap_shib_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager, + const gss_cred_id_t gssCred, + const gss_ctx_id_t gssCtx) +{ + if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx)) + return false; + + auto_ptr resolver(ShibbolethResolver::create()); + + /* + * For now, leave ApplicationID defaulted. + * Later on, we could allow this via config option to the mechanism + * or rely on an SPRequest interface to pass in a URI identifying the + * acceptor. + */ +#if 0 + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + if (gssCred != GSS_C_NO_CREDENTIAL && + gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE) { + resolver->setApplicationID((const char *)nameBuf.value); + gss_release_buffer(&minor, &nameBuf); + } +#endif + + gss_buffer_desc mechName = GSS_C_EMPTY_BUFFER; + OM_uint32 major, minor; + + major = gssEapExportNameInternal(&minor, gssCtx->initiatorName, &mechName, + EXPORT_NAME_FLAG_OID | + EXPORT_NAME_FLAG_COMPOSITE); + if (major == GSS_S_COMPLETE) { + resolver->addToken(&mechName); + gss_release_buffer(&minor, &mechName); + } + +#ifdef HAVE_OPENSAML + const gss_eap_saml_assertion_provider *saml; + saml = static_cast + (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION)); + if (saml != NULL && saml->getAssertion() != NULL) { + resolver->addToken(saml->getAssertion()); + } +#else + /* If no OpenSAML, parse the XML assertion explicitly */ + const gss_eap_radius_attr_provider *radius; + int authenticated, complete; + gss_buffer_desc value = GSS_C_EMPTY_BUFFER; + gss_eap_attrid attrid(VENDORPEC_UKERNA, PW_SAML_AAA_ASSERTION); + + radius = static_cast + (m_manager->getProvider(ATTR_TYPE_RADIUS)); + if (radius != NULL && + radius->getFragmentedAttribute(attrid, &authenticated, &complete, &value)) { + string str((char *)value.value, value.length); + istringstream istream(str); + DOMDocument *doc = XMLToolingConfig::getConfig().getParser().parse(istream); + const XMLObjectBuilder *b = XMLObjectBuilder::getBuilder(doc->getDocumentElement()); + resolver->addToken(b->buildFromDocument(doc)); + gss_release_buffer(&minor, &value); + } +#endif /* HAVE_OPENSAML */ + + try { + resolver->resolve(); + m_attributes = resolver->getResolvedAttributes(); + resolver->getResolvedAttributes().clear(); + } catch (exception &e) { + return false; + } + + m_authenticated = true; + m_initialized = true; + + return true; +} + +ssize_t +gss_eap_shib_attr_provider::getAttributeIndex(const gss_buffer_t attr) const +{ + int i = 0; + + GSSEAP_ASSERT(m_initialized); + + for (vector::const_iterator a = m_attributes.begin(); + a != m_attributes.end(); + ++a) + { + for (vector::const_iterator s = (*a)->getAliases().begin(); + s != (*a)->getAliases().end(); + ++s) { + if (attr->length == (*s).length() && + memcmp((*s).c_str(), attr->value, attr->length) == 0) { + return i; + } + } + } + + return -1; +} + +bool +gss_eap_shib_attr_provider::setAttribute(int complete GSSEAP_UNUSED, + const gss_buffer_t attr, + const gss_buffer_t value) +{ + string attrStr((char *)attr->value, attr->length); + vector ids(1, attrStr); + BinaryAttribute *a = new BinaryAttribute(ids); + + GSSEAP_ASSERT(m_initialized); + + if (value->length != 0) { + string valueStr((char *)value->value, value->length); + + a->getValues().push_back(valueStr); + } + + m_attributes.push_back(a); + m_authenticated = false; + + return true; +} + +bool +gss_eap_shib_attr_provider::deleteAttribute(const gss_buffer_t attr) +{ + int i; + + GSSEAP_ASSERT(m_initialized); + + i = getAttributeIndex(attr); + if (i >= 0) + m_attributes.erase(m_attributes.begin() + i); + + m_authenticated = false; + + return true; +} + +bool +gss_eap_shib_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, + void *data) const +{ + GSSEAP_ASSERT(m_initialized); + + for (vector::const_iterator a = m_attributes.begin(); + a != m_attributes.end(); + ++a) + { + gss_buffer_desc attribute; + + attribute.value = (void *)((*a)->getId()); + attribute.length = strlen((char *)attribute.value); + + if (!addAttribute(m_manager, this, &attribute, data)) + return false; + } + + return true; +} + +const Attribute * +gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr) const +{ + const Attribute *ret = NULL; + + GSSEAP_ASSERT(m_initialized); + + for (vector::const_iterator a = m_attributes.begin(); + a != m_attributes.end(); + ++a) + { + for (vector::const_iterator s = (*a)->getAliases().begin(); + s != (*a)->getAliases().end(); + ++s) { + if (attr->length == (*s).length() && + memcmp((*s).c_str(), attr->value, attr->length) == 0) { + ret = *a; + break; + } + } + if (ret != NULL) + break; + } + + return ret; +} + +bool +gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const +{ + const Attribute *shibAttr = NULL; + const BinaryAttribute *binaryAttr; + gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER; + gss_buffer_desc displayValueBuf = GSS_C_EMPTY_BUFFER; + int nvalues, i = *more; + + GSSEAP_ASSERT(m_initialized); + + *more = 0; + + shibAttr = getAttribute(attr); + if (shibAttr == NULL) + return false; + + nvalues = shibAttr->valueCount(); + + if (i == -1) + i = 0; + if (i >= nvalues) + return false; + + binaryAttr = dynamic_cast(shibAttr); + if (binaryAttr != NULL) { + std::string str = binaryAttr->getValues()[*more]; + + valueBuf.value = (void *)str.data(); + valueBuf.length = str.size(); + } else { + std::string str = shibAttr->getSerializedValues()[*more]; + + valueBuf.value = (void *)str.c_str(); + valueBuf.length = str.length(); + + const SimpleAttribute *simpleAttr = + dynamic_cast(shibAttr); + const ScopedAttribute *scopedAttr = + dynamic_cast(shibAttr); + if (simpleAttr != NULL || scopedAttr != NULL) + displayValueBuf = valueBuf; + } + + if (authenticated != NULL) + *authenticated = m_authenticated; + if (complete != NULL) + *complete = true; + if (value != NULL) + duplicateBuffer(valueBuf, value); + if (display_value != NULL) + duplicateBuffer(displayValueBuf, display_value); + if (nvalues > ++i) + *more = i; + + return true; +} + +gss_any_t +gss_eap_shib_attr_provider::mapToAny(int authenticated, + gss_buffer_t type_id GSSEAP_UNUSED) const +{ + gss_any_t output; + + GSSEAP_ASSERT(m_initialized); + + if (authenticated && !m_authenticated) + return (gss_any_t)NULL; + + vector v = duplicateAttributes(m_attributes); + + output = (gss_any_t)new vector (v); + + return output; +} + +void +gss_eap_shib_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED, + gss_any_t input) const +{ + GSSEAP_ASSERT(m_initialized); + + vector *v = ((vector *)input); + delete v; +} + +const char * +gss_eap_shib_attr_provider::prefix(void) const +{ + return NULL; +} + +const char * +gss_eap_shib_attr_provider::name(void) const +{ + return "local"; +} + +JSONObject +gss_eap_shib_attr_provider::jsonRepresentation(void) const +{ + JSONObject obj; + + if (m_initialized == false) + return obj; /* don't export incomplete context */ + + JSONObject jattrs = JSONObject::array(); + + for (vector::const_iterator a = m_attributes.begin(); + a != m_attributes.end(); ++a) { + DDF attr = (*a)->marshall(); + JSONObject jattr = JSONObject::ddf(attr); + jattrs.append(jattr); + } + + obj.set("attributes", jattrs); + + obj.set("authenticated", m_authenticated); + + return obj; +} + +bool +gss_eap_shib_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx, + JSONObject &obj) +{ + if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj)) + return false; + + GSSEAP_ASSERT(m_authenticated == false); + GSSEAP_ASSERT(m_attributes.size() == 0); + + JSONObject jattrs = obj["attributes"]; + size_t nelems = jattrs.size(); + + for (size_t i = 0; i < nelems; i++) { + JSONObject jattr = jattrs.get(i); + + DDF attr = jattr.ddf(); + Attribute *attribute = Attribute::unmarshall(attr); + m_attributes.push_back(attribute); + } + + m_authenticated = obj["authenticated"].integer(); + m_initialized = true; + + return true; +} + +bool +gss_eap_shib_attr_provider::init(void) +{ + bool ret = false; + + try { + ret = ShibbolethResolver::init(); + } catch (exception &e) { + } + + if (ret) + gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext); + + return ret; +} + +void +gss_eap_shib_attr_provider::finalize(void) +{ + gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_LOCAL); + ShibbolethResolver::term(); +} + +OM_uint32 +gss_eap_shib_attr_provider::mapException(OM_uint32 *minor, + std::exception &e) const +{ + if (typeid(e) == typeid(AttributeException)) + *minor = GSSEAP_SHIB_ATTR_FAILURE; + else if (typeid(e) == typeid(AttributeExtractionException)) + *minor = GSSEAP_SHIB_ATTR_EXTRACT_FAILURE; + else if (typeid(e) == typeid(AttributeFilteringException)) + *minor = GSSEAP_SHIB_ATTR_FILTER_FAILURE; + else if (typeid(e) == typeid(AttributeResolutionException)) + *minor = GSSEAP_SHIB_ATTR_RESOLVE_FAILURE; + else if (typeid(e) == typeid(ConfigurationException)) + *minor = GSSEAP_SHIB_CONFIG_FAILURE; + else if (typeid(e) == typeid(ListenerException)) + *minor = GSSEAP_SHIB_LISTENER_FAILURE; + else + return GSS_S_CONTINUE_NEEDED; + + gssEapSaveStatusInfo(*minor, "%s", e.what()); + + return GSS_S_FAILURE; +} + +gss_eap_attr_provider * +gss_eap_shib_attr_provider::createAttrContext(void) +{ + return new gss_eap_shib_attr_provider; +} + +Attribute * +gss_eap_shib_attr_provider::duplicateAttribute(const Attribute *src) +{ + DDF obj = src->marshall(); + Attribute *attribute = Attribute::unmarshall(obj); + obj.destroy(); + + return attribute; +} + +vector +gss_eap_shib_attr_provider::duplicateAttributes(const vector src) +{ + vector dst; + + for (vector::const_iterator a = src.begin(); + a != src.end(); + ++a) + dst.push_back(duplicateAttribute(*a)); + + return dst; +} + +OM_uint32 +gssEapLocalAttrProviderInit(OM_uint32 *minor) +{ + if (!gss_eap_shib_attr_provider::init()) { + *minor = GSSEAP_SHIB_INIT_FAILURE; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapLocalAttrProviderFinalize(OM_uint32 *minor) +{ + gss_eap_shib_attr_provider::finalize(); + + *minor = 0; + return GSS_S_COMPLETE; +} diff --git a/mech_eap/util_shib.h b/mech_eap/util_shib.h new file mode 100644 index 0000000..4cf7481 --- /dev/null +++ b/mech_eap/util_shib.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Local attribute provider. + */ + +#ifndef _UTIL_SHIB_H_ +#define _UTIL_SHIB_H_ 1 + +#ifdef __cplusplus + +#include + +namespace shibsp { + class Attribute; +}; + +namespace shibresolver { + class ShibbolethResolver; +}; + +struct gss_eap_shib_attr_provider : gss_eap_attr_provider { +public: + gss_eap_shib_attr_provider(void); + ~gss_eap_shib_attr_provider(void); + + bool initWithExistingContext(const gss_eap_attr_ctx *source, + const gss_eap_attr_provider *ctx); + bool initWithGssContext(const gss_eap_attr_ctx *source, + const gss_cred_id_t cred, + const gss_ctx_id_t ctx); + + bool setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value); + bool deleteAttribute(const gss_buffer_t value); + bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const; + bool getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const; + gss_any_t mapToAny(int authenticated, + gss_buffer_t type_id) const; + void releaseAnyNameMapping(gss_buffer_t type_id, + gss_any_t input) const; + + const char *prefix(void) const; + const char *name(void) const; + bool initWithJsonObject(const gss_eap_attr_ctx *manager, + JSONObject &obj); + JSONObject jsonRepresentation(void) const; + + static bool init(void); + static void finalize(void); + + OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const; + + static gss_eap_attr_provider *createAttrContext(void); + + std::vector getAttributes(void) const { + return m_attributes; + } + +private: + static shibsp::Attribute * + duplicateAttribute(const shibsp::Attribute *src); + static std::vector + duplicateAttributes(const std::vector src); + + ssize_t getAttributeIndex(const gss_buffer_t attr) const; + const shibsp::Attribute *getAttribute(const gss_buffer_t attr) const; + + bool authenticated(void) const { return m_authenticated; } + + bool m_initialized; + bool m_authenticated; + std::vector m_attributes; +}; + +extern "C" { +#endif + +OM_uint32 gssEapLocalAttrProviderInit(OM_uint32 *minor); +OM_uint32 gssEapLocalAttrProviderFinalize(OM_uint32 *minor); + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIL_SHIB_H_ */ diff --git a/mech_eap/util_sm.c b/mech_eap/util_sm.c new file mode 100644 index 0000000..a286bba --- /dev/null +++ b/mech_eap/util_sm.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Context establishment state machine. + */ + +#include "gssapiP_eap.h" + +/* private flags */ +#define SM_FLAG_TRANSITED 0x80000000 + +#define SM_ASSERT_VALID(ctx, status) do { \ + GSSEAP_ASSERT(GSS_ERROR((status)) || \ + ((status) == GSS_S_CONTINUE_NEEDED && ((ctx)->state > GSSEAP_STATE_INITIAL && (ctx)->state < GSSEAP_STATE_ESTABLISHED)) || \ + ((status) == GSS_S_COMPLETE && (ctx)->state == GSSEAP_STATE_ESTABLISHED)); \ + } while (0) + +#ifdef GSSEAP_DEBUG +static const char * +gssEapStateToString(enum gss_eap_state state) +{ + const char *s; + + switch (state) { + case GSSEAP_STATE_INITIAL: + s = "INITIAL"; + break; + case GSSEAP_STATE_AUTHENTICATE: + s = "AUTHENTICATE"; + break; + case GSSEAP_STATE_INITIATOR_EXTS: + s = "INITIATOR_EXTS"; + break; + case GSSEAP_STATE_ACCEPTOR_EXTS: + s = "ACCEPTOR_EXTS"; + break; +#ifdef GSSEAP_ENABLE_REAUTH + case GSSEAP_STATE_REAUTHENTICATE: + s = "REAUTHENTICATE"; + break; +#endif + case GSSEAP_STATE_ESTABLISHED: + s = "ESTABLISHED"; + break; + default: + s = "INVALID"; + break; + } + + return s; +} + +void +gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state) +{ + GSSEAP_ASSERT(state >= GSSEAP_STATE_INITIAL); + GSSEAP_ASSERT(state <= GSSEAP_STATE_ESTABLISHED); + + fprintf(stderr, "GSS-EAP: state transition %s->%s\n", + gssEapStateToString(GSSEAP_SM_STATE(ctx)), + gssEapStateToString(state)); + + ctx->state = state; +} +#endif /* GSSEAP_DEBUG */ + +static OM_uint32 +makeErrorToken(OM_uint32 *minor, + OM_uint32 majorStatus, + OM_uint32 minorStatus, + struct gss_eap_token_buffer_set *token) +{ + OM_uint32 major, tmpMinor; + unsigned char errorData[8]; + gss_buffer_desc errorBuffer; + + GSSEAP_ASSERT(GSS_ERROR(majorStatus)); + + /* + * Only return error codes that the initiator could have caused, + * to avoid information leakage. + */ + if (IS_RADIUS_ERROR(minorStatus)) { + /* Squash RADIUS error codes */ + minorStatus = GSSEAP_RADIUS_PROT_FAILURE; + } else if (!IS_WIRE_ERROR(minorStatus)) { + /* Don't return non-wire error codes */ + minorStatus = 0; + } + + if (minorStatus != 0) + minorStatus -= ERROR_TABLE_BASE_eapg; + + store_uint32_be(majorStatus, &errorData[0]); + store_uint32_be(minorStatus, &errorData[4]); + + major = gssEapAllocInnerTokens(&tmpMinor, 1, token); + if (GSS_ERROR(major)) { + *minor = tmpMinor; + return major; + } + + errorBuffer.length = sizeof(errorData); + errorBuffer.value = errorData; + + major = duplicateBuffer(&tmpMinor, &errorBuffer, &token->buffers.elements[0]); + if (GSS_ERROR(major)) { + gssEapReleaseInnerTokens(&tmpMinor, token, 1); + *minor = tmpMinor; + return major; + } + + token->buffers.count = 1; + token->types[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapSmStep(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech, + OM_uint32 reqFlags, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + struct gss_eap_sm *sm, /* ordered by state */ + size_t smCount) +{ + OM_uint32 major, tmpMajor, tmpMinor; + struct gss_eap_token_buffer_set inputTokens = { { 0, GSS_C_NO_BUFFER }, NULL }; + struct gss_eap_token_buffer_set outputTokens = { { 0, GSS_C_NO_BUFFER }, NULL }; + gss_buffer_desc unwrappedInputToken = GSS_C_EMPTY_BUFFER; + gss_buffer_desc unwrappedOutputToken = GSS_C_EMPTY_BUFFER; + unsigned int smFlags = 0; + size_t i, j; + int initialContextToken = 0; + enum gss_eap_token_type tokType; + + GSSEAP_ASSERT(smCount > 0); + + *minor = 0; + + outputToken->length = 0; + outputToken->value = NULL; + + if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) { + major = gssEapVerifyToken(minor, ctx, inputToken, &tokType, + &unwrappedInputToken); + if (GSS_ERROR(major)) + goto cleanup; + + if (tokType != (CTX_IS_INITIATOR(ctx) + ? TOK_TYPE_ACCEPTOR_CONTEXT : TOK_TYPE_INITIATOR_CONTEXT)) { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_WRONG_TOK_ID; + goto cleanup; + } + } else if (!CTX_IS_INITIATOR(ctx) || ctx->state != GSSEAP_STATE_INITIAL) { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_WRONG_SIZE; + goto cleanup; + } else { + initialContextToken = 1; + } + + if (CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_BAD_STATUS; + *minor = GSSEAP_CONTEXT_ESTABLISHED; + goto cleanup; + } + + GSSEAP_ASSERT(ctx->state < GSSEAP_STATE_ESTABLISHED); + + major = gssEapDecodeInnerTokens(minor, &unwrappedInputToken, &inputTokens); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapAllocInnerTokens(minor, smCount, &outputTokens); + if (GSS_ERROR(major)) + goto cleanup; + + ctx->inputTokens = &inputTokens; + ctx->outputTokens = &outputTokens; + + /* Process all the tokens that are valid for the current state. */ + for (i = 0; i < smCount; i++) { + struct gss_eap_sm *smp = &sm[i]; + int processToken = 0; + gss_buffer_t innerInputToken = GSS_C_NO_BUFFER; + OM_uint32 *inputTokenType = NULL; + gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER; + + if ((smp->validStates & ctx->state) == 0) + continue; + + /* + * We special case the first call to gss_init_sec_context so that + * all token providers have the opportunity to generate an initial + * context token. Providers where inputTokenType is ITOK_TYPE_NONE + * are always called and generally act on state transition boundaries, + * for example to advance the state after a series of optional tokens + * (as is the case with the extension token exchange) or to generate + * a new token after the state was advanced by a provider which did + * not emit a token. + */ + if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) { + processToken = 1; + } else if ((smFlags & SM_FLAG_TRANSITED) == 0) { + /* Don't regurgitate a token which belonds to a previous state. */ + for (j = 0; j < inputTokens.buffers.count; j++) { + if ((inputTokens.types[j] & ITOK_TYPE_MASK) == smp->inputTokenType) { + if (processToken) { + /* Check for duplicate inner tokens */ + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_DUPLICATE_ITOK; + break; + } + processToken = 1; + innerInputToken = &inputTokens.buffers.elements[j]; + inputTokenType = &inputTokens.types[j]; + } + } + if (GSS_ERROR(major)) + break; + } + + if (processToken) { + enum gss_eap_state oldState = ctx->state; + + smFlags = 0; + if (inputTokenType != NULL && (*inputTokenType & ITOK_FLAG_CRITICAL)) + smFlags |= SM_FLAG_INPUT_TOKEN_CRITICAL; + + major = smp->processToken(minor, cred, ctx, target, mech, reqFlags, + timeReq, chanBindings, innerInputToken, + &innerOutputToken, &smFlags); + if (GSS_ERROR(major)) + break; + + if (inputTokenType != NULL) + *inputTokenType |= ITOK_FLAG_VERIFIED; + if (ctx->state < oldState) + i = 0; /* restart */ + else if (ctx->state != oldState) + smFlags |= SM_FLAG_TRANSITED; + + if (innerOutputToken.value != NULL) { + outputTokens.buffers.elements[outputTokens.buffers.count] = innerOutputToken; + GSSEAP_ASSERT(smp->outputTokenType != ITOK_TYPE_NONE); + outputTokens.types[outputTokens.buffers.count] = smp->outputTokenType; + if (smFlags & SM_FLAG_OUTPUT_TOKEN_CRITICAL) + outputTokens.types[outputTokens.buffers.count] |= ITOK_FLAG_CRITICAL; + outputTokens.buffers.count++; + } + /* + * Break out if we made a state transition and have some tokens to send. + */ + if ((smFlags & SM_FLAG_TRANSITED) && + ((smFlags & SM_FLAG_FORCE_SEND_TOKEN) || outputTokens.buffers.count != 0)) { + SM_ASSERT_VALID(ctx, major); + break; + } + } else if ((smp->itokFlags & SM_ITOK_FLAG_REQUIRED) && + smp->inputTokenType != ITOK_TYPE_NONE) { + /* Check for required inner tokens */ + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_MISSING_REQUIRED_ITOK; + break; + } + } + + GSSEAP_ASSERT(outputTokens.buffers.count <= smCount); + + /* Check we understood all critical tokens sent by peer */ + if (!GSS_ERROR(major)) { + for (j = 0; j < inputTokens.buffers.count; j++) { + if ((inputTokens.types[j] & ITOK_FLAG_CRITICAL) && + (inputTokens.types[j] & ITOK_FLAG_VERIFIED) == 0) { + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_CRIT_ITOK_UNAVAILABLE; + goto cleanup; + } + } + } + + /* Optionaly emit an error token if we are the acceptor */ + if (GSS_ERROR(major)) { + if (CTX_IS_INITIATOR(ctx)) + goto cleanup; /* return error directly to caller */ + + /* replace any emitted tokens with error token */ + gssEapReleaseInnerTokens(&tmpMinor, &outputTokens, 1); + + tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &outputTokens); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + goto cleanup; + } + } + + /* Format output token from inner tokens */ + if (outputTokens.buffers.count != 0 || /* inner tokens to send */ + !CTX_IS_INITIATOR(ctx) || /* any leg acceptor */ + !CTX_IS_ESTABLISHED(ctx)) { /* non-last leg initiator */ + tmpMajor = gssEapEncodeInnerTokens(&tmpMinor, &outputTokens, &unwrappedOutputToken); + if (tmpMajor == GSS_S_COMPLETE) { + if (CTX_IS_INITIATOR(ctx)) + tokType = TOK_TYPE_INITIATOR_CONTEXT; + else + tokType = TOK_TYPE_ACCEPTOR_CONTEXT; + + tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &unwrappedOutputToken, + tokType, outputToken); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + goto cleanup; + } + } + } + + /* If the context is established, empty tokens only to be emitted by initiator */ + GSSEAP_ASSERT(!CTX_IS_ESTABLISHED(ctx) || ((outputToken->length == 0) == CTX_IS_INITIATOR(ctx))); + + SM_ASSERT_VALID(ctx, major); + +cleanup: + gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 0); + gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 1); + + gss_release_buffer(&tmpMinor, &unwrappedOutputToken); + + ctx->inputTokens = NULL; + ctx->outputTokens = NULL; + + return major; +} diff --git a/mech_eap/util_tld.c b/mech_eap/util_tld.c new file mode 100644 index 0000000..05bc3d1 --- /dev/null +++ b/mech_eap/util_tld.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Thread local data abstraction, using pthreads on Unix and the TlsXXX + * APIs on Windows. + */ + +#include "gssapiP_eap.h" + +/* Clean up thread-local data; called on thread detach */ +static void +destroyThreadLocalData(struct gss_eap_thread_local_data *tld) +{ + if (tld->statusInfo != NULL) + gssEapDestroyStatusInfo(tld->statusInfo); + if (tld->krbContext != NULL) + gssEapDestroyKrbContext(tld->krbContext); + GSSEAP_FREE(tld); +} + +#ifdef WIN32 + +/* + * This is the TLS index returned by TlsAlloc() on process init. + * Each thread, on thread attach in DllMain(), allocates its thread-local + * data and uses this index with TlsSetValue() to store it. + * It can then subsequently be retrieved with TlsGetValue(). + */ +static DWORD tlsIndex = TLS_OUT_OF_INDEXES; + +/* Access thread-local data */ +struct gss_eap_thread_local_data * +gssEapGetThreadLocalData(void) +{ + struct gss_eap_thread_local_data *tlsData; + + GSSEAP_ASSERT(tlsIndex != TLS_OUT_OF_INDEXES); + + tlsData = TlsGetValue(tlsIndex); + if (tlsData == NULL) { + tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData)); + TlsSetValue(tlsIndex, tlsData); + } + + return tlsData; +} + +BOOL WINAPI +DllMain(HINSTANCE hDLL, /* DLL module handle */ + DWORD reason, /* reason called */ + LPVOID reserved) /* reserved */ +{ + struct gss_eap_thread_local_data *tlsData; + OM_uint32 major, minor; + + switch (reason) { + case DLL_PROCESS_ATTACH: + /* Allocate a TLS index. */ + major = gssEapInitiatorInit(&minor); + if (GSS_ERROR(major)) + return FALSE; + + tlsIndex = TlsAlloc(); + if (tlsIndex == TLS_OUT_OF_INDEXES) + return FALSE; + /* No break: Initialize the index for first thread.*/ + case DLL_THREAD_ATTACH: + /* Initialize the TLS index for this thread. */ + tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData)); + if (tlsData == NULL) + return FALSE; + TlsSetValue(tlsIndex, tlsData); + break; + case DLL_THREAD_DETACH: + /* Release the allocated memory for this thread. */ + tlsData = TlsGetValue(tlsIndex); + if (tlsData != NULL) { + destroyThreadLocalData(tlsData); + TlsSetValue(tlsIndex, NULL); + } + break; + case DLL_PROCESS_DETACH: + /* Release the TLS index. */ + TlsFree(tlsIndex); + gssEapFinalize(); + break; + default: + break; + } + + return TRUE; + UNREFERENCED_PARAMETER(hDLL); + UNREFERENCED_PARAMETER(reserved); +} + +#else /* WIN32 */ + +/* pthreads implementation */ + +static GSSEAP_THREAD_ONCE tldKeyOnce = GSSEAP_ONCE_INITIALIZER; +static GSSEAP_THREAD_KEY tldKey; + +static void +pthreadDestroyThreadLocalData(void *arg) +{ + struct gss_eap_thread_local_data* tld = arg; + + if (tld != NULL) + destroyThreadLocalData(tld); +} + +static void +createThreadLocalDataKey(void) +{ + GSSEAP_KEY_CREATE(&tldKey, pthreadDestroyThreadLocalData); +} + +struct gss_eap_thread_local_data * +gssEapGetThreadLocalData() +{ + struct gss_eap_thread_local_data *tld; + + GSSEAP_ONCE(&tldKeyOnce, createThreadLocalDataKey); + + tld = GSSEAP_GETSPECIFIC(tldKey); + if (tld == NULL) { + tld = GSSEAP_CALLOC(1, sizeof(*tld)); + if (tld == NULL) + return NULL; + + GSSEAP_SETSPECIFIC(tldKey, tld); + } + + return tld; +} + +#endif /* WIN32 */ diff --git a/mech_eap/util_token.c b/mech_eap/util_token.c new file mode 100644 index 0000000..d94c437 --- /dev/null +++ b/mech_eap/util_token.c @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Portions Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Utility routines for GSS tokens. + */ + +#include "gssapiP_eap.h" + +OM_uint32 +gssEapEncodeInnerTokens(OM_uint32 *minor, + struct gss_eap_token_buffer_set *tokens, + gss_buffer_t buffer) +{ + OM_uint32 major, tmpMinor; + size_t required = 0, i; + unsigned char *p; + + buffer->value = NULL; + buffer->length = 0; + + for (i = 0; i < tokens->buffers.count; i++) { + required += 8 + tokens->buffers.elements[i].length; + } + + /* + * We must always return a non-NULL token otherwise the calling state + * machine assumes we are finished. Hence care in case malloc(0) does + * return NULL. + */ + buffer->value = GSSEAP_MALLOC(required ? required : 1); + if (buffer->value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + buffer->length = required; + p = (unsigned char *)buffer->value; + + for (i = 0; i < tokens->buffers.count; i++) { + gss_buffer_t tokenBuffer = &tokens->buffers.elements[i]; + + GSSEAP_ASSERT((tokens->types[i] & ITOK_FLAG_VERIFIED) == 0); /* private flag */ + + /* + * Extensions are encoded as type-length-value, where the upper + * bit of the type indicates criticality. + */ + store_uint32_be(tokens->types[i], &p[0]); + store_uint32_be(tokenBuffer->length, &p[4]); + memcpy(&p[8], tokenBuffer->value, tokenBuffer->length); + + p += 8 + tokenBuffer->length; + } + + GSSEAP_ASSERT(p == (unsigned char *)buffer->value + required); + GSSEAP_ASSERT(buffer->value != NULL); + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) { + gss_release_buffer(&tmpMinor, buffer); + } + + return major; +} + +OM_uint32 +gssEapDecodeInnerTokens(OM_uint32 *minor, + const gss_buffer_t buffer, + struct gss_eap_token_buffer_set *tokens) +{ + OM_uint32 major, tmpMinor; + unsigned char *p; + size_t count = 0; + size_t remain; + + tokens->buffers.count = 0; + tokens->buffers.elements = NULL; + tokens->types = NULL; + + if (buffer->length == 0) { + major = GSS_S_COMPLETE; + goto cleanup; + } + + p = (unsigned char *)buffer->value; + remain = buffer->length; + + do { + OM_uint32 *ntypes; + gss_buffer_desc tokenBuffer, *newTokenBuffers; + + if (remain < 8) { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_TOK_TRUNC; + goto cleanup; + } + + if (tokens->buffers.count <= count) { + if (count == 0) + count = 1; + else + count *= 2; + + ntypes = GSSEAP_MALLOC(count * sizeof(OM_uint32)); + if (ntypes == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + if (tokens->types != NULL) { + memcpy(ntypes, tokens->types, tokens->buffers.count * sizeof(OM_uint32)); + GSSEAP_FREE(tokens->types); + } + tokens->types = ntypes; + + newTokenBuffers = GSSEAP_MALLOC(count * sizeof(gss_buffer_desc)); + if (newTokenBuffers == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + if (tokens->buffers.elements != NULL) { + memcpy(newTokenBuffers, tokens->buffers.elements, + tokens->buffers.count * sizeof(gss_buffer_desc)); + GSSEAP_FREE(tokens->buffers.elements); + } + tokens->buffers.elements = newTokenBuffers; + } + + tokens->types[tokens->buffers.count] = load_uint32_be(&p[0]); + tokenBuffer.length = load_uint32_be(&p[4]); + + if (remain < 8 + tokenBuffer.length) { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_TOK_TRUNC; + goto cleanup; + } + tokenBuffer.value = &p[8]; + + tokens->buffers.elements[tokens->buffers.count] = tokenBuffer; + tokens->buffers.count++; + + p += 8 + tokenBuffer.length; + remain -= 8 + tokenBuffer.length; + } while (remain != 0); + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) + gssEapReleaseInnerTokens(&tmpMinor, tokens, 0); + + return major; +} + +/* + * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $ + */ + +/* XXXX this code currently makes the assumption that a mech oid will + never be longer than 127 bytes. This assumption is not inherent in + the interfaces, so the code can be fixed if the OSI namespace + balloons unexpectedly. */ + +/* + * Each token looks like this: + * 0x60 tag for APPLICATION 0, SEQUENCE + * (constructed, definite-length) + * possible multiple bytes, need to parse/generate + * 0x06 tag for OBJECT IDENTIFIER + * compile-time constant string (assume 1 byte) + * compile-time constant string + * the ANY containing the application token + * bytes 0,1 are the token type + * bytes 2,n are the token data + * + * Note that the token type field is a feature of RFC 1964 mechanisms and + * is not used by other GSSAPI mechanisms. As such, a token type of -1 + * is interpreted to mean that no token type should be expected or + * generated. + * + * For the purposes of this abstraction, the token "header" consists of + * the sequence tag and length octets, the mech OID DER encoding, and the + * first two inner bytes, which indicate the token type. The token + * "body" consists of everything else. + */ + +static size_t +der_length_size(size_t length) +{ + if (length < (1<<7)) + return 1; + else if (length < (1<<8)) + return 2; +#if INT_MAX == 0x7fff + else + return 3; +#else + else if (length < (1<<16)) + return 3; + else if (length < (1<<24)) + return 4; + else + return 5; +#endif +} + +static void +der_write_length(unsigned char **buf, size_t length) +{ + if (length < (1<<7)) { + *(*buf)++ = (unsigned char)length; + } else { + *(*buf)++ = (unsigned char)(der_length_size(length)+127); +#if INT_MAX > 0x7fff + if (length >= (1<<24)) + *(*buf)++ = (unsigned char)(length>>24); + if (length >= (1<<16)) + *(*buf)++ = (unsigned char)((length>>16)&0xff); +#endif + if (length >= (1<<8)) + *(*buf)++ = (unsigned char)((length>>8)&0xff); + *(*buf)++ = (unsigned char)(length&0xff); + } +} + +/* returns decoded length, or < 0 on failure. Advances buf and + decrements bufsize */ + +static int +der_read_length(unsigned char **buf, ssize_t *bufsize) +{ + unsigned char sf; + int ret; + + if (*bufsize < 1) + return -1; + + sf = *(*buf)++; + (*bufsize)--; + if (sf & 0x80) { + if ((sf &= 0x7f) > ((*bufsize)-1)) + return -1; + if (sf > sizeof(int)) + return -1; + ret = 0; + for (; sf; sf--) { + ret = (ret<<8) + (*(*buf)++); + (*bufsize)--; + } + } else { + ret = sf; + } + + return ret; +} + +/* returns the length of a token, given the mech oid and the body size */ + +size_t +tokenSize(const gss_OID_desc *mech, size_t body_size) +{ + GSSEAP_ASSERT(mech != GSS_C_NO_OID); + + /* set body_size to sequence contents size */ + body_size += 4 + (size_t) mech->length; /* NEED overflow check */ + return 1 + der_length_size(body_size) + body_size; +} + +/* fills in a buffer with the token header. The buffer is assumed to + be the right size. buf is advanced past the token header */ + +void +makeTokenHeader( + const gss_OID_desc *mech, + size_t body_size, + unsigned char **buf, + enum gss_eap_token_type tok_type) +{ + *(*buf)++ = 0x60; + der_write_length(buf, 4 + mech->length + body_size); + *(*buf)++ = 0x06; + *(*buf)++ = (unsigned char)mech->length; + memcpy(*buf, mech->elements, mech->length); + *buf += mech->length; + GSSEAP_ASSERT(tok_type != TOK_TYPE_NONE); + *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff); + *(*buf)++ = (unsigned char)(tok_type & 0xff); +} + +/* + * Given a buffer containing a token, reads and verifies the token, + * leaving buf advanced past the token header, and setting body_size + * to the number of remaining bytes. Returns 0 on success, + * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the + * mechanism in the token does not match the mech argument. buf and + * *body_size are left unmodified on error. + */ + +OM_uint32 +verifyTokenHeader(OM_uint32 *minor, + gss_OID mech, + size_t *body_size, + unsigned char **buf_in, + size_t toksize_in, + enum gss_eap_token_type *ret_tok_type) +{ + unsigned char *buf = *buf_in; + ssize_t seqsize; + gss_OID_desc toid; + ssize_t toksize = (ssize_t)toksize_in; + + *minor = GSSEAP_BAD_TOK_HEADER; + + if (ret_tok_type != NULL) + *ret_tok_type = TOK_TYPE_NONE; + + if ((toksize -= 1) < 0) + return GSS_S_DEFECTIVE_TOKEN; + + if (*buf++ != 0x60) + return GSS_S_DEFECTIVE_TOKEN; + + seqsize = der_read_length(&buf, &toksize); + if (seqsize < 0) + return GSS_S_DEFECTIVE_TOKEN; + + if (seqsize != toksize) + return GSS_S_DEFECTIVE_TOKEN; + + if ((toksize -= 1) < 0) + return GSS_S_DEFECTIVE_TOKEN; + + if (*buf++ != 0x06) + return GSS_S_DEFECTIVE_TOKEN; + + if ((toksize -= 1) < 0) + return GSS_S_DEFECTIVE_TOKEN; + + toid.length = *buf++; + + if ((toksize -= toid.length) < 0) + return GSS_S_DEFECTIVE_TOKEN; + + toid.elements = buf; + buf += toid.length; + + if (mech->elements == NULL) { + *mech = toid; + if (toid.length == 0) + return GSS_S_BAD_MECH; + } else if (!oidEqual(&toid, mech)) { + *minor = GSSEAP_WRONG_MECH; + return GSS_S_BAD_MECH; + } + + if (ret_tok_type != NULL) { + if ((toksize -= 2) < 0) + return GSS_S_DEFECTIVE_TOKEN; + + *ret_tok_type = load_uint16_be(buf); + buf += 2; + } + + *buf_in = buf; + *body_size = toksize; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapAllocInnerTokens(OM_uint32 *minor, + size_t count, + struct gss_eap_token_buffer_set *tokens) +{ + OM_uint32 major; + + tokens->buffers.count = 0; + tokens->buffers.elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc)); + if (tokens->buffers.elements == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + tokens->types = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32)); + if (tokens->types == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + if (GSS_ERROR(major)) { + if (tokens->buffers.elements != NULL) { + GSSEAP_FREE(tokens->buffers.elements); + tokens->buffers.elements = NULL; + } + if (tokens->types != NULL) { + GSSEAP_FREE(tokens->types); + tokens->types = NULL; + } + } + + return major; +} + +OM_uint32 +gssEapReleaseInnerTokens(OM_uint32 *minor, + struct gss_eap_token_buffer_set *tokens, + int freeBuffers) +{ + OM_uint32 tmpMinor; + size_t i; + + if (tokens->buffers.elements != NULL) { + if (freeBuffers) { + for (i = 0; i < tokens->buffers.count; i++) + gss_release_buffer(&tmpMinor, &tokens->buffers.elements[i]); + } + GSSEAP_FREE(tokens->buffers.elements); + tokens->buffers.elements = NULL; + } + tokens->buffers.count = 0; + + if (tokens->types != NULL) { + GSSEAP_FREE(tokens->types); + tokens->types = NULL; + } + + *minor = 0; + return GSS_S_COMPLETE; +} diff --git a/mech_eap/verify_mic.c b/mech_eap/verify_mic.c new file mode 100644 index 0000000..c0829f5 --- /dev/null +++ b/mech_eap/verify_mic.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Message protection services: verify a message integrity check. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_verify_mic(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t message_buffer, + gss_buffer_t message_token, + gss_qop_t *qop_state) +{ + OM_uint32 major; + gss_iov_buffer_desc iov[3]; + int conf_state; + + if (message_token->length < 16) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_BAD_SIG; + } + + *minor = 0; + + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[0].buffer = *message_buffer; + + iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[1].buffer = *message_token; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapUnwrapOrVerifyMIC(minor, ctx, &conf_state, qop_state, + iov, 2, TOK_TYPE_MIC); + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/wrap.c b/mech_eap/wrap.c new file mode 100644 index 0000000..2e27fb3 --- /dev/null +++ b/mech_eap/wrap.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Message protection services: wrap. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_wrap(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + OM_uint32 major; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + major = gssEapWrap(minor, ctx, conf_req_flag, qop_req, + input_message_buffer, + conf_state, output_message_buffer); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} + +OM_uint32 +gssEapWrap(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + OM_uint32 major, tmpMinor; + gss_iov_buffer_desc iov[4]; + unsigned char *p; + int i; + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer.value = NULL; + iov[0].buffer.length = 0; + + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[1].buffer = *input_message_buffer; + + iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING; + iov[2].buffer.value = NULL; + iov[2].buffer.length = 0; + + iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER; + iov[3].buffer.value = NULL; + iov[3].buffer.length = 0; + + major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req, + NULL, iov, 4); + if (GSS_ERROR(major)) { + return major; + } + + for (i = 0, output_message_buffer->length = 0; i < 4; i++) { + output_message_buffer->length += iov[i].buffer.length; + } + + output_message_buffer->value = GSSEAP_MALLOC(output_message_buffer->length); + if (output_message_buffer->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + for (i = 0, p = output_message_buffer->value; i < 4; i++) { + if (iov[i].type == GSS_IOV_BUFFER_TYPE_DATA) { + memcpy(p, input_message_buffer->value, input_message_buffer->length); + } + iov[i].buffer.value = p; + p += iov[i].buffer.length; + } + + major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state, + iov, 4, TOK_TYPE_WRAP); + if (GSS_ERROR(major)) { + gss_release_buffer(&tmpMinor, output_message_buffer); + } + + return major; +} diff --git a/mech_eap/wrap_iov.c b/mech_eap/wrap_iov.c new file mode 100644 index 0000000..be890b6 --- /dev/null +++ b/mech_eap/wrap_iov.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 2008 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Message protection services: wrap with scatter-gather API. + */ + +#include "gssapiP_eap.h" + +unsigned char +rfc4121Flags(gss_ctx_id_t ctx, int receiving) +{ + unsigned char flags; + int isAcceptor; + + isAcceptor = !CTX_IS_INITIATOR(ctx); + if (receiving) + isAcceptor = !isAcceptor; + + flags = 0; + if (isAcceptor) + flags |= TOK_FLAG_SENDER_IS_ACCEPTOR; + + if ((ctx->flags & CTX_FLAG_KRB_REAUTH) && + (ctx->gssFlags & GSS_C_MUTUAL_FLAG)) + flags |= TOK_FLAG_ACCEPTOR_SUBKEY; + + return flags; +} + +OM_uint32 +gssEapWrapOrGetMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype) +{ + krb5_error_code code = 0; + gss_iov_buffer_t header; + gss_iov_buffer_t padding; + gss_iov_buffer_t trailer; + unsigned char flags; + unsigned char *outbuf = NULL; + unsigned char *tbuf = NULL; + int keyUsage; + size_t rrc = 0; + size_t gssHeaderLen, gssTrailerLen; + size_t dataLen, assocDataLen; + krb5_context krbContext; +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto = NULL; +#endif + + if (ctx->encryptionType == ENCTYPE_NULL) { + *minor = GSSEAP_KEY_UNAVAILABLE; + return GSS_S_UNAVAILABLE; + } + + GSSEAP_KRB_INIT(&krbContext); + + flags = rfc4121Flags(ctx, FALSE); + + if (toktype == TOK_TYPE_WRAP) { + keyUsage = CTX_IS_INITIATOR(ctx) + ? KEY_USAGE_INITIATOR_SEAL + : KEY_USAGE_ACCEPTOR_SEAL; + } else { + keyUsage = CTX_IS_INITIATOR(ctx) + ? KEY_USAGE_INITIATOR_SIGN + : KEY_USAGE_ACCEPTOR_SIGN; + } + + gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen); + + header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor = GSSEAP_MISSING_IOV; + return GSS_S_FAILURE; + } + + padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL) + padding->buffer.length = 0; + + trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto); + if (code != 0) + goto cleanup; +#endif + + if (toktype == TOK_TYPE_WRAP && conf_req_flag) { + size_t krbHeaderLen, krbTrailerLen, krbPadLen; + size_t ec = 0, confDataLen = dataLen - assocDataLen; + + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen); + if (code != 0) + goto cleanup; + + code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + confDataLen + 16 /* E(Header) */, + &krbPadLen); + if (code != 0) + goto cleanup; + + if (krbPadLen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) { + /* Windows rejects AEAD tokens with non-zero EC */ + code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec); + if (code != 0) + goto cleanup; + } else + ec = krbPadLen; + + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + KRB5_CRYPTO_TYPE_TRAILER, &krbTrailerLen); + if (code != 0) + goto cleanup; + + gssHeaderLen = 16 /* Header */ + krbHeaderLen; + gssTrailerLen = ec + 16 /* E(Header) */ + krbTrailerLen; + + if (trailer == NULL) { + rrc = gssTrailerLen; + /* Workaround for Windows bug where it rotates by EC + RRC */ + if (ctx->gssFlags & GSS_C_DCE_STYLE) + rrc -= ec; + gssHeaderLen += gssTrailerLen; + } + + if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + code = gssEapAllocIov(header, (size_t)gssHeaderLen); + } else if (header->buffer.length < gssHeaderLen) + code = GSSEAP_WRONG_SIZE; + if (code != 0) + goto cleanup; + outbuf = (unsigned char *)header->buffer.value; + header->buffer.length = (size_t)gssHeaderLen; + + if (trailer != NULL) { + if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) + code = gssEapAllocIov(trailer, (size_t)gssTrailerLen); + else if (trailer->buffer.length < gssTrailerLen) + code = GSSEAP_WRONG_SIZE; + if (code != 0) + goto cleanup; + trailer->buffer.length = (size_t)gssTrailerLen; + } + + /* TOK_ID */ + store_uint16_be((uint16_t)toktype, outbuf); + /* flags */ + outbuf[2] = flags + | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0); + /* filler */ + outbuf[3] = 0xFF; + /* EC */ + store_uint16_be(ec, outbuf + 4); + /* RRC */ + store_uint16_be(0, outbuf + 6); + store_uint64_be(ctx->sendSeq, outbuf + 8); + + /* + * EC | copy of header to be encrypted, located in + * (possibly rotated) trailer + */ + if (trailer == NULL) + tbuf = (unsigned char *)header->buffer.value + 16; /* Header */ + else + tbuf = (unsigned char *)trailer->buffer.value; + + memset(tbuf, 0xFF, ec); + memcpy(tbuf + ec, header->buffer.value, 16); + + code = gssEapEncrypt(krbContext, + ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0), + ec, rrc, KRB_CRYPTO_CONTEXT(ctx), + keyUsage, iov, iov_count); + if (code != 0) + goto cleanup; + + /* RRC */ + store_uint16_be(rrc, outbuf + 6); + + ctx->sendSeq++; + } else if (toktype == TOK_TYPE_WRAP && !conf_req_flag) { + wrap_with_checksum: + + gssHeaderLen = 16; + + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + KRB5_CRYPTO_TYPE_CHECKSUM, &gssTrailerLen); + if (code != 0) + goto cleanup; + + GSSEAP_ASSERT(gssTrailerLen <= 0xFFFF); + + if (trailer == NULL) { + rrc = gssTrailerLen; + gssHeaderLen += gssTrailerLen; + } + + if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) + code = gssEapAllocIov(header, (size_t)gssHeaderLen); + else if (header->buffer.length < gssHeaderLen) + code = GSSEAP_WRONG_SIZE; + if (code != 0) + goto cleanup; + outbuf = (unsigned char *)header->buffer.value; + header->buffer.length = (size_t)gssHeaderLen; + + if (trailer != NULL) { + if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) + code = gssEapAllocIov(trailer, (size_t)gssTrailerLen); + else if (trailer->buffer.length < gssTrailerLen) + code = GSSEAP_WRONG_SIZE; + if (code != 0) + goto cleanup; + trailer->buffer.length = (size_t)gssTrailerLen; + } + + /* TOK_ID */ + store_uint16_be((uint16_t)toktype, outbuf); + /* flags */ + outbuf[2] = flags; + /* filler */ + outbuf[3] = 0xFF; + if (toktype == TOK_TYPE_WRAP) { + /* Use 0 for checksum calculation, substitute + * checksum length later. + */ + /* EC */ + store_uint16_be(0, outbuf + 4); + /* RRC */ + store_uint16_be(0, outbuf + 6); + } else { + /* MIC and DEL store 0xFF in EC and RRC */ + store_uint16_be(0xFFFF, outbuf + 4); + store_uint16_be(0xFFFF, outbuf + 6); + } + store_uint64_be(ctx->sendSeq, outbuf + 8); + + code = gssEapSign(krbContext, ctx->checksumType, rrc, + KRB_CRYPTO_CONTEXT(ctx), keyUsage, + iov, iov_count); + if (code != 0) + goto cleanup; + + ctx->sendSeq++; + + if (toktype == TOK_TYPE_WRAP) { + /* Fix up EC field */ + store_uint16_be(gssTrailerLen, outbuf + 4); + /* Fix up RRC field */ + store_uint16_be(rrc, outbuf + 6); + } + } else if (toktype == TOK_TYPE_MIC) { + trailer = NULL; + goto wrap_with_checksum; + } else if (toktype == TOK_TYPE_DELETE_CONTEXT) { + trailer = NULL; + goto wrap_with_checksum; + } else { + abort(); + } + + code = 0; + if (conf_state != NULL) + *conf_state = conf_req_flag; + +cleanup: + if (code != 0) + gssEapReleaseIov(iov, iov_count); +#ifdef HAVE_HEIMDAL_VERSION + if (krbCrypto != NULL) + krb5_crypto_destroy(krbContext, krbCrypto); +#endif + + *minor = code; + + return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_wrap_iov(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + if (qop_req != GSS_C_QOP_DEFAULT) { + *minor = GSSEAP_UNKNOWN_QOP; + return GSS_S_UNAVAILABLE; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state, + iov, iov_count, TOK_TYPE_WRAP); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/wrap_iov_length.c b/mech_eap/wrap_iov_length.c new file mode 100644 index 0000000..5621aed --- /dev/null +++ b/mech_eap/wrap_iov_length.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright 2008 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Message protection services: determine protected message size. + */ + +#include "gssapiP_eap.h" + +#define INIT_IOV_DATA(_iov) do { (_iov)->buffer.value = NULL; \ + (_iov)->buffer.length = 0; } \ + while (0) + +OM_uint32 +gssEapWrapIovLength(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + gss_iov_buffer_t header, trailer, padding; + size_t dataLength, assocDataLength; + size_t gssHeaderLen, gssPadLen, gssTrailerLen; + size_t krbHeaderLen = 0, krbTrailerLen = 0, krbPadLen = 0; + krb5_error_code code; + krb5_context krbContext; + int dce_style; + size_t ec; +#ifdef HAVE_HEIMDAL_VERSION + krb5_crypto krbCrypto = NULL; +#endif + + if (qop_req != GSS_C_QOP_DEFAULT) { + *minor = GSSEAP_UNKNOWN_QOP; + return GSS_S_UNAVAILABLE; + } + + if (ctx->encryptionType == ENCTYPE_NULL) { + *minor = GSSEAP_KEY_UNAVAILABLE; + return GSS_S_UNAVAILABLE; + } + + GSSEAP_KRB_INIT(&krbContext); + + header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor = GSSEAP_MISSING_IOV; + return GSS_S_FAILURE; + } + INIT_IOV_DATA(header); + + trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + if (trailer != NULL) { + INIT_IOV_DATA(trailer); + } + + dce_style = ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0); + + /* For CFX, EC is used instead of padding, and is placed in header or trailer */ + padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL) { + INIT_IOV_DATA(padding); + } + + gssEapIovMessageLength(iov, iov_count, &dataLength, &assocDataLength); + + if (conf_req_flag && gssEapIsIntegrityOnly(iov, iov_count)) + conf_req_flag = FALSE; + + gssPadLen = gssTrailerLen = 0; + +#ifdef HAVE_HEIMDAL_VERSION + code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto); + if (code != 0) + return code; +#endif + + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + conf_req_flag ? + KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM, + &krbTrailerLen); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + + if (conf_req_flag) { + code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + } + + gssHeaderLen = 16; /* Header */ + if (conf_req_flag) { + gssHeaderLen += krbHeaderLen; /* Kerb-Header */ + gssTrailerLen = 16 /* E(Header) */ + krbTrailerLen; /* Kerb-Trailer */ + + code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx), + dataLength - assocDataLength + 16 /* E(Header) */, + &krbPadLen); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + + if (krbPadLen == 0 && dce_style) { + /* Windows rejects AEAD tokens with non-zero EC */ + code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + } else + ec = krbPadLen; + + gssTrailerLen += ec; + } else { + gssTrailerLen = krbTrailerLen; /* Kerb-Checksum */ + } + + dataLength += gssPadLen; + + if (trailer == NULL) + gssHeaderLen += gssTrailerLen; + else + trailer->buffer.length = gssTrailerLen; + + GSSEAP_ASSERT(gssPadLen == 0 || padding != NULL); + + if (padding != NULL) + padding->buffer.length = gssPadLen; + + header->buffer.length = gssHeaderLen; + + if (conf_state != NULL) + *conf_state = conf_req_flag; + + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_wrap_iov_length(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req, + conf_state, iov, iov_count); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/mech_eap/wrap_size_limit.c b/mech_eap/wrap_size_limit.c new file mode 100644 index 0000000..d11fd63 --- /dev/null +++ b/mech_eap/wrap_size_limit.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Message protection services: determine maximum input size. + */ + +#include "gssapiP_eap.h" + +OM_uint32 GSSAPI_CALLCONV +gss_wrap_size_limit(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) +{ + gss_iov_buffer_desc iov[4]; + OM_uint32 major, overhead; + + if (ctx == GSS_C_NO_CONTEXT) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT; + } + + *minor = 0; + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + if (!CTX_IS_ESTABLISHED(ctx)) { + major = GSS_S_NO_CONTEXT; + *minor = GSSEAP_CONTEXT_INCOMPLETE; + goto cleanup; + } + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer.value = NULL; + iov[0].buffer.length = 0; + + iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[1].buffer.length = req_output_size; + iov[1].buffer.value = NULL; + + iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING; + iov[2].buffer.value = NULL; + iov[2].buffer.length = 0; + + iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER; + iov[3].buffer.value = NULL; + iov[3].buffer.length = 0; + + major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req, + NULL, iov, 4); + if (GSS_ERROR(major)) + goto cleanup; + + overhead = iov[0].buffer.length + iov[3].buffer.length; + + if (iov[2].buffer.length == 0 && overhead < req_output_size) + *max_input_size = req_output_size - overhead; + else + *max_input_size = 0; + +cleanup: + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + return major; +} diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c deleted file mode 100644 index 8b7b47b..0000000 --- a/src/crypto/tls_openssl.c +++ /dev/null @@ -1,4145 +0,0 @@ -/* - * SSL/TLS interface functions for OpenSSL - * Copyright (c) 2004-2015, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#ifndef CONFIG_SMARTCARD -#ifndef OPENSSL_NO_ENGINE -#ifndef ANDROID -#define OPENSSL_NO_ENGINE -#endif -#endif -#endif - -#include -#include -#include -#include -#ifndef OPENSSL_NO_ENGINE -#include -#endif /* OPENSSL_NO_ENGINE */ -#ifndef OPENSSL_NO_DSA -#include -#endif -#ifndef OPENSSL_NO_DH -#include -#endif - -#include "common.h" -#include "crypto.h" -#include "sha1.h" -#include "sha256.h" -#include "tls.h" - -#if OPENSSL_VERSION_NUMBER < 0x10000000L -/* ERR_remove_thread_state replaces ERR_remove_state and the latter is - * deprecated. However, OpenSSL 0.9.8 doesn't include - * ERR_remove_thread_state. */ -#define ERR_remove_thread_state(tid) ERR_remove_state(0) -#endif - -#if defined(OPENSSL_IS_BORINGSSL) -/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */ -typedef size_t stack_index_t; -#else -typedef int stack_index_t; -#endif - -#ifdef SSL_set_tlsext_status_type -#ifndef OPENSSL_NO_TLSEXT -#define HAVE_OCSP -#include -#endif /* OPENSSL_NO_TLSEXT */ -#endif /* SSL_set_tlsext_status_type */ - -#ifdef ANDROID -#include -#include - -static BIO * BIO_from_keystore(const char *key) -{ - BIO *bio = NULL; - uint8_t *value = NULL; - int length = keystore_get(key, strlen(key), &value); - if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) - BIO_write(bio, value, length); - free(value); - return bio; -} -#endif /* ANDROID */ - -static int tls_openssl_ref_count = 0; -static int tls_ex_idx_session = -1; - -struct tls_context { - void (*event_cb)(void *ctx, enum tls_event ev, - union tls_event_data *data); - void *cb_ctx; - int cert_in_cb; - char *ocsp_stapling_response; -}; - -static struct tls_context *tls_global = NULL; - - -struct tls_data { - SSL_CTX *ssl; - unsigned int tls_session_lifetime; -}; - -struct tls_connection { - struct tls_context *context; - SSL_CTX *ssl_ctx; - SSL *ssl; - BIO *ssl_in, *ssl_out; -#ifndef OPENSSL_NO_ENGINE - ENGINE *engine; /* functional reference to the engine */ - EVP_PKEY *private_key; /* the private key if using engine */ -#endif /* OPENSSL_NO_ENGINE */ - char *subject_match, *altsubject_match, *suffix_match, *domain_match; - int read_alerts, write_alerts, failed; - - tls_session_ticket_cb session_ticket_cb; - void *session_ticket_cb_ctx; - - /* SessionTicket received from OpenSSL hello_extension_cb (server) */ - u8 *session_ticket; - size_t session_ticket_len; - - unsigned int ca_cert_verify:1; - unsigned int cert_probe:1; - unsigned int server_cert_only:1; - unsigned int invalid_hb_used:1; - unsigned int success_data:1; - - u8 srv_cert_hash[32]; - - unsigned int flags; - - X509 *peer_cert; - X509 *peer_issuer; - X509 *peer_issuer_issuer; - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - unsigned char client_random[SSL3_RANDOM_SIZE]; - unsigned char server_random[SSL3_RANDOM_SIZE]; -#endif -}; - - -static struct tls_context * tls_context_new(const struct tls_config *conf) -{ - struct tls_context *context = os_zalloc(sizeof(*context)); - if (context == NULL) - return NULL; - if (conf) { - context->event_cb = conf->event_cb; - context->cb_ctx = conf->cb_ctx; - context->cert_in_cb = conf->cert_in_cb; - } - return context; -} - - -#ifdef CONFIG_NO_STDOUT_DEBUG - -static void _tls_show_errors(void) -{ - unsigned long err; - - while ((err = ERR_get_error())) { - /* Just ignore the errors, since stdout is disabled */ - } -} -#define tls_show_errors(l, f, t) _tls_show_errors() - -#else /* CONFIG_NO_STDOUT_DEBUG */ - -static void tls_show_errors(int level, const char *func, const char *txt) -{ - unsigned long err; - - wpa_printf(level, "OpenSSL: %s - %s %s", - func, txt, ERR_error_string(ERR_get_error(), NULL)); - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", - ERR_error_string(err, NULL)); - } -} - -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -#ifdef CONFIG_NATIVE_WINDOWS - -/* Windows CryptoAPI and access to certificate stores */ -#include - -#ifdef __MINGW32_VERSION -/* - * MinGW does not yet include all the needed definitions for CryptoAPI, so - * define here whatever extra is needed. - */ -#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) -#define CERT_STORE_READONLY_FLAG 0x00008000 -#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 - -#endif /* __MINGW32_VERSION */ - - -struct cryptoapi_rsa_data { - const CERT_CONTEXT *cert; - HCRYPTPROV crypt_prov; - DWORD key_spec; - BOOL free_crypt_prov; -}; - - -static void cryptoapi_error(const char *msg) -{ - wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", - msg, (unsigned int) GetLastError()); -} - - -static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); - return 0; -} - - -static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); - return 0; -} - - -static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - struct cryptoapi_rsa_data *priv = - (struct cryptoapi_rsa_data *) rsa->meth->app_data; - HCRYPTHASH hash; - DWORD hash_size, len, i; - unsigned char *buf = NULL; - int ret = 0; - - if (priv == NULL) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - if (padding != RSA_PKCS1_PADDING) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - RSA_R_UNKNOWN_PADDING_TYPE); - return 0; - } - - if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { - wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", - __func__); - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - RSA_R_INVALID_MESSAGE_LENGTH); - return 0; - } - - if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) - { - cryptoapi_error("CryptCreateHash failed"); - return 0; - } - - len = sizeof(hash_size); - if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, - 0)) { - cryptoapi_error("CryptGetHashParam failed"); - goto err; - } - - if ((int) hash_size != flen) { - wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", - (unsigned) hash_size, flen); - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, - RSA_R_INVALID_MESSAGE_LENGTH); - goto err; - } - if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { - cryptoapi_error("CryptSetHashParam failed"); - goto err; - } - - len = RSA_size(rsa); - buf = os_malloc(len); - if (buf == NULL) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { - cryptoapi_error("CryptSignHash failed"); - goto err; - } - - for (i = 0; i < len; i++) - to[i] = buf[len - i - 1]; - ret = len; - -err: - os_free(buf); - CryptDestroyHash(hash); - - return ret; -} - - -static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) -{ - wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); - return 0; -} - - -static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) -{ - if (priv == NULL) - return; - if (priv->crypt_prov && priv->free_crypt_prov) - CryptReleaseContext(priv->crypt_prov, 0); - if (priv->cert) - CertFreeCertificateContext(priv->cert); - os_free(priv); -} - - -static int cryptoapi_finish(RSA *rsa) -{ - cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); - os_free((void *) rsa->meth); - rsa->meth = NULL; - return 1; -} - - -static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) -{ - HCERTSTORE cs; - const CERT_CONTEXT *ret = NULL; - - cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, - store | CERT_STORE_OPEN_EXISTING_FLAG | - CERT_STORE_READONLY_FLAG, L"MY"); - if (cs == NULL) { - cryptoapi_error("Failed to open 'My system store'"); - return NULL; - } - - if (strncmp(name, "cert://", 7) == 0) { - unsigned short wbuf[255]; - MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); - ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | - PKCS_7_ASN_ENCODING, - 0, CERT_FIND_SUBJECT_STR, - wbuf, NULL); - } else if (strncmp(name, "hash://", 7) == 0) { - CRYPT_HASH_BLOB blob; - int len; - const char *hash = name + 7; - unsigned char *buf; - - len = os_strlen(hash) / 2; - buf = os_malloc(len); - if (buf && hexstr2bin(hash, buf, len) == 0) { - blob.cbData = len; - blob.pbData = buf; - ret = CertFindCertificateInStore(cs, - X509_ASN_ENCODING | - PKCS_7_ASN_ENCODING, - 0, CERT_FIND_HASH, - &blob, NULL); - } - os_free(buf); - } - - CertCloseStore(cs, 0); - - return ret; -} - - -static int tls_cryptoapi_cert(SSL *ssl, const char *name) -{ - X509 *cert = NULL; - RSA *rsa = NULL, *pub_rsa; - struct cryptoapi_rsa_data *priv; - RSA_METHOD *rsa_meth; - - if (name == NULL || - (strncmp(name, "cert://", 7) != 0 && - strncmp(name, "hash://", 7) != 0)) - return -1; - - priv = os_zalloc(sizeof(*priv)); - rsa_meth = os_zalloc(sizeof(*rsa_meth)); - if (priv == NULL || rsa_meth == NULL) { - wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " - "for CryptoAPI RSA method"); - os_free(priv); - os_free(rsa_meth); - return -1; - } - - priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); - if (priv->cert == NULL) { - priv->cert = cryptoapi_find_cert( - name, CERT_SYSTEM_STORE_LOCAL_MACHINE); - } - if (priv->cert == NULL) { - wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " - "'%s'", name); - goto err; - } - - cert = d2i_X509(NULL, - (const unsigned char **) &priv->cert->pbCertEncoded, - priv->cert->cbCertEncoded); - if (cert == NULL) { - wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " - "encoding"); - goto err; - } - - if (!CryptAcquireCertificatePrivateKey(priv->cert, - CRYPT_ACQUIRE_COMPARE_KEY_FLAG, - NULL, &priv->crypt_prov, - &priv->key_spec, - &priv->free_crypt_prov)) { - cryptoapi_error("Failed to acquire a private key for the " - "certificate"); - goto err; - } - - rsa_meth->name = "Microsoft CryptoAPI RSA Method"; - rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; - rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; - rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; - rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; - rsa_meth->finish = cryptoapi_finish; - rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; - rsa_meth->app_data = (char *) priv; - - rsa = RSA_new(); - if (rsa == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!SSL_use_certificate(ssl, cert)) { - RSA_free(rsa); - rsa = NULL; - goto err; - } - pub_rsa = cert->cert_info->key->pkey->pkey.rsa; - X509_free(cert); - cert = NULL; - - rsa->n = BN_dup(pub_rsa->n); - rsa->e = BN_dup(pub_rsa->e); - if (!RSA_set_method(rsa, rsa_meth)) - goto err; - - if (!SSL_use_RSAPrivateKey(ssl, rsa)) - goto err; - RSA_free(rsa); - - return 0; - -err: - if (cert) - X509_free(cert); - if (rsa) - RSA_free(rsa); - else { - os_free(rsa_meth); - cryptoapi_free_data(priv); - } - return -1; -} - - -static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) -{ - HCERTSTORE cs; - PCCERT_CONTEXT ctx = NULL; - X509 *cert; - char buf[128]; - const char *store; -#ifdef UNICODE - WCHAR *wstore; -#endif /* UNICODE */ - - if (name == NULL || strncmp(name, "cert_store://", 13) != 0) - return -1; - - store = name + 13; -#ifdef UNICODE - wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); - if (wstore == NULL) - return -1; - wsprintf(wstore, L"%S", store); - cs = CertOpenSystemStore(0, wstore); - os_free(wstore); -#else /* UNICODE */ - cs = CertOpenSystemStore(0, store); -#endif /* UNICODE */ - if (cs == NULL) { - wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " - "'%s': error=%d", __func__, store, - (int) GetLastError()); - return -1; - } - - while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { - cert = d2i_X509(NULL, - (const unsigned char **) &ctx->pbCertEncoded, - ctx->cbCertEncoded); - if (cert == NULL) { - wpa_printf(MSG_INFO, "CryptoAPI: Could not process " - "X509 DER encoding for CA cert"); - continue; - } - - X509_NAME_oneline(X509_get_subject_name(cert), buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " - "system certificate store: subject='%s'", buf); - - if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { - tls_show_errors(MSG_WARNING, __func__, - "Failed to add ca_cert to OpenSSL " - "certificate store"); - } - - X509_free(cert); - } - - if (!CertCloseStore(cs, 0)) { - wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " - "'%s': error=%d", __func__, name + 13, - (int) GetLastError()); - } - - return 0; -} - - -#else /* CONFIG_NATIVE_WINDOWS */ - -static int tls_cryptoapi_cert(SSL *ssl, const char *name) -{ - return -1; -} - -#endif /* CONFIG_NATIVE_WINDOWS */ - - -static void ssl_info_cb(const SSL *ssl, int where, int ret) -{ - const char *str; - int w; - - wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); - w = where & ~SSL_ST_MASK; - if (w & SSL_ST_CONNECT) - str = "SSL_connect"; - else if (w & SSL_ST_ACCEPT) - str = "SSL_accept"; - else - str = "undefined"; - - if (where & SSL_CB_LOOP) { - wpa_printf(MSG_DEBUG, "SSL: %s:%s", - str, SSL_state_string_long(ssl)); - } else if (where & SSL_CB_ALERT) { - struct tls_connection *conn = SSL_get_app_data((SSL *) ssl); - wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", - where & SSL_CB_READ ? - "read (remote end reported an error)" : - "write (local SSL3 detected an error)", - SSL_alert_type_string_long(ret), - SSL_alert_desc_string_long(ret)); - if ((ret >> 8) == SSL3_AL_FATAL) { - if (where & SSL_CB_READ) - conn->read_alerts++; - else - conn->write_alerts++; - } - if (conn->context->event_cb != NULL) { - union tls_event_data ev; - struct tls_context *context = conn->context; - os_memset(&ev, 0, sizeof(ev)); - ev.alert.is_local = !(where & SSL_CB_READ); - ev.alert.type = SSL_alert_type_string_long(ret); - ev.alert.description = SSL_alert_desc_string_long(ret); - context->event_cb(context->cb_ctx, TLS_ALERT, &ev); - } - } else if (where & SSL_CB_EXIT && ret <= 0) { - wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", - str, ret == 0 ? "failed" : "error", - SSL_state_string_long(ssl)); - } -} - - -#ifndef OPENSSL_NO_ENGINE -/** - * tls_engine_load_dynamic_generic - load any openssl engine - * @pre: an array of commands and values that load an engine initialized - * in the engine specific function - * @post: an array of commands and values that initialize an already loaded - * engine (or %NULL if not required) - * @id: the engine id of the engine to load (only required if post is not %NULL - * - * This function is a generic function that loads any openssl engine. - * - * Returns: 0 on success, -1 on failure - */ -static int tls_engine_load_dynamic_generic(const char *pre[], - const char *post[], const char *id) -{ - ENGINE *engine; - const char *dynamic_id = "dynamic"; - - engine = ENGINE_by_id(id); - if (engine) { - ENGINE_free(engine); - wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " - "available", id); - return 0; - } - ERR_clear_error(); - - engine = ENGINE_by_id(dynamic_id); - if (engine == NULL) { - wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", - dynamic_id, - ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - - /* Perform the pre commands. This will load the engine. */ - while (pre && pre[0]) { - wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); - if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { - wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " - "%s %s [%s]", pre[0], pre[1], - ERR_error_string(ERR_get_error(), NULL)); - ENGINE_free(engine); - return -1; - } - pre += 2; - } - - /* - * Free the reference to the "dynamic" engine. The loaded engine can - * now be looked up using ENGINE_by_id(). - */ - ENGINE_free(engine); - - engine = ENGINE_by_id(id); - if (engine == NULL) { - wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", - id, ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - - while (post && post[0]) { - wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); - if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { - wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" - " %s %s [%s]", post[0], post[1], - ERR_error_string(ERR_get_error(), NULL)); - ENGINE_remove(engine); - ENGINE_free(engine); - return -1; - } - post += 2; - } - ENGINE_free(engine); - - return 0; -} - - -/** - * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc - * @pkcs11_so_path: pksc11_so_path from the configuration - * @pcks11_module_path: pkcs11_module_path from the configuration - */ -static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, - const char *pkcs11_module_path) -{ - char *engine_id = "pkcs11"; - const char *pre_cmd[] = { - "SO_PATH", NULL /* pkcs11_so_path */, - "ID", NULL /* engine_id */, - "LIST_ADD", "1", - /* "NO_VCHECK", "1", */ - "LOAD", NULL, - NULL, NULL - }; - const char *post_cmd[] = { - "MODULE_PATH", NULL /* pkcs11_module_path */, - NULL, NULL - }; - - if (!pkcs11_so_path) - return 0; - - pre_cmd[1] = pkcs11_so_path; - pre_cmd[3] = engine_id; - if (pkcs11_module_path) - post_cmd[1] = pkcs11_module_path; - else - post_cmd[0] = NULL; - - wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", - pkcs11_so_path); - - return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); -} - - -/** - * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc - * @opensc_so_path: opensc_so_path from the configuration - */ -static int tls_engine_load_dynamic_opensc(const char *opensc_so_path) -{ - char *engine_id = "opensc"; - const char *pre_cmd[] = { - "SO_PATH", NULL /* opensc_so_path */, - "ID", NULL /* engine_id */, - "LIST_ADD", "1", - "LOAD", NULL, - NULL, NULL - }; - - if (!opensc_so_path) - return 0; - - pre_cmd[1] = opensc_so_path; - pre_cmd[3] = engine_id; - - wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", - opensc_so_path); - - return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); -} -#endif /* OPENSSL_NO_ENGINE */ - - -static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess) -{ - struct wpabuf *buf; - - if (tls_ex_idx_session < 0) - return; - buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); - if (!buf) - return; - wpa_printf(MSG_DEBUG, - "OpenSSL: Free application session data %p (sess %p)", - buf, sess); - wpabuf_free(buf); - - SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL); -} - - -void * tls_init(const struct tls_config *conf) -{ - struct tls_data *data; - SSL_CTX *ssl; - struct tls_context *context; - const char *ciphers; - - if (tls_openssl_ref_count == 0) { - tls_global = context = tls_context_new(conf); - if (context == NULL) - return NULL; -#ifdef CONFIG_FIPS -#ifdef OPENSSL_FIPS - if (conf && conf->fips_mode) { - static int fips_enabled = 0; - - if (!fips_enabled && !FIPS_mode_set(1)) { - wpa_printf(MSG_ERROR, "Failed to enable FIPS " - "mode"); - ERR_load_crypto_strings(); - ERR_print_errors_fp(stderr); - os_free(tls_global); - tls_global = NULL; - return NULL; - } else { - wpa_printf(MSG_INFO, "Running in FIPS mode"); - fips_enabled = 1; - } - } -#else /* OPENSSL_FIPS */ - if (conf && conf->fips_mode) { - wpa_printf(MSG_ERROR, "FIPS mode requested, but not " - "supported"); - os_free(tls_global); - tls_global = NULL; - return NULL; - } -#endif /* OPENSSL_FIPS */ -#endif /* CONFIG_FIPS */ - SSL_load_error_strings(); - SSL_library_init(); -#ifndef OPENSSL_NO_SHA256 - EVP_add_digest(EVP_sha256()); -#endif /* OPENSSL_NO_SHA256 */ - /* TODO: if /dev/urandom is available, PRNG is seeded - * automatically. If this is not the case, random data should - * be added here. */ - -#ifdef PKCS12_FUNCS -#ifndef OPENSSL_NO_RC2 - /* - * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. - * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 - * versions, but it looks like OpenSSL 1.0.0 does not do that - * anymore. - */ - EVP_add_cipher(EVP_rc2_40_cbc()); -#endif /* OPENSSL_NO_RC2 */ - PKCS12_PBE_add(); -#endif /* PKCS12_FUNCS */ - } else { - context = tls_context_new(conf); - if (context == NULL) - return NULL; - } - tls_openssl_ref_count++; - - data = os_zalloc(sizeof(*data)); - if (data) - ssl = SSL_CTX_new(SSLv23_method()); - else - ssl = NULL; - if (ssl == NULL) { - tls_openssl_ref_count--; - if (context != tls_global) - os_free(context); - if (tls_openssl_ref_count == 0) { - os_free(tls_global); - tls_global = NULL; - } - return NULL; - } - data->ssl = ssl; - if (conf) - data->tls_session_lifetime = conf->tls_session_lifetime; - - SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2); - SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3); - - SSL_CTX_set_info_callback(ssl, ssl_info_cb); - SSL_CTX_set_app_data(ssl, context); - if (data->tls_session_lifetime > 0) { - SSL_CTX_set_quiet_shutdown(ssl, 1); - /* - * Set default context here. In practice, this will be replaced - * by the per-EAP method context in tls_connection_set_verify(). - */ - SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7); - SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER); - SSL_CTX_set_timeout(ssl, data->tls_session_lifetime); - SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb); - } else { - SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF); - } - - if (tls_ex_idx_session < 0) { - tls_ex_idx_session = SSL_SESSION_get_ex_new_index( - 0, NULL, NULL, NULL, NULL); - if (tls_ex_idx_session < 0) { - tls_deinit(data); - return NULL; - } - } - -#ifndef OPENSSL_NO_ENGINE - wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); - ERR_load_ENGINE_strings(); - ENGINE_load_dynamic(); - - if (conf && - (conf->opensc_engine_path || conf->pkcs11_engine_path || - conf->pkcs11_module_path)) { - if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || - tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, - conf->pkcs11_module_path)) { - tls_deinit(data); - return NULL; - } - } -#endif /* OPENSSL_NO_ENGINE */ - - if (conf && conf->openssl_ciphers) - ciphers = conf->openssl_ciphers; - else - ciphers = "DEFAULT:!EXP:!LOW"; - if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) { - wpa_printf(MSG_ERROR, - "OpenSSL: Failed to set cipher string '%s'", - ciphers); - tls_deinit(data); - return NULL; - } - - return data; -} - - -void tls_deinit(void *ssl_ctx) -{ - struct tls_data *data = ssl_ctx; - SSL_CTX *ssl = data->ssl; - struct tls_context *context = SSL_CTX_get_app_data(ssl); - if (context != tls_global) - os_free(context); - if (data->tls_session_lifetime > 0) - SSL_CTX_flush_sessions(ssl, 0); - SSL_CTX_free(ssl); - - tls_openssl_ref_count--; - if (tls_openssl_ref_count == 0) { -#ifndef OPENSSL_NO_ENGINE - ENGINE_cleanup(); -#endif /* OPENSSL_NO_ENGINE */ - CRYPTO_cleanup_all_ex_data(); - ERR_remove_thread_state(NULL); - ERR_free_strings(); - EVP_cleanup(); - os_free(tls_global->ocsp_stapling_response); - tls_global->ocsp_stapling_response = NULL; - os_free(tls_global); - tls_global = NULL; - } - - os_free(data); -} - - -#ifndef OPENSSL_NO_ENGINE - -/* Cryptoki return values */ -#define CKR_PIN_INCORRECT 0x000000a0 -#define CKR_PIN_INVALID 0x000000a1 -#define CKR_PIN_LEN_RANGE 0x000000a2 - -/* libp11 */ -#define ERR_LIB_PKCS11 ERR_LIB_USER - -static int tls_is_pin_error(unsigned int err) -{ - return ERR_GET_LIB(err) == ERR_LIB_PKCS11 && - (ERR_GET_REASON(err) == CKR_PIN_INCORRECT || - ERR_GET_REASON(err) == CKR_PIN_INVALID || - ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE); -} - -#endif /* OPENSSL_NO_ENGINE */ - - -static int tls_engine_init(struct tls_connection *conn, const char *engine_id, - const char *pin, const char *key_id, - const char *cert_id, const char *ca_cert_id) -{ -#ifndef OPENSSL_NO_ENGINE - int ret = -1; - if (engine_id == NULL) { - wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); - return -1; - } - - ERR_clear_error(); -#ifdef ANDROID - ENGINE_load_dynamic(); -#endif - conn->engine = ENGINE_by_id(engine_id); - if (!conn->engine) { - wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", - engine_id, ERR_error_string(ERR_get_error(), NULL)); - goto err; - } - if (ENGINE_init(conn->engine) != 1) { - wpa_printf(MSG_ERROR, "ENGINE: engine init failed " - "(engine: %s) [%s]", engine_id, - ERR_error_string(ERR_get_error(), NULL)); - goto err; - } - wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); - -#ifndef ANDROID - if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { - wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", - ERR_error_string(ERR_get_error(), NULL)); - goto err; - } -#endif - if (key_id) { - /* - * Ensure that the ENGINE does not attempt to use the OpenSSL - * UI system to obtain a PIN, if we didn't provide one. - */ - struct { - const void *password; - const char *prompt_info; - } key_cb = { "", NULL }; - - /* load private key first in-case PIN is required for cert */ - conn->private_key = ENGINE_load_private_key(conn->engine, - key_id, NULL, - &key_cb); - if (!conn->private_key) { - unsigned long err = ERR_get_error(); - - wpa_printf(MSG_ERROR, - "ENGINE: cannot load private key with id '%s' [%s]", - key_id, - ERR_error_string(err, NULL)); - if (tls_is_pin_error(err)) - ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN; - else - ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - goto err; - } - } - - /* handle a certificate and/or CA certificate */ - if (cert_id || ca_cert_id) { - const char *cmd_name = "LOAD_CERT_CTRL"; - - /* test if the engine supports a LOAD_CERT_CTRL */ - if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, - 0, (void *)cmd_name, NULL)) { - wpa_printf(MSG_ERROR, "ENGINE: engine does not support" - " loading certificates"); - ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - goto err; - } - } - - return 0; - -err: - if (conn->engine) { - ENGINE_free(conn->engine); - conn->engine = NULL; - } - - if (conn->private_key) { - EVP_PKEY_free(conn->private_key); - conn->private_key = NULL; - } - - return ret; -#else /* OPENSSL_NO_ENGINE */ - return 0; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static void tls_engine_deinit(struct tls_connection *conn) -{ -#ifndef OPENSSL_NO_ENGINE - wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); - if (conn->private_key) { - EVP_PKEY_free(conn->private_key); - conn->private_key = NULL; - } - if (conn->engine) { - ENGINE_finish(conn->engine); - conn->engine = NULL; - } -#endif /* OPENSSL_NO_ENGINE */ -} - - -int tls_get_errors(void *ssl_ctx) -{ - int count = 0; - unsigned long err; - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "TLS - SSL error: %s", - ERR_error_string(err, NULL)); - count++; - } - - return count; -} - - -static void tls_msg_cb(int write_p, int version, int content_type, - const void *buf, size_t len, SSL *ssl, void *arg) -{ - struct tls_connection *conn = arg; - const u8 *pos = buf; - - wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d", - write_p ? "TX" : "RX", version, content_type); - wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len); - if (content_type == 24 && len >= 3 && pos[0] == 1) { - size_t payload_len = WPA_GET_BE16(pos + 1); - if (payload_len + 3 > len) { - wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected"); - conn->invalid_hb_used = 1; - } - } -} - - -struct tls_connection * tls_connection_init(void *ssl_ctx) -{ - struct tls_data *data = ssl_ctx; - SSL_CTX *ssl = data->ssl; - struct tls_connection *conn; - long options; - struct tls_context *context = SSL_CTX_get_app_data(ssl); - - conn = os_zalloc(sizeof(*conn)); - if (conn == NULL) - return NULL; - conn->ssl_ctx = ssl; - conn->ssl = SSL_new(ssl); - if (conn->ssl == NULL) { - tls_show_errors(MSG_INFO, __func__, - "Failed to initialize new SSL connection"); - os_free(conn); - return NULL; - } - - conn->context = context; - SSL_set_app_data(conn->ssl, conn); - SSL_set_msg_callback(conn->ssl, tls_msg_cb); - SSL_set_msg_callback_arg(conn->ssl, conn); - options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | - SSL_OP_SINGLE_DH_USE; -#ifdef SSL_OP_NO_COMPRESSION - options |= SSL_OP_NO_COMPRESSION; -#endif /* SSL_OP_NO_COMPRESSION */ - SSL_set_options(conn->ssl, options); - - conn->ssl_in = BIO_new(BIO_s_mem()); - if (!conn->ssl_in) { - tls_show_errors(MSG_INFO, __func__, - "Failed to create a new BIO for ssl_in"); - SSL_free(conn->ssl); - os_free(conn); - return NULL; - } - - conn->ssl_out = BIO_new(BIO_s_mem()); - if (!conn->ssl_out) { - tls_show_errors(MSG_INFO, __func__, - "Failed to create a new BIO for ssl_out"); - SSL_free(conn->ssl); - BIO_free(conn->ssl_in); - os_free(conn); - return NULL; - } - - SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); - - return conn; -} - - -void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return; - if (conn->success_data) { - /* - * Make sure ssl_clear_bad_session() does not remove this - * session. - */ - SSL_set_quiet_shutdown(conn->ssl, 1); - SSL_shutdown(conn->ssl); - } - SSL_free(conn->ssl); - tls_engine_deinit(conn); - os_free(conn->subject_match); - os_free(conn->altsubject_match); - os_free(conn->suffix_match); - os_free(conn->domain_match); - os_free(conn->session_ticket); - os_free(conn); -} - - -int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) -{ - return conn ? SSL_is_init_finished(conn->ssl) : 0; -} - - -int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - - /* Shutdown previous TLS connection without notifying the peer - * because the connection was already terminated in practice - * and "close notify" shutdown alert would confuse AS. */ - SSL_set_quiet_shutdown(conn->ssl, 1); - SSL_shutdown(conn->ssl); - return SSL_clear(conn->ssl) == 1 ? 0 : -1; -} - - -static int tls_match_altsubject_component(X509 *cert, int type, - const char *value, size_t len) -{ - GENERAL_NAME *gen; - void *ext; - int found = 0; - stack_index_t i; - - ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - - for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { - gen = sk_GENERAL_NAME_value(ext, i); - if (gen->type != type) - continue; - if (os_strlen((char *) gen->d.ia5->data) == len && - os_memcmp(value, gen->d.ia5->data, len) == 0) - found++; - } - - return found; -} - - -static int tls_match_altsubject(X509 *cert, const char *match) -{ - int type; - const char *pos, *end; - size_t len; - - pos = match; - do { - if (os_strncmp(pos, "EMAIL:", 6) == 0) { - type = GEN_EMAIL; - pos += 6; - } else if (os_strncmp(pos, "DNS:", 4) == 0) { - type = GEN_DNS; - pos += 4; - } else if (os_strncmp(pos, "URI:", 4) == 0) { - type = GEN_URI; - pos += 4; - } else { - wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " - "match '%s'", pos); - return 0; - } - end = os_strchr(pos, ';'); - while (end) { - if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || - os_strncmp(end + 1, "DNS:", 4) == 0 || - os_strncmp(end + 1, "URI:", 4) == 0) - break; - end = os_strchr(end + 1, ';'); - } - if (end) - len = end - pos; - else - len = os_strlen(pos); - if (tls_match_altsubject_component(cert, type, pos, len) > 0) - return 1; - pos = end + 1; - } while (end); - - return 0; -} - - -#ifndef CONFIG_NATIVE_WINDOWS -static int domain_suffix_match(const u8 *val, size_t len, const char *match, - int full) -{ - size_t i, match_len; - - /* Check for embedded nuls that could mess up suffix matching */ - for (i = 0; i < len; i++) { - if (val[i] == '\0') { - wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject"); - return 0; - } - } - - match_len = os_strlen(match); - if (match_len > len || (full && match_len != len)) - return 0; - - if (os_strncasecmp((const char *) val + len - match_len, match, - match_len) != 0) - return 0; /* no match */ - - if (match_len == len) - return 1; /* exact match */ - - if (val[len - match_len - 1] == '.') - return 1; /* full label match completes suffix match */ - - wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match"); - return 0; -} -#endif /* CONFIG_NATIVE_WINDOWS */ - - -static int tls_match_suffix(X509 *cert, const char *match, int full) -{ -#ifdef CONFIG_NATIVE_WINDOWS - /* wincrypt.h has conflicting X509_NAME definition */ - return -1; -#else /* CONFIG_NATIVE_WINDOWS */ - GENERAL_NAME *gen; - void *ext; - int i; - stack_index_t j; - int dns_name = 0; - X509_NAME *name; - - wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s", - full ? "": "suffix ", match); - - ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - - for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) { - gen = sk_GENERAL_NAME_value(ext, j); - if (gen->type != GEN_DNS) - continue; - dns_name++; - wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName", - gen->d.dNSName->data, - gen->d.dNSName->length); - if (domain_suffix_match(gen->d.dNSName->data, - gen->d.dNSName->length, match, full) == - 1) { - wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found", - full ? "Match" : "Suffix match"); - return 1; - } - } - - if (dns_name) { - wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched"); - return 0; - } - - name = X509_get_subject_name(cert); - i = -1; - for (;;) { - X509_NAME_ENTRY *e; - ASN1_STRING *cn; - - i = X509_NAME_get_index_by_NID(name, NID_commonName, i); - if (i == -1) - break; - e = X509_NAME_get_entry(name, i); - if (e == NULL) - continue; - cn = X509_NAME_ENTRY_get_data(e); - if (cn == NULL) - continue; - wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName", - cn->data, cn->length); - if (domain_suffix_match(cn->data, cn->length, match, full) == 1) - { - wpa_printf(MSG_DEBUG, "TLS: %s in commonName found", - full ? "Match" : "Suffix match"); - return 1; - } - } - - wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found", - full ? "": "suffix "); - return 0; -#endif /* CONFIG_NATIVE_WINDOWS */ -} - - -static enum tls_fail_reason openssl_tls_fail_reason(int err) -{ - switch (err) { - case X509_V_ERR_CERT_REVOKED: - return TLS_FAIL_REVOKED; - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_CRL_NOT_YET_VALID: - return TLS_FAIL_NOT_YET_VALID; - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_CRL_HAS_EXPIRED: - return TLS_FAIL_EXPIRED; - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - case X509_V_ERR_UNABLE_TO_GET_CRL: - case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: - case X509_V_ERR_CERT_CHAIN_TOO_LONG: - case X509_V_ERR_PATH_LENGTH_EXCEEDED: - case X509_V_ERR_INVALID_CA: - return TLS_FAIL_UNTRUSTED; - case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: - case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: - case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: - case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: - case X509_V_ERR_CERT_UNTRUSTED: - case X509_V_ERR_CERT_REJECTED: - return TLS_FAIL_BAD_CERTIFICATE; - default: - return TLS_FAIL_UNSPECIFIED; - } -} - - -static struct wpabuf * get_x509_cert(X509 *cert) -{ - struct wpabuf *buf; - u8 *tmp; - - int cert_len = i2d_X509(cert, NULL); - if (cert_len <= 0) - return NULL; - - buf = wpabuf_alloc(cert_len); - if (buf == NULL) - return NULL; - - tmp = wpabuf_put(buf, cert_len); - i2d_X509(cert, &tmp); - return buf; -} - - -static void openssl_tls_fail_event(struct tls_connection *conn, - X509 *err_cert, int err, int depth, - const char *subject, const char *err_str, - enum tls_fail_reason reason) -{ - union tls_event_data ev; - struct wpabuf *cert = NULL; - struct tls_context *context = conn->context; - - if (context->event_cb == NULL) - return; - - cert = get_x509_cert(err_cert); - os_memset(&ev, 0, sizeof(ev)); - ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? - reason : openssl_tls_fail_reason(err); - ev.cert_fail.depth = depth; - ev.cert_fail.subject = subject; - ev.cert_fail.reason_txt = err_str; - ev.cert_fail.cert = cert; - context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); - wpabuf_free(cert); -} - - -static void openssl_tls_cert_event(struct tls_connection *conn, - X509 *err_cert, int depth, - const char *subject) -{ - struct wpabuf *cert = NULL; - union tls_event_data ev; - struct tls_context *context = conn->context; - char *altsubject[TLS_MAX_ALT_SUBJECT]; - int alt, num_altsubject = 0; - GENERAL_NAME *gen; - void *ext; - stack_index_t i; -#ifdef CONFIG_SHA256 - u8 hash[32]; -#endif /* CONFIG_SHA256 */ - - if (context->event_cb == NULL) - return; - - os_memset(&ev, 0, sizeof(ev)); - if (conn->cert_probe || context->cert_in_cb) { - cert = get_x509_cert(err_cert); - ev.peer_cert.cert = cert; - } -#ifdef CONFIG_SHA256 - if (cert) { - const u8 *addr[1]; - size_t len[1]; - addr[0] = wpabuf_head(cert); - len[0] = wpabuf_len(cert); - if (sha256_vector(1, addr, len, hash) == 0) { - ev.peer_cert.hash = hash; - ev.peer_cert.hash_len = sizeof(hash); - } - } -#endif /* CONFIG_SHA256 */ - ev.peer_cert.depth = depth; - ev.peer_cert.subject = subject; - - ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL); - for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { - char *pos; - - if (num_altsubject == TLS_MAX_ALT_SUBJECT) - break; - gen = sk_GENERAL_NAME_value(ext, i); - if (gen->type != GEN_EMAIL && - gen->type != GEN_DNS && - gen->type != GEN_URI) - continue; - - pos = os_malloc(10 + gen->d.ia5->length + 1); - if (pos == NULL) - break; - altsubject[num_altsubject++] = pos; - - switch (gen->type) { - case GEN_EMAIL: - os_memcpy(pos, "EMAIL:", 6); - pos += 6; - break; - case GEN_DNS: - os_memcpy(pos, "DNS:", 4); - pos += 4; - break; - case GEN_URI: - os_memcpy(pos, "URI:", 4); - pos += 4; - break; - } - - os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length); - pos += gen->d.ia5->length; - *pos = '\0'; - } - - for (alt = 0; alt < num_altsubject; alt++) - ev.peer_cert.altsubject[alt] = altsubject[alt]; - ev.peer_cert.num_altsubject = num_altsubject; - - context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev); - wpabuf_free(cert); - for (alt = 0; alt < num_altsubject; alt++) - os_free(altsubject[alt]); -} - - -static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) -{ - char buf[256]; - X509 *err_cert; - int err, depth; - SSL *ssl; - struct tls_connection *conn; - struct tls_context *context; - char *match, *altmatch, *suffix_match, *domain_match; - const char *err_str; - - err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); - if (!err_cert) - return 0; - - err = X509_STORE_CTX_get_error(x509_ctx); - depth = X509_STORE_CTX_get_error_depth(x509_ctx); - ssl = X509_STORE_CTX_get_ex_data(x509_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); - X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - - conn = SSL_get_app_data(ssl); - if (conn == NULL) - return 0; - - if (depth == 0) - conn->peer_cert = err_cert; - else if (depth == 1) - conn->peer_issuer = err_cert; - else if (depth == 2) - conn->peer_issuer_issuer = err_cert; - - context = conn->context; - match = conn->subject_match; - altmatch = conn->altsubject_match; - suffix_match = conn->suffix_match; - domain_match = conn->domain_match; - - if (!preverify_ok && !conn->ca_cert_verify) - preverify_ok = 1; - if (!preverify_ok && depth > 0 && conn->server_cert_only) - preverify_ok = 1; - if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) && - (err == X509_V_ERR_CERT_HAS_EXPIRED || - err == X509_V_ERR_CERT_NOT_YET_VALID)) { - wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity " - "time mismatch"); - preverify_ok = 1; - } - - err_str = X509_verify_cert_error_string(err); - -#ifdef CONFIG_SHA256 - /* - * Do not require preverify_ok so we can explicity allow otherwise - * invalid pinned server certificates. - */ - if (depth == 0 && conn->server_cert_only) { - struct wpabuf *cert; - cert = get_x509_cert(err_cert); - if (!cert) { - wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " - "server certificate data"); - preverify_ok = 0; - } else { - u8 hash[32]; - const u8 *addr[1]; - size_t len[1]; - addr[0] = wpabuf_head(cert); - len[0] = wpabuf_len(cert); - if (sha256_vector(1, addr, len, hash) < 0 || - os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { - err_str = "Server certificate mismatch"; - err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; - preverify_ok = 0; - } else if (!preverify_ok) { - /* - * Certificate matches pinned certificate, allow - * regardless of other problems. - */ - wpa_printf(MSG_DEBUG, - "OpenSSL: Ignore validation issues for a pinned server certificate"); - preverify_ok = 1; - } - wpabuf_free(cert); - } - } -#endif /* CONFIG_SHA256 */ - - if (!preverify_ok) { - wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," - " error %d (%s) depth %d for '%s'", err, err_str, - depth, buf); - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - err_str, TLS_FAIL_UNSPECIFIED); - return preverify_ok; - } - - wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " - "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", - preverify_ok, err, err_str, - conn->ca_cert_verify, depth, buf); - if (depth == 0 && match && os_strstr(buf, match) == NULL) { - wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " - "match with '%s'", buf, match); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Subject mismatch", - TLS_FAIL_SUBJECT_MISMATCH); - } else if (depth == 0 && altmatch && - !tls_match_altsubject(err_cert, altmatch)) { - wpa_printf(MSG_WARNING, "TLS: altSubjectName match " - "'%s' not found", altmatch); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "AltSubject mismatch", - TLS_FAIL_ALTSUBJECT_MISMATCH); - } else if (depth == 0 && suffix_match && - !tls_match_suffix(err_cert, suffix_match, 0)) { - wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found", - suffix_match); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Domain suffix mismatch", - TLS_FAIL_DOMAIN_SUFFIX_MISMATCH); - } else if (depth == 0 && domain_match && - !tls_match_suffix(err_cert, domain_match, 1)) { - wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found", - domain_match); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Domain mismatch", - TLS_FAIL_DOMAIN_MISMATCH); - } else - openssl_tls_cert_event(conn, err_cert, depth, buf); - - if (conn->cert_probe && preverify_ok && depth == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " - "on probe-only run"); - preverify_ok = 0; - openssl_tls_fail_event(conn, err_cert, err, depth, buf, - "Server certificate chain probe", - TLS_FAIL_SERVER_CHAIN_PROBE); - } - - if (preverify_ok && context->event_cb != NULL) - context->event_cb(context->cb_ctx, - TLS_CERT_CHAIN_SUCCESS, NULL); - - return preverify_ok; -} - - -#ifndef OPENSSL_NO_STDIO -static int tls_load_ca_der(struct tls_data *data, const char *ca_cert) -{ - SSL_CTX *ssl_ctx = data->ssl; - X509_LOOKUP *lookup; - int ret = 0; - - lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx), - X509_LOOKUP_file()); - if (lookup == NULL) { - tls_show_errors(MSG_WARNING, __func__, - "Failed add lookup for X509 store"); - return -1; - } - - if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { - unsigned long err = ERR_peek_error(); - tls_show_errors(MSG_WARNING, __func__, - "Failed load CA in DER format"); - if (ERR_GET_LIB(err) == ERR_LIB_X509 && - ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " - "cert already in hash table error", - __func__); - } else - ret = -1; - } - - return ret; -} -#endif /* OPENSSL_NO_STDIO */ - - -static int tls_connection_ca_cert(struct tls_data *data, - struct tls_connection *conn, - const char *ca_cert, const u8 *ca_cert_blob, - size_t ca_cert_blob_len, const char *ca_path) -{ - SSL_CTX *ssl_ctx = data->ssl; - X509_STORE *store; - - /* - * Remove previously configured trusted CA certificates before adding - * new ones. - */ - store = X509_STORE_new(); - if (store == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " - "certificate store", __func__); - return -1; - } - SSL_CTX_set_cert_store(ssl_ctx, store); - - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); - conn->ca_cert_verify = 1; - - if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " - "chain"); - conn->cert_probe = 1; - conn->ca_cert_verify = 0; - return 0; - } - - if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { -#ifdef CONFIG_SHA256 - const char *pos = ca_cert + 7; - if (os_strncmp(pos, "server/sha256/", 14) != 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " - "hash value '%s'", ca_cert); - return -1; - } - pos += 14; - if (os_strlen(pos) != 32 * 2) { - wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " - "hash length in ca_cert '%s'", ca_cert); - return -1; - } - if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " - "value in ca_cert '%s'", ca_cert); - return -1; - } - conn->server_cert_only = 1; - wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " - "certificate match"); - return 0; -#else /* CONFIG_SHA256 */ - wpa_printf(MSG_INFO, "No SHA256 included in the build - " - "cannot validate server certificate hash"); - return -1; -#endif /* CONFIG_SHA256 */ - } - - if (ca_cert_blob) { - X509 *cert = d2i_X509(NULL, - (const unsigned char **) &ca_cert_blob, - ca_cert_blob_len); - if (cert == NULL) { - tls_show_errors(MSG_WARNING, __func__, - "Failed to parse ca_cert_blob"); - return -1; - } - - if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx), - cert)) { - unsigned long err = ERR_peek_error(); - tls_show_errors(MSG_WARNING, __func__, - "Failed to add ca_cert_blob to " - "certificate store"); - if (ERR_GET_LIB(err) == ERR_LIB_X509 && - ERR_GET_REASON(err) == - X509_R_CERT_ALREADY_IN_HASH_TABLE) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " - "cert already in hash table error", - __func__); - } else { - X509_free(cert); - return -1; - } - } - X509_free(cert); - wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " - "to certificate store", __func__); - return 0; - } - -#ifdef ANDROID - if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) { - BIO *bio = BIO_from_keystore(&ca_cert[11]); - STACK_OF(X509_INFO) *stack = NULL; - stack_index_t i; - - if (bio) { - stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); - BIO_free(bio); - } - if (!stack) - return -1; - - for (i = 0; i < sk_X509_INFO_num(stack); ++i) { - X509_INFO *info = sk_X509_INFO_value(stack, i); - if (info->x509) { - X509_STORE_add_cert(ssl_ctx->cert_store, - info->x509); - } - if (info->crl) { - X509_STORE_add_crl(ssl_ctx->cert_store, - info->crl); - } - } - sk_X509_INFO_pop_free(stack, X509_INFO_free); - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); - return 0; - } -#endif /* ANDROID */ - -#ifdef CONFIG_NATIVE_WINDOWS - if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == - 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " - "system certificate store"); - return 0; - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - if (ca_cert || ca_path) { -#ifndef OPENSSL_NO_STDIO - if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != - 1) { - tls_show_errors(MSG_WARNING, __func__, - "Failed to load root certificates"); - if (ca_cert && - tls_load_ca_der(data, ca_cert) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " - "DER format CA certificate", - __func__); - } else - return -1; - } else { - wpa_printf(MSG_DEBUG, "TLS: Trusted root " - "certificate(s) loaded"); - tls_get_errors(data); - } -#else /* OPENSSL_NO_STDIO */ - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", - __func__); - return -1; -#endif /* OPENSSL_NO_STDIO */ - } else { - /* No ca_cert configured - do not try to verify server - * certificate */ - conn->ca_cert_verify = 0; - } - - return 0; -} - - -static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert) -{ - SSL_CTX *ssl_ctx = data->ssl; - - if (ca_cert) { - if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) - { - tls_show_errors(MSG_WARNING, __func__, - "Failed to load root certificates"); - return -1; - } - - wpa_printf(MSG_DEBUG, "TLS: Trusted root " - "certificate(s) loaded"); - -#ifndef OPENSSL_NO_STDIO - /* Add the same CAs to the client certificate requests */ - SSL_CTX_set_client_CA_list(ssl_ctx, - SSL_load_client_CA_file(ca_cert)); -#endif /* OPENSSL_NO_STDIO */ - } - - return 0; -} - - -int tls_global_set_verify(void *ssl_ctx, int check_crl) -{ - int flags; - - if (check_crl) { - struct tls_data *data = ssl_ctx; - X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl); - if (cs == NULL) { - tls_show_errors(MSG_INFO, __func__, "Failed to get " - "certificate store when enabling " - "check_crl"); - return -1; - } - flags = X509_V_FLAG_CRL_CHECK; - if (check_crl == 2) - flags |= X509_V_FLAG_CRL_CHECK_ALL; - X509_STORE_set_flags(cs, flags); - } - return 0; -} - - -static int tls_connection_set_subject_match(struct tls_connection *conn, - const char *subject_match, - const char *altsubject_match, - const char *suffix_match, - const char *domain_match) -{ - os_free(conn->subject_match); - conn->subject_match = NULL; - if (subject_match) { - conn->subject_match = os_strdup(subject_match); - if (conn->subject_match == NULL) - return -1; - } - - os_free(conn->altsubject_match); - conn->altsubject_match = NULL; - if (altsubject_match) { - conn->altsubject_match = os_strdup(altsubject_match); - if (conn->altsubject_match == NULL) - return -1; - } - - os_free(conn->suffix_match); - conn->suffix_match = NULL; - if (suffix_match) { - conn->suffix_match = os_strdup(suffix_match); - if (conn->suffix_match == NULL) - return -1; - } - - os_free(conn->domain_match); - conn->domain_match = NULL; - if (domain_match) { - conn->domain_match = os_strdup(domain_match); - if (conn->domain_match == NULL) - return -1; - } - - return 0; -} - - -static void tls_set_conn_flags(SSL *ssl, unsigned int flags) -{ -#ifdef SSL_OP_NO_TICKET - if (flags & TLS_CONN_DISABLE_SESSION_TICKET) - SSL_set_options(ssl, SSL_OP_NO_TICKET); -#ifdef SSL_clear_options - else - SSL_clear_options(ssl, SSL_OP_NO_TICKET); -#endif /* SSL_clear_options */ -#endif /* SSL_OP_NO_TICKET */ - -#ifdef SSL_OP_NO_TLSv1 - if (flags & TLS_CONN_DISABLE_TLSv1_0) - SSL_set_options(ssl, SSL_OP_NO_TLSv1); - else - SSL_clear_options(ssl, SSL_OP_NO_TLSv1); -#endif /* SSL_OP_NO_TLSv1 */ -#ifdef SSL_OP_NO_TLSv1_1 - if (flags & TLS_CONN_DISABLE_TLSv1_1) - SSL_set_options(ssl, SSL_OP_NO_TLSv1_1); - else - SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1); -#endif /* SSL_OP_NO_TLSv1_1 */ -#ifdef SSL_OP_NO_TLSv1_2 - if (flags & TLS_CONN_DISABLE_TLSv1_2) - SSL_set_options(ssl, SSL_OP_NO_TLSv1_2); - else - SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2); -#endif /* SSL_OP_NO_TLSv1_2 */ -} - - -int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, - int verify_peer, unsigned int flags, - const u8 *session_ctx, size_t session_ctx_len) -{ - static int counter = 0; - struct tls_data *data = ssl_ctx; - - if (conn == NULL) - return -1; - - if (verify_peer) { - conn->ca_cert_verify = 1; - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT | - SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); - } else { - conn->ca_cert_verify = 0; - SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); - } - - tls_set_conn_flags(conn->ssl, flags); - conn->flags = flags; - - SSL_set_accept_state(conn->ssl); - - if (data->tls_session_lifetime == 0) { - /* - * Set session id context to a unique value to make sure - * session resumption cannot be used either through session - * caching or TLS ticket extension. - */ - counter++; - SSL_set_session_id_context(conn->ssl, - (const unsigned char *) &counter, - sizeof(counter)); - } else if (session_ctx) { - SSL_set_session_id_context(conn->ssl, session_ctx, - session_ctx_len); - } - - return 0; -} - - -static int tls_connection_client_cert(struct tls_connection *conn, - const char *client_cert, - const u8 *client_cert_blob, - size_t client_cert_blob_len) -{ - if (client_cert == NULL && client_cert_blob == NULL) - return 0; - - if (client_cert_blob && - SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, - client_cert_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " - "OK"); - return 0; - } else if (client_cert_blob) { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_certificate_ASN1 failed"); - } - - if (client_cert == NULL) - return -1; - -#ifdef ANDROID - if (os_strncmp("keystore://", client_cert, 11) == 0) { - BIO *bio = BIO_from_keystore(&client_cert[11]); - X509 *x509 = NULL; - int ret = -1; - if (bio) { - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - BIO_free(bio); - } - if (x509) { - if (SSL_use_certificate(conn->ssl, x509) == 1) - ret = 0; - X509_free(x509); - } - return ret; - } -#endif /* ANDROID */ - -#ifndef OPENSSL_NO_STDIO - if (SSL_use_certificate_file(conn->ssl, client_cert, - SSL_FILETYPE_ASN1) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" - " --> OK"); - return 0; - } - - if (SSL_use_certificate_file(conn->ssl, client_cert, - SSL_FILETYPE_PEM) == 1) { - ERR_clear_error(); - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" - " --> OK"); - return 0; - } - - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_certificate_file failed"); -#else /* OPENSSL_NO_STDIO */ - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); -#endif /* OPENSSL_NO_STDIO */ - - return -1; -} - - -static int tls_global_client_cert(struct tls_data *data, - const char *client_cert) -{ -#ifndef OPENSSL_NO_STDIO - SSL_CTX *ssl_ctx = data->ssl; - - if (client_cert == NULL) - return 0; - - if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, - SSL_FILETYPE_ASN1) != 1 && - SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 && - SSL_CTX_use_certificate_file(ssl_ctx, client_cert, - SSL_FILETYPE_PEM) != 1) { - tls_show_errors(MSG_INFO, __func__, - "Failed to load client certificate"); - return -1; - } - return 0; -#else /* OPENSSL_NO_STDIO */ - if (client_cert == NULL) - return 0; - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); - return -1; -#endif /* OPENSSL_NO_STDIO */ -} - - -static int tls_passwd_cb(char *buf, int size, int rwflag, void *password) -{ - if (password == NULL) { - return 0; - } - os_strlcpy(buf, (char *) password, size); - return os_strlen(buf); -} - - -#ifdef PKCS12_FUNCS -static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, - const char *passwd) -{ - EVP_PKEY *pkey; - X509 *cert; - STACK_OF(X509) *certs; - int res = 0; - char buf[256]; - - pkey = NULL; - cert = NULL; - certs = NULL; - if (!passwd) - passwd = ""; - if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { - tls_show_errors(MSG_DEBUG, __func__, - "Failed to parse PKCS12 file"); - PKCS12_free(p12); - return -1; - } - wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); - - if (cert) { - X509_NAME_oneline(X509_get_subject_name(cert), buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " - "subject='%s'", buf); - if (ssl) { - if (SSL_use_certificate(ssl, cert) != 1) - res = -1; - } else { - if (SSL_CTX_use_certificate(data->ssl, cert) != 1) - res = -1; - } - X509_free(cert); - } - - if (pkey) { - wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); - if (ssl) { - if (SSL_use_PrivateKey(ssl, pkey) != 1) - res = -1; - } else { - if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1) - res = -1; - } - EVP_PKEY_free(pkey); - } - - if (certs) { -#if OPENSSL_VERSION_NUMBER >= 0x10002000L - SSL_clear_chain_certs(ssl); - while ((cert = sk_X509_pop(certs)) != NULL) { - X509_NAME_oneline(X509_get_subject_name(cert), buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "TLS: additional certificate" - " from PKCS12: subject='%s'", buf); - if (SSL_add1_chain_cert(ssl, cert) != 1) { - tls_show_errors(MSG_DEBUG, __func__, - "Failed to add additional certificate"); - res = -1; - break; - } - } - if (!res) { - /* Try to continue anyway */ - } - sk_X509_free(certs); -#ifndef OPENSSL_IS_BORINGSSL - res = SSL_build_cert_chain(ssl, - SSL_BUILD_CHAIN_FLAG_CHECK | - SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR); - if (!res) { - tls_show_errors(MSG_DEBUG, __func__, - "Failed to build certificate chain"); - } else if (res == 2) { - wpa_printf(MSG_DEBUG, - "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates"); - } -#endif /* OPENSSL_IS_BORINGSSL */ - /* - * Try to continue regardless of result since it is possible for - * the extra certificates not to be required. - */ - res = 0; -#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - SSL_CTX_clear_extra_chain_certs(data->ssl); -#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */ - while ((cert = sk_X509_pop(certs)) != NULL) { - X509_NAME_oneline(X509_get_subject_name(cert), buf, - sizeof(buf)); - wpa_printf(MSG_DEBUG, "TLS: additional certificate" - " from PKCS12: subject='%s'", buf); - /* - * There is no SSL equivalent for the chain cert - so - * always add it to the context... - */ - if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1) - { - res = -1; - break; - } - } - sk_X509_free(certs); -#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ - } - - PKCS12_free(p12); - - if (res < 0) - tls_get_errors(data); - - return res; -} -#endif /* PKCS12_FUNCS */ - - -static int tls_read_pkcs12(struct tls_data *data, SSL *ssl, - const char *private_key, const char *passwd) -{ -#ifdef PKCS12_FUNCS - FILE *f; - PKCS12 *p12; - - f = fopen(private_key, "rb"); - if (f == NULL) - return -1; - - p12 = d2i_PKCS12_fp(f, NULL); - fclose(f); - - if (p12 == NULL) { - tls_show_errors(MSG_INFO, __func__, - "Failed to use PKCS#12 file"); - return -1; - } - - return tls_parse_pkcs12(data, ssl, p12, passwd); - -#else /* PKCS12_FUNCS */ - wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " - "p12/pfx files"); - return -1; -#endif /* PKCS12_FUNCS */ -} - - -static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl, - const u8 *blob, size_t len, const char *passwd) -{ -#ifdef PKCS12_FUNCS - PKCS12 *p12; - - p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len); - if (p12 == NULL) { - tls_show_errors(MSG_INFO, __func__, - "Failed to use PKCS#12 blob"); - return -1; - } - - return tls_parse_pkcs12(data, ssl, p12, passwd); - -#else /* PKCS12_FUNCS */ - wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " - "p12/pfx blobs"); - return -1; -#endif /* PKCS12_FUNCS */ -} - - -#ifndef OPENSSL_NO_ENGINE -static int tls_engine_get_cert(struct tls_connection *conn, - const char *cert_id, - X509 **cert) -{ - /* this runs after the private key is loaded so no PIN is required */ - struct { - const char *cert_id; - X509 *cert; - } params; - params.cert_id = cert_id; - params.cert = NULL; - - if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", - 0, ¶ms, NULL, 1)) { - unsigned long err = ERR_get_error(); - - wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" - " '%s' [%s]", cert_id, - ERR_error_string(err, NULL)); - if (tls_is_pin_error(err)) - return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN; - return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - } - if (!params.cert) { - wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" - " '%s'", cert_id); - return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - } - *cert = params.cert; - return 0; -} -#endif /* OPENSSL_NO_ENGINE */ - - -static int tls_connection_engine_client_cert(struct tls_connection *conn, - const char *cert_id) -{ -#ifndef OPENSSL_NO_ENGINE - X509 *cert; - - if (tls_engine_get_cert(conn, cert_id, &cert)) - return -1; - - if (!SSL_use_certificate(conn->ssl, cert)) { - tls_show_errors(MSG_ERROR, __func__, - "SSL_use_certificate failed"); - X509_free(cert); - return -1; - } - X509_free(cert); - wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " - "OK"); - return 0; - -#else /* OPENSSL_NO_ENGINE */ - return -1; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static int tls_connection_engine_ca_cert(struct tls_data *data, - struct tls_connection *conn, - const char *ca_cert_id) -{ -#ifndef OPENSSL_NO_ENGINE - X509 *cert; - SSL_CTX *ssl_ctx = data->ssl; - X509_STORE *store; - - if (tls_engine_get_cert(conn, ca_cert_id, &cert)) - return -1; - - /* start off the same as tls_connection_ca_cert */ - store = X509_STORE_new(); - if (store == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " - "certificate store", __func__); - X509_free(cert); - return -1; - } - SSL_CTX_set_cert_store(ssl_ctx, store); - if (!X509_STORE_add_cert(store, cert)) { - unsigned long err = ERR_peek_error(); - tls_show_errors(MSG_WARNING, __func__, - "Failed to add CA certificate from engine " - "to certificate store"); - if (ERR_GET_LIB(err) == ERR_LIB_X509 && - ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { - wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" - " already in hash table error", - __func__); - } else { - X509_free(cert); - return -1; - } - } - X509_free(cert); - wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " - "to certificate store", __func__); - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); - conn->ca_cert_verify = 1; - - return 0; - -#else /* OPENSSL_NO_ENGINE */ - return -1; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static int tls_connection_engine_private_key(struct tls_connection *conn) -{ -#ifndef OPENSSL_NO_ENGINE - if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { - tls_show_errors(MSG_ERROR, __func__, - "ENGINE: cannot use private key for TLS"); - return -1; - } - if (!SSL_check_private_key(conn->ssl)) { - tls_show_errors(MSG_INFO, __func__, - "Private key failed verification"); - return -1; - } - return 0; -#else /* OPENSSL_NO_ENGINE */ - wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " - "engine support was not compiled in"); - return -1; -#endif /* OPENSSL_NO_ENGINE */ -} - - -static int tls_connection_private_key(struct tls_data *data, - struct tls_connection *conn, - const char *private_key, - const char *private_key_passwd, - const u8 *private_key_blob, - size_t private_key_blob_len) -{ - SSL_CTX *ssl_ctx = data->ssl; - char *passwd; - int ok; - - if (private_key == NULL && private_key_blob == NULL) - return 0; - - if (private_key_passwd) { - passwd = os_strdup(private_key_passwd); - if (passwd == NULL) - return -1; - } else - passwd = NULL; - - SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); - SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); - - ok = 0; - while (private_key_blob) { - if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, - (u8 *) private_key_blob, - private_key_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" - "ASN1(EVP_PKEY_RSA) --> OK"); - ok = 1; - break; - } - - if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, - (u8 *) private_key_blob, - private_key_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" - "ASN1(EVP_PKEY_DSA) --> OK"); - ok = 1; - break; - } - - if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, - (u8 *) private_key_blob, - private_key_blob_len) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: " - "SSL_use_RSAPrivateKey_ASN1 --> OK"); - ok = 1; - break; - } - - if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob, - private_key_blob_len, passwd) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " - "OK"); - ok = 1; - break; - } - - break; - } - - while (!ok && private_key) { -#ifndef OPENSSL_NO_STDIO - if (SSL_use_PrivateKey_file(conn->ssl, private_key, - SSL_FILETYPE_ASN1) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: " - "SSL_use_PrivateKey_File (DER) --> OK"); - ok = 1; - break; - } - - if (SSL_use_PrivateKey_file(conn->ssl, private_key, - SSL_FILETYPE_PEM) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: " - "SSL_use_PrivateKey_File (PEM) --> OK"); - ok = 1; - break; - } -#else /* OPENSSL_NO_STDIO */ - wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", - __func__); -#endif /* OPENSSL_NO_STDIO */ - - if (tls_read_pkcs12(data, conn->ssl, private_key, passwd) - == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " - "--> OK"); - ok = 1; - break; - } - - if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { - wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " - "access certificate store --> OK"); - ok = 1; - break; - } - - break; - } - - if (!ok) { - tls_show_errors(MSG_INFO, __func__, - "Failed to load private key"); - os_free(passwd); - return -1; - } - ERR_clear_error(); - SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); - os_free(passwd); - - if (!SSL_check_private_key(conn->ssl)) { - tls_show_errors(MSG_INFO, __func__, "Private key failed " - "verification"); - return -1; - } - - wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); - return 0; -} - - -static int tls_global_private_key(struct tls_data *data, - const char *private_key, - const char *private_key_passwd) -{ - SSL_CTX *ssl_ctx = data->ssl; - char *passwd; - - if (private_key == NULL) - return 0; - - if (private_key_passwd) { - passwd = os_strdup(private_key_passwd); - if (passwd == NULL) - return -1; - } else - passwd = NULL; - - SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); - SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); - if ( -#ifndef OPENSSL_NO_STDIO - SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, - SSL_FILETYPE_ASN1) != 1 && - SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, - SSL_FILETYPE_PEM) != 1 && -#endif /* OPENSSL_NO_STDIO */ - tls_read_pkcs12(data, NULL, private_key, passwd)) { - tls_show_errors(MSG_INFO, __func__, - "Failed to load private key"); - os_free(passwd); - ERR_clear_error(); - return -1; - } - os_free(passwd); - ERR_clear_error(); - SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); - - if (!SSL_CTX_check_private_key(ssl_ctx)) { - tls_show_errors(MSG_INFO, __func__, - "Private key failed verification"); - return -1; - } - - return 0; -} - - -static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) -{ -#ifdef OPENSSL_NO_DH - if (dh_file == NULL) - return 0; - wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " - "dh_file specified"); - return -1; -#else /* OPENSSL_NO_DH */ - DH *dh; - BIO *bio; - - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (conn == NULL) - return -1; - - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", - dh_file, ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - BIO_free(bio); -#ifndef OPENSSL_NO_DSA - while (dh == NULL) { - DSA *dsa; - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" - " trying to parse as DSA params", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) - break; - dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); - BIO_free(bio); - if (!dsa) { - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " - "'%s': %s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - break; - } - - wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " - "params into DH params"); - break; - } - break; - } -#endif /* !OPENSSL_NO_DSA */ - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " - "'%s'", dh_file); - return -1; - } - - if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { - wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " - "%s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - DH_free(dh); - return -1; - } - DH_free(dh); - return 0; -#endif /* OPENSSL_NO_DH */ -} - - -static int tls_global_dh(struct tls_data *data, const char *dh_file) -{ -#ifdef OPENSSL_NO_DH - if (dh_file == NULL) - return 0; - wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " - "dh_file specified"); - return -1; -#else /* OPENSSL_NO_DH */ - SSL_CTX *ssl_ctx = data->ssl; - DH *dh; - BIO *bio; - - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (ssl_ctx == NULL) - return -1; - - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", - dh_file, ERR_error_string(ERR_get_error(), NULL)); - return -1; - } - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - BIO_free(bio); -#ifndef OPENSSL_NO_DSA - while (dh == NULL) { - DSA *dsa; - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" - " trying to parse as DSA params", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) - break; - dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); - BIO_free(bio); - if (!dsa) { - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " - "'%s': %s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - break; - } - - wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " - "params into DH params"); - break; - } - break; - } -#endif /* !OPENSSL_NO_DSA */ - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " - "'%s'", dh_file); - return -1; - } - - if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { - wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " - "%s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - DH_free(dh); - return -1; - } - DH_free(dh); - return 0; -#endif /* OPENSSL_NO_DH */ -} - - -int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, - struct tls_random *keys) -{ - SSL *ssl; - - if (conn == NULL || keys == NULL) - return -1; - ssl = conn->ssl; -#if OPENSSL_VERSION_NUMBER < 0x10100000L - if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) - return -1; - - os_memset(keys, 0, sizeof(*keys)); - keys->client_random = ssl->s3->client_random; - keys->client_random_len = SSL3_RANDOM_SIZE; - keys->server_random = ssl->s3->server_random; - keys->server_random_len = SSL3_RANDOM_SIZE; -#else - if (ssl == NULL) - return -1; - - os_memset(keys, 0, sizeof(*keys)); - keys->client_random = conn->client_random; - keys->client_random_len = SSL_get_client_random( - ssl, conn->client_random, sizeof(conn->client_random)); - keys->server_random = conn->server_random; - keys->server_random_len = SSL_get_server_random( - ssl, conn->server_random, sizeof(conn->server_random)); -#endif - - return 0; -} - - -#ifndef CONFIG_FIPS -static int openssl_get_keyblock_size(SSL *ssl) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000L - const EVP_CIPHER *c; - const EVP_MD *h; - int md_size; - - if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL || - ssl->read_hash == NULL) - return -1; - - c = ssl->enc_read_ctx->cipher; -#if OPENSSL_VERSION_NUMBER >= 0x00909000L - h = EVP_MD_CTX_md(ssl->read_hash); -#else - h = ssl->read_hash; -#endif - if (h) - md_size = EVP_MD_size(h); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - else if (ssl->s3) - md_size = ssl->s3->tmp.new_mac_secret_size; -#endif - else - return -1; - - wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d " - "IV_len=%d", EVP_CIPHER_key_length(c), md_size, - EVP_CIPHER_iv_length(c)); - return 2 * (EVP_CIPHER_key_length(c) + - md_size + - EVP_CIPHER_iv_length(c)); -#else - const SSL_CIPHER *ssl_cipher; - int cipher, digest; - const EVP_CIPHER *c; - const EVP_MD *h; - - ssl_cipher = SSL_get_current_cipher(ssl); - if (!ssl_cipher) - return -1; - cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher); - digest = SSL_CIPHER_get_digest_nid(ssl_cipher); - wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d", - cipher, digest); - if (cipher < 0 || digest < 0) - return -1; - c = EVP_get_cipherbynid(cipher); - h = EVP_get_digestbynid(digest); - if (!c || !h) - return -1; - - wpa_printf(MSG_DEBUG, - "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d", - EVP_CIPHER_key_length(c), EVP_MD_size(h), - EVP_CIPHER_iv_length(c)); - return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) + - EVP_CIPHER_iv_length(c)); -#endif -} -#endif /* CONFIG_FIPS */ - - -static int openssl_tls_prf(struct tls_connection *conn, - const char *label, int server_random_first, - int skip_keyblock, u8 *out, size_t out_len) -{ -#ifdef CONFIG_FIPS - wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS " - "mode"); - return -1; -#else /* CONFIG_FIPS */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L - SSL *ssl; - u8 *rnd; - int ret = -1; - int skip = 0; - u8 *tmp_out = NULL; - u8 *_out = out; - const char *ver; - - /* - * TLS library did not support key generation, so get the needed TLS - * session parameters and use an internal implementation of TLS PRF to - * derive the key. - */ - - if (conn == NULL) - return -1; - ssl = conn->ssl; - if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL || - ssl->session->master_key_length <= 0) - return -1; - ver = SSL_get_version(ssl); - - if (skip_keyblock) { - skip = openssl_get_keyblock_size(ssl); - if (skip < 0) - return -1; - tmp_out = os_malloc(skip + out_len); - if (!tmp_out) - return -1; - _out = tmp_out; - } - - rnd = os_malloc(2 * SSL3_RANDOM_SIZE); - if (!rnd) { - os_free(tmp_out); - return -1; - } - - if (server_random_first) { - os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE); - os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random, - SSL3_RANDOM_SIZE); - } else { - os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE); - os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random, - SSL3_RANDOM_SIZE); - } - - if (os_strcmp(ver, "TLSv1.2") == 0) { - tls_prf_sha256(ssl->session->master_key, - ssl->session->master_key_length, - label, rnd, 2 * SSL3_RANDOM_SIZE, - _out, skip + out_len); - ret = 0; - } else if (tls_prf_sha1_md5(ssl->session->master_key, - ssl->session->master_key_length, - label, rnd, 2 * SSL3_RANDOM_SIZE, - _out, skip + out_len) == 0) { - ret = 0; - } - os_free(rnd); - if (ret == 0 && skip_keyblock) - os_memcpy(out, _out + skip, out_len); - bin_clear_free(tmp_out, skip); - - return ret; -#else - SSL *ssl; - SSL_SESSION *sess; - u8 *rnd; - int ret = -1; - int skip = 0; - u8 *tmp_out = NULL; - u8 *_out = out; - unsigned char client_random[SSL3_RANDOM_SIZE]; - unsigned char server_random[SSL3_RANDOM_SIZE]; - unsigned char master_key[64]; - size_t master_key_len; - const char *ver; - - /* - * TLS library did not support key generation, so get the needed TLS - * session parameters and use an internal implementation of TLS PRF to - * derive the key. - */ - - if (conn == NULL) - return -1; - ssl = conn->ssl; - if (ssl == NULL) - return -1; - ver = SSL_get_version(ssl); - sess = SSL_get_session(ssl); - if (!ver || !sess) - return -1; - - if (skip_keyblock) { - skip = openssl_get_keyblock_size(ssl); - if (skip < 0) - return -1; - tmp_out = os_malloc(skip + out_len); - if (!tmp_out) - return -1; - _out = tmp_out; - } - - rnd = os_malloc(2 * SSL3_RANDOM_SIZE); - if (!rnd) { - os_free(tmp_out); - return -1; - } - - SSL_get_client_random(ssl, client_random, sizeof(client_random)); - SSL_get_server_random(ssl, server_random, sizeof(server_random)); - master_key_len = SSL_SESSION_get_master_key(sess, master_key, - sizeof(master_key)); - - if (server_random_first) { - os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE); - os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, - SSL3_RANDOM_SIZE); - } else { - os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE); - os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random, - SSL3_RANDOM_SIZE); - } - - if (os_strcmp(ver, "TLSv1.2") == 0) { - tls_prf_sha256(master_key, master_key_len, - label, rnd, 2 * SSL3_RANDOM_SIZE, - _out, skip + out_len); - ret = 0; - } else if (tls_prf_sha1_md5(master_key, master_key_len, - label, rnd, 2 * SSL3_RANDOM_SIZE, - _out, skip + out_len) == 0) { - ret = 0; - } - os_memset(master_key, 0, sizeof(master_key)); - os_free(rnd); - if (ret == 0 && skip_keyblock) - os_memcpy(out, _out + skip, out_len); - bin_clear_free(tmp_out, skip); - - return ret; -#endif -#endif /* CONFIG_FIPS */ -} - - -int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, - const char *label, int server_random_first, - int skip_keyblock, u8 *out, size_t out_len) -{ -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - SSL *ssl; - if (conn == NULL) - return -1; - if (server_random_first || skip_keyblock) - return openssl_tls_prf(conn, label, - server_random_first, skip_keyblock, - out, out_len); - ssl = conn->ssl; - if (SSL_export_keying_material(ssl, out, out_len, label, - os_strlen(label), NULL, 0, 0) == 1) { - wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF"); - return 0; - } -#endif - return openssl_tls_prf(conn, label, server_random_first, - skip_keyblock, out, out_len); -} - - -static struct wpabuf * -openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, - int server) -{ - int res; - struct wpabuf *out_data; - - /* - * Give TLS handshake data from the server (if available) to OpenSSL - * for processing. - */ - if (in_data && wpabuf_len(in_data) > 0 && - BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) - < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_write"); - return NULL; - } - - /* Initiate TLS handshake or continue the existing handshake */ - if (server) - res = SSL_accept(conn->ssl); - else - res = SSL_connect(conn->ssl); - if (res != 1) { - int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ) - wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " - "more data"); - else if (err == SSL_ERROR_WANT_WRITE) - wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " - "write"); - else { - tls_show_errors(MSG_INFO, __func__, "SSL_connect"); - conn->failed++; - } - } - - /* Get the TLS handshake data to be sent to the server */ - res = BIO_ctrl_pending(conn->ssl_out); - wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); - out_data = wpabuf_alloc(res); - if (out_data == NULL) { - wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " - "handshake output (%d bytes)", res); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - return NULL; - } - res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), - res); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_read"); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - wpabuf_free(out_data); - return NULL; - } - wpabuf_put(out_data, res); - - return out_data; -} - - -static struct wpabuf * -openssl_get_appl_data(struct tls_connection *conn, size_t max_len) -{ - struct wpabuf *appl_data; - int res; - - appl_data = wpabuf_alloc(max_len + 100); - if (appl_data == NULL) - return NULL; - - res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), - wpabuf_size(appl_data)); - if (res < 0) { - int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ || - err == SSL_ERROR_WANT_WRITE) { - wpa_printf(MSG_DEBUG, "SSL: No Application Data " - "included"); - } else { - tls_show_errors(MSG_INFO, __func__, - "Failed to read possible " - "Application Data"); - } - wpabuf_free(appl_data); - return NULL; - } - - wpabuf_put(appl_data, res); - wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " - "message", appl_data); - - return appl_data; -} - - -static struct wpabuf * -openssl_connection_handshake(struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data, int server) -{ - struct wpabuf *out_data; - - if (appl_data) - *appl_data = NULL; - - out_data = openssl_handshake(conn, in_data, server); - if (out_data == NULL) - return NULL; - if (conn->invalid_hb_used) { - wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); - wpabuf_free(out_data); - return NULL; - } - - if (SSL_is_init_finished(conn->ssl)) { - wpa_printf(MSG_DEBUG, - "OpenSSL: Handshake finished - resumed=%d", - tls_connection_resumed(conn->ssl_ctx, conn)); - if (appl_data && in_data) - *appl_data = openssl_get_appl_data(conn, - wpabuf_len(in_data)); - } - - if (conn->invalid_hb_used) { - wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); - if (appl_data) { - wpabuf_free(*appl_data); - *appl_data = NULL; - } - wpabuf_free(out_data); - return NULL; - } - - return out_data; -} - - -struct wpabuf * -tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return openssl_connection_handshake(conn, in_data, appl_data, 0); -} - - -struct wpabuf * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data, - struct wpabuf **appl_data) -{ - return openssl_connection_handshake(conn, in_data, appl_data, 1); -} - - -struct wpabuf * tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - int res; - struct wpabuf *buf; - - if (conn == NULL) - return NULL; - - /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ - if ((res = BIO_reset(conn->ssl_in)) < 0 || - (res = BIO_reset(conn->ssl_out)) < 0) { - tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return NULL; - } - res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Encryption failed - SSL_write"); - return NULL; - } - - /* Read encrypted data to be sent to the server */ - buf = wpabuf_alloc(wpabuf_len(in_data) + 300); - if (buf == NULL) - return NULL; - res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Encryption failed - BIO_read"); - wpabuf_free(buf); - return NULL; - } - wpabuf_put(buf, res); - - return buf; -} - - -struct wpabuf * tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const struct wpabuf *in_data) -{ - int res; - struct wpabuf *buf; - - /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ - res = BIO_write(conn->ssl_in, wpabuf_head(in_data), - wpabuf_len(in_data)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Decryption failed - BIO_write"); - return NULL; - } - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return NULL; - } - - /* Read decrypted data for further processing */ - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); - if (buf == NULL) - return NULL; - res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Decryption failed - SSL_read"); - wpabuf_free(buf); - return NULL; - } - wpabuf_put(buf, res); - - if (conn->invalid_hb_used) { - wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); - wpabuf_free(buf); - return NULL; - } - - return buf; -} - - -int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) -{ -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - return conn ? SSL_cache_hit(conn->ssl) : 0; -#else - return conn ? conn->ssl->hit : 0; -#endif -} - - -int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, - u8 *ciphers) -{ - char buf[100], *pos, *end; - u8 *c; - int ret; - - if (conn == NULL || conn->ssl == NULL || ciphers == NULL) - return -1; - - buf[0] = '\0'; - pos = buf; - end = pos + sizeof(buf); - - c = ciphers; - while (*c != TLS_CIPHER_NONE) { - const char *suite; - - switch (*c) { - case TLS_CIPHER_RC4_SHA: - suite = "RC4-SHA"; - break; - case TLS_CIPHER_AES128_SHA: - suite = "AES128-SHA"; - break; - case TLS_CIPHER_RSA_DHE_AES128_SHA: - suite = "DHE-RSA-AES128-SHA"; - break; - case TLS_CIPHER_ANON_DH_AES128_SHA: - suite = "ADH-AES128-SHA"; - break; - default: - wpa_printf(MSG_DEBUG, "TLS: Unsupported " - "cipher selection: %d", *c); - return -1; - } - ret = os_snprintf(pos, end - pos, ":%s", suite); - if (os_snprintf_error(end - pos, ret)) - break; - pos += ret; - - c++; - } - - wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) - if (os_strstr(buf, ":ADH-")) { - /* - * Need to drop to security level 0 to allow anonymous - * cipher suites for EAP-FAST. - */ - SSL_set_security_level(conn->ssl, 0); - } else if (SSL_get_security_level(conn->ssl) == 0) { - /* Force at least security level 1 */ - SSL_set_security_level(conn->ssl, 1); - } -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ -#endif - - if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { - tls_show_errors(MSG_INFO, __func__, - "Cipher suite configuration failed"); - return -1; - } - - return 0; -} - - -int tls_get_version(void *ssl_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - const char *name; - if (conn == NULL || conn->ssl == NULL) - return -1; - - name = SSL_get_version(conn->ssl); - if (name == NULL) - return -1; - - os_strlcpy(buf, name, buflen); - return 0; -} - - -int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, - char *buf, size_t buflen) -{ - const char *name; - if (conn == NULL || conn->ssl == NULL) - return -1; - - name = SSL_get_cipher(conn->ssl); - if (name == NULL) - return -1; - - os_strlcpy(buf, name, buflen); - return 0; -} - - -int tls_connection_enable_workaround(void *ssl_ctx, - struct tls_connection *conn) -{ - SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); - - return 0; -} - - -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) -/* ClientHello TLS extensions require a patch to openssl, so this function is - * commented out unless explicitly needed for EAP-FAST in order to be able to - * build this file with unmodified openssl. */ -int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, - int ext_type, const u8 *data, - size_t data_len) -{ - if (conn == NULL || conn->ssl == NULL || ext_type != 35) - return -1; - - if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, - data_len) != 1) - return -1; - - return 0; -} -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ - - -int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->failed; -} - - -int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->read_alerts; -} - - -int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) -{ - if (conn == NULL) - return -1; - return conn->write_alerts; -} - - -#ifdef HAVE_OCSP - -static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) -{ -#ifndef CONFIG_NO_STDOUT_DEBUG - BIO *out; - size_t rlen; - char *txt; - int res; - - if (wpa_debug_level > MSG_DEBUG) - return; - - out = BIO_new(BIO_s_mem()); - if (!out) - return; - - OCSP_RESPONSE_print(out, rsp, 0); - rlen = BIO_ctrl_pending(out); - txt = os_malloc(rlen + 1); - if (!txt) { - BIO_free(out); - return; - } - - res = BIO_read(out, txt, rlen); - if (res > 0) { - txt[res] = '\0'; - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt); - } - os_free(txt); - BIO_free(out); -#endif /* CONFIG_NO_STDOUT_DEBUG */ -} - - -static void debug_print_cert(X509 *cert, const char *title) -{ -#ifndef CONFIG_NO_STDOUT_DEBUG - BIO *out; - size_t rlen; - char *txt; - int res; - - if (wpa_debug_level > MSG_DEBUG) - return; - - out = BIO_new(BIO_s_mem()); - if (!out) - return; - - X509_print(out, cert); - rlen = BIO_ctrl_pending(out); - txt = os_malloc(rlen + 1); - if (!txt) { - BIO_free(out); - return; - } - - res = BIO_read(out, txt, rlen); - if (res > 0) { - txt[res] = '\0'; - wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt); - } - os_free(txt); - - BIO_free(out); -#endif /* CONFIG_NO_STDOUT_DEBUG */ -} - - -static int ocsp_resp_cb(SSL *s, void *arg) -{ - struct tls_connection *conn = arg; - const unsigned char *p; - int len, status, reason; - OCSP_RESPONSE *rsp; - OCSP_BASICRESP *basic; - OCSP_CERTID *id; - ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; - X509_STORE *store; - STACK_OF(X509) *certs = NULL; - - len = SSL_get_tlsext_status_ocsp_resp(s, &p); - if (!p) { - wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); - return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; - } - - wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); - - rsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if (!rsp) { - wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); - return 0; - } - - ocsp_debug_print_resp(rsp); - - status = OCSP_response_status(rsp); - if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", - status, OCSP_response_status_str(status)); - return 0; - } - - basic = OCSP_response_get1_basic(rsp); - if (!basic) { - wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); - return 0; - } - - store = SSL_CTX_get_cert_store(conn->ssl_ctx); - if (conn->peer_issuer) { - debug_print_cert(conn->peer_issuer, "Add OCSP issuer"); - - if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) { - tls_show_errors(MSG_INFO, __func__, - "OpenSSL: Could not add issuer to certificate store"); - } - certs = sk_X509_new_null(); - if (certs) { - X509 *cert; - cert = X509_dup(conn->peer_issuer); - if (cert && !sk_X509_push(certs, cert)) { - tls_show_errors( - MSG_INFO, __func__, - "OpenSSL: Could not add issuer to OCSP responder trust store"); - X509_free(cert); - sk_X509_free(certs); - certs = NULL; - } - if (certs && conn->peer_issuer_issuer) { - cert = X509_dup(conn->peer_issuer_issuer); - if (cert && !sk_X509_push(certs, cert)) { - tls_show_errors( - MSG_INFO, __func__, - "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); - X509_free(cert); - } - } - } - } - - status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); - sk_X509_pop_free(certs, X509_free); - if (status <= 0) { - tls_show_errors(MSG_INFO, __func__, - "OpenSSL: OCSP response failed verification"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); - - if (!conn->peer_cert) { - wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - if (!conn->peer_issuer) { - wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer); - if (!id) { - wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, - &this_update, &next_update)) { - wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", - (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" : - " (OCSP not required)"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; - } - - if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { - tls_show_errors(MSG_INFO, __func__, - "OpenSSL: OCSP status times invalid"); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - return 0; - } - - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(rsp); - - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", - OCSP_cert_status_str(status)); - - if (status == V_OCSP_CERTSTATUS_GOOD) - return 1; - if (status == V_OCSP_CERTSTATUS_REVOKED) - return 0; - if (conn->flags & TLS_CONN_REQUIRE_OCSP) { - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); - return 0; - } - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); - return 1; -} - - -static int ocsp_status_cb(SSL *s, void *arg) -{ - char *tmp; - char *resp; - size_t len; - - if (tls_global->ocsp_stapling_response == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured"); - return SSL_TLSEXT_ERR_OK; - } - - resp = os_readfile(tls_global->ocsp_stapling_response, &len); - if (resp == NULL) { - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file"); - /* TODO: Build OCSPResponse with responseStatus = internalError - */ - return SSL_TLSEXT_ERR_OK; - } - wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response"); - tmp = OPENSSL_malloc(len); - if (tmp == NULL) { - os_free(resp); - return SSL_TLSEXT_ERR_ALERT_FATAL; - } - - os_memcpy(tmp, resp, len); - os_free(resp); - SSL_set_tlsext_status_ocsp_resp(s, tmp, len); - - return SSL_TLSEXT_ERR_OK; -} - -#endif /* HAVE_OCSP */ - - -int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, - const struct tls_connection_params *params) -{ - struct tls_data *data = tls_ctx; - int ret; - unsigned long err; - int can_pkcs11 = 0; - const char *key_id = params->key_id; - const char *cert_id = params->cert_id; - const char *ca_cert_id = params->ca_cert_id; - const char *engine_id = params->engine ? params->engine_id : NULL; - - if (conn == NULL) - return -1; - - /* - * If the engine isn't explicitly configured, and any of the - * cert/key fields are actually PKCS#11 URIs, then automatically - * use the PKCS#11 ENGINE. - */ - if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0) - can_pkcs11 = 1; - - if (!key_id && params->private_key && can_pkcs11 && - os_strncmp(params->private_key, "pkcs11:", 7) == 0) { - can_pkcs11 = 2; - key_id = params->private_key; - } - - if (!cert_id && params->client_cert && can_pkcs11 && - os_strncmp(params->client_cert, "pkcs11:", 7) == 0) { - can_pkcs11 = 2; - cert_id = params->client_cert; - } - - if (!ca_cert_id && params->ca_cert && can_pkcs11 && - os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) { - can_pkcs11 = 2; - ca_cert_id = params->ca_cert; - } - - /* If we need to automatically enable the PKCS#11 ENGINE, do so. */ - if (can_pkcs11 == 2 && !engine_id) - engine_id = "pkcs11"; - -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) -#if OPENSSL_VERSION_NUMBER < 0x10100000L - if (params->flags & TLS_CONN_EAP_FAST) { - wpa_printf(MSG_DEBUG, - "OpenSSL: Use TLSv1_method() for EAP-FAST"); - if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) { - tls_show_errors(MSG_INFO, __func__, - "Failed to set TLSv1_method() for EAP-FAST"); - return -1; - } - } -#endif -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", - __func__, ERR_error_string(err, NULL)); - } - - if (engine_id) { - wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); - ret = tls_engine_init(conn, engine_id, params->pin, - key_id, cert_id, ca_cert_id); - if (ret) - return ret; - } - if (tls_connection_set_subject_match(conn, - params->subject_match, - params->altsubject_match, - params->suffix_match, - params->domain_match)) - return -1; - - if (engine_id && ca_cert_id) { - if (tls_connection_engine_ca_cert(data, conn, ca_cert_id)) - return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; - } else if (tls_connection_ca_cert(data, conn, params->ca_cert, - params->ca_cert_blob, - params->ca_cert_blob_len, - params->ca_path)) - return -1; - - if (engine_id && cert_id) { - if (tls_connection_engine_client_cert(conn, cert_id)) - return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; - } else if (tls_connection_client_cert(conn, params->client_cert, - params->client_cert_blob, - params->client_cert_blob_len)) - return -1; - - if (engine_id && key_id) { - wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); - if (tls_connection_engine_private_key(conn)) - return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; - } else if (tls_connection_private_key(data, conn, - params->private_key, - params->private_key_passwd, - params->private_key_blob, - params->private_key_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", - params->private_key); - return -1; - } - - if (tls_connection_dh(conn, params->dh_file)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", - params->dh_file); - return -1; - } - - if (params->openssl_ciphers && - SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) { - wpa_printf(MSG_INFO, - "OpenSSL: Failed to set cipher string '%s'", - params->openssl_ciphers); - return -1; - } - - tls_set_conn_flags(conn->ssl, params->flags); - -#ifdef HAVE_OCSP - if (params->flags & TLS_CONN_REQUEST_OCSP) { - SSL_CTX *ssl_ctx = data->ssl; - SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp); - SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb); - SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn); - } -#else /* HAVE_OCSP */ - if (params->flags & TLS_CONN_REQUIRE_OCSP) { - wpa_printf(MSG_INFO, - "OpenSSL: No OCSP support included - reject configuration"); - return -1; - } - if (params->flags & TLS_CONN_REQUEST_OCSP) { - wpa_printf(MSG_DEBUG, - "OpenSSL: No OCSP support included - allow optional OCSP case to continue"); - } -#endif /* HAVE_OCSP */ - - conn->flags = params->flags; - - tls_get_errors(data); - - return 0; -} - - -int tls_global_set_params(void *tls_ctx, - const struct tls_connection_params *params) -{ - struct tls_data *data = tls_ctx; - SSL_CTX *ssl_ctx = data->ssl; - unsigned long err; - - while ((err = ERR_get_error())) { - wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", - __func__, ERR_error_string(err, NULL)); - } - - if (tls_global_ca_cert(data, params->ca_cert) || - tls_global_client_cert(data, params->client_cert) || - tls_global_private_key(data, params->private_key, - params->private_key_passwd) || - tls_global_dh(data, params->dh_file)) { - wpa_printf(MSG_INFO, "TLS: Failed to set global parameters"); - return -1; - } - - if (params->openssl_ciphers && - SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) { - wpa_printf(MSG_INFO, - "OpenSSL: Failed to set cipher string '%s'", - params->openssl_ciphers); - return -1; - } - -#ifdef SSL_OP_NO_TICKET - if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET) - SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET); -#ifdef SSL_CTX_clear_options - else - SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET); -#endif /* SSL_clear_options */ -#endif /* SSL_OP_NO_TICKET */ - -#ifdef HAVE_OCSP - SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb); - SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx); - os_free(tls_global->ocsp_stapling_response); - if (params->ocsp_stapling_response) - tls_global->ocsp_stapling_response = - os_strdup(params->ocsp_stapling_response); - else - tls_global->ocsp_stapling_response = NULL; -#endif /* HAVE_OCSP */ - - return 0; -} - - -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) -/* Pre-shared secred requires a patch to openssl, so this function is - * commented out unless explicitly needed for EAP-FAST in order to be able to - * build this file with unmodified openssl. */ - -#ifdef OPENSSL_IS_BORINGSSL -static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - const SSL_CIPHER **cipher, void *arg) -#else /* OPENSSL_IS_BORINGSSL */ -static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - SSL_CIPHER **cipher, void *arg) -#endif /* OPENSSL_IS_BORINGSSL */ -{ - struct tls_connection *conn = arg; - int ret; - -#if OPENSSL_VERSION_NUMBER < 0x10100000L - if (conn == NULL || conn->session_ticket_cb == NULL) - return 0; - - ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, - conn->session_ticket, - conn->session_ticket_len, - s->s3->client_random, - s->s3->server_random, secret); -#else - unsigned char client_random[SSL3_RANDOM_SIZE]; - unsigned char server_random[SSL3_RANDOM_SIZE]; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return 0; - - SSL_get_client_random(s, client_random, sizeof(client_random)); - SSL_get_server_random(s, server_random, sizeof(server_random)); - - ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, - conn->session_ticket, - conn->session_ticket_len, - client_random, - server_random, secret); -#endif - - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - if (ret <= 0) - return 0; - - *secret_len = SSL_MAX_MASTER_KEY_LENGTH; - return 1; -} - - -static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, - int len, void *arg) -{ - struct tls_connection *conn = arg; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); - - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " - "extension", data, len); - - conn->session_ticket = os_malloc(len); - if (conn->session_ticket == NULL) - return 0; - - os_memcpy(conn->session_ticket, data, len); - conn->session_ticket_len = len; - - return 1; -} -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ - - -int tls_connection_set_session_ticket_cb(void *tls_ctx, - struct tls_connection *conn, - tls_session_ticket_cb cb, - void *ctx) -{ -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) - conn->session_ticket_cb = cb; - conn->session_ticket_cb_ctx = ctx; - - if (cb) { - if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, - conn) != 1) - return -1; - SSL_set_session_ticket_ext_cb(conn->ssl, - tls_session_ticket_ext_cb, conn); - } else { - if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) - return -1; - SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); - } - - return 0; -#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ - return -1; -#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ -} - - -int tls_get_library_version(char *buf, size_t buf_len) -{ - return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s", - OPENSSL_VERSION_TEXT, - SSLeay_version(SSLEAY_VERSION)); -} - - -void tls_connection_set_success_data(struct tls_connection *conn, - struct wpabuf *data) -{ - SSL_SESSION *sess; - struct wpabuf *old; - - if (tls_ex_idx_session < 0) - goto fail; - sess = SSL_get_session(conn->ssl); - if (!sess) - goto fail; - old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); - if (old) { - wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p", - old); - wpabuf_free(old); - } - if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) - goto fail; - - wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data); - conn->success_data = 1; - return; - -fail: - wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data"); - wpabuf_free(data); -} - - -void tls_connection_set_success_data_resumed(struct tls_connection *conn) -{ - wpa_printf(MSG_DEBUG, - "OpenSSL: Success data accepted for resumed session"); - conn->success_data = 1; -} - - -const struct wpabuf * -tls_connection_get_success_data(struct tls_connection *conn) -{ - SSL_SESSION *sess; - - if (tls_ex_idx_session < 0 || - !(sess = SSL_get_session(conn->ssl))) - return NULL; - return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); -} - - -void tls_connection_remove_session(struct tls_connection *conn) -{ - SSL_SESSION *sess; - - sess = SSL_get_session(conn->ssl); - if (!sess) - return; - - if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1) - wpa_printf(MSG_DEBUG, - "OpenSSL: Session was not cached"); - else - wpa_printf(MSG_DEBUG, - "OpenSSL: Removed cached session to disable session resumption"); -} diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h deleted file mode 100644 index e62f167..0000000 --- a/src/eap_common/eap_common.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * EAP common peer/server definitions - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_COMMON_H -#define EAP_COMMON_H - -#include "wpabuf.h" - -struct erp_tlvs { - const u8 *keyname; - const u8 *domain; - - u8 keyname_len; - u8 domain_len; -}; - -int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); -const u8 * eap_hdr_validate(int vendor, EapType eap_type, - const struct wpabuf *msg, size_t *plen); -struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, - u8 code, u8 identifier); -void eap_update_len(struct wpabuf *msg); -u8 eap_get_id(const struct wpabuf *msg); -EapType eap_get_type(const struct wpabuf *msg); -int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs, - int stop_at_keyname); - -#endif /* EAP_COMMON_H */ diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h deleted file mode 100644 index 54f26ca..0000000 --- a/src/eap_common/eap_defs.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * EAP server/peer: Shared EAP definitions - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_DEFS_H -#define EAP_DEFS_H - -/* RFC 3748 - Extensible Authentication Protocol (EAP) */ - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_hdr { - u8 code; - u8 identifier; - be16 length; /* including code and identifier; network byte order */ - /* followed by length-4 octets of data */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, - EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 }; - -/* EAP Request and Response data begins with one octet Type. Success and - * Failure do not have additional data. */ - -/* Type field in EAP-Initiate and EAP-Finish messages */ -enum eap_erp_type { - EAP_ERP_TYPE_REAUTH_START = 1, - EAP_ERP_TYPE_REAUTH = 2, -}; - -/* ERP TV/TLV types */ -enum eap_erp_tlv_type { - EAP_ERP_TLV_KEYNAME_NAI = 1, - EAP_ERP_TV_RRK_LIFETIME = 2, - EAP_ERP_TV_RMSK_LIFETIME = 3, - EAP_ERP_TLV_DOMAIN_NAME = 4, - EAP_ERP_TLV_CRYPTOSUITES = 5, - EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6, - EAP_ERP_TLV_CALLED_STATION_ID = 128, - EAP_ERP_TLV_CALLING_STATION_ID = 129, - EAP_ERP_TLV_NAS_IDENTIFIER = 130, - EAP_ERP_TLV_NAS_IP_ADDRESS = 131, - EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132, -}; - -/* ERP Cryptosuite */ -enum eap_erp_cryptosuite { - EAP_ERP_CS_HMAC_SHA256_64 = 1, - EAP_ERP_CS_HMAC_SHA256_128 = 2, - EAP_ERP_CS_HMAC_SHA256_256 = 3, -}; - -/* - * EAP Method Types as allocated by IANA: - * http://www.iana.org/assignments/eap-numbers - */ -typedef enum { - EAP_TYPE_NONE = 0, - EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, - EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, - EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, - EAP_TYPE_MD5 = 4, /* RFC 3748 */ - EAP_TYPE_OTP = 5 /* RFC 3748 */, - EAP_TYPE_GTC = 6, /* RFC 3748 */ - EAP_TYPE_TLS = 13 /* RFC 2716 */, - EAP_TYPE_LEAP = 17 /* Cisco proprietary */, - EAP_TYPE_SIM = 18 /* RFC 4186 */, - EAP_TYPE_TTLS = 21 /* RFC 5281 */, - EAP_TYPE_AKA = 23 /* RFC 4187 */, - EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */, - EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */, - EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */, - EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment; - * type 38 has previously been allocated for - * EAP-HTTP Digest, (funk.com) */, - EAP_TYPE_FAST = 43 /* RFC 4851 */, - EAP_TYPE_PAX = 46 /* RFC 4746 */, - EAP_TYPE_PSK = 47 /* RFC 4764 */, - EAP_TYPE_SAKE = 48 /* RFC 4763 */, - EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, - EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */, - EAP_TYPE_GPSK = 51 /* RFC 5433 */, - EAP_TYPE_PWD = 52 /* RFC 5931 */, - EAP_TYPE_EKE = 53 /* RFC 6124 */, - EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ -} EapType; - - -/* SMI Network Management Private Enterprise Code for vendor specific types */ -enum { - EAP_VENDOR_IETF = 0, - EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, - EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance (moved to WBA) */, - EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */, - EAP_VENDOR_WFA_NEW = 40808 /* Wi-Fi Alliance */ -}; - -#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP -#define EAP_VENDOR_TYPE_UNAUTH_TLS 1 - -#define EAP_VENDOR_WFA_UNAUTH_TLS 13 - -#define EAP_MSK_LEN 64 -#define EAP_EMSK_LEN 64 -#define EAP_EMSK_NAME_LEN 8 -#define ERP_MAX_KEY_LEN 64 - -#endif /* EAP_DEFS_H */ diff --git a/src/eap_common/eap_fast_common.h b/src/eap_common/eap_fast_common.h deleted file mode 100644 index d59a845..0000000 --- a/src/eap_common/eap_fast_common.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * EAP-FAST definitions (RFC 4851) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_FAST_H -#define EAP_FAST_H - -#define EAP_FAST_VERSION 1 -#define EAP_FAST_KEY_LEN 64 -#define EAP_FAST_SIMCK_LEN 40 -#define EAP_FAST_SKS_LEN 40 -#define EAP_FAST_CMK_LEN 20 - -#define TLS_EXT_PAC_OPAQUE 35 - -/* - * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field - * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined - * in the general PAC TLV format (Section 4.2). - */ -#define PAC_TYPE_PAC_KEY 1 -#define PAC_TYPE_PAC_OPAQUE 2 -#define PAC_TYPE_CRED_LIFETIME 3 -#define PAC_TYPE_A_ID 4 -#define PAC_TYPE_I_ID 5 -/* - * 6 was previous assigned for SERVER_PROTECTED_DATA, but - * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved. - */ -#define PAC_TYPE_A_ID_INFO 7 -#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8 -#define PAC_TYPE_PAC_INFO 9 -#define PAC_TYPE_PAC_TYPE 10 - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct pac_tlv_hdr { - be16 type; - be16 len; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -#define EAP_FAST_PAC_KEY_LEN 32 - -/* RFC 5422: 4.2.6 PAC-Type TLV */ -#define PAC_TYPE_TUNNEL_PAC 1 -/* Application Specific Short Lived PACs (only in volatile storage) */ -/* User Authorization PAC */ -#define PAC_TYPE_USER_AUTHORIZATION 3 -/* Application Specific Long Lived PACs */ -/* Machine Authentication PAC */ -#define PAC_TYPE_MACHINE_AUTHENTICATION 2 - - -/* - * RFC 5422: - * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange - */ -struct eap_fast_key_block_provisioning { - /* Extra key material after TLS key_block */ - u8 session_key_seed[EAP_FAST_SKS_LEN]; - u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */ - u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */ -}; - - -struct wpabuf; -struct tls_connection; - -struct eap_fast_tlv_parse { - u8 *eap_payload_tlv; - size_t eap_payload_tlv_len; - struct eap_tlv_crypto_binding_tlv *crypto_binding; - size_t crypto_binding_len; - int iresult; - int result; - int request_action; - u8 *pac; - size_t pac_len; -}; - -void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len); -void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, - u16 len); -void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, - const struct wpabuf *data); -struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf); -void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, - const u8 *client_random, u8 *master_secret); -u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, - const char *label, size_t len); -void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk); -void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk); -int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, - int tlv_type, u8 *pos, size_t len); - -#endif /* EAP_FAST_H */ diff --git a/src/eap_common/eap_gpsk_common.h b/src/eap_common/eap_gpsk_common.h deleted file mode 100644 index fbcd547..0000000 --- a/src/eap_common/eap_gpsk_common.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * EAP server/peer: EAP-GPSK shared routines - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_GPSK_COMMON_H -#define EAP_GPSK_COMMON_H - -#define EAP_GPSK_OPCODE_GPSK_1 1 -#define EAP_GPSK_OPCODE_GPSK_2 2 -#define EAP_GPSK_OPCODE_GPSK_3 3 -#define EAP_GPSK_OPCODE_GPSK_4 4 -#define EAP_GPSK_OPCODE_FAIL 5 -#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6 - -/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */ -#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001 -#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002 -#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003 - -#define EAP_GPSK_RAND_LEN 32 -#define EAP_GPSK_MAX_SK_LEN 32 -#define EAP_GPSK_MAX_PK_LEN 32 -#define EAP_GPSK_MAX_MIC_LEN 32 - -#define EAP_GPSK_VENDOR_IETF 0x00000000 -#define EAP_GPSK_CIPHER_RESERVED 0x000000 -#define EAP_GPSK_CIPHER_AES 0x000001 -#define EAP_GPSK_CIPHER_SHA256 0x000002 - - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_gpsk_csuite { - u8 vendor[4]; - u8 specifier[2]; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -int eap_gpsk_supported_ciphersuite(int vendor, int specifier); -int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, - int specifier, - const u8 *rand_client, const u8 *rand_server, - const u8 *id_client, size_t id_client_len, - const u8 *id_server, size_t id_server_len, - u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, - u8 *pk, size_t *pk_len); -int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, - int specifier, - const u8 *rand_peer, const u8 *rand_server, - const u8 *id_peer, size_t id_peer_len, - const u8 *id_server, size_t id_server_len, - u8 method_type, u8 *sid, size_t *sid_len); -size_t eap_gpsk_mic_len(int vendor, int specifier); -int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, - int specifier, const u8 *data, size_t len, u8 *mic); - -#endif /* EAP_GPSK_COMMON_H */ diff --git a/src/eap_common/eap_ikev2_common.h b/src/eap_common/eap_ikev2_common.h deleted file mode 100644 index e7502d7..0000000 --- a/src/eap_common/eap_ikev2_common.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * EAP-IKEv2 definitions - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_IKEV2_COMMON_H -#define EAP_IKEV2_COMMON_H - -#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80 -#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40 -#define IKEV2_FLAGS_ICV_INCLUDED 0x20 - -#define IKEV2_FRAGMENT_SIZE 1400 - -struct ikev2_keys; - -int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, - const u8 *i_nonce, size_t i_nonce_len, - const u8 *r_nonce, size_t r_nonce_len, - u8 *keymat); -struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code); -int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, - int initiator, const struct wpabuf *msg, - const u8 *pos, const u8 *end); - -#endif /* EAP_IKEV2_COMMON_H */ diff --git a/src/eap_common/eap_pax_common.h b/src/eap_common/eap_pax_common.h deleted file mode 100644 index e6cdf4d..0000000 --- a/src/eap_common/eap_pax_common.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * EAP server/peer: EAP-PAX shared routines - * Copyright (c) 2005-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PAX_COMMON_H -#define EAP_PAX_COMMON_H - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_pax_hdr { - u8 op_code; - u8 flags; - u8 mac_id; - u8 dh_group_id; - u8 public_key_id; - /* Followed by variable length payload and ICV */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -/* op_code: */ -enum { - EAP_PAX_OP_STD_1 = 0x01, - EAP_PAX_OP_STD_2 = 0x02, - EAP_PAX_OP_STD_3 = 0x03, - EAP_PAX_OP_SEC_1 = 0x11, - EAP_PAX_OP_SEC_2 = 0x12, - EAP_PAX_OP_SEC_3 = 0x13, - EAP_PAX_OP_SEC_4 = 0x14, - EAP_PAX_OP_SEC_5 = 0x15, - EAP_PAX_OP_ACK = 0x21 -}; - -/* flags: */ -#define EAP_PAX_FLAGS_MF 0x01 -#define EAP_PAX_FLAGS_CE 0x02 -#define EAP_PAX_FLAGS_AI 0x04 - -/* mac_id: */ -#define EAP_PAX_MAC_HMAC_SHA1_128 0x01 -#define EAP_PAX_HMAC_SHA256_128 0x02 - -/* dh_group_id: */ -#define EAP_PAX_DH_GROUP_NONE 0x00 -#define EAP_PAX_DH_GROUP_2048_MODP 0x01 -#define EAP_PAX_DH_GROUP_3072_MODP 0x02 -#define EAP_PAX_DH_GROUP_NIST_ECC_P_256 0x03 - -/* public_key_id: */ -#define EAP_PAX_PUBLIC_KEY_NONE 0x00 -#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP 0x01 -#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 0x02 -#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC 0x03 - -/* ADE type: */ -#define EAP_PAX_ADE_VENDOR_SPECIFIC 0x01 -#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING 0x02 -#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING 0x03 - - -#define EAP_PAX_RAND_LEN 32 -#define EAP_PAX_MAC_LEN 16 -#define EAP_PAX_ICV_LEN 16 -#define EAP_PAX_AK_LEN 16 -#define EAP_PAX_MK_LEN 16 -#define EAP_PAX_CK_LEN 16 -#define EAP_PAX_ICK_LEN 16 -#define EAP_PAX_MID_LEN 16 - - -int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, - const char *identifier, - const u8 *entropy, size_t entropy_len, - size_t output_len, u8 *output); -int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, - const u8 *data1, size_t data1_len, - const u8 *data2, size_t data2_len, - const u8 *data3, size_t data3_len, - u8 *mac); -int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e, - u8 *mk, u8 *ck, u8 *ick, u8 *mid); - -#endif /* EAP_PAX_COMMON_H */ diff --git a/src/eap_common/eap_peap_common.h b/src/eap_common/eap_peap_common.h deleted file mode 100644 index 7aad0df..0000000 --- a/src/eap_common/eap_peap_common.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * EAP-PEAP common routines - * Copyright (c) 2008-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PEAP_COMMON_H -#define EAP_PEAP_COMMON_H - -int peap_prfplus(int version, const u8 *key, size_t key_len, - const char *label, const u8 *seed, size_t seed_len, - u8 *buf, size_t buf_len); - -#endif /* EAP_PEAP_COMMON_H */ diff --git a/src/eap_common/eap_psk_common.h b/src/eap_common/eap_psk_common.h deleted file mode 100644 index 8bc2c3c..0000000 --- a/src/eap_common/eap_psk_common.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * EAP server/peer: EAP-PSK shared routines - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PSK_COMMON_H -#define EAP_PSK_COMMON_H - - -#define EAP_PSK_RAND_LEN 16 -#define EAP_PSK_MAC_LEN 16 -#define EAP_PSK_TEK_LEN 16 -#define EAP_PSK_PSK_LEN 16 -#define EAP_PSK_AK_LEN 16 -#define EAP_PSK_KDK_LEN 16 - -#define EAP_PSK_R_FLAG_CONT 1 -#define EAP_PSK_R_FLAG_DONE_SUCCESS 2 -#define EAP_PSK_R_FLAG_DONE_FAILURE 3 -#define EAP_PSK_E_FLAG 0x20 - -#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6) -#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6) - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -/* EAP-PSK First Message (AS -> Supplicant) */ -struct eap_psk_hdr_1 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - /* Followed by variable length ID_S */ -} STRUCT_PACKED; - -/* EAP-PSK Second Message (Supplicant -> AS) */ -struct eap_psk_hdr_2 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - u8 rand_p[EAP_PSK_RAND_LEN]; - u8 mac_p[EAP_PSK_MAC_LEN]; - /* Followed by variable length ID_P */ -} STRUCT_PACKED; - -/* EAP-PSK Third Message (AS -> Supplicant) */ -struct eap_psk_hdr_3 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - u8 mac_s[EAP_PSK_MAC_LEN]; - /* Followed by variable length PCHANNEL */ -} STRUCT_PACKED; - -/* EAP-PSK Fourth Message (Supplicant -> AS) */ -struct eap_psk_hdr_4 { - u8 flags; - u8 rand_s[EAP_PSK_RAND_LEN]; - /* Followed by variable length PCHANNEL */ -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk); -int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, - u8 *msk, u8 *emsk); - -#endif /* EAP_PSK_COMMON_H */ diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h deleted file mode 100644 index a0d717e..0000000 --- a/src/eap_common/eap_pwd_common.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * EAP server/peer: EAP-pwd shared definitions - * Copyright (c) 2009, Dan Harkins - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_PWD_COMMON_H -#define EAP_PWD_COMMON_H - -#include -#include -#include - -/* - * definition of a finite cyclic group - * TODO: support one based on a prime field - */ -typedef struct group_definition_ { - u16 group_num; - EC_GROUP *group; - EC_POINT *pwe; - BIGNUM *order; - BIGNUM *prime; -} EAP_PWD_group; - -/* - * EAP-pwd header, included on all payloads - * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set) - */ -#define EAP_PWD_HDR_SIZE 1 - -#define EAP_PWD_OPCODE_ID_EXCH 1 -#define EAP_PWD_OPCODE_COMMIT_EXCH 2 -#define EAP_PWD_OPCODE_CONFIRM_EXCH 3 -#define EAP_PWD_GET_LENGTH_BIT(x) ((x) & 0x80) -#define EAP_PWD_SET_LENGTH_BIT(x) ((x) |= 0x80) -#define EAP_PWD_GET_MORE_BIT(x) ((x) & 0x40) -#define EAP_PWD_SET_MORE_BIT(x) ((x) |= 0x40) -#define EAP_PWD_GET_EXCHANGE(x) ((x) & 0x3f) -#define EAP_PWD_SET_EXCHANGE(x,y) ((x) |= (y)) - -/* EAP-pwd-ID payload */ -struct eap_pwd_id { - be16 group_num; - u8 random_function; -#define EAP_PWD_DEFAULT_RAND_FUNC 1 - u8 prf; -#define EAP_PWD_DEFAULT_PRF 1 - u8 token[4]; - u8 prep; -#define EAP_PWD_PREP_NONE 0 -#define EAP_PWD_PREP_MS 1 - u8 identity[0]; /* length inferred from payload */ -} STRUCT_PACKED; - -/* common routines */ -int compute_password_element(EAP_PWD_group *grp, u16 num, - const u8 *password, size_t password_len, - const u8 *id_server, size_t id_server_len, - const u8 *id_peer, size_t id_peer_len, - const u8 *token); -int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k, - const BIGNUM *peer_scalar, const BIGNUM *server_scalar, - const u8 *confirm_peer, const u8 *confirm_server, - const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id); -struct crypto_hash * eap_pwd_h_init(void); -void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len); -void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest); - -#endif /* EAP_PWD_COMMON_H */ diff --git a/src/eap_common/eap_sake_common.h b/src/eap_common/eap_sake_common.h deleted file mode 100644 index 9e1e757..0000000 --- a/src/eap_common/eap_sake_common.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * EAP server/peer: EAP-SAKE shared routines - * Copyright (c) 2006-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_SAKE_COMMON_H -#define EAP_SAKE_COMMON_H - -#define EAP_SAKE_VERSION 2 - -#define EAP_SAKE_SUBTYPE_CHALLENGE 1 -#define EAP_SAKE_SUBTYPE_CONFIRM 2 -#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3 -#define EAP_SAKE_SUBTYPE_IDENTITY 4 - -#define EAP_SAKE_AT_RAND_S 1 -#define EAP_SAKE_AT_RAND_P 2 -#define EAP_SAKE_AT_MIC_S 3 -#define EAP_SAKE_AT_MIC_P 4 -#define EAP_SAKE_AT_SERVERID 5 -#define EAP_SAKE_AT_PEERID 6 -#define EAP_SAKE_AT_SPI_S 7 -#define EAP_SAKE_AT_SPI_P 8 -#define EAP_SAKE_AT_ANY_ID_REQ 9 -#define EAP_SAKE_AT_PERM_ID_REQ 10 -#define EAP_SAKE_AT_ENCR_DATA 128 -#define EAP_SAKE_AT_IV 129 -#define EAP_SAKE_AT_PADDING 130 -#define EAP_SAKE_AT_NEXT_TMPID 131 -#define EAP_SAKE_AT_MSK_LIFE 132 - -#define EAP_SAKE_RAND_LEN 16 -#define EAP_SAKE_MIC_LEN 16 -#define EAP_SAKE_ROOT_SECRET_LEN 16 -#define EAP_SAKE_SMS_LEN 16 -#define EAP_SAKE_TEK_AUTH_LEN 16 -#define EAP_SAKE_TEK_CIPHER_LEN 16 -#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN) - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_sake_hdr { - u8 version; /* EAP_SAKE_VERSION */ - u8 session_id; - u8 subtype; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - - -struct eap_sake_parse_attr { - const u8 *rand_s; - const u8 *rand_p; - const u8 *mic_s; - const u8 *mic_p; - const u8 *serverid; - size_t serverid_len; - const u8 *peerid; - size_t peerid_len; - const u8 *spi_s; - size_t spi_s_len; - const u8 *spi_p; - size_t spi_p_len; - const u8 *any_id_req; - const u8 *perm_id_req; - const u8 *encr_data; - size_t encr_data_len; - const u8 *iv; - size_t iv_len; - const u8 *next_tmpid; - size_t next_tmpid_len; - const u8 *msk_life; -}; - -int eap_sake_parse_attributes(const u8 *buf, size_t len, - struct eap_sake_parse_attr *attr); -void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b, - const u8 *rand_s, const u8 *rand_p, - u8 *tek, u8 *msk, u8 *emsk); -int eap_sake_compute_mic(const u8 *tek_auth, - const u8 *rand_s, const u8 *rand_p, - const u8 *serverid, size_t serverid_len, - const u8 *peerid, size_t peerid_len, - int peer, const u8 *eap, size_t eap_len, - const u8 *mic_pos, u8 *mic); -void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data, - size_t len); - -#endif /* EAP_SAKE_COMMON_H */ diff --git a/src/eap_common/eap_sim_common.h b/src/eap_common/eap_sim_common.h deleted file mode 100644 index daeb0e2..0000000 --- a/src/eap_common/eap_sim_common.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * EAP peer/server: EAP-SIM/AKA/AKA' shared routines - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_SIM_COMMON_H -#define EAP_SIM_COMMON_H - -#define EAP_SIM_NONCE_S_LEN 16 -#define EAP_SIM_NONCE_MT_LEN 16 -#define EAP_SIM_MAC_LEN 16 -#define EAP_SIM_MK_LEN 20 -#define EAP_SIM_K_AUT_LEN 16 -#define EAP_SIM_K_ENCR_LEN 16 -#define EAP_SIM_KEYING_DATA_LEN 64 -#define EAP_SIM_IV_LEN 16 -#define EAP_SIM_KC_LEN 8 -#define EAP_SIM_SRES_LEN 4 - -#define GSM_RAND_LEN 16 - -#define EAP_SIM_VERSION 1 - -/* EAP-SIM Subtypes */ -#define EAP_SIM_SUBTYPE_START 10 -#define EAP_SIM_SUBTYPE_CHALLENGE 11 -#define EAP_SIM_SUBTYPE_NOTIFICATION 12 -#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13 -#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14 - -/* AT_CLIENT_ERROR_CODE error codes */ -#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0 -#define EAP_SIM_UNSUPPORTED_VERSION 1 -#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2 -#define EAP_SIM_RAND_NOT_FRESH 3 - -#define EAP_SIM_MAX_FAST_REAUTHS 1000 - -#define EAP_SIM_MAX_CHAL 3 - - -/* EAP-AKA Subtypes */ -#define EAP_AKA_SUBTYPE_CHALLENGE 1 -#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2 -#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4 -#define EAP_AKA_SUBTYPE_IDENTITY 5 -#define EAP_AKA_SUBTYPE_NOTIFICATION 12 -#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13 -#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14 - -/* AT_CLIENT_ERROR_CODE error codes */ -#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0 - -#define EAP_AKA_RAND_LEN 16 -#define EAP_AKA_AUTN_LEN 16 -#define EAP_AKA_AUTS_LEN 14 -#define EAP_AKA_RES_MAX_LEN 16 -#define EAP_AKA_IK_LEN 16 -#define EAP_AKA_CK_LEN 16 -#define EAP_AKA_MAX_FAST_REAUTHS 1000 -#define EAP_AKA_MIN_RES_LEN 4 -#define EAP_AKA_MAX_RES_LEN 16 -#define EAP_AKA_CHECKCODE_LEN 20 - -#define EAP_AKA_PRIME_K_AUT_LEN 32 -#define EAP_AKA_PRIME_CHECKCODE_LEN 32 -#define EAP_AKA_PRIME_K_RE_LEN 32 - -struct wpabuf; - -void eap_sim_derive_mk(const u8 *identity, size_t identity_len, - const u8 *nonce_mt, u16 selected_version, - const u8 *ver_list, size_t ver_list_len, - int num_chal, const u8 *kc, u8 *mk); -void eap_aka_derive_mk(const u8 *identity, size_t identity_len, - const u8 *ik, const u8 *ck, u8 *mk); -int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, - u8 *emsk); -int eap_sim_derive_keys_reauth(u16 _counter, - const u8 *identity, size_t identity_len, - const u8 *nonce_s, const u8 *mk, u8 *msk, - u8 *emsk); -int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, - const u8 *mac, const u8 *extra, size_t extra_len); -void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, - const u8 *extra, size_t extra_len); - -#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) -void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, - const u8 *ik, const u8 *ck, u8 *k_encr, - u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk); -int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, - const u8 *identity, size_t identity_len, - const u8 *nonce_s, u8 *msk, u8 *emsk); -int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, - const u8 *mac, const u8 *extra, - size_t extra_len); -void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, - u8 *mac, const u8 *extra, size_t extra_len); - -void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, - const u8 *network_name, - size_t network_name_len); -#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ -static inline void eap_aka_prime_derive_keys(const u8 *identity, - size_t identity_len, - const u8 *ik, const u8 *ck, - u8 *k_encr, u8 *k_aut, u8 *k_re, - u8 *msk, u8 *emsk) -{ -} - -static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, - const u8 *identity, - size_t identity_len, - const u8 *nonce_s, u8 *msk, - u8 *emsk) -{ - return -1; -} - -static inline int eap_sim_verify_mac_sha256(const u8 *k_aut, - const struct wpabuf *req, - const u8 *mac, const u8 *extra, - size_t extra_len) -{ - return -1; -} -#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ - - -/* EAP-SIM/AKA Attributes (0..127 non-skippable) */ -#define EAP_SIM_AT_RAND 1 -#define EAP_SIM_AT_AUTN 2 /* only AKA */ -#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */ -#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */ -#define EAP_SIM_AT_PADDING 6 /* only encrypted */ -#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */ -#define EAP_SIM_AT_PERMANENT_ID_REQ 10 -#define EAP_SIM_AT_MAC 11 -#define EAP_SIM_AT_NOTIFICATION 12 -#define EAP_SIM_AT_ANY_ID_REQ 13 -#define EAP_SIM_AT_IDENTITY 14 /* only send */ -#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */ -#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */ -#define EAP_SIM_AT_FULLAUTH_ID_REQ 17 -#define EAP_SIM_AT_COUNTER 19 /* only encrypted */ -#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */ -#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */ -#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */ -#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */ -#define EAP_SIM_AT_KDF 24 /* only AKA' */ -#define EAP_SIM_AT_IV 129 -#define EAP_SIM_AT_ENCR_DATA 130 -#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */ -#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */ -#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */ -#define EAP_SIM_AT_RESULT_IND 135 -#define EAP_SIM_AT_BIDDING 136 - -/* AT_NOTIFICATION notification code values */ -#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0 -#define EAP_SIM_TEMPORARILY_DENIED 1026 -#define EAP_SIM_NOT_SUBSCRIBED 1031 -#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384 -#define EAP_SIM_SUCCESS 32768 - -/* EAP-AKA' AT_KDF Key Derivation Function values */ -#define EAP_AKA_PRIME_KDF 1 - -/* AT_BIDDING flags */ -#define EAP_AKA_BIDDING_FLAG_D 0x8000 - - -enum eap_sim_id_req { - NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID -}; - - -struct eap_sim_attrs { - const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s; - const u8 *next_pseudonym, *next_reauth_id; - const u8 *nonce_mt, *identity, *res, *auts; - const u8 *checkcode; - const u8 *kdf_input; - const u8 *bidding; - size_t num_chal, version_list_len, encr_data_len; - size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len; - size_t res_len_bits; - size_t checkcode_len; - size_t kdf_input_len; - enum eap_sim_id_req id_req; - int notification, counter, selected_version, client_error_code; - int counter_too_small; - int result_ind; -#define EAP_AKA_PRIME_KDF_MAX 10 - u16 kdf[EAP_AKA_PRIME_KDF_MAX]; - size_t kdf_count; -}; - -int eap_sim_parse_attr(const u8 *start, const u8 *end, - struct eap_sim_attrs *attr, int aka, int encr); -u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, - size_t encr_data_len, const u8 *iv, - struct eap_sim_attrs *attr, int aka); - - -struct eap_sim_msg; - -struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype); -struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type, - const u8 *k_aut, - const u8 *extra, size_t extra_len); -void eap_sim_msg_free(struct eap_sim_msg *msg); -u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, - const u8 *data, size_t len); -u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, - u16 value, const u8 *data, size_t len); -u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr); -int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, - u8 attr_encr); -int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, - int attr_pad); - -void eap_sim_report_notification(void *msg_ctx, int notification, int aka); - -#endif /* EAP_SIM_COMMON_H */ diff --git a/src/eap_common/eap_tlv_common.h b/src/eap_common/eap_tlv_common.h deleted file mode 100644 index 3286055..0000000 --- a/src/eap_common/eap_tlv_common.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt) - * Copyright (c) 2004-2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_TLV_COMMON_H -#define EAP_TLV_COMMON_H - -/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */ -#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */ -#define EAP_TLV_NAK_TLV 4 -#define EAP_TLV_ERROR_CODE_TLV 5 -#define EAP_TLV_CONNECTION_BINDING_TLV 6 -#define EAP_TLV_VENDOR_SPECIFIC_TLV 7 -#define EAP_TLV_URI_TLV 8 -#define EAP_TLV_EAP_PAYLOAD_TLV 9 -#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10 -#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */ -#define EAP_TLV_CRYPTO_BINDING_TLV 12 -#define EAP_TLV_CALLING_STATION_ID_TLV 13 -#define EAP_TLV_CALLED_STATION_ID_TLV 14 -#define EAP_TLV_NAS_PORT_TYPE_TLV 15 -#define EAP_TLV_SERVER_IDENTIFIER_TLV 16 -#define EAP_TLV_IDENTITY_TYPE_TLV 17 -#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18 -#define EAP_TLV_REQUEST_ACTION_TLV 19 -#define EAP_TLV_PKCS7_TLV 20 - -#define EAP_TLV_RESULT_SUCCESS 1 -#define EAP_TLV_RESULT_FAILURE 2 - -#define EAP_TLV_TYPE_MANDATORY 0x8000 -#define EAP_TLV_TYPE_MASK 0x3fff - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif /* _MSC_VER */ - -struct eap_tlv_hdr { - be16 tlv_type; - be16 length; -} STRUCT_PACKED; - -struct eap_tlv_nak_tlv { - be16 tlv_type; - be16 length; - be32 vendor_id; - be16 nak_type; -} STRUCT_PACKED; - -struct eap_tlv_result_tlv { - be16 tlv_type; - be16 length; - be16 status; -} STRUCT_PACKED; - -/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */ -struct eap_tlv_intermediate_result_tlv { - be16 tlv_type; - be16 length; - be16 status; - /* Followed by optional TLVs */ -} STRUCT_PACKED; - -/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */ -struct eap_tlv_crypto_binding_tlv { - be16 tlv_type; - be16 length; - u8 reserved; - u8 version; - u8 received_version; - u8 subtype; - u8 nonce[32]; - u8 compound_mac[20]; -} STRUCT_PACKED; - -struct eap_tlv_pac_ack_tlv { - be16 tlv_type; - be16 length; - be16 pac_type; - be16 pac_len; - be16 result; -} STRUCT_PACKED; - -/* RFC 4851, Section 4.2.9 - Request-Action TLV */ -struct eap_tlv_request_action_tlv { - be16 tlv_type; - be16 length; - be16 action; -} STRUCT_PACKED; - -/* RFC 5422, Section 4.2.6 - PAC-Type TLV */ -struct eap_tlv_pac_type_tlv { - be16 tlv_type; /* PAC_TYPE_PAC_TYPE */ - be16 length; - be16 pac_type; -} STRUCT_PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ - -#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0 -#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1 - -#define EAP_TLV_ACTION_PROCESS_TLV 1 -#define EAP_TLV_ACTION_NEGOTIATE_EAP 2 - -#endif /* EAP_TLV_COMMON_H */ diff --git a/src/eap_common/eap_ttls.h b/src/eap_common/eap_ttls.h deleted file mode 100644 index 17901d4..0000000 --- a/src/eap_common/eap_ttls.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * EAP server/peer: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_TTLS_H -#define EAP_TTLS_H - -struct ttls_avp { - be32 avp_code; - be32 avp_length; /* 8-bit flags, 24-bit length; - * length includes AVP header */ - /* optional 32-bit Vendor-ID */ - /* Data */ -}; - -struct ttls_avp_vendor { - be32 avp_code; - be32 avp_length; /* 8-bit flags, 24-bit length; - * length includes AVP header */ - be32 vendor_id; - /* Data */ -}; - -#define AVP_FLAGS_VENDOR 0x80 -#define AVP_FLAGS_MANDATORY 0x40 - -#define AVP_PAD(start, pos) \ -do { \ - int __pad; \ - __pad = (4 - (((pos) - (start)) & 3)) & 3; \ - os_memset((pos), 0, __pad); \ - pos += __pad; \ -} while (0) - - -/* RFC 2865 */ -#define RADIUS_ATTR_USER_NAME 1 -#define RADIUS_ATTR_USER_PASSWORD 2 -#define RADIUS_ATTR_CHAP_PASSWORD 3 -#define RADIUS_ATTR_REPLY_MESSAGE 18 -#define RADIUS_ATTR_CHAP_CHALLENGE 60 -#define RADIUS_ATTR_EAP_MESSAGE 79 - -/* RFC 2548 */ -#define RADIUS_VENDOR_ID_MICROSOFT 311 -#define RADIUS_ATTR_MS_CHAP_RESPONSE 1 -#define RADIUS_ATTR_MS_CHAP_ERROR 2 -#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6 -#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11 -#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25 -#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26 -#define RADIUS_ATTR_MS_CHAP2_CPW 27 - -#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16 -#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50 -#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8 -#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50 -#define EAP_TTLS_CHAP_CHALLENGE_LEN 16 -#define EAP_TTLS_CHAP_PASSWORD_LEN 16 - -#endif /* EAP_TTLS_H */ diff --git a/src/eap_common/eap_wsc_common.h b/src/eap_common/eap_wsc_common.h deleted file mode 100644 index 0e7b653..0000000 --- a/src/eap_common/eap_wsc_common.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * EAP-WSC definitions for Wi-Fi Protected Setup - * Copyright (c) 2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_WSC_COMMON_H -#define EAP_WSC_COMMON_H - -#define EAP_VENDOR_TYPE_WSC 1 - -#define WSC_FLAGS_MF 0x01 -#define WSC_FLAGS_LF 0x02 - -#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0" -#define WSC_ID_REGISTRAR_LEN 30 -#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0" -#define WSC_ID_ENROLLEE_LEN 29 - -#define WSC_FRAGMENT_SIZE 1400 - - -struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code); - -#endif /* EAP_WSC_COMMON_H */ diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h deleted file mode 100644 index 1a645af..0000000 --- a/src/eap_peer/eap.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * EAP peer state machine functions (RFC 4137) - * Copyright (c) 2004-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_H -#define EAP_H - -#include "common/defs.h" -#include "eap_common/eap_defs.h" -#include "eap_peer/eap_methods.h" - -struct eap_sm; -struct wpa_config_blob; -struct wpabuf; - -struct eap_method_type { - int vendor; - u32 method; -}; - -#ifdef IEEE8021X_EAPOL - -/** - * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine - * - * These variables are used in the interface between EAP peer state machine and - * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is - * expected to maintain these variables and register a callback functions for - * EAP state machine to get and set the variables. - */ -enum eapol_bool_var { - /** - * EAPOL_eapSuccess - EAP SUCCESS state reached - * - * EAP state machine reads and writes this value. - */ - EAPOL_eapSuccess, - - /** - * EAPOL_eapRestart - Lower layer request to restart authentication - * - * Set to TRUE in lower layer, FALSE in EAP state machine. - */ - EAPOL_eapRestart, - - /** - * EAPOL_eapFail - EAP FAILURE state reached - * - * EAP state machine writes this value. - */ - EAPOL_eapFail, - - /** - * EAPOL_eapResp - Response to send - * - * Set to TRUE in EAP state machine, FALSE in lower layer. - */ - EAPOL_eapResp, - - /** - * EAPOL_eapNoResp - Request has been process; no response to send - * - * Set to TRUE in EAP state machine, FALSE in lower layer. - */ - EAPOL_eapNoResp, - - /** - * EAPOL_eapReq - EAP request available from lower layer - * - * Set to TRUE in lower layer, FALSE in EAP state machine. - */ - EAPOL_eapReq, - - /** - * EAPOL_portEnabled - Lower layer is ready for communication - * - * EAP state machines reads this value. - */ - EAPOL_portEnabled, - - /** - * EAPOL_altAccept - Alternate indication of success (RFC3748) - * - * EAP state machines reads this value. - */ - EAPOL_altAccept, - - /** - * EAPOL_altReject - Alternate indication of failure (RFC3748) - * - * EAP state machines reads this value. - */ - EAPOL_altReject, - - /** - * EAPOL_eapTriggerStart - EAP-based trigger to send EAPOL-Start - * - * EAP state machine writes this value. - */ - EAPOL_eapTriggerStart -}; - -/** - * enum eapol_int_var - EAPOL integer state variables for EAP state machine - * - * These variables are used in the interface between EAP peer state machine and - * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is - * expected to maintain these variables and register a callback functions for - * EAP state machine to get and set the variables. - */ -enum eapol_int_var { - /** - * EAPOL_idleWhile - Outside time for EAP peer timeout - * - * This integer variable is used to provide an outside timer that the - * external (to EAP state machine) code must decrement by one every - * second until the value reaches zero. This is used in the same way as - * EAPOL state machine timers. EAP state machine reads and writes this - * value. - */ - EAPOL_idleWhile -}; - -/** - * struct eapol_callbacks - Callback functions from EAP to lower layer - * - * This structure defines the callback functions that EAP state machine - * requires from the lower layer (usually EAPOL state machine) for updating - * state variables and requesting information. eapol_ctx from - * eap_peer_sm_init() call will be used as the ctx parameter for these - * callback functions. - */ -struct eapol_callbacks { - /** - * get_config - Get pointer to the current network configuration - * @ctx: eapol_ctx from eap_peer_sm_init() call - */ - struct eap_peer_config * (*get_config)(void *ctx); - - /** - * get_bool - Get a boolean EAPOL state variable - * @variable: EAPOL boolean variable to get - * Returns: Value of the EAPOL variable - */ - Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable); - - /** - * set_bool - Set a boolean EAPOL state variable - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @variable: EAPOL boolean variable to set - * @value: Value for the EAPOL variable - */ - void (*set_bool)(void *ctx, enum eapol_bool_var variable, - Boolean value); - - /** - * get_int - Get an integer EAPOL state variable - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @variable: EAPOL integer variable to get - * Returns: Value of the EAPOL variable - */ - unsigned int (*get_int)(void *ctx, enum eapol_int_var variable); - - /** - * set_int - Set an integer EAPOL state variable - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @variable: EAPOL integer variable to set - * @value: Value for the EAPOL variable - */ - void (*set_int)(void *ctx, enum eapol_int_var variable, - unsigned int value); - - /** - * get_eapReqData - Get EAP-Request data - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @len: Pointer to variable that will be set to eapReqDataLen - * Returns: Reference to eapReqData (EAP state machine will not free - * this) or %NULL if eapReqData not available. - */ - struct wpabuf * (*get_eapReqData)(void *ctx); - - /** - * set_config_blob - Set named configuration blob - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @blob: New value for the blob - * - * Adds a new configuration blob or replaces the current value of an - * existing blob. - */ - void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); - - /** - * get_config_blob - Get a named configuration blob - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @name: Name of the blob - * Returns: Pointer to blob data or %NULL if not found - */ - const struct wpa_config_blob * (*get_config_blob)(void *ctx, - const char *name); - - /** - * notify_pending - Notify that a pending request can be retried - * @ctx: eapol_ctx from eap_peer_sm_init() call - * - * An EAP method can perform a pending operation (e.g., to get a - * response from an external process). Once the response is available, - * this callback function can be used to request EAPOL state machine to - * retry delivering the previously received (and still unanswered) EAP - * request to EAP state machine. - */ - void (*notify_pending)(void *ctx); - - /** - * eap_param_needed - Notify that EAP parameter is needed - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY) - * @txt: User readable text describing the required parameter - */ - void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field, - const char *txt); - - /** - * notify_cert - Notification of a peer certificate - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @depth: Depth in certificate chain (0 = server) - * @subject: Subject of the peer certificate - * @altsubject: Select fields from AltSubject of the peer certificate - * @num_altsubject: Number of altsubject values - * @cert_hash: SHA-256 hash of the certificate - * @cert: Peer certificate - */ - void (*notify_cert)(void *ctx, int depth, const char *subject, - const char *altsubject[], int num_altsubject, - const char *cert_hash, const struct wpabuf *cert); - - /** - * notify_status - Notification of the current EAP state - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @status: Step in the process of EAP authentication - * @parameter: Step-specific parameter, e.g., EAP method name - */ - void (*notify_status)(void *ctx, const char *status, - const char *parameter); - -#ifdef CONFIG_EAP_PROXY - /** - * eap_proxy_cb - Callback signifying any updates from eap_proxy - * @ctx: eapol_ctx from eap_peer_sm_init() call - */ - void (*eap_proxy_cb)(void *ctx); -#endif /* CONFIG_EAP_PROXY */ - - /** - * set_anon_id - Set or add anonymous identity - * @ctx: eapol_ctx from eap_peer_sm_init() call - * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear - * @len: Length of anonymous identity in octets - */ - void (*set_anon_id)(void *ctx, const u8 *id, size_t len); -}; - -/** - * struct eap_config - Configuration for EAP state machine - */ -struct eap_config { - /** - * opensc_engine_path - OpenSC engine for OpenSSL engine support - * - * Usually, path to engine_opensc.so. - */ - const char *opensc_engine_path; - /** - * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support - * - * Usually, path to engine_pkcs11.so. - */ - const char *pkcs11_engine_path; - /** - * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine - * - * Usually, path to opensc-pkcs11.so. - */ - const char *pkcs11_module_path; - /** - * openssl_ciphers - OpenSSL cipher string - * - * This is an OpenSSL specific configuration option for configuring the - * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the - * default. - */ - const char *openssl_ciphers; - /** - * wps - WPS context data - * - * This is only used by EAP-WSC and can be left %NULL if not available. - */ - struct wps_context *wps; - - /** - * cert_in_cb - Include server certificates in callback - */ - int cert_in_cb; -}; - -struct eap_sm * eap_peer_sm_init(void *eapol_ctx, - const struct eapol_callbacks *eapol_cb, - void *msg_ctx, struct eap_config *conf); -void eap_peer_sm_deinit(struct eap_sm *sm); -int eap_peer_sm_step(struct eap_sm *sm); -void eap_sm_abort(struct eap_sm *sm); -int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, - int verbose); -const char * eap_sm_get_method_name(struct eap_sm *sm); -struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted); -void eap_sm_request_identity(struct eap_sm *sm); -void eap_sm_request_password(struct eap_sm *sm); -void eap_sm_request_new_password(struct eap_sm *sm); -void eap_sm_request_pin(struct eap_sm *sm); -void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len); -void eap_sm_request_passphrase(struct eap_sm *sm); -void eap_sm_request_sim(struct eap_sm *sm, const char *req); -void eap_sm_notify_ctrl_attached(struct eap_sm *sm); -u32 eap_get_phase2_type(const char *name, int *vendor); -struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config, - size_t *count); -void eap_set_fast_reauth(struct eap_sm *sm, int enabled); -void eap_set_workaround(struct eap_sm *sm, unsigned int workaround); -void eap_set_force_disabled(struct eap_sm *sm, int disabled); -void eap_set_external_sim(struct eap_sm *sm, int external_sim); -int eap_key_available(struct eap_sm *sm); -void eap_notify_success(struct eap_sm *sm); -void eap_notify_lower_layer_success(struct eap_sm *sm); -const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len); -const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); -struct wpabuf * eap_get_eapRespData(struct eap_sm *sm); -void eap_register_scard_ctx(struct eap_sm *sm, void *ctx); -void eap_invalidate_cached_session(struct eap_sm *sm); - -int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf); -int eap_is_wps_pin_enrollee(struct eap_peer_config *conf); - -struct ext_password_data; -void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext); -void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len); -int eap_peer_was_failure_expected(struct eap_sm *sm); -void eap_peer_erp_free_keys(struct eap_sm *sm); - -#endif /* IEEE8021X_EAPOL */ - -#endif /* EAP_H */ diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h deleted file mode 100644 index 2b1a1d5..0000000 --- a/src/eap_peer/eap_config.h +++ /dev/null @@ -1,774 +0,0 @@ -/* - * EAP peer configuration data - * Copyright (c) 2003-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_CONFIG_H -#define EAP_CONFIG_H - -/** - * struct eap_peer_config - EAP peer configuration/credentials - */ -struct eap_peer_config { - /** - * identity - EAP Identity - * - * This field is used to set the real user identity or NAI (for - * EAP-PSK/PAX/SAKE/GPSK). - */ - u8 *identity; - - /** - * identity_len - EAP Identity length - */ - size_t identity_len; - - /** - * anonymous_identity - Anonymous EAP Identity - * - * This field is used for unencrypted use with EAP types that support - * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the - * real identity (identity field) only to the authentication server. - * - * If not set, the identity field will be used for both unencrypted and - * protected fields. - * - * This field can also be used with EAP-SIM/AKA/AKA' to store the - * pseudonym identity. - */ - u8 *anonymous_identity; - - /** - * anonymous_identity_len - Length of anonymous_identity - */ - size_t anonymous_identity_len; - - /** - * password - Password string for EAP - * - * This field can include either the plaintext password (default - * option) or a NtPasswordHash (16-byte MD4 hash of the unicode - * presentation of the password) if flags field has - * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can - * only be used with authentication mechanism that use this hash as the - * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2, - * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). - * - * In addition, this field is used to configure a pre-shared key for - * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK - * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length - * PSK. - */ - u8 *password; - - /** - * password_len - Length of password field - */ - size_t password_len; - - /** - * ca_cert - File path to CA certificate file (PEM/DER) - * - * This file can have one or more trusted CA certificates. If ca_cert - * and ca_path are not included, server certificate will not be - * verified. This is insecure and a trusted CA certificate should - * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - * - * Alternatively, this can be used to only perform matching of the - * server certificate (SHA-256 hash of the DER encoded X.509 - * certificate). In this case, the possible CA certificates in the - * server certificate chain are ignored and only the server certificate - * is verified. This is configured with the following format: - * hash:://server/sha256/cert_hash_in_hex - * For example: "hash://server/sha256/ - * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" - * - * On Windows, trusted CA certificates can be loaded from the system - * certificate store by setting this to cert_store://name, e.g., - * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". - * Note that when running wpa_supplicant as an application, the user - * certificate store (My user account) is used, whereas computer store - * (Computer account) is used when running wpasvc as a service. - */ - u8 *ca_cert; - - /** - * ca_path - Directory path for CA certificate files (PEM) - * - * This path may contain multiple CA certificates in OpenSSL format. - * Common use for this is to point to system trusted CA list which is - * often installed into directory like /etc/ssl/certs. If configured, - * these certificates are added to the list of trusted CAs. ca_cert - * may also be included in that case, but it is not required. - */ - u8 *ca_path; - - /** - * client_cert - File path to client certificate file (PEM/DER) - * - * This field is used with EAP method that use TLS authentication. - * Usually, this is only configured for EAP-TLS, even though this could - * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *client_cert; - - /** - * private_key - File path to client private key file (PEM/DER/PFX) - * - * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be - * commented out. Both the private key and certificate will be read - * from the PKCS#12 file in this case. Full path to the file should be - * used since working directory may change when wpa_supplicant is run - * in the background. - * - * Windows certificate store can be used by leaving client_cert out and - * configuring private_key in one of the following formats: - * - * cert://substring_to_match - * - * hash://certificate_thumbprint_in_hex - * - * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" - * - * Note that when running wpa_supplicant as an application, the user - * certificate store (My user account) is used, whereas computer store - * (Computer account) is used when running wpasvc as a service. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *private_key; - - /** - * private_key_passwd - Password for private key file - * - * If left out, this will be asked through control interface. - */ - char *private_key_passwd; - - /** - * dh_file - File path to DH/DSA parameters file (in PEM format) - * - * This is an optional configuration file for setting parameters for an - * ephemeral DH key exchange. In most cases, the default RSA - * authentication does not use this configuration. However, it is - * possible setup RSA to use ephemeral DH key exchange. In addition, - * ciphers with DSA keys always use ephemeral DH keys. This can be used - * to achieve forward secrecy. If the file is in DSA parameters format, - * it will be automatically converted into DH params. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *dh_file; - - /** - * subject_match - Constraint for server certificate subject - * - * This substring is matched against the subject of the authentication - * server certificate. If this string is set, the server sertificate is - * only accepted if it contains this string in the subject. The subject - * string is in following format: - * - * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com - * - * Note: Since this is a substring match, this cannot be used securily - * to do a suffix match against a possible domain name in the CN entry. - * For such a use case, domain_suffix_match should be used instead. - */ - u8 *subject_match; - - /** - * altsubject_match - Constraint for server certificate alt. subject - * - * Semicolon separated string of entries to be matched against the - * alternative subject name of the authentication server certificate. - * If this string is set, the server sertificate is only accepted if it - * contains one of the entries in an alternative subject name - * extension. - * - * altSubjectName string is in following format: TYPE:VALUE - * - * Example: EMAIL:server@example.com - * Example: DNS:server.example.com;DNS:server2.example.com - * - * Following types are supported: EMAIL, DNS, URI - */ - u8 *altsubject_match; - - /** - * domain_suffix_match - Constraint for server domain name - * - * If set, this FQDN is used as a suffix match requirement for the - * server certificate in SubjectAltName dNSName element(s). If a - * matching dNSName is found, this constraint is met. If no dNSName - * values are present, this constraint is matched against SubjectName CN - * using same suffix match comparison. Suffix match here means that the - * host/domain name is compared one label at a time starting from the - * top-level domain and all the labels in domain_suffix_match shall be - * included in the certificate. The certificate may include additional - * sub-level labels in addition to the required labels. - * - * For example, domain_suffix_match=example.com would match - * test.example.com but would not match test-example.com. - */ - char *domain_suffix_match; - - /** - * domain_match - Constraint for server domain name - * - * If set, this FQDN is used as a full match requirement for the - * server certificate in SubjectAltName dNSName element(s). If a - * matching dNSName is found, this constraint is met. If no dNSName - * values are present, this constraint is matched against SubjectName CN - * using same full match comparison. This behavior is similar to - * domain_suffix_match, but has the requirement of a full match, i.e., - * no subdomains or wildcard matches are allowed. Case-insensitive - * comparison is used, so "Example.com" matches "example.com", but would - * not match "test.Example.com". - */ - char *domain_match; - - /** - * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2) - * - * This file can have one or more trusted CA certificates. If ca_cert2 - * and ca_path2 are not included, server certificate will not be - * verified. This is insecure and a trusted CA certificate should - * always be configured. Full path to the file should be used since - * working directory may change when wpa_supplicant is run in the - * background. - * - * This field is like ca_cert, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *ca_cert2; - - /** - * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2) - * - * This path may contain multiple CA certificates in OpenSSL format. - * Common use for this is to point to system trusted CA list which is - * often installed into directory like /etc/ssl/certs. If configured, - * these certificates are added to the list of trusted CAs. ca_cert - * may also be included in that case, but it is not required. - * - * This field is like ca_path, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - u8 *ca_path2; - - /** - * client_cert2 - File path to client certificate file - * - * This field is like client_cert, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *client_cert2; - - /** - * private_key2 - File path to client private key file - * - * This field is like private_key, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *private_key2; - - /** - * private_key2_passwd - Password for private key file - * - * This field is like private_key_passwd, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - char *private_key2_passwd; - - /** - * dh_file2 - File path to DH/DSA parameters file (in PEM format) - * - * This field is like dh_file, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - u8 *dh_file2; - - /** - * subject_match2 - Constraint for server certificate subject - * - * This field is like subject_match, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - u8 *subject_match2; - - /** - * altsubject_match2 - Constraint for server certificate alt. subject - * - * This field is like altsubject_match, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - u8 *altsubject_match2; - - /** - * domain_suffix_match2 - Constraint for server domain name - * - * This field is like domain_suffix_match, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - char *domain_suffix_match2; - - /** - * domain_match2 - Constraint for server domain name - * - * This field is like domain_match, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - char *domain_match2; - - /** - * eap_methods - Allowed EAP methods - * - * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of - * allowed EAP methods or %NULL if all methods are accepted. - */ - struct eap_method_type *eap_methods; - - /** - * phase1 - Phase 1 (outer authentication) parameters - * - * String with field-value pairs, e.g., "peapver=0" or - * "peapver=1 peaplabel=1". - * - * 'peapver' can be used to force which PEAP version (0 or 1) is used. - * - * 'peaplabel=1' can be used to force new label, "client PEAP - * encryption", to be used during key derivation when PEAPv1 or newer. - * - * Most existing PEAPv1 implementation seem to be using the old label, - * "client EAP encryption", and wpa_supplicant is now using that as the - * default value. - * - * Some servers, e.g., Radiator, may require peaplabel=1 configuration - * to interoperate with PEAPv1; see eap_testing.txt for more details. - * - * 'peap_outer_success=0' can be used to terminate PEAP authentication - * on tunneled EAP-Success. This is required with some RADIUS servers - * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g., - * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode). - * - * include_tls_length=1 can be used to force wpa_supplicant to include - * TLS Message Length field in all TLS messages even if they are not - * fragmented. - * - * sim_min_num_chal=3 can be used to configure EAP-SIM to require three - * challenges (by default, it accepts 2 or 3). - * - * result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use - * protected result indication. - * - * fast_provisioning option can be used to enable in-line provisioning - * of EAP-FAST credentials (PAC): - * 0 = disabled, - * 1 = allow unauthenticated provisioning, - * 2 = allow authenticated provisioning, - * 3 = allow both unauthenticated and authenticated provisioning - * - * fast_max_pac_list_len=num option can be used to set the maximum - * number of PAC entries to store in a PAC list (default: 10). - * - * fast_pac_format=binary option can be used to select binary format - * for storing PAC entries in order to save some space (the default - * text format uses about 2.5 times the size of minimal binary format). - * - * crypto_binding option can be used to control PEAPv0 cryptobinding - * behavior: - * 0 = do not use cryptobinding (default) - * 1 = use cryptobinding if server supports it - * 2 = require cryptobinding - * - * EAP-WSC (WPS) uses following options: pin=Device_Password and - * uuid=Device_UUID - * - * For wired IEEE 802.1X authentication, "allow_canned_success=1" can be - * used to configure a mode that allows EAP-Success (and EAP-Failure) - * without going through authentication step. Some switches use such - * sequence when forcing the port to be authorized/unauthorized or as a - * fallback option if the authentication server is unreachable. By - * default, wpa_supplicant discards such frames to protect against - * potential attacks by rogue devices, but this option can be used to - * disable that protection for cases where the server/authenticator does - * not need to be authenticated. - */ - char *phase1; - - /** - * phase2 - Phase2 (inner authentication with TLS tunnel) parameters - * - * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or - * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can - * be used to disable MSCHAPv2 password retry in authentication failure - * cases. - */ - char *phase2; - - /** - * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM - * - * This field is used to configure PC/SC smartcard interface. - * Currently, the only configuration is whether this field is %NULL (do - * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC. - * - * This field is used for EAP-SIM and EAP-AKA. - */ - char *pcsc; - - /** - * pin - PIN for USIM, GSM SIM, and smartcards - * - * This field is used to configure PIN for SIM and smartcards for - * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a - * smartcard is used for private key operations. - * - * If left out, this will be asked through control interface. - */ - char *pin; - - /** - * engine - Enable OpenSSL engine (e.g., for smartcard access) - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - int engine; - - /** - * engine_id - Engine ID for OpenSSL engine - * - * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 - * engine. - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - char *engine_id; - - /** - * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2) - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - * - * This field is like engine, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - int engine2; - - - /** - * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2) - * - * This field is used to configure PIN for SIM and smartcards for - * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a - * smartcard is used for private key operations. - * - * This field is like pin2, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - * - * If left out, this will be asked through control interface. - */ - char *pin2; - - /** - * engine2_id - Engine ID for OpenSSL engine (Phase 2) - * - * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 - * engine. - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - * - * This field is like engine_id, but used for phase 2 (inside - * EAP-TTLS/PEAP/FAST tunnel) authentication. - */ - char *engine2_id; - - - /** - * key_id - Key ID for OpenSSL engine - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - char *key_id; - - /** - * cert_id - Cert ID for OpenSSL engine - * - * This is used if the certificate operations for EAP-TLS are performed - * using a smartcard. - */ - char *cert_id; - - /** - * ca_cert_id - CA Cert ID for OpenSSL engine - * - * This is used if the CA certificate for EAP-TLS is on a smartcard. - */ - char *ca_cert_id; - - /** - * key2_id - Key ID for OpenSSL engine (phase2) - * - * This is used if private key operations for EAP-TLS are performed - * using a smartcard. - */ - char *key2_id; - - /** - * cert2_id - Cert ID for OpenSSL engine (phase2) - * - * This is used if the certificate operations for EAP-TLS are performed - * using a smartcard. - */ - char *cert2_id; - - /** - * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2) - * - * This is used if the CA certificate for EAP-TLS is on a smartcard. - */ - char *ca_cert2_id; - - /** - * otp - One-time-password - * - * This field should not be set in configuration step. It is only used - * internally when OTP is entered through the control interface. - */ - u8 *otp; - - /** - * otp_len - Length of the otp field - */ - size_t otp_len; - - /** - * pending_req_identity - Whether there is a pending identity request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_identity; - - /** - * pending_req_password - Whether there is a pending password request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_password; - - /** - * pending_req_pin - Whether there is a pending PIN request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_pin; - - /** - * pending_req_new_password - Pending password update request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_new_password; - - /** - * pending_req_passphrase - Pending passphrase request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - int pending_req_passphrase; - - /** - * pending_req_otp - Whether there is a pending OTP request - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request needed - * information. - */ - char *pending_req_otp; - - /** - * pending_req_otp_len - Length of the pending OTP request - */ - size_t pending_req_otp_len; - - /** - * pac_file - File path or blob name for the PAC entries (EAP-FAST) - * - * wpa_supplicant will need to be able to create this file and write - * updates to it when PAC is being provisioned or refreshed. Full path - * to the file should be used since working directory may change when - * wpa_supplicant is run in the background. - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - char *pac_file; - - /** - * mschapv2_retry - MSCHAPv2 retry in progress - * - * This field is used internally by EAP-MSCHAPv2 and should not be set - * as part of configuration. - */ - int mschapv2_retry; - - /** - * new_password - New password for password update - * - * This field is used during MSCHAPv2 password update. This is normally - * requested from the user through the control interface and not set - * from configuration. - */ - u8 *new_password; - - /** - * new_password_len - Length of new_password field - */ - size_t new_password_len; - - /** - * fragment_size - Maximum EAP fragment size in bytes (default 1398) - * - * This value limits the fragment size for EAP methods that support - * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set - * small enough to make the EAP messages fit in MTU of the network - * interface used for EAPOL. The default value is suitable for most - * cases. - */ - int fragment_size; - -#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0) -#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1) - /** - * flags - Network configuration flags (bitfield) - * - * This variable is used for internal flags to describe further details - * for the network parameters. - * bit 0 = password is represented as a 16-byte NtPasswordHash value - * instead of plaintext password - * bit 1 = password is stored in external storage; the value in the - * password field is the name of that external entry - */ - u32 flags; - - /** - * ocsp - Whether to use/require OCSP to check server certificate - * - * 0 = do not use OCSP stapling (TLS certificate status extension) - * 1 = try to use OCSP stapling, but not require response - * 2 = require valid OCSP stapling response - */ - int ocsp; - - /** - * external_sim_resp - Response from external SIM processing - * - * This field should not be set in configuration step. It is only used - * internally when control interface is used to request external - * SIM/USIM processing. - */ - char *external_sim_resp; - - /** - * sim_num - User selected SIM identifier - * - * This variable is used for identifying which SIM is used if the system - * has more than one. - */ - int sim_num; - - /** - * openssl_ciphers - OpenSSL cipher string - * - * This is an OpenSSL specific configuration option for configuring the - * ciphers for this connection. If not set, the default cipher suite - * list is used. - */ - char *openssl_ciphers; - - /** - * erp - Whether EAP Re-authentication Protocol (ERP) is enabled - */ - int erp; -}; - - -/** - * struct wpa_config_blob - Named configuration blob - * - * This data structure is used to provide storage for binary objects to store - * abstract information like certificates and private keys inlined with the - * configuration data. - */ -struct wpa_config_blob { - /** - * name - Blob name - */ - char *name; - - /** - * data - Pointer to binary data - */ - u8 *data; - - /** - * len - Length of binary data - */ - size_t len; - - /** - * next - Pointer to next blob in the configuration - */ - struct wpa_config_blob *next; -}; - -#endif /* EAP_CONFIG_H */ diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h deleted file mode 100644 index 99b44da..0000000 --- a/src/eap_peer/eap_i.h +++ /dev/null @@ -1,389 +0,0 @@ -/* - * EAP peer state machines internal structures (RFC 4137) - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_I_H -#define EAP_I_H - -#include "wpabuf.h" -#include "utils/list.h" -#include "eap_peer/eap.h" -#include "eap_common/eap_common.h" - -/* RFC 4137 - EAP Peer state machine */ - -typedef enum { - DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC -} EapDecision; - -typedef enum { - METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE -} EapMethodState; - -/** - * struct eap_method_ret - EAP return values from struct eap_method::process() - * - * These structure contains OUT variables for the interface between peer state - * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as - * the return value of struct eap_method::process() so it is not included in - * this structure. - */ -struct eap_method_ret { - /** - * ignore - Whether method decided to drop the current packed (OUT) - */ - Boolean ignore; - - /** - * methodState - Method-specific state (IN/OUT) - */ - EapMethodState methodState; - - /** - * decision - Authentication decision (OUT) - */ - EapDecision decision; - - /** - * allowNotifications - Whether method allows notifications (OUT) - */ - Boolean allowNotifications; -}; - - -/** - * struct eap_method - EAP method interface - * This structure defines the EAP method interface. Each method will need to - * register its own EAP type, EAP name, and set of function pointers for method - * specific operations. This interface is based on section 4.4 of RFC 4137. - */ -struct eap_method { - /** - * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) - */ - int vendor; - - /** - * method - EAP type number (EAP_TYPE_*) - */ - EapType method; - - /** - * name - Name of the method (e.g., "TLS") - */ - const char *name; - - /** - * init - Initialize an EAP method - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * Returns: Pointer to allocated private data, or %NULL on failure - * - * This function is used to initialize the EAP method explicitly - * instead of using METHOD_INIT state as specific in RFC 4137. The - * method is expected to initialize it method-specific state and return - * a pointer that will be used as the priv argument to other calls. - */ - void * (*init)(struct eap_sm *sm); - - /** - * deinit - Deinitialize an EAP method - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * - * Deinitialize the EAP method and free any allocated private data. - */ - void (*deinit)(struct eap_sm *sm, void *priv); - - /** - * process - Process an EAP request - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @ret: Return values from EAP request validation and processing - * @reqData: EAP request to be processed (eapReqData) - * Returns: Pointer to allocated EAP response packet (eapRespData) - * - * This function is a combination of m.check(), m.process(), and - * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other - * words, this function validates the incoming request, processes it, - * and build a response packet. m.check() and m.process() return values - * are returned through struct eap_method_ret *ret variable. Caller is - * responsible for freeing the returned EAP response packet. - */ - struct wpabuf * (*process)(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData); - - /** - * isKeyAvailable - Find out whether EAP method has keying material - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * Returns: %TRUE if key material (eapKeyData) is available - */ - Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv); - - /** - * getKey - Get EAP method specific keying material (eapKeyData) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Pointer to variable to store key length (eapKeyDataLen) - * Returns: Keying material (eapKeyData) or %NULL if not available - * - * This function can be used to get the keying material from the EAP - * method. The key may already be stored in the method-specific private - * data or this function may derive the key. - */ - u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len); - - /** - * get_status - Get EAP method status - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf - * - * Query EAP method for status information. This function fills in a - * text area with current status information from the EAP method. If - * the buffer (buf) is not large enough, status information will be - * truncated to fit the buffer. - */ - int (*get_status)(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose); - - /** - * has_reauth_data - Whether method is ready for fast reauthentication - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * Returns: %TRUE or %FALSE based on whether fast reauthentication is - * possible - * - * This function is an optional handler that only EAP methods - * supporting fast re-authentication need to implement. - */ - Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv); - - /** - * deinit_for_reauth - Release data that is not needed for fast re-auth - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * - * This function is an optional handler that only EAP methods - * supporting fast re-authentication need to implement. This is called - * when authentication has been completed and EAP state machine is - * requesting that enough state information is maintained for fast - * re-authentication - */ - void (*deinit_for_reauth)(struct eap_sm *sm, void *priv); - - /** - * init_for_reauth - Prepare for start of fast re-authentication - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * - * This function is an optional handler that only EAP methods - * supporting fast re-authentication need to implement. This is called - * when EAP authentication is started and EAP state machine is - * requesting fast re-authentication to be used. - */ - void * (*init_for_reauth)(struct eap_sm *sm, void *priv); - - /** - * get_identity - Get method specific identity for re-authentication - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Length of the returned identity - * Returns: Pointer to the method specific identity or %NULL if default - * identity is to be used - * - * This function is an optional handler that only EAP methods - * that use method specific identity need to implement. - */ - const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len); - - /** - * free - Free EAP method data - * @method: Pointer to the method data registered with - * eap_peer_method_register(). - * - * This function will be called when the EAP method is being - * unregistered. If the EAP method allocated resources during - * registration (e.g., allocated struct eap_method), they should be - * freed in this function. No other method functions will be called - * after this call. If this function is not defined (i.e., function - * pointer is %NULL), a default handler is used to release the method - * data with free(method). This is suitable for most cases. - */ - void (*free)(struct eap_method *method); - -#define EAP_PEER_METHOD_INTERFACE_VERSION 1 - /** - * version - Version of the EAP peer method interface - * - * The EAP peer method implementation should set this variable to - * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the - * EAP method is using supported API version when using dynamically - * loadable EAP methods. - */ - int version; - - /** - * next - Pointer to the next EAP method - * - * This variable is used internally in the EAP method registration code - * to create a linked list of registered EAP methods. - */ - struct eap_method *next; - -#ifdef CONFIG_DYNAMIC_EAP_METHODS - /** - * dl_handle - Handle for the dynamic library - * - * This variable is used internally in the EAP method registration code - * to store a handle for the dynamic library. If the method is linked - * in statically, this is %NULL. - */ - void *dl_handle; -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - - /** - * get_emsk - Get EAP method specific keying extended material (EMSK) - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Pointer to a variable to store EMSK length - * Returns: EMSK or %NULL if not available - * - * This function can be used to get the extended keying material from - * the EAP method. The key may already be stored in the method-specific - * private data or this function may derive the key. - */ - u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); - - /** - * getSessionId - Get EAP method specific Session-Id - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @priv: Pointer to private EAP method data from eap_method::init() - * @len: Pointer to a variable to store Session-Id length - * Returns: Session-Id or %NULL if not available - * - * This function can be used to get the Session-Id from the EAP method. - * The Session-Id may already be stored in the method-specific private - * data or this function may derive the Session-Id. - */ - u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len); -}; - - -struct eap_erp_key { - struct dl_list list; - size_t rRK_len; - size_t rIK_len; - u8 rRK[ERP_MAX_KEY_LEN]; - u8 rIK[ERP_MAX_KEY_LEN]; - u32 next_seq; - char keyname_nai[]; -}; - -/** - * struct eap_sm - EAP state machine data - */ -struct eap_sm { - enum { - EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED, - EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD, - EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS, - EAP_FAILURE - } EAP_state; - /* Long-term local variables */ - EapType selectedMethod; - EapMethodState methodState; - int lastId; - struct wpabuf *lastRespData; - EapDecision decision; - /* Short-term local variables */ - Boolean rxReq; - Boolean rxSuccess; - Boolean rxFailure; - int reqId; - EapType reqMethod; - int reqVendor; - u32 reqVendorMethod; - Boolean ignore; - /* Constants */ - int ClientTimeout; - - /* Miscellaneous variables */ - Boolean allowNotifications; /* peer state machine <-> methods */ - struct wpabuf *eapRespData; /* peer to lower layer */ - Boolean eapKeyAvailable; /* peer to lower layer */ - u8 *eapKeyData; /* peer to lower layer */ - size_t eapKeyDataLen; /* peer to lower layer */ - u8 *eapSessionId; /* peer to lower layer */ - size_t eapSessionIdLen; /* peer to lower layer */ - const struct eap_method *m; /* selected EAP method */ - /* not defined in RFC 4137 */ - Boolean changed; - void *eapol_ctx; - const struct eapol_callbacks *eapol_cb; - void *eap_method_priv; - int init_phase2; - int fast_reauth; - Boolean reauthInit; /* send EAP-Identity/Re-auth */ - u32 erp_seq; - - Boolean rxResp /* LEAP only */; - Boolean leap_done; - Boolean peap_done; - u8 req_sha1[20]; /* SHA1() of the current EAP packet */ - u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used - * in duplicate request detection. */ - - void *msg_ctx; - void *scard_ctx; - void *ssl_ctx; - void *ssl_ctx2; - - unsigned int workaround; - - /* Optional challenges generated in Phase 1 (EAP-FAST) */ - u8 *peer_challenge, *auth_challenge; - - int num_rounds; - int force_disabled; - - struct wps_context *wps; - - int prev_failure; - struct eap_peer_config *last_config; - - struct ext_password_data *ext_pw; - struct wpabuf *ext_pw_buf; - - int external_sim; - - unsigned int expected_failure:1; - - struct dl_list erp_keys; /* struct eap_erp_key */ -}; - -const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); -const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len); -const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash); -const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len); -const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len); -void eap_clear_config_otp(struct eap_sm *sm); -const char * eap_get_config_phase1(struct eap_sm *sm); -const char * eap_get_config_phase2(struct eap_sm *sm); -int eap_get_config_fragment_size(struct eap_sm *sm); -struct eap_peer_config * eap_get_config(struct eap_sm *sm); -void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob); -const struct wpa_config_blob * -eap_get_config_blob(struct eap_sm *sm, const char *name); -void eap_notify_pending(struct eap_sm *sm); -int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method); - -#endif /* EAP_I_H */ diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h deleted file mode 100644 index e35c919..0000000 --- a/src/eap_peer/eap_methods.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * EAP peer: Method registration - * Copyright (c) 2004-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_METHODS_H -#define EAP_METHODS_H - -#include "eap_common/eap_defs.h" - -const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method); -const struct eap_method * eap_peer_get_methods(size_t *count); - -struct eap_method * eap_peer_method_alloc(int version, int vendor, - EapType method, const char *name); -void eap_peer_method_free(struct eap_method *method); -int eap_peer_method_register(struct eap_method *method); - - -#ifdef IEEE8021X_EAPOL - -EapType eap_peer_get_type(const char *name, int *vendor); -const char * eap_get_name(int vendor, EapType type); -size_t eap_get_names(char *buf, size_t buflen); -char ** eap_get_names_as_string_array(size_t *num); -void eap_peer_unregister_methods(void); - -#else /* IEEE8021X_EAPOL */ - -static inline EapType eap_peer_get_type(const char *name, int *vendor) -{ - *vendor = EAP_VENDOR_IETF; - return EAP_TYPE_NONE; -} - -static inline const char * eap_get_name(int vendor, EapType type) -{ - return NULL; -} - -static inline size_t eap_get_names(char *buf, size_t buflen) -{ - return 0; -} - -static inline int eap_peer_register_methods(void) -{ - return 0; -} - -static inline void eap_peer_unregister_methods(void) -{ -} - -static inline char ** eap_get_names_as_string_array(size_t *num) -{ - return NULL; -} - -#endif /* IEEE8021X_EAPOL */ - - -#ifdef CONFIG_DYNAMIC_EAP_METHODS - -int eap_peer_method_load(const char *so); -int eap_peer_method_unload(struct eap_method *method); - -#else /* CONFIG_DYNAMIC_EAP_METHODS */ - -static inline int eap_peer_method_load(const char *so) -{ - return 0; -} - -static inline int eap_peer_method_unload(struct eap_method *method) -{ - return 0; -} - -#endif /* CONFIG_DYNAMIC_EAP_METHODS */ - -/* EAP peer method registration calls for statically linked in methods */ -int eap_peer_md5_register(void); -int eap_peer_tls_register(void); -int eap_peer_unauth_tls_register(void); -int eap_peer_wfa_unauth_tls_register(void); -int eap_peer_mschapv2_register(void); -int eap_peer_peap_register(void); -int eap_peer_ttls_register(void); -int eap_peer_gtc_register(void); -int eap_peer_otp_register(void); -int eap_peer_sim_register(void); -int eap_peer_leap_register(void); -int eap_peer_psk_register(void); -int eap_peer_aka_register(void); -int eap_peer_aka_prime_register(void); -int eap_peer_fast_register(void); -int eap_peer_pax_register(void); -int eap_peer_sake_register(void); -int eap_peer_gpsk_register(void); -int eap_peer_wsc_register(void); -int eap_peer_ikev2_register(void); -int eap_peer_vendor_test_register(void); -int eap_peer_tnc_register(void); -int eap_peer_pwd_register(void); -int eap_peer_eke_register(void); - -#endif /* EAP_METHODS_H */ diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c deleted file mode 100644 index af2b754..0000000 --- a/src/eap_peer/eap_tls_common.c +++ /dev/null @@ -1,1108 +0,0 @@ -/* - * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2013, Jouni Malinen - * - * 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/sha1.h" -#include "crypto/tls.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" - - -static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, - u8 code, u8 identifier) -{ - if (type == EAP_UNAUTH_TLS_TYPE) - return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, - code, identifier); - if (type == EAP_WFA_UNAUTH_TLS_TYPE) - return eap_msg_alloc(EAP_VENDOR_WFA_NEW, - EAP_VENDOR_WFA_UNAUTH_TLS, payload_len, - code, identifier); - return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, - identifier); -} - - -static int eap_tls_check_blob(struct eap_sm *sm, const char **name, - const u8 **data, size_t *data_len) -{ - const struct wpa_config_blob *blob; - - if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) - return 0; - - blob = eap_get_config_blob(sm, *name + 7); - if (blob == NULL) { - wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " - "found", __func__, *name + 7); - return -1; - } - - *name = NULL; - *data = blob->data; - *data_len = blob->len; - - return 0; -} - - -static void eap_tls_params_flags(struct tls_connection_params *params, - const char *txt) -{ - if (txt == NULL) - return; - if (os_strstr(txt, "tls_allow_md5=1")) - params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; - if (os_strstr(txt, "tls_disable_time_checks=1")) - params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; - if (os_strstr(txt, "tls_disable_session_ticket=1")) - params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; - if (os_strstr(txt, "tls_disable_session_ticket=0")) - params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET; - if (os_strstr(txt, "tls_disable_tlsv1_0=1")) - params->flags |= TLS_CONN_DISABLE_TLSv1_0; - if (os_strstr(txt, "tls_disable_tlsv1_0=0")) - params->flags &= ~TLS_CONN_DISABLE_TLSv1_0; - if (os_strstr(txt, "tls_disable_tlsv1_1=1")) - params->flags |= TLS_CONN_DISABLE_TLSv1_1; - if (os_strstr(txt, "tls_disable_tlsv1_1=0")) - params->flags &= ~TLS_CONN_DISABLE_TLSv1_1; - if (os_strstr(txt, "tls_disable_tlsv1_2=1")) - params->flags |= TLS_CONN_DISABLE_TLSv1_2; - if (os_strstr(txt, "tls_disable_tlsv1_2=0")) - params->flags &= ~TLS_CONN_DISABLE_TLSv1_2; -} - - -static void eap_tls_params_from_conf1(struct tls_connection_params *params, - struct eap_peer_config *config) -{ - params->ca_cert = (char *) config->ca_cert; - params->ca_path = (char *) config->ca_path; - params->client_cert = (char *) config->client_cert; - params->private_key = (char *) config->private_key; - params->private_key_passwd = (char *) config->private_key_passwd; - params->dh_file = (char *) config->dh_file; - params->subject_match = (char *) config->subject_match; - params->altsubject_match = (char *) config->altsubject_match; - params->suffix_match = config->domain_suffix_match; - params->domain_match = config->domain_match; - params->engine = config->engine; - params->engine_id = config->engine_id; - params->pin = config->pin; - params->key_id = config->key_id; - params->cert_id = config->cert_id; - params->ca_cert_id = config->ca_cert_id; - eap_tls_params_flags(params, config->phase1); -} - - -static void eap_tls_params_from_conf2(struct tls_connection_params *params, - struct eap_peer_config *config) -{ - params->ca_cert = (char *) config->ca_cert2; - params->ca_path = (char *) config->ca_path2; - params->client_cert = (char *) config->client_cert2; - params->private_key = (char *) config->private_key2; - params->private_key_passwd = (char *) config->private_key2_passwd; - params->dh_file = (char *) config->dh_file2; - params->subject_match = (char *) config->subject_match2; - params->altsubject_match = (char *) config->altsubject_match2; - params->suffix_match = config->domain_suffix_match2; - params->domain_match = config->domain_match2; - params->engine = config->engine2; - params->engine_id = config->engine2_id; - params->pin = config->pin2; - params->key_id = config->key2_id; - params->cert_id = config->cert2_id; - params->ca_cert_id = config->ca_cert2_id; - eap_tls_params_flags(params, config->phase2); -} - - -static int eap_tls_params_from_conf(struct eap_sm *sm, - struct eap_ssl_data *data, - struct tls_connection_params *params, - struct eap_peer_config *config, int phase2) -{ - os_memset(params, 0, sizeof(*params)); - if (sm->workaround && data->eap_type != EAP_TYPE_FAST) { - /* - * Some deployed authentication servers seem to be unable to - * handle the TLS Session Ticket extension (they are supposed - * to ignore unrecognized TLS extensions, but end up rejecting - * the ClientHello instead). As a workaround, disable use of - * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and - * EAP-TTLS (EAP-FAST uses session ticket, so any server that - * supports EAP-FAST does not need this workaround). - */ - params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; - } - if (phase2) { - wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); - eap_tls_params_from_conf2(params, config); - } else { - wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); - eap_tls_params_from_conf1(params, config); - if (data->eap_type == EAP_TYPE_FAST) - params->flags |= TLS_CONN_EAP_FAST; - } - - /* - * Use blob data, if available. Otherwise, leave reference to external - * file as-is. - */ - if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, - ¶ms->ca_cert_blob_len) || - eap_tls_check_blob(sm, ¶ms->client_cert, - ¶ms->client_cert_blob, - ¶ms->client_cert_blob_len) || - eap_tls_check_blob(sm, ¶ms->private_key, - ¶ms->private_key_blob, - ¶ms->private_key_blob_len) || - eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, - ¶ms->dh_blob_len)) { - wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); - return -1; - } - - params->openssl_ciphers = config->openssl_ciphers; - - return 0; -} - - -static int eap_tls_init_connection(struct eap_sm *sm, - struct eap_ssl_data *data, - struct eap_peer_config *config, - struct tls_connection_params *params) -{ - int res; - - if (config->ocsp) - params->flags |= TLS_CONN_REQUEST_OCSP; - if (config->ocsp == 2) - params->flags |= TLS_CONN_REQUIRE_OCSP; - data->conn = tls_connection_init(data->ssl_ctx); - if (data->conn == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " - "connection"); - return -1; - } - - res = tls_connection_set_params(data->ssl_ctx, data->conn, params); - if (res == TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN) { - /* - * At this point with the pkcs11 engine the PIN is wrong. We - * reset the PIN in the configuration to be sure to not use it - * again and the calling function must request a new one. - */ - wpa_printf(MSG_INFO, - "TLS: Bad PIN provided, requesting a new one"); - os_free(config->pin); - config->pin = NULL; - eap_sm_request_pin(sm); - sm->ignore = TRUE; - } else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { - wpa_printf(MSG_INFO, "TLS: Failed to initialize engine"); - } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { - wpa_printf(MSG_INFO, "TLS: Failed to load private key"); - sm->ignore = TRUE; - } - if (res) { - wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " - "parameters"); - tls_connection_deinit(data->ssl_ctx, data->conn); - data->conn = NULL; - return -1; - } - - return 0; -} - - -/** - * eap_peer_tls_ssl_init - Initialize shared TLS functionality - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @config: Pointer to the network configuration - * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) - * Returns: 0 on success, -1 on failure - * - * This function is used to initialize shared TLS functionality for EAP-TLS, - * EAP-PEAP, EAP-TTLS, and EAP-FAST. - */ -int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, - struct eap_peer_config *config, u8 eap_type) -{ - struct tls_connection_params params; - - if (config == NULL) - return -1; - - data->eap = sm; - data->eap_type = eap_type; - data->phase2 = sm->init_phase2; - data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : - sm->ssl_ctx; - if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < - 0) - return -1; - - if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) - return -1; - - data->tls_out_limit = config->fragment_size; - if (data->phase2) { - /* Limit the fragment size in the inner TLS authentication - * since the outer authentication with EAP-PEAP does not yet - * support fragmentation */ - if (data->tls_out_limit > 100) - data->tls_out_limit -= 100; - } - - if (config->phase1 && - os_strstr(config->phase1, "include_tls_length=1")) { - wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " - "unfragmented packets"); - data->include_tls_length = 1; - } - - return 0; -} - - -/** - * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * - * This function deinitializes shared TLS functionality that was initialized - * with eap_peer_tls_ssl_init(). - */ -void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) -{ - tls_connection_deinit(data->ssl_ctx, data->conn); - eap_peer_tls_reset_input(data); - eap_peer_tls_reset_output(data); -} - - -/** - * eap_peer_tls_derive_key - Derive a key based on TLS session data - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @label: Label string for deriving the keys, e.g., "client EAP encryption" - * @len: Length of the key material to generate (usually 64 for MSK) - * Returns: Pointer to allocated key on success or %NULL on failure - * - * This function uses TLS-PRF to generate pseudo-random data based on the TLS - * session data (client/server random and master key). Each key type may use a - * different label to bind the key usage into the generated material. - * - * The caller is responsible for freeing the returned buffer. - */ -u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len) -{ - u8 *out; - - out = os_malloc(len); - if (out == NULL) - return NULL; - - if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0, - out, len)) { - os_free(out); - return NULL; - } - - return out; -} - - -/** - * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) - * @len: Pointer to length of the session ID generated - * Returns: Pointer to allocated Session-Id on success or %NULL on failure - * - * This function derive the Session-Id based on the TLS session data - * (client/server random and method type). - * - * The caller is responsible for freeing the returned buffer. - */ -u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, - struct eap_ssl_data *data, u8 eap_type, - size_t *len) -{ - struct tls_random keys; - u8 *out; - - if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys)) - return NULL; - - if (keys.client_random == NULL || keys.server_random == NULL) - return NULL; - - *len = 1 + keys.client_random_len + keys.server_random_len; - out = os_malloc(*len); - if (out == NULL) - return NULL; - - /* Session-Id = EAP type || client.random || server.random */ - out[0] = eap_type; - os_memcpy(out + 1, keys.client_random, keys.client_random_len); - os_memcpy(out + 1 + keys.client_random_len, keys.server_random, - keys.server_random_len); - - return out; -} - - -/** - * eap_peer_tls_reassemble_fragment - Reassemble a received fragment - * @data: Data for TLS processing - * @in_data: Next incoming TLS segment - * Returns: 0 on success, 1 if more data is needed for the full message, or - * -1 on error - */ -static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, - const struct wpabuf *in_data) -{ - size_t tls_in_len, in_len; - - tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; - in_len = in_data ? wpabuf_len(in_data) : 0; - - if (tls_in_len + in_len == 0) { - /* No message data received?! */ - wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " - "tls_in_left=%lu tls_in_len=%lu in_len=%lu", - (unsigned long) data->tls_in_left, - (unsigned long) tls_in_len, - (unsigned long) in_len); - eap_peer_tls_reset_input(data); - return -1; - } - - if (tls_in_len + in_len > 65536) { - /* - * Limit length to avoid rogue servers from causing large - * memory allocations. - */ - wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " - "64 kB)"); - eap_peer_tls_reset_input(data); - return -1; - } - - if (in_len > data->tls_in_left) { - /* Sender is doing something odd - reject message */ - wpa_printf(MSG_INFO, "SSL: more data than TLS message length " - "indicated"); - eap_peer_tls_reset_input(data); - return -1; - } - - if (wpabuf_resize(&data->tls_in, in_len) < 0) { - wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " - "data"); - eap_peer_tls_reset_input(data); - return -1; - } - if (in_data) - wpabuf_put_buf(data->tls_in, in_data); - data->tls_in_left -= in_len; - - if (data->tls_in_left > 0) { - wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " - "data", (unsigned long) data->tls_in_left); - return 1; - } - - return 0; -} - - -/** - * eap_peer_tls_data_reassemble - Reassemble TLS data - * @data: Data for TLS processing - * @in_data: Next incoming TLS segment - * @need_more_input: Variable for returning whether more input data is needed - * to reassemble this TLS packet - * Returns: Pointer to output data, %NULL on error or when more data is needed - * for the full message (in which case, *need_more_input is also set to 1). - * - * This function reassembles TLS fragments. Caller must not free the returned - * data buffer since an internal pointer to it is maintained. - */ -static const struct wpabuf * eap_peer_tls_data_reassemble( - struct eap_ssl_data *data, const struct wpabuf *in_data, - int *need_more_input) -{ - *need_more_input = 0; - - if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { - /* Message has fragments */ - int res = eap_peer_tls_reassemble_fragment(data, in_data); - if (res) { - if (res == 1) - *need_more_input = 1; - return NULL; - } - - /* Message is now fully reassembled. */ - } else { - /* No fragments in this message, so just make a copy of it. */ - data->tls_in_left = 0; - data->tls_in = wpabuf_dup(in_data); - if (data->tls_in == NULL) - return NULL; - } - - return data->tls_in; -} - - -/** - * eap_tls_process_input - Process incoming TLS message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @in_data: Message received from the server - * @out_data: Buffer for returning a pointer to application data (if available) - * Returns: 0 on success, 1 if more input data is needed, 2 if application data - * is available, -1 on failure - */ -static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - const struct wpabuf *msg; - int need_more_input; - struct wpabuf *appl_data; - - msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); - if (msg == NULL) - return need_more_input ? 1 : -1; - - /* Full TLS message reassembled - continue handshake processing */ - if (data->tls_out) { - /* This should not happen.. */ - wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " - "tls_out data even though tls_out_len = 0"); - wpabuf_free(data->tls_out); - WPA_ASSERT(data->tls_out == NULL); - } - appl_data = NULL; - data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn, - msg, &appl_data); - - eap_peer_tls_reset_input(data); - - if (appl_data && - tls_connection_established(data->ssl_ctx, data->conn) && - !tls_connection_get_failed(data->ssl_ctx, data->conn)) { - wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", - appl_data); - *out_data = appl_data; - return 2; - } - - wpabuf_free(appl_data); - - return 0; -} - - -/** - * eap_tls_process_output - Process outgoing TLS message - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * @id: EAP identifier for the response - * @ret: Return value to use on success - * @out_data: Buffer for returning the allocated output buffer - * Returns: ret (0 or 1) on success, -1 on failure - */ -static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, - int peap_version, u8 id, int ret, - struct wpabuf **out_data) -{ - size_t len; - u8 *flags; - int more_fragments, length_included; - - if (data->tls_out == NULL) - return -1; - len = wpabuf_len(data->tls_out) - data->tls_out_pos; - wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " - "%lu bytes)", - (unsigned long) len, - (unsigned long) wpabuf_len(data->tls_out)); - - /* - * Limit outgoing message to the configured maximum size. Fragment - * message if needed. - */ - if (len > data->tls_out_limit) { - more_fragments = 1; - len = data->tls_out_limit; - wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " - "will follow", (unsigned long) len); - } else - more_fragments = 0; - - length_included = data->tls_out_pos == 0 && - (wpabuf_len(data->tls_out) > data->tls_out_limit || - data->include_tls_length); - if (!length_included && - eap_type == EAP_TYPE_PEAP && peap_version == 0 && - !tls_connection_established(data->eap->ssl_ctx, data->conn)) { - /* - * Windows Server 2008 NPS really wants to have the TLS Message - * length included in phase 0 even for unfragmented frames or - * it will get very confused with Compound MAC calculation and - * Outer TLVs. - */ - length_included = 1; - } - - *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len, - EAP_CODE_RESPONSE, id); - if (*out_data == NULL) - return -1; - - flags = wpabuf_put(*out_data, 1); - *flags = peap_version; - if (more_fragments) - *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; - if (length_included) { - *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; - wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); - } - - wpabuf_put_data(*out_data, - wpabuf_head_u8(data->tls_out) + data->tls_out_pos, - len); - data->tls_out_pos += len; - - if (!more_fragments) - eap_peer_tls_reset_output(data); - - return ret; -} - - -/** - * eap_peer_tls_process_helper - Process TLS handshake message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * @id: EAP identifier for the response - * @in_data: Message received from the server - * @out_data: Buffer for returning a pointer to the response message - * Returns: 0 on success, 1 if more input data is needed, 2 if application data - * is available, or -1 on failure - * - * This function can be used to process TLS handshake messages. It reassembles - * the received fragments and uses a TLS library to process the messages. The - * response data from the TLS library is fragmented to suitable output messages - * that the caller can send out. - * - * out_data is used to return the response message if the return value of this - * function is 0, 2, or -1. In case of failure, the message is likely a TLS - * alarm message. The caller is responsible for freeing the allocated buffer if - * *out_data is not %NULL. - * - * This function is called for each received TLS message during the TLS - * handshake after eap_peer_tls_process_init() call and possible processing of - * TLS Flags field. Once the handshake has been completed, i.e., when - * tls_connection_established() returns 1, EAP method specific decrypting of - * the tunneled data is used. - */ -int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, - u8 id, const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - int ret = 0; - - *out_data = NULL; - - if (data->tls_out && wpabuf_len(data->tls_out) > 0 && - wpabuf_len(in_data) > 0) { - wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " - "fragments are waiting to be sent out"); - return -1; - } - - if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { - /* - * No more data to send out - expect to receive more data from - * the AS. - */ - int res = eap_tls_process_input(sm, data, in_data, out_data); - if (res) { - /* - * Input processing failed (res = -1) or more data is - * needed (res = 1). - */ - return res; - } - - /* - * The incoming message has been reassembled and processed. The - * response was allocated into data->tls_out buffer. - */ - } - - if (data->tls_out == NULL) { - /* - * No outgoing fragments remaining from the previous message - * and no new message generated. This indicates an error in TLS - * processing. - */ - eap_peer_tls_reset_output(data); - return -1; - } - - if (tls_connection_get_failed(data->ssl_ctx, data->conn)) { - /* TLS processing has failed - return error */ - wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " - "report error (len=%u)", - (unsigned int) wpabuf_len(data->tls_out)); - ret = -1; - /* TODO: clean pin if engine used? */ - if (wpabuf_len(data->tls_out) == 0) { - wpabuf_free(data->tls_out); - data->tls_out = NULL; - return -1; - } - } - - if (wpabuf_len(data->tls_out) == 0) { - /* - * TLS negotiation should now be complete since all other cases - * needing more data should have been caught above based on - * the TLS Message Length field. - */ - wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); - wpabuf_free(data->tls_out); - data->tls_out = NULL; - return 1; - } - - /* Send the pending message (in fragments, if needed). */ - return eap_tls_process_output(data, eap_type, peap_version, id, ret, - out_data); -} - - -/** - * eap_peer_tls_build_ack - Build a TLS ACK frame - * @id: EAP identifier for the response - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * Returns: Pointer to the allocated ACK frame or %NULL on failure - */ -struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, - int peap_version) -{ - struct wpabuf *resp; - - resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id); - if (resp == NULL) - return NULL; - wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", - (int) eap_type, id, peap_version); - wpabuf_put_u8(resp, peap_version); /* Flags */ - return resp; -} - - -/** - * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * Returns: 0 on success, -1 on failure - */ -int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) -{ - eap_peer_tls_reset_input(data); - eap_peer_tls_reset_output(data); - return tls_connection_shutdown(data->ssl_ctx, data->conn); -} - - -/** - * eap_peer_tls_status - Get TLS status - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @buf: Buffer for status information - * @buflen: Maximum buffer length - * @verbose: Whether to include verbose status information - * Returns: Number of bytes written to buf. - */ -int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, - char *buf, size_t buflen, int verbose) -{ - char version[20], name[128]; - int len = 0, ret; - - if (tls_get_version(data->ssl_ctx, data->conn, version, - sizeof(version)) < 0) - version[0] = '\0'; - if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) < 0) - name[0] = '\0'; - - ret = os_snprintf(buf + len, buflen - len, - "eap_tls_version=%s\n" - "EAP TLS cipher=%s\n" - "tls_session_reused=%d\n", - version, name, - tls_connection_resumed(data->ssl_ctx, data->conn)); - if (os_snprintf_error(buflen - len, ret)) - return len; - len += ret; - - return len; -} - - -/** - * eap_peer_tls_process_init - Initial validation/processing of EAP requests - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @ret: Return values from EAP request validation and processing - * @reqData: EAP request to be processed (eapReqData) - * @len: Buffer for returning length of the remaining payload - * @flags: Buffer for returning TLS flags - * Returns: Pointer to payload after TLS flags and length or %NULL on failure - * - * This function validates the EAP header and processes the optional TLS - * Message Length field. If this is the first fragment of a TLS message, the - * TLS reassembly code is initialized to receive the indicated number of bytes. - * - * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this - * function as the first step in processing received messages. They will need - * to process the flags (apart from Message Length Included) that are returned - * through the flags pointer and the message payload that will be returned (and - * the length is returned through the len pointer). Return values (ret) are set - * for continuation of EAP method processing. The caller is responsible for - * setting these to indicate completion (either success or failure) based on - * the authentication result. - */ -const u8 * eap_peer_tls_process_init(struct eap_sm *sm, - struct eap_ssl_data *data, - EapType eap_type, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - size_t *len, u8 *flags) -{ - const u8 *pos; - size_t left; - unsigned int tls_msg_len; - - if (tls_get_errors(data->ssl_ctx)) { - wpa_printf(MSG_INFO, "SSL: TLS errors detected"); - ret->ignore = TRUE; - return NULL; - } - - if (eap_type == EAP_UNAUTH_TLS_TYPE) - pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, - EAP_VENDOR_TYPE_UNAUTH_TLS, reqData, - &left); - else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE) - pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW, - EAP_VENDOR_WFA_UNAUTH_TLS, reqData, - &left); - else - pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, - &left); - if (pos == NULL) { - ret->ignore = TRUE; - return NULL; - } - if (left == 0) { - wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags " - "octet included"); - if (!sm->workaround) { - ret->ignore = TRUE; - return NULL; - } - - wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags " - "indicates ACK frame"); - *flags = 0; - } else { - *flags = *pos++; - left--; - } - wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " - "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), - *flags); - if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { - if (left < 4) { - wpa_printf(MSG_INFO, "SSL: Short frame with TLS " - "length"); - ret->ignore = TRUE; - return NULL; - } - tls_msg_len = WPA_GET_BE32(pos); - wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", - tls_msg_len); - if (data->tls_in_left == 0) { - data->tls_in_total = tls_msg_len; - data->tls_in_left = tls_msg_len; - wpabuf_free(data->tls_in); - data->tls_in = NULL; - } - pos += 4; - left -= 4; - - if (left > tls_msg_len) { - wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " - "bytes) smaller than this fragment (%d " - "bytes)", (int) tls_msg_len, (int) left); - ret->ignore = TRUE; - return NULL; - } - } - - ret->ignore = FALSE; - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_FAIL; - ret->allowNotifications = TRUE; - - *len = left; - return pos; -} - - -/** - * eap_peer_tls_reset_input - Reset input buffers - * @data: Data for TLS processing - * - * This function frees any allocated memory for input buffers and resets input - * state. - */ -void eap_peer_tls_reset_input(struct eap_ssl_data *data) -{ - data->tls_in_left = data->tls_in_total = 0; - wpabuf_free(data->tls_in); - data->tls_in = NULL; -} - - -/** - * eap_peer_tls_reset_output - Reset output buffers - * @data: Data for TLS processing - * - * This function frees any allocated memory for output buffers and resets - * output state. - */ -void eap_peer_tls_reset_output(struct eap_ssl_data *data) -{ - data->tls_out_pos = 0; - wpabuf_free(data->tls_out); - data->tls_out = NULL; -} - - -/** - * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @in_data: Message received from the server - * @in_decrypted: Buffer for returning a pointer to the decrypted message - * Returns: 0 on success, 1 if more input data is needed, or -1 on failure - */ -int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const struct wpabuf *in_data, - struct wpabuf **in_decrypted) -{ - const struct wpabuf *msg; - int need_more_input; - - msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); - if (msg == NULL) - return need_more_input ? 1 : -1; - - *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg); - eap_peer_tls_reset_input(data); - if (*in_decrypted == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); - return -1; - } - return 0; -} - - -/** - * eap_peer_tls_encrypt - Encrypt phase 2 TLS message - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @data: Data for TLS processing - * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) - * @peap_version: Version number for EAP-PEAP/TTLS - * @id: EAP identifier for the response - * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments - * @out_data: Buffer for returning a pointer to the encrypted response message - * Returns: 0 on success, -1 on failure - */ -int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, u8 id, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - if (in_data) { - eap_peer_tls_reset_output(data); - data->tls_out = tls_connection_encrypt(data->ssl_ctx, - data->conn, in_data); - if (data->tls_out == NULL) { - wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " - "data (in_len=%lu)", - (unsigned long) wpabuf_len(in_data)); - eap_peer_tls_reset_output(data); - return -1; - } - } - - return eap_tls_process_output(data, eap_type, peap_version, id, 0, - out_data); -} - - -/** - * eap_peer_select_phase2_methods - Select phase 2 EAP method - * @config: Pointer to the network configuration - * @prefix: 'phase2' configuration prefix, e.g., "auth=" - * @types: Buffer for returning allocated list of allowed EAP methods - * @num_types: Buffer for returning number of allocated EAP methods - * Returns: 0 on success, -1 on failure - * - * This function is used to parse EAP method list and select allowed methods - * for Phase2 authentication. - */ -int eap_peer_select_phase2_methods(struct eap_peer_config *config, - const char *prefix, - struct eap_method_type **types, - size_t *num_types) -{ - char *start, *pos, *buf; - struct eap_method_type *methods = NULL, *_methods; - u32 method; - size_t num_methods = 0, prefix_len; - - if (config == NULL || config->phase2 == NULL) - goto get_defaults; - - start = buf = os_strdup(config->phase2); - if (buf == NULL) - return -1; - - prefix_len = os_strlen(prefix); - - while (start && *start != '\0') { - int vendor; - pos = os_strstr(start, prefix); - if (pos == NULL) - break; - if (start != pos && *(pos - 1) != ' ') { - start = pos + prefix_len; - continue; - } - - start = pos + prefix_len; - pos = os_strchr(start, ' '); - if (pos) - *pos++ = '\0'; - method = eap_get_phase2_type(start, &vendor); - if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { - wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " - "method '%s'", start); - } else { - num_methods++; - _methods = os_realloc_array(methods, num_methods, - sizeof(*methods)); - if (_methods == NULL) { - os_free(methods); - os_free(buf); - return -1; - } - methods = _methods; - methods[num_methods - 1].vendor = vendor; - methods[num_methods - 1].method = method; - } - - start = pos; - } - - os_free(buf); - -get_defaults: - if (methods == NULL) - methods = eap_get_phase2_types(config, &num_methods); - - if (methods == NULL) { - wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); - return -1; - } - wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", - (u8 *) methods, - num_methods * sizeof(struct eap_method_type)); - - *types = methods; - *num_types = num_methods; - - return 0; -} - - -/** - * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 - * @types: Buffer for returning allocated list of allowed EAP methods - * @num_types: Buffer for returning number of allocated EAP methods - * @hdr: EAP-Request header (and the following EAP type octet) - * @resp: Buffer for returning the EAP-Nak message - * Returns: 0 on success, -1 on failure - */ -int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, - struct eap_hdr *hdr, struct wpabuf **resp) -{ - u8 *pos = (u8 *) (hdr + 1); - size_t i; - - /* TODO: add support for expanded Nak */ - wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); - wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", - (u8 *) types, num_types * sizeof(struct eap_method_type)); - *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, - EAP_CODE_RESPONSE, hdr->identifier); - if (*resp == NULL) - return -1; - - for (i = 0; i < num_types; i++) { - if (types[i].vendor == EAP_VENDOR_IETF && - types[i].method < 256) - wpabuf_put_u8(*resp, types[i].method); - } - - eap_update_len(*resp); - - return 0; -} diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h deleted file mode 100644 index acd2b78..0000000 --- a/src/eap_peer/eap_tls_common.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2009, 2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EAP_TLS_COMMON_H -#define EAP_TLS_COMMON_H - -/** - * struct eap_ssl_data - TLS data for EAP methods - */ -struct eap_ssl_data { - /** - * conn - TLS connection context data from tls_connection_init() - */ - struct tls_connection *conn; - - /** - * tls_out - TLS message to be sent out in fragments - */ - struct wpabuf *tls_out; - - /** - * tls_out_pos - The current position in the outgoing TLS message - */ - size_t tls_out_pos; - - /** - * tls_out_limit - Maximum fragment size for outgoing TLS messages - */ - size_t tls_out_limit; - - /** - * tls_in - Received TLS message buffer for re-assembly - */ - struct wpabuf *tls_in; - - /** - * tls_in_left - Number of remaining bytes in the incoming TLS message - */ - size_t tls_in_left; - - /** - * tls_in_total - Total number of bytes in the incoming TLS message - */ - size_t tls_in_total; - - /** - * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) - */ - int phase2; - - /** - * include_tls_length - Whether the TLS length field is included even - * if the TLS data is not fragmented - */ - int include_tls_length; - - /** - * eap - EAP state machine allocated with eap_peer_sm_init() - */ - struct eap_sm *eap; - - /** - * ssl_ctx - TLS library context to use for the connection - */ - void *ssl_ctx; - - /** - * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) - */ - u8 eap_type; -}; - - -/* EAP TLS Flags */ -#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 -#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 -#define EAP_TLS_FLAGS_START 0x20 -#define EAP_TLS_VERSION_MASK 0x07 - - /* could be up to 128 bytes, but only the first 64 bytes are used */ -#define EAP_TLS_KEY_LEN 64 - -/* dummy type used as a flag for UNAUTH-TLS */ -#define EAP_UNAUTH_TLS_TYPE 255 -#define EAP_WFA_UNAUTH_TLS_TYPE 254 - - -int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, - struct eap_peer_config *config, u8 eap_type); -void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); -u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, - const char *label, size_t len); -u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, - struct eap_ssl_data *data, u8 eap_type, - size_t *len); -int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, - u8 id, const struct wpabuf *in_data, - struct wpabuf **out_data); -struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, - int peap_version); -int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data); -int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, - char *buf, size_t buflen, int verbose); -const u8 * eap_peer_tls_process_init(struct eap_sm *sm, - struct eap_ssl_data *data, - EapType eap_type, - struct eap_method_ret *ret, - const struct wpabuf *reqData, - size_t *len, u8 *flags); -void eap_peer_tls_reset_input(struct eap_ssl_data *data); -void eap_peer_tls_reset_output(struct eap_ssl_data *data); -int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const struct wpabuf *in_data, - struct wpabuf **in_decrypted); -int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - EapType eap_type, int peap_version, u8 id, - const struct wpabuf *in_data, - struct wpabuf **out_data); -int eap_peer_select_phase2_methods(struct eap_peer_config *config, - const char *prefix, - struct eap_method_type **types, - size_t *num_types); -int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, - struct eap_hdr *hdr, struct wpabuf **resp); - -#endif /* EAP_TLS_COMMON_H */ diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c deleted file mode 100644 index b186c91..0000000 --- a/src/eap_peer/eap_ttls.c +++ /dev/null @@ -1,1721 +0,0 @@ -/* - * EAP peer method: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2011, Jouni Malinen - * - * 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/ms_funcs.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_common/chap.h" -#include "eap_common/eap_ttls.h" -#include "mschapv2.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" - - -#define EAP_TTLS_VERSION 0 - - -static void eap_ttls_deinit(struct eap_sm *sm, void *priv); - - -struct eap_ttls_data { - struct eap_ssl_data ssl; - - int ttls_version; - - const struct eap_method *phase2_method; - void *phase2_priv; - int phase2_success; - int phase2_start; - - enum phase2_types { - EAP_TTLS_PHASE2_EAP, - EAP_TTLS_PHASE2_MSCHAPV2, - EAP_TTLS_PHASE2_MSCHAP, - EAP_TTLS_PHASE2_PAP, - EAP_TTLS_PHASE2_CHAP - } phase2_type; - struct eap_method_type phase2_eap_type; - struct eap_method_type *phase2_eap_types; - size_t num_phase2_eap_types; - - u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; - int auth_response_valid; - u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ - u8 ident; - int resuming; /* starting a resumed session */ - int reauth; /* reauthentication */ - u8 *key_data; - u8 *session_id; - size_t id_len; - - struct wpabuf *pending_phase2_req; - -#ifdef EAP_TNC - int ready_for_tnc; - int tnc_started; -#endif /* EAP_TNC */ -}; - - -static void * eap_ttls_init(struct eap_sm *sm) -{ - struct eap_ttls_data *data; - struct eap_peer_config *config = eap_get_config(sm); - char *selected; - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - data->ttls_version = EAP_TTLS_VERSION; - selected = "EAP"; - data->phase2_type = EAP_TTLS_PHASE2_EAP; - - if (config && config->phase2) { - if (os_strstr(config->phase2, "autheap=")) { - selected = "EAP"; - data->phase2_type = EAP_TTLS_PHASE2_EAP; - } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { - selected = "MSCHAPV2"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; - } else if (os_strstr(config->phase2, "auth=MSCHAP")) { - selected = "MSCHAP"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; - } else if (os_strstr(config->phase2, "auth=PAP")) { - selected = "PAP"; - data->phase2_type = EAP_TTLS_PHASE2_PAP; - } else if (os_strstr(config->phase2, "auth=CHAP")) { - selected = "CHAP"; - data->phase2_type = EAP_TTLS_PHASE2_CHAP; - } - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); - - if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { - if (eap_peer_select_phase2_methods(config, "autheap=", - &data->phase2_eap_types, - &data->num_phase2_eap_types) - < 0) { - eap_ttls_deinit(sm, data); - return NULL; - } - - data->phase2_eap_type.vendor = EAP_VENDOR_IETF; - data->phase2_eap_type.method = EAP_TYPE_NONE; - } - - if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); - eap_ttls_deinit(sm, data); - return NULL; - } - - return data; -} - - -static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - if (data->phase2_priv && data->phase2_method) { - data->phase2_method->deinit(sm, data->phase2_priv); - data->phase2_method = NULL; - data->phase2_priv = NULL; - } -} - - -static void eap_ttls_free_key(struct eap_ttls_data *data) -{ - if (data->key_data) { - bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); - data->key_data = NULL; - } -} - - -static void eap_ttls_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - if (data == NULL) - return; - eap_ttls_phase2_eap_deinit(sm, data); - os_free(data->phase2_eap_types); - eap_peer_tls_ssl_deinit(sm, &data->ssl); - eap_ttls_free_key(data); - os_free(data->session_id); - wpabuf_free(data->pending_phase2_req); - os_free(data); -} - - -static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, - int mandatory, size_t len) -{ - struct ttls_avp_vendor *avp; - u8 flags; - size_t hdrlen; - - avp = (struct ttls_avp_vendor *) avphdr; - flags = mandatory ? AVP_FLAGS_MANDATORY : 0; - if (vendor_id) { - flags |= AVP_FLAGS_VENDOR; - hdrlen = sizeof(*avp); - avp->vendor_id = host_to_be32(vendor_id); - } else { - hdrlen = sizeof(struct ttls_avp); - } - - avp->avp_code = host_to_be32(avp_code); - avp->avp_length = host_to_be32(((u32) flags << 24) | - (u32) (hdrlen + len)); - - return avphdr + hdrlen; -} - - -static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, - u32 vendor_id, int mandatory, - const u8 *data, size_t len) -{ - u8 *pos; - pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); - os_memcpy(pos, data, len); - pos += len; - AVP_PAD(start, pos); - return pos; -} - - -static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, - int mandatory) -{ - struct wpabuf *msg; - u8 *avp, *pos; - - msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); - if (msg == NULL) { - wpabuf_free(*resp); - *resp = NULL; - return -1; - } - - avp = wpabuf_mhead(msg); - pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); - os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); - pos += wpabuf_len(*resp); - AVP_PAD(avp, pos); - wpabuf_free(*resp); - wpabuf_put(msg, pos - avp); - *resp = msg; - return 0; -} - - -static int eap_ttls_v0_derive_key(struct eap_sm *sm, - struct eap_ttls_data *data) -{ - eap_ttls_free_key(data); - data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, - "ttls keying material", - EAP_TLS_KEY_LEN + - EAP_EMSK_LEN); - if (!data->key_data) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); - return -1; - } - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", - data->key_data, EAP_TLS_KEY_LEN); - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK", - data->key_data + EAP_TLS_KEY_LEN, - EAP_EMSK_LEN); - - os_free(data->session_id); - data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, - EAP_TYPE_TTLS, - &data->id_len); - if (data->session_id) { - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", - data->session_id, data->id_len); - } else { - wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); - } - - return 0; -} - - -#ifndef CONFIG_FIPS -static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, - struct eap_ttls_data *data, size_t len) -{ - return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); -} -#endif /* CONFIG_FIPS */ - - -static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, - u8 method) -{ - size_t i; - for (i = 0; i < data->num_phase2_eap_types; i++) { - if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || - data->phase2_eap_types[i].method != method) - continue; - - data->phase2_eap_type.vendor = - data->phase2_eap_types[i].vendor; - data->phase2_eap_type.method = - data->phase2_eap_types[i].method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - break; - } -} - - -static int eap_ttls_phase2_eap_process(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - struct wpabuf **resp) -{ - struct wpabuf msg; - struct eap_method_ret iret; - - os_memset(&iret, 0, sizeof(iret)); - wpabuf_set(&msg, hdr, len); - *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, - &msg); - if ((iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) && - (iret.decision == DECISION_UNCOND_SUCC || - iret.decision == DECISION_COND_SUCC || - iret.decision == DECISION_FAIL)) { - ret->methodState = iret.methodState; - ret->decision = iret.decision; - } - - return 0; -} - - -static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - u8 method, struct wpabuf **resp) -{ -#ifdef EAP_TNC - if (data->tnc_started && data->phase2_method && - data->phase2_priv && method == EAP_TYPE_TNC && - data->phase2_eap_type.method == EAP_TYPE_TNC) - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, - resp); - - if (data->ready_for_tnc && !data->tnc_started && - method == EAP_TYPE_TNC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " - "EAP method"); - data->tnc_started = 1; - } - - if (data->tnc_started) { - if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || - data->phase2_eap_type.method == EAP_TYPE_TNC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " - "type %d for TNC", method); - return -1; - } - - data->phase2_eap_type.vendor = EAP_VENDOR_IETF; - data->phase2_eap_type.method = method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d (TNC)", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - - if (data->phase2_type == EAP_TTLS_PHASE2_EAP) - eap_ttls_phase2_eap_deinit(sm, data); - } -#endif /* EAP_TNC */ - - if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && - data->phase2_eap_type.method == EAP_TYPE_NONE) - eap_ttls_phase2_select_eap_method(data, method); - - if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) - { - if (eap_peer_tls_phase2_nak(data->phase2_eap_types, - data->num_phase2_eap_types, - hdr, resp)) - return -1; - return 0; - } - - if (data->phase2_priv == NULL) { - data->phase2_method = eap_peer_get_eap_method( - EAP_VENDOR_IETF, method); - if (data->phase2_method) { - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - } - } - if (data->phase2_priv == NULL || data->phase2_method == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " - "Phase 2 EAP method %d", method); - return -1; - } - - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); -} - - -static int eap_ttls_phase2_request_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, - struct wpabuf **resp) -{ - size_t len = be_to_host16(hdr->length); - u8 *pos; - struct eap_peer_config *config = eap_get_config(sm); - - if (len <= sizeof(struct eap_hdr)) { - wpa_printf(MSG_INFO, "EAP-TTLS: too short " - "Phase 2 request (len=%lu)", (unsigned long) len); - return -1; - } - pos = (u8 *) (hdr + 1); - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); - switch (*pos) { - case EAP_TYPE_IDENTITY: - *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); - break; - default: - if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, - *pos, resp) < 0) - return -1; - break; - } - - if (*resp == NULL && - (config->pending_req_identity || config->pending_req_password || - config->pending_req_otp)) { - return 0; - } - - if (*resp == NULL) - return -1; - - wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", - *resp); - return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); -} - - -static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ -#ifdef CONFIG_FIPS - wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build"); - return -1; -#else /* CONFIG_FIPS */ -#ifdef EAP_MSCHAPv2 - struct wpabuf *msg; - u8 *buf, *pos, *challenge, *peer_challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* MS-CHAP-Challenge */ - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " - "implicit challenge"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); - - /* MS-CHAP2-Response */ - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - EAP_TTLS_MSCHAPV2_RESPONSE_LEN); - data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; - *pos++ = data->ident; - *pos++ = 0; /* Flags */ - if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { - os_free(challenge); - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " - "random data for peer challenge"); - return -1; - } - peer_challenge = pos; - pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; - os_memset(pos, 0, 8); /* Reserved, must be zero */ - pos += 8; - if (mschapv2_derive_response(identity, identity_len, password, - password_len, pwhash, challenge, - peer_challenge, pos, data->auth_response, - data->master_key)) { - os_free(challenge); - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " - "response"); - return -1; - } - data->auth_response_valid = 1; - - pos += 24; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - return 0; -#else /* EAP_MSCHAPv2 */ - wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); - return -1; -#endif /* EAP_MSCHAPv2 */ -#endif /* CONFIG_FIPS */ -} - - -static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ -#ifdef CONFIG_FIPS - wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build"); - return -1; -#else /* CONFIG_FIPS */ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/MSCHAP: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* MS-CHAP-Challenge */ - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " - "implicit challenge"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); - - /* MS-CHAP-Response */ - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - EAP_TTLS_MSCHAP_RESPONSE_LEN); - data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - *pos++ = 1; /* Flags: Use NT style passwords */ - os_memset(pos, 0, 24); /* LM-Response */ - pos += 24; - if (pwhash) { - challenge_response(challenge, password, pos); /* NT-Response */ - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", - password, 16); - } else { - nt_challenge_response(challenge, password, password_len, - pos); /* NT-Response */ - wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", - password, password_len); - } - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", - challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); - pos += 24; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - /* EAP-TTLS/MSCHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -#endif /* CONFIG_FIPS */ -} - - -static int eap_ttls_phase2_request_pap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos; - size_t pad; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + password_len + 100); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/PAP: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts - * the data, so no separate encryption is used in the AVP itself. - * However, the password is padded to obfuscate its length. */ - pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, - password_len + pad); - os_memcpy(pos, password, password_len); - pos += password_len; - os_memset(pos, 0, pad); - pos += pad; - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - /* EAP-TTLS/PAP does not provide tunneled success notification, - * so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -} - - -static int eap_ttls_phase2_request_chap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ -#ifdef CONFIG_FIPS - wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build"); - return -1; -#else /* CONFIG_FIPS */ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, - "EAP-TTLS/CHAP: Failed to allocate memory"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - /* User-Name */ - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - /* CHAP-Challenge */ - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " - "implicit challenge"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, - challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); - - /* CHAP-Password */ - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, - 1 + EAP_TTLS_CHAP_PASSWORD_LEN); - data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - - /* MD5(Ident + Password + Challenge) */ - chap_md5(data->ident, password, password_len, challenge, - EAP_TTLS_CHAP_CHALLENGE_LEN, pos); - - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", - identity, identity_len); - wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", - password, password_len); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", - challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", - pos, EAP_TTLS_CHAP_PASSWORD_LEN); - pos += EAP_TTLS_CHAP_PASSWORD_LEN; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - /* EAP-TTLS/CHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -#endif /* CONFIG_FIPS */ -} - - -static int eap_ttls_phase2_request(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, - struct wpabuf **resp) -{ - int res = 0; - size_t len; - enum phase2_types phase2_type = data->phase2_type; - -#ifdef EAP_TNC - if (data->tnc_started) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); - phase2_type = EAP_TTLS_PHASE2_EAP; - } -#endif /* EAP_TNC */ - - if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || - phase2_type == EAP_TTLS_PHASE2_MSCHAP || - phase2_type == EAP_TTLS_PHASE2_PAP || - phase2_type == EAP_TTLS_PHASE2_CHAP) { - if (eap_get_config_identity(sm, &len) == NULL) { - wpa_printf(MSG_INFO, - "EAP-TTLS: Identity not configured"); - eap_sm_request_identity(sm); - if (eap_get_config_password(sm, &len) == NULL) - eap_sm_request_password(sm); - return 0; - } - - if (eap_get_config_password(sm, &len) == NULL) { - wpa_printf(MSG_INFO, - "EAP-TTLS: Password not configured"); - eap_sm_request_password(sm); - return 0; - } - } - - switch (phase2_type) { - case EAP_TTLS_PHASE2_EAP: - res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); - break; - case EAP_TTLS_PHASE2_MSCHAPV2: - res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); - break; - case EAP_TTLS_PHASE2_MSCHAP: - res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); - break; - case EAP_TTLS_PHASE2_PAP: - res = eap_ttls_phase2_request_pap(sm, data, ret, resp); - break; - case EAP_TTLS_PHASE2_CHAP: - res = eap_ttls_phase2_request_chap(sm, data, ret, resp); - break; - default: - wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); - res = -1; - break; - } - - if (res < 0) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } - - return res; -} - - -struct ttls_parse_avp { - u8 *mschapv2; - u8 *eapdata; - size_t eap_len; - int mschapv2_error; -}; - - -static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, - struct ttls_parse_avp *parse) -{ - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); - if (parse->eapdata == NULL) { - parse->eapdata = os_malloc(dlen); - if (parse->eapdata == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " - "memory for Phase 2 EAP data"); - return -1; - } - os_memcpy(parse->eapdata, dpos, dlen); - parse->eap_len = dlen; - } else { - u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); - if (neweap == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " - "memory for Phase 2 EAP data"); - return -1; - } - os_memcpy(neweap + parse->eap_len, dpos, dlen); - parse->eapdata = neweap; - parse->eap_len += dlen; - } - - return 0; -} - - -static int eap_ttls_parse_avp(u8 *pos, size_t left, - struct ttls_parse_avp *parse) -{ - struct ttls_avp *avp; - u32 avp_code, avp_length, vendor_id = 0; - u8 avp_flags, *dpos; - size_t dlen; - - avp = (struct ttls_avp *) pos; - avp_code = be_to_host32(avp->avp_code); - avp_length = be_to_host32(avp->avp_length); - avp_flags = (avp_length >> 24) & 0xff; - avp_length &= 0xffffff; - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " - "length=%d", (int) avp_code, avp_flags, - (int) avp_length); - - if (avp_length > left) { - wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " - "(len=%d, left=%lu) - dropped", - (int) avp_length, (unsigned long) left); - return -1; - } - - if (avp_length < sizeof(*avp)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", - avp_length); - return -1; - } - - dpos = (u8 *) (avp + 1); - dlen = avp_length - sizeof(*avp); - if (avp_flags & AVP_FLAGS_VENDOR) { - if (dlen < 4) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " - "underflow"); - return -1; - } - vendor_id = WPA_GET_BE32(dpos); - wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", - (int) vendor_id); - dpos += 4; - dlen -= 4; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); - - if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { - if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) - return -1; - } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { - /* This is an optional message that can be displayed to - * the user. */ - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", - dpos, dlen); - } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && - avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", - dpos, dlen); - if (dlen != 43) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " - "MS-CHAP2-Success length " - "(len=%lu, expected 43)", - (unsigned long) dlen); - return -1; - } - parse->mschapv2 = dpos; - } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && - avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { - wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", - dpos, dlen); - parse->mschapv2_error = 1; - } else if (avp_flags & AVP_FLAGS_MANDATORY) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " - "code %d vendor_id %d - dropped", - (int) avp_code, (int) vendor_id); - return -1; - } else { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " - "code %d vendor_id %d", - (int) avp_code, (int) vendor_id); - } - - return avp_length; -} - - -static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, - struct ttls_parse_avp *parse) -{ - u8 *pos; - size_t left, pad; - int avp_length; - - pos = wpabuf_mhead(in_decrypted); - left = wpabuf_len(in_decrypted); - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); - if (left < sizeof(struct ttls_avp)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" - " len=%lu expected %lu or more - dropped", - (unsigned long) left, - (unsigned long) sizeof(struct ttls_avp)); - return -1; - } - - /* Parse AVPs */ - os_memset(parse, 0, sizeof(*parse)); - - while (left > 0) { - avp_length = eap_ttls_parse_avp(pos, left, parse); - if (avp_length < 0) - return -1; - - pad = (4 - (avp_length & 3)) & 3; - pos += avp_length + pad; - if (left < avp_length + pad) - left = 0; - else - left -= avp_length + pad; - } - - return 0; -} - - -static u8 * eap_ttls_fake_identity_request(void) -{ - struct eap_hdr *hdr; - u8 *buf; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " - "Phase 2 - use fake EAP-Request Identity"); - buf = os_malloc(sizeof(*hdr) + 1); - if (buf == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " - "memory for fake EAP-Identity Request"); - return NULL; - } - - hdr = (struct eap_hdr *) buf; - hdr->code = EAP_CODE_REQUEST; - hdr->identifier = 0; - hdr->length = host_to_be16(sizeof(*hdr) + 1); - buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; - - return buf; -} - - -static int eap_ttls_encrypt_response(struct eap_sm *sm, - struct eap_ttls_data *data, - struct wpabuf *resp, u8 identifier, - struct wpabuf **out_data) -{ - if (resp == NULL) - return 0; - - wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", - resp); - if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, - data->ttls_version, identifier, - resp, out_data)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " - "frame"); - wpabuf_free(resp); - return -1; - } - wpabuf_free(resp); - - return 0; -} - - -static int eap_ttls_process_phase2_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse, - struct wpabuf **resp) -{ - struct eap_hdr *hdr; - size_t len; - - if (parse->eapdata == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " - "packet - dropped"); - return -1; - } - - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", - parse->eapdata, parse->eap_len); - hdr = (struct eap_hdr *) parse->eapdata; - - if (parse->eap_len < sizeof(*hdr)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " - "frame (len=%lu, expected %lu or more) - dropped", - (unsigned long) parse->eap_len, - (unsigned long) sizeof(*hdr)); - return -1; - } - len = be_to_host16(hdr->length); - if (len > parse->eap_len) { - wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " - "EAP frame (EAP hdr len=%lu, EAP data len in " - "AVP=%lu)", - (unsigned long) len, - (unsigned long) parse->eap_len); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " - "identifier=%d length=%lu", - hdr->code, hdr->identifier, (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " - "processing failed"); - return -1; - } - break; - default: - wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - return -1; - } - - return 0; -} - - -static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse) -{ -#ifdef EAP_MSCHAPv2 - if (parse->mschapv2_error) { - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " - "MS-CHAP-Error - failed"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - /* Reply with empty data to ACK error */ - return 1; - } - - if (parse->mschapv2 == NULL) { -#ifdef EAP_TNC - if (data->phase2_success && parse->eapdata) { - /* - * Allow EAP-TNC to be started after successfully - * completed MSCHAPV2. - */ - return 1; - } -#endif /* EAP_TNC */ - wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " - "received for Phase2 MSCHAPV2"); - return -1; - } - if (parse->mschapv2[0] != data->ident) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " - "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", - parse->mschapv2[0], data->ident); - return -1; - } - if (!data->auth_response_valid || - mschapv2_verify_auth_response(data->auth_response, - parse->mschapv2 + 1, 42)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " - "response in Phase 2 MSCHAPV2 success request"); - return -1; - } - - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " - "authentication succeeded"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - - /* - * Reply with empty data; authentication server will reply - * with EAP-Success after this. - */ - return 1; -#else /* EAP_MSCHAPv2 */ - wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); - return -1; -#endif /* EAP_MSCHAPv2 */ -} - - -#ifdef EAP_TNC -static int eap_ttls_process_tnc_start(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse, - struct wpabuf **resp) -{ - /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ - if (parse->eapdata == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " - "unexpected tunneled data (no EAP)"); - return -1; - } - - if (!data->ready_for_tnc) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " - "EAP after non-EAP, but not ready for TNC"); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " - "non-EAP method"); - data->tnc_started = 1; - - if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) - return -1; - - return 0; -} -#endif /* EAP_TNC */ - - -static int eap_ttls_process_decrypted(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - struct ttls_parse_avp *parse, - struct wpabuf *in_decrypted, - struct wpabuf **out_data) -{ - struct wpabuf *resp = NULL; - struct eap_peer_config *config = eap_get_config(sm); - int res; - enum phase2_types phase2_type = data->phase2_type; - -#ifdef EAP_TNC - if (data->tnc_started) - phase2_type = EAP_TTLS_PHASE2_EAP; -#endif /* EAP_TNC */ - - switch (phase2_type) { - case EAP_TTLS_PHASE2_EAP: - if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < - 0) - return -1; - break; - case EAP_TTLS_PHASE2_MSCHAPV2: - res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); -#ifdef EAP_TNC - if (res == 1 && parse->eapdata && data->phase2_success) { - /* - * TNC may be required as the next - * authentication method within the tunnel. - */ - ret->methodState = METHOD_MAY_CONT; - data->ready_for_tnc = 1; - if (eap_ttls_process_tnc_start(sm, data, ret, parse, - &resp) == 0) - break; - } -#endif /* EAP_TNC */ - return res; - case EAP_TTLS_PHASE2_MSCHAP: - case EAP_TTLS_PHASE2_PAP: - case EAP_TTLS_PHASE2_CHAP: -#ifdef EAP_TNC - if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < - 0) - return -1; - break; -#else /* EAP_TNC */ - /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled - * requests to the supplicant */ - wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " - "tunneled data"); - return -1; -#endif /* EAP_TNC */ - } - - if (resp) { - if (eap_ttls_encrypt_response(sm, data, resp, identifier, - out_data) < 0) - return -1; - } else if (config->pending_req_identity || - config->pending_req_password || - config->pending_req_otp || - config->pending_req_new_password) { - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = wpabuf_dup(in_decrypted); - } - - return 0; -} - - -static int eap_ttls_implicit_identity_request(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - struct wpabuf **out_data) -{ - int retval = 0; - struct eap_hdr *hdr; - struct wpabuf *resp; - - hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); - if (hdr == NULL) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - - resp = NULL; - if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " - "processing failed"); - retval = -1; - } else { - struct eap_peer_config *config = eap_get_config(sm); - if (resp == NULL && - (config->pending_req_identity || - config->pending_req_password || - config->pending_req_otp || - config->pending_req_new_password)) { - /* - * Use empty buffer to force implicit request - * processing when EAP request is re-processed after - * user input. - */ - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = wpabuf_alloc(0); - } - - retval = eap_ttls_encrypt_response(sm, data, resp, identifier, - out_data); - } - - os_free(hdr); - - if (retval < 0) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } - - return retval; -} - - -static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, - struct eap_method_ret *ret, u8 identifier, - struct wpabuf **out_data) -{ - data->phase2_start = 0; - - /* - * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only - * if TLS part was indeed resuming a previous session. Most - * Authentication Servers terminate EAP-TTLS before reaching this - * point, but some do not. Make wpa_supplicant stop phase 2 here, if - * needed. - */ - if (data->reauth && - tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " - "skip phase 2"); - *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, - data->ttls_version); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - return 0; - } - - return eap_ttls_implicit_identity_request(sm, data, ret, identifier, - out_data); -} - - -static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, - struct eap_method_ret *ret, u8 identifier, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - struct wpabuf *in_decrypted = NULL; - int retval = 0; - struct ttls_parse_avp parse; - - os_memset(&parse, 0, sizeof(parse)); - - wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" - " Phase 2", - in_data ? (unsigned long) wpabuf_len(in_data) : 0); - - if (data->pending_phase2_req) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " - "skip decryption and use old data"); - /* Clear TLS reassembly state. */ - eap_peer_tls_reset_input(&data->ssl); - - in_decrypted = data->pending_phase2_req; - data->pending_phase2_req = NULL; - if (wpabuf_len(in_decrypted) == 0) { - wpabuf_free(in_decrypted); - return eap_ttls_implicit_identity_request( - sm, data, ret, identifier, out_data); - } - goto continue_req; - } - - if ((in_data == NULL || wpabuf_len(in_data) == 0) && - data->phase2_start) { - return eap_ttls_phase2_start(sm, data, ret, identifier, - out_data); - } - - if (in_data == NULL || wpabuf_len(in_data) == 0) { - /* Received TLS ACK - requesting more fragments */ - return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, - data->ttls_version, - identifier, NULL, out_data); - } - - retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); - if (retval) - goto done; - -continue_req: - data->phase2_start = 0; - - if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { - retval = -1; - goto done; - } - - retval = eap_ttls_process_decrypted(sm, data, ret, identifier, - &parse, in_decrypted, out_data); - -done: - wpabuf_free(in_decrypted); - os_free(parse.eapdata); - - if (retval < 0) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } - - return retval; -} - - -static int eap_ttls_process_handshake(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - const struct wpabuf *in_data, - struct wpabuf **out_data) -{ - int res; - - res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, - data->ttls_version, identifier, - in_data, out_data); - if (res < 0) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " - "Phase 2"); - if (data->resuming) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " - "skip Phase 2"); - ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_MAY_CONT; - } - data->phase2_start = 1; - eap_ttls_v0_derive_key(sm, data); - - if (*out_data == NULL || wpabuf_len(*out_data) == 0) { - if (eap_ttls_decrypt(sm, data, ret, identifier, - NULL, out_data)) { - wpa_printf(MSG_WARNING, "EAP-TTLS: " - "failed to process early " - "start for Phase 2"); - } - res = 0; - } - data->resuming = 0; - } - - if (res == 2) { - /* - * Application data included in the handshake message. - */ - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = *out_data; - *out_data = NULL; - res = eap_ttls_decrypt(sm, data, ret, identifier, in_data, - out_data); - } - - return res; -} - - -static void eap_ttls_check_auth_status(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret) -{ - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - if (ret->decision == DECISION_UNCOND_SUCC || - ret->decision == DECISION_COND_SUCC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " - "completed successfully"); - data->phase2_success = 1; -#ifdef EAP_TNC - if (!data->ready_for_tnc && !data->tnc_started) { - /* - * TNC may be required as the next - * authentication method within the tunnel. - */ - ret->methodState = METHOD_MAY_CONT; - data->ready_for_tnc = 1; - } -#endif /* EAP_TNC */ - } - } else if (ret->methodState == METHOD_MAY_CONT && - (ret->decision == DECISION_UNCOND_SUCC || - ret->decision == DECISION_COND_SUCC)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " - "completed successfully (MAY_CONT)"); - data->phase2_success = 1; - } -} - - -static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - size_t left; - int res; - u8 flags, id; - struct wpabuf *resp; - const u8 *pos; - struct eap_ttls_data *data = priv; - struct wpabuf msg; - - pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, - reqData, &left, &flags); - if (pos == NULL) - return NULL; - id = eap_get_id(reqData); - - if (flags & EAP_TLS_FLAGS_START) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " - "ver=%d)", flags & EAP_TLS_VERSION_MASK, - data->ttls_version); - - /* RFC 5281, Ch. 9.2: - * "This packet MAY contain additional information in the form - * of AVPs, which may provide useful hints to the client" - * For now, ignore any potential extra data. - */ - left = 0; - } - - wpabuf_set(&msg, pos, left); - - resp = NULL; - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - !data->resuming) { - res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); - } else { - res = eap_ttls_process_handshake(sm, data, ret, id, - &msg, &resp); - } - - eap_ttls_check_auth_status(sm, data, ret); - - /* FIX: what about res == -1? Could just move all error processing into - * the other functions and get rid of this res==1 case here. */ - if (res == 1) { - wpabuf_free(resp); - return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, - data->ttls_version); - } - return resp; -} - - -static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - data->phase2_success; -} - - -static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - wpabuf_free(data->pending_phase2_req); - data->pending_phase2_req = NULL; -#ifdef EAP_TNC - data->ready_for_tnc = 0; - data->tnc_started = 0; -#endif /* EAP_TNC */ -} - - -static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - eap_ttls_free_key(data); - os_free(data->session_id); - data->session_id = NULL; - if (eap_peer_tls_reauth_init(sm, &data->ssl)) { - os_free(data); - return NULL; - } - if (data->phase2_priv && data->phase2_method && - data->phase2_method->init_for_reauth) - data->phase2_method->init_for_reauth(sm, data->phase2_priv); - data->phase2_start = 0; - data->phase2_success = 0; - data->resuming = 1; - data->reauth = 1; - return priv; -} - - -static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose) -{ - struct eap_ttls_data *data = priv; - int len, ret; - - len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); - ret = os_snprintf(buf + len, buflen - len, - "EAP-TTLSv%d Phase2 method=", - data->ttls_version); - if (os_snprintf_error(buflen - len, ret)) - return len; - len += ret; - switch (data->phase2_type) { - case EAP_TTLS_PHASE2_EAP: - ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", - data->phase2_method ? - data->phase2_method->name : "?"); - break; - case EAP_TTLS_PHASE2_MSCHAPV2: - ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); - break; - case EAP_TTLS_PHASE2_MSCHAP: - ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); - break; - case EAP_TTLS_PHASE2_PAP: - ret = os_snprintf(buf + len, buflen - len, "PAP\n"); - break; - case EAP_TTLS_PHASE2_CHAP: - ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); - break; - default: - ret = 0; - break; - } - if (os_snprintf_error(buflen - len, ret)) - return len; - len += ret; - - return len; -} - - -static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_ttls_data *data = priv; - return data->key_data != NULL && data->phase2_success; -} - - -static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ttls_data *data = priv; - u8 *key; - - if (data->key_data == NULL || !data->phase2_success) - return NULL; - - key = os_malloc(EAP_TLS_KEY_LEN); - if (key == NULL) - return NULL; - - *len = EAP_TLS_KEY_LEN; - os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); - - return key; -} - - -static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ttls_data *data = priv; - u8 *id; - - if (data->session_id == NULL || !data->phase2_success) - return NULL; - - id = os_malloc(data->id_len); - if (id == NULL) - return NULL; - - *len = data->id_len; - os_memcpy(id, data->session_id, data->id_len); - - return id; -} - - -static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_ttls_data *data = priv; - u8 *key; - - if (data->key_data == NULL) - return NULL; - - key = os_malloc(EAP_EMSK_LEN); - if (key == NULL) - return NULL; - - *len = EAP_EMSK_LEN; - os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); - - return key; -} - - -int eap_peer_ttls_register(void) -{ - struct eap_method *eap; - int ret; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); - if (eap == NULL) - return -1; - - eap->init = eap_ttls_init; - eap->deinit = eap_ttls_deinit; - eap->process = eap_ttls_process; - eap->isKeyAvailable = eap_ttls_isKeyAvailable; - eap->getKey = eap_ttls_getKey; - eap->getSessionId = eap_ttls_get_session_id; - eap->get_status = eap_ttls_get_status; - eap->has_reauth_data = eap_ttls_has_reauth_data; - eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; - eap->init_for_reauth = eap_ttls_init_for_reauth; - eap->get_emsk = eap_ttls_get_emsk; - - ret = eap_peer_method_register(eap); - if (ret) - eap_peer_method_free(eap); - return ret; -} diff --git a/src/utils/common.h b/src/utils/common.h deleted file mode 100644 index 0b9cc3d..0000000 --- a/src/utils/common.h +++ /dev/null @@ -1,559 +0,0 @@ -/* - * wpa_supplicant/hostapd / common helper functions, etc. - * Copyright (c) 2002-2007, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef COMMON_H -#define COMMON_H - -#include "os.h" - -#if defined(__linux__) || defined(__GLIBC__) -#include -#include -#endif /* __linux__ */ - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ - defined(__OpenBSD__) -#include -#include -#define __BYTE_ORDER _BYTE_ORDER -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN -#ifdef __OpenBSD__ -#define bswap_16 swap16 -#define bswap_32 swap32 -#define bswap_64 swap64 -#else /* __OpenBSD__ */ -#define bswap_16 bswap16 -#define bswap_32 bswap32 -#define bswap_64 bswap64 -#endif /* __OpenBSD__ */ -#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || - * defined(__DragonFly__) || defined(__OpenBSD__) */ - -#ifdef __APPLE__ -#include -#include -#define __BYTE_ORDER _BYTE_ORDER -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN -static inline unsigned short bswap_16(unsigned short v) -{ - return ((v & 0xff) << 8) | (v >> 8); -} - -static inline unsigned int bswap_32(unsigned int v) -{ - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | - ((v & 0xff0000) >> 8) | (v >> 24); -} -#endif /* __APPLE__ */ - -#ifdef CONFIG_NATIVE_WINDOWS -#include - -typedef int socklen_t; - -#ifndef MSG_DONTWAIT -#define MSG_DONTWAIT 0 /* not supported */ -#endif - -#endif /* CONFIG_NATIVE_WINDOWS */ - -#ifdef _MSC_VER -#define inline __inline - -#undef vsnprintf -#define vsnprintf _vsnprintf -#undef close -#define close closesocket -#endif /* _MSC_VER */ - - -/* Define platform specific integer types */ - -#ifdef _MSC_VER -typedef UINT64 u64; -typedef UINT32 u32; -typedef UINT16 u16; -typedef UINT8 u8; -typedef INT64 s64; -typedef INT32 s32; -typedef INT16 s16; -typedef INT8 s8; -#define WPA_TYPES_DEFINED -#endif /* _MSC_VER */ - -#ifdef __vxworks -typedef unsigned long long u64; -typedef UINT32 u32; -typedef UINT16 u16; -typedef UINT8 u8; -typedef long long s64; -typedef INT32 s32; -typedef INT16 s16; -typedef INT8 s8; -#define WPA_TYPES_DEFINED -#endif /* __vxworks */ - -#ifndef WPA_TYPES_DEFINED -#ifdef CONFIG_USE_INTTYPES_H -#include -#else -#include -#endif -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint8_t u8; -typedef int64_t s64; -typedef int32_t s32; -typedef int16_t s16; -typedef int8_t s8; -#define WPA_TYPES_DEFINED -#endif /* !WPA_TYPES_DEFINED */ - - -/* Define platform specific byte swapping macros */ - -#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) - -static inline unsigned short wpa_swap_16(unsigned short v) -{ - return ((v & 0xff) << 8) | (v >> 8); -} - -static inline unsigned int wpa_swap_32(unsigned int v) -{ - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | - ((v & 0xff0000) >> 8) | (v >> 24); -} - -#define le_to_host16(n) (n) -#define host_to_le16(n) (n) -#define be_to_host16(n) wpa_swap_16(n) -#define host_to_be16(n) wpa_swap_16(n) -#define le_to_host32(n) (n) -#define host_to_le32(n) (n) -#define be_to_host32(n) wpa_swap_32(n) -#define host_to_be32(n) wpa_swap_32(n) - -#define WPA_BYTE_SWAP_DEFINED - -#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ - - -#ifndef WPA_BYTE_SWAP_DEFINED - -#ifndef __BYTE_ORDER -#ifndef __LITTLE_ENDIAN -#ifndef __BIG_ENDIAN -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#if defined(sparc) -#define __BYTE_ORDER __BIG_ENDIAN -#endif -#endif /* __BIG_ENDIAN */ -#endif /* __LITTLE_ENDIAN */ -#endif /* __BYTE_ORDER */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define le_to_host16(n) ((__force u16) (le16) (n)) -#define host_to_le16(n) ((__force le16) (u16) (n)) -#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) -#define host_to_be16(n) ((__force be16) bswap_16((n))) -#define le_to_host32(n) ((__force u32) (le32) (n)) -#define host_to_le32(n) ((__force le32) (u32) (n)) -#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) -#define host_to_be32(n) ((__force be32) bswap_32((n))) -#define le_to_host64(n) ((__force u64) (le64) (n)) -#define host_to_le64(n) ((__force le64) (u64) (n)) -#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) -#define host_to_be64(n) ((__force be64) bswap_64((n))) -#elif __BYTE_ORDER == __BIG_ENDIAN -#define le_to_host16(n) bswap_16(n) -#define host_to_le16(n) bswap_16(n) -#define be_to_host16(n) (n) -#define host_to_be16(n) (n) -#define le_to_host32(n) bswap_32(n) -#define host_to_le32(n) bswap_32(n) -#define be_to_host32(n) (n) -#define host_to_be32(n) (n) -#define le_to_host64(n) bswap_64(n) -#define host_to_le64(n) bswap_64(n) -#define be_to_host64(n) (n) -#define host_to_be64(n) (n) -#ifndef WORDS_BIGENDIAN -#define WORDS_BIGENDIAN -#endif -#else -#error Could not determine CPU byte order -#endif - -#define WPA_BYTE_SWAP_DEFINED -#endif /* !WPA_BYTE_SWAP_DEFINED */ - - -/* Macros for handling unaligned memory accesses */ - -static inline u16 WPA_GET_BE16(const u8 *a) -{ - return (a[0] << 8) | a[1]; -} - -static inline void WPA_PUT_BE16(u8 *a, u16 val) -{ - a[0] = val >> 8; - a[1] = val & 0xff; -} - -static inline u16 WPA_GET_LE16(const u8 *a) -{ - return (a[1] << 8) | a[0]; -} - -static inline void WPA_PUT_LE16(u8 *a, u16 val) -{ - a[1] = val >> 8; - a[0] = val & 0xff; -} - -static inline u32 WPA_GET_BE24(const u8 *a) -{ - return (a[0] << 16) | (a[1] << 8) | a[2]; -} - -static inline void WPA_PUT_BE24(u8 *a, u32 val) -{ - a[0] = (val >> 16) & 0xff; - a[1] = (val >> 8) & 0xff; - a[2] = val & 0xff; -} - -static inline u32 WPA_GET_BE32(const u8 *a) -{ - return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; -} - -static inline void WPA_PUT_BE32(u8 *a, u32 val) -{ - a[0] = (val >> 24) & 0xff; - a[1] = (val >> 16) & 0xff; - a[2] = (val >> 8) & 0xff; - a[3] = val & 0xff; -} - -static inline u32 WPA_GET_LE32(const u8 *a) -{ - return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; -} - -static inline void WPA_PUT_LE32(u8 *a, u32 val) -{ - a[3] = (val >> 24) & 0xff; - a[2] = (val >> 16) & 0xff; - a[1] = (val >> 8) & 0xff; - a[0] = val & 0xff; -} - -static inline u64 WPA_GET_BE64(const u8 *a) -{ - return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) | - (((u64) a[2]) << 40) | (((u64) a[3]) << 32) | - (((u64) a[4]) << 24) | (((u64) a[5]) << 16) | - (((u64) a[6]) << 8) | ((u64) a[7]); -} - -static inline void WPA_PUT_BE64(u8 *a, u64 val) -{ - a[0] = val >> 56; - a[1] = val >> 48; - a[2] = val >> 40; - a[3] = val >> 32; - a[4] = val >> 24; - a[5] = val >> 16; - a[6] = val >> 8; - a[7] = val & 0xff; -} - -static inline u64 WPA_GET_LE64(const u8 *a) -{ - return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) | - (((u64) a[5]) << 40) | (((u64) a[4]) << 32) | - (((u64) a[3]) << 24) | (((u64) a[2]) << 16) | - (((u64) a[1]) << 8) | ((u64) a[0]); -} - -static inline void WPA_PUT_LE64(u8 *a, u64 val) -{ - a[7] = val >> 56; - a[6] = val >> 48; - a[5] = val >> 40; - a[4] = val >> 32; - a[3] = val >> 24; - a[2] = val >> 16; - a[1] = val >> 8; - a[0] = val & 0xff; -} - - -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif -#ifndef ETH_HLEN -#define ETH_HLEN 14 -#endif -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif -#ifndef ETH_P_ALL -#define ETH_P_ALL 0x0003 -#endif -#ifndef ETH_P_80211_ENCAP -#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ -#endif -#ifndef ETH_P_PAE -#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -#endif /* ETH_P_PAE */ -#ifndef ETH_P_EAPOL -#define ETH_P_EAPOL ETH_P_PAE -#endif /* ETH_P_EAPOL */ -#ifndef ETH_P_RSN_PREAUTH -#define ETH_P_RSN_PREAUTH 0x88c7 -#endif /* ETH_P_RSN_PREAUTH */ -#ifndef ETH_P_RRB -#define ETH_P_RRB 0x890D -#endif /* ETH_P_RRB */ - - -#ifdef __GNUC__ -#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) -#define STRUCT_PACKED __attribute__ ((packed)) -#else -#define PRINTF_FORMAT(a,b) -#define STRUCT_PACKED -#endif - - -#ifdef CONFIG_ANSI_C_EXTRA - -#if !defined(_MSC_VER) || _MSC_VER < 1400 -/* snprintf - used in number of places; sprintf() is _not_ a good replacement - * due to possible buffer overflow; see, e.g., - * http://www.ijs.si/software/snprintf/ for portable implementation of - * snprintf. */ -int snprintf(char *str, size_t size, const char *format, ...); - -/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ - -/* getopt - only used in main.c */ -int getopt(int argc, char *const argv[], const char *optstring); -extern char *optarg; -extern int optind; - -#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF -#ifndef __socklen_t_defined -typedef int socklen_t; -#endif -#endif - -/* inline - define as __inline or just define it to be empty, if needed */ -#ifdef CONFIG_NO_INLINE -#define inline -#else -#define inline __inline -#endif - -#ifndef __func__ -#define __func__ "__func__ not defined" -#endif - -#ifndef bswap_16 -#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) -#endif - -#ifndef bswap_32 -#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ - (((u32) (a) << 8) & 0xff0000) | \ - (((u32) (a) >> 8) & 0xff00) | \ - (((u32) (a) >> 24) & 0xff)) -#endif - -#ifndef MSG_DONTWAIT -#define MSG_DONTWAIT 0 -#endif - -#ifdef _WIN32_WCE -void perror(const char *s); -#endif /* _WIN32_WCE */ - -#endif /* CONFIG_ANSI_C_EXTRA */ - -#ifndef MAC2STR -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" - -/* - * Compact form for string representation of MAC address - * To be used, e.g., for constructing dbus paths for P2P Devices - */ -#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x" -#endif - -#ifndef BIT -#define BIT(x) (1U << (x)) -#endif - -/* - * Definitions for sparse validation - * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) - */ -#ifdef __CHECKER__ -#define __force __attribute__((force)) -#define __bitwise __attribute__((bitwise)) -#else -#define __force -#define __bitwise -#endif - -typedef u16 __bitwise be16; -typedef u16 __bitwise le16; -typedef u32 __bitwise be32; -typedef u32 __bitwise le32; -typedef u64 __bitwise be64; -typedef u64 __bitwise le64; - -#ifndef __must_check -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -#define __must_check __attribute__((__warn_unused_result__)) -#else -#define __must_check -#endif /* __GNUC__ */ -#endif /* __must_check */ - -#ifndef __maybe_unused -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -#define __maybe_unused __attribute__((unused)) -#else -#define __maybe_unused -#endif /* __GNUC__ */ -#endif /* __must_check */ - -int hwaddr_aton(const char *txt, u8 *addr); -int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); -int hwaddr_compact_aton(const char *txt, u8 *addr); -int hwaddr_aton2(const char *txt, u8 *addr); -int hex2byte(const char *hex); -int hexstr2bin(const char *hex, u8 *buf, size_t len); -void inc_byte_array(u8 *counter, size_t len); -void wpa_get_ntp_timestamp(u8 *buf); -int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...); -int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, - char sep); -int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); -int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, - size_t len); - -int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask); - -#ifdef CONFIG_NATIVE_WINDOWS -void wpa_unicode2ascii_inplace(TCHAR *str); -TCHAR * wpa_strdup_tchar(const char *str); -#else /* CONFIG_NATIVE_WINDOWS */ -#define wpa_unicode2ascii_inplace(s) do { } while (0) -#define wpa_strdup_tchar(s) strdup((s)) -#endif /* CONFIG_NATIVE_WINDOWS */ - -void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len); -size_t printf_decode(u8 *buf, size_t maxlen, const char *str); - -const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); - -char * wpa_config_parse_string(const char *value, size_t *len); -int is_hex(const u8 *data, size_t len); -size_t merge_byte_arrays(u8 *res, size_t res_len, - const u8 *src1, size_t src1_len, - const u8 *src2, size_t src2_len); -char * dup_binstr(const void *src, size_t len); - -static inline int is_zero_ether_addr(const u8 *a) -{ - return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); -} - -static inline int is_broadcast_ether_addr(const u8 *a) -{ - return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; -} - -static inline int is_multicast_ether_addr(const u8 *a) -{ - return a[0] & 0x01; -} - -#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" - -#include "wpa_debug.h" - - -struct wpa_freq_range_list { - struct wpa_freq_range { - unsigned int min; - unsigned int max; - } *range; - unsigned int num; -}; - -int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value); -int freq_range_list_includes(const struct wpa_freq_range_list *list, - unsigned int freq); -char * freq_range_list_str(const struct wpa_freq_range_list *list); - -int int_array_len(const int *a); -void int_array_concat(int **res, const int *a); -void int_array_sort_unique(int *a); -void int_array_add_unique(int **res, int a); - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -void str_clear_free(char *str); -void bin_clear_free(void *bin, size_t len); - -int random_mac_addr(u8 *addr); -int random_mac_addr_keep_oui(u8 *addr); - -const char * cstr_token(const char *str, const char *delim, const char **last); -char * str_token(char *str, const char *delim, char **context); -size_t utf8_escape(const char *inp, size_t in_size, - char *outp, size_t out_size); -size_t utf8_unescape(const char *inp, size_t in_size, - char *outp, size_t out_size); -int is_ctrl_char(char c); - - -/* - * gcc 4.4 ends up generating strict-aliasing warnings about some very common - * networking socket uses that do not really result in a real problem and - * cannot be easily avoided with union-based type-punning due to struct - * definitions including another struct in system header files. To avoid having - * to fully disable strict-aliasing warnings, provide a mechanism to hide the - * typecast from aliasing for now. A cleaner solution will hopefully be found - * in the future to handle these cases. - */ -void * __hide_aliasing_typecast(void *foo); -#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) - -#ifdef CONFIG_VALGRIND -#include -#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) -#else /* CONFIG_VALGRIND */ -#define WPA_MEM_DEFINED(ptr, len) do { } while (0) -#endif /* CONFIG_VALGRIND */ - -#endif /* COMMON_H */ diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h deleted file mode 100644 index 17d8f96..0000000 --- a/src/utils/wpa_debug.h +++ /dev/null @@ -1,370 +0,0 @@ -/* - * wpa_supplicant/hostapd / Debug prints - * Copyright (c) 2002-2013, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_DEBUG_H -#define WPA_DEBUG_H - -#include "wpabuf.h" - -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - -/* Debugging function - conditional printf and hex dump. Driver wrappers can - * use these for debugging purposes. */ - -enum { - MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR -}; - -#ifdef CONFIG_NO_STDOUT_DEBUG - -#define wpa_debug_print_timestamp() do { } while (0) -#define wpa_printf(args...) do { } while (0) -#define wpa_hexdump(l,t,b,le) do { } while (0) -#define wpa_hexdump_buf(l,t,b) do { } while (0) -#define wpa_hexdump_key(l,t,b,le) do { } while (0) -#define wpa_hexdump_buf_key(l,t,b) do { } while (0) -#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) -#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) -#define wpa_debug_open_file(p) do { } while (0) -#define wpa_debug_close_file() do { } while (0) -#define wpa_debug_setup_stdout() do { } while (0) -#define wpa_dbg(args...) do { } while (0) - -static inline int wpa_debug_reopen_file(void) -{ - return 0; -} - -#else /* CONFIG_NO_STDOUT_DEBUG */ - -int wpa_debug_open_file(const char *path); -int wpa_debug_reopen_file(void); -void wpa_debug_close_file(void); -void wpa_debug_setup_stdout(void); - -/** - * wpa_debug_printf_timestamp - Print timestamp for debug output - * - * This function prints a timestamp in seconds_from_1970.microsoconds - * format if debug output has been configured to include timestamps in debug - * messages. - */ -void wpa_debug_print_timestamp(void); - -/** - * wpa_printf - conditional printf - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. - * - * Note: New line '\n' is added to the end of the text when printing to stdout. - */ -void wpa_printf(int level, const char *fmt, ...) -PRINTF_FORMAT(2, 3); - -/** - * wpa_hexdump - conditional hex dump - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump. - */ -void wpa_hexdump(int level, const char *title, const void *buf, size_t len); - -static inline void wpa_hexdump_buf(int level, const char *title, - const struct wpabuf *buf) -{ - wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL, - buf ? wpabuf_len(buf) : 0); -} - -/** - * wpa_hexdump_key - conditional hex dump, hide keys - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump. This works - * like wpa_hexdump(), but by default, does not include secret keys (passwords, - * etc.) in debug output. - */ -void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len); - -static inline void wpa_hexdump_buf_key(int level, const char *title, - const struct wpabuf *buf) -{ - wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL, - buf ? wpabuf_len(buf) : 0); -} - -/** - * wpa_hexdump_ascii - conditional hex dump - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump with both - * the hex numbers and ASCII characters (for printable range) are shown. 16 - * bytes per line will be shown. - */ -void wpa_hexdump_ascii(int level, const char *title, const void *buf, - size_t len); - -/** - * wpa_hexdump_ascii_key - conditional hex dump, hide keys - * @level: priority level (MSG_*) of the message - * @title: title of for the message - * @buf: data buffer to be dumped - * @len: length of the buf - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. The contents of buf is printed out has hex dump with both - * the hex numbers and ASCII characters (for printable range) are shown. 16 - * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by - * default, does not include secret keys (passwords, etc.) in debug output. - */ -void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, - size_t len); - -/* - * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce - * binary size. As such, it should be used with debugging messages that are not - * needed in the control interface while wpa_msg() has to be used for anything - * that needs to shown to control interface monitors. - */ -#define wpa_dbg(args...) wpa_msg(args) - -#endif /* CONFIG_NO_STDOUT_DEBUG */ - - -#ifdef CONFIG_NO_WPA_MSG -#define wpa_msg(args...) do { } while (0) -#define wpa_msg_ctrl(args...) do { } while (0) -#define wpa_msg_global(args...) do { } while (0) -#define wpa_msg_global_ctrl(args...) do { } while (0) -#define wpa_msg_no_global(args...) do { } while (0) -#define wpa_msg_global_only(args...) do { } while (0) -#define wpa_msg_register_cb(f) do { } while (0) -#define wpa_msg_register_ifname_cb(f) do { } while (0) -#else /* CONFIG_NO_WPA_MSG */ -/** - * wpa_msg - Conditional printf for default target and ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. The - * output may be directed to stdout, stderr, and/or syslog based on - * configuration. This function is like wpa_printf(), but it also sends the - * same message to all attached ctrl_iface monitors. - * - * Note: New line '\n' is added to the end of the text when printing to stdout. - */ -void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg(), but it sends the output only to the - * attached ctrl_iface monitors. In other words, it can be used for frequent - * events that do not need to be sent to syslog. - */ -void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_global - Global printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg(), but it sends the output as a global event, - * i.e., without being specific to an interface. For backwards compatibility, - * an old style event is also delivered on one of the interfaces (the one - * specified by the context data). - */ -void wpa_msg_global(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg_global(), but it sends the output only to the - * attached global ctrl_iface monitors. In other words, it can be used for - * frequent events that do not need to be sent to syslog. - */ -void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_no_global - Conditional printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg(), but it does not send the output as a global - * event. - */ -void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -/** - * wpa_msg_global_only - Conditional printf for ctrl_iface monitors - * @ctx: Pointer to context data; this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @level: priority level (MSG_*) of the message - * @fmt: printf format string, followed by optional arguments - * - * This function is used to print conditional debugging and error messages. - * This function is like wpa_msg_global(), but it sends the output only as a - * global event. - */ -void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...) -PRINTF_FORMAT(3, 4); - -enum wpa_msg_type { - WPA_MSG_PER_INTERFACE, - WPA_MSG_GLOBAL, - WPA_MSG_NO_GLOBAL, - WPA_MSG_ONLY_GLOBAL, -}; - -typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type, - const char *txt, size_t len); - -/** - * wpa_msg_register_cb - Register callback function for wpa_msg() messages - * @func: Callback function (%NULL to unregister) - */ -void wpa_msg_register_cb(wpa_msg_cb_func func); - -typedef const char * (*wpa_msg_get_ifname_func)(void *ctx); -void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func); - -#endif /* CONFIG_NO_WPA_MSG */ - -#ifdef CONFIG_NO_HOSTAPD_LOGGER -#define hostapd_logger(args...) do { } while (0) -#define hostapd_logger_register_cb(f) do { } while (0) -#else /* CONFIG_NO_HOSTAPD_LOGGER */ -void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, - const char *fmt, ...) PRINTF_FORMAT(5, 6); - -typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, - unsigned int module, int level, - const char *txt, size_t len); - -/** - * hostapd_logger_register_cb - Register callback function for hostapd_logger() - * @func: Callback function (%NULL to unregister) - */ -void hostapd_logger_register_cb(hostapd_logger_cb_func func); -#endif /* CONFIG_NO_HOSTAPD_LOGGER */ - -#define HOSTAPD_MODULE_IEEE80211 0x00000001 -#define HOSTAPD_MODULE_IEEE8021X 0x00000002 -#define HOSTAPD_MODULE_RADIUS 0x00000004 -#define HOSTAPD_MODULE_WPA 0x00000008 -#define HOSTAPD_MODULE_DRIVER 0x00000010 -#define HOSTAPD_MODULE_IAPP 0x00000020 -#define HOSTAPD_MODULE_MLME 0x00000040 - -enum hostapd_logger_level { - HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, - HOSTAPD_LEVEL_DEBUG = 1, - HOSTAPD_LEVEL_INFO = 2, - HOSTAPD_LEVEL_NOTICE = 3, - HOSTAPD_LEVEL_WARNING = 4 -}; - - -#ifdef CONFIG_DEBUG_SYSLOG - -void wpa_debug_open_syslog(void); -void wpa_debug_close_syslog(void); - -#else /* CONFIG_DEBUG_SYSLOG */ - -static inline void wpa_debug_open_syslog(void) -{ -} - -static inline void wpa_debug_close_syslog(void) -{ -} - -#endif /* CONFIG_DEBUG_SYSLOG */ - -#ifdef CONFIG_DEBUG_LINUX_TRACING - -int wpa_debug_open_linux_tracing(void); -void wpa_debug_close_linux_tracing(void); - -#else /* CONFIG_DEBUG_LINUX_TRACING */ - -static inline int wpa_debug_open_linux_tracing(void) -{ - return 0; -} - -static inline void wpa_debug_close_linux_tracing(void) -{ -} - -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - - -#ifdef EAPOL_TEST -#define WPA_ASSERT(a) \ - do { \ - if (!(a)) { \ - printf("WPA_ASSERT FAILED '" #a "' " \ - "%s %s:%d\n", \ - __FUNCTION__, __FILE__, __LINE__); \ - exit(1); \ - } \ - } while (0) -#else -#define WPA_ASSERT(a) do { } while (0) -#endif - -const char * debug_level_str(int level); -int str_to_debug_level(const char *s); - -#endif /* WPA_DEBUG_H */ diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h deleted file mode 100644 index c3ef1ba..0000000 --- a/src/utils/wpabuf.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Dynamic data buffer - * Copyright (c) 2007-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPABUF_H -#define WPABUF_H - -/* wpabuf::buf is a pointer to external data */ -#define WPABUF_FLAG_EXT_DATA BIT(0) - -/* - * Internal data structure for wpabuf. Please do not touch this directly from - * elsewhere. This is only defined in header file to allow inline functions - * from this file to access data. - */ -struct wpabuf { - size_t size; /* total size of the allocated buffer */ - size_t used; /* length of data in the buffer */ - u8 *buf; /* pointer to the head of the buffer */ - unsigned int flags; - /* optionally followed by the allocated buffer */ -}; - - -int wpabuf_resize(struct wpabuf **buf, size_t add_len); -struct wpabuf * wpabuf_alloc(size_t len); -struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); -struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); -struct wpabuf * wpabuf_dup(const struct wpabuf *src); -void wpabuf_free(struct wpabuf *buf); -void wpabuf_clear_free(struct wpabuf *buf); -void * wpabuf_put(struct wpabuf *buf, size_t len); -struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); -struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); -void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); - - -/** - * wpabuf_size - Get the currently allocated size of a wpabuf buffer - * @buf: wpabuf buffer - * Returns: Currently allocated size of the buffer - */ -static inline size_t wpabuf_size(const struct wpabuf *buf) -{ - return buf->size; -} - -/** - * wpabuf_len - Get the current length of a wpabuf buffer data - * @buf: wpabuf buffer - * Returns: Currently used length of the buffer - */ -static inline size_t wpabuf_len(const struct wpabuf *buf) -{ - return buf->used; -} - -/** - * wpabuf_tailroom - Get size of available tail room in the end of the buffer - * @buf: wpabuf buffer - * Returns: Tail room (in bytes) of available space in the end of the buffer - */ -static inline size_t wpabuf_tailroom(const struct wpabuf *buf) -{ - return buf->size - buf->used; -} - -/** - * wpabuf_head - Get pointer to the head of the buffer data - * @buf: wpabuf buffer - * Returns: Pointer to the head of the buffer data - */ -static inline const void * wpabuf_head(const struct wpabuf *buf) -{ - return buf->buf; -} - -static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) -{ - return wpabuf_head(buf); -} - -/** - * wpabuf_mhead - Get modifiable pointer to the head of the buffer data - * @buf: wpabuf buffer - * Returns: Pointer to the head of the buffer data - */ -static inline void * wpabuf_mhead(struct wpabuf *buf) -{ - return buf->buf; -} - -static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) -{ - return wpabuf_mhead(buf); -} - -static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) -{ - u8 *pos = wpabuf_put(buf, 1); - *pos = data; -} - -static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) -{ - u8 *pos = wpabuf_put(buf, 2); - WPA_PUT_LE16(pos, data); -} - -static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) -{ - u8 *pos = wpabuf_put(buf, 4); - WPA_PUT_LE32(pos, data); -} - -static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) -{ - u8 *pos = wpabuf_put(buf, 2); - WPA_PUT_BE16(pos, data); -} - -static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) -{ - u8 *pos = wpabuf_put(buf, 3); - WPA_PUT_BE24(pos, data); -} - -static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) -{ - u8 *pos = wpabuf_put(buf, 4); - WPA_PUT_BE32(pos, data); -} - -static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, - size_t len) -{ - if (data) - os_memcpy(wpabuf_put(buf, len), data, len); -} - -static inline void wpabuf_put_buf(struct wpabuf *dst, - const struct wpabuf *src) -{ - wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); -} - -static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) -{ - buf->buf = (u8 *) data; - buf->flags = WPABUF_FLAG_EXT_DATA; - buf->size = buf->used = len; -} - -static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) -{ - wpabuf_put_data(dst, str, os_strlen(str)); -} - -#endif /* WPABUF_H */