예제 #1
0
파일: cms.c 프로젝트: MavenRain/sslcmd
// 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;
}
예제 #2
0
/*
 * Resets the context
 */
static void resetContext(SSPIContext * sspiContext)
{
    pSFT->DeleteSecurityContext(&(sspiContext->context));
#if defined(_MSC_VER) && _MSC_VER <= 1200
    pSFT->FreeCredentialHandle(&(sspiContext->credentials));
#else
    pSFT->FreeCredentialsHandle(&(sspiContext->credentials));
#endif
    sspiContext->continueNeeded = 0;
}
예제 #3
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;
}
예제 #4
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);
	}
}
예제 #5
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;
}
예제 #6
0
static bool AcquireCredentials(void)
{
	SCHANNEL_CRED   SchannelCred;
	TimeStamp       tsExpiry;
	SECURITY_STATUS scRet;

	memset(&SchannelCred, 0, sizeof(SchannelCred));

	SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
	SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1_CLIENTS;
	SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;

	// Create an SSPI credential.
	scRet = g_pSSPI->AcquireCredentialsHandle(
		NULL,                   // Name of principal
		UNISP_NAME,             // Name of package
		SECPKG_CRED_OUTBOUND,   // Flags indicating use
		NULL,                   // Pointer to logon ID
		&SchannelCred,          // Package specific data
		NULL,                   // Pointer to GetKey() func
		NULL,                   // Value to pass to GetKey()
		&hCreds, 				// (out) Cred Handle
		&tsExpiry);             // (out) Lifetime (optional)

	ReportSslError(scRet, __LINE__);
	return scRet == SEC_E_OK;
}
예제 #7
0
/*
 * Wrapper arround initializeSecurityContext.  Supplies several
 * default parameters as well as logging in case of errors.
 */
static SECURITY_STATUS
initializeSecurityContext(CredHandle * credentials, CtxtHandle * context,
                          char *spn, ULONG contextReq,
                          SecBufferDesc * inBuffer, CtxtHandle * newContext,
                          SecBufferDesc * outBuffer)
{
    ULONG contextAttributes;
    SECURITY_STATUS status;

    status =
        pSFT->InitializeSecurityContext(credentials, context, spn, contextReq,
                                        0, SECURITY_NETWORK_DREP, inBuffer, 0,
                                        newContext, outBuffer,
                                        &contextAttributes, NULL);

    if (!SEC_SUCCESS(status)) {
        if (status == SEC_E_INVALID_TOKEN) {
            NE_DEBUG(NE_DBG_HTTPAUTH,
                     "InitializeSecurityContext [fail] SEC_E_INVALID_TOKEN.\n");
        } else if (status == SEC_E_UNSUPPORTED_FUNCTION) {
            NE_DEBUG(NE_DBG_HTTPAUTH,
                     "InitializeSecurityContext [fail] SEC_E_UNSUPPORTED_FUNCTION.\n");
        } else {
            NE_DEBUG(NE_DBG_HTTPAUTH,
                     "InitializeSecurityContext [fail] [%x].\n", status);
        }
    }

    return status;
}
예제 #8
0
파일: cms.c 프로젝트: MavenRain/sslcmd
// create credentials
SECURITY_STATUS create_creds (void)   
{
  DWORD  cSupportedAlgs = 0;
  ALG_ID rgbSupportedAlgs[16];
  
  ZeroMemory (&SchannelCred, sizeof (SchannelCred));

  SchannelCred.dwVersion             = SCHANNEL_CRED_VERSION;
  SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3 | SP_PROT_TLS1;

  if (aiKeyExch) { 
    rgbSupportedAlgs[cSupportedAlgs++] = aiKeyExch;
  }
  
  if (cSupportedAlgs) {
    SchannelCred.cSupportedAlgs    = cSupportedAlgs;
    SchannelCred.palgSupportedAlgs = rgbSupportedAlgs;
  }

  SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
  // We need manual validation
  SchannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
  
  ss = sspi->AcquireCredentialsHandleA (NULL, UNISP_NAME_A, 
            SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, 
            NULL, &hClientCreds, &ts);
  return ss;
}
예제 #9
0
void UnloadSslModule(void)
{
	if (g_pSSPI && SecIsValidHandle(&hCreds))
		g_pSSPI->FreeCredentialsHandle(&hCreds);
	CloseHandle(g_hSslMutex);
	if (g_hSchannel)
		FreeLibrary(g_hSchannel);
}
예제 #10
0
void NetlibSslFree(SslHandle *ssl)
{
	if (ssl == NULL) return;

	g_pSSPI->DeleteSecurityContext(&ssl->hContext);

	mir_free(ssl->pbRecDataBuf);
	mir_free(ssl->pbIoBuffer);
	memset(ssl, 0, sizeof(SslHandle));
	mir_free(ssl);
}
예제 #11
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;
}
예제 #12
0
파일: cms.c 프로젝트: MavenRain/sslcmd
void secure_info (void)
{
  SecPkgContext_ConnectionInfo ci;

  ss = sspi->QueryContextAttributes (&hContext, SECPKG_ATTR_CONNECTION_INFO, (PVOID)&ci);
  if(ss != SEC_E_OK) { printf("Error 0x%x querying connection info\n", ss); return; }

  printf ("  [ Protocol : %s\n",      alg2s(ci.dwProtocol));
  printf ("  [ Cipher   : %s-%i\n",   alg2s(ci.aiCipher), ci.dwCipherStrength);
  printf ("  [ Hash     : %s-%i\n",   alg2s(ci.aiHash),   ci.dwHashStrength  );
  printf ("  [ Exchange : %s-%i\n\n", alg2s(ci.aiExch),   ci.dwExchStrength  );
}
예제 #13
0
파일: cms.c 프로젝트: MavenRain/sslcmd
SECURITY_STATUS ssl_recv (void)
{
  SecBufferDesc  msg;
  SecBuffer      sb[4];
  DWORD          cbIoBuffer=0;
  SecBuffer      *pData=NULL, *pExtra=NULL;
  int            len, i;
  ss=SEC_E_INCOMPLETE_MESSAGE;
  
  do
  {
    if (cbIoBuffer==0 || ss==SEC_E_INCOMPLETE_MESSAGE)
    {
      len = recv (s, pbDataIn + cbIoBuffer, cbBufferLen - cbIoBuffer, 0);
      if (len<=0) break;
      
      cbIoBuffer += len;
      
      sb[0].pvBuffer   = pbDataIn;
      sb[0].cbBuffer   = cbIoBuffer;
    
      sb[0].BufferType = SECBUFFER_DATA;
      sb[1].BufferType = SECBUFFER_EMPTY;
      sb[2].BufferType = SECBUFFER_EMPTY;
      sb[3].BufferType = SECBUFFER_EMPTY;

      msg.ulVersion    = SECBUFFER_VERSION;
      msg.cBuffers     = 4;
      msg.pBuffers     = sb;
    
      ss = sspi->DecryptMessage (&hContext, &msg, 0, NULL);
    
      if (ss == SEC_I_CONTEXT_EXPIRED) break;
    
      for (i=0; i<4; i++) {
        if (pData==NULL && sb[i].BufferType==SECBUFFER_DATA) pData=&sb[i];
        if (pExtra==NULL && sb[i].BufferType==SECBUFFER_EXTRA) pExtra=&sb[i];
      }
      
      if (pData!=NULL)
      {
        cbDataIn=pData->cbBuffer;
        if (cbDataIn!=0)
        {
          memcpy (pbDataIn, pData->pvBuffer, cbDataIn);
          break;
        }
      }
    }
  } while (1);
  return SEC_E_OK;
}
예제 #14
0
void NetlibDestroySecurityProvider(HANDLE hSecurity)
{
	if (hSecurity == NULL) return;

	WaitForSingleObject(hSecMutex, INFINITE);

	if (ntlmCnt != 0) 
	{
		NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;
		if (SecIsValidHandle(&hNtlm->hClientContext)) g_pSSPI->DeleteSecurityContext(&hNtlm->hClientContext);
		if (SecIsValidHandle(&hNtlm->hClientCredential)) g_pSSPI->FreeCredentialsHandle(&hNtlm->hClientCredential);
		mir_free(hNtlm->szProvider);
		mir_free(hNtlm->szPrincipal);

		--ntlmCnt;

		mir_free(hNtlm);
	}

	if (secCnt && --secCnt == 0)
		FreeSecurityLibrary();

	ReleaseMutex(hSecMutex);
}
예제 #15
0
/*
 * Simplification wrapper arround AcquireCredentialsHandle as most of
 * the parameters do not change.
 */
