2

目前,我的 GSS 演示应用程序(在服务器端)收到 KrbException:解密字段的完整性检查失败(31)。现在我正在寻找这个的原因。我怀疑,它来自于这样一个事实

  1. 客户端和服务器应用程序在同一台机器 (localhost) 上运行和/或
  2. SPN 是为另一台机器(计算机)生成的

第二个表示服务主体是为机器 xxx0815.domain.net 生成的,所以 SPN 是 HTTP/xxx0815.domain.net@DOMAIN.NET。而且我的机器不是那个,但是我已经拿到了keytab文件,这样服务器的登录方法就成功了。

我怀疑正确还是我犯了另一个错误?

服务器配置及源码:
server.conf

Server { 
    com.sun.security.auth.module.Krb5LoginModule 
        required 
        isInitiator=false 
        doNotPrompt=true 
        useKeyTab=true 
        keyTab="gssdemo.keytab" 
        storeKey=true 
        principal="HTTP/xxx0815.domain.net@DOMAIN.NET" 
        debug=true; 
};

GSSServer.java(省略了样板文件)

    GSSManager manager = GSSManager.getInstance();
    GSSName serverName = manager.createName(getServerName(), null);
    GSSCredential serverCred = manager.createCredential(serverName,
                                                        GSSCredential.INDEFINITE_LIFETIME,
                                                        createKerberosOid(),
                                                        GSSCredential.ACCEPT_ONLY);
    GSSContext context = manager.createContext(serverCred);
    System.out.println("Context created successfully. Now incoming tokens could be accepted.");

    ServerSocket serverSocket = new ServerSocket(55555);
    SocketAdapter ca = new SocketAdapter(serverSocket.accept());

    while (!context.isEstablished()) {
        byte[] inToken = ca.readToken();
        byte[] outToken = context.acceptSecContext(inToken, 0, inToken.length);

        if (outToken != null) {
            ca.sendToken(outToken);
        }
    }

    System.out.println("Context established");
    System.out.println("Connected user is: " + context.getSrcName());
    context.dispose();

客户端配置及源码:
client.conf

Client {
    com.sun.security.auth.module.Krb5LoginModule
        required
        useTicketCache=true
        debug=true;
};

GssClient.java(样板省略)

    GSSManager manager = GSSManager.getInstance();
    GSSName clientName = manager.createName(getClientName(), null);
    GSSCredential clientCred = manager.createCredential(clientName,
                                                        8 * 3600,
                                                        createKerberosOid(),
                                                        GSSCredential.INITIATE_ONLY);
    GSSName serviceName = manager.createName("HTTP/xxx0815.domain.net@DOMAIN.NET", null);

    GSSContext context = manager.createContext(serviceName,
                                               createKerberosOid(),
                                               clientCred,
                                               GSSContext.DEFAULT_LIFETIME);
    context.requestMutualAuth(true);
    context.requestConf(false);
    context.requestInteg(true);

    System.out.println("Establishing context");
    SocketAdapter ca = new SocketAdapter(new Socket("localhost", 55555));

    byte[] inToken = new byte[0];
    while (true) {
        byte[] outToken = context.initSecContext(inToken, 0, inToken.length);

        if (outToken != null) {
            ca.sendToken(outToken);
        }

        if (context.isEstablished()) {
            break;
        }

        inToken = ca.readToken();
    }

    System.out.println("Context established: " + context.isEstablished());

    context.dispose();

我检查了传出和传入的网络数据 - 两边都是一样的,所以我可以排除那里的问题(我对输出进行了 BASE64 编码,然后通过流发送它。我认为没有什么可以去的那里错了...)。

我得到的例外:

Caused by: GSSException: Failure unspecified at GSS-API level (Mechanism level: Integrity check on decrypted field failed (31))
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:741)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:323)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
    at de.westlb.mrm.sandbox.gss.GssServer.acceptAndEstablish(GssServer.java:88)
    at de.westlb.mrm.sandbox.gss.GssServer.run(GssServer.java:66)
    ... 4 more
Caused by: KrbException: Integrity check on decrypted field failed (31)
    at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:154)
    at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
    at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:125)
    at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
    at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:168)
    at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:267)
    at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:134)
    at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:79)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:724)
    ... 8 more
4

1 回答 1

1

如果完整性检查失败,则表明数据未正确发送/接收(或者这是不正确的错误消息)。换句话说,发生了一些修改。

我知道您说您已经在网络级别检查了发送的数据是否与接收的数据匹配,但是您确定它在发送之前或接收之后没有损坏吗?我建议您首先检查您的代码。

编辑:在回答您的问题时,可以将服务主体(实际上是任何票证)绑定到特定机器,但这通常是根据 IP 地址完成的。在任何情况下,类似的事情都会导致不同的更高级别的错误。

您收到的错误听起来像是一开始就无法解密票证。一个可能的原因是它使用了错误的密钥,这可能与您复制密钥表有关。使用错误的票证也可能导致错误的密钥(因为 kerberos 基本上提供了密钥管理协议)。您是否可能缓存了旧的/不正确的票?

于 2009-01-12T11:15:18.290 回答