krb5 commit: Process SPNEGO error tokens through mech
Greg Hudson
ghudson at mit.edu
Wed Feb 6 15:10:20 EST 2019
https://github.com/krb5/krb5/commit/51d3f2ab706197bf8fea82e0a7e9c877d6563986
commit 51d3f2ab706197bf8fea82e0a7e9c877d6563986
Author: Luke Howard <lukeh at padl.com>
Date: Fri Dec 28 23:13:05 2018 +1100
Process SPNEGO error tokens through mech
In the SPNEGO initiator code, if the acceptor returns a token with
negState=REJCET and a mechanism token, process the token through the
mech to get a better error status.
[ghudson at mit.edu: modified approach for clarity and to prevent some
edge cases; rewrote commit message]
ticket: 8775 (new)
src/lib/gssapi/spnego/spnego_mech.c | 48 +++++++++++++++++++++++-----------
src/tests/gssapi/t_err.c | 11 ++++++--
src/tests/gssapi/t_gssapi.py | 1 +
3 files changed, 41 insertions(+), 19 deletions(-)
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 4d7506e..01d4135 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -129,7 +129,7 @@ init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
gss_OID, gss_buffer_t *, gss_buffer_t *, send_token_flag *);
static OM_uint32
init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
- gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
+ OM_uint32, gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
send_token_flag *);
@@ -724,11 +724,20 @@ init_ctx_cont(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
&supportedMech, responseToken, mechListMIC);
if (ret != GSS_S_COMPLETE)
goto cleanup;
- if (*acc_negState == REJECT) {
- *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
- map_errcode(minor_status);
+
+ /* Bail out now on a reject with no error token. If we have an error
+ * token, keep going and get a better error status from the mech. */
+ if (*acc_negState == REJECT && *responseToken == GSS_C_NO_BUFFER) {
+ if (!sc->nego_done) {
+ /* RFC 4178 says to return GSS_S_BAD_MECH on a
+ * mechanism negotiation failure. */
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ map_errcode(minor_status);
+ ret = GSS_S_BAD_MECH;
+ } else {
+ ret = GSS_S_FAILURE;
+ }
*tokflag = NO_TOKEN_SEND;
- ret = GSS_S_FAILURE;
goto cleanup;
}
/*
@@ -886,6 +895,7 @@ static OM_uint32
init_ctx_call_init(OM_uint32 *minor_status,
spnego_gss_ctx_id_t sc,
spnego_gss_cred_id_t spcred,
+ OM_uint32 acc_negState,
gss_name_t target_name,
OM_uint32 req_flags,
OM_uint32 time_req,
@@ -918,6 +928,14 @@ init_ctx_call_init(OM_uint32 *minor_status,
mechtok_out,
&sc->ctx_flags,
time_rec);
+
+ /* Bail out if the acceptor gave us an error token but the mech didn't
+ * see it as an error. */
+ if (acc_negState == REJECT && !GSS_ERROR(ret)) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+
if (ret == GSS_S_COMPLETE) {
sc->mech_complete = 1;
if (ret_flags != NULL)
@@ -959,10 +977,10 @@ init_ctx_call_init(OM_uint32 *minor_status,
gss_release_buffer(&tmpmin, &sc->DER_mechTypes);
if (put_mech_set(sc->mech_set, &sc->DER_mechTypes) < 0)
goto fail;
- tmpret = init_ctx_call_init(&tmpmin, sc, spcred, target_name,
- req_flags, time_req, mechtok_in,
- actual_mech, mechtok_out, ret_flags,
- time_rec, send_token);
+ tmpret = init_ctx_call_init(&tmpmin, sc, spcred, acc_negState,
+ target_name, req_flags, time_req,
+ mechtok_in, actual_mech, mechtok_out,
+ ret_flags, time_rec, send_token);
if (HARD_ERROR(tmpret))
goto fail;
*minor_status = tmpmin;
@@ -1060,13 +1078,11 @@ spnego_gss_init_sec_context(
/* Step 2: invoke the selected or optimistic mechanism's
* gss_init_sec_context function, if it didn't complete previously. */
if (!spnego_ctx->mech_complete) {
- ret = init_ctx_call_init(
- minor_status, spnego_ctx, spcred,
- target_name, req_flags,
- time_req, mechtok_in,
- actual_mech, &mechtok_out,
- ret_flags, time_rec,
- &send_token);
+ ret = init_ctx_call_init(minor_status, spnego_ctx, spcred,
+ acc_negState, target_name, req_flags,
+ time_req, mechtok_in, actual_mech,
+ &mechtok_out, ret_flags, time_rec,
+ &send_token);
if (ret != GSS_S_COMPLETE)
goto cleanup;
diff --git a/src/tests/gssapi/t_err.c b/src/tests/gssapi/t_err.c
index b7c32b4..3a9c47b 100644
--- a/src/tests/gssapi/t_err.c
+++ b/src/tests/gssapi/t_err.c
@@ -74,11 +74,16 @@ main(int argc, char *argv[])
gss_buffer_desc itok, atok;
gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT;
- if (argc != 2) {
- fprintf(stderr, "Usage: %s targetname\n", argv[0]);
+ argv++;
+ if (*argv != NULL && strcmp(*argv, "--spnego") == 0) {
+ mech = &mech_spnego;
+ argv++;
+ }
+ if (*argv == NULL || argv[1] != NULL) {
+ fprintf(stderr, "Usage: t_err targetname\n");
return 1;
}
- tname = import_name(argv[1]);
+ tname = import_name(*argv);
/* Get the initial context token. */
flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_MUTUAL_FLAG;
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
index 8428e82..54d5cf5 100755
--- a/src/tests/gssapi/t_gssapi.py
+++ b/src/tests/gssapi/t_gssapi.py
@@ -178,6 +178,7 @@ if krb5_mech not in out or spnego_mech not in out:
# Test that accept_sec_context can produce an error token and
# init_sec_context can interpret it.
realm.run(['./t_err', 'p:' + realm.host_princ])
+realm.run(['./t_err', '--spnego', 'p:' + realm.host_princ])
# Test the GSS_KRB5_CRED_NO_CI_FLAGS_X cred option.
realm.run(['./t_ciflags', 'p:' + realm.host_princ])
More information about the cvs-krb5
mailing list