SPNEGO / ActiveDirectory / AES256:校验失败

Mat*_*tke 5 java kerberos spnego

我正在尝试将 SPNEGO/Kerberos5 身份验证与 Active Directory 2008 和 Java 一起使用。我遵循了本指南:http : //spnego.sourceforge.net/ - “预检”进展顺利,但后来我得到了著名的例外:

Exception in thread "main" GSSException: Failure unspecified at GSS-API level (Mechanism level: Checksum failed)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:856)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
    at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:906)
    at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:556)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
    at de.meona.auth.spnego.TestSpnegoAes.main(TestSpnegoAes.java:45)
Caused by: KrbException: Checksum failed
    at sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType.decrypt(Aes256CtsHmacSha1EType.java:102)
Run Code Online (Sandbox Code Playgroud)

我仔细查看了这篇文章,因为问题似乎很相似: 校验和失败:Kerberos / Spring / Active Directory (2008)

为了使问题可重现,我编写了一个小的 Java 类。我能够单步到发生异常的那一行。我认为这是因为用于解密的秘密服务密钥与 Active Directory 用于加密服务票证的秘密服务密钥不同。怎么会这样?

public class TestSpnegoAes {

    private static Oid spnegoOid = null;
    private static String negotiate = "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";
    private static GSSManager manager;

    // -Dsun.security.krb5.debug=true
    // -Djava.security.auth.login.config=login.conf

    public static void main(String[] args) throws GSSException, LoginException, PrivilegedActionException {
        spnegoOid = new Oid("1.3.6.1.5.5.2");

        manager = GSSManager.getInstance();

        LoginContext loginContext = new LoginContext("spnego-server");
        loginContext.login();

        Subject subject = loginContext.getSubject();
        GSSCredential serviceCredentials = getServerCredential(subject);

        GSSContext context = manager.createContext(serviceCredentials);

        byte[] token = Base64.decode(negotiate);
        context.acceptSecContext(token, 0, token.length);
    }

    static GSSCredential getServerCredential(final Subject subject) throws PrivilegedActionException {

        final PrivilegedExceptionAction<GSSCredential> action = new PrivilegedExceptionAction<GSSCredential>() {
            public GSSCredential run() throws GSSException {
                return manager.createCredential(null, GSSCredential.INDEFINITE_LIFETIME, spnegoOid,
                        GSSCredential.ACCEPT_ONLY);
            }
        };
        return Subject.doAs(subject, action);
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的 login.conf 文件:

spnego-server {
    com.sun.security.auth.module.Krb5LoginModule required
    useKeyTab=true
    storeKey=true
    isInitiator=false
    keyTab="file:///C:/Temp/krbtest/meona-service.keytab" 
    principal=meona-service;
};
Run Code Online (Sandbox Code Playgroud)

如果您想复制,我也很乐意提供密钥表文件。它是在 PDC 上使用“kpass /out keytab /princ meona-service@meona.intra /pass ... /crypto AES256-SHA1 /ptype KRB5_NT_PRINCIPAL”生成的。

由于LoginContext登录成功,我认为密钥恢复成功。

这是标准输出:

Java config name: null
Native config name: C:\Windows\krb5.ini
Found KeyTab C:\Temp\krbtest\meona-service.keytab for meona-service@meona.intra
Found KeyTab C:\Temp\krbtest\meona-service.keytab for meona-service@meona.intra
Entered Krb5Context.acceptSecContext with state=STATE_NEW
>>> KeyTabInputStream, readName(): MEONA.INTRA
>>> KeyTabInputStream, readName(): meona-service
>>> KeyTab: load() entry length: 75; type: 18
Looking for keys for: meona-service@meona.intra
Added key: 18version: 1
>>> EType: sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType
Exception in thread "main" GSSException: Failure unspecified at GSS-API level (Mechanism level: Checksum failed)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:856)
Run Code Online (Sandbox Code Playgroud)

如果我不使用密钥表,而是使用预身份验证,我可以恢复密钥,但稍后会出现相同的错误。

有任何想法吗?

这是我用来生成 SPNEGO 协商标头的 krb5.conf。

[libdefaults]
    default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    permitted_enctypes   = aes256-cts-hmac-sha1-96 aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    default_realm = MEONA.INTRA

[realms]
    MEONA.INTRA = {
        kdc = pdc.meona.intra
        default_domain = MEONA.INTRA
}

[domain_realm]
    .MEONA.INTRA = MEONA.INTRA 
Run Code Online (Sandbox Code Playgroud)

我尝试了不同的变体(有/没有“.intra”,大写/小写),但没有成功。但是在将票证加密(使用 AD 服务用户的设置)更改为 ARC4/HMAC1 后,一切都按预期进行 - AES256 有什么问题?

小智 0

我在使用 Java 17 和 Spnego 时看到了这个问题

我的 Keytab 文件包含 AES128/256 的条目。我们已通过支持为 AD 帐户启用 AES 令牌。然后我看到错误“校验和失败”(KVN 和密码未更改)。支持通过 ktpass 生成 keytab。我在服务器上替换它,重新启动应用程序后,错误得到解决。

我通过 ktab 使用新的 kvn 重新生成了 keytab 文件 - keytab 也有效。

启用AES后,您需要“刷新”AD中的帐户以更改KVN参数。然后集成就会起作用。