Canonical clients in AS-REQ for non-TGS server principals

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Canonical clients in AS-REQ for non-TGS server principals

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;

--
--
Jakob Uhd Jepsen
Systems Engineer
[hidden email]

_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Canonical clients in AS-REQ for non-TGS server principals

Jeffrey Altman-2
On 2/7/2017 9:58 AM, Jakob Uhd Jepsen wrote:

> 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

>


_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev

smime.p7s (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Canonical clients in AS-REQ for non-TGS server principals

Greg Hudson
In reply to this post by Jakob Uhd Jepsen
On 02/07/2017 09:58 AM, Jakob Uhd Jepsen wrote:
> 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             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Loading...