Skip Menu |
 

To: rt@krbdev.mit.edu
Subject: SPNEGO init/accept output parameter bugs
Date: Tue, 05 Nov 2019 13:47:37 -0500
From: ghudson@mit.edu
gss_init_sec_context() and gss_accept_sec_context() both output a token and either create or modify a security context.  There are some additional outputs: actual_mech_type, ret_flags, and time_rec for gss_init_sec_context(), and src_name, mech_type, ret_flags, time_rec, and delegated_cred_handle for gss_accept_sec_context().  RFC 2744 sections 5.1 and 5.19 define some rules for how these parameters should be set when GSS_S_CONTINUE_NEEDED is returned.

Although the mechglue initializes most output parameters, it does not do so for ret_flags and time_rec.  This is a separate bug, which impacts the following SPNEGO misbehaviors; if SPNEGO does not set these output parameters, the caller's value will remain unchanged.

The current SPNEGO implementation has the following bugs related to the additional output parameters:

* gss_init_sec_context() only sets ret_flags if the underlying mech is called and returns GSS_S_COMPLETE, or if SPNEGO itself will return GSS_S_COMPLETE.  gss_accept_sec_context() initializes ret_flags to 0, and only sets ret_flags to another value if the underlying mech is called and returns GSS_S_COMPLETE; ret_flags could remain as 0 on SPNEGO's final return from gss_accept_sec_context(), if the MIC exchange forces an extra round trip.

* gss_init_sec_context() and gss_accept_sec_context() do not filter out PROT_READY from ret_flags as required by RFC 4178.

* gss_init_sec_context() and gss_accept_sec_context() pass time_rec directly to the underlying mech.  gss_accept_sec_context() initializes time_rec to 0 but gss_init_sec_context() does not.  Neither function will set time_rec to a meaningful value if the underlying mech is not called on the final SPNEGO call due to the MIC exchange.  Note that time_rec is relative to the current time; if SPNEGO records time_rec from the underlying mech at one step and reports it to the caller at a later step, the time differential between steps could render that value inaccurate.  SPNEGO could either adjust the value by the differential, or call gss_context_time() on the underlying context.

* gss_accept_sec_context() initializes mech_type to GSS_C_NO_OID and passes it directly to the underlying mech.  If the underlying mech is not called on the final step, mech_type will remain as GSS_C_NO_OID.

* gss_accept_sec_context() initializes delegated_cred_handle to GSS_C_NO_CREDENTIAL and passes it directly to the underlying mech.  SPNEGO could report a delegated cred to the caller too early (before the MIC exchange) and not on the final call.

* gss_accept_sec_context() could leak a value of src_name (recorded as sc->internal_name) if the underlying mech reports it twice.  RFC 2744 doesn't explicitly prohibit this, although it seems like it should be unusual.
 
Subject: git commit
From: ghudson@mit.edu
Download (untitled) / with headers
text/plain 1.1KiB

Fix SPNEGO output parameter bugs

When accepting, do not leak a name if the underlying mech reports a
src_name twice. Record mech_type and delegated_cred_handle and report
them to the caller at the final SPNEGO step, not when the underlying
mech reports them.

When initiating or accepting, report ret_flags at every step, and
filter out PROT_READY as required by RFC 4178 section 3.1. Report a
time_rec value at the final step even if we didn't call into the
underlying mech, using a call to gss_context_time() if necessary.

In the mechglue, initialize ret_flags and time_rec for both
gss_initialize_sec_context() and gss_accept_sec_context().

https://github.com/krb5/krb5/commit/24b844714dea3e47b17511746b5df5b6ddf13d43
Author: Greg Hudson <ghudson@mit.edu>
Commit: 24b844714dea3e47b17511746b5df5b6ddf13d43
Branch: master
src/lib/gssapi/mechglue/g_accept_sec_context.c | 6 ++
src/lib/gssapi/mechglue/g_init_sec_context.c | 6 ++
src/lib/gssapi/spnego/gssapiP_spnego.h | 1 +
src/lib/gssapi/spnego/spnego_mech.c | 85 +++++++++++++-----------
4 files changed, 60 insertions(+), 38 deletions(-)