首页 > 解决方案 > gss_accept_sec_context() 错误:ASN.1 结构缺少必填字段

问题描述

我正在尝试在 Ubuntu 上实现 Kerberos 身份验证。

run_kerberos_server.sh

#!/usr/bin/env bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

docker stop krb5-server && docker rm krb5-server && true

docker run -d --network=altexy --name krb5-server \
  -e KRB5_REALM=EXAMPLE.COM -e KRB5_KDC=localhost -e KRB5_PASS=12345 \
  -v /etc/localtime:/etc/localtime:ro \
  -v /etc/timezone:/etc/timezone:ro \
   --network-alias example.com \
  -p 88:88 -p 464:464 -p 749:749 gcavalcante8808/krb5-server

echo "=== Init krb5-server docker container ==="
docker exec krb5-server /bin/sh -c "
# Create users bob as normal user
# and add principal for the service
cat << EOF  | kadmin.local
add_principal -randkey \"HTTP/service.example.com@EXAMPLE.COM\"
ktadd -k /etc/krb5-service.keytab -norandkey \"HTTP/service.example.com@EXAMPLE.COM\"
ktadd -k /etc/admin.keytab -norandkey \"admin/admin@EXAMPLE.COM\"
listprincs
quit
EOF
"

echo "=== Copy keytabs  ==="
docker cp krb5-server:/etc/krb5-service.keytab "${DIR}"/krb5-service.keytab
docker cp krb5-server:/etc/admin.keytab "${DIR}"/admin.keytab

获取 Kerberos 票证:

alex@alex-secfense:~/projects/proxy-auth/etc/kerberos$ kinit admin/admin@EXAMPLE.COM
Password for admin/admin@EXAMPLE.COM: 
alex@alex-secfense:~/projects/proxy-auth/etc/kerberos$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: admin/admin@EXAMPLE.COM

Valid starting       Expires              Service principal
16.12.2020 12:05:38  17.12.2020 00:05:38  krbtgt/EXAMPLE.COM@EXAMPLE.COM
    renew until 17.12.2020 12:05:35

然后我启动 nginx,也在 Docker 容器中,图像来自openresty/openresty:xenial. 我的/etc/hosts文件有127.0.0.1 service.example.com行。

我的 Firefox 配置为network.negotiate-auth.trusted-uris=service.example.com

我打开service.example.com:<mapped_port> page in Firefox, nginx responds with 401 and Firefox send Authorization: Negotiate ...` 标题。

我的服务器端代码(错误和结果处理被剥离):

MYAPI int authenticate(const char* token, size_t length)
{
    gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
    gss_name_t my_gss_name = GSS_C_NO_NAME;
    gss_cred_id_t my_gss_creds = GSS_C_NO_CREDENTIAL;

    OM_uint32 minor_status;
    OM_uint32 major_status;
    gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
    gss_name_t client_name = GSS_C_NO_NAME;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;

    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    input_token.length = length;
    input_token.value = (void*)token;

    major_status = gss_accept_sec_context(&minor_status, &gss_context, my_gss_creds, &input_token,
            GSS_C_NO_CHANNEL_BINDINGS, &client_name, NULL, &output_token, NULL, NULL, NULL);

     return 0;
}

最终,我得到gss_accept_sec_context() error:ASN.1 structure is missing a required field错误。

相同的代码适用于 Windows Kerberos 设置。

知道这是什么意思或如何调试问题吗?

我确实定义了KRB5_TRACE=/<log_file_name>环境变量并看到如下行:

[7] 1607798057.341744: Sending request (937 bytes) to EXAMPLE.COM
[6] 1608109670.292389: Sending request (937 bytes) to EXAMPLE.COM
[6] 1608109670.660887: Sending request (937 bytes) to EXAMPLE.COM

可能是DNS问题?

更新:我错过了在调用之前指定要在服务器端使用的 keyatb 文件gss_accept_sec_context(再次删除了错误处理):

OM_uint32 major_status = gsskrb5_register_acceptor_identity(keytab_filename)

标签: kerberos

解决方案


您的代码打破了上下文完成的基本概念。它违反了 RFC 7546 并且不值得信赖,而且您完全忽略了主要/次要。现在,由于 ASN.1 编码被破坏,您的令牌会在运行中以某种方式被修改。

  • 传输前后转储令牌并进行比较。
  • 先从gss-servergss-client开始。
  • 阅读他们的代码并实现你的同类。不要偏离上下文看完成的命令,
  • 在 Firefox 获得服务票证后显示票证缓存。

一旦您需要令牌,请使用https://lapo.it/asn1js/显示检查它们。


推荐阅读