⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssl.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: SSL.CPP
Abstract: SSL handling.
--*/

#include "httpd.h"


// This is an undocumented registry setting.  If the user wishes to have HTTPD
// bind to port 443 but wants to use an ISAPI read filter instead of our SSL,
// they should set COMM\HTTP\SSL\Enabled=SKIP_SSL_PROCESSING and HTTPD will
// call recv but will not process the requests.

// This is not for the faint of heart!  This has never received any test and is
// included as a last ditch effort for the desperate.
#define SKIP_SSL_PROCESSING           0x01191977


static HINSTANCE                      hCryptLib;
static HINSTANCE                      hSchannelLib;

PFN_CERTGETNAMESTRINGA                    pCertGetNameStringA;
static PFN_CERTGETNAMESTRINGW             pCertGetNameStringW;
static PFN_CERTFREECERTIFICATECONTEXT     pCertFreeCertificateContext;
static PFN_CERTFINDCERTIFICATEINSTORE     pCertFindCertificateInStore;
static PFN_CERTOPENSTORE                  pCertOpenStore;
static PFN_CERTCLOSESTORE                 pCertCloseStore;
static PFN_SSLCRACKCERTIFICATE            pSSLCrackCert;
static PFN_CERTGETCERTIFICATECHAIN        pCertGetCertificateChain;
static PFN_CERTCERTFREECERTIFICATECHAIN   pCertFreeCertificateChain;

// Modified from wincrypt.h
#define pCertOpenSystemStore(hProv,szSubsystemProtocol) \
    pCertOpenStore(                              \
        CERT_STORE_PROV_SYSTEM_W,               \
        0,                                      \
        (hProv),                                \
        CERT_STORE_NO_CRYPT_RELEASE_FLAG|CERT_SYSTEM_STORE_CURRENT_USER,    \
        (const void *) (szSubsystemProtocol)    \
        )

void ResetSecurityFcnPtrs(void) {
	pCertFreeCertificateContext = NULL;
	pCertGetNameStringA         = NULL;
	pCertGetNameStringW         = NULL;
	pCertFindCertificateInStore = NULL;
	pCertOpenStore              = NULL;
	pCertCloseStore             = NULL;
	pCertGetCertificateChain    = NULL;
	pCertFreeCertificateChain   = NULL;
}

// To allow for devices that don't have CAPI2 but still include HTTPAUTH component,
// load functions at runtime.
BOOL SSLGetFunctionPointers(void) {
	if (pCertCloseStore)
		return TRUE;

	hCryptLib = LoadLibrary(L"\\windows\\crypt32.dll");

	if (hCryptLib == 0) {
		DEBUGMSG(ZONE_INIT,(L"HTTPD: Unable to load crypt32.dll, GLE=0x%08x\r\n",GetLastError()));
		return FALSE;
	}

	pCertFreeCertificateContext = (PFN_CERTFREECERTIFICATECONTEXT)    GetProcAddress(hCryptLib,CE_STRING("CertFreeCertificateContext"));
	pCertGetNameStringA         = (PFN_CERTGETNAMESTRINGA)            GetProcAddress(hCryptLib,CE_STRING("CertGetNameStringA"));
	pCertGetNameStringW         = (PFN_CERTGETNAMESTRINGW)            GetProcAddress(hCryptLib,CE_STRING("CertGetNameStringW"));
	pCertFindCertificateInStore = (PFN_CERTFINDCERTIFICATEINSTORE)    GetProcAddress(hCryptLib,CE_STRING("CertFindCertificateInStore"));
	pCertOpenStore              = (PFN_CERTOPENSTORE)                 GetProcAddress(hCryptLib,CE_STRING("CertOpenStore"));
	pCertCloseStore             = (PFN_CERTCLOSESTORE)                GetProcAddress(hCryptLib,CE_STRING("CertCloseStore"));
	pCertGetCertificateChain    = (PFN_CERTGETCERTIFICATECHAIN)       GetProcAddress(hCryptLib,CE_STRING("CertGetCertificateChain"));
	pCertFreeCertificateChain   = (PFN_CERTCERTFREECERTIFICATECHAIN)  GetProcAddress(hCryptLib,CE_STRING("CertFreeCertificateChain"));
 
	if (!pCertFreeCertificateContext || !pCertGetNameStringA || !pCertFindCertificateInStore ||
	    !pCertOpenStore              || !pCertCloseStore     || !pCertGetNameStringW || !pCertFreeCertificateChain) {
		DEBUGMSG(ZONE_INIT,(L"HTTPD: GetProcAddress fails on Cert functions from crypt32.dll, GLE=0x%08x\r\n",GetLastError()));

		ResetSecurityFcnPtrs();
		return FALSE;
	}

	// Failing this is non-fatal
	hSchannelLib = LoadLibrary(L"\\windows\\schannel.dll");
	if (hSchannelLib) {
		pSSLCrackCert = (PFN_SSLCRACKCERTIFICATE) GetProcAddress(hSchannelLib,SSL_CRACK_CERTIFICATE_NAME);
	}

	return TRUE;
}