static int acquireCredentialsHandle(CredHandle * credentials, char *package)
{
    SECURITY_STATUS status;
    TimeStamp timestamp;

    status =
        pSFT->AcquireCredentialsHandle(NULL, package, SECPKG_CRED_OUTBOUND,
                                       NULL, NULL, NULL, NULL, credentials,
                                       &timestamp);

    if (status != SEC_E_OK) {
        NE_DEBUG(NE_DBG_HTTPAUTH,
                 "sspi: AcquireCredentialsHandle [fail] [%x].\n", status);
        return -1;
    }

    return 0;
}
예제 #16
0
파일: cms.c 프로젝트: MavenRain/sslcmd
// encrypt and send data to remote system
SECURITY_STATUS ssl_send (void)
{
  SecBufferDesc  msg;
  SecBuffer      sb[4];
  
  // stream header
  sb[0].pvBuffer   = pbBufferOut; 
  sb[0].cbBuffer   = Sizes.cbHeader; 
  sb[0].BufferType = SECBUFFER_STREAM_HEADER;

  // stream data
  sb[1].pvBuffer   = pbBufferOut + Sizes.cbHeader;
  sb[1].cbBuffer   = cbDataOut; 
  sb[1].BufferType = SECBUFFER_DATA; 
  
  // stream trailer
  sb[2].pvBuffer   = pbBufferOut + Sizes.cbHeader + cbDataOut; 
  sb[2].cbBuffer   = Sizes.cbTrailer; 
  sb[2].BufferType = SECBUFFER_STREAM_TRAILER; 

  sb[3].pvBuffer   = SECBUFFER_EMPTY; 
  sb[3].cbBuffer   = SECBUFFER_EMPTY; 
  sb[3].BufferType = SECBUFFER_EMPTY;

  msg.ulVersion    = SECBUFFER_VERSION; 
  msg.cBuffers     = 4;
  msg.pBuffers     = sb; 
  
  // encrypt
  ss = sspi->EncryptMessage (&hContext, 0, &msg, 0);
  
  // send
  if (ss==SEC_E_OK) {
    send (s, pbBufferOut, sb[0].cbBuffer + sb[1].cbBuffer + sb[2].cbBuffer, 0);
  }
  return ss;
}
예제 #17
0
/*
 * Processes received authentication tokens as well as supplies the
 * response token.
 */
