Пример #1
0
static bool ClientConnect(SslHandle *ssl, const char *host)
{
	if (SecIsValidHandle(&ssl->hContext)) {
		g_pSSPI->DeleteSecurityContext(&ssl->hContext);
		SecInvalidateHandle(&ssl->hContext);
	}

	if (MySslEmptyCache) MySslEmptyCache();

	DWORD dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
		ISC_REQ_REPLAY_DETECT |
		ISC_REQ_CONFIDENTIALITY |
		ISC_REQ_EXTENDED_ERROR |
		ISC_REQ_ALLOCATE_MEMORY |
		ISC_REQ_STREAM;

	//  Initiate a ClientHello message and generate a token.
	SecBuffer OutBuffers[1];
	OutBuffers[0].pvBuffer = NULL;
	OutBuffers[0].BufferType = SECBUFFER_TOKEN;
	OutBuffers[0].cbBuffer = 0;

	SecBufferDesc OutBuffer;
	OutBuffer.cBuffers = _countof(OutBuffers);
	OutBuffer.pBuffers = OutBuffers;
	OutBuffer.ulVersion = SECBUFFER_VERSION;

	TimeStamp tsExpiry;
	DWORD dwSSPIOutFlags;
	SECURITY_STATUS scRet = g_pSSPI->InitializeSecurityContext(&hCreds, NULL, _A2T(host), dwSSPIFlags, 0, 0, NULL, 0,
		&ssl->hContext, &OutBuffer, &dwSSPIOutFlags, &tsExpiry);
	if (scRet != SEC_I_CONTINUE_NEEDED) {
		ReportSslError(scRet, __LINE__);
		return 0;
	}

	// Send response to server if there is one.
	if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL) {
		DWORD cbData = send(ssl->s, (char*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
		if (cbData == SOCKET_ERROR || cbData == 0) {
			Netlib_Logf(NULL, "SSL failure sending connection data (%d %d)", ssl->s, WSAGetLastError());
			g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
			return 0;
		}

		// Free output buffer.
		g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
		OutBuffers[0].pvBuffer = NULL;
	}

	return ClientHandshakeLoop(ssl, TRUE) == SEC_E_OK;
}
Пример #2
0
// 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;
}
Пример #3
0
void NetlibSslShutdown(SslHandle *ssl)
{
	if (ssl == NULL || !SecIsValidHandle(&ssl->hContext))
		return;

	DWORD dwType = SCHANNEL_SHUTDOWN;

	SecBuffer OutBuffers[1];
	OutBuffers[0].pvBuffer = &dwType;
	OutBuffers[0].BufferType = SECBUFFER_TOKEN;
	OutBuffers[0].cbBuffer = sizeof(dwType);

	SecBufferDesc OutBuffer;
	OutBuffer.cBuffers = _countof(OutBuffers);
	OutBuffer.pBuffers = OutBuffers;
	OutBuffer.ulVersion = SECBUFFER_VERSION;

	SECURITY_STATUS scRet = g_pSSPI->ApplyControlToken(&ssl->hContext, &OutBuffer);
	if (FAILED(scRet))
		return;

	// Build an SSL close notify message.

	DWORD dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
		ISC_REQ_REPLAY_DETECT |
		ISC_REQ_CONFIDENTIALITY |
		ISC_RET_EXTENDED_ERROR |
		ISC_REQ_ALLOCATE_MEMORY |
		ISC_REQ_STREAM;

	OutBuffers[0].pvBuffer = NULL;
	OutBuffers[0].BufferType = SECBUFFER_TOKEN;
	OutBuffers[0].cbBuffer = 0;

	OutBuffer.cBuffers = 1;
	OutBuffer.pBuffers = OutBuffers;
	OutBuffer.ulVersion = SECBUFFER_VERSION;

	TimeStamp tsExpiry;
	DWORD dwSSPIOutFlags;
	scRet = g_pSSPI->InitializeSecurityContext(&hCreds, &ssl->hContext, NULL, dwSSPIFlags, 0, 0, NULL, 0,
		&ssl->hContext, &OutBuffer, &dwSSPIOutFlags, &tsExpiry);
	if (FAILED(scRet))
		return;

	// Send the close notify message to the server.
	if (OutBuffers[0].pvBuffer != NULL && OutBuffers[0].cbBuffer != 0) {
		send(ssl->s, (char*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
		g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
	}
}
Пример #4
0
HANDLE NetlibInitSecurityProvider(const TCHAR* szProvider, const TCHAR* szPrincipal)
{
	HANDLE hSecurity = NULL;

	if (_tcsicmp(szProvider, _T("Basic")) == 0)
	{
		NtlmHandleType* hNtlm = (NtlmHandleType*)mir_calloc(sizeof(NtlmHandleType));
		hNtlm->szProvider = mir_tstrdup(szProvider);
		SecInvalidateHandle(&hNtlm->hClientContext);
		SecInvalidateHandle(&hNtlm->hClientCredential);
		ntlmCnt++;

		return hNtlm;
	}

	WaitForSingleObject(hSecMutex, INFINITE);

	if (secCnt == 0 ) 
	{
		LoadSecurityLibrary();
		secCnt += g_hSecurity != NULL;
	}
	else secCnt++;

	if (g_pSSPI != NULL) 
	{
		PSecPkgInfo ntlmSecurityPackageInfo;
		bool isGSSAPI = _tcsicmp(szProvider, _T("GSSAPI")) == 0;
		const TCHAR *szProviderC = isGSSAPI ? _T("Kerberos") : szProvider;
		SECURITY_STATUS sc = g_pSSPI->QuerySecurityPackageInfo((LPTSTR)szProviderC, &ntlmSecurityPackageInfo);
		if (sc == SEC_E_OK)
		{
			NtlmHandleType* hNtlm;

			hSecurity = hNtlm = (NtlmHandleType*)mir_calloc(sizeof(NtlmHandleType));
			hNtlm->cbMaxToken = ntlmSecurityPackageInfo->cbMaxToken;
			g_pSSPI->FreeContextBuffer(ntlmSecurityPackageInfo);

			hNtlm->szProvider = mir_tstrdup(szProvider);
			hNtlm->szPrincipal = mir_tstrdup(szPrincipal ? szPrincipal : _T(""));
			SecInvalidateHandle(&hNtlm->hClientContext);
			SecInvalidateHandle(&hNtlm->hClientCredential);
			ntlmCnt++;
		}
	}

	ReleaseMutex(hSecMutex);
	return hSecurity;
}
Пример #5
0
/*
 * Query specified package for it's maximum token size.
 */
static int getMaxTokenSize(char *package, ULONG * maxTokenSize)
{
    SECURITY_STATUS status;
    SecPkgInfo *packageSecurityInfo = NULL;

    status = pSFT->QuerySecurityPackageInfo(package, &packageSecurityInfo);
    if (status == SEC_E_OK) {
        *maxTokenSize = packageSecurityInfo->cbMaxToken;
        if (pSFT->FreeContextBuffer(packageSecurityInfo) != SEC_E_OK) {
            NE_DEBUG(NE_DBG_HTTPAUTH,
                     "sspi: Unable to free security package info.");
        }
    } else {
        NE_DEBUG(NE_DBG_HTTPAUTH,
                 "sspi: QuerySecurityPackageInfo [failed] [%x].", status);
        return -1;
    }

    return 0;
}
Пример #6
0
static SECURITY_STATUS ClientHandshakeLoop(SslHandle *ssl, BOOL fDoInitialRead)
{
	DWORD dwSSPIFlags =
		ISC_REQ_SEQUENCE_DETECT |
		ISC_REQ_REPLAY_DETECT |
		ISC_REQ_CONFIDENTIALITY |
		ISC_REQ_EXTENDED_ERROR |
		ISC_REQ_ALLOCATE_MEMORY |
		ISC_REQ_STREAM;

	ssl->cbIoBuffer = 0;

	BOOL fDoRead = fDoInitialRead;

	SECURITY_STATUS scRet = SEC_I_CONTINUE_NEEDED;

	// Loop until the handshake is finished or an error occurs.
	while (scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) {
		// Read server data
		if (0 == ssl->cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE) {
			if (fDoRead) {
				static const TIMEVAL tv = { 6, 0 };
				fd_set fd;

				// If buffer not large enough reallocate buffer
				if (ssl->sbIoBuffer <= ssl->cbIoBuffer) {
					ssl->sbIoBuffer += 4096;
					ssl->pbIoBuffer = (PUCHAR)mir_realloc(ssl->pbIoBuffer, ssl->sbIoBuffer);
				}

				FD_ZERO(&fd);
				FD_SET(ssl->s, &fd);
				if (select(1, &fd, NULL, NULL, &tv) != 1) {
					Netlib_Logf(NULL, "SSL Negotiation failure recieving data (timeout) (bytes %u)", ssl->cbIoBuffer);
					scRet = ERROR_NOT_READY;
					break;
				}

				DWORD cbData = recv(ssl->s, (char*)ssl->pbIoBuffer + ssl->cbIoBuffer, ssl->sbIoBuffer - ssl->cbIoBuffer, 0);
				if (cbData == SOCKET_ERROR) {
					Netlib_Logf(NULL, "SSL Negotiation failure recieving data (%d)", WSAGetLastError());
					scRet = ERROR_NOT_READY;
					break;
				}
				if (cbData == 0) {
					Netlib_Logf(NULL, "SSL Negotiation connection gracefully closed");
					scRet = ERROR_NOT_READY;
					break;
				}

				ssl->cbIoBuffer += cbData;
			}
			else fDoRead = TRUE;
		}

		// Set up the input buffers. Buffer 0 is used to pass in data
		// received from the server. Schannel will consume some or all
		// of this. Leftover data (if any) will be placed in buffer 1 and
		// given a buffer type of SECBUFFER_EXTRA.

		SecBuffer InBuffers[2];
		InBuffers[0].pvBuffer = ssl->pbIoBuffer;
		InBuffers[0].cbBuffer = ssl->cbIoBuffer;
		InBuffers[0].BufferType = SECBUFFER_TOKEN;

		InBuffers[1].pvBuffer = NULL;
		InBuffers[1].cbBuffer = 0;
		InBuffers[1].BufferType = SECBUFFER_EMPTY;

		SecBufferDesc InBuffer;
		InBuffer.cBuffers = _countof(InBuffers);
		InBuffer.pBuffers = InBuffers;
		InBuffer.ulVersion = SECBUFFER_VERSION;

		// Set up the output buffers. These are initialized to NULL
		// so as to make it less likely we'll attempt to free random
		// garbage later.

		SecBuffer OutBuffers[1];
		OutBuffers[0].pvBuffer = NULL;
		OutBuffers[0].BufferType = SECBUFFER_TOKEN;
		OutBuffers[0].cbBuffer = 0;

		SecBufferDesc OutBuffer;
		OutBuffer.cBuffers = _countof(OutBuffers);
		OutBuffer.pBuffers = OutBuffers;
		OutBuffer.ulVersion = SECBUFFER_VERSION;

		TimeStamp tsExpiry;
		DWORD dwSSPIOutFlags;
		scRet = g_pSSPI->InitializeSecurityContext(&hCreds, &ssl->hContext, NULL, dwSSPIFlags, 0, 0,
			&InBuffer, 0, NULL, &OutBuffer, &dwSSPIOutFlags, &tsExpiry);

		// If success (or if the error was one of the special extended ones),
		// send the contents of the output buffer to the server.
		if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || (FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))) {
			if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL) {
				DWORD cbData = send(ssl->s, (char*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
				if (cbData == SOCKET_ERROR || cbData == 0) {
					Netlib_Logf(NULL, "SSL Negotiation failure sending data (%d)", WSAGetLastError());
					g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
					return SEC_E_INTERNAL_ERROR;
				}

				// Free output buffer.
				g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
				OutBuffers[0].pvBuffer = NULL;
			}
		}

		// we need to read more data from the server and try again.
		if (scRet == SEC_E_INCOMPLETE_MESSAGE)
			continue;

		// handshake completed successfully.
		if (scRet == SEC_E_OK) {
			// Store remaining data for further use
			if (InBuffers[1].BufferType == SECBUFFER_EXTRA) {
				memmove(ssl->pbIoBuffer, ssl->pbIoBuffer + (ssl->cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer);
				ssl->cbIoBuffer = InBuffers[1].cbBuffer;
			}
			else ssl->cbIoBuffer = 0;
			break;
		}

		// Check for fatal error.
		if (FAILED(scRet)) break;

		// server just requested client authentication.
		if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) {
			// Server has requested client authentication and
			// GetNewClientCredentials(ssl);

			// Go around again.
			fDoRead = FALSE;
			scRet = SEC_I_CONTINUE_NEEDED;
			continue;
		}

		// Copy any leftover data from the buffer, and go around again.
		if (InBuffers[1].BufferType == SECBUFFER_EXTRA) {
			memmove(ssl->pbIoBuffer, ssl->pbIoBuffer + (ssl->cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer);
			ssl->cbIoBuffer = InBuffers[1].cbBuffer;
		}
		else ssl->cbIoBuffer = 0;
	}

	// Delete the security context in the case of a fatal error.
	ReportSslError(scRet, __LINE__);

	if (ssl->cbIoBuffer == 0) {
		mir_free(ssl->pbIoBuffer);
		ssl->pbIoBuffer = NULL;
		ssl->sbIoBuffer = 0;
	}

	return scRet;
}
Пример #7
0
// 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;
}