// Called when web server is starting up.
void CGlobalVariables::InitSSL(CReg *pWebsite) {
	DEBUG_CODE_INIT;
	DWORD               dwErr = 0;
	WCHAR               wszSubject[MAX_PATH+1];
	PCCERT_CONTEXT      pCertContext = NULL;
	SCHANNEL_CRED       SchannelCred;
	DWORD               dwLen;
	
	DEBUGCHK((m_fSSL == FALSE) && (m_hSSLCertStore == 0) && (m_fHasSSLCreds == 0));
	DEBUGCHK(m_fRootSite); // this should only be called for default site, non-default websites use this still.
	DWORD fEnableSSL;

	CReg reg((HKEY)*pWebsite,RK_SSL);

	m_dwSSLPort = reg.ValueDW(RV_SSL_PORT,IPPORT_SSL);

	if (! (fEnableSSL = reg.ValueDW(RV_SSL_ENABLE))) {
		DEBUGMSG(ZONE_SSL,(L"HTTPD: SSL not enabled via registry settings\r\n"));
		myleave(800);
	}

	if (fEnableSSL == SKIP_SSL_PROCESSING) {
		// HTTPD won't call it's SSL processing, presumably there's an ISAPI filter setup to handle this.
		m_fSSLSkipProcessing = TRUE;
		m_fSSL = TRUE;
		myleave(0);
	}

	if (!SSLGetFunctionPointers())
		myleave(0);

	if (! reg.ValueSZ(RV_SSL_CERT_SUBJECT,wszSubject,ARRAYSIZEOF(wszSubject)))  {
		DEBUGMSG(ZONE_ERROR | ZONE_INIT,(L"HTTPD: SSL has been turned on through registry but key %s wasn't set, required value\r\n",RV_SSL_CERT_SUBJECT));
		myleave(801);
	}

	if (0 == (m_hSSLCertStore = pCertOpenSystemStore(0, L"MY"))) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: CertOpenStore failed, no SSL will be performed.  GLE=0x%08x\r\n",GetLastError()));
		dwErr = GetLastError();
		myleave(802);
	}

	pCertContext = pCertFindCertificateInStore(m_hSSLCertStore, 
	                                          X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
	                                          0,
	                                          CERT_FIND_SUBJECT_STR_W,
	                                          wszSubject,
	                                          NULL);
	if (!pCertContext) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: CertFindCertificateInStore failed, no SSL will be performed.  GLE=0x%08x\r\n",GetLastError()));
		dwErr = GetLastError();
		myleave(803);
	}

	ZeroMemory(&SchannelCred, sizeof(SchannelCred));
	SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
	SchannelCred.cCreds = 1;
	SchannelCred.paCred = &pCertContext;

	dwErr = m_SecurityInterface.AcquireCredentialsHandle(
	                               	NULL,                 // Name of principal
	                               	UNISP_NAME,           // Name of package
	                               	SECPKG_CRED_INBOUND,  // Flags indicating use
	                               	NULL,                 // Pointer to logon ID
	                               	&SchannelCred,        // Package specific data
	                               	NULL,                 // Pointer to GetKey() func
	                               	NULL,                 // Value to pass to GetKey()
	                               	&m_hSSLCreds,         // (out) Cred Handle
	                               	NULL);                // (out) Lifetime (optional)

	if (dwErr != SEC_E_OK) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: AcquireCredentialsHandle failed, no SSL will be performed.  Error = 0x%08x\r\n",dwErr));
		myleave(804);
	}

	m_fHasSSLCreds = TRUE;