int ne_sspi_authenticate(void *context, const char *base64Token, char **responseToken)
{
    SecBufferDesc outBufferDesc;
    SecBuffer outBuffer;
    int status;
    SECURITY_STATUS securityStatus;
    ULONG contextFlags;

    SSPIContext *sspiContext;
    if (initialized <= 0) {
        return -1;
    }

    status = getContext(context, &sspiContext);
    if (status) {
        return status;
    }

    /* TODO: Not sure what flags should be set. joe: this needs to be
     * driven by the ne_auth interface; the GSSAPI code needs similar
     * flags. */
    contextFlags = ISC_REQ_CONFIDENTIALITY | ISC_REQ_MUTUAL_AUTH;

    initSingleEmptyBuffer(&outBufferDesc, &outBuffer);
    status = makeBuffer(&outBufferDesc, sspiContext->maxTokenSize);
    if (status) {
        return status;
    }

    if (base64Token) {
        SecBufferDesc inBufferDesc;
        SecBuffer inBuffer;

        if (!sspiContext->continueNeeded) {
            freeBuffer(&outBufferDesc);
            NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Got an unexpected token.\n");
            return -1;
        }

        initSingleEmptyBuffer(&inBufferDesc, &inBuffer);

        status = base64ToBuffer(base64Token, &inBufferDesc);
        if (status) {
            freeBuffer(&outBufferDesc);
            return status;
        }

        securityStatus =
            initializeSecurityContext(&sspiContext->credentials,
                                      &(sspiContext->context),
                                      sspiContext->serverName, contextFlags,
                                      &inBufferDesc, &(sspiContext->context),
                                      &outBufferDesc);
        if (securityStatus == SEC_E_OK)
        {
            sspiContext->authfinished = 1;
        }
        freeBuffer(&inBufferDesc);
    } else {
        if (sspiContext->continueNeeded) {
            freeBuffer(&outBufferDesc);
            NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Expected a token from server.\n");
            return -1;
        }
        if (sspiContext->authfinished && (sspiContext->credentials.dwLower || sspiContext->credentials.dwUpper)) {
            if (sspiContext->authfinished)
            {
                freeBuffer(&outBufferDesc);
                sspiContext->authfinished = 0;
                NE_DEBUG(NE_DBG_HTTPAUTH,"sspi: failing because starting over from failed try.\n");
                return -1;
            }
            sspiContext->authfinished = 0;
        }

        /* Reset any existing context since we are starting over */
        resetContext(sspiContext);

        if (acquireCredentialsHandle
            (&sspiContext->credentials, sspiContext->mechanism) != SEC_E_OK) {
                freeBuffer(&outBufferDesc);
                NE_DEBUG(NE_DBG_HTTPAUTH,
                    "sspi: acquireCredentialsHandle failed.\n");
                return -1;
        }

        securityStatus =
            initializeSecurityContext(&sspiContext->credentials, NULL,
                                      sspiContext->serverName, contextFlags,
                                      NULL, &(sspiContext->context),
                                      &outBufferDesc);
    }

    if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE
        || securityStatus == SEC_I_COMPLETE_NEEDED) {
        SECURITY_STATUS compleStatus =
            pSFT->CompleteAuthToken(&(sspiContext->context), &outBufferDesc);

        if (compleStatus != SEC_E_OK) {
            freeBuffer(&outBufferDesc);
            NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: CompleteAuthToken failed.\n");
            return -1;
        }
    }

    if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE
        || securityStatus == SEC_I_CONTINUE_NEEDED) {
        sspiContext->continueNeeded = 1;
    } else {
        sspiContext->continueNeeded = 0;
    }

    if (!(securityStatus == SEC_I_COMPLETE_AND_CONTINUE
          || securityStatus == SEC_I_COMPLETE_NEEDED
          || securityStatus == SEC_I_CONTINUE_NEEDED
          || securityStatus == SEC_E_OK)) {
        NE_DEBUG(NE_DBG_HTTPAUTH,
                 "sspi: initializeSecurityContext [failed] [%x].\n",
                 securityStatus);
        freeBuffer(&outBufferDesc);
        return -1;
    }

    *responseToken = ne_base64(outBufferDesc.pBuffers->pvBuffer,
                               outBufferDesc.pBuffers->cbBuffer);
    freeBuffer(&outBufferDesc);

    return 0;
}
예제 #18
0
static bool VerifyCertificate(SslHandle *ssl, PCSTR pszServerName, DWORD dwCertFlags)
{
	static LPSTR rgszUsages[] =
	{
		szOID_PKIX_KP_SERVER_AUTH,
		szOID_SERVER_GATED_CRYPTO,
		szOID_SGC_NETSCAPE
	};

	CERT_CHAIN_PARA          ChainPara = { 0 };
	HTTPSPolicyCallbackData  polHttps = { 0 };
	CERT_CHAIN_POLICY_PARA   PolicyPara = { 0 };
	CERT_CHAIN_POLICY_STATUS PolicyStatus = { 0 };
	PCCERT_CHAIN_CONTEXT     pChainContext = NULL;
	PCCERT_CONTEXT           pServerCert = NULL;
	DWORD scRet;

	PWSTR pwszServerName = mir_a2u(pszServerName);

	scRet = g_pSSPI->QueryContextAttributes(&ssl->hContext, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pServerCert);
	if (scRet != SEC_E_OK)
		goto cleanup;

	if (pServerCert == NULL) {
		scRet = SEC_E_WRONG_PRINCIPAL;
		goto cleanup;
	}

	ChainPara.cbSize = sizeof(ChainPara);
	ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
	ChainPara.RequestedUsage.Usage.cUsageIdentifier = _countof(rgszUsages);
	ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;

	if (!CertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore, &ChainPara, 0, NULL, &pChainContext)) {
		scRet = GetLastError();
		goto cleanup;
	}

	polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
	polHttps.dwAuthType = AUTHTYPE_SERVER;
	polHttps.fdwChecks = dwCertFlags;
	polHttps.pwszServerName = pwszServerName;

	PolicyPara.cbSize = sizeof(PolicyPara);
	PolicyPara.pvExtraPolicyPara = &polHttps;

	PolicyStatus.cbSize = sizeof(PolicyStatus);

	if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) {
		scRet = GetLastError();
		goto cleanup;
	}

	if (PolicyStatus.dwError) {
		scRet = PolicyStatus.dwError;
		goto cleanup;
	}

	scRet = SEC_E_OK;

cleanup:
	if (pChainContext)
		CertFreeCertificateChain(pChainContext);
	if (pServerCert)
		CertFreeCertificateContext(pServerCert);
	mir_free(pwszServerName);

	ReportSslError(scRet, __LINE__, true);
	return scRet == SEC_E_OK;
}
예제 #19
0
파일: cms.c 프로젝트: MavenRain/sslcmd
SECURITY_STATUS ReadDecrypt (void)

// calls recv() - blocking socket read
// http://msdn.microsoft.com/en-us/library/ms740121(VS.85).aspx

// The encrypted message is decrypted in place, overwriting the original contents of its buffer.
// http://msdn.microsoft.com/en-us/library/aa375211(VS.85).aspx

{
  SecBuffer       ExtraBuffer;
  SecBuffer       *pDataBuffer, *pExtraBuffer;

  SECURITY_STATUS scRet;            // unsigned long cbBuffer;    // Size of the buffer, in bytes
  SecBufferDesc   Message;        // unsigned long BufferType;  // Type of the buffer (below)
  SecBuffer       Buffers[4];    // void    SEC_FAR * pvBuffer;   // Pointer to the buffer

  DWORD           cbIoBuffer, cbData, length;
  PBYTE           buff;
  int             i;

  // Read data from server until done.
  cbIoBuffer = 0;
  scRet = 0;
  
  while(TRUE) // Read some data.
  {
    if( cbIoBuffer == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE ) // get the data
    {
      cbDataIn = recv(s, pbBufferIn + cbIoBuffer, cbBufferLen - cbIoBuffer, 0);
      if(cbDataIn == SOCKET_ERROR)
      {
        printf("**** Error %d reading data from server\n", WSAGetLastError());
        scRet = SEC_E_INTERNAL_ERROR;
        break;
      }
      else if(cbDataIn == 0) // Server disconnected.
      {
        if(cbIoBuffer)
        {
          printf("**** Server unexpectedly disconnected\n");
          scRet = SEC_E_INTERNAL_ERROR;
          return scRet;
        }
        else
        break; // All Done
      }
      else // success
      {
        cbIoBuffer += cbDataIn;
      }
    }

    // Decrypt the received data.
    Buffers[0].pvBuffer     = pbBufferIn;
    Buffers[0].cbBuffer     = cbIoBuffer;
    Buffers[0].BufferType   = SECBUFFER_DATA;  // Initial Type of the buffer 1
    Buffers[1].BufferType   = SECBUFFER_EMPTY; // Initial Type of the buffer 2
    Buffers[2].BufferType   = SECBUFFER_EMPTY; // Initial Type of the buffer 3
    Buffers[3].BufferType   = SECBUFFER_EMPTY; // Initial Type of the buffer 4

    Message.ulVersion       = SECBUFFER_VERSION;    // Version number
    Message.cBuffers        = 4;                                    // Number of buffers - must contain four SecBuffer structures.
    Message.pBuffers        = Buffers;                        // Pointer to array of buffers
    
    scRet = sspi->DecryptMessage(&hContext, &Message, 0, NULL);
    
    if( scRet == SEC_I_CONTEXT_EXPIRED ) break; // Server signalled end of session
    
    //      if( scRet == SEC_E_INCOMPLETE_MESSAGE - Input buffer has partial encrypted record, read more
    if( scRet != SEC_E_OK &&
        scRet != SEC_I_RENEGOTIATE &&
        scRet != SEC_I_CONTEXT_EXPIRED )
    { printf("**** DecryptMessage ");
      return scRet; }

    // Locate data and (optional) extra buffers.
    pDataBuffer  = NULL;
    pExtraBuffer = NULL;
    
    for(i = 1; i < 4; i++)
    {
      if( pDataBuffer  == NULL && Buffers[i].BufferType == SECBUFFER_DATA  ) pDataBuffer  = &Buffers[i];
      if( pExtraBuffer == NULL && Buffers[i].BufferType == SECBUFFER_EXTRA ) pExtraBuffer = &Buffers[i];
    }

    if (pDataBuffer!=NULL)
    {
      cbDataIn=pDataBuffer->cbBuffer;
      if (cbDataIn!=0)
      {
        memcpy (pbDataIn, pDataBuffer->pvBuffer, cbDataIn);
      }
    }
      
    // Move any "extra" data to the input buffer.
    if(pExtraBuffer)
    {
      printf ("extra");
      MoveMemory(pbBufferIn, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
      cbIoBuffer = pExtraBuffer->cbBuffer; // printf("cbIoBuffer= %d  \n", cbIoBuffer);
    }
    else
    cbIoBuffer = 0;
  printf ("\nhello");
  }

  return SEC_E_OK;
}
예제 #20
0
파일: cms.c 프로젝트: MavenRain/sslcmd
// 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;
}
예제 #21
0
/*
 * Resets the context
 */
