+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
--- /dev/null
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = libeap mech_eap
+EXTRA_DIST = mech_eap.spec
--- /dev/null
+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
+
--- /dev/null
+#!/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
--- /dev/null
+#! /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 <tromey@cygnus.com>.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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 <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+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 <bug-automake@gnu.org>.
+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:
--- /dev/null
+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
+++ /dev/null
-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)
--- /dev/null
+*.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
--- /dev/null
+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
--- /dev/null
+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)
--- /dev/null
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifndef CONFIG_SMARTCARD
+#ifndef OPENSSL_NO_ENGINE
+#ifndef ANDROID
+#define OPENSSL_NO_ENGINE
+#endif
+#endif
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#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 <openssl/ocsp.h>
+#endif /* OPENSSL_NO_TLSEXT */
+#endif /* SSL_set_tlsext_status_type */
+
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include <keystore/keystore_get.h>
+
+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 <wincrypt.h>
+
+#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");
+}
--- /dev/null
+/*
+ * EAP common peer/server definitions
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP server/peer: Shared EAP definitions
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP-FAST definitions (RFC 4851)
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP-IKEv2 definitions
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#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 */
--- /dev/null
+/*
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP server/peer: EAP-pwd shared definitions
+ * Copyright (c) 2009, Dan Harkins <dharkins@lounge.org>
+ *
+ * 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 <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+#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 */
--- /dev/null
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP server/peer: EAP-TTLS (RFC 5281)
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP-WSC definitions for Wi-Fi Protected Setup
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#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 */
--- /dev/null
+/*
+ * EAP peer state machine functions (RFC 4137)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP peer configuration data
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP peer state machines internal structures (RFC 4137)
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP peer: Method registration
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/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;
+}
--- /dev/null
+/*
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * EAP peer method: EAP-TTLS (RFC 5281)
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "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; i<config->chbind_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; i<config->chbind_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; i<config->chbind_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;
+}
--- /dev/null
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * 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 <endian.h>
+#include <byteswap.h>
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__OpenBSD__)
+#include <sys/types.h>
+#include <sys/endian.h>
+#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 <sys/types.h>
+#include <machine/endian.h>
+#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 <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <winsock.h>
+#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 <inttypes.h>
+#else
+#include <stdint.h>
+#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 <valgrind/memcheck.h>
+#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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * wpa_supplicant/hostapd / Debug prints
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+/*
+ * Dynamic data buffer
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
+ *
+ * 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 */
--- /dev/null
+## -*- 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])])
+])
--- /dev/null
+%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 <hartmans@moonbuildcentos.dev.ja.net> - @VERSION@-2
+- Add radius_ad plugin
+
--- /dev/null
+/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
--- /dev/null
+The initial implementation of mech_eap was written by PADL Software
+under contract to JANET(UK).
+
+--
+Luke Howard <lukeh@padl.com>
+January, 2011
--- /dev/null
+Copyright (c) 2011, JANET(UK)
+
+See the LICENSE file for licensing terms.
--- /dev/null
+/*
+ * 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.
+ */
--- /dev/null
+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]
--- /dev/null
+- 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
+
--- /dev/null
+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 = '<saml:Assertion ...'
+ SAML-AAA-Assertion += '...'
+ }
+
+You'll need to split it into multiple lines because of the RADIUS
+attribute size limit.
+
+Testing
+=======
+
+You can then test the MIT or Cyrus GSS and SASL example programs.
+Sample usage is given below. Substitute <user>, <pass> and <host>
+appropriately (<host> 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 <user>@<realm> -pass <pass> <host> host@<host> \
+ "Testing GSS EAP"
+% gss-server -port 5555 -export host@<host>
+
+Note: for SASL you will be prompted for a username and password.
+
+% client -C -p 5556 -s host -m EAP-AES128 <host>
+% server -c -p 5556 -s host -h <host>
+
+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.
+
--- /dev/null
+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:
+
+ <GSSAPIAttribute name="urn:ietf:params:gss:radius-attribute 26.25622.133"
+ id="urn:mspac:" binary="true"/>
+
+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.
--- /dev/null
+- 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/* -*- 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 <krb5/krb5.h>
+
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#! /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 <config-patches@gnu.org> 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 <config-patches@gnu.org>."
+
+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 <stdio.h> /* 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 <sys/systemcfg.h>
+
+ 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 <stdlib.h>
+ #include <unistd.h>
+
+ 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 <unistd.h>
+ 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' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/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 <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # 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 <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#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 <sys/param.h>
+ 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 <sys/param.h>
+# 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 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> 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:
--- /dev/null
+#! /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 <config-patches@gnu.org>. 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 <config-patches@gnu.org>."
+
+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:
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+# -*- 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#include <time.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef WIN32
+#ifndef MAXHOSTNAMELEN
+# include <WinSock2.h>
+# define MAXHOSTNAMELEN NI_MAXHOST
+#endif
+#endif
+
+/* GSS headers */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#ifdef HAVE_HEIMDAL_VERSION
+typedef struct gss_any *gss_any_t;
+#else
+#include <gssapi/gssapi_ext.h>
+#endif
+#include "gssapi_eap.h"
+
+#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
+typedef const gss_OID_desc *gss_const_OID;
+#endif
+
+/* Kerberos headers */
+#include <krb5.h>
+
+/* EAP headers */
+#include <includes.h>
+#include <common.h>
+#include <eap_peer/eap.h>
+#include <eap_peer/eap_config.h>
+#include <eap_peer/eap_methods.h>
+#include <eap_common/eap_common.h>
+#include <wpabuf.h>
+
+#ifdef GSSEAP_ENABLE_ACCEPTOR
+/* libradsec headers */
+#include <radsec/radsec.h>
+#include <radsec/request.h>
+#include <radsec/radius.h>
+#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_ */
--- /dev/null
+/*
+ * 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 <gssapi/gssapi.h>
+
+#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_ */
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 <set->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;
+}
--- /dev/null
+#!/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:
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#
+# 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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+authdata_client_0
--- /dev/null
+realm gss-eap {
+ type = "UDP"
+ timeout = 5
+ retries = 3
+ server {
+ hostname = "localhost"
+ service = "1812"
+ secret = "testing123"
+ }
+}
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 <sys/param.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#include <krb5.h>
+
+#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 <gssapi/gssapi_alloc.h>
+#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 <assert.h>
+#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 <winbase.h>
+
+#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 <pthread.h>
+
+#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_ */
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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 <typeinfo>
+#include <string>
+#include <sstream>
+#include <exception>
+#include <new>
+
+/* 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;
+}
--- /dev/null
+/*
+ * 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 <string>
+#include <new>
+
+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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 <shlobj.h> /* may need to use ShFolder.h instead */
+# include <stdio.h>
+#else
+# include <pwd.h>
+#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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 <typeinfo>
+#include <string>
+#include <sstream>
+#include <exception>
+#include <new>
+
+#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);
+}
--- /dev/null
+/*
+ * 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 <string>
+#include <new>
+
+#include <jansson.h>
+
+#ifdef HAVE_SHIBRESOLVER
+#include <shibsp/remoting/ddf.h>
+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_ */
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 <libmoonshot.h>
+
+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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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<const gss_eap_radius_attr_provider *>(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 <gss_eap_attrid> &attrs,
+ gss_eap_attrid &attrid)
+{
+ for (std::vector<gss_eap_attrid>::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 <gss_eap_attrid> 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;
+}
--- /dev/null
+/*
+ * 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 <unsigned int, unsigned int> 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_ */
--- /dev/null
+/*
+ * 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 <dlfcn.h>
+
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <sstream>
+
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/unicode.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xmltooling/util/ParserPool.h>
+#include <xmltooling/util/DateTime.h>
+
+#include <saml/exceptions.h>
+#include <saml/SAMLConfig.h>
+#include <saml/saml1/core/Assertions.h>
+#include <saml/saml2/core/Assertions.h>
+#include <saml/saml2/metadata/Metadata.h>
+#include <saml/saml2/metadata/MetadataProvider.h>
+
+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<const gss_eap_saml_assertion_provider *>(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<const gss_eap_radius_attr_provider *>
+ (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<saml2::Assertion *>(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<saml2::Assertion *>(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<gss_eap_saml_assertion_provider *>
+ (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 <saml2::AttributeStatement *> &statements =
+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+
+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+ s != statements.end();
+ ++s) {
+ const vector<saml2::Attribute*> &attrs =
+ const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
+
+ for (vector<saml2::Attribute*>::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<XMLCh> *
+decomposeAttributeName(const gss_buffer_t attr)
+{
+ BaseRefVectorOf<XMLCh> *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<XMLCh> *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<XMLCh> *components = decomposeAttributeName(attr);
+ if (components == NULL)
+ return false;
+
+ /* For each attribute statement, look for an attribute match */
+ const vector<saml2::AttributeStatement *> &statements =
+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+
+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+ s != statements.end();
+ ++s) {
+ const vector<saml2::Attribute *> &attrs =
+ const_cast<const saml2::AttributeStatement *>(*s)->getAttributes();
+ ssize_t index = -1, i = 0;
+
+ /* There's got to be an easier way to do this */
+ for (vector<saml2::Attribute *>::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<XMLCh> *components = decomposeAttributeName(attr);
+ if (components == NULL)
+ return false;
+
+ /* For each attribute statement, look for an attribute match */
+ const vector <saml2::AttributeStatement *> &statements =
+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+ const saml2::Attribute *ret = NULL;
+
+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+ s != statements.end();
+ ++s) {
+ const vector<saml2::Attribute *> &attrs =
+ const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
+
+ for (vector<saml2::Attribute *>::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<const saml2::AttributeValue *>(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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <xmltooling/XMLObject.h>
+#ifndef HAVE_OPENSAML
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/ParserPool.h>
+#endif
+
+#include <saml/saml2/core/Assertions.h>
+
+#include <shibsp/exceptions.h>
+#include <shibsp/attribute/SimpleAttribute.h>
+#include <shibsp/attribute/BinaryAttribute.h>
+#include <shibsp/attribute/ScopedAttribute.h>
+#include <shibresolver/resolver.h>
+
+#include <sstream>
+
+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<Attribute>())
+ ;
+}
+
+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<const gss_eap_shib_attr_provider *>(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<ShibbolethResolver> 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<const gss_eap_saml_assertion_provider *>
+ (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<const gss_eap_radius_attr_provider *>
+ (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<Attribute *>::const_iterator a = m_attributes.begin();
+ a != m_attributes.end();
+ ++a)
+ {
+ for (vector<string>::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 <string> 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<Attribute*>::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<Attribute *>::const_iterator a = m_attributes.begin();
+ a != m_attributes.end();
+ ++a)
+ {
+ for (vector<string>::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<const BinaryAttribute *>(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<const SimpleAttribute *>(shibAttr);
+ const ScopedAttribute *scopedAttr =
+ dynamic_cast<const ScopedAttribute *>(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 <Attribute *>v = duplicateAttributes(m_attributes);
+
+ output = (gss_any_t)new vector <Attribute *>(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 <Attribute *> *v = ((vector <Attribute *> *)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<Attribute*>::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 <Attribute *>
+gss_eap_shib_attr_provider::duplicateAttributes(const vector <Attribute *>src)
+{
+ vector <Attribute *> dst;
+
+ for (vector<Attribute *>::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;
+}
--- /dev/null
+/*
+ * 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 <vector>
+
+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<shibsp::Attribute *> getAttributes(void) const {
+ return m_attributes;
+ }
+
+private:
+ static shibsp::Attribute *
+ duplicateAttribute(const shibsp::Attribute *src);
+ static std::vector <shibsp::Attribute *>
+ duplicateAttributes(const std::vector <shibsp::Attribute *>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<shibsp::Attribute *> m_attributes;
+};
+
+extern "C" {
+#endif
+
+OM_uint32 gssEapLocalAttrProviderInit(OM_uint32 *minor);
+OM_uint32 gssEapLocalAttrProviderFinalize(OM_uint32 *minor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_SHIB_H_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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)
+ * <length> possible multiple bytes, need to parse/generate
+ * 0x06 tag for OBJECT IDENTIFIER
+ * <moid_length> compile-time constant string (assume 1 byte)
+ * <moid_bytes> compile-time constant string
+ * <inner_bytes> 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#ifndef CONFIG_SMARTCARD
-#ifndef OPENSSL_NO_ENGINE
-#ifndef ANDROID
-#define OPENSSL_NO_ENGINE
-#endif
-#endif
-#endif
-
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/pkcs12.h>
-#include <openssl/x509v3.h>
-#ifndef OPENSSL_NO_ENGINE
-#include <openssl/engine.h>
-#endif /* OPENSSL_NO_ENGINE */
-#ifndef OPENSSL_NO_DSA
-#include <openssl/dsa.h>
-#endif
-#ifndef OPENSSL_NO_DH
-#include <openssl/dh.h>
-#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 <openssl/ocsp.h>
-#endif /* OPENSSL_NO_TLSEXT */
-#endif /* SSL_set_tlsext_status_type */
-
-#ifdef ANDROID
-#include <openssl/pem.h>
-#include <keystore/keystore_get.h>
-
-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 <wincrypt.h>
-
-#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");
-}
+++ /dev/null
-/*
- * EAP common peer/server definitions
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP server/peer: Shared EAP definitions
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP-FAST definitions (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP server/peer: EAP-GPSK shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP-IKEv2 definitions
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#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 */
+++ /dev/null
-/*
- * EAP server/peer: EAP-PAX shared routines
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP-PEAP common routines
- * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP server/peer: EAP-PSK shared routines
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP server/peer: EAP-pwd shared definitions
- * Copyright (c) 2009, Dan Harkins <dharkins@lounge.org>
- *
- * 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 <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/evp.h>
-
-/*
- * 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 */
+++ /dev/null
-/*
- * EAP server/peer: EAP-SAKE shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP server/peer: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP-WSC definitions for Wi-Fi Protected Setup
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#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 */
+++ /dev/null
-/*
- * EAP peer state machine functions (RFC 4137)
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP peer configuration data
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP peer state machines internal structures (RFC 4137)
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP peer: Method registration
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/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;
-}
+++ /dev/null
-/*
- * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/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;
-}
+++ /dev/null
-/*
- * wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
- *
- * 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 <endian.h>
-#include <byteswap.h>
-#endif /* __linux__ */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
- defined(__OpenBSD__)
-#include <sys/types.h>
-#include <sys/endian.h>
-#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 <sys/types.h>
-#include <machine/endian.h>
-#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 <winsock.h>
-
-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 <inttypes.h>
-#else
-#include <stdint.h>
-#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 <valgrind/memcheck.h>
-#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 */
+++ /dev/null
-/*
- * wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
- *
- * 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 */
+++ /dev/null
-/*
- * Dynamic data buffer
- * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
- *
- * 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 */