#if defined (UNDER_CE)
	dwLen = pCertGetNameStringA(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,CERT_NAME_ISSUER_FLAG,NULL,NULL,0);
	if (dwLen != 0 && dwLen != 1)  {
		if (NULL != (m_pszSSLIssuer = MyRgAllocNZ(CHAR,dwLen)))
			pCertGetNameStringA(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,CERT_NAME_ISSUER_FLAG,NULL,m_pszSSLIssuer,dwLen);
	}

	dwLen = pCertGetNameStringA(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,NULL,0);
	if (dwLen != 0 && dwLen != 1) {
		if (NULL != (m_pszSSLSubject = MyRgAllocNZ(CHAR,dwLen)))
			pCertGetNameStringA(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,m_pszSSLSubject,dwLen);
	}

	if (!m_pszSSLIssuer)
		DEBUGMSG(ZONE_SSL,(L"HTTPD: Unable to determine Certificate Issuer\r\n"));

	if (!m_pszSSLSubject)
		DEBUGMSG(ZONE_SSL,(L"HTTPD: Unable to determine Certificate Subject\r\n"));
#endif

	if (NULL == (m_SSLUserMemDescr = svsutil_AllocFixedMemDescr(sizeof(SSLUserMap),10)))
		myleave(809);

	m_SSLUsers.InitializeSSLUsers(&reg,m_SSLUserMemDescr);

	// options to ignore client cert errors.
	m_dwSSLCertTrustOverride  = reg.ValueDW(RV_SSL_CERT_TRUST_OVERRIDE,0);
	m_dwSSLCertTrustOverride  = (~m_dwSSLCertTrustOverride);
	m_fSSL = TRUE;

done:
	if (pCertContext)
		pCertFreeCertificateContext(pCertContext);

	if (!m_fSSL)
		FreeSSLResources();

	if (dwErr) {
		DEBUGCHK(!m_fSSL);
		m_pLog->WriteEvent(IDS_HTTPD_SSL_INIT_ERROR,dwErr);
	}
}

// Called when web server is shutting down.
void CGlobalVariables::FreeSSLResources(void) {
	DEBUGCHK(m_fRootSite);

	if (m_hSSLCertStore) {
		pCertCloseStore(m_hSSLCertStore,0);
		m_hSSLCertStore = 0;
	}

	if (m_fHasSSLCreds) {
		m_SecurityInterface.FreeCredentialHandle(&m_hSSLCreds);
		m_fHasSSLCreds = FALSE;
	}

	if (hCryptLib) {
		FreeLibrary(hCryptLib);
		hCryptLib = 0;
	}

	if (hSchannelLib) {
		FreeLibrary(hSchannelLib);
		hSchannelLib = 0;
	}

	m_SSLUsers.DeInitUsers();

	if (m_SSLUserMemDescr)
		svsutil_ReleaseFixedNonEmpty(m_SSLUserMemDescr);

	ResetSecurityFcnPtrs();
}

