From: Luke Howard Date: Mon, 28 Nov 2011 15:01:39 +0000 (+1100) Subject: Revert "Support EAP-TLS in Moonshot (requires OpenSSL)" X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.orig;a=commitdiff_plain;h=3d5083e8a273503d6d5233195d2ee7cb2e754e6d Revert "Support EAP-TLS in Moonshot (requires OpenSSL)" This reverts commit 2ef42df0ecea8745a678fe26ff9b16072b93586b. --- 3d5083e8a273503d6d5233195d2ee7cb2e754e6d diff --cc acinclude.m4 index 401ad2a,0000000..ff06090 mode 100644,000000..100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@@ -1,399 -1,0 +1,361 @@@ +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 /usr/local ; 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_LIBS="-L$check_krb5_dir/lib/ -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_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_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_LIBS="-leap -lutils -lcrypto -ltls"; + EAP_LDFLAGS="-L$eapdir/eap_example -L$eapdir/src/utils -L$eapdir/src/crypto -L$eapdir/src/tls"; + AC_SUBST(EAP_CFLAGS) + AC_SUBST(EAP_LDFLAGS) + AC_SUBST(EAP_LIBS) +fi +])dnl + +AC_DEFUN([AX_CHECK_SHIBSP], +[AC_MSG_CHECKING(for Shibboleth implementation) +SHIBSP_DIR= +found_shibsp="no" +AC_ARG_WITH(shibsp, + AC_HELP_STRING([--with-shibsp], + [Use shibspboleth (in specified installation directory)]), + [check_shibsp_dir="$withval"], + [check_shibsp_dir=]) +for dir in $check_shibsp_dir $prefix /usr /usr/local ; do + shibspdir="$dir" + if test -f "$dir/include/shibsp/SPConfig.h"; then + found_shibsp="yes"; + SHIBSP_DIR="${shibspdir}" + SHIBSP_CXXFLAGS="-I$shibspdir/include"; + break; + fi +done +AC_MSG_RESULT($found_shibsp) +if test x_$found_shibsp != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find Shibboleth libraries. + + Please install Shibboleth or specify installation directory with + --with-shibsp=(dir). +---------------------------------------------------------------------- +]) +else + printf "Shibboleth found in $shibspdir\n"; + SHIBSP_LIBS="-lshibsp -lsaml -lxml-security-c -lxmltooling -lxerces-c"; + SHIBSP_LDFLAGS="-L$shibspdir/lib"; + AC_SUBST(SHIBSP_CXXFLAGS) + AC_SUBST(SHIBSP_LDFLAGS) + AC_SUBST(SHIBSP_LIBS) + AC_DEFINE_UNQUOTED([HAVE_SHIBSP], 1, [Define is Shibboleth SP is available]) +fi +])dnl + +AC_DEFUN([AX_CHECK_SHIBRESOLVER], +[AC_MSG_CHECKING(for Shibboleth resolver implementation) +SHIBRESOLVER_DIR= +found_shibresolver="no" +AC_ARG_WITH(shibresolver, + AC_HELP_STRING([--with-shibresolver], + [Use Shibboleth resolver (in specified installation directory)]), + [check_shibresolver_dir="$withval"], + [check_shibresolver_dir=]) +if test x_$check_shibresolver_dir != x_no; then +for dir in $check_shibresolver_dir $prefix /usr /usr/local ; do + shibresolverdir="$dir" + if test -f "$dir/include/shibresolver/resolver.h"; then + found_shibresolver="yes"; + SHIBRESOLVER_DIR="${shibresolverdir}" + SHIBRESOLVER_CXXFLAGS="-I$shibresolverdir/include"; + break; + fi +done +fi +AC_MSG_RESULT($found_shibresolver) +if test x_$check_shibresolver_dir != x_no; then +if test x_$found_shibresolver != x_yes; then + AC_MSG_WARN([ +---------------------------------------------------------------------- + Cannot find Shibboleth resolver libraries, building without + Shibboleth support. + + Please install Shibboleth or specify installation directory with + --with-shibresolver=(dir). +---------------------------------------------------------------------- +]) +else + printf "Shibboleth resolver found in $shibresolverdir\n"; + SHIBRESOLVER_LIBS="-lshibresolver"; + SHIBRESOLVER_LDFLAGS="-L$shibresolverdir/lib"; + AC_SUBST(SHIBRESOLVER_CXXFLAGS) + AC_SUBST(SHIBRESOLVER_LDFLAGS) + AC_SUBST(SHIBRESOLVER_LIBS) + AC_DEFINE_UNQUOTED([HAVE_SHIBRESOLVER], 1, [Define is Shibboleth resolver is available]) +fi +fi +])dnl + +AC_DEFUN([AX_CHECK_OPENSAML], +[AC_MSG_CHECKING(for OpenSAML implementation) +OPENSAML_DIR= +found_opensaml="no" +AC_ARG_WITH(opensaml, + AC_HELP_STRING([--with-opensaml], + [Use OpenSAML (in specified installation directory)]), + [check_opensaml_dir="$withval"], + [check_opensaml_dir=]) +if test x_$check_opensaml_dir != x_no; then +for dir in $check_opensaml_dir $prefix /usr /usr/local ; do + opensamldir="$dir" + if test -f "$dir/include/saml/Assertion.h"; then + found_opensaml="yes"; + OPENSAML_DIR="${opensamldir}" + OPENSAML_CXXFLAGS="-I$opensamldir/include"; + break; + fi +done +fi +AC_MSG_RESULT($found_opensaml) +if test x_$check_opensaml_dir != x_no; then +if test x_$found_opensaml != x_yes; then + AC_MSG_WARN([ +---------------------------------------------------------------------- + Cannot find OpenSAML libraries, building without OpenSAML support. + + Please install OpenSAML or specify installation directory with + --with-opensaml=(dir). +---------------------------------------------------------------------- +]) +else + printf "OpenSAML found in $opensamldir\n"; + OPENSAML_LIBS="-lsaml -lxml-security-c -lxmltooling -lxerces-c"; + OPENSAML_LDFLAGS="-L$opensamldir/lib"; + AC_SUBST(OPENSAML_CXXFLAGS) + AC_SUBST(OPENSAML_LDFLAGS) + AC_SUBST(OPENSAML_LIBS) + AC_DEFINE_UNQUOTED([HAVE_OPENSAML], 1, [Define is OpenSAML is available]) +fi +fi +])dnl + - AC_DEFUN([AX_CHECK_OPENSSL], - [AC_MSG_CHECKING(for OpenSSL) - OPENSSL_DIR= - found_openssl="no" - AC_ARG_WITH(openssl, - AC_HELP_STRING([--with-openssl], - [Use OpenSSL (in specified installation directory)]), - [check_openssl_dir="$withval"], - [check_openssl_dir=]) - for dir in $check_openssl_dir $prefix /usr /usr/local ; do - openssldir="$dir" - if test -f "$dir/include/openssl/opensslv.h"; then - found_openssl="yes"; - OPENSSL_DIR="${openssldir}" - OPENSSL_CFLAGS="-I$openssldir/include"; - break; - fi - done - AC_MSG_RESULT($found_openssl) - if test x_$found_openssl != x_yes; then - AC_MSG_ERROR([ - ---------------------------------------------------------------------- - Cannot find OpenSSL libraries. - - Please install libssl or specify installation directory with - --with-openssl=(dir). - ---------------------------------------------------------------------- - ]) - else - printf "OpenSSL found in $openssldir\n"; - OPENSSL_LIBS="-lssl -lcrypto"; - OPENSSL_LDFLAGS="-L$openssldir/lib"; - AC_SUBST(OPENSSL_CFLAGS) - AC_SUBST(OPENSSL_LDFLAGS) - AC_SUBST(OPENSSL_LIBS) - fi - ])dnl - +AC_DEFUN([AX_CHECK_RADSEC], +[AC_MSG_CHECKING(for radsec) +RADSEC_DIR= +found_radsec="no" +AC_ARG_WITH(radsec, + AC_HELP_STRING([--with-radsec], + [Use radsec (in specified installation directory)]), + [check_radsec_dir="$withval"], + [check_radsec_dir=]) +for dir in $check_radsec_dir $prefix /usr /usr/local ; do + radsecdir="$dir" + if test -f "$dir/include/radsec/radsec.h"; then + found_radsec="yes"; + RADSEC_DIR="${radsecdir}" + RADSEC_CFLAGS="-I$radsecdir/include"; + break; + fi +done +AC_MSG_RESULT($found_radsec) +if test x_$found_radsec != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find radsec libraries. + + Please install libradsec or specify installation directory with + --with-radsec=(dir). +---------------------------------------------------------------------- +]) +else + printf "radsec found in $radsecdir\n"; + RADSEC_LIBS="-lradsec"; + RADSEC_LDFLAGS="-L$radsecdir/lib"; + AC_SUBST(RADSEC_CFLAGS) + AC_SUBST(RADSEC_LDFLAGS) + AC_SUBST(RADSEC_LIBS) +fi +])dnl + +AC_DEFUN([AX_CHECK_JANSSON], +[AC_MSG_CHECKING(for jansson) +JANSSON_DIR= +found_jansson="no" +AC_ARG_WITH(jansson, + AC_HELP_STRING([--with-jansson], + [Use jansson (in specified installation directory)]), + [check_jansson_dir="$withval"], + [check_jansson_dir=]) +for dir in $check_jansson_dir $prefix /usr /usr/local ; do + janssondir="$dir" + if test -f "$dir/include/jansson.h"; then + found_jansson="yes"; + JANSSON_DIR="${janssondir}" + JANSSON_CFLAGS="-I$janssondir/include"; + break; + fi +done +AC_MSG_RESULT($found_jansson) +if test x_$found_jansson != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find jansson libraries. + + Please install libjansson or specify installation directory with + --with-jansson=(dir). +---------------------------------------------------------------------- +]) +else + printf "jansson found in $janssondir\n"; + JANSSON_LIBS="-ljansson"; + JANSSON_LDFLAGS="-L$janssondir/lib"; + AC_SUBST(JANSSON_CFLAGS) + AC_SUBST(JANSSON_LDFLAGS) + AC_SUBST(JANSSON_LIBS) +fi +])dnl + +AC_DEFUN([AX_CHECK_LIBMOONSHOT], +[AC_MSG_CHECKING(for Moonshot identity selector implementation) +LIBMOONSHOT_DIR= +LIBMOONSHOT_CFLAGS= +LIBMOONSHOT_LDFLAGS= +LIBMOONSHOT_LIBS= +found_libmoonshot="no" +AC_ARG_WITH(libmoonshot, + AC_HELP_STRING([--with-libmoonshot], + [Use libmoonshot (in specified installation directory)]), + [check_libmoonshot_dir="$withval"], + [check_libmoonshot_dir=]) +for dir in $check_libmoonshot_dir $prefix /usr /usr/local ; do + libmoonshotdir="$dir" + if test -f "$dir/include/libmoonshot.h"; then + found_libmoonshot="yes"; + LIBMOONSHOT_DIR="${libmoonshotdir}" + LIBMOONSHOT_CFLAGS="-I$libmoonshotdir/include"; + break; + fi +done +AC_MSG_RESULT($found_libmoonshot) +if test x_$found_libmoonshot = x_yes; then + printf "libmoonshot found in $libmoonshotdir\n"; + LIBMOONSHOT_LIBS="-lmoonshot"; + LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib"; + AC_CHECK_LIB(moonshot, moonshot_get_identity, [AC_DEFINE_UNQUOTED([HAVE_MOONSHOT_GET_IDENTITY], 1, [Define if Moonshot identity selector is available])], [], "$LIBMOONSHOT_LIBS") +fi + AC_SUBST(LIBMOONSHOT_CFLAGS) + AC_SUBST(LIBMOONSHOT_LDFLAGS) + AC_SUBST(LIBMOONSHOT_LIBS) + AM_CONDITIONAL(LIBMOONSHOT, test "x$found_libmoonshot" != "xno") +])dnl + diff --cc configure.ac index 1049dd7,0000000..4297345 mode 100644,000000..100644 --- a/configure.ac +++ b/configure.ac @@@ -1,94 -1,0 +1,92 @@@ +AC_PREREQ([2.61]) +AC_INIT([mech_eap], [0.1], [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) +AC_REPLACE_FUNCS(vasprintf) + +dnl Check if we're on Solaris and set CFLAGS accordingly +dnl AC_CANONICAL_TARGET +dnl case "${target_os}" in +dnl solaris*) +dnl TARGET_CFLAGS="-DSYS_SOLARIS9 -D_POSIX_PTHREAD_SEMANTICS" +dnl if test "$GCC" != yes ; then +dnl TARGET_CFLAGS="$TARGET_CFLAGS -mt" +dnl else +dnl TARGET_CFLAGS="$TARGET_CFLAGS -pthreads" +dnl fi +dnl TARGET_LDFLAGS="-lpthread -lsocket -lnsl" +dnl ;; +dnl *) +dnl TARGET_CFLAGS="-Wall -pedantic -pthread" +dnl TARGET_LDFLAGS="" +dnl esac + +reauth=no +AC_ARG_ENABLE(reauth, + [ --enable-reauth whether to enable fast reauthentication protocol: yes/no; default no ], + [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then + reauth=$enableval + else + echo "--enable-reauth argument must be yes or no" + exit -1 + fi + ]) + +if test "x$reauth" = "xyes" ; then + echo "Fast reauthentication protocol enabled" + TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_REAUTH" +fi +AM_CONDITIONAL(GSSEAP_ENABLE_REAUTH, test "x$reauth" != "xno") + +acceptor=yes +AC_ARG_ENABLE(acceptor, + [ --enable-acceptor whether to enable acceptor codepaths: yes/no; default yes ], + [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then + acceptor=$enableval + else + echo "--enable-acceptor argument must be yes or no" + exit -1 + fi + ]) + +if test "x$acceptor" = "xyes" ; then + echo "acceptor enabled" + TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_ACCEPTOR" +fi +AM_CONDITIONAL(GSSEAP_ENABLE_ACCEPTOR, test "x$acceptor" != "xno") + +AC_SUBST(TARGET_CFLAGS) +AC_SUBST(TARGET_LDFLAGS) +AX_CHECK_WINDOWS +AX_CHECK_KRB5 +AX_CHECK_OPENSAML +AM_CONDITIONAL(OPENSAML, test "x_$check_opensaml_dir" != "x_no") + +AX_CHECK_SHIBRESOLVER +AM_CONDITIONAL(SHIBRESOLVER, test "x_$check_shibresolver_dir" != "x_no") +if test x_$found_shibresolver = x_yes; then + AX_CHECK_SHIBSP +fi + - AX_CHECK_OPENSSL - +if test "x$acceptor" = "xyes" ; then + AX_CHECK_RADSEC + AX_CHECK_JANSSON +fi + +AX_CHECK_LIBMOONSHOT +AC_CONFIG_FILES([Makefile libeap/Makefile mech_eap/Makefile + mech_eap.spec]) +AC_OUTPUT diff --cc libeap/Makefile.am index 8cc9fb5,0000000..163e4ff mode 100644,000000..100644 --- a/libeap/Makefile.am +++ b/libeap/Makefile.am @@@ -1,191 -1,0 +1,211 @@@ +AUTOMAKE_OPTIONS = foreign + - AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils @OPENSSL_CFLAGS@ ++AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils +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 + +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/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 + +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 +CFLAGS += -DCONFIG_IPV6 + +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH - CFLAGS += -DCONFIG_INTERNAL_SHA1 - CFLAGS += -DEAP_TLS_OPENSSL - CFLAGS += -DPKCS12_FUNCS ++CFLAGS += -DCONFIG_CRYPTO_INTERNAL ++CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT + +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/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-ctr.c \ + src/crypto/aes-eax.c \ + src/crypto/aes-encblock.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-unwrap.c \ + src/crypto/aes-wrap.c \ ++ src/crypto/des-internal.c \ ++ src/crypto/dh_group5.c \ ++ src/crypto/dh_groups.c \ ++ src/crypto/md4-internal.c \ + src/crypto/md5.c \ ++ src/crypto/md5-internal.c \ + src/crypto/md5-non-fips.c \ + src/crypto/milenage.c \ + src/crypto/ms_funcs.c \ ++ src/crypto/rc4.c \ + src/crypto/sha1.c \ ++ src/crypto/sha1-internal.c \ + src/crypto/sha1-pbkdf2.c \ + src/crypto/sha1-tlsprf.c \ + src/crypto/sha1-tprf.c \ + src/crypto/sha256.c \ - src/crypto/crypto_openssl.c \ - src/crypto/tls_openssl.c \ - src/crypto/aes.h \ - src/crypto/aes_i.h \ - src/crypto/aes_wrap.h \ - src/crypto/crypto.h \ - src/crypto/md5.h \ - src/crypto/milenage.h \ - src/crypto/ms_funcs.h \ - src/crypto/sha1.h \ - src/crypto/sha256.h \ - src/crypto/tls.h ++ src/crypto/sha256-internal.c \ ++ src/crypto/crypto_internal.c \ ++ src/crypto/crypto_internal-cipher.c \ ++ src/crypto/crypto_internal-modexp.c \ ++ src/crypto/crypto_internal-rsa.c \ ++ src/crypto/tls_internal.c \ ++ src/crypto/fips_prf_internal.c \ ++ src/crypto/aes.h \ ++ src/crypto/aes_i.h \ ++ src/crypto/aes_wrap.h \ ++ src/crypto/crypto.h \ ++ src/crypto/des_i.h \ ++ src/crypto/dh_group5.h \ ++ src/crypto/dh_groups.h \ ++ src/crypto/md5.h \ ++ src/crypto/md5_i.h \ ++ src/crypto/milenage.h \ ++ src/crypto/ms_funcs.h \ ++ src/crypto/sha1.h \ ++ src/crypto/sha1_i.h \ ++ src/crypto/sha256.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) ++ 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) $(TLS_SRCS) + +noinst_LTLIBRARIES = libeap.la diff --cc mech_eap/Makefile.am index a652182,0000000..8c6f64c mode 100644,000000..100644 --- a/mech_eap/Makefile.am +++ b/mech_eap/Makefile.am @@@ -1,190 -1,0 +1,189 @@@ +AUTOMAKE_OPTIONS = foreign + +EXTRA_DIST = gsseap_err.et radsec_err.et \ + mech_eap.exports mech_eap-noacceptor.exports radius_ad.exports \ + LICENSE AUTHORS + + +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 = mech_eap.exports +else +GSSEAP_EXPORTS = 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 \ - @RADSEC_LDFLAGS@ @OPENSSL_LDFLAGS@ @TARGET_LDFLAGS@ ++ @RADSEC_LDFLAGS@ @TARGET_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@ ++ @OPENSAML_LIBS@ @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_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_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 \ + util_radius.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 radius_ad.exports -no-undefined +radius_ad_la_LIBADD = @KRB5_LIBS@ +radius_ad_la_SOURCES = util_adshim.c authdata_plugin.h +endif +endif + +gsseap_err.h gsseap_err.c: gsseap_err.et + $(COMPILE_ET) $< + +radsec_err.h radsec_err.c: radsec_err.et + $(COMPILE_ET) $< + +radsec_err.c: radsec_err.h + +clean-generic: + rm -f gsseap_err.[ch] radsec_err.[ch] diff --cc mech_eap/gssapiP_eap.h index c763fbd,0000000..d1790a0 mode 100644,000000..100644 --- a/mech_eap/gssapiP_eap.h +++ b/mech_eap/gssapiP_eap.h @@@ -1,413 -1,0 +1,410 @@@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GSSAPIP_EAP_H_ +#define _GSSAPIP_EAP_H_ 1 + +#include "config.h" + +#ifdef HAVE_HEIMDAL_VERSION +#define KRB5_DEPRECATED /* so we can use krb5_free_unparsed_name() */ +#endif + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef WIN32 +#ifndef MAXHOSTNAMELEN +# include +# define MAXHOSTNAMELEN NI_MAXHOST +#endif +#endif + +/* GSS headers */ +#include +#include +#ifdef HAVE_HEIMDAL_VERSION +typedef struct gss_any *gss_any_t; +#else +#include +#endif +#include "gssapi_eap.h" + +#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH +typedef const gss_OID_desc *gss_const_OID; +#endif + +/* Kerberos headers */ +#include + +/* EAP headers */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef GSSEAP_ENABLE_ACCEPTOR +/* FreeRADIUS headers */ +#ifdef __cplusplus +extern "C" { +#ifndef WIN32 +#define operator fr_operator +#endif +#endif +#include +#include + +#undef pid_t + +/* libradsec headers */ +#include +#include +#ifdef __cplusplus +#ifndef WIN32 +#undef operator +#endif +} +#endif +#endif /* GSSEAP_ENABLE_ACCEPTOR */ + +#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_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; +#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_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_MASK 0xFFFF0000 + +struct gss_eap_initiator_ctx { + unsigned int idleWhile; + struct eap_peer_config eapPeerConfig; + struct eap_sm *eap; + struct wpabuf reqData; +}; + +#ifdef GSSEAP_ENABLE_ACCEPTOR +struct gss_eap_acceptor_ctx { + struct rs_context *radContext; + struct rs_connection *radConn; + char *radServer; + gss_buffer_desc state; + VALUE_PAIR *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 + +/* 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) + +/* upper bound of RADIUS error range must be kept in sync with radsec.h */ +#define IS_RADIUS_ERROR(err) ((err) >= ERROR_TABLE_BASE_rse && \ + (err) <= ERROR_TABLE_BASE_rse + 20) + +/* 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, + ssize_t desired_output_len, + 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); + +#ifdef __cplusplus +} +#endif + +#endif /* _GSSAPIP_EAP_H_ */ diff --cc mech_eap/gssapi_eap.h index 02f132f,0000000..588665b mode 100644,000000..100644 --- a/mech_eap/gssapi_eap.h +++ b/mech_eap/gssapi_eap.h @@@ -1,97 -1,0 +1,90 @@@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GSSAPI_EAP_H_ +#define _GSSAPI_EAP_H_ 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * GSS EAP mechanism OIDs. + */ +extern gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM; +extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM; + +/* + * Mechanism name OID. + */ +extern gss_OID GSS_EAP_NT_EAP_NAME; + +/* + * The libradsec configuration file; defaults to radsec.conf + * in the system configuration directory if unspecified. + */ +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE; + +/* + * The stanza in the libradsec configuration file; defaults + * to "gss-eap" if unspecified. + */ +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA; + +/* + * Flags as a 32-bit integer in network byte order, + * followed by a boolean octet indicating whether to + * clear the specified flags (if absent, defaults to + * FALSE, ie. set flags). + */ +extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG; + +/* + * Password; for mechanism glues that do not support + * gss_acquire_cred_with_password(), this can be set + * on an existing credentials handle. + */ +extern gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD; + +/* - * Path to PKCS#12 private key file for use with EAP-TLS - * authentication. - */ - extern gss_OID GSS_EAP_CRED_SET_CRED_PRIVATE_KEY; - - - /* + * Credentials flag indicating the local attributes + * processing should be skipped. + */ +#define GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG 0x00000001 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _GSSAPI_EAP_H_ */ diff --cc mech_eap/init_sec_context.c index 8a877fd,0000000..e99b479 mode 100644,000000..100644 --- a/mech_eap/init_sec_context.c +++ b/mech_eap/init_sec_context.c @@@ -1,1105 -1,0 +1,1097 @@@ +/* + * 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" + +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; + } + + 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 GSSEAP_UNUSED, + const char *name GSSEAP_UNUSED) +{ + return NULL; +} + +static void +peerNotifyPending(void *ctx GSSEAP_UNUSED) +{ +} + +static struct eapol_callbacks gssEapPolicyCallbacks = { + peerGetConfig, + peerGetBool, + peerSetBool, + peerGetInt, + peerSetInt, + peerGetEapReqData, + peerSetConfigBlob, + peerGetConfigBlob, + peerNotifyPending, +}; + +#ifdef GSSEAP_DEBUG +extern int wpa_debug_level; +#endif + +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; + 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; + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + GSSEAP_KRB_INIT(&krbContext); + + eapPeerConfig->fragment_size = 1024; +#ifdef GSSEAP_DEBUG + wpa_debug_level = 0; +#endif + + 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; - } ++ 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; + - if (cred->flags & CRED_FLAG_CERTIFICATE) { - eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value; - eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value; - eapPeerConfig->private_key_passwd = (unsigned 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 reqFlags) +{ + OM_uint32 major; + const unsigned char *key; + size_t keyLength; + +#if 1 + /* XXX actually check for mutual auth */ + if (reqFlags & GSS_C_MUTUAL_FLAG) + ctx->gssFlags |= GSS_C_MUTUAL_FLAG; +#endif + + /* 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 = ERROR_TABLE_BASE_eapg + load_uint32_be(&p[4]); + + 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 && + ctx->acceptorName == GSS_C_NO_NAME) { + /* Accept target name hint from acceptor */ + major = gssEapImportName(minor, inputToken, + GSS_C_NT_USER_NAME, + ctx->mechanismUsed, + &ctx->acceptorName); + if (GSS_ERROR(major)) + return major; + } + + /* + * 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; + } + + 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, reqFlags); + 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; + + 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; + gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; + + if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) + buffer = chanBindings->application_data; + + major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT, + &buffer, NULL, outputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_ASSERT(outputToken->value != NULL); + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + 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, + 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, + SM_ITOK_FLAG_REQUIRED, + 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); + + return major; +} diff --cc mech_eap/set_cred_option.c index 98bb482,0000000..7bb9b7b mode 100644,000000..100644 --- a/mech_eap/set_cred_option.c +++ b/mech_eap/set_cred_option.c @@@ -1,223 -1,0 +1,208 @@@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Set an extended property on a credential handle. + */ + +#include "gssapiP_eap.h" + +static OM_uint32 +setCredRadiusConfigFile(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER; + + if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) { + major = duplicateBuffer(minor, buffer, &configFileBuffer); + if (GSS_ERROR(major)) + return major; + } + + gss_release_buffer(&tmpMinor, &cred->radiusConfigFile); + cred->radiusConfigFile = configFileBuffer; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +setCredRadiusConfigStanza(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER; + + if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) { + major = duplicateBuffer(minor, buffer, &configStanzaBuffer); + if (GSS_ERROR(major)) + return major; + } + + gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza); + cred->radiusConfigStanza = configStanzaBuffer; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +setCredFlag(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + OM_uint32 flags; + unsigned char *p; + + if (buffer == GSS_C_NO_BUFFER) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE; + } + + if (buffer->length < 4) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_FAILURE; + } + + p = (unsigned char *)buffer->value; + + flags = load_uint32_be(buffer->value) & CRED_FLAG_PUBLIC_MASK; + + if (buffer->length > 4 && p[4]) + cred->flags &= ~(flags); + else + cred->flags |= flags; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +setCredPassword(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_OID oid GSSEAP_UNUSED, + const gss_buffer_t buffer) +{ + return gssEapSetCredPassword(minor, cred, buffer); +} + - static OM_uint32 - setCredPrivateKey(OM_uint32 *minor, - gss_cred_id_t cred, - const gss_OID oid GSSEAP_UNUSED, - const gss_buffer_t buffer) - { - return gssEapSetCredClientCertificate(minor, cred, GSS_C_NO_BUFFER, buffer); - } - +static struct { + gss_OID_desc oid; + OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred, + const gss_OID, const gss_buffer_t); +} setCredOps[] = { + /* 1.3.6.1.4.1.5322.22.3.3.1 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x01" }, + setCredRadiusConfigFile, + }, + /* 1.3.6.1.4.1.5322.22.3.3.2 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x02" }, + setCredRadiusConfigStanza, + }, + /* 1.3.6.1.4.1.5322.22.3.3.3 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x03" }, + setCredFlag, + }, + /* 1.3.6.1.4.1.5322.22.3.3.4 */ + { + { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x04" }, + setCredPassword, + }, - /* 1.3.6.1.4.1.5322.22.3.3.5 */ - { - { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x05" }, - setCredPrivateKey, - }, +}; + +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE = &setCredOps[0].oid; +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA = &setCredOps[1].oid; +gss_OID GSS_EAP_CRED_SET_CRED_FLAG = &setCredOps[2].oid; +gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD = &setCredOps[3].oid; - gss_OID GSS_EAP_CRED_SET_CRED_PRIVATE_KEY = &setCredOps[4].oid; + +OM_uint32 GSSAPI_CALLCONV +gssspi_set_cred_option(OM_uint32 *minor, + gss_cred_id_t *pCred, + const gss_OID desired_object, + const gss_buffer_t value) +{ + OM_uint32 major; + gss_cred_id_t cred = *pCred; + int i; + + if (cred == GSS_C_NO_CREDENTIAL) { + *minor = EINVAL; + return GSS_S_UNAVAILABLE; + } + + GSSEAP_MUTEX_LOCK(&cred->mutex); + + major = GSS_S_UNAVAILABLE; + *minor = GSSEAP_BAD_CRED_OPTION; + + for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) { + if (oidEqual(&setCredOps[i].oid, desired_object)) { + major = (*setCredOps[i].setOption)(minor, cred, + desired_object, value); + break; + } + } + + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + + return major; +} + +#if 0 +OM_uint32 +gsseap_set_cred_flag(OM_uint32 *minor, + gss_cred_id_t cred, + OM_uint32 flag, + int clear) +{ + unsigned char buf[5]; + gss_buffer_desc value; + + value.length = sizeof(buf); + value.value = buf; + + store_uint32_be(flag, buf); + buf[4] = (clear != 0); + + return gssspi_set_cred_option(minor, &cred, + GSS_EAP_CRED_SET_CRED_FLAG, &value); +} +#endif diff --cc mech_eap/util.h index 7a6c094,0000000..4f54d41 mode 100644,000000..100644 --- a/mech_eap/util.h +++ b/mech_eap/util.h @@@ -1,1038 -1,0 +1,1032 @@@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Portions Copyright 2003-2010 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * Utility functions. + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ 1 + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#endif +#include +#include + +#include + +#ifdef WIN32 +#define inline __inline +#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)) + +#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_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) + +#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); + +OM_uint32 +gssEapCompareName(OM_uint32 *minor, + gss_name_t name1, + gss_name_t name2, + 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 +#define GSSEAP_CALLOC calloc +#define GSSEAP_MALLOC malloc +#define GSSEAP_FREE free +#define GSSEAP_REALLOC realloc +#endif + +#ifndef GSSAPI_CALLCONV +#define GSSAPI_CALLCONV KRB5_CALLCONV +#endif + +#ifndef GSSEAP_ASSERT +#include +#define GSSEAP_ASSERT(x) assert((x)) +#endif /* !GSSEAP_ASSERT */ + +#ifdef WIN32 +#define GSSEAP_CONSTRUCTOR +#define GSSEAP_DESTRUCTOR +#else +#define GSSEAP_CONSTRUCTOR __attribute__((constructor)) +#define GSSEAP_DESTRUCTOR __attribute__((destructor)) +#endif + +#define GSSEAP_NOT_IMPLEMENTED do { \ + GSSEAP_ASSERT(0 && "not implemented"); \ + *minor = ENOSYS; \ + return GSS_S_FAILURE; \ + } while (0) + +#ifdef WIN32 + +#include + +#define GSSEAP_GET_LAST_ERROR() (GetLastError()) /* XXX FIXME */ + +#define GSSEAP_MUTEX CRITICAL_SECTION +#define GSSEAP_MUTEX_INIT(m) (InitializeCriticalSection((m)), 0) +#define GSSEAP_MUTEX_DESTROY(m) DeleteCriticalSection((m)) +#define GSSEAP_MUTEX_LOCK(m) EnterCriticalSection((m)) +#define GSSEAP_MUTEX_UNLOCK(m) LeaveCriticalSection((m)) +#define GSSEAP_ONCE_LEAVE do { return TRUE; } while (0) + +/* Thread-local is handled separately */ + +#define GSSEAP_THREAD_ONCE INIT_ONCE +#define GSSEAP_ONCE_CALLBACK(cb) BOOL CALLBACK cb(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) +#define GSSEAP_ONCE(o, i) InitOnceExecuteOnce((o), (i), NULL, NULL) +#define GSSEAP_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT + +#else + +#include + +#define GSSEAP_GET_LAST_ERROR() (errno) + +#define GSSEAP_MUTEX pthread_mutex_t +#define GSSEAP_MUTEX_INIT(m) pthread_mutex_init((m), NULL) +#define GSSEAP_MUTEX_DESTROY(m) pthread_mutex_destroy((m)) +#define GSSEAP_MUTEX_LOCK(m) pthread_mutex_lock((m)) +#define GSSEAP_MUTEX_UNLOCK(m) pthread_mutex_unlock((m)) + +#define GSSEAP_THREAD_KEY pthread_key_t +#define GSSEAP_KEY_CREATE(k, d) pthread_key_create((k), (d)) +#define GSSEAP_GETSPECIFIC(k) pthread_getspecific((k)) +#define GSSEAP_SETSPECIFIC(k, d) pthread_setspecific((k), (d)) + +#define GSSEAP_THREAD_ONCE pthread_once_t +#define GSSEAP_ONCE_CALLBACK(cb) void cb(void) +#define GSSEAP_ONCE(o, i) pthread_once((o), (i)) +#define GSSEAP_ONCE_INITIALIZER PTHREAD_ONCE_INIT +#define GSSEAP_ONCE_LEAVE do { } while (0) + +#endif /* WIN32 */ + +/* Helper functions */ +static inline void +store_uint16_be(uint16_t val, void *vp) +{ + unsigned char *p = (unsigned char *)vp; + + p[0] = (val >> 8) & 0xff; + p[1] = (val ) & 0xff; +} + +static inline uint16_t +load_uint16_be(const void *cvp) +{ + const unsigned char *p = (const unsigned char *)cvp; + + return (p[1] | (p[0] << 8)); +} + +static inline void +store_uint32_be(uint32_t val, void *vp) +{ + unsigned char *p = (unsigned char *)vp; + + p[0] = (val >> 24) & 0xff; + p[1] = (val >> 16) & 0xff; + p[2] = (val >> 8) & 0xff; + p[3] = (val ) & 0xff; +} + +static inline uint32_t +load_uint32_be(const void *cvp) +{ + const unsigned char *p = (const unsigned char *)cvp; + + return (p[3] | (p[2] << 8) + | ((uint32_t) p[1] << 16) + | ((uint32_t) p[0] << 24)); +} + +static inline void +store_uint64_be(uint64_t val, void *vp) +{ + unsigned char *p = (unsigned char *)vp; + + p[0] = (unsigned char)((val >> 56) & 0xff); + p[1] = (unsigned char)((val >> 48) & 0xff); + p[2] = (unsigned char)((val >> 40) & 0xff); + p[3] = (unsigned char)((val >> 32) & 0xff); + p[4] = (unsigned char)((val >> 24) & 0xff); + p[5] = (unsigned char)((val >> 16) & 0xff); + p[6] = (unsigned char)((val >> 8) & 0xff); + p[7] = (unsigned char)((val ) & 0xff); +} + +static inline uint64_t +load_uint64_be(const void *cvp) +{ + const unsigned char *p = (const unsigned char *)cvp; + + return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4); +} + +static inline unsigned char * +store_buffer(gss_buffer_t buffer, void *vp, int wide_nums) +{ + unsigned char *p = (unsigned char *)vp; + + if (wide_nums) { + store_uint64_be(buffer->length, p); + p += 8; + } else { + store_uint32_be(buffer->length, p); + p += 4; + } + + if (buffer->value != NULL) { + memcpy(p, buffer->value, buffer->length); + p += buffer->length; + } + + return p; +} + +static inline unsigned char * +load_buffer(const void *cvp, size_t length, gss_buffer_t buffer) +{ + buffer->length = 0; + buffer->value = GSSEAP_MALLOC(length); + if (buffer->value == NULL) + return NULL; + buffer->length = length; + memcpy(buffer->value, cvp, length); + return (unsigned char *)cvp + length; +} + +static inline unsigned char * +store_oid(gss_OID oid, void *vp) +{ + gss_buffer_desc buf; + + if (oid != GSS_C_NO_OID) { + buf.length = oid->length; + buf.value = oid->elements; + } else { + buf.length = 0; + buf.value = NULL; + } + + return store_buffer(&buf, vp, FALSE); +} + +static inline void +krbDataToGssBuffer(krb5_data *data, gss_buffer_t buffer) +{ + buffer->value = (void *)data->data; + buffer->length = data->length; +} + +static inline void +krbPrincComponentToGssBuffer(krb5_principal krbPrinc, + int index, gss_buffer_t buffer) +{ +#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 void +krbPrincRealmToGssBuffer(krb5_principal krbPrinc, gss_buffer_t buffer) +{ +#ifdef HAVE_HEIMDAL_VERSION + buffer->value = (void *)KRB_PRINC_REALM(krbPrinc); + buffer->length = strlen((char *)buffer->value); +#else + krbDataToGssBuffer(KRB_PRINC_REALM(krbPrinc), buffer); +#endif +} + +static inline void +gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data) +{ + data->data = (char *)buffer->value; + data->length = buffer->length; +} + +/* util_tld.c */ +struct gss_eap_status_info; + +struct gss_eap_thread_local_data { + krb5_context krbContext; + struct gss_eap_status_info *statusInfo; +}; + +struct gss_eap_thread_local_data * +gssEapGetThreadLocalData(void); + +void +gssEapDestroyStatusInfo(struct gss_eap_status_info *status); + +void +gssEapDestroyKrbContext(krb5_context context); + +#ifdef __cplusplus +} +#endif + +#ifdef GSSEAP_ENABLE_ACCEPTOR +#include "util_json.h" +#include "util_attr.h" +#include "util_base64.h" +#endif /* GSSEAP_ENABLE_ACCEPTOR */ +#ifdef GSSEAP_ENABLE_REAUTH +#include "util_reauth.h" +#endif + +#endif /* _UTIL_H_ */ diff --cc mech_eap/util_cred.c index 53a19a7,0000000..746bd61 mode 100644,000000..100644 --- a/mech_eap/util_cred.c +++ b/mech_eap/util_cred.c @@@ -1,844 -1,0 +1,756 @@@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Utility routines for credential handles. + */ + +#include "gssapiP_eap.h" + +#ifdef WIN32 +# include /* may need to use ShFolder.h instead */ +# include +#else +# include +#endif + +OM_uint32 +gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred) +{ + OM_uint32 tmpMinor; + gss_cred_id_t cred; + + *pCred = GSS_C_NO_CREDENTIAL; + + cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred)); + if (cred == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) { + *minor = GSSEAP_GET_LAST_ERROR(); + gssEapReleaseCred(&tmpMinor, &cred); + return GSS_S_FAILURE; + } + + *pCred = cred; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static void +zeroAndReleasePassword(gss_buffer_t password) +{ + 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->subjectNameConstraint); + gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint); - gss_release_buffer(&tmpMinor, &cred->privateKey); - gss_release_buffer(&tmpMinor, &cred->clientCertificate); + +#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, - gss_buffer_t defaultPrivateKey) ++ 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; + } + - if (defaultPrivateKey != GSS_C_NO_BUFFER) { - defaultPrivateKey->length = 0; - defaultPrivateKey->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 if (i == 2) - dst = defaultPrivateKey; + 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); - gss_release_buffer(&tmpMinor, defaultPrivateKey); + } + + memset(buf, 0, sizeof(buf)); + + return major; +} + +gss_OID +gssEapPrimaryMechForCred(gss_cred_id_t cred) +{ + gss_OID nameMech = GSS_C_NO_OID; + + if (cred->mechanisms != GSS_C_NO_OID_SET && + cred->mechanisms->count == 1) + nameMech = &cred->mechanisms->elements[0]; + + return nameMech; +} + +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); + + 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, GSS_C_NO_BUFFER); ++ 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->subjectNameConstraint.value != NULL) + duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint); + if (src->subjectAltNameConstraint.value != NULL) + duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint); - 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; - gss_buffer_desc defaultPrivateKey = GSS_C_EMPTY_BUFFER; + int isDefaultIdentity = FALSE; + - major = readStaticIdentityFile(minor, &defaultIdentity, - &defaultPassword, &defaultPrivateKey); ++ 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, &isDefaultIdentity); + if (GSS_ERROR(major)) + goto cleanup; + } + } + - if (isDefaultIdentity) { - if (defaultPrivateKey.length != 0) { - major = gssEapSetCredClientCertificate(minor, cred, GSS_C_NO_BUFFER, - &defaultPrivateKey); - if (GSS_ERROR(major)) - goto cleanup; - } - - if ((cred->flags & CRED_FLAG_PASSWORD) == 0) { - major = gssEapSetCredPassword(minor, cred, &defaultPassword); - 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); - gss_release_buffer(&tmpMinor, &defaultPrivateKey); + + 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) { ++ if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 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; +}