Discussion:
Canonical clients in AS-REQ for non-TGS server principals
Jakob Uhd Jepsen
2017-02-07 14:58:54 UTC
Permalink
I have run into a limitation of the AS-REQ protocol, when used with
canonical clients, that I am not sure why exists. Our code is using v
1.12.1 kerberos, though from what I can tell, this bit has not been
changed in a long time and is still present in the latest release
version. It was introduced back in 2009 in commit
589ad211b633c9319a074c032c47db6b7bd62237

The relevant method is verify_as_reply in get_in_tkt.c

What I am attempting to do, it use an AS-REQ/AS-REP exchange to get a
ticket from an NT-ENTERPRISE client to a service, that is *not* the TGS
service. I do not want a TGT, but a direct service ticket. I also want
the client to be the canonical client. It seems this is not allowed, and
I am trying to understand why. There are no cross-realm shennanigans in
out setup to complicate matters.

(For context, I've pasted in the relevant code at the bottom of this).

Specifically, the canon_req field is set for a canonicalize request or
an enterprise client. In the case of client canoncialization, both of
these will be true. Yet due to the stipulation that the server principal
be a TGS for canon_ok to be true, we end up in the if branch following
this. Here, the AS-REP is checked to see if the request client and the
as_reply client are identical. If the KDC canonicalized the client, this
may not be the case, and the whole exchanged ends up with a
KRB5_KDCREP_MODIFIED error.

It doesn't seem that the intent of the comment to prevent servers to
change, matches the full effect of the code, when used in this manner.
Is there are reason I'm not seeing, why canonicalizing client names in
this instance should not be allowed?

/*
* We only allow the AS-REP server name to be changed if the
* caller set the canonicalize flag (or requested an enterprise
* principal) and we requested (and received) a TGT.
*/
canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL ||
(request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS);
if (canon_req) {
canon_ok = IS_TGS_PRINC(request->server) &&
IS_TGS_PRINC(as_reply->enc_part2->server);
if (!canon_ok && (request->kdc_options &
KDC_OPT_REQUEST_ANONYMOUS)) {
canon_ok = krb5_principal_compare_any_realm(context,
as_reply->client,
krb5_anonymous_principal());
}
} else
canon_ok = 0;

if ((!canon_ok &&
(!krb5_principal_compare(context, as_reply->client,
request->client) ||
!krb5_principal_compare(context, as_reply->enc_part2->server,
request->server)))
|| !krb5_principal_compare(context,
as_reply->enc_part2->server, as_reply->ticket->server)
....
<SNIP>
.....
} return KRB5_KDCREP_MODIFIED;
--
--
Jakob Uhd Jepsen
Systems Engineer
***@one.com

_______________________________________________
krbdev mailing list ***@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev
Jeffrey Altman
2017-02-07 16:14:27 UTC
Permalink
Post by Jakob Uhd Jepsen
I have run into a limitation of the AS-REQ protocol, when used with
canonical clients, that I am not sure why exists. Our code is using v
1.12.1 kerberos, though from what I can tell, this bit has not been
changed in a long time and is still present in the latest release
version. It was introduced back in 2009 in commit
589ad211b633c9319a074c032c47db6b7bd62237
The relevant method is verify_as_reply in get_in_tkt.c
What I am attempting to do, it use an AS-REQ/AS-REP exchange to get a
ticket from an NT-ENTERPRISE client to a service, that is *not* the TGS
service. I do not want a TGT, but a direct service ticket. I also want
the client to be the canonical client. It seems this is not allowed, and
I am trying to understand why. There are no cross-realm shennanigans in
out setup to complicate matters.
(For context, I've pasted in the relevant code at the bottom of this).
Specifically, the canon_req field is set for a canonicalize request or
an enterprise client. In the case of client canoncialization, both of
these will be true. Yet due to the stipulation that the server principal
be a TGS for canon_ok to be true, we end up in the if branch following
this. Here, the AS-REP is checked to see if the request client and the
as_reply client are identical. If the KDC canonicalized the client, this
may not be the case, and the whole exchanged ends up with a
KRB5_KDCREP_MODIFIED error.
It doesn't seem that the intent of the comment to prevent servers to
change, matches the full effect of the code, when used in this manner.
Is there are reason I'm not seeing, why canonicalizing client names in
this instance should not be allowed?
/*
* We only allow the AS-REP server name to be changed if the
* caller set the canonicalize flag (or requested an enterprise
* principal) and we requested (and received) a TGT.
*/
canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL ||
(request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS);
if (canon_req) {
canon_ok = IS_TGS_PRINC(request->server) &&
IS_TGS_PRINC(as_reply->enc_part2->server);
if (!canon_ok && (request->kdc_options &
KDC_OPT_REQUEST_ANONYMOUS)) {
canon_ok = krb5_principal_compare_any_realm(context,
as_reply->client,
krb5_anonymous_principal());
}
} else
canon_ok = 0;
if ((!canon_ok &&
(!krb5_principal_compare(context, as_reply->client,
request->client) ||
!krb5_principal_compare(context, as_reply->enc_part2->server,
request->server)))
|| !krb5_principal_compare(context,
as_reply->enc_part2->server, as_reply->ticket->server)
....
<SNIP>
.....
} return KRB5_KDCREP_MODIFIED;
I have not looked at the history but it sounds to me that the test
should be whether or not the ticket returned from the KDC is an initial
ticket, not whether or not it is a TGT.

That said, there may be a historical reason why the behavior was
restricted to TGTs.

Jeffrey Altman
Greg Hudson
2017-02-07 16:32:20 UTC
Permalink
Post by Jakob Uhd Jepsen
I have run into a limitation of the AS-REQ protocol, when used with
canonical clients, that I am not sure why exists.
This code dates back to a period of churn in the code base in 2008-2009
as the team integrated a bunch of changes for better interoperability
with Microsoft's Kerberos implementation.

I looked at the commits as they appeared on the development branch for
this work. First is r21462 (we used Subversion back then):

https://src.mit.edu/fisheye/changelog/krb5/?cs=21462

which simply conditionalizes the client-against-request and
server-against-request checks on the canonicalize flag. This is
followed by r21484:

https://src.mit.edu/fisheye/changelog/krb5/?cs=21484

which adds in the implicit assumption that an enterprise client
principal implies canonicalization. (r21487 corrects "=" to "==" in the
expression there.) Finally there is r21662:

https://src.mit.edu/fisheye/changelog/krb5/?cs=21662

which appears intended to restrict changes to the server principal to
when a krbtgt principal is requested, but also restricts changes to the
client principal, as you discovered.

Even just the motivation for this change is a little confusing, as there
is no such thing as a cross-realm AS request. It seems potentially
useful to accept changes in the case of the realm we sent the request
to, although that seems equally true for a non-krbtgt server principal.
I did find this paragraph in the security considerations of RFC 6806:

Changing the server name can be a very significant attack. For
example, if a user is authenticating in order to send some
confidential information, then the attacker could gain this
information by directing the user to a server under the attacker's
control. The server name in the response is protected by RFC 4120,
but not the one in the request. Fortunately, users are typically
authenticating to the "krbtgt" service in an AS exchange. Clients
that permit changes to the server name when no protection beyond RFC
4120 is in use SHOULD carefully restrict what service names are
acceptable. One critical case to consider is the password-changing
service. When a user authenticates to change their password, they
use an AS authentication directly to the password-changing service.
Clients MUST restrict service name changes sufficiently that the
client ends up talking to the correct password-changing service.

I think it should be safe to alter the code to allow a change to the
client principal if the requested server principal is not a TGT. We do
need to be very careful not to introduce an attack vector when making
the change, as these parts of the AS exchange are not protected by any
cryptography (in the absence of FAST or MS-KKDCP or similar).
_______________________________________________
krbdev mailing list ***@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev

Loading...