I am trying to implement SASL bind over GSSAPI using Kerberos credentials with the ldap_sasl_bind_s() function. I follow the steps described in the ldap_sasl_bind_s(GSSAPI) - What should be provided in the credentials BERVAL structure chain.
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
Please note I have two applications. Let us call them client and server; client is being run under some Active Directory domain account, and the 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);
After filling credhandle1, I pass it to the first call of InitializeSecurityContext again on 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);
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 the constructed token.
The 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);
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 contains credentials returned from the server. This call returns SEC_E_OK, and produced an empty output token in sec_buffer_desc3. This token is passed to the server which calls ldap_sasl_bind_s() a second time
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred2, NULL, NULL, &servresp2);
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.
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). The 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);
In SECBUFFER_DATA buffer passed to DecryptMessage, I receive a four-bytes long token (which seems to be the last four 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;
I am constructing the input SecBufferDesc object for EncryptMessage using three buffers. The 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);
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.
I looked at the RFC mentioned in the post and also tried to find any working example with SASL and kerberos credentials. However, I was not able to deal with this error.
How can I get to the bottom of this issue? Or what could some working code example be?
ldap_sasl_bind_s
. OpenLDAP uses Cyrus SASL for all SASL operations...or are you using the Windows-native LDAP metthods? – UnscreenedGSSAPI
andGSS-SPNEGO
through SSPI. If you plan to pass an alternative credential, use theberval
structure. Assign the SSPI cred handle to the value of theberval
struct and the length withsizeof
. Should probably be 8 bytes. First try to implement auth only w/o conf and int. – Unscreened