ssl.cpp

来自「Windows CE 6.0 Server 源码」· C++ 代码 · 共 1,131 行 · 第 1/3 页

CPP
1,131
字号
		if ((dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) || (dwErrorStatus & CERT_TRUST_CTL_IS_NOT_TIME_VALID))
			m_SSLInfo.m_dwCertFlags |= CRED_STATUS_INVALID_TIME;

		if ((dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) ||  (dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) ||
		    (dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) ||  (dwErrorStatus & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID)) {
			m_SSLInfo.m_dwCertFlags |= RCRED_STATUS_UNKNOWN_ISSUER;
		}

		if ((dwErrorStatus & CERT_TRUST_IS_REVOKED) || (dwErrorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
			m_SSLInfo.m_dwCertFlags |= CRED_STATUS_REVOKED;
	}
	m_SSLInfo.m_dwCertFlags |= RCRED_CRED_EXISTS;

	fRet = TRUE;
done:
	if (!fRet)
		m_rs = STATUS_FORBIDDEN;

	return fRet;
}

#define SSL_ACCEPT_SECURITY_CONTEXT_FLAGS  (ASC_REQ_SEQUENCE_DETECT |  \
	                                        ASC_REQ_REPLAY_DETECT   |  \
	                                        ASC_REQ_CONFIDENTIALITY |  \
	                                        ASC_REQ_EXTENDED_ERROR  |  \
	                                        ASC_REQ_ALLOCATE_MEMORY |  \
	                                        ASC_REQ_STREAM)

// HandleSSLHandShake is called when a request on a secure channel first comes in
// in order to initiante the SSL connection.  It is also called during a 
// renegotiation of an SSL session, which occurs most likely when web server
// requests it in order to retrieve the client certificate.
BOOL CHttpRequest::HandleSSLHandShake(BOOL fRenegotiate, BYTE *pInitialData, DWORD cbInitialData)  {
	if (m_SSLInfo.m_fSSLInitialized && !fRenegotiate)
		return TRUE;

	CBuffer tempBuf;
	CBuffer *pBuf = fRenegotiate ? &tempBuf : &m_bufRequest;

	DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: call HandleSSLHandShake(fRenegotiate=%d,pInitialData=0x%08x,cbInitialData=%d,m_socket=0x%08x)\r\n",
	                           fRenegotiate, pInitialData,cbInitialData,m_socket));
#if defined (DEBUG)
	// make sure we should we be in here.
	DEBUGCHK(m_fIsSecurePort && g_pVars->m_fSSL && !g_pVars->m_fSSLSkipProcessing); 
	// make sure buffers are clean.
	DEBUGCHK(!pBuf->m_pszBuf && !pBuf->m_iSize && !pBuf->m_iNextIn);
	// if we're not on renogitate, we shouldn't have any VRoot info yet.
	if (!fRenegotiate)
		DEBUGCHK(!GetPerms());
#endif

	SECURITY_STATUS scRet = SEC_I_CONTINUE_NEEDED;
	PCCERT_CONTEXT  pRemoteCertContext = NULL;

	SecBufferDesc   InBuffer;
	SecBufferDesc   OutBuffer;
	SecBuffer       InBuffers[2];
	SecBuffer       OutBuffers[1];
	DWORD           dwRead;

	BOOL   fInitContext = !fRenegotiate; // when renegotiating we have initialized context already.
	DWORD  dwAvailable;    
	DWORD  dwSSPIOutFlags;
	DWORD  dwSSPIFlags  = SSL_ACCEPT_SECURITY_CONTEXT_FLAGS;
	DWORD  dwTotalRecv  = 0;

	// if renegotiating, we start out with data in pInitialData and cbInitialData, so we don't call recv()
	BOOL   fCallRecv    = !fRenegotiate;
	BOOL   fHasClientCert;

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

	// If m_SSLInfo.m_pClientCertContext we set ASC_REQ_MUTUAL_AUTH to avoid renegotiating.  Occurs during a keep-alive.
	// If m_SSLInfo.m_pClientCertContext=NULL and our VRoot permissions require or request a cert, likely we're in renegotiate to get MUTUAL_AUTH.
	if (m_SSLInfo.m_pClientCertContext || (GetPerms() & (HSE_URL_FLAGS_NEGO_CERT | HSE_URL_FLAGS_REQUIRE_CERT)))
		dwSSPIFlags |= ASC_REQ_MUTUAL_AUTH;

	if (fRenegotiate && cbInitialData) {
		// on initial query we have data in m_bufRequest already.  On renegotiate
		// copy initial data into temporary buffer.
		if (! pBuf->AllocMem(cbInitialData))
			return FALSE;

		memcpy(pBuf->m_pszBuf,pInitialData,cbInitialData);
		pBuf->m_iNextIn = cbInitialData;
	}

	while (1) {
		if (fCallRecv && (0 == pBuf->m_iNextIn || scRet == SEC_E_INCOMPLETE_MESSAGE)) {
			DEBUGCHK(dwTotalRecv <= g_pVars->m_dwPostReadSize);
			if (dwTotalRecv == g_pVars->m_dwPostReadSize) {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: Failing SSL Handshake negotiation because > %d bytes have been sent in it\r\n",g_pVars->m_dwPostReadSize));
				return FALSE;
			}

			DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake calling select()\r\n"));
			if (! MySelect(m_socket,g_pVars->m_dwConnectionTimeout))
				return FALSE;

			// check how much input is waiting
			if(ioctlsocket(m_socket, FIONREAD, &dwAvailable))
				return FALSE;

			// We'll read a maximum of g_pVars->m_dwPostReadSize total to prevent DoS attacks of exhausting sys resources.
			if (dwTotalRecv + dwAvailable > g_pVars->m_dwPostReadSize)
				dwAvailable = g_pVars->m_dwPostReadSize - dwTotalRecv;

			if (!pBuf->AllocMem(dwAvailable))
				return FALSE;

			dwRead = recv(m_socket, pBuf->m_pszBuf+pBuf->m_iNextIn,dwAvailable,0);
			if (dwRead == SOCKET_ERROR || dwRead == 0) {
				DEBUGMSG(ZONE_SOCKET,(L"HTTPD: SSL call to recv failed, GLE=0x%08x\r\n",GetLastError()));
				return FALSE;
			}

			pBuf->m_iNextIn += dwRead;
			dwTotalRecv     += dwRead;
			DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake read %d bytes\r\n",dwRead));
		}

		//
		// InBuffers[1] is for getting extra data that
		//  SSPI/SCHANNEL doesn't proccess on this
		//  run around the loop.
		//
		InBuffers[0].pvBuffer   = pBuf->m_pszBuf;
		InBuffers[0].cbBuffer   = pBuf->m_iNextIn;
		InBuffers[0].BufferType = SECBUFFER_TOKEN;

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

		InBuffer.cBuffers       = 2;
		InBuffer.pBuffers       = InBuffers;
		InBuffer.ulVersion      = SECBUFFER_VERSION;

		fCallRecv = TRUE;
		//
		// Initialize these so if we fail, pvBuffer contains NULL,
		// so we don't try to free random garbage at the quit
		//
		OutBuffers[0].pvBuffer   = NULL;
		OutBuffers[0].BufferType = SECBUFFER_TOKEN;
		OutBuffers[0].cbBuffer   = 0;

		scRet = g_pVars->m_SecurityInterface.AcceptSecurityContext(
		                                   &g_pVars->m_hSSLCreds,
		                                   (fInitContext?NULL:&m_SSLInfo.m_hcred),
		                                   &InBuffer,
		                                   dwSSPIFlags,
		                                   SECURITY_NATIVE_DREP,
		                                   (fInitContext?&m_SSLInfo.m_hcred:NULL),
		                                   &OutBuffer,
		                                   &dwSSPIOutFlags,
		                                   NULL);

		DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake AcceptSecurityContext() returns 0x%08x\r\n",scRet));

		fInitContext = FALSE;
		fHasClientCert = dwSSPIOutFlags & ASC_RET_MUTUAL_AUTH;

		if ((GetPerms() & HSE_URL_FLAGS_REQUIRE_CERT) && !fHasClientCert) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: Client certificate required for current vroot, not sent by client browser.  Terminating HTTP request.\r\n"));
			m_rs = STATUS_FORBIDDEN;
			return FALSE;
		}

		if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED ||
		    (FAILED(scRet) && (0 != (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))))  {
			if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL) {
				DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake sending %d bytes to client\r\n",OutBuffers[0].cbBuffer));
				send( m_socket,(PCSTR)OutBuffers[0].pvBuffer,OutBuffers[0].cbBuffer,0);
			}
			m_SSLInfo.m_fHasCtxt = TRUE;
		}

		if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL) 
			g_pVars->m_SecurityInterface.FreeContextBuffer( OutBuffers[0].pvBuffer );

		if (InBuffers[1].BufferType == SECBUFFER_EXTRA)  {
			DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake returns SECBUFFER_EXTRA, %d extra bytes\r\n",InBuffers[1].cbBuffer));
			memcpy(pBuf->m_pszBuf,
			       (LPBYTE) (pBuf->m_pszBuf + (pBuf->m_iNextIn - InBuffers[1].cbBuffer)),
			       InBuffers[1].cbBuffer);
			pBuf->m_iNextIn= InBuffers[1].cbBuffer;
		}
		else if (scRet != SEC_E_INCOMPLETE_MESSAGE) {
			DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake scRet != SEC_E_INCOMPLETE_MESSAGE, resetting read buffer\r\n"));
			pBuf->Reset();
		}

		if (scRet == SEC_E_OK) {
			SecPkgContext_ConnectionInfo ConnectionInfo;
			
			g_pVars->m_SecurityInterface.QueryContextAttributes(&m_SSLInfo.m_hcred,
			                        SECPKG_ATTR_CONNECTION_INFO,
			                        (PVOID)&ConnectionInfo);

			m_SSLInfo.m_dwSessionKeySize = ConnectionInfo.dwCipherStrength;
			m_SSLInfo.m_dwSSLPrivKeySize = ConnectionInfo.dwHashStrength;

			scRet = g_pVars->m_SecurityInterface.QueryContextAttributes(&m_SSLInfo.m_hcred,
			                            SECPKG_ATTR_STREAM_SIZES,&m_SSLInfo.m_Sizes);

			m_SSLInfo.m_fSSLInitialized = TRUE;
			if (scRet != SEC_E_OK)
				return FALSE;

			DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake successfully authenticated.  SessionKeySize = %d, PrivKeySize = %d\r\n",
			                           m_SSLInfo.m_dwSessionKeySize,m_SSLInfo.m_dwSSLPrivKeySize));

			return fHasClientCert ? CheckClientCert() : TRUE;
		}
		else if (FAILED(scRet) && (scRet != SEC_E_INCOMPLETE_MESSAGE)) {
			DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: HandleSSLHandShake fails, scRet = 0x%08x\n",scRet));
			return FALSE;
		}
	}

	DEBUGCHK(FALSE);
	return FALSE;
}

// When we need a client certificate and don't have one, need to renegotiate the request.
CHttpRequest::SSLRenegotiateRequest(void) {
	BOOL            fRet = FALSE;
	SECURITY_STATUS scRet;
	SecBufferDesc   InBuffer; 
	SecBufferDesc   OutBuffer;
	SecBuffer       OutBuffers[1];

	SecBuffer      Buffers[4];
	DWORD          dwSSPIFlags    = SSL_ACCEPT_SECURITY_CONTEXT_FLAGS | ASC_REQ_MUTUAL_AUTH;
	DWORD          dwSSPIOutFlags = 0;

	InBuffer.ulVersion   = SECBUFFER_VERSION;
	InBuffer.cBuffers    = 4;
	InBuffer.pBuffers    = Buffers;

	Buffers[0].pvBuffer   = "";
	Buffers[0].cbBuffer   = 0;
	Buffers[0].BufferType = SECBUFFER_TOKEN;

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

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

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

	DEBUGMSG(ZONE_SSL | ZONE_REQUEST,(L"HTTPD: SSL requesting renegotiation\r\n"));

	DEBUGCHK(! m_fPerformedSSLRenegotiateRequest);

	scRet = g_pVars->m_SecurityInterface.AcceptSecurityContext(&g_pVars->m_hSSLCreds,
		                                   &m_SSLInfo.m_hcred,
		                                   &InBuffer,
		                                   dwSSPIFlags,
		                                   SECURITY_NATIVE_DREP,
		                                   &m_SSLInfo.m_hcred,
		                                   &OutBuffer,
		                                   &dwSSPIOutFlags,
		                                   NULL);
	if (FAILED(scRet)) {
		DEBUGMSG(ZONE_SSL,(L"HTTPD: Renegotiation of SSL channel to retrieve client cert failed on AcceptSecurityContext(),error=0x%08x\r\n",scRet));
		goto done;
	}

	if (! (dwSSPIOutFlags & ASC_RET_MUTUAL_AUTH)) {
		DEBUGMSG(ZONE_SSL,(L"HTTPD: Renegotiation of SSL channel to retrieve client cert failed, SSPI doesn't support ASC_REQ_MUTUAL_AUTH flag\r\n"));
		goto done;
	}

	if (SOCKET_ERROR != send(m_socket,(PSTR)OutBuffers[0].pvBuffer,OutBuffers[0].cbBuffer,0))
		fRet = TRUE;

done:
	if (OutBuffers[0].pvBuffer)
		g_pVars->m_SecurityInterface.FreeContextBuffer(OutBuffers[0].pvBuffer);

	m_fPerformedSSLRenegotiateRequest = TRUE;

	return fRet;
}

// SSLDecrypt Decrypts m_bufRequest buffer during RecvToBuf() call.
//
// Paramaters:
//
//   pszBuf -  pointer to the buffer to decrypt, which in this implementation 
//             will always be a pointer to the first unencrypted byte of m_bufRequest.m_pszBuf.
//             This data is modified in place.
//
//   dwLen  -  number of bytes from pszBuf to the end of the buffer that we've received off the wire.
//
//   pdwBytesDecryptedTotal - returns the number of bytes decrypted during the function.
// 
//   pdwExtraRequired  - If DecryptMessage returns SEC_E_INCOMPLETE_MESSAGE, it also specifies
//                       the number of bytes that need to be read for it to have a complete buffer to unencrypt with.
//
//   pdwIgnore         - Each block of data (there are most likely multiple blocks in a signle HTTP request) has
//                       a header and trailer that are security related only and aren't part of 
//                       the HTTP message as far as the protocol is concerned.  For instance, when HandleRequest()
//                       requests to read 48KB of POST data it wants 48KB of actual POST, any
//                       header and trailer data sizes will be factored out of calculation by RecvToBuf().
//
//  pfCompletedRenegotiate - Set TRUE if we successfully complete a SSL renegotiation, most
//                           likely with the intention of retrieving a client certificate.
//

SECURITY_STATUS CHttpRequest::SSLDecrypt(PSTR pszBuf, const DWORD dwLen, DWORD *pdwBytesDecryptedTotal, DWORD *pdwOffset, DWORD *pdwExtraRequired, DWORD *pdwIgnore, BOOL *pfCompletedRenegotiate) {
	SECURITY_STATUS scRet;
	SecBuffer      Buffers[4];
	SecBufferDesc  Message;

	DWORD cbBuffer    = dwLen;
	DWORD dwRemaining = dwLen;
	PVOID pvBuffer    = (PVOID) pszBuf;

	DWORD cbHeader     = 0;    // length of header
	DWORD cbTrailer    = 0;    // length of trailer
	VOID  *pbDecrypted = NULL; // pointer to decrypted blob (from current call into DecryptMessage)
	DWORD cbDecrypted  = 0;    // amount of bytes decrypted (from current call into DecryptMessage)


	VOID  *pbExtra  = NULL; // Any data that was not decrypted after last call into DecryptMessage
	DWORD cbExtra   = 0;    // length of this extra data.

	DEBUGCHK((*pdwBytesDecryptedTotal == 0) && (*pdwIgnore==0) && (*pfCompletedRenegotiate==FALSE));

	Message.ulVersion = SECBUFFER_VERSION;
	Message.cBuffers = 4;
	Message.pBuffers = Buffers;

	DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: SSLDecrypt(pszBuf=0x%08x,dwLen=%d)\r\n",pszBuf,dwLen));

	//
	// We use a while loop to do decryption because DecryptMessage will not 
	// necessarily decrypt a buffer all at once, but instead may need multiple calls
	// to complete this operation.  It will decrypt not a byte at a time, but instead
	// in chunks (say of a few KB) at a time, and must have an entire chunk to 
	// decrypt.
	//
	while (1) {
		Buffers[0].pvBuffer = (PVOID) pvBuffer;
		Buffers[0].cbBuffer = cbBuffer;
		Buffers[0].BufferType = SECBUFFER_DATA;

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

		// Have SSPI decrypt as much as it can of this buffer.
		scRet = g_pVars->m_SecurityInterface.DecryptMessage(&m_SSLInfo.m_hcred, &Message, 0, NULL);
		if (scRet != SEC_E_OK && scRet != SEC_E_INCOMPLETE_MESSAGE && scRet != SEC_I_RENEGOTIATE) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: failed on DecryptMessage, err code = 0x%08x\r\n",scRet));
			return scRet;
		}

		if ((scRet == SEC_E_OK) || (scRet == SEC_I_RENEGOTIATE)) {
			DEBUGCHK(Buffers[0].BufferType == SECBUFFER_STREAM_HEADER);
			DEBUGCHK(Buffers[1].BufferType == SECBUFFER_DATA);
			DEBUGCHK(Buffers[2].BufferType == SECBUFFER_STREAM_TRAILER);
			DEBUGCHK((Buffers[3].BufferType == SECBUFFER_EXTRA) || (Buffers[3].BufferType == SECBUFFER_EMPTY));

			// Determine header, trailer, decrypted, and extra lengths.
			cbHeader    = Buffers[0].cbBuffer;
			cbDecrypted = Buffers[1].cbBuffer;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?