// Initiate a ClientHello message and generate a token. SECURITY_STATUS chs_hello (void) { DWORD dwFlagsIn, dwFlagsOut; SecBuffer sb[1]; SecBufferDesc hs; dwFlagsIn = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; sb[0].pvBuffer = NULL; sb[0].BufferType = SECBUFFER_TOKEN; sb[0].cbBuffer = 0; hs.cBuffers = 1; hs.pBuffers = sb; hs.ulVersion = SECBUFFER_VERSION; ss = sspi->InitializeSecurityContextA (&hClientCreds, NULL, pszServer, dwFlagsIn, 0, SECURITY_NATIVE_DREP, NULL, 0, &hContext, &hs, &dwFlagsOut, &ts); // should indicate continuing if (ss==SEC_I_CONTINUE_NEEDED) { // send data if (sb[0].cbBuffer != 0) { send (s, sb[0].pvBuffer, sb[0].cbBuffer, 0); ss = sspi->FreeContextBuffer (sb[0].pvBuffer); } } return ss; }
// perform SSL handshake with remote system SECURITY_STATUS chs (void) { DWORD dwFlagsIn, dwFlagsOut; SecBuffer ib[2], ob[1]; SecBufferDesc in, out; DWORD cbIoBuffer=0; PBYTE IoBuffer; int len; BOOL bRead=TRUE; // 8192 should be enough for handshake but // if you see any errors, try increasing it. IoBuffer = LocalAlloc (LMEM_FIXED, 8192); if ((ss=chs_hello())!=SEC_E_OK) { return ss; } dwFlagsIn = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; ss=SEC_I_CONTINUE_NEEDED; while (ss==SEC_I_CONTINUE_NEEDED || ss==SEC_E_INCOMPLETE_MESSAGE) { if (ss==SEC_E_INCOMPLETE_MESSAGE || cbIoBuffer==0) { if (bRead) { len=recv (s, &IoBuffer[cbIoBuffer], 8192, 0); // some socket error if (len<=0) { break; } cbIoBuffer += len; } else { bRead=TRUE; } } ib[0].pvBuffer = IoBuffer; ib[0].cbBuffer = cbIoBuffer; ib[0].BufferType = SECBUFFER_TOKEN; ib[1].pvBuffer = NULL; ib[1].cbBuffer = 0; ib[1].BufferType = SECBUFFER_EMPTY; in.cBuffers = 2; in.pBuffers = ib; in.ulVersion = SECBUFFER_VERSION; ob[0].pvBuffer = NULL; ob[0].BufferType = SECBUFFER_TOKEN; ob[0].cbBuffer = 0; out.cBuffers = 1; out.pBuffers = ob; out.ulVersion = SECBUFFER_VERSION; ss = sspi->InitializeSecurityContextA (&hClientCreds, &hContext, NULL, dwFlagsIn, 0, SECURITY_NATIVE_DREP, &in, 0, NULL, &out, &dwFlagsOut, &ts); // might get SEC_E_ILLEGAL_MESSAGE here if (ss==SEC_E_OK || ss==SEC_I_CONTINUE_NEEDED || FAILED (ss) && (dwFlagsOut & ISC_RET_EXTENDED_ERROR)) { if (ob[0].cbBuffer != 0) { len=send (s, ob[0].pvBuffer, ob[0].cbBuffer, 0); // socket error if (len<=0) { break; } sspi->FreeContextBuffer (ob[0].pvBuffer); } } if (ss==SEC_E_INCOMPLETE_MESSAGE) continue; if (ss==SEC_E_OK) { if (ib[1].BufferType==SECBUFFER_EXTRA) { // i don't handle extra data here but it should be. } break; } // Copy any leftover data from the "extra" buffer, and go around again. if ( ib[1].BufferType == SECBUFFER_EXTRA ) { MoveMemory (IoBuffer, &IoBuffer[cbIoBuffer - ib[1].cbBuffer], ib[1].cbBuffer); cbIoBuffer = ib[1].cbBuffer; } else cbIoBuffer = 0; } LocalFree (IoBuffer); return ss; }