// Shuts down SSL handeling when an HTTP session is over.
void CHttpRequest::CloseSSLSession() {
	DEBUG_CODE_INIT;
	DWORD           dwType;

	SecBufferDesc   OutBuffer;
	SecBuffer       OutBuffers[1];
	DWORD           dwSSPIFlags;
	DWORD           dwSSPIOutFlags;

	if (m_SSLInfo.m_pCertChainContext)
		pCertFreeCertificateChain(m_SSLInfo.m_pCertChainContext);

	if (m_SSLInfo.m_pClientCertContext)
		pCertFreeCertificateContext(m_SSLInfo.m_pClientCertContext);

	if (m_SSLInfo.m_fHasCtxt) {
		dwType = SCHANNEL_SHUTDOWN;

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

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

		if (FAILED(g_pVars->m_SecurityInterface.ApplyControlToken(&m_SSLInfo.m_hcred, &OutBuffer))) {
			DEBUGMSG(ZONE_SSL,(L"HTTPD: ApplyControlToken failed on SCHANNEL_SHUTDOWN."));
			myleave(2000);
		}

		dwSSPIFlags =   ASC_REQ_SEQUENCE_DETECT  | ASC_REQ_REPLAY_DETECT   |
		                ASC_REQ_CONFIDENTIALITY  | ASC_REQ_EXTENDED_ERROR  |
		                ASC_REQ_ALLOCATE_MEMORY  | ASC_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;

		if (FAILED(g_pVars->m_SecurityInterface.AcceptSecurityContext(&g_pVars->m_hSSLCreds,&m_SSLInfo.m_hcred,NULL,
		                        dwSSPIFlags,SECURITY_NATIVE_DREP,NULL,&OutBuffer,&dwSSPIOutFlags,NULL))) {

			DEBUGMSG(ZONE_SSL,(L"HTTPD: AcceptSecurity context failed on shutting down SSL connection"));
			myleave (2001);
		}

		if (OutBuffers[0].pvBuffer && OutBuffers[0].cbBuffer) {
			send(m_socket, (PSTR) OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
			g_pVars->m_SecurityInterface.FreeContextBuffer(OutBuffers[0].pvBuffer);
		}
	}

done:
	if (m_SSLInfo.m_fHasCtxt)
		g_pVars->m_SecurityInterface.DeleteSecurityContext(&m_SSLInfo.m_hcred);
}


// from IIS
#define CRED_STATUS_INVALID_TIME    0x00001000
#define CRED_STATUS_REVOKED         0x00002000


BOOL CHttpRequest::CheckClientCert(void)  {
	BOOL                         fRet = FALSE;
	CERT_CHAIN_PARA ChainPara;
	LPSTR  rgpszClientUsage[] = {szOID_PKIX_KP_CLIENT_AUTH,};
	DWORD  dwClientUsageCount = (sizeof(rgpszClientUsage)/sizeof(rgpszClientUsage[0]));
	DWORD  dwErrorStatus;

	if (m_SSLInfo.m_pClientCertContext || m_SSLInfo.m_pCertChainContext) {
		// I don't believe this can happen because web server doesn't accept multiple renegotiates.
		// If it does we'll ignore new client certificate sent across and use existing one.
		DEBUGCHK(0);
		return TRUE;
	}
	DEBUGCHK(m_SSLInfo.m_dwCertFlags == 0);

	// Get Cert Chain information.
	SECURITY_STATUS scRet = g_pVars->m_SecurityInterface.QueryContextAttributes(&m_SSLInfo.m_hcred,
	                                                             SECPKG_ATTR_REMOTE_CERT_CONTEXT,
	                                                             &m_SSLInfo.m_pClientCertContext);

	if (scRet == S_OK && !m_SSLInfo.m_pClientCertContext && ! (GetPerms() & HSE_URL_FLAGS_REQUIRE_CERT)) {
		// If we're only doing HSE_URL_FLAGS_NEGO_CERT and we don't have a certificate
		// then there's no problems.  However if the certificate is garbage (i.e.
		// pCertGetCertificateChain check fails) then we'll fail request in this case.
		fRet = TRUE;
		goto done;
	}

	if (S_OK != scRet || !m_SSLInfo.m_pClientCertContext || !m_SSLInfo.m_pClientCertContext->hCertStore)
		goto done;

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

	ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
	ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
	ChainPara.RequestedUsage.Usage.cUsageIdentifier = dwClientUsageCount;
	ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgpszClientUsage;

	if (! pCertGetCertificateChain(NULL,m_SSLInfo.m_pClientCertContext,NULL,NULL,
	                                &ChainPara,0,NULL,&m_SSLInfo.m_pCertChainContext)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: CertGetCertificateChain fails, error=0x%08x\r\n",GetLastError()));
		goto done;
	}

	dwErrorStatus = m_SSLInfo.m_pCertChainContext->TrustStatus.dwErrorStatus;
	if (dwErrorStatus) {
		if (dwErrorStatus & g_pVars->m_dwSSLCertTrustOverride) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: SSL Client cert is invalid, failing request.  pCertChainContext->TrustStatus.dwErrorStatus=0x%08x.  Terminating connection.\r\n",dwErrorStatus));
			m_fKeepAlive = FALSE;
			goto done;
		}
		DEBUGMSG(ZONE_SSL,(L"HTTPD: Warning, pCertChainContext->TrustStatus.dwErrorStatus=0x%08x (indicates failure) but was overriden by registry CertTrustOverride setting\r\n",dwErrorStatus));

⌨️ 快捷键说明

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