Subject: Re: [kitten] Checking the transited list of a kerberos ticket in a transitive cross-realm trust situation...

From: Stefan Metzmacher <[email-masked]>
Date: Mon, 2 Aug 2021 16:49:43 +0200

Hi,

due to customer requests I'm trying to resume the discussion
about ways to disable the transited checks in gss_accept_sec_context()
when we know we're in an active directory situation and rely on
the [K]DCs (of our primary domain) to check the cross-realm topology
base on their knowledge of the trust topology.

To summarize the discussion we had active directory DCs do transited
checking (even without a PAC) and fails to issue service tickets
if the check fails, so any service ticket is already checked,
but without TKT_FLG_TRANSIT_POLICY_CHECKED being added to the
ticket.

As only the [K]DCs have the full picture of the trust topology,
we need ways to implicitly get the behavior we would get
if TKT_FLG_TRANSIT_POLICY_CHECKED would be set.

The related bug is:
https://bugzilla.samba.org/show_bug.cgi?id=12907
("pam_winbind with krb5_auth or wbinfo -K doesn't work for users of trusted
domains with more than 1 hop between server and user realm")
It only has references to the past discussion and related bugs,
which also need to alter the gss_accept_sec_context() behavior.

As a start we have the following basic call sequence:

	gss_cred_id_t acceptor_creds = GSS_C_NO_CREDENTIAL;
	gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
	gss_key_value_element_desc keytab_element = {
		.key = "keytab",
		.value = "FILE:/path/to/keytab",
	};
	gss_key_value_set_desc cred_store = {
		.elements = &keytab_element,
		.count = 1,
	};

	gss_acquire_cred_from(..., &acceptor_creds, &cred_store, ...)

	gss_accept_sec_context(..., &context_handle, acceptor_creds,...);

So we need to a way pass KRB5_VERIFY_AP_REQ_NO_TRANSITED_CHECK to
krb5_decrypt_ticket() used deep in gss_accept_sec_context().

The initial solution I proposed was:

	gss_set_cred_option(acceptor_creds, GSS_KRB5_CRED_NO_TRANSIT_CHECK_X)

which would be called between gss_acquire_cred_from() and
gss_accept_sec_context().

As GSS_KRB5_CRED_NO_CI_FLAGS_X is already using the same way
to alter gss_init_sec_context(), I thought it would be the natural
way to implement GSS_KRB5_CRED_NO_TRANSIT_CHECK_X.

But it seems gss_set_cred_option() is not accepted because it's
a deprecated.

The following alternatives would be able to solve the problem:

1. An additional cred_store element could be passed to
   gss_acquire_cred_from() in order to set the
   GSS_CF_NO_TRANSIT_CHECK flag on acceptor_creds

2. I think someone had the idea of using gss_set_sec_context_option()

   In theory this would be the perfect way as we want to alter the
   behavior of gss_accept_sec_context(), but this gets GSS_C_NO_CONTEXT
   in the first iteration, so we don't have a context to
   pass to gss_set_sec_context_option().

   At least in heimdal gss_set_sec_context_option() seems
   to work with GSS_C_NO_CONTEXT and would alter some global state.
   E.g. _gsskrb5_set_sec_context_option() supports things like
   GSS_KRB5_SET_DEFAULT_REALM_X, GSS_KRB5_SET_DNS_CANONICALIZE_X
   GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X and more which seems to
   work on a per thread global krb5_context. These are
   also available via special functions like gsskrb5_set_dns_canonicalize()
   or gsskrb5_register_acceptor_identity().

   krb5_gss_set_sec_context_option() in MIT doesn't support anything
   at the monent and kg_accept_krb5() doesn't seem to operate on
   a global krb5_context.

3. Implement a krb5.conf option similar to "dns_canonicalize_hostname"
   or "ignore_acceptor_hostname" from MIT

   I think this would be a good addition in order to allow admins
   to specify "disable_transit_check = true" and get it also
   for unaware applications.

   But I think for an application that's aware of the fact that
   it never wants any transit checking in gss_accept_sec_context()
   we should better have an api to disable it instead of playing
   games with the "KRB5_CONFIG" environment variable.

It would be really great if we could find a way forward with this,
I typically point customers to the related branches (in most
cases using the heimdal version shipped in Samba), but
they are really unhappy with that situation and asked
me to trigger the discussion again in order to get a solution
that is acceptable in the upstream projects (Heimdal, MIT and Samba)
and would be available by default in distributions.

Nico it would be nice to get some constructive feedback from you,
as you're the one blocking the current patchsets.

Thanks in advance for any possible help!
metze

Am 24.01.20 um 19:49 schrieb Stefan Metzmacher:
> Hi Greg,
> 
>> On 1/23/20 6:25 AM, Stefan Metzmacher wrote:
>>> it would be great if we could make some progress here...
>>
>> Does this need to be an application flag, or can it be in the krb5.conf
>> realm configuration?  Presumably people are currently working around
>> this by setting [capaths] on the server; a realm variable would simplify
>> this workaround by not requiring specific knowledge of the domain geometry.
>>
>> I reviewed the thread, and it sounds like the current understanding is
>> that AD applies a transited check (of sorts) to cross-realm tickets, but
>>  doesn't say so by setting the transit-policy-checked flag in the
>> ticket. 
> 
> Exactly.
> 
>> From the upstream point of view the server's realm
>> configuration is in a better position to know that the realm is an AD
>> realm than the server application; perhaps that is not true from Samba's
>> point of view, but I thought I would check.
> 
> In Samba we know that we're joined to an AD domain
> and then we want to force disabling the transited check
> for gss_accept_sec_context().
> 
> For Samba as AD DC we want also want to disable this for
> krb5_rd_req_decoded in the KDC too.
> 
> A krb5.conf option would also be good in order to support
> non-samba services in AD-Domains. But the c library should also
> support changing it at runtime.
> 
> metze
> 
> 
> _______________________________________________
> krbdev mailing list             [email-masked]
> https://mailman.mit.edu/mailman/listinfo/krbdev
>

---

From: Greg Hudson <[email-masked]>
Date: Mon, 2 Aug 2021 13:24:03 -0400

> but without TKT_FLG_TRANSIT_POLICY_CHECKED being added to the

I just want to acknowledge here that we're taking on technical debt
because the non-conformant party is perceived to be inflexible.

> 	gss_set_cred_option(acceptor_creds, GSS_KRB5_CRED_NO_TRANSIT_CHECK_X)
[...]
> But it seems gss_set_cred_option() is not accepted because it's

Personally I'm fine with this.

>    GSS_CF_NO_TRANSIT_CHECK flag on acceptor_creds

This is similar to a cred option.  I don't see any strong advantages of
one over the other.

> 2. I think someone had the idea of using gss_set_sec_context_option()

This seems hard to do without (per-thread) global state.  Even if we
bring in gss_create_sec_context() from some versions of the channel
bindings draft, the mechglue doesn't know mechanism will be used to
accept the context, so it would have to store OID/value pairs in the
mechglue context and replay them to the mech context once it finds out
which kind of mech context to create.  (And hope that all of the context
option values are flat byte strings, not structures containing pointers
to objects whose lifetimes might have expired between the
set_cred_option() call and the first accept_sec_context() call.)

Doing this with global state seems strictly worse than communicating the
flag via the cred.

>    or "ignore_acceptor_hostname" from MIT

I would argue for this to be a per-realm option if we do this, since
it's a statement about a particular realm's KDCs being non-conformant.

---

From: Stefan Metzmacher <[email-masked]>
Date: Mon, 9 Aug 2021 10:59:58 +0200

Hi Greg,

> Personally I'm fine with this.

Ok, should I just use a different oid (I can allocate one from the Samba pool)
and submit the changes to MIT without the "wait for heimdal first" tag?

It would be great to have that in MIT and we can also apply it to
Samba's fork of Heimdal and have most Samba setups covered.

> This is similar to a cred option.  I don't see any strong advantages of

Same here, I just wanted to find ways to make Nico happy.

> Doing this with global state seems strictly worse than communicating the

Yes, it seems way to complex.

> it's a statement about a particular realm's KDCs being non-conformant.

Ok. I can also implement that in addition to the GSS_KRB5_CRED_NO_TRANSIT_CHECK_X
option.

Thanks for the feedback!
metze

---

From: Stefan Metzmacher <[email-masked]>
Date: Mon, 9 Aug 2021 14:15:07 +0200

> Ok. I can also implement that in addition to the GSS_KRB5_CRED_NO_TRANSIT_CHECK_X

I just found the "reject_bad_transit" option that's already implemented for the MIT kdc,
but I guess we want an extra option, correct?

Do we want the new "no_transit_check" option to be used via:
krb5_appdefault_boolean()?

That would allow the following combinations in MIT:

1:
 [appdefaults]
     app = {
        SOME.REALM = {
             no_transit_check = true
        }
     }

2:
 [appdefaults]
     app = {
        no_transit_check = true
     }

3:
 [appdefaults]
     SOME.REALM = {
        no_transit_check = true
     }

4:
 [appdefaults]
      no_transit_check = true

While heimdal falls back to 2 additional options:

5:
  [realms]
     SOME.REALM = {
        no_transit_check = true
     }

6:

  [libdefaults]
      no_transit_check = true

metze