3
votes

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

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 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); 

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);

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.

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 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);

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). 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 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; 

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);

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 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.

Thank you ! -Grigor

1
Cyrus SASL does not support SSPI, GSS-API only. Have you considered to implement an appropriate plugin rather than satisfying the loop?Michael-O
Hi Michael, thanks for your response. Actually I don't use Cyrus I use SSPI.Grigor Aleksanyan
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?Michael-O
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.Grigor Aleksanyan
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.Michael-O

1 Answers

2
votes

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!