Reported to Heimdal by Michał Kępień <michal@isc.org>.
From the report:
Acknowledgement
---------------
This flaw was found while working on addressing ZDI-CAN-12302: ISC BIND
TKEY Query Heap-based Buffer Overflow Remote Code Execution
Vulnerability, which was reported to ISC by Trend Micro's Zero Day
Initiative.
Fix _gss_spnego_set_sec_context_option() to return GSS_S_UNAVAILABLE if no
context handle is provided, so that mechglue will skip to the next mechanism.
There are no globally settable options on SPNEGO itself.
Fixes: #803
The functions for storing and retrieving GSS OIDs and buffers from
krb5_storage, added in 6554dc69, are generally useful. Move those into private
_gss_mg_XXX() API and update gss_{export,import}_{cred,sec_context} to use them
where appropriate.
Code style/consistency: store_negoex_auth_mech() should free the exported
context buffer after use. There is no leak as the buffer was freed at the end
of the function.
Support for exporting partially established acceptor context tokens. With this,
an acceptor can send the initiator an encrypted state cookie containing the
exported context token.
(The concrete mechanism, of course, must either require a single round trip or
support partial context export itself. Kerberos and GSS EAP would work, but
Kerberos with GSS_C_DCE_STYLE would not, as currently implemented.)
Partial context export is not permitted for initiators.
Fix for issue #486 based on a patch by Nico Williams.
A GSS-API acceptor can return an error token to be sent to the initiator. Our
SPNEGO implementation discarded these when sending a SPNEGO reject response.
This patch fixes the SPNEGO acceptor to convey those in the SPNEGO response.
The SPNEGO initiator is also updated to not bail out early on receiving a
SPNEGO reject response from the acceptor, but instead pass the response token
(if any) to gss_init_sec_context(). A reject response with no response token
will continue to return an error.
SPNEGO was already using union creds. Now make the mechglue know about
it, delete all of the cred-related SPNEGO stubs that are now not called
(lib/gssapi/spnego/cred_stubs.c), and implement gss_get/set_neg_mechs()
by storing the OID set in the union cred.
This commit was essentially authored as much if not more by Luke Howard
<lukeh at padl.com> as much as by the listed author.
The SPNEGO dispatch table does not include gss_duplicate_cred(). It can call
directly into the mechglue because a SPNEGO credential is a mechglue
credential.
SPNEGO credentials are mechglue credentials. SPNEGO credential wrapper
functions can be replaced with direct calls into the mechglue, unless a
specific check is required to avoid infinite recursion (as is the case where
the mechglue enumerates all mechanism when passed a null credential handle).
The recent changes to SPNEGO removed support for GSS_C_PEER_HAS_UPDATED_SPNEGO,
through which the Kerberos mechanism could indicate to SPNEGO that the peer did
not suffer from SPNEGO conformance bugs present in some versions of Windows.*
This patch restores this workaround, documented in [MS-SPNG] Appendix A <7>
Section 3.1.5.1. Whilst improving interoperability with these admittedly now
unsupported versions of Windows, it does introduce a risk that Kerberos with
pre-AES ciphers could be negotiated in lieu of a stronger and more preferred
mechanism.
Note: this patch inverts the mechanism interface from
GSS_C_PEER_HAS_UPDATED_SPNEGO to GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO, so that new
mechanisms (which did not ship with these older versions of Windows) are not
required to implement it.
* Windows 2000, Windows 2003, and Windows XP
Sort the list of mechanisms proposed by the initiator so that mechanisms are
preferred by their advertised support for GSS flags. For example, if
GSS_C_MUTUAL_FLAG is requested, a mechanism that offers GSS_C_MA_AUTH_TARG will
be preferred over one that doesn't. The flag/mechanism attribute combinations
are also assigned a weight (mutual trumps anonymous, for example).
- Formalize the TYPE:collection_name:subsidiary_name naming scheme for
ccaches in ccache collections
- KEYRING: ccaches are weird because they have one more optional field: the
"anchor", so rather than just assume a naming convention everywhere, we
add new functions as well
- Add krb5_cc_{resolve,default}_sub() that allows one to specify a
"subsidiary" ccache name in a collection separately from the
collection name
- Add krb5_cc_{resolve,default}_for() which take a principal name,
unparse it, and use it as the subsidiary ccache name (with colons
replaced)
- Make kinit use the new interfaces
- Add missing DIR ccache iteration functionality
- Revamps test_cc
- Add krb5_cc_get_collection() and krb5_cc_get_subsidiary()
- Bump the ccops SPI version number
- Add gss_store_cred_into2()
- Make MEMORY:anonymous not linked into the global MEMORY ccache
collection, and uses this for delegated cred handles
TBD:
- Split this up into a krb5 change and gss mech_krb5 change?
- Add krb5_cc_init_and_store() utility, per Greg's suggestion?
NTLM erroneously requires a mechListMIC at the SPNEGO layer if an internal MIC
in the NTLM protocol was used. Add a private interface between SPNEGO and the
Samba NTLM mechanism to allow the mechanism to signal that a mechListMIC is
required even if it otherwise would not be.
This interface is the same as that supported by MIT.
Note that only the Samba NTLM mechanism currently implements this feature, it
is not implemented by the Heimdal NTLM mechanism (which does not support NTLM
authenticate message MICs).
Previously krb5 was tried explicitly, but now the internal mech list is
reordered so that krb5 is first, this should no longer be required. This
permits an application to specify another mechanism as preferred over krb5
using gss_set_neg_mechs().
RFC 4178 4.2.2 uses the field name negState rather than negResult in
NegTokenResp, to denote the negotiation state. Harmonize with this, also
replacing the underscores in accept-completed and accepet-incomplete to match
the RFC.
An implementation of draft-zhu-negoex-04 for MIT Kerberos was developed in
2011. This has been recently integrated, with many fixes from Greg Hudson. This
commit ports it to Heimdal. The implementation has been interoperability tested
with MIT Kerberos and Windows, using the GSS EAP mechanism developed as part of
the Moonshot project.
The SPNEGO code was also updated to import the state machine from Apple which
improves mechListMIC processing and avoids discarding initial context tokens
generated during mechanism probing, that can be used for optimistic tokens.
Finally, to aid in testing, the GSS-API mechanism glue configuration file can
be changed using the environment variable GSS_MECH_CONFIG. This environment
variable name, along with the format of the configuration file, is compatible
with MIT (although it would be difficult for a single mechanism binary to
support both implementations).
Wrapping GSS names at the SPNEGO level serves no purpose; remove it and return
mechglue names directly. This required a small change to the NTLM mechanism to
allow NULL names to be passed to its release name function.
Implementation of gss_set_neg_mechs() and gss_get_neg_mechs() as defined in RFC
4178. New gss_release_cred_by_mech() API for dropping a credential from a
mechanism glue credential.
SPNEGO uses the callback function acceptor_approved() in order to determine
which mechanisms to advertise to the initiator in the case that the initiator
sent an empty initial context token. Prior to this commit, that function was
not passed in the acceptor credential (if present), so always uses a default
credential. For correctness, we should only advertise the availability of
mechanisms for which we have a credential.
Implement the GSS-API credential store API extensions defined by MIT here:
https://k5wiki.kerberos.org/wiki/Projects/Credential_Store_extensions
Note: we kill off gss_acquire_cred_ext() here. This was never a public API,
although mechanisms could have implemented it and I briefly used it in my
BrowserID prototype mechanism. gss_acquire_cred_ext_from() occupies the place
in the dispatch table where gss_acquire_cred_ext() used to, but this structure
was never visible outside Heimdal (i.e. it is only used by internal
mechanisms);
(Mechanisms that need to accept arbitrary key/value dictionaries from
applications should now implement gss_acquire_cred_from().)
SPNEGO uses the callback function initiator_approved() in order to determine
mechanism availability. Prior to this commit, is not passed in the initiator
credential, so it always uses a default credential. This breaks SPNEGO if a
non-default credential (such as one acquired with
gss_acquire_cred_with_password()) is used. This commit addresses this.
It turns out gss_add_cred() really needed a complete rewrite. It's much
better to first have a gss_duplicate_cred() (which has been needed for
other reasons anyways), and use that when the input_cred_handle is not
GSS_C_NO_CREDENTIAL and output_cred_handle is not NULL, then mutate that
duplicate credential handle (or the input_cred_handle if
output_cred_handle is NULL).