SASL绑定在GSSAPI上使用kerberos凭据与ldap_sasl_bind_s函数

SASL bind over GSSAPI using kerberos credentials with ldap_sasl_bind_s function

本文关键字:ldap sasl bind 函数 GSSAPI 绑定 kerberos SASL      更新时间:2023-10-16

我正在尝试使用kerberos凭据与ldap_sasl_bind_s函数实现GSSAPI上的SASL绑定。我遵循ldap_sasl_bind_s(GSSAPI)中描述的步骤—凭证BERVAL结构链

中应该提供的内容

我得到了上述链中描述的所有调用的预期返回值,直到最后(第三次)对ldap_sasl_bind_s的调用,该调用因LDAP_INVALID_CREDENTIALS错误而失败。我还看到在windows事件查看器

中出现以下错误
Error value:
80090308: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 5, v1771

请注意,我有两个应用程序,让我们称之为客户端和服务器,客户端是在一些活动域帐户下运行,服务器应用程序从客户端接收凭据,并尝试使用客户端提供的令牌绑定到ldap。以下是我所做的步骤。客户端调用

int res = AcquireCredentialsHandle(NULL, "Kerberos"  , SECPKG_CRED_BOTH,NULL, NULL, NULL, NULL, &credhandle1, &expry1); 

在填充了credhandle1之后,我将它传递给客户端InitializeSecurityContext的第一次调用

  res = InitializeSecurityContext(&credhandle1,NULL,(SEC_CHAR*)(&spn1[0]),ISC_REQ_INTEGRITY|ISC_REQ_MUTUAL_AUTH|ISC_REQ_SEQUENCE_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_REQ_DELEGATE,0,SECURITY_NATIVE_DREP ,NULL,0,&NewContext2,&sec_buffer_desc1,&contextattr2,&expry2);

我使用活动目录设置中可用的spn-s之一。这个调用返回SEC_I_CONTINUE_NEEDED,并填充sec_buffer_desc1,然后将sec_buffer_desc1传递给我的服务器应用程序,用构造的令牌调用ldap_sasl_bind_s。

第一次调用ldap_sasl_bind_s返回LDAP_SUCCESS,并填充结构体berval *servresp,下面是调用

rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred1, NULL, NULL, &servresp);

servresp中的令牌传递给客户端应用程序,该应用程序执行InitializeSecurityContext的第二次调用,如下所示

res = InitializeSecurityContext(&credhandle1, &NewContext2, (SEC_CHAR*)(&spn1[0]),ISC_REQ_INTEGRITY|ISC_REQ_MUTUAL_AUTH|ISC_REQ_SEQUENCE_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_REQ_DELEGATE,0, 0, &InBuffDesc3, 0, &NewContext3, &sec_buffer_desc3, &contextattr3, &expry3);

InBuffDesc3包含从服务器返回的凭据。这个调用返回sece_ok,并在sec_buffer_desc3中产生空的输出令牌,此令牌传递给第二次调用ldap_sasl_bind_s的服务器

rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred2, NULL, NULL, &servresp2);

这个调用再次返回LDAP_SUCCESS,并用32字节长的令牌填充servresp2,然后将其传递给客户机。服务器上的最后一个错误消息是LDAP_SASL_BIND_IN_PROGRESS。

我传递给DecryptMessage NewContext2(在InitSecContext调用中收到)作为第一个参数。作为第二个参数传递给DecryptMessage的BuffDesc包含指向两个SecBuffer对象的指针,SecBuffer[0]具有类型SECBUFFER_STREAM并包含服务器响应(由ldap_sasl_bind_s的第二次调用生成的令牌)和SecBuffer[1]具有类型SECBUFFER_DATA。在DecryptMessage调用SecBuffer[1]被一些令牌填充后(它的大小也在改变,所以我认为它包含解密消息)。DecryptMessage的第三个参数为0,最后一个参数由解密消息后的SECQOP_WRAP_NO_ENCRYPT值填充。

ULONG ulQop;
res = DecryptMessage( &NewContext2, &BuffDesc, 0, &ulQop); 

在SECBUFFER_DATA缓冲区传递给DecryptMessage我收到4字节长的令牌(这似乎是输入SECBUFFER_STREAM缓冲区的最后4字节)。"解密消息(SecBuff[1].pvBuffer)"的第一个字节是7,然后我执行以下操作

    unsigned char * ptr = (unsigned char *)SecBuff[1].pvBuffer;
    int maxsize = (ptr[1]<<16) | (ptr[2]<<8)| (ptr[3]);
    ptr = (unsigned char *) malloc(4);
    ptr[0]= 4;
    ptr[1]= maxsize>>16;
    ptr[2]= maxsize>>8;
    ptr[3]= maxsize; 

我正在为EncryptMessage使用构造输入SecBufferDesc对象三个缓冲区,第一个具有类型SECBUFFER_TOKEN,在EncryptMEssage调用后填充(所以我认为它在此调用后包含加密消息),第二个具有SECBUFFER_DATA类型并包含我上面构造的ptr,以及类型SECBUFFER_PADDING的第三个缓冲区。我调用EncryptMessage如下

err = EncryptMessage(&NewContext2,fQOP,&inSecBufDescSecond, 0);

返回sece_ok,并在缓冲区中生成类型为SECBUFFER_TOKEN的28字节长的令牌,然后将此输出令牌传递给我的服务器应用程序,该应用程序使用此令牌调用ldap_sasl_bind_s作为客户端凭证,并因无效凭证错误而失败。

我查看了帖子中提到的RFC,并试图找到SASL和kerberos凭据的任何工作示例,但是无法处理此错误。任何帮助将不胜感激,你能帮助我得到这个问题的底部,或提供一些工作代码的例子,让我可以看看。

谢谢!-Grigor

我遇到了完全相同的问题,我想我找到了解决方案:

在第三个ldap_sasl_bind_s调用中发送的消息应该是给EncryptMessage的所有三个缓冲区的的连接(按TOKEN, DATA, PADDING的顺序)

当我这样做的时候,它工作了!