Skip Menu |
 

Subject: gss_accept_sec_context() SPNEGO-wrapped src_name interacts badly with gss_localname()
Download (untitled) / with headers
text/plain 2.1KiB
After successfully establishing a SPNEGO context,
gss_accept_sec_context() returns GSS_S_COMPLETE to the caller with
*mech_type set to the underlying mech OID (not SPNEGO) and *src_name
set to a union name containing a SPNEGO MN. (SPNEGO just stores a
union name as its internal name, so the mech_name field inside the
mechglue's union name is another union name containing an MN for the
underlying mech.)

For the most part this inconsistency is invisible to the caller.
gss_display_name(), gss_inquire_name(), gss_export_name(), and
gss_get_name_attribute() will all be passed through by SPNEGO. Even
the mech_MN reported by gss_inquire_name() will be the underlying
mech.

gss_localname() (based on the Solaris gssd_pname_to_uid()) accepts a
mech parameter--presumably the intent is to allow the caller to ask
for the local name of a non-MN. If the caller provides the mech
returned by gss_accept_sec_context(), the mechglue will notice the
mismatch and will attempt to re-canonicalize the name for the
underlying mech; the conversion process might lose some information
about the name. (As an example, while the mechglue tries to preserve
name attributes across the conversion, the mech may not accept the
gss_set_name_attribute() calls. This was observed with the EAP
mechanism in
https://github.com/modauthgssapi/mod_auth_gssapi/pull/195 .)

Also, SPNEGO doesn't currently implement a passthrough for
gss_localname(), so even if the caller doesn't pass a mech OID,
SPNEGO will force the mechglue to fall back to attributes for getting
the local name.

The mechglue gss_accept_sec_context() has a special case for
*delegated_cred_handle: if the mech returns a different actual_mech
than the mech's own OID, gss_accept_context() will assume that the
delegated cred handle is a union cred and won't wrap it. We could do
the same for *src_name.

Nico suggests adding explicit unwrapping functions to the SPI (here
is a name/context/cred; give me the underlying union
name/context/cred or fail if it's not a simple wrapping). If we did
that then we wouldn't be making as many assumptions about mech
implementations which return actual_mech values different from their
own OIDs, at the expense of more code.
Ticket 8897 solves part of this problem, by passing through gss_localname() in SPNEGO.  If an application passes in the reported actual_mech() to gss_localname() then there still may be an issue.
 
Ticket 8901 removes one of the complications for extending the accept_sec_context contract to apply to src_name.  A second complication is gss_inquire_context(), which is an alternate way to retrieve src_name from an acceptor context.  If gss_accept_sec_context() returned an unwrapped src_name and gss_inquire_context() returned a wrapped src_name (it currently always wraps), that would be an unfortunate inconsistency.

Heimdal has a more comprehensive approach to this issue: a mech can declare via flags that it uses mechglue creds or mechglue names for all purposes.  SPNEGO does both; as a consequence, gss_set_neg_mechs() has to be implemented at the mechglue layer rather than the SPNEGO layer.  There are some interesting and arguably beneficial side-effects: (1) a non-SPNEGO cred can be used as a SPNEGO claimant or acceptor cred handle, and (2) SPNEGO does not have to implement pass-through credential or name methods.  However, the mechglue code to implement these flags is not trivial, and there is a lot of potential for memory errors if it is done incorrectly.