Java ignores/errors canonicalized principals (NT-PRINCIPAL) from Active Directory

Osipov, Michael (LDA IT PLM) michael.osipov at siemens.com
Fri Oct 22 16:25:31 UTC 2021


Apoligies, the Java kinit run was not performed with the correct 
krb5.conf. I have now repeated with the proper one and the stacktrace 
fits the code and my analysis now:

> C:\Users\osipovmi>kinit osipovmi at ad001.siemens.net
> Picked up _JAVA_OPTIONS: -Dsun.security.krb5.debug=false -Djava.security.krb5.conf=C:\Config\Kerberos\krb5.conf
> Password for osipovmi at ad001.siemens.net:
> Exception: krb_error 41 Message stream modified (41) Message stream modified
> KrbException: Message stream modified (41)
>         at sun.security.krb5.KrbKdcRep.check(KrbKdcRep.java:69)
>         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)

I am pretty confident that the sname realm string is the cause here.

Michael

Am 2021-10-20 um 10:03 schrieb Osipov, Michael (LDA IT PLM):
> 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 osipovmi at 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.COM at 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 OSIPOVMI at ad001.siemens.net
>> Passwort für OSIPOVMI at ad001.siemens.net:
>> $ klist
>> Ticketzwischenspeicher: FILE:/tmp/krb5cc_722
>> Standard-Principal: osipovmi at AD001.SIEMENS.NET
>>
>> Valid starting       Expires              Service principal
>> 20.10.2021 10:02:14  20.10.2021 20:02:14  
>> krbtgt/AD001.SIEMENS.NET at 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




More information about the security-dev mailing list