[krbdev.mit.edu #8777] S4U2Self with X.509 certificate bugs
Microsoft's S4U2Self extension allows a service to obtain a ticket to
itself from an arbitrary user. The user can be identified by regular
krb5 principal, by enterprise principal, or by X.509 certificate. In
the latter two cases, AS requests are used to identify the client's
realm. After the realm is identified, a TGS-REQ with S4U2Self pa-
data is used to obtain the ticket. (In the cross-realm case,
multiple TGS-REQs are required.)
Commit 0e39f8a3ad915eeb0131fb4a87b0fef304101cfd added the client code
for S4U2Self to the MIT krb5 tree. It contained support for using an
X.509 certificate to identify the user, but that functionality was
not reachable by any public path. Isaac Boukris has identified and
corrected the following issues with the client code for using X.509
* During realm identification, the code attempted to present the
X.509 certificate using an optimistic preauth list and special
handling in preauth2.c. Changes to the preauth framework caused this
attempt to fail (because it did not produce authenticating padata
from a clpreauth module) and fall back to sending an AS request
without the cert.
* When performing realm identification with a cert, the existing code
uses a client principal with NT-ENTERPRISE type and no data
components. Windows clients provide a principal of type NT-X500-
PRINCIPAL and the certificate subject as a single data component.
Doing that would require partially decoding the certificate.
Experimentally, using a single empty data component actually works
better with Windows KDCs than including the certificate subject (it
works with cross-realm), so we should do that instead.
* If an enterprise principal and cert are both presented to the API,
to be consistent with Windows clients we should do realm
identification with just the enterprise principal, and then prsent
the cert in the TGS request. The current code presents (well, tries
to present) the certificate during realm identification in this case.
* In krb5_get_self_cred_from_kdc(), if no client principal is
provided, the code to build s4u_user.user_id.user did not terminate
the krb5_build_principal_ext() variable argument list and could
* In the same function, the PA-FOR_USER padata input is supplied to
krb5_get_cred_via_tkt_ext() via an in_padata list, while the PA-FOR-
X509-USER padata is constructed via a callback because so that the
TGS subkey can be used to build it. When the TGS reply is received,
krb5int_process_tgs_reply() looks for PA-FOR_USER or PA-FOR-X509-USER
padata in the in_padata list to decide whether to use S4U2Self logic
to validate the client. Because the PA-FOR-X509-USER padata is not
supplied via the in_padata list, the code will never find that type.
In the usual case, we will find the PA-FOR_USER type and do the right
thing, but in the cert-only case there is no PA-FOR_USER padata
value, so the S4U2Self logic is not applied.