Skip to content

Commit

Permalink
Add support for retrieving the mech_ssf
Browse files Browse the repository at this point in the history
In the latest MIT Kerberos implementation it is possible to extract
the calculated SSF wich is based on the encryption type that has been
used to establish the GSSAPI security context.

Use this method if available or fall back to the old "DES" value.

Signed-off-by: Simo Sorce <simo@redhat.com>
  • Loading branch information
simo5 authored and brong committed Jan 29, 2018
1 parent 62c19a0 commit 4b0306d
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 11 deletions.
20 changes: 20 additions & 0 deletions m4/sasl2.m4
Expand Up @@ -290,6 +290,26 @@ if test "$gssapi" != no; then
cmu_save_LIBS="$LIBS"
LIBS="$LIBS $GSSAPIBASE_LIBS"
AC_CHECK_FUNCS(gss_inquire_sec_context_by_oid)
if test "$ac_cv_func_gss_inquire_sec_context_by_oid" = no ; then
if test "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"; then
AC_CHECK_DECL(gss_inquire_sec_context_by_oid,
[AC_DEFINE(HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID,1,
[Define if your GSSAPI implementation defines gss_inquire_sec_context_by_oid])],,
[
AC_INCLUDES_DEFAULT
#include <gssapi/gssapi_ext.h>
])
fi
fi
if test "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"; then
AC_EGREP_HEADER(GSS_C_SEC_CONTEXT_SASL_SSF, gssapi/gssapi_ext.h,
[AC_DEFINE(HAVE_GSS_C_SEC_CONTEXT_SASL_SSF,,
[Define if your GSSAPI implementation defines GSS_C_SEC_CONTEXT_SASL_SSF])])
fi
cmu_save_LIBS="$LIBS"
LIBS="$LIBS $GSSAPIBASE_LIBS"
AC_MSG_CHECKING([for SPNEGO support in GSSAPI libraries])
AC_TRY_RUN([
#ifdef HAVE_GSSAPI_H
Expand Down
102 changes: 91 additions & 11 deletions plugins/gssapi.c
Expand Up @@ -51,7 +51,12 @@
#include <gssapi/gssapi.h>
#endif

#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H
#include <gssapi/gssapi_krb5.h>
#endif
#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
#include <gssapi/gssapi_ext.h>
#endif

#ifdef WIN32
# include <winsock2.h>
Expand Down Expand Up @@ -98,18 +103,25 @@ extern gss_OID gss_nt_service_name;
/* Check if CyberSafe flag is defined */
#ifdef CSF_GSS_C_DES3_FLAG
#define K5_MAX_SSF 112
#define K5_MIN_SSF 112
#endif

/* Heimdal and MIT use the following */
#ifdef GSS_KRB5_CONF_C_QOP_DES3_KD
#define K5_MAX_SSF 112
#define K5_MIN_SSF 112
#endif

#endif

#ifndef K5_MAX_SSF
/* All modern Kerberos implementations support AES */
#define K5_MAX_SSF 256
#endif

/* All Kerberos implementations support DES */
#define K5_MAX_SSF 56
#ifndef K5_MIN_SSF
#define K5_MIN_SSF 56
#endif

/* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
Expand Down Expand Up @@ -674,6 +686,47 @@ static int gssapi_wrap_sizes(context_t *text, sasl_out_params_t *oparams)
return SASL_OK;
}

#if !defined(HAVE_GSS_C_SEC_CONTEXT_SASL_SSF)
gss_OID_desc gss_sasl_ssf = {
11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"
};
gss_OID GSS_C_SEC_CONTEXT_SASL_SSF = &gss_sasl_ssf;
#endif

static int gssapi_get_ssf(context_t *text, sasl_ssf_t *mech_ssf)
{
#ifdef HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID
OM_uint32 maj_stat = 0, min_stat = 0;
gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF;
uint32_t ssf;

maj_stat = gss_inquire_sec_context_by_oid(&min_stat, text->gss_ctx,
ssf_oid, &bufset);
switch (maj_stat) {
case GSS_S_UNAVAILABLE:
/* Not supported by the library, fallback to default */
goto fallback;
case GSS_S_COMPLETE:
if ((bufset->count != 1) || (bufset->elements[0].length != 4)) {
/* Malformed bufset, fail */
(void)gss_release_buffer_set(&min_stat, &bufset);
return SASL_FAIL;
}
memcpy(&ssf, bufset->elements[0].value, 4);
(void)gss_release_buffer_set(&min_stat, &bufset);
*mech_ssf = ntohl(ssf);
return SASL_OK;
default:
return SASL_FAIL;
}

fallback:
#endif
*mech_ssf = K5_MIN_SSF;
return SASL_OK;
}

/* The GSS-SPNEGO mechanism does not do SSF negotiation, instead it uses the
* flags negotiated by GSSAPI to determine If confidentiality or integrity are
* used. These flags are stored in text->qop transalated as layers by the
Expand All @@ -687,7 +740,10 @@ static int gssapi_spnego_ssf(context_t *text,
if (text->qop & LAYER_CONFIDENTIALITY) {
oparams->encode = &gssapi_privacy_encode;
oparams->decode = &gssapi_decode;
oparams->mech_ssf = K5_MAX_SSF;
ret = gssapi_get_ssf(text, &oparams->mech_ssf);
if (ret != SASL_OK) {
return ret;
}
} else if (text->qop & LAYER_INTEGRITY) {
oparams->encode = &gssapi_integrity_encode;
oparams->decode = &gssapi_decode;
Expand Down Expand Up @@ -1089,6 +1145,7 @@ gssapi_server_mech_ssfcap(context_t *text,
gss_buffer_desc real_input_token, real_output_token;
OM_uint32 maj_stat = 0, min_stat = 0;
unsigned char sasldata[4];
sasl_ssf_t mech_ssf;
int ret;

input_token = &real_input_token;
Expand Down Expand Up @@ -1149,9 +1206,14 @@ gssapi_server_mech_ssfcap(context_t *text,
params->props.maxbufsize) {
sasldata[0] |= LAYER_INTEGRITY;
}
ret = gssapi_get_ssf(text, &mech_ssf);
if (ret != SASL_OK) {
sasl_gss_free_context_contents(text);
return ret;
}
if ((text->qop & LAYER_CONFIDENTIALITY) &&
text->requiressf <= K5_MAX_SSF &&
text->limitssf >= K5_MAX_SSF &&
text->requiressf <= mech_ssf &&
text->limitssf >= mech_ssf &&
params->props.maxbufsize) {
sasldata[0] |= LAYER_CONFIDENTIALITY;
}
Expand Down Expand Up @@ -1271,10 +1333,18 @@ gssapi_server_mech_ssfreq(context_t *text,
} else if (/* For compatibility with broken clients setting both bits */
(layerchoice & (LAYER_CONFIDENTIALITY | LAYER_INTEGRITY)) &&
(text->qop & LAYER_CONFIDENTIALITY)) { /* privacy */
int ret;
oparams->encode = &gssapi_privacy_encode;
oparams->decode = &gssapi_decode;
/* FIX ME: Need to extract the proper value here */
oparams->mech_ssf = K5_MAX_SSF;

ret = gssapi_get_ssf(text, &oparams->mech_ssf);
if (ret != SASL_OK) {
GSS_LOCK_MUTEX_CTX(params->utils, text);
gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX_CTX(params->utils, text);
sasl_gss_free_context_contents(text);
return ret;
}
} else {
/* not a supported encryption layer */
SETERROR(text->utils,
Expand Down Expand Up @@ -1845,6 +1915,8 @@ static int gssapi_client_mech_step(void *conn_context,
unsigned int alen, external = params->external_ssf;
sasl_ssf_t need, allowed;
char serverhas, mychoice;
sasl_ssf_t mech_ssf;
int ret;

real_input_token.value = (void *) serverin;
real_input_token.length = serverinlen;
Expand Down Expand Up @@ -1879,8 +1951,17 @@ static int gssapi_client_mech_step(void *conn_context,
return SASL_FAIL;
}

ret = gssapi_get_ssf(text, &mech_ssf);
if (ret != SASL_OK) {
GSS_LOCK_MUTEX_CTX(params->utils, text);
gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX_CTX(params->utils, text);
sasl_gss_free_context_contents(text);
return SASL_FAIL;
}

/* taken from kerberos.c */
if (secprops->min_ssf > (K5_MAX_SSF + external)) {
if (secprops->min_ssf > (mech_ssf + external)) {
return SASL_TOOWEAK;
} else if (secprops->min_ssf > secprops->max_ssf) {
return SASL_BADPARAM;
Expand All @@ -1904,17 +1985,16 @@ static int gssapi_client_mech_step(void *conn_context,

/* use the strongest layer available */
if ((text->qop & LAYER_CONFIDENTIALITY) &&
allowed >= K5_MAX_SSF &&
need <= K5_MAX_SSF &&
allowed >= mech_ssf &&
need <= mech_ssf &&
(serverhas & LAYER_CONFIDENTIALITY)) {

const char *ad_compat;

/* encryption */
oparams->encode = &gssapi_privacy_encode;
oparams->decode = &gssapi_decode;
/* FIX ME: Need to extract the proper value here */
oparams->mech_ssf = K5_MAX_SSF;
oparams->mech_ssf = mech_ssf;
mychoice = LAYER_CONFIDENTIALITY;

if (serverhas & LAYER_INTEGRITY) {
Expand Down

0 comments on commit 4b0306d

Please sign in to comment.