Subject: | Cross-realm S4U2Self to an Active Directory realm alias |
To: | rt@kerborg-prod-app-1.mit.edu |
From: | ghudson@mit.edu |
Date: | Fri, 09 Sep 2022 08:35:56 -0400 |
In this scenario, a service named svc@SREALM wants to use S4U2Self to get a ticket to itself from client@CREALM, but the calling application specifies the realm using a case-variant alias "crealm" instead. A real-world report of this scenario is described in https://mailman.mit.edu/pipermail/kerberos/2022-March/022803.html , although the names given there are different and the use of the lowercase client realm was revealed through inspection of the packet trace. Both the service and client realms in this report are Active Directory 2016, while the library used by svc@SREALM is MIT krb5.
First, the library fetches a cross-TGT to the client realm. Here we run into issue 8941: we ask SREALM for krbtgt/crealm and get back krbtgt/CREALM, which looks like a realm referral even though it is actually the desired cross-TGT with a canonicalized realm name. The library follows the referral, asking CREALM for krbtgt/crealm and getting back krbtgt/CREALM, which looks like a referral to the same realm. We handle this by trying again "without referrrals", but because the KRB5_GC_CANONICALIZE flag is used, we make exactly the same TGS query again, but accept whatever service the KDC gives us (krbtgt/CREALM again). Although we used turtuous processing and wind up with a local TGT for CREALM instead of a cross-TGT krbtgt/CREALM@SREALM, we do get a usable answer from this process.
The library makes an S4U2Self request to CREALM asking for client@crealm, getting back a referral TGT to krbtgt/SREALM with the client's PAC. Following the referral, the client asks SREALM for client@crealm, and gets back a ticket from client@crealm to svc@SREALM. Note that the Active Directory KDCs do not canonicalize the client realm name for these queries.
The lack of client realm canonicalization could be a potential issue, but on top of that the Active Directory KDC for SREALM places a transited field containing CREALM in the ticket. Normally the transited field would be empty because the requesting TGT is for the ticket's client realm, but here the ticket client realm is "crealm" while the requesting TGT is from CREALM, and while AD knows those are the same realm, apparently its transited code uses case-specific matching. Although a Windows service would not check the transited field (MS-KILE 3.1.5.4), attempting to use this ticket with an MIT krb5 library results in a transited check failure (CREALM is not on the expected path between crealm and SREALM).
Possible fixes for this scenario are:
* The application could use the canonical realm name (or use an enterprise principal if it doesn't really know; there is a process for discovering the client realm for an enterprise principal).
* AD could correctly omit the transited field when issuing the ticket.
* AD could canonicalize the client realm in the S4U2Self responses. (It's conceivable that this is not easy, or something would go wrong if it did. But issuing a ticket with a non-canonical realm name seems fraught.)
* AD could set the transited-policy-checked flag in tickets (investigation by Samba developers indicates that AD KDCs do implement transited policies, even though MS-KILE says they don't) in which case the MIT krb5 library would not check the transited field (as of release 1.18).
* After the MIT krb5 library fetches the cross-TGT, it could treat the second component of what it gets back (CREALM) as the canonical client realm name and use that for the S4U2Self requests instead of the realm alias.
The scenario could also be more efficient if issue 8941 were addressed. Although canonicalization of cross-realm TGT names cannot work particularly well in the Kerberos protocol, perhaps the second TGS response (CREALM issuing krbtgt/CREALM instead of krbtgt/crealm) should cause the library to back off to the previous krbtgt/CREALM@SREALM answer instead of making a duplicate TGS request and accepting the krbtgt/CREALM@CREALM result.
First, the library fetches a cross-TGT to the client realm. Here we run into issue 8941: we ask SREALM for krbtgt/crealm and get back krbtgt/CREALM, which looks like a realm referral even though it is actually the desired cross-TGT with a canonicalized realm name. The library follows the referral, asking CREALM for krbtgt/crealm and getting back krbtgt/CREALM, which looks like a referral to the same realm. We handle this by trying again "without referrrals", but because the KRB5_GC_CANONICALIZE flag is used, we make exactly the same TGS query again, but accept whatever service the KDC gives us (krbtgt/CREALM again). Although we used turtuous processing and wind up with a local TGT for CREALM instead of a cross-TGT krbtgt/CREALM@SREALM, we do get a usable answer from this process.
The library makes an S4U2Self request to CREALM asking for client@crealm, getting back a referral TGT to krbtgt/SREALM with the client's PAC. Following the referral, the client asks SREALM for client@crealm, and gets back a ticket from client@crealm to svc@SREALM. Note that the Active Directory KDCs do not canonicalize the client realm name for these queries.
The lack of client realm canonicalization could be a potential issue, but on top of that the Active Directory KDC for SREALM places a transited field containing CREALM in the ticket. Normally the transited field would be empty because the requesting TGT is for the ticket's client realm, but here the ticket client realm is "crealm" while the requesting TGT is from CREALM, and while AD knows those are the same realm, apparently its transited code uses case-specific matching. Although a Windows service would not check the transited field (MS-KILE 3.1.5.4), attempting to use this ticket with an MIT krb5 library results in a transited check failure (CREALM is not on the expected path between crealm and SREALM).
Possible fixes for this scenario are:
* The application could use the canonical realm name (or use an enterprise principal if it doesn't really know; there is a process for discovering the client realm for an enterprise principal).
* AD could correctly omit the transited field when issuing the ticket.
* AD could canonicalize the client realm in the S4U2Self responses. (It's conceivable that this is not easy, or something would go wrong if it did. But issuing a ticket with a non-canonical realm name seems fraught.)
* AD could set the transited-policy-checked flag in tickets (investigation by Samba developers indicates that AD KDCs do implement transited policies, even though MS-KILE says they don't) in which case the MIT krb5 library would not check the transited field (as of release 1.18).
* After the MIT krb5 library fetches the cross-TGT, it could treat the second component of what it gets back (CREALM) as the canonical client realm name and use that for the S4U2Self requests instead of the realm alias.
The scenario could also be more efficient if issue 8941 were addressed. Although canonicalization of cross-realm TGT names cannot work particularly well in the Kerberos protocol, perhaps the second TGS response (CREALM issuing krbtgt/CREALM instead of krbtgt/crealm) should cause the library to back off to the previous krbtgt/CREALM@SREALM answer instead of making a duplicate TGS request and accepting the krbtgt/CREALM@CREALM result.