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 + -
显示快捷键?