📄 ssl.cpp
字号:
pbDecrypted = Buffers[1].pvBuffer;
cbTrailer = Buffers[2].cbBuffer;
#ifdef DEBUG
// There was previously a bug in SSPI where it miscomputed
// trailer length and an elaborate workaround was needed in the if block
// below. Bug has been fixed, leave DEBUGCHK as an extra check for future.
if ((Buffers[2].BufferType == SECBUFFER_STREAM_TRAILER) && (Buffers[3].BufferType == SECBUFFER_EXTRA)) {
DEBUGCHK(Buffers[2].cbBuffer < Buffers[3].cbBuffer);
}
#endif
if (Buffers[3].BufferType == SECBUFFER_EXTRA) {
// Extra is effectively left over bytes - i.e. if we pass in 1000
// bytes to decrypet and header=5 bytes, decrypt=100 bytes, and trailer=5 bytes,
// then we have 1000-5-100-5=890 bytes extra - i.e. SSPI didn't
// modify these bytes and we need to call a decrypt again on them.
// Just record this so that when we "clean up" the decrypted data in place,
// we know how much extra we have to carry with us into the next call.
cbExtra = Buffers[3].cbBuffer;
pbExtra = Buffers[3].pvBuffer;
DEBUGCHK((cbExtra != 0) && (pbExtra != NULL));
}
else {
cbExtra = 0;
pbExtra = NULL;
}
}
if (scRet == SEC_E_OK) {
// DecrypteMessage has decrypted some (not necessarily all) of the data
// we have passed it. Since all of this work is done in place, we have
// to strip out the crypto header and trailer gunk that isn't relevant to
// HTTP
if (cbHeader) {
// Get rid of header gunk by copying over non-header bytes.
memmove(pvBuffer,(PSTR)pvBuffer+cbHeader,dwRemaining-cbHeader);
}
// Update counters.
*pdwBytesDecryptedTotal += cbDecrypted;
*pdwIgnore += cbHeader+cbTrailer;
dwRemaining -= (cbDecrypted+cbHeader+cbTrailer);
DEBUGCHK(dwRemaining == cbExtra);
DEBUGCHK((int)dwRemaining >= 0);
DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: DecryptMessage SEC_E_OK, bytes decrypted=%d, dwRemaining=%d,cbExtra=%d\r\n",
cbDecrypted,dwRemaining,cbExtra));
if (cbExtra) {
// There is data that was not decrypted on this pass. In this case,
// "get rid of" the crypto trailer too (like header), and reset
// the base pointer for another decrypt operation.
PSTR pszEnd = (PSTR)pvBuffer+cbDecrypted;
if (cbTrailer)
memmove(pszEnd,pszEnd+cbTrailer,cbExtra);
pvBuffer = (PVOID) pszEnd;
*pdwOffset = cbBuffer = cbExtra;
continue;
}
}
else if (scRet == SEC_I_RENEGOTIATE) {
// SSL renogotiation. This is typically (but not always) hit when the
// Web Server has requested a client certificate from the web client.
DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: DecryptMessage SEC_I_RENEGOTIATE\r\n"));
if (m_fPerformedClientInitiatedRenegotiate) {
// We only allow client to request one renegotiate per session. We
// do this to prevent denial of service attacks where client kept sending
// a renegotiate every few seconds.
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Client has requested more than one SSL renegotiation, web server does not support this, failing request\r\n"));
return E_FAIL;
}
if (! HandleSSLHandShake(TRUE))
return E_FAIL;
m_fPerformedClientInitiatedRenegotiate = TRUE;
*pfCompletedRenegotiate = TRUE;
// Recalculate lengths.
*pdwIgnore += cbHeader+cbTrailer;
dwRemaining -= (cbHeader+cbTrailer);
if (cbExtra) {
// See comments in 'if (cbExtra)' block above...
PSTR pszEnd = (PSTR)pvBuffer+cbDecrypted;
if (cbTrailer)
memmove(pszEnd,pszEnd+cbTrailer,cbExtra);
pvBuffer = (PVOID) pszEnd;
*pdwOffset = cbBuffer = cbExtra;
continue;
}
scRet = SEC_E_OK;
}
else {
// To decrypt the current chunk, we need to read in Buffers[1].cbBuffer more data.
DEBUGCHK(scRet == SEC_E_INCOMPLETE_MESSAGE);
DEBUGCHK(Buffers[1].BufferType == SECBUFFER_MISSING);
*pdwExtraRequired = Buffers[1].cbBuffer;
DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: DecryptMessage SEC_E_INCOMPLETE_MESSAGE, *pdwExtraRequired=%d\r\n",*pdwExtraRequired));
}
*pdwOffset = dwLen - *pdwBytesDecryptedTotal - *pdwIgnore;
break;
}
return scRet;
}
BOOL CHttpRequest::SendEncryptedData(PSTR pszBuf, DWORD dwLen, BOOL fCopyBuffer) {
DEBUG_CODE_INIT;
BOOL fRet = FALSE;
SecBuffer Buffers[4];
SecBufferDesc Message;
CHAR szHeader[64];
CHAR szTrailer[64];
SECURITY_STATUS scRet;
DWORD dwRemaining;
DWORD dwOffset = 0;
CHAR szStaticBuf[2048];
PSTR pszSendBuf = pszBuf;
DEBUGCHK(sizeof(szHeader) >= m_SSLInfo.m_Sizes.cbHeader);
DEBUGCHK(sizeof(szTrailer) >= m_SSLInfo.m_Sizes.cbTrailer);
DEBUGCHK(m_fIsSecurePort && g_pVars->m_fSSL);
Message.ulVersion = SECBUFFER_VERSION;
Message.cBuffers = 4;
Message.pBuffers = Buffers;
Buffers[0].pvBuffer = szHeader;
Buffers[0].cbBuffer = m_SSLInfo.m_Sizes.cbHeader;
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
Buffers[2].pvBuffer = szTrailer;
Buffers[2].cbBuffer = m_SSLInfo.m_Sizes.cbTrailer;
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
Buffers[3].BufferType = SECBUFFER_EMPTY;
dwRemaining = dwLen;
if (fCopyBuffer) {
if (dwLen <= sizeof(szStaticBuf)) {
pszSendBuf = szStaticBuf;
}
else {
if (! (pszSendBuf = MyRgAllocNZ(CHAR,dwLen)))
myleave(1908);
}
memcpy(pszSendBuf,pszBuf,dwLen);
}
while (dwRemaining) {
DWORD dwSend = min(dwRemaining,m_SSLInfo.m_Sizes.cbMaximumMessage);
Buffers[1].pvBuffer = pszSendBuf+dwOffset;
Buffers[1].cbBuffer = dwSend;
Buffers[1].BufferType = SECBUFFER_DATA;
// Note: Assuming nagling is turned on the header+trailer should NOT be sent
// across in separate packets but along with body.
scRet = g_pVars->m_SecurityInterface.EncryptMessage(&m_SSLInfo.m_hcred,0,&Message,0);
if (scRet != SEC_E_OK && scRet != SEC_E_INCOMPLETE_MESSAGE)
myleave(1909);
if (SOCKET_ERROR == send(m_socket,(PSTR)Buffers[0].pvBuffer,Buffers[0].cbBuffer,0))
myleave(1910);
if (SOCKET_ERROR == send(m_socket,(PSTR)Buffers[1].pvBuffer,Buffers[1].cbBuffer,0))
myleave(1911);
if (SOCKET_ERROR == send(m_socket,(PSTR)Buffers[2].pvBuffer,Buffers[2].cbBuffer,0))
myleave(1912);
dwOffset += dwSend;
dwRemaining -= dwSend;
}
fRet = TRUE;
done:
DEBUGMSG_ERR(ZONE_RESPONSE | ZONE_SSL,(L"HTTPD: SendEncryptedData failed, err = %d, GLE=0x%08x\r\n",err,GetLastError()));
if (pszSendBuf != szStaticBuf && pszSendBuf != pszBuf) {
DEBUGCHK(fCopyBuffer);
MyFree(pszSendBuf);
}
return fRet;
}
//
// CSSLUsers implementation functions
//
VOID
ReverseMemCopy(PUCHAR Dest, PUCHAR Source, ULONG Size) {
PUCHAR p;
p = Dest + Size - 1;
do {
*p-- = *Source++;
} while (p >= Dest);
}
// Called on web server initialization, reads SSL users into table from registry.
void CSSLUsers::InitializeSSLUsers(CReg *pSSLReg, FixedMemDescr *pUserMem) {
#if defined (DEBUG) || defined (_DEBUG)
BYTE b[sizeof(CSSLUsers)] = {0};
DEBUGCHK(0 == memcmp(b,this,sizeof(CSSLUsers)));
#endif
CReg rootReg((HKEY) (*pSSLReg),RK_USERS);
if (! rootReg.IsOK())
return;
DWORD cUsers = rootReg.NumSubkeys();
if (0 == cUsers)
return;
for (DWORD i = 0; i < cUsers; i++) {
CReg userReg;
WCHAR szUserName[MAX_PATH];
DWORD cbUserName; // size in bytes, not WCHARs
if (! rootReg.EnumKey(szUserName,SVSUTIL_ARRLEN(szUserName)))
continue;
if (! userReg.Open(rootReg,szUserName)) {
DEBUGCHK(0); // EnumKey shouldn't have suceeded if Opening can fail.
continue;
}
DWORD cMappings = userReg.NumSubkeys();
if (0 == cMappings)
continue;
cbUserName = (wcslen(szUserName)+1)*sizeof(WCHAR);
for (DWORD j = 0; j < cMappings; j++) {
CReg mapReg;
WCHAR szUserMap[MAX_PATH];
// open mapping registry key and read in its parameters
if (! userReg.EnumKey(szUserMap,SVSUTIL_ARRLEN(szUserMap)))
continue;
if (! mapReg.Open(userReg,szUserMap)) {
DEBUGCHK(0);
continue;
}
WCHAR szIssuerCN[MAX_ISSUER_LEN];
BYTE bSerialNumber[MAX_SERIAL_NUMBER];
DWORD cbIssuerCN = sizeof(szIssuerCN);
DWORD cbSerialNumber = sizeof(bSerialNumber);;
if (! mapReg.IsOK()) {
DEBUGCHK(0);
continue;
}
if (ERROR_SUCCESS != RegQueryValueEx(mapReg, RV_SSL_ISSUER_CN, NULL, NULL, (LPBYTE)szIssuerCN, &cbIssuerCN))
cbIssuerCN = 0;
if (ERROR_SUCCESS != RegQueryValueEx(mapReg, RV_SSL_SERIAL_NUMBER, NULL, NULL, (LPBYTE)bSerialNumber, &cbSerialNumber))
cbSerialNumber = 0;
if ((cbIssuerCN == 0) && (cbSerialNumber == 0)) {
DEBUGMSG(ZONE_SSL,(L"HTTPD: Initialize SSL skipping user %s's path %s, either issuer or serial number must be set\r\n",szUserName,szUserMap));
continue;
}
SSLUserMap *pNew = (SSLUserMap *)svsutil_GetFixed(pUserMem);
if (! pNew)
return;
pNew->pNext = pUserMapHead;
pUserMapHead = pNew;
memset(pNew,0,sizeof(SSLUserMap));
DWORD cbAlloc = cbUserName+cbIssuerCN+cbSerialNumber;
if (NULL == (pNew->pBuffer = MyRgAllocNZ(BYTE,cbAlloc)))
return;
// write this mapping information to the buffer
BYTE *pWrite = pNew->pBuffer;
memcpy(pWrite,szUserName,cbUserName);
pNew->szUserName = (WCHAR*)pWrite;
pWrite += cbUserName;
if (cbIssuerCN) {
memcpy(pWrite,szIssuerCN,cbIssuerCN);
pNew->szIssuerCN = (WCHAR*)pWrite;
pWrite += cbIssuerCN;
}
pNew->cbSerialNumber = cbSerialNumber;
if (cbSerialNumber) {
// Serial number is in reverse byte order in cert. Reverse it
// now so we can do memcmp's per request.
ReverseMemCopy(pWrite,bSerialNumber,cbSerialNumber);
pNew->pSerialNumber = pWrite;
pWrite += cbSerialNumber;
}
DEBUGCHK(pWrite == (pNew->pBuffer + cbAlloc));
}
}
}
// Called once an SSL client certificate has been received, uses the cert's serial number
// and/or issuer to see if it maps to a web server "pseudo-user".
WCHAR * CSSLUsers::MapUser(BYTE *pSerialNumber, DWORD cbSerialNumber, WCHAR *szIssuerCN) {
SSLUserMap *pTrav = pUserMapHead;
while (pTrav) {
// For the SSLUserMap, the serial number and/or issuer is present. If
// both members are set the certificate needs to match both of them, otherwise
// we're fine if we only match the one present field.
DEBUGCHK(pTrav->szUserName && ((pTrav->cbSerialNumber && pTrav->pSerialNumber) || pTrav->szIssuerCN));
if (pTrav->cbSerialNumber && ((pTrav->cbSerialNumber != cbSerialNumber) ||
(0 != memcmp(pTrav->pSerialNumber,pSerialNumber,cbSerialNumber))))
{
// User mapping had a serial number but it didn't match passed in certificate.
pTrav = pTrav->pNext;
continue;
}
if (pTrav->szIssuerCN && (0 != wcscmp(szIssuerCN,pTrav->szIssuerCN))) {
// User mapping had IssuerCN but it didn't match passed in certificate.
pTrav = pTrav->pNext;
continue;
}
return pTrav->szUserName;
}
return NULL;
}
// Called once an SSL client certificate has been received, tries to map
// certificate to user.
BOOL CHttpRequest::HandleSSLClientCertCheck(void) {
WCHAR szIssuer[2000];
WCHAR *szUser;
// the virtual root must request a mapping explicitly.
if (! (GetPerms() & HSE_URL_FLAGS_MAP_CERT))
return FALSE;
// don't have SSL info.
if (!m_fHandleSSL || !m_SSLInfo.m_pClientCertContext ||
!m_SSLInfo.m_pClientCertContext->pCertInfo ||
!m_SSLInfo.m_pClientCertContext->pCertInfo->SerialNumber.pbData)
return FALSE;
int cbSerialNum = m_SSLInfo.m_pClientCertContext->pCertInfo->SerialNumber.cbData;
BYTE *pSerialNumber = m_SSLInfo.m_pClientCertContext->pCertInfo->SerialNumber.pbData;
if (m_wszRemoteUser == NULL) {
if (! pCertGetNameStringW(m_SSLInfo.m_pClientCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,CERT_NAME_ISSUER_FLAG,0,szIssuer,sizeof(szIssuer)))
return FALSE;
if (NULL == (szUser = g_pVars->m_SSLUsers.MapUser(pSerialNumber,cbSerialNum,szIssuer)))
return FALSE;
m_wszRemoteUser = MySzDupW(szUser);
}
m_AuthLevelGranted = DeterminePermissionGranted(GetUserList(),m_AuthLevelGranted);
DEBUGMSG(ZONE_SSL_VERBOSE,(L"HTTPD: SSL Client cert mapping retrieves user=<<%s>>, auth granted = %d\r\n",szUser,m_AuthLevelGranted));
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -