|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: context.c
//
// Contents: Schannel context management routines.
//
// Classes:
//
// Functions:
//
// History: 09-23-97 jbanes LSA integration stuff.
//
//----------------------------------------------------------------------------
#include <spbase.h>
#include <certmap.h>
#include <mapper.h>
#include <dsysdbg.h>
DWORD g_cContext = 0;
#if DBG
void DumpContexts(void); static void AddContextToList(PSPContext pContext); static void DeleteContextFromList(PSPContext pContext); #endif
/************************************************************************
* SPContextCreate * * Create a new SPContext, and initialize it. * * Returns - PSPContext pointer to context object. * \***********************************************************************/
PSPContext SPContextCreate(LPWSTR pszTarget) {
PSPContext pContext;
SP_BEGIN("SPContextCreate");
pContext = (PSPContext)SPExternalAlloc( sizeof(SPContext)); if(!pContext) { SP_RETURN(NULL); }
DebugLog((DEB_TRACE, "Create context:0x%p\n", pContext));
FillMemory(pContext, sizeof(SPContext), 0);
pContext->Magic = SP_CONTEXT_MAGIC; pContext->Flags = 0;
GenerateRandomThumbprint(&pContext->ContextThumbprint);
if(pszTarget) { pContext->pszTarget = SPExternalAlloc((lstrlenW(pszTarget) + 1) * sizeof(WCHAR)); if(pContext->pszTarget == NULL) { SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); SPExternalFree(pContext); SP_RETURN(NULL); } lstrcpyW(pContext->pszTarget, pszTarget); }
pContext->dwRequestedCF = CF_EXPORT;
if(SslGlobalStrongEncryptionPermitted) { pContext->dwRequestedCF |= CF_DOMESTIC; }
pContext->fCertChainsAllowed = FALSE;
g_cContext++;
#if DBG
//AddContextToList(pContext);
#endif
SP_RETURN(pContext); }
/************************************************************************
* VOID SPContextClean(PSPContext pContext) * * Clean out everything used by the handshake (in case we want * to do another). * \***********************************************************************/
BOOL SPContextClean(PSPContext pContext) { SP_BEGIN("SPContextClean");
if(pContext == NULL || pContext->Magic != SP_CONTEXT_MAGIC) { DebugLog((DEB_WARN, "Attempt to delete invalid context\n")); SP_RETURN(FALSE); }
if(pContext->pbEncryptedKey) { SPExternalFree(pContext->pbEncryptedKey); pContext->pbEncryptedKey = NULL; }
if(pContext->pbServerKeyExchange) { SPExternalFree(pContext->pbServerKeyExchange); pContext->pbServerKeyExchange = NULL; }
if(pContext->pbIssuerList) { SPExternalFree(pContext->pbIssuerList); pContext->pbIssuerList = NULL; }
if(pContext->pClientHello) { SPExternalFree(pContext->pClientHello); pContext->pClientHello = NULL; }
if((pContext->Flags & CONTEXT_FLAG_FULL_HANDSHAKE) && (pContext->RipeZombie != NULL) && (pContext->RipeZombie->pClientCred != NULL)) { // We've just done a client-side full handshake in which a default
// client certificate was selected. This client credential
// technically belongs to the cache (so that other contexts can
// query the certificate etc) but we want to free up the
// application-process hProv now, while we're in the context
// of the owning process.
PSPCredential pClientCred = pContext->RipeZombie->pClientCred;
if(pClientCred->hRemoteProv) { if(!RemoteCryptReleaseContext( pClientCred->hRemoteProv, 0, pClientCred->dwCapiFlags)) { SP_LOG_RESULT(GetLastError()); } pClientCred->hRemoteProv = 0; } }
pContext->fExchKey = FALSE;
SP_RETURN(TRUE); }
/************************************************************************
* VOID SPDeleteContext(PSPContext pContext) * * Delete an existing context object. * \***********************************************************************/
BOOL SPContextDelete(PSPContext pContext) { SP_BEGIN("SPContextDelete");
DebugLog((DEB_TRACE, "Delete context:0x%p\n", pContext));
if(pContext == NULL || pContext->Magic != SP_CONTEXT_MAGIC) { DebugLog((DEB_WARN, "Attempt to delete invalid context\n")); SP_RETURN(FALSE); }
// DsysAssert((pContext->pCredGroup->dwFlags & CRED_FLAG_DELETED) == 0);
if(pContext->State != SP_STATE_CONNECTED && pContext->State != SP_STATE_SHUTDOWN) { DebugLog((DEB_WARN, "Attempting to delete an incompleted context\n"));
// The context is being deleted in the middle of a handshake,
// which is curious. This may be caused by the user aborting
// an operation, or it may be caused by a reconfiguration of
// the remote computer that caused the reconnect attempt to
// fail. If it's the latter cause, then the only way to recover
// is to request a full handshake next time. We have no way
// of knowing which it is, so it's probably best that we kill
// the current cache entry.
if(pContext->RipeZombie) { pContext->RipeZombie->ZombieJuju = FALSE; } }
SPContextClean(pContext);
if(pContext->pszTarget) { SPExternalFree(pContext->pszTarget); pContext->pszTarget = NULL; }
if(pContext->pszCredentialName) { SPExternalFree(pContext->pszCredentialName); pContext->pszCredentialName = NULL; }
//
// Delete session keys.
//
if(pContext->hReadKey) { if(pContext->pReadCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hReadKey, 0); pContext->hReadKey = 0; } } if(pContext->hPendingReadKey) { if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hPendingReadKey, 0); pContext->hPendingReadKey = 0; } } if(pContext->hWriteKey) { if(pContext->pWriteCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hWriteKey, 0); pContext->hWriteKey = 0; } } if(pContext->hPendingWriteKey) { if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hPendingWriteKey, 0); pContext->hPendingWriteKey = 0; } }
if(pContext->hReadMAC) { if(pContext->pReadCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hReadMAC, 0); pContext->hReadMAC = 0; } } if(pContext->hPendingReadMAC) { if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hPendingReadMAC, 0); pContext->hPendingReadMAC = 0; } } if(pContext->hWriteMAC) { if(pContext->pWriteCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hWriteMAC, 0); pContext->hWriteMAC = 0; } } if(pContext->hPendingWriteMAC) { if(pContext->pPendingCipherInfo->aiCipher != CALG_SKIPJACK) { SchCryptDestroyKey(pContext->hPendingWriteMAC, 0); pContext->hPendingWriteMAC = 0; } }
//
// Delete the handshake hashes
//
if(pContext->hMd5Handshake) { SchCryptDestroyHash(pContext->hMd5Handshake, pContext->RipeZombie->dwCapiFlags); pContext->hMd5Handshake = 0; } if(pContext->hShaHandshake) { SchCryptDestroyHash(pContext->hShaHandshake, pContext->RipeZombie->dwCapiFlags); pContext->hShaHandshake = 0; }
SPDereferenceCredential(pContext->pCredGroup);
SPCacheDereference(pContext->RipeZombie);
#if DBG
//DeleteContextFromList(pContext);
#endif
FillMemory( pContext, sizeof( SPContext ), 0 ); g_cContext--;
SPExternalFree( pContext ); SP_RETURN(TRUE); }
/************************************************************************
* SPContext SPContextSetCredentials * * Associate a set of credentials with a context. * * Returns - PSPContext pointer to context object. * \***********************************************************************/ SP_STATUS SPContextSetCredentials( PSPContext pContext, PSPCredentialGroup pCred) { DWORD cbThumbprint; BOOL fNewCredentials = FALSE;
SP_BEGIN("SPContextSetCredentials");
if(pContext->Magic != SP_CONTEXT_MAGIC) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); }
// DsysAssert((pCred->dwFlags & CRED_FLAG_DELETED) == 0);
//
// Associate the credential group with the context.
//
if(pCred != pContext->pCredGroup) { if(pContext->pCredGroup) { SPDereferenceCredential(pContext->pCredGroup); }
SPReferenceCredential(pCred);
pContext->pCredGroup = pCred;
fNewCredentials = TRUE; }
//
// Set the protocol.
//
if(pContext->State == SP_STATE_NONE) { switch(pCred->grbitProtocol) { case SP_PROT_UNI_CLIENT: case SP_PROT_UNI_SERVER: case SP_PROT_PCT1_CLIENT: case SP_PROT_PCT1_SERVER: case SP_PROT_SSL2_CLIENT: case SP_PROT_SSL2_SERVER: case SP_PROT_SSL3_CLIENT: case SP_PROT_SSL3_SERVER: case SP_PROT_TLS1_CLIENT: case SP_PROT_TLS1_SERVER: pContext->ProtocolHandler = ServerProtocolHandler; pContext->InitiateHello = GenerateHello; break;
default: SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH)); } }
//
// If the client application has supplied a new credential, then
// attempt to choose a suitable client certificate to send to
// the server.
//
if(fNewCredentials && pContext->State == SSL3_STATE_GEN_SERVER_HELLORESP) { Ssl3CheckForExistingCred(pContext); }
//
// Allow the "manual cred validation" flag to be set from either
// AcquireCredentialsHandle or InitializeSecurityContext.
//
if(pCred->dwFlags & CRED_FLAG_MANUAL_CRED_VALIDATION) { if((pContext->Flags & CONTEXT_FLAG_MUTUAL_AUTH) == 0) { pContext->Flags |= CONTEXT_FLAG_MANUAL_CRED_VALIDATION; } }
SP_RETURN(PCT_ERR_OK); }
SP_STATUS ContextInitCiphersFromCache(SPContext *pContext) { PSessCacheItem pZombie; SP_STATUS pctRet;
pZombie = pContext->RipeZombie;
pContext->pPendingCipherInfo = GetCipherInfo(pZombie->aiCipher, pZombie->dwStrength); pContext->pPendingHashInfo = GetHashInfo(pZombie->aiHash); pContext->pKeyExchInfo = GetKeyExchangeInfo(pZombie->SessExchSpec);
pContext->dwPendingCipherSuiteIndex = pZombie->dwCipherSuiteIndex;
if(!IsCipherAllowed(pContext, pContext->pPendingCipherInfo, pZombie->fProtocol, pZombie->dwCF)) { pContext->pPendingCipherInfo = NULL; return (SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH)); }
// Load the pending hash structure
pContext->pPendingHashInfo = GetHashInfo(pZombie->aiHash);
if(!IsHashAllowed(pContext, pContext->pPendingHashInfo, pZombie->fProtocol)) { pContext->pPendingHashInfo = NULL; return (SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH)); }
// load the exch info structure
pContext->pKeyExchInfo = GetKeyExchangeInfo(pZombie->SessExchSpec); if(!IsExchAllowed(pContext, pContext->pKeyExchInfo, pZombie->fProtocol)) { pContext->pKeyExchInfo = NULL; return (SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH)); }
// Determine the CSP to use, based on the key exchange algorithm.
pctRet = DetermineClientCSP(pContext); if(pctRet != PCT_ERR_OK) { return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); }
#if DBG
switch(pZombie->fProtocol) { case SP_PROT_PCT1_CLIENT: DebugLog((DEB_TRACE, "Protocol:PCT Client\n")); break;
case SP_PROT_PCT1_SERVER: DebugLog((DEB_TRACE, "Protocol:PCT Server\n")); break;
case SP_PROT_SSL2_CLIENT: DebugLog((DEB_TRACE, "Protocol:SSL2 Client\n")); break;
case SP_PROT_SSL2_SERVER: DebugLog((DEB_TRACE, "Protocol:SSL2 Server\n")); break;
case SP_PROT_SSL3_CLIENT: DebugLog((DEB_TRACE, "Protocol:SSL3 Client\n")); break;
case SP_PROT_SSL3_SERVER: DebugLog((DEB_TRACE, "Protocol:SSL3 Server\n")); break;
case SP_PROT_TLS1_CLIENT: DebugLog((DEB_TRACE, "Protocol:TLS Client\n")); break;
case SP_PROT_TLS1_SERVER: DebugLog((DEB_TRACE, "Protocol:TLS Server\n")); break;
default: DebugLog((DEB_TRACE, "Protocol:0x%x\n", pZombie->fProtocol)); }
DebugLog((DEB_TRACE, "Cipher: %s\n", pContext->pPendingCipherInfo->szName)); DebugLog((DEB_TRACE, "Strength:%d\n", pContext->pPendingCipherInfo->dwStrength)); DebugLog((DEB_TRACE, "Hash: %s\n", pContext->pPendingHashInfo->szName)); DebugLog((DEB_TRACE, "Exchange:%s\n", pContext->pKeyExchInfo->szName)); #endif
return PCT_ERR_OK; }
SP_STATUS DetermineClientCSP(PSPContext pContext) { PSPCredential pCred = NULL;
if(!(pContext->RipeZombie->fProtocol & SP_PROT_CLIENTS)) { return PCT_ERR_OK; }
if(pContext->RipeZombie->hMasterProv != 0) { return PCT_ERR_OK; }
switch(pContext->pKeyExchInfo->Spec) { case SP_EXCH_RSA_PKCS1: pContext->RipeZombie->hMasterProv = g_hRsaSchannel; break;
case SP_EXCH_DH_PKCS3: pContext->RipeZombie->hMasterProv = g_hDhSchannelProv; break;
default: DebugLog((DEB_ERROR, "Appropriate Schannel CSP not available!\n")); pContext->RipeZombie->hMasterProv = 0; return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); }
return PCT_ERR_OK; }
SP_STATUS ContextInitCiphers( SPContext *pContext, BOOL fRead, BOOL fWrite) { SP_BEGIN("ContextInitCiphers");
if((pContext == NULL) || (pContext->RipeZombie == NULL)) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); }
pContext->pCipherInfo = pContext->pPendingCipherInfo; if ((NULL == pContext->pCipherInfo) || ((pContext->RipeZombie->fProtocol & pContext->pCipherInfo->fProtocol) == 0)) { SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH)); }
pContext->pHashInfo = pContext->pPendingHashInfo; if ((NULL == pContext->pHashInfo)|| ((pContext->RipeZombie->fProtocol & pContext->pHashInfo->fProtocol) == 0)) { SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH)); }
if (NULL == pContext->pKeyExchInfo) { SP_RETURN(SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH)); }
if(fRead) { pContext->pReadCipherInfo = pContext->pPendingCipherInfo; pContext->pReadHashInfo = pContext->pPendingHashInfo; } if(fWrite) { pContext->pWriteCipherInfo = pContext->pPendingCipherInfo; pContext->pWriteHashInfo = pContext->pPendingHashInfo; }
SP_RETURN(PCT_ERR_OK); }
SP_STATUS SPContextDoMapping( PSPContext pContext) { PSessCacheItem pZombie; PSPCredentialGroup pCred; SP_STATUS pctRet; LONG iState; BOOL fSuccess; LONG iMapper;
const SCH_MAPPER_DEFAULT_STATE = 0; const SCH_MAPPER_NORMAL_STATE = 1;
SP_BEGIN("SPContextDoMapping");
pZombie = pContext->RipeZombie; pCred = pContext->RipeZombie->pServerCred;
if(pCred->cMappers) { // Clear "called" flags.
for(iMapper = 0; iMapper < pCred->cMappers; iMapper++) { pCred->pahMappers[iMapper]->m_dwFlags &= ~SCH_FLAG_MAPPER_CALLED; } pZombie->phMapper = NULL;
for(iState = 0; iState < 2; iState++) { for(iMapper = 0; iMapper < pCred->cMappers; iMapper++) { if(pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_MAPPER_CALLED) { // This mapper has already had its chance.
continue; }
if(iState == SCH_MAPPER_DEFAULT_STATE) { if(!(pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_DEFAULT_MAPPER)) { continue; } }
if((pCred->dwFlags & CRED_FLAG_NO_SYSTEM_MAPPER) && (pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)) { // Skip the system mapper.
DebugLog((DEB_TRACE, "Skip the system mapper\n")); continue; }
#if DBG
if(pCred->pahMappers[iMapper]->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER) { DebugLog((DEB_TRACE, "Invoke the system mapper\n")); } else { DebugLog((DEB_TRACE, "Invoke the application mapper\n")); } #endif
// Invoke mapper.
pctRet = SslMapCredential( pCred->pahMappers[iMapper], X509_ASN_CHAIN, pZombie->pRemoteCert, NULL, &pZombie->hLocator);
pCred->pahMappers[iMapper]->m_dwFlags |= SCH_FLAG_MAPPER_CALLED;
if(NT_SUCCESS(pctRet)) { // Mapping was successful.
DebugLog((DEB_TRACE, "Mapping was successful (0x%p)\n", pZombie->hLocator));
SslReferenceMapper(pCred->pahMappers[iMapper]); if(pZombie->phMapper) { SslDereferenceMapper(pZombie->phMapper); } pZombie->phMapper = pCred->pahMappers[iMapper]; pZombie->LocatorStatus = SEC_E_OK; break; } else { // Mapping failed.
DebugLog((DEB_TRACE, "Mapping failed (0x%x)\n", pctRet));
pZombie->LocatorStatus = pctRet; } }
if(pZombie->phMapper) { break; } } }
SP_RETURN(PCT_ERR_OK); }
SP_STATUS RemoveDuplicateIssuers( PBYTE pbIssuers, PDWORD pcbIssuers) { DWORD cbIssuers = *pcbIssuers; DWORD cBlob; PCRYPT_DATA_BLOB rgBlob; DWORD cbIssuer; PBYTE pbIssuer; PBYTE pbSource, pbDest; DWORD i, j;
if(pbIssuers == NULL || cbIssuers < 2) { return PCT_ERR_OK; }
// Count number of issuers.
cBlob = 0; pbIssuer = pbIssuers; while(pbIssuer + 1 < pbIssuers + cbIssuers) { cbIssuer = MAKEWORD(pbIssuer[1], pbIssuer[0]);
pbIssuer += 2 + cbIssuer; cBlob++; }
// Allocate memory for blob list.
rgBlob = SPExternalAlloc(cBlob * sizeof(CRYPT_DATA_BLOB)); if(rgBlob == NULL) { return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); }
// Build blob list.
cBlob = 0; pbIssuer = pbIssuers; while(pbIssuer + 1 < pbIssuers + cbIssuers) { cbIssuer = MAKEWORD(pbIssuer[1], pbIssuer[0]); rgBlob[cBlob].cbData = 2 + cbIssuer; rgBlob[cBlob].pbData = pbIssuer;
pbIssuer += 2 + cbIssuer; cBlob++; }
// Mark duplicates.
for(i = 0; i < cBlob; i++) { if(rgBlob[i].pbData == NULL) continue;
for(j = i + 1; j < cBlob; j++) { if(rgBlob[j].pbData == NULL) continue;
if(rgBlob[i].cbData == rgBlob[j].cbData && memcmp(rgBlob[i].pbData, rgBlob[j].pbData, rgBlob[j].cbData) == 0) { // duplicate found
rgBlob[j].pbData = NULL; } } }
// Compact list.
pbSource = pbIssuers; pbDest = pbIssuers; for(i = 0; i < cBlob; i++) { if(rgBlob[i].pbData) { if(pbDest != pbSource) { MoveMemory(pbDest, pbSource, rgBlob[i].cbData); } pbDest += rgBlob[i].cbData; } pbSource += rgBlob[i].cbData; } *pcbIssuers = (DWORD)(pbDest - pbIssuers);
// Free blob list.
SPExternalFree(rgBlob);
return PCT_ERR_OK; }
SP_STATUS SPContextGetIssuers( PSPCredentialGroup pCredGroup) { LONG i; PBYTE pbIssuerList; DWORD cbIssuerList; PBYTE pbIssuer; DWORD cbIssuer; PBYTE pbNew; DWORD Status;
LockCredential(pCredGroup);
if((pCredGroup->pbTrustedIssuers != NULL) && !(pCredGroup->dwFlags & CRED_FLAG_UPDATE_ISSUER_LIST)) { // Issuer list has already been built.
Status = PCT_ERR_OK; goto cleanup; }
// Free existing issuer list.
if(pCredGroup->pbTrustedIssuers) { LocalFree(pCredGroup->pbTrustedIssuers); pCredGroup->pbTrustedIssuers = NULL; pCredGroup->cbTrustedIssuers = 0; } pCredGroup->dwFlags &= ~CRED_FLAG_UPDATE_ISSUER_LIST;
//
// Get issuers from application-specified ROOT store.
//
pbIssuerList = NULL; cbIssuerList = 0;
while(pCredGroup->hApplicationRoots) { Status = ExtractIssuerNamesFromStore(pCredGroup->hApplicationRoots, NULL, &cbIssuerList); if(Status != PCT_ERR_OK) { break; }
pbIssuerList = LocalAlloc(LPTR, cbIssuerList); if(pbIssuerList == NULL) { break; }
Status = ExtractIssuerNamesFromStore(pCredGroup->hApplicationRoots, pbIssuerList, &cbIssuerList); if(Status != PCT_ERR_OK) { LocalFree(pbIssuerList); pbIssuerList = NULL; cbIssuerList = 0; }
break; }
//
// Call each of the mappers in turn, building a large
// list of all trusted issuers.
//
for(i = 0; i < pCredGroup->cMappers; i++) { #if 0
if((pCredGroup->dwFlags & CRED_FLAG_NO_SYSTEM_MAPPER) && (pCredGroup->pahMappers[i]->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)) { // Skip the system mapper.
continue; } #endif
Status = SslGetMapperIssuerList(pCredGroup->pahMappers[i], &pbIssuer, &cbIssuer); if(!NT_SUCCESS(Status)) { continue; }
if(pbIssuerList == NULL) { pbIssuerList = LocalAlloc(LPTR, cbIssuer); if(pbIssuerList == NULL) { SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); break; } } else { pbNew = LocalReAlloc(pbIssuerList, cbIssuerList + cbIssuer, LMEM_MOVEABLE); if(pbNew == NULL) { SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); break; } pbIssuerList = pbNew; }
CopyMemory(pbIssuerList + cbIssuerList, pbIssuer, cbIssuer);
cbIssuerList += cbIssuer;
SPExternalFree(pbIssuer); }
//
// Remove duplicates from list.
//
if(pbIssuerList) { Status = RemoveDuplicateIssuers(pbIssuerList, &cbIssuerList); if(!NT_SUCCESS(Status)) { LocalFree(pbIssuerList); goto cleanup; } }
pCredGroup->cbTrustedIssuers = cbIssuerList; // do not reverse these lines
pCredGroup->pbTrustedIssuers = pbIssuerList;
Status = PCT_ERR_OK;
cleanup:
UnlockCredential(pCredGroup);
return Status; }
SP_STATUS SPPickClientCertificate( PSPContext pContext, DWORD dwExchSpec) { PSPCredentialGroup pCred; PSPCredential pCurrentCred; SP_STATUS pctRet; DWORD i;
pCred = pContext->pCredGroup; if((pCred == NULL) || (pCred->pCredList == NULL)) { return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); }
pContext->pActiveClientCred = NULL;
pctRet = PCT_ERR_SPECS_MISMATCH;
for(i = 0; i < pCred->cCredList; i++) { pCurrentCred = pCred->pCredList + i;
if(pCurrentCred->pCert == NULL) { continue; }
if(pCurrentCred->pPublicKey == NULL) { continue; }
// Does this cert contain the proper key type.
if(dwExchSpec != pCurrentCred->dwExchSpec) { continue; // try the next cert.
}
// Does this cert have the proper encoding type?
if(pCurrentCred->pCert->dwCertEncodingType != X509_ASN_ENCODING) { continue; }
// WE FOUND ONE
pContext->pActiveClientCred = pCurrentCred;
pctRet = PCT_ERR_OK; break; }
return pctRet; }
SP_STATUS SPPickServerCertificate( PSPContext pContext, DWORD dwExchSpec) { PSPCredentialGroup pCred; PSPCredential pCurrentCred; SP_STATUS pctRet; DWORD i;
pCred = pContext->RipeZombie->pServerCred; if((pCred == NULL) || (pCred->pCredList == NULL)) { return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); }
DsysAssert((pContext->RipeZombie->dwFlags & SP_CACHE_FLAG_READONLY) == 0);
#if 0
if(pContext->RipeZombie->dwFlags & SP_CACHE_FLAG_READONLY) { // What in the world causes this case to occur? Anything?
// Don't mess with the current credentials.
if(pContext->RipeZombie->pActiveServerCred == NULL) { return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); } else { return PCT_ERR_OK; } } #endif
pContext->RipeZombie->pActiveServerCred = NULL;
pctRet = PCT_ERR_SPECS_MISMATCH;
for(i = 0; i < pCred->cCredList; i++) { pCurrentCred = pCred->pCredList + i;
if(pCurrentCred->pCert == NULL) { continue; }
if(pCurrentCred->pPublicKey == NULL) { continue; }
// Does this cert contain the proper key type.
if(dwExchSpec != pCurrentCred->dwExchSpec) { continue; // try the next cert.
}
// Does this cert have the proper encoding type?
if(pCurrentCred->pCert->dwCertEncodingType != X509_ASN_ENCODING) { continue; }
// WE FOUND ONE
pContext->RipeZombie->pActiveServerCred = pCurrentCred; pContext->RipeZombie->CredThumbprint = pCred->CredThumbprint; pContext->RipeZombie->CertThumbprint = pCurrentCred->CertThumbprint;
// Set "master" provider handle to current credential's. Note that
// SSL3 will sometimes overide this selection in favor of its
// ephemeral key pair.
pContext->RipeZombie->hMasterProv = pCurrentCred->hProv;
pctRet = PCT_ERR_OK; break; }
return pctRet; }
// This routine is called by the user process. It frees a context
// structure that was originally allocated by the LSA process,
// and passed over via the SPContextDeserialize routine.
BOOL LsaContextDelete(PSPContext pContext) { if(pContext) { if(pContext->hReadKey) { SchCryptDestroyKey(pContext->hReadKey, 0); pContext->hReadKey = 0; } if(pContext->hReadMAC) { SchCryptDestroyKey(pContext->hReadMAC, 0); pContext->hReadMAC = 0; } if(pContext->hWriteKey) { SchCryptDestroyKey(pContext->hWriteKey, 0); pContext->hWriteKey = 0; } if(pContext->hWriteMAC) { SchCryptDestroyKey(pContext->hWriteMAC, 0); pContext->hWriteMAC = 0; }
// Close locator if this handle belongs to the system
// default certificate mapper.
if(pContext->RipeZombie) { if(pContext->RipeZombie->hLocator && pContext->RipeZombie->phMapper) { if(pContext->RipeZombie->phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER) { NtClose((HANDLE)pContext->RipeZombie->hLocator); pContext->RipeZombie->hLocator = 0; } }
if(pContext->RipeZombie->pbServerCertificate) { SPExternalFree(pContext->RipeZombie->pbServerCertificate); pContext->RipeZombie->pbServerCertificate = NULL; } } } return TRUE; }
/*
* * Misc Utility functions. * */
#if DBG
typedef struct _DbgMapCrypto { DWORD C; PSTR psz; } DbgMapCrypto;
DbgMapCrypto DbgCryptoNames[] = { {CALG_RC4, "RC4 "}, };
CHAR DbgNameSpace[100]; PSTR DbgAlgNames[] = { "Basic RSA", "RSA with MD2", "RSA with MD5", "RC4 stream"}; #define AlgName(x) ((x < sizeof(DbgAlgNames) / sizeof(PSTR)) ? DbgAlgNames[x] : "Unknown")
PSTR DbgGetNameOfCrypto(DWORD x) { int i; for (i = 0; i < sizeof(DbgCryptoNames) / sizeof(DbgMapCrypto) ; i++ ) { if (x == DbgCryptoNames[i].C) { wsprintf(DbgNameSpace, "%s", (DbgCryptoNames[i].psz)); return DbgNameSpace; } }
return("Unknown"); } #endif
#if 0
PSTR CopyString( PSTR pszString) { PSTR pszNewString; DWORD cchString;
cchString = lstrlen(pszString) + 1;
pszNewString = (PSTR)SPExternalAlloc(cchString);
if (pszNewString) { CopyMemory(pszNewString, pszString, cchString); }
return(pszNewString); } #endif
#ifdef LTS
int __cdecl memcmp ( const void * buf1, const void * buf2, size_t count ) { if (!count) return(0);
while ( --count && *(char *)buf1 == *(char *)buf2 ) { buf1 = (char *)buf1 + 1; buf2 = (char *)buf2 + 1; }
return( *((unsigned char *)buf1) - *((unsigned char *)buf2) ); }
#endif
#if DBG
typedef struct _CONTEXTLIST { struct _CONTEXTLIST *pNext; PSPContext pContext; } CONTEXTLIST, *PCONTEXTLIST;
PCONTEXTLIST g_ContextList = NULL;
static void AddContextToList(PSPContext pContext) { PCONTEXTLIST pNew = LocalAlloc(LMEM_FIXED, sizeof(CONTEXTLIST)); pNew->pNext = g_ContextList; pNew->pContext = pContext; g_ContextList = pNew; }
static void DeleteContextFromList(PSPContext pContext) { PCONTEXTLIST pItem, pPrevItem; BOOL fFound = FALSE;
if(g_ContextList == NULL) { DebugLog((DEB_ERROR, "List is empty!\n")); } else if(g_ContextList->pContext == pContext) { // Delete first item in list
g_ContextList = g_ContextList->pNext; fFound = TRUE; } else { pPrevItem = g_ContextList;
for(pItem = g_ContextList->pNext; pItem; pItem = pItem->pNext) { if(pItem->pContext == pContext) { pPrevItem->pNext = pItem->pNext; LocalFree(pItem); fFound = TRUE; break; } pPrevItem = pItem; } }
if(!fFound) { DebugLog((DEB_ERROR, "Unknown context 0x%p\n", pContext)); } }
void DumpContexts(void) { PCONTEXTLIST pItem; DWORD dwCount = 0;
SP_BEGIN("DumpContexts");
for(pItem = g_ContextList; pItem; pItem = pItem->pNext) { dwCount++;
DebugLog((DEB_TRACE, "Context:%8x, Cache:%8x\n", pItem->pContext, pItem->pContext->RipeZombie)); }
if(dwCount != g_cContext) { DebugLog((DEB_ERROR, "Context count discrepancy %d vs. %d\n", dwCount, g_cContext)); }
SP_END(); }
#endif
|