static void resetContext(SSPIContext * sspiContext)
{
    pSFT->DeleteSecurityContext(&(sspiContext->context));
    pSFT->FreeCredentialsHandle(&(sspiContext->credentials));
    sspiContext->continueNeeded = 0;
}
예제 #22
0
파일: cms.c 프로젝트: MavenRain/sslcmd
int main (int argc, char *argv[])
{
  INIT_SECURITY_INTERFACE pInitSecurityInterface;
  
  // set buffer width of console
  setw (300);
  
  puts ("\n  [ cms v0.1 - Copyleft 2015 (x) @Odzhan\n");
  
  // set up default values
  args.address   = NULL;
  args.ai_family = AF_INET;
  args.port      = DEFAULT_PORT;
  args.port_nbr  = atoi(args.port);
  
  pInitSecurityInterface = (INIT_SECURITY_INTERFACE)GetProcAddress(LoadLibrary("Secur32"), "InitSecurityInterfaceA" );
  if (pInitSecurityInterface==NULL) printf ("didn't resolve");
  sspi = pInitSecurityInterface();
  
  // process command line
  parse_args(argc, argv);

  // resolve address and open socket
  if (open_tcp ()) 
  {
    start_handler ();
      
    // create credentials
    if (create_creds()==SEC_E_OK)
    {
      // connect to server
      if (connect (s, ai_addr, ai_addrlen) != SOCKET_ERROR) {
        // perform the handshake
        if (chs () == SEC_E_OK) {
          printf ("  [ connected\n\n");
          secure_info();
          ss=sspi->QueryContextAttributes (&hContext, SECPKG_ATTR_STREAM_SIZES, &Sizes );
          cbBufferLen  = Sizes.cbHeader  +  Sizes.cbMaximumMessage  +  Sizes.cbTrailer;
          pbBufferIn        = LocalAlloc(LMEM_FIXED, cbBufferLen);
          pbBufferOut       = LocalAlloc(LMEM_FIXED, cbBufferLen);
          pbDataIn=pbBufferIn + Sizes.cbHeader;
          pbDataOut=pbBufferOut + Sizes.cbHeader;
          cbBufferLen = Sizes.cbMaximumMessage;
          
          printf ("  [ running cmd\n");
          cmd();
            
        } else {
          printf ("  [ handshake failed\n");
        }
      } else {
        printf ("  [ unable to connect\n");
      }
    } else {
      printf ("  [ error creating credentials\n");
    }
    stop_handler ();
    close_tcp();
  }
  return 0;
}
예제 #23
0
char* CompleteGssapi(HANDLE hSecurity, unsigned char *szChallenge, unsigned chlsz)
{
	if (!szChallenge || !szChallenge[0]) return NULL;

	NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;
	unsigned char inDataBuffer[1024];

	SecBuffer inBuffers[2] = 
	{
		{ sizeof(inDataBuffer), SECBUFFER_DATA, inDataBuffer },
		{ chlsz, SECBUFFER_STREAM, szChallenge },
	};

	SecBufferDesc inBuffersDesc = { SECBUFFER_VERSION, 2, inBuffers };

	unsigned long qop = 0;
	SECURITY_STATUS sc = g_pSSPI->DecryptMessage(&hNtlm->hClientContext, &inBuffersDesc, 0, &qop);
	if (sc != SEC_E_OK) 
	{
		ReportSecError(sc, __LINE__);
		return NULL;
	}

	unsigned char LayerMask = inDataBuffer[0];
	unsigned int MaxMessageSize = htonl(*(unsigned*)&inDataBuffer[1]);

	SecPkgContext_Sizes sizes;
	sc = g_pSSPI->QueryContextAttributes(&hNtlm->hClientContext, SECPKG_ATTR_SIZES, &sizes);
	if (sc != SEC_E_OK) 
	{
		ReportSecError(sc, __LINE__);
		return NULL;
	}

	unsigned char *tokenBuffer = (unsigned char*)alloca(sizes.cbSecurityTrailer);
	unsigned char *paddingBuffer = (unsigned char*)alloca(sizes.cbBlockSize);

	unsigned char outDataBuffer[4] = { 1, 0, 16, 0 };

	SecBuffer outBuffers[3] = 
	{
		{ sizes.cbSecurityTrailer, SECBUFFER_TOKEN, tokenBuffer },
		{ sizeof(outDataBuffer), SECBUFFER_DATA, outDataBuffer },
		{ sizes.cbBlockSize, SECBUFFER_PADDING, paddingBuffer }
	};
	SecBufferDesc outBuffersDesc = { SECBUFFER_VERSION, 3, outBuffers };

	sc = g_pSSPI->EncryptMessage(&hNtlm->hClientContext, SECQOP_WRAP_NO_ENCRYPT, &outBuffersDesc, 0);
	if (sc != SEC_E_OK) 
	{
		ReportSecError(sc, __LINE__);
		return NULL;
	}

	unsigned i, ressz = 0;
	for (i = 0; i < outBuffersDesc.cBuffers; i++) 
		ressz += outBuffersDesc.pBuffers[i].cbBuffer;


	unsigned char *response = (unsigned char*)alloca(ressz), *p = response;
	for (i = 0; i < outBuffersDesc.cBuffers; i++) 
	{
		memcpy(p, outBuffersDesc.pBuffers[i].pvBuffer, outBuffersDesc.pBuffers[i].cbBuffer);
		p += outBuffersDesc.pBuffers[i].cbBuffer;
	}

	NETLIBBASE64 nlb64;
	nlb64.cbDecoded = ressz;
	nlb64.pbDecoded = response;
	nlb64.cchEncoded = Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
	nlb64.pszEncoded = (char*)alloca(nlb64.cchEncoded);
	if (!NetlibBase64Encode(0,(LPARAM)&nlb64)) return NULL;

	return mir_strdup(nlb64.pszEncoded);
} 
예제 #24
0
char* NtlmCreateResponseFromChallenge(HANDLE hSecurity, const char *szChallenge, const TCHAR* login, const TCHAR* psw, 
									  bool http, unsigned& complete)
{
	SECURITY_STATUS sc;
	SecBufferDesc outputBufferDescriptor,inputBufferDescriptor;
	SecBuffer outputSecurityToken,inputSecurityToken;
	TimeStamp tokenExpiration;
	ULONG contextAttributes;
	NETLIBBASE64 nlb64 = { 0 };

	NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;

	if (hSecurity == NULL || ntlmCnt == 0) return NULL;

 	if (_tcsicmp(hNtlm->szProvider, _T("Basic")))
	{
		bool isGSSAPI = _tcsicmp(hNtlm->szProvider, _T("GSSAPI")) == 0;
		TCHAR *szProvider = isGSSAPI ? _T("Kerberos") : hNtlm->szProvider;
		bool hasChallenge = szChallenge != NULL && szChallenge[0] != '\0';
		if (hasChallenge) 
		{
			nlb64.cchEncoded = lstrlenA(szChallenge);
			nlb64.pszEncoded = (char*)szChallenge;
			nlb64.cbDecoded = Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded);
			nlb64.pbDecoded = (PBYTE)alloca(nlb64.cbDecoded);
			if (!NetlibBase64Decode(0, (LPARAM)&nlb64)) return NULL;

			if (isGSSAPI && complete)
				return CompleteGssapi(hSecurity, nlb64.pbDecoded, nlb64.cbDecoded);

			inputBufferDescriptor.cBuffers = 1;
			inputBufferDescriptor.pBuffers = &inputSecurityToken;
			inputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
			inputSecurityToken.BufferType = SECBUFFER_TOKEN;
			inputSecurityToken.cbBuffer = nlb64.cbDecoded;
			inputSecurityToken.pvBuffer = nlb64.pbDecoded;

			// try to decode the domain name from the NTLM challenge
			if (login != NULL && login[0] != '\0' && !hNtlm->hasDomain) 
			{
				NtlmType2packet* pkt = ( NtlmType2packet* )nlb64.pbDecoded;
				if (!strncmp(pkt->sign, "NTLMSSP", 8) && pkt->type == 2) 
				{
#ifdef UNICODE
					wchar_t* domainName = (wchar_t*)&nlb64.pbDecoded[pkt->targetName.offset];
					int domainLen = pkt->targetName.len;

					// Negotiate ANSI? if yes, convert the ANSI name to unicode
					if ((pkt->flags & 1) == 0) 
					{
						int bufsz = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, NULL, 0);
						wchar_t* buf = (wchar_t*)alloca(bufsz * sizeof(wchar_t));
						domainLen = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, buf, bufsz) - 1;
						domainName = buf;
					}
					else
						domainLen /= sizeof(wchar_t);
#else
					char* domainName = (char*)&nlb64.pbDecoded[pkt->targetName.offset];
					int domainLen = pkt->targetName.len;

					// Negotiate Unicode? if yes, convert the unicode name to ANSI
					if (pkt->flags & 1) 
					{
						int bufsz = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)domainName, domainLen, NULL, 0, NULL, NULL);
						char* buf = (char*)alloca(bufsz);
						domainLen = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)domainName, domainLen, buf, bufsz, NULL, NULL) - 1;
						domainName = buf;
					}
#endif

					if (domainLen) 
					{
						size_t newLoginLen = _tcslen(login) + domainLen + 1;
						TCHAR *newLogin = (TCHAR*)alloca(newLoginLen * sizeof(TCHAR));

						_tcsncpy(newLogin, domainName, domainLen);
						newLogin[domainLen] = '\\';
						_tcscpy(newLogin + domainLen + 1, login);

						char* szChl = NtlmCreateResponseFromChallenge(hSecurity, NULL, newLogin, psw, http, complete);
						mir_free(szChl);
					}
				}
			}
		}
		else 
		{
			if (SecIsValidHandle(&hNtlm->hClientContext)) g_pSSPI->DeleteSecurityContext(&hNtlm->hClientContext);
			if (SecIsValidHandle(&hNtlm->hClientCredential)) g_pSSPI->FreeCredentialsHandle(&hNtlm->hClientCredential);

			SEC_WINNT_AUTH_IDENTITY auth;

			if (login != NULL && login[0] != '\0') 
			{
				memset(&auth, 0, sizeof(auth));
#ifdef _UNICODE
				NetlibLogf(NULL, "Security login requested, user: %S pssw: %s", login, psw ? "(exist)" : "(no psw)");
#else
				NetlibLogf(NULL, "Security login requested, user: %s pssw: %s", login, psw ? "(exist)" : "(no psw)");
#endif

				const TCHAR* loginName = login;
				const TCHAR* domainName = _tcschr(login, '\\');
				int domainLen = 0;
				int loginLen = lstrlen(loginName);
				if (domainName != NULL) 
				{
					loginName = domainName + 1;
					loginLen = lstrlen(loginName);
					domainLen = domainName - login;
					domainName = login;
				}
				else if ((domainName = _tcschr(login, '@')) != NULL) 
				{
					loginName = login;
					loginLen = domainName - login;
					domainLen = lstrlen(++domainName);
				}

#ifdef UNICODE
				auth.User = (PWORD)loginName;
				auth.UserLength = loginLen;
				auth.Password = (PWORD)psw;
				auth.PasswordLength = lstrlen(psw);
				auth.Domain = (PWORD)domainName;
				auth.DomainLength = domainLen;
				auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
				auth.User = (PBYTE)loginName;
				auth.UserLength = loginLen;
				auth.Password = (PBYTE)psw;
				auth.PasswordLength = lstrlen(psw);
				auth.Domain = (PBYTE)domainName;
				auth.DomainLength = domainLen;
				auth.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif

				hNtlm->hasDomain = domainLen != 0;
			}

			sc = g_pSSPI->AcquireCredentialsHandle(NULL, szProvider, 
				SECPKG_CRED_OUTBOUND, NULL, hNtlm->hasDomain ? &auth : NULL, NULL, NULL, 
				&hNtlm->hClientCredential, &tokenExpiration);
			if (sc != SEC_E_OK) 
			{
				ReportSecError(sc, __LINE__);
				return NULL;
			}
		}

		outputBufferDescriptor.cBuffers = 1;
		outputBufferDescriptor.pBuffers = &outputSecurityToken;
		outputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
		outputSecurityToken.BufferType = SECBUFFER_TOKEN;
		outputSecurityToken.cbBuffer = hNtlm->cbMaxToken;
		outputSecurityToken.pvBuffer = alloca(outputSecurityToken.cbBuffer);

		sc = g_pSSPI->InitializeSecurityContext(&hNtlm->hClientCredential,
			hasChallenge ? &hNtlm->hClientContext : NULL,
			hNtlm->szPrincipal, isGSSAPI ? ISC_REQ_MUTUAL_AUTH | ISC_REQ_STREAM : 0, 0, SECURITY_NATIVE_DREP,
			hasChallenge ? &inputBufferDescriptor : NULL, 0, &hNtlm->hClientContext,
			&outputBufferDescriptor, &contextAttributes, &tokenExpiration);

		complete = (sc != SEC_I_COMPLETE_AND_CONTINUE && sc != SEC_I_CONTINUE_NEEDED);

		if (sc == SEC_I_COMPLETE_NEEDED || sc == SEC_I_COMPLETE_AND_CONTINUE)
		{
			sc = g_pSSPI->CompleteAuthToken(&hNtlm->hClientContext, &outputBufferDescriptor);
		}

		if (sc != SEC_E_OK && sc != SEC_I_CONTINUE_NEEDED)
		{
			ReportSecError(sc, __LINE__);
			return NULL;
		}

		nlb64.cbDecoded = outputSecurityToken.cbBuffer;
		nlb64.pbDecoded = (PBYTE)outputSecurityToken.pvBuffer;
	}
	else
	{
		if (!login || !psw) return NULL;

		char *szLogin = mir_t2a(login);
		char *szPassw = mir_t2a(psw);

		size_t authLen = strlen(szLogin) + strlen(szPassw) + 5;
		char *szAuth = (char*)alloca(authLen);
		
		nlb64.cbDecoded = mir_snprintf(szAuth, authLen,"%s:%s", szLogin, szPassw);
		nlb64.pbDecoded=(PBYTE)szAuth;
		complete = true;

		mir_free(szPassw);
		mir_free(szLogin);
	}

	nlb64.cchEncoded = Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
	nlb64.pszEncoded = (char*)alloca(nlb64.cchEncoded);
	if (!NetlibBase64Encode(0,(LPARAM)&nlb64)) return NULL;

	char* result;
	if (http)
	{
		char* szProvider = mir_t2a(hNtlm->szProvider);
		nlb64.cchEncoded += (int)strlen(szProvider) + 10;
		result = (char*)mir_alloc(nlb64.cchEncoded);
		mir_snprintf(result, nlb64.cchEncoded, "%s %s", szProvider, nlb64.pszEncoded);
		mir_free(szProvider);
	}
	else
		result = mir_strdup(nlb64.pszEncoded);

	return result;
}
예제 #25
0
int NetlibSslWrite(SslHandle *ssl, const char *buf, int num)
{
	if (ssl == NULL) return SOCKET_ERROR;

	SecPkgContext_StreamSizes Sizes;
	SECURITY_STATUS scRet = g_pSSPI->QueryContextAttributes(&ssl->hContext, SECPKG_ATTR_STREAM_SIZES, &Sizes);
	if (scRet != SEC_E_OK)
		return scRet;

	PUCHAR pbDataBuffer = (PUCHAR)mir_calloc(Sizes.cbMaximumMessage + Sizes.cbHeader + Sizes.cbTrailer);

	PUCHAR pbMessage = pbDataBuffer + Sizes.cbHeader;

	DWORD sendOff = 0;
	while (sendOff < (DWORD)num) {
		DWORD cbMessage = min(Sizes.cbMaximumMessage, (DWORD)num - sendOff);
		memcpy(pbMessage, buf + sendOff, cbMessage);

		SecBuffer Buffers[4] = { 0 };
		Buffers[0].pvBuffer = pbDataBuffer;
		Buffers[0].cbBuffer = Sizes.cbHeader;
		Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;

		Buffers[1].pvBuffer = pbMessage;
		Buffers[1].cbBuffer = cbMessage;
		Buffers[1].BufferType = SECBUFFER_DATA;

		Buffers[2].pvBuffer = pbMessage + cbMessage;
		Buffers[2].cbBuffer = Sizes.cbTrailer;
		Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;

		Buffers[3].BufferType = SECBUFFER_EMPTY;

		SecBufferDesc Message;
		Message.ulVersion = SECBUFFER_VERSION;
		Message.cBuffers = _countof(Buffers);
		Message.pBuffers = Buffers;

		if (g_pSSPI->EncryptMessage != NULL)
			scRet = g_pSSPI->EncryptMessage(&ssl->hContext, 0, &Message, 0);
		else
			scRet = ((ENCRYPT_MESSAGE_FN)g_pSSPI->Reserved3)(&ssl->hContext, 0, &Message, 0);

		if (FAILED(scRet)) break;

		// Calculate encrypted packet size
		DWORD cbData = Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer;

		// Send the encrypted data to the server.
		cbData = send(ssl->s, (char*)pbDataBuffer, cbData, 0);
		if (cbData == SOCKET_ERROR || cbData == 0) {
			Netlib_Logf(NULL, "SSL failure sending data (%d)", WSAGetLastError());
			scRet = SEC_E_INTERNAL_ERROR;
			break;
		}

		sendOff += cbMessage;
	}

	mir_free(pbDataBuffer);
	return scRet == SEC_E_OK ? num : SOCKET_ERROR;
}
예제 #26
0
int NetlibSslRead(SslHandle *ssl, char *buf, int num, int peek)
{
	if (ssl == NULL) return SOCKET_ERROR;

	if (num <= 0) return 0;

	if (ssl->state != sockOpen || (ssl->cbRecDataBuf != 0 && (!peek || ssl->cbRecDataBuf >= num)))
		return NetlibSslReadSetResult(ssl, buf, num, peek);

	SECURITY_STATUS scRet = SEC_E_OK;

	while (true) {
		if (0 == ssl->cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE) {
			if (ssl->sbIoBuffer <= ssl->cbIoBuffer) {
				ssl->sbIoBuffer += 2048;
				ssl->pbIoBuffer = (PUCHAR)mir_realloc(ssl->pbIoBuffer, ssl->sbIoBuffer);
			}

			if (peek) {
				static const TIMEVAL tv = { 0 };
				fd_set fd;
				FD_ZERO(&fd);
				FD_SET(ssl->s, &fd);

				DWORD cbData = select(1, &fd, NULL, NULL, &tv);
				if (cbData == SOCKET_ERROR) {
					ssl->state = sockError;
					return NetlibSslReadSetResult(ssl, buf, num, peek);
				}

				if (cbData == 0 && ssl->cbRecDataBuf)
					return NetlibSslReadSetResult(ssl, buf, num, peek);
			}

			DWORD cbData = recv(ssl->s, (char*)ssl->pbIoBuffer + ssl->cbIoBuffer, ssl->sbIoBuffer - ssl->cbIoBuffer, 0);
			if (cbData == SOCKET_ERROR) {
				Netlib_Logf(NULL, "SSL failure recieving data (%d)", WSAGetLastError());
				ssl->state = sockError;
				return NetlibSslReadSetResult(ssl, buf, num, peek);
			}

			if (cbData == 0) {
				Netlib_Logf(NULL, "SSL connection gracefully closed");
				if (peek && ssl->cbRecDataBuf) {
					ssl->state = sockClosed;
					return NetlibSslReadSetResult(ssl, buf, num, peek);
				}

				// Server disconnected.
				if (ssl->cbIoBuffer) {
					ssl->state = sockError;
					return NetlibSslReadSetResult(ssl, buf, num, peek);
				}

				return 0;
			}
			ssl->cbIoBuffer += cbData;
		}

		// Attempt to decrypt the received data.
		SecBuffer Buffers[4];
		Buffers[0].pvBuffer = ssl->pbIoBuffer;
		Buffers[0].cbBuffer = ssl->cbIoBuffer;
		Buffers[0].BufferType = SECBUFFER_DATA;

		Buffers[1].BufferType = SECBUFFER_EMPTY;
		Buffers[2].BufferType = SECBUFFER_EMPTY;
		Buffers[3].BufferType = SECBUFFER_EMPTY;

		SecBufferDesc Message;
		Message.ulVersion = SECBUFFER_VERSION;
		Message.cBuffers = _countof(Buffers);
		Message.pBuffers = Buffers;

		if (g_pSSPI->DecryptMessage != NULL && g_pSSPI->DecryptMessage != PVOID(0x80000000))
			scRet = g_pSSPI->DecryptMessage(&ssl->hContext, &Message, 0, NULL);
		else
			scRet = ((DECRYPT_MESSAGE_FN)g_pSSPI->Reserved4)(&ssl->hContext, &Message, 0, NULL);

		// The input buffer contains only a fragment of an
		// encrypted record. Loop around and read some more
		// data.
		if (scRet == SEC_E_INCOMPLETE_MESSAGE)
			continue;

		if (scRet != SEC_E_OK && scRet != SEC_I_RENEGOTIATE && scRet != SEC_I_CONTEXT_EXPIRED) {
			ReportSslError(scRet, __LINE__);
			ssl->state = sockError;
			return NetlibSslReadSetResult(ssl, buf, num, peek);
		}

		// Locate data and (optional) extra buffers.
		SecBuffer *pDataBuffer = NULL;
		SecBuffer *pExtraBuffer = NULL;
		for (int i = 1; i < _countof(Buffers); i++) {
			if (pDataBuffer == NULL && Buffers[i].BufferType == SECBUFFER_DATA)
				pDataBuffer = &Buffers[i];

			if (pExtraBuffer == NULL && Buffers[i].BufferType == SECBUFFER_EXTRA)
				pExtraBuffer = &Buffers[i];
		}

		// Return decrypted data.
		DWORD resNum = 0;
		if (pDataBuffer) {
			DWORD bytes = peek ? 0 : min((DWORD)num, pDataBuffer->cbBuffer);
			DWORD rbytes = pDataBuffer->cbBuffer - bytes;
			if (rbytes > 0) {
				int nbytes = ssl->cbRecDataBuf + rbytes;
				if (ssl->sbRecDataBuf < nbytes) {
					ssl->sbRecDataBuf = nbytes;
					ssl->pbRecDataBuf = (PUCHAR)mir_realloc(ssl->pbRecDataBuf, nbytes);
				}
				memcpy(ssl->pbRecDataBuf + ssl->cbRecDataBuf, (char*)pDataBuffer->pvBuffer + bytes, rbytes);
				ssl->cbRecDataBuf = nbytes;
			}

			if (peek) {
				resNum = bytes = min(num, ssl->cbRecDataBuf);
				memcpy(buf, ssl->pbRecDataBuf, bytes);
			}
			else {
				resNum = bytes;
				memcpy(buf, pDataBuffer->pvBuffer, bytes);
			}
		}

		// Move any "extra" data to the input buffer.
		if (pExtraBuffer) {
			memmove(ssl->pbIoBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
			ssl->cbIoBuffer = pExtraBuffer->cbBuffer;
		}
		else ssl->cbIoBuffer = 0;

		if (pDataBuffer && resNum)
			return resNum;

		// Server signaled end of session
		if (scRet == SEC_I_CONTEXT_EXPIRED) {
			Netlib_Logf(NULL, "SSL Server signaled SSL Shutdown");
			ssl->state = sockClosed;
			return NetlibSslReadSetResult(ssl, buf, num, peek);
		}

		if (scRet == SEC_I_RENEGOTIATE) {
			// The server wants to perform another handshake
			// sequence.

			scRet = ClientHandshakeLoop(ssl, FALSE);
			if (scRet != SEC_E_OK) {
				ssl->state = sockError;
				return NetlibSslReadSetResult(ssl, buf, num, peek);
			}
		}
	}
}
예제 #27
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;
}