Hi folks,

we have recently noticed the following with Java's kinit (tested with Zulu 8 and 13, code is identical in 18 as well):

C:\Users\osipovmi>kinit osipo...@ad001.siemens.net

I have intentionally written the realm in lowercase to rely on canonicalization of the AD KDC. krb5.conf contains "canonicalize = true" as well.

Wireshark shows me in the AS-REQ:
as-req/req-body/sname: name-type KRB5-NT-SRV-INST (2), sname-string (2): krbtgt and ad001.siemens.net

AS-REP:
as-rep/ticket/sname: name-type KRB5-NT-SRV-INST (2), sname-string (2): krbtgt and AD001.SIEMENS.NET

Hence, the KDC has properly canonicalized the sname. Java gives me:

Exception: krb_error 41 Message stream modified (41) Message stream modified
KrbException: Message stream modified (41)
        at sun.security.krb5.KrbKdcRep.check(KrbKdcRep.java:55)
        at sun.security.krb5.KrbAsRep.decrypt(KrbAsRep.java:159)
        at sun.security.krb5.KrbAsRep.decryptUsingPassword(KrbAsRep.java:139)
        at sun.security.krb5.KrbAsReqBuilder.resolve(KrbAsReqBuilder.java:312)
        at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:498)
        at sun.security.krb5.internal.tools.Kinit.acquire(Kinit.java:248)
        at sun.security.krb5.internal.tools.Kinit.<init>(Kinit.java:134)
        at sun.security.krb5.internal.tools.Kinit.main(Kinit.java:96)

Referrals aren't involved here, same realm.
The failing code block is from:
* https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/9a751dc19fae78ce58fb0eb176522070c992fb6f/jdk/src/share/classes/sun/security/krb5/KrbKdcRep.java#L58-L71 * https://github.com/AdoptOpenJDK/openjdk-jdk/blob/ff4997014fe5462dca2b313f3f483400ffee5b62/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java#L58-L71

        // sname change in TGS-REP is allowed only if client
        // sent CANONICALIZE and new sname is a referral of
        // the form krbtgt/to-realm....@from-realm.com.
        if (!req.reqBody.sname.equals(rep.encKDCRepPart.sname)) {
            String[] snameStrings = rep.encKDCRepPart.sname.getNameStrings();
            if (isAsReq || !req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) 
||
                    snameStrings == null || snameStrings.length != 2 ||
                    !snameStrings[0].equals(PrincipalName.TGS_DEFAULT_SRV_NAME) 
||
                    !rep.encKDCRepPart.sname.getRealmString().equals(
                            req.reqBody.sname.getRealmString())) {
                rep.encKDCRepPart.key.destroy();
                throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
            }
        }

So it either fails for
isAsReq
or
!rep.encKDCRepPart.sname.getRealmString().equals(
                            req.reqBody.sname.getRealmString())

Here is MIT Kerberos:
$ kinit osipo...@ad001.siemens.net
Passwort für osipo...@ad001.siemens.net:
$ klist
Ticketzwischenspeicher: FILE:/tmp/krb5cc_722
Standard-Principal: osipo...@ad001.siemens.net

Valid starting       Expires              Service principal
20.10.2021 10:02:14  20.10.2021 20:02:14  
krbtgt/ad001.siemens....@ad001.siemens.net
        erneuern bis 21.10.2021 10:02:10

Works as expected. Can someone explain? Shall I create a bug for this?

Michael

Reply via email to