SASL bind over GSSAPI using Kerberos credentials the with ldap_sasl_bind_s function
Asked Answered
P

1

3

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?

Piano answered 13/9, 2015 at 22:0 Comment(5)
Cyrus SASL does not support SSPI, GSS-API only. Have you considered to implement an appropriate plugin rather than satisfying the loop?Unscreened
Hi Michael, thanks for your response. Actually I don't use Cyrus I use SSPI.Piano
Yes, you do, hence the name ldap_sasl_bind_s. OpenLDAP uses Cyrus SASL for all SASL operations...or are you using the Windows-native LDAP metthods?Unscreened
Yes, I don't use Open Ldap. I use Winows-native LDAP methods. Currently I am trying to implement single sign on for Windows Active Directory users of my application. My server application should support Kerberos authentication using LDAP server (instead of connecting directly to Kerberos server).My server should not be a part of Active Directory (Kerberos) domain.Piano
Why? The Microsoft implementation does already implement the mechs GSSAPI and GSS-SPNEGO through SSPI. If you plan to pass an alternative credential, use the berval structure. Assign the SSPI cred handle to the value of the berval struct and the length with sizeof. Should probably be 8 bytes. First try to implement auth only w/o conf and int.Unscreened
Z
3

I ran into the exact same problem, and I think I found the solution:

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!

Zoster answered 18/10, 2019 at 20:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.