使用带有 ldap_sasl_bind_s 函数的 kerberos 凭据通过 GSSAPI 绑定 SASL
我正在尝试使用带有 ldap_sasl_bind_s 函数的 kerberos 凭据通过 GSSAPI 实现 SASL 绑定.我遵循 ldap_sasl_bind_s(GSSAPI) - 应该在凭证 BERVAL 结构中提供什么 链
I am trying to implement SASL bind over GSSAPI using kerberos credentials with ldap_sasl_bind_s function. I follow to the steps described in ldap_sasl_bind_s(GSSAPI) - What should be provided in the credentials BERVAL structure chain
我得到了上述链中描述的所有调用的预期返回值,直到最后一次(第三次)调用 ldap_sasl_bind_s,该调用因 LDAP_INVALID_CREDENTIALS 错误而失败.我还看到 Windows 事件查看器中发生以下错误
I get expected return values for all calls described in the mentioned chain, until the last(third) call to ldap_sasl_bind_s, which fails with LDAP_INVALID_CREDENTIALS error. Also I see the following error occurs in the windows event viewer
Error value:
80090308: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 5, v1771
请注意我有两个应用程序,我们称它们为客户端和服务器,客户端在某个活动域帐户下运行,服务器应用程序从客户端接收凭据并尝试使用客户端提供的令牌绑定到 ldap.这是我做的步骤.客户来电
Please note I have two applications, let us call them client and server, client is being run under some Active domain account,server application receives credentials from the client and tries to bind to ldap using tokens provided by the client. here are the steps I do. Client calls
int res = AcquireCredentialsHandle(NULL, "Kerberos" , SECPKG_CRED_BOTH,NULL, NULL, NULL, NULL, &credhandle1, &expry1);
填充 credhandle1 后,我将它传递给客户端的 InitializeSecurityContext 的第一次调用
After filling credhandle1 I pass it to the first call of InitializeSecurityContext again in the client side
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,然后将其传递给我的服务器应用程序以使用构造的令牌调用 ldap_sasl_bind_s.
I use one of the spn-s available in my active directory setup. This call returns SEC_I_CONTINUE_NEEDED, and fills sec_buffer_desc1 which is then passed to my server application to call ldap_sasl_bind_s with constructed token.
第一次调用ldap_sasl_bind_s返回LDAP_SUCCESS,并填充struct berval *servresp,这里是调用
First call of ldap_sasl_bind_s returns LDAP_SUCCESS, and fills struct berval *servresp, here is the call
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred1, NULL, NULL, &servresp);
servresp 中的令牌被传递给执行 InitializeSecurityContext 的第二次调用的客户端应用程序,如下所示
The token in servresp is passed to the client application which does the second call of InitializeSecurityContext as follows
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 包含从服务器返回的凭据.此调用返回 SEC_E_OK,并在 sec_buffer_desc3 中生成空输出令牌,此令牌被传递给第二次调用 ldap_sasl_bind_s 的服务器
InBuffDesc3 contains credentials returned from the server. This call returns SEC_E_OK, and produced empty output token in sec_buffer_desc3, This token is passed to the server which calls ldap_sasl_bind_s second time
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred2, NULL, NULL, &servresp2);
此调用再次返回 LDAP_SUCCESS 并用 32 字节长的令牌填充 servresp2,然后将其传递给客户端.服务器中的最后一条错误消息是 LDAP_SASL_BIND_IN_PROGRESS.
This call again returns LDAP_SUCCESS and fills servresp2 with 32 byte long token which is then passed to the client. Last error message in the server is 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 值填充.这是电话
I pass to DecryptMessage NewContext2 (that was received in InitSecContext call) as a first argument. BuffDesc passed as second argument to DecryptMessage contains pointer to two SecBuffer objects, SecBuffer[0] has type SECBUFFER_STREAM and contains server response (token generated by the second call of ldap_sasl_bind_s) and SecBuffer[1] has type SECBUFFER_DATA.After DecryptMessage call SecBuffer[1] is being filled by some token(also it's size is being changed, so I think that it contains decrypted message). Third argument of DecryptMessage is 0 and the last one is being filled by SECQOP_WRAP_NO_ENCRYPT value after Decrypting the message. Here is the call
ULONG ulQop;
res = DecryptMessage( &NewContext2, &BuffDesc, 0, &ulQop);
在传递给 DecryptMessage 的 SECBUFFER_DATA 缓冲区中,我收到 4 个字节长的令牌(这似乎是输入 SECBUFFER_STREAM 缓冲区的最后 4 个字节).decrypted message(SecBuff[1].pvBuffer)"的第一个字节是7,那么我做如下
In SECBUFFER_DATA buffer passed to DecryptMessage I receive 4 bytes long token (which seems to be the last 4 bytes of input SECBUFFER_STREAM buffer). The first byte of "decrypted message(SecBuff[1].pvBuffer)" is 7, then I do the following
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
I am constructing the input SecBufferDesc object for EncryptMessage using three buffers, first one has type SECBUFFER_TOKEN which is filled after EncryptMEssage call(so I think it contains encrypted message after this call), the second one has SECBUFFER_DATA type and contains ptr I have constructed above, and the third buffer of type SECBUFFER_PADDING. I call EncryptMessage as follows
err = EncryptMessage(&NewContext2,fQOP,&inSecBufDescSecond, 0);
它返回 SEC_E_OK,并在缓冲区中生成 28 字节长的令牌,类型为 SECBUFFER_TOKEN,然后将此输出令牌传递给我的服务器应用程序,该服务器应用程序将此令牌作为客户端凭据调用 ldap_sasl_bind_s,并因无效凭据错误而失败.
which returns SEC_E_OK, and produces 28 bytes long token in the buffer with type SECBUFFER_TOKEN, this output token is then passed to my server application which calls ldap_sasl_bind_s with this token as client credentials and fails with invalid credentials error.
我查看了帖子中提到的 RFC,还试图找到任何具有 SASL 和 kerberos 凭据的工作示例,但是无法处理此错误.任何帮助将不胜感激,您能否帮助我深入了解此问题,或提供一些工作代码示例以便我查看.
I looked at RFC mentioned in the post also tried to find any working example with SASL and kerberos credentials, however was not able to deal with this error. Any help will be appreciated, could you please help me to get to the bottom of this issue, or provide some working code example so that I can take a look.
谢谢!-格里戈尔
推荐答案
我遇到了完全相同的问题,我想我找到了解决方案:
I ran into the exact same problem, and I think I found the solution:
您在第三个 ldap_sasl_bind_s 调用中发送的消息应该是 所有三个 给 EncryptMessage 的缓冲区的串联(按照 TOKEN、DATA、PADDING 的顺序)
The message you send in the third ldap_sasl_bind_s call should be the concatenation of all three buffers given to EncryptMessage (in the order TOKEN, DATA, PADDING)
当我这样做时,它会起作用!
When I do that, it works!
相关文章