992 lines
26 KiB
C
992 lines
26 KiB
C
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
||
|
//
|
||
|
// File: cliprot.c
|
||
|
//
|
||
|
// Contents:
|
||
|
//
|
||
|
// Classes:
|
||
|
//
|
||
|
// Functions:
|
||
|
//
|
||
|
// History: 09-23-97 jbanes LSA integration stuff.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <spbase.h>
|
||
|
#include <pct1msg.h>
|
||
|
#include <pct1prot.h>
|
||
|
#include <ssl2msg.h>
|
||
|
#include <ssl3msg.h>
|
||
|
#include <ssl2prot.h>
|
||
|
|
||
|
UNICipherMap UniAvailableCiphers[] = {
|
||
|
// NULL cipher suite
|
||
|
{
|
||
|
// 0
|
||
|
SSL3_NULL_WITH_NULL_NULL
|
||
|
},
|
||
|
|
||
|
// PCT ciphers
|
||
|
{
|
||
|
// 1
|
||
|
UNI_CK_PCT,
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
0, 0,
|
||
|
SP_EXCH_UNKNOWN
|
||
|
},
|
||
|
{
|
||
|
// 2
|
||
|
SSL_MKFAST(PCT_SSL_CERT_TYPE, MSBOF(PCT1_CERT_X509_CHAIN), LSBOF(PCT1_CERT_X509_CHAIN)),
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
0, 0,
|
||
|
SP_EXCH_UNKNOWN
|
||
|
},
|
||
|
{
|
||
|
// 3
|
||
|
SSL_MKFAST(PCT_SSL_CERT_TYPE, MSBOF(PCT1_CERT_X509), LSBOF(PCT1_CERT_X509)),
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
0, 0,
|
||
|
SP_EXCH_UNKNOWN
|
||
|
},
|
||
|
{
|
||
|
// 4
|
||
|
SSL_MKFAST(PCT_SSL_HASH_TYPE, MSBOF(PCT1_HASH_MD5), LSBOF(PCT1_HASH_MD5)),
|
||
|
SP_PROT_PCT1,
|
||
|
CALG_MD5,
|
||
|
0, 0,
|
||
|
SP_EXCH_UNKNOWN
|
||
|
},
|
||
|
{
|
||
|
// 5
|
||
|
SSL_MKFAST(PCT_SSL_HASH_TYPE, MSBOF(PCT1_HASH_SHA), LSBOF(PCT1_HASH_SHA)),
|
||
|
SP_PROT_PCT1,
|
||
|
CALG_SHA,
|
||
|
0, 0,
|
||
|
SP_EXCH_UNKNOWN
|
||
|
},
|
||
|
{
|
||
|
// 6
|
||
|
SSL_MKFAST(PCT_SSL_EXCH_TYPE, MSBOF(SP_EXCH_RSA_PKCS1), LSBOF(SP_EXCH_RSA_PKCS1)),
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
0, 0,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX
|
||
|
},
|
||
|
|
||
|
// SSL3 Domestic ciphers
|
||
|
{
|
||
|
// 7
|
||
|
SSL3_RSA_WITH_RC4_128_MD5,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_MD5 ,
|
||
|
CALG_RC4 ,128 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 8
|
||
|
SSL3_RSA_WITH_RC4_128_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA ,
|
||
|
CALG_RC4 ,128 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 9
|
||
|
SSL3_RSA_WITH_3DES_EDE_CBC_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA,
|
||
|
CALG_3DES ,168 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 10
|
||
|
SSL3_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA,
|
||
|
CALG_3DES ,168 ,
|
||
|
SP_EXCH_DH_PKCS3, CALG_DH_EPHEM,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// PCT Domestic ciphers
|
||
|
{
|
||
|
// 12
|
||
|
SSL_MKFAST(PCT_SSL_CIPHER_TYPE_1ST_HALF, MSBOF(PCT1_CIPHER_RC4>>16), LSBOF(PCT1_CIPHER_RC4>>16)),
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
CALG_RC4 ,128 ,
|
||
|
SP_EXCH_UNKNOWN, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 13
|
||
|
SSL_MKFAST(PCT_SSL_CIPHER_TYPE_2ND_HALF, MSBOF(PCT1_ENC_BITS_128), LSBOF(PCT1_MAC_BITS_128)),
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
CALG_RC4 ,128 ,
|
||
|
SP_EXCH_UNKNOWN, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// SSL2 Domestic ciphers
|
||
|
{
|
||
|
// 14
|
||
|
SSL_CK_RC4_128_WITH_MD5,
|
||
|
SP_PROT_SSL2 ,
|
||
|
CALG_MD5 ,
|
||
|
CALG_RC4 ,128 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 15
|
||
|
SSL_CK_DES_192_EDE3_CBC_WITH_MD5,
|
||
|
SP_PROT_SSL2 ,
|
||
|
CALG_MD5 ,
|
||
|
CALG_3DES ,168 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 16
|
||
|
SSL_CK_RC2_128_CBC_WITH_MD5,
|
||
|
SP_PROT_SSL2 ,
|
||
|
CALG_MD5 ,
|
||
|
CALG_RC2 ,128 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// SSL3 domestic DES ciphers
|
||
|
{
|
||
|
// 22
|
||
|
SSL3_RSA_WITH_DES_CBC_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA ,
|
||
|
CALG_DES , 56,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 23
|
||
|
SSL3_DHE_DSS_WITH_DES_CBC_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA ,
|
||
|
CALG_DES , 56 ,
|
||
|
SP_EXCH_DH_PKCS3, CALG_DH_EPHEM,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// SSL2 domestic DES ciphers
|
||
|
{
|
||
|
// 24
|
||
|
SSL_CK_DES_64_CBC_WITH_MD5,
|
||
|
SP_PROT_SSL2,
|
||
|
CALG_MD5 ,
|
||
|
CALG_DES , 56 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// SSL3 56-bit export ciphers
|
||
|
{
|
||
|
// 25
|
||
|
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA ,
|
||
|
CALG_RC4 ,56 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
EXPORT56_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 26
|
||
|
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA ,
|
||
|
CALG_DES , 56,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
EXPORT56_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 27
|
||
|
TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA ,
|
||
|
CALG_DES , 56 ,
|
||
|
SP_EXCH_DH_PKCS3, CALG_DH_EPHEM,
|
||
|
EXPORT56_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// SSL3 Export ciphers
|
||
|
{
|
||
|
// 28
|
||
|
SSL3_RSA_EXPORT_WITH_RC4_40_MD5,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_MD5 ,
|
||
|
CALG_RC4 ,40 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
EXPORT40_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 29
|
||
|
SSL3_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_MD5 ,
|
||
|
CALG_RC2 ,40 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
EXPORT40_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// PCT Export ciphers
|
||
|
{
|
||
|
// 30
|
||
|
SSL_MKFAST(PCT_SSL_CIPHER_TYPE_1ST_HALF, MSBOF(PCT1_CIPHER_RC4>>16), LSBOF(PCT1_CIPHER_RC4>>16)),
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
CALG_RC4 ,40 ,
|
||
|
SP_EXCH_UNKNOWN, CALG_RSA_KEYX,
|
||
|
EXPORT40_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 31
|
||
|
SSL_MKFAST(PCT_SSL_CIPHER_TYPE_2ND_HALF, MSBOF(PCT1_ENC_BITS_40), LSBOF(PCT1_MAC_BITS_128)),
|
||
|
SP_PROT_PCT1,
|
||
|
0,
|
||
|
CALG_RC4 ,40 ,
|
||
|
SP_EXCH_UNKNOWN, CALG_RSA_KEYX,
|
||
|
EXPORT40_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// SSL2 Export ciphers
|
||
|
{
|
||
|
// 32
|
||
|
SSL_CK_RC4_128_EXPORT40_WITH_MD5,
|
||
|
SP_PROT_SSL2 ,
|
||
|
CALG_MD5 ,
|
||
|
CALG_RC4 ,40 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
EXPORT40_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 33
|
||
|
SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5,
|
||
|
SP_PROT_SSL2 ,
|
||
|
CALG_MD5 ,
|
||
|
CALG_RC2 ,40 ,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
EXPORT40_CIPHER_SUITE
|
||
|
},
|
||
|
|
||
|
// SSL3 Zero privacy ciphers
|
||
|
{
|
||
|
// 34
|
||
|
SSL3_RSA_WITH_NULL_MD5,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_MD5 ,
|
||
|
CALG_NULLCIPHER, 0,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
},
|
||
|
{
|
||
|
// 35
|
||
|
SSL3_RSA_WITH_NULL_SHA,
|
||
|
SP_PROT_SSL3 | SP_PROT_TLS1,
|
||
|
CALG_SHA ,
|
||
|
CALG_NULLCIPHER, 0,
|
||
|
SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX,
|
||
|
DOMESTIC_CIPHER_SUITE
|
||
|
}
|
||
|
};
|
||
|
|
||
|
DWORD UniNumCiphers = sizeof(UniAvailableCiphers)/sizeof(UNICipherMap);
|
||
|
|
||
|
|
||
|
|
||
|
SP_STATUS WINAPI
|
||
|
GenerateSsl2StyleHello(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pOutput,
|
||
|
WORD fProtocol);
|
||
|
|
||
|
|
||
|
SP_STATUS
|
||
|
GetSupportedCapiAlgs(
|
||
|
HCRYPTPROV hProv,
|
||
|
DWORD dwCapiFlags,
|
||
|
PROV_ENUMALGS_EX ** ppAlgInfo,
|
||
|
DWORD * pcAlgInfo)
|
||
|
{
|
||
|
PROV_ENUMALGS_EX AlgInfo;
|
||
|
DWORD dwFlags;
|
||
|
DWORD cbData;
|
||
|
DWORD cAlgs;
|
||
|
DWORD i;
|
||
|
|
||
|
*ppAlgInfo = NULL;
|
||
|
*pcAlgInfo = 0;
|
||
|
|
||
|
// Count the algorithms.
|
||
|
dwFlags = CRYPT_FIRST;
|
||
|
for(cAlgs = 0; ; cAlgs++)
|
||
|
{
|
||
|
cbData = sizeof(PROV_ENUMALGS_EX);
|
||
|
if(!SchCryptGetProvParam(hProv,
|
||
|
PP_ENUMALGS_EX,
|
||
|
(PBYTE)&AlgInfo,
|
||
|
&cbData,
|
||
|
dwFlags,
|
||
|
dwCapiFlags))
|
||
|
{
|
||
|
if(GetLastError() != ERROR_NO_MORE_ITEMS)
|
||
|
{
|
||
|
SP_LOG_RESULT(GetLastError());
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
dwFlags = 0;
|
||
|
}
|
||
|
if(cAlgs == 0)
|
||
|
{
|
||
|
return SP_LOG_RESULT(SEC_E_ALGORITHM_MISMATCH);
|
||
|
}
|
||
|
|
||
|
// Allocate memory.
|
||
|
*ppAlgInfo = SPExternalAlloc(sizeof(PROV_ENUMALGS_EX) * cAlgs);
|
||
|
if(*ppAlgInfo == NULL)
|
||
|
{
|
||
|
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
|
||
|
}
|
||
|
|
||
|
// Read the algorithms.
|
||
|
dwFlags = CRYPT_FIRST;
|
||
|
for(i = 0; i < cAlgs; i++)
|
||
|
{
|
||
|
cbData = sizeof(PROV_ENUMALGS_EX);
|
||
|
if(!SchCryptGetProvParam(hProv,
|
||
|
PP_ENUMALGS_EX,
|
||
|
(PBYTE)(*ppAlgInfo + i),
|
||
|
&cbData,
|
||
|
dwFlags,
|
||
|
dwCapiFlags))
|
||
|
{
|
||
|
if(GetLastError() != ERROR_NO_MORE_ITEMS)
|
||
|
{
|
||
|
SP_LOG_RESULT(GetLastError());
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
dwFlags = 0;
|
||
|
}
|
||
|
if(i == 0)
|
||
|
{
|
||
|
SPExternalFree(*ppAlgInfo);
|
||
|
*ppAlgInfo = NULL;
|
||
|
|
||
|
LogNoCiphersSupportedEvent();
|
||
|
return SP_LOG_RESULT(SEC_E_ALGORITHM_MISMATCH);
|
||
|
}
|
||
|
|
||
|
*pcAlgInfo = i;
|
||
|
|
||
|
return PCT_ERR_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
SP_STATUS WINAPI
|
||
|
GenerateHello(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pOutput,
|
||
|
BOOL fCache)
|
||
|
{
|
||
|
PSessCacheItem pZombie;
|
||
|
PSPCredentialGroup pCred;
|
||
|
BOOL fFound;
|
||
|
DWORD fProt;
|
||
|
|
||
|
if (!pOutput)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
|
||
|
}
|
||
|
|
||
|
if(fCache)
|
||
|
{
|
||
|
// Look this id up in the cache
|
||
|
fFound = SPCacheRetrieveByName(pContext->pszTarget,
|
||
|
pContext->pCredGroup,
|
||
|
&pContext->RipeZombie);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fFound = FALSE;
|
||
|
}
|
||
|
|
||
|
if(!fFound)
|
||
|
{
|
||
|
// We're doing a full handshake, so allocate a cache entry.
|
||
|
if(!SPCacheRetrieveNew(FALSE,
|
||
|
pContext->pszTarget,
|
||
|
&pContext->RipeZombie))
|
||
|
{
|
||
|
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
|
||
|
}
|
||
|
pContext->RipeZombie->dwCF = pContext->dwRequestedCF;
|
||
|
}
|
||
|
|
||
|
if(pContext->RipeZombie == NULL)
|
||
|
{
|
||
|
return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
|
||
|
}
|
||
|
pZombie = pContext->RipeZombie;
|
||
|
|
||
|
pCred = pContext->pCredGroup;
|
||
|
if(!pCred)
|
||
|
{
|
||
|
return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
|
||
|
}
|
||
|
|
||
|
// Use protocol from cache unless it's a new cache element,
|
||
|
// in which case use the protocol from credential.
|
||
|
if(fFound)
|
||
|
{
|
||
|
fProt = pZombie->fProtocol;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fProt = pCred->grbitEnabledProtocols;
|
||
|
}
|
||
|
pContext->dwProtocol = fProt;
|
||
|
pContext->dwClientEnabledProtocols = fProt;
|
||
|
|
||
|
if(SP_PROT_UNI_CLIENT & fProt)
|
||
|
{
|
||
|
pContext->State = UNI_STATE_CLIENT_HELLO;
|
||
|
pContext->ProtocolHandler = ClientProtocolHandler;
|
||
|
|
||
|
return GenerateUniHello(pContext, pOutput, pCred->grbitEnabledProtocols);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
if(SP_PROT_TLS1_CLIENT & fProt)
|
||
|
{
|
||
|
DWORD dwProtocol = SP_PROT_TLS1_CLIENT;
|
||
|
|
||
|
pContext->State = SSL3_STATE_CLIENT_HELLO;
|
||
|
pContext->ProtocolHandler = Ssl3ProtocolHandler;
|
||
|
if(!fFound)
|
||
|
{
|
||
|
pZombie->fProtocol = SP_PROT_TLS1_CLIENT;
|
||
|
}
|
||
|
|
||
|
if(SP_PROT_SSL3_CLIENT & fProt)
|
||
|
{
|
||
|
// Both TLS and SSL3 are enabled.
|
||
|
dwProtocol |= SP_PROT_SSL3_CLIENT;
|
||
|
}
|
||
|
|
||
|
return GenerateTls1ClientHello(pContext, pOutput, dwProtocol);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
if(SP_PROT_SSL3_CLIENT & fProt)
|
||
|
{
|
||
|
pContext->State = SSL3_STATE_CLIENT_HELLO;
|
||
|
pContext->ProtocolHandler = Ssl3ProtocolHandler;
|
||
|
if(!fFound)
|
||
|
{
|
||
|
pZombie->fProtocol = SP_PROT_SSL3_CLIENT;
|
||
|
}
|
||
|
|
||
|
return GenerateSsl3ClientHello(pContext, pOutput);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
if(SP_PROT_PCT1_CLIENT & fProt)
|
||
|
{
|
||
|
pContext->State = PCT1_STATE_CLIENT_HELLO;
|
||
|
pContext->ProtocolHandler = Pct1ClientProtocolHandler;
|
||
|
|
||
|
return GeneratePct1StyleHello(pContext, pOutput);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
if(SP_PROT_SSL2_CLIENT & fProt)
|
||
|
{
|
||
|
pContext->State = SSL2_STATE_CLIENT_HELLO;
|
||
|
pContext->ProtocolHandler = Ssl2ClientProtocolHandler;
|
||
|
|
||
|
return GenerateUniHello(pContext, pOutput, SP_PROT_SSL2_CLIENT);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return SP_LOG_RESULT(SEC_E_ALGORITHM_MISMATCH);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ClientVetAlg
|
||
|
//
|
||
|
// Synopsis: Examine the cipher suite input, and decide if it is currently
|
||
|
// enabled. Take into account the enabled protocols and ciphers
|
||
|
// enabled in the schannel registry as well as the protocols and
|
||
|
// ciphers enabled by the application in the V3 credential.
|
||
|
// Return TRUE if the cipher suite is enabled.
|
||
|
//
|
||
|
// Arguments: [pContext] -- Schannel context.
|
||
|
//
|
||
|
// [dwProtocol] -- Client protocols to be included in the
|
||
|
// ClientHello message.
|
||
|
//
|
||
|
// [pCipherMap] -- Cipher suite to be examined.
|
||
|
//
|
||
|
// History: 10-29-97 jbanes Created
|
||
|
//
|
||
|
// Notes: This routine is called by the client-side only.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL
|
||
|
ClientVetAlg(
|
||
|
PSPContext pContext,
|
||
|
DWORD dwProtocol,
|
||
|
UNICipherMap * pCipherMap)
|
||
|
{
|
||
|
PCipherInfo pCipherInfo = NULL;
|
||
|
PHashInfo pHashInfo = NULL;
|
||
|
PKeyExchangeInfo pExchInfo = NULL;
|
||
|
|
||
|
if((pCipherMap->fProt & dwProtocol) == 0)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Is cipher supported?
|
||
|
if(pCipherMap->aiCipher != 0)
|
||
|
{
|
||
|
pCipherInfo = GetCipherInfo(pCipherMap->aiCipher,
|
||
|
pCipherMap->dwStrength);
|
||
|
|
||
|
if(!IsCipherSuiteAllowed(pContext,
|
||
|
pCipherInfo,
|
||
|
dwProtocol,
|
||
|
pContext->RipeZombie->dwCF,
|
||
|
pCipherMap->dwFlags))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Is hash supported?
|
||
|
if(pCipherMap->aiHash != 0)
|
||
|
{
|
||
|
pHashInfo = GetHashInfo(pCipherMap->aiHash);
|
||
|
|
||
|
if(!IsHashAllowed(pContext, pHashInfo, dwProtocol))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Is exchange alg supported?
|
||
|
if(pCipherMap->KeyExch != SP_EXCH_UNKNOWN)
|
||
|
{
|
||
|
pExchInfo = GetKeyExchangeInfo(pCipherMap->KeyExch);
|
||
|
|
||
|
if(!IsExchAllowed(pContext, pExchInfo, dwProtocol))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ClientBuildAlgList
|
||
|
//
|
||
|
// Synopsis: Build a list of ciphers to be included in the ClientHello
|
||
|
// message. This routine is used by all protocols.
|
||
|
//
|
||
|
// Arguments: [pContext] -- Schannel context.
|
||
|
//
|
||
|
// [fProtocol] -- Protocol(s) to be included in the
|
||
|
// ClientHello message.
|
||
|
//
|
||
|
// [pCipherSpecs] -- (out) Array where cipher specs are
|
||
|
// placed.
|
||
|
//
|
||
|
// [pcCipherSpecs] -- (out) Size of cipher specs array.
|
||
|
//
|
||
|
// History: 10-29-97 jbanes Created
|
||
|
//
|
||
|
// Notes: This routine is called by the client-side only.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
SP_STATUS
|
||
|
ClientBuildAlgList(
|
||
|
PSPContext pContext,
|
||
|
DWORD dwProtocol,
|
||
|
Ssl2_Cipher_Kind * pCipherSpecs,
|
||
|
PDWORD pcCipherSpecs)
|
||
|
{
|
||
|
DWORD i;
|
||
|
DWORD cCipherSpecs = 0;
|
||
|
|
||
|
// Consider only the client protocols.
|
||
|
dwProtocol &= SP_PROT_CLIENTS;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Handle the RSA case.
|
||
|
//
|
||
|
|
||
|
if(g_hRsaSchannel && g_pRsaSchannelAlgs)
|
||
|
{
|
||
|
for(i = 0; i < UniNumCiphers; i++)
|
||
|
{
|
||
|
if(UniAvailableCiphers[i].KeyExch != SP_EXCH_RSA_PKCS1 &&
|
||
|
UniAvailableCiphers[i].KeyExch != SP_EXCH_UNKNOWN)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(!ClientVetAlg(pContext, dwProtocol, UniAvailableCiphers + i))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(!IsAlgSupportedCapi(dwProtocol,
|
||
|
UniAvailableCiphers + i,
|
||
|
g_pRsaSchannelAlgs,
|
||
|
g_cRsaSchannelAlgs))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// this cipher is good to request
|
||
|
pCipherSpecs[cCipherSpecs++] = UniAvailableCiphers[i].CipherKind;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Handle the DH case.
|
||
|
//
|
||
|
|
||
|
if(g_hDhSchannelProv)
|
||
|
{
|
||
|
for(i = 0; i < UniNumCiphers; i++)
|
||
|
{
|
||
|
if(UniAvailableCiphers[i].KeyExch != SP_EXCH_DH_PKCS3)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(!ClientVetAlg(pContext, dwProtocol, UniAvailableCiphers + i))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(!IsAlgSupportedCapi(dwProtocol,
|
||
|
UniAvailableCiphers + i,
|
||
|
g_pDhSchannelAlgs,
|
||
|
g_cDhSchannelAlgs))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// this cipher is good to request
|
||
|
pCipherSpecs[cCipherSpecs++] = UniAvailableCiphers[i].CipherKind;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if(cCipherSpecs == 0)
|
||
|
{
|
||
|
return SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH);
|
||
|
}
|
||
|
|
||
|
*pcCipherSpecs = cCipherSpecs;
|
||
|
|
||
|
return PCT_ERR_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
SP_STATUS WINAPI
|
||
|
GenerateUniHelloMessage(
|
||
|
PSPContext pContext,
|
||
|
Ssl2_Client_Hello * pHelloMessage,
|
||
|
DWORD fProtocol
|
||
|
)
|
||
|
{
|
||
|
SP_STATUS pctRet;
|
||
|
UCHAR bOffset = 2;
|
||
|
|
||
|
SP_BEGIN("GenerateUniHelloMessage");
|
||
|
|
||
|
|
||
|
if(!pHelloMessage)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
|
||
|
}
|
||
|
|
||
|
|
||
|
pContext->Flags |= CONTEXT_FLAG_CLIENT;
|
||
|
|
||
|
|
||
|
// Generate the cipher list
|
||
|
pHelloMessage->cCipherSpecs = MAX_UNI_CIPHERS;
|
||
|
pctRet = ClientBuildAlgList(pContext,
|
||
|
fProtocol,
|
||
|
pHelloMessage->CipherSpecs,
|
||
|
&pHelloMessage->cCipherSpecs);
|
||
|
if(pctRet != PCT_ERR_OK)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(pctRet));
|
||
|
}
|
||
|
|
||
|
|
||
|
// We're minimally version 2
|
||
|
pHelloMessage->dwVer = SSL2_CLIENT_VERSION;
|
||
|
|
||
|
|
||
|
if(fProtocol & SP_PROT_TLS1_CLIENT)
|
||
|
{
|
||
|
pHelloMessage->dwVer = TLS1_CLIENT_VERSION;
|
||
|
}
|
||
|
else if(fProtocol & SP_PROT_SSL3_CLIENT)
|
||
|
{
|
||
|
pHelloMessage->dwVer = SSL3_CLIENT_VERSION;
|
||
|
}
|
||
|
|
||
|
/* Build the hello message. */
|
||
|
pHelloMessage->cbSessionID = 0;
|
||
|
|
||
|
if (pContext->RipeZombie && pContext->RipeZombie->cbSessionID)
|
||
|
{
|
||
|
KeyExchangeSystem *pKeyExchSys = NULL;
|
||
|
|
||
|
// Get pointer to key exchange system.
|
||
|
pKeyExchSys = KeyExchangeFromSpec(pContext->RipeZombie->SessExchSpec,
|
||
|
pContext->RipeZombie->fProtocol);
|
||
|
if(pKeyExchSys)
|
||
|
{
|
||
|
// Request a reconnect.
|
||
|
CopyMemory(pHelloMessage->SessionID,
|
||
|
pContext->RipeZombie->SessionID,
|
||
|
pContext->RipeZombie->cbSessionID);
|
||
|
|
||
|
pHelloMessage->cbSessionID = pContext->RipeZombie->cbSessionID;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugLog((DEB_WARN, "Abstaining from requesting reconnect\n"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CopyMemory( pHelloMessage->Challenge,
|
||
|
pContext->pChallenge,
|
||
|
pContext->cbChallenge);
|
||
|
pHelloMessage->cbChallenge = pContext->cbChallenge;
|
||
|
|
||
|
SP_RETURN(PCT_ERR_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
SP_STATUS WINAPI
|
||
|
GenerateUniHello(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pOutput,
|
||
|
DWORD fProtocol
|
||
|
)
|
||
|
|
||
|
{
|
||
|
SP_STATUS pctRet;
|
||
|
Ssl2_Client_Hello HelloMessage;
|
||
|
|
||
|
SP_BEGIN("GenerateUniHello");
|
||
|
|
||
|
GenerateRandomBits( pContext->pChallenge, SSL2_CHALLENGE_SIZE );
|
||
|
pContext->cbChallenge = SSL2_CHALLENGE_SIZE;
|
||
|
|
||
|
pctRet = GenerateUniHelloMessage(pContext, &HelloMessage, fProtocol);
|
||
|
|
||
|
pContext->ReadCounter = 0;
|
||
|
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
SP_RETURN(pctRet);
|
||
|
}
|
||
|
if(PCT_ERR_OK != (pctRet = Ssl2PackClientHello(&HelloMessage, pOutput)))
|
||
|
{
|
||
|
SP_RETURN(pctRet);
|
||
|
}
|
||
|
|
||
|
// Save the ClientHello message so we can hash it later, once
|
||
|
// we know what algorithm and CSP we're using.
|
||
|
if(pContext->pClientHello)
|
||
|
{
|
||
|
SPExternalFree(pContext->pClientHello);
|
||
|
}
|
||
|
pContext->pClientHello = SPExternalAlloc(pOutput->cbData);
|
||
|
if(pContext->pClientHello == NULL)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
|
||
|
}
|
||
|
CopyMemory(pContext->pClientHello, pOutput->pvBuffer, pOutput->cbData);
|
||
|
pContext->cbClientHello = pOutput->cbData;
|
||
|
pContext->dwClientHelloProtocol = SP_PROT_SSL2_CLIENT;
|
||
|
|
||
|
/* We set this here to tell the protocol engine that we just send a client
|
||
|
* hello, and we're expecting a pct server hello */
|
||
|
pContext->WriteCounter = 1;
|
||
|
pContext->ReadCounter = 0;
|
||
|
|
||
|
SP_RETURN(PCT_ERR_OK);
|
||
|
}
|
||
|
|
||
|
SP_STATUS WINAPI
|
||
|
ClientProtocolHandler(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommInput,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
SP_STATUS pctRet = 0;
|
||
|
PUCHAR pb;
|
||
|
DWORD dwVersion;
|
||
|
PSPCredentialGroup pCred;
|
||
|
|
||
|
pCred = pContext->pCredGroup;
|
||
|
if(!pCred)
|
||
|
{
|
||
|
return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
|
||
|
}
|
||
|
|
||
|
/* PCTv1.0 Server Hello starts with
|
||
|
* RECORD_LENGTH_MSB (ignore)
|
||
|
* RECORD_LENGTH_LSB (ignore)
|
||
|
* PCT1_SERVER_HELLO (must be equal)
|
||
|
* SH_PAD
|
||
|
* PCT1_CLIENT_VERSION_MSB (must be pct1)
|
||
|
* PCT1_CLIENT_VERSION_LSB (must be pct1)
|
||
|
*
|
||
|
* ... PCT hello ...
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* SSLv2 Hello starts with
|
||
|
* RECORD_LENGTH_MSB (ignore)
|
||
|
* RECORD_LENGTH_LSB (ignore)
|
||
|
* SSL2_SERVER_HELLO (must be equal)
|
||
|
* SESSION_ID_HIT
|
||
|
* CERTIFICATE_TYPE
|
||
|
* SSL2_CLIENT_VERSION_MSB (Must be ssl2)
|
||
|
* SSL2_CLIENT_VERSION_LSB (Must be ssl2)
|
||
|
*
|
||
|
* ... SSLv2 Hello ...
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* SSLv3 Type 3 Server Hello starts with
|
||
|
* 0x15 Hex (HANDSHAKE MESSAGE)
|
||
|
* VERSION MSB
|
||
|
* VERSION LSB
|
||
|
* RECORD_LENGTH_MSB (ignore)
|
||
|
* RECORD_LENGTH_LSB (ignore)
|
||
|
* HS TYPE (SERVER_HELLO)
|
||
|
* 3 bytes HS record length
|
||
|
* HS Version
|
||
|
* HS Version
|
||
|
*/
|
||
|
|
||
|
// We need at least 12 bytes to determine what we have.
|
||
|
if (pCommInput->cbData < 12)
|
||
|
{
|
||
|
return(PCT_INT_INCOMPLETE_MSG);
|
||
|
}
|
||
|
|
||
|
pb = pCommInput->pvBuffer;
|
||
|
|
||
|
if(pb[0] == SSL3_CT_HANDSHAKE && pb[5] == SSL3_HS_SERVER_HELLO)
|
||
|
{
|
||
|
dwVersion = COMBINEBYTES(pb[9], pb[10]);
|
||
|
|
||
|
if((dwVersion == SSL3_CLIENT_VERSION) &&
|
||
|
(pCred->grbitEnabledProtocols & SP_PROT_SSL3_CLIENT))
|
||
|
{
|
||
|
// This appears to be an SSL3 server_hello.
|
||
|
pContext->dwProtocol = SP_PROT_SSL3_CLIENT;
|
||
|
}
|
||
|
else if((dwVersion == TLS1_CLIENT_VERSION) &&
|
||
|
(pCred->grbitEnabledProtocols & SP_PROT_TLS1_CLIENT))
|
||
|
{
|
||
|
// This appears to be a TLS server_hello.
|
||
|
pContext->dwProtocol = SP_PROT_TLS1_CLIENT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
|
||
|
}
|
||
|
|
||
|
pContext->ProtocolHandler = Ssl3ProtocolHandler;
|
||
|
pContext->DecryptHandler = Ssl3DecryptHandler;
|
||
|
return(Ssl3ProtocolHandler(pContext, pCommInput, pCommOutput));
|
||
|
}
|
||
|
|
||
|
if(pb[2] == SSL2_MT_SERVER_HELLO)
|
||
|
{
|
||
|
dwVersion = COMBINEBYTES(pb[5], pb[6]);
|
||
|
if(dwVersion == SSL2_CLIENT_VERSION)
|
||
|
{
|
||
|
if(!(SP_PROT_SSL2_CLIENT & pCred->grbitEnabledProtocols))
|
||
|
{
|
||
|
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
|
||
|
}
|
||
|
|
||
|
// This appears to be an SSL2 server_hello.
|
||
|
pContext->dwProtocol = SP_PROT_SSL2_CLIENT;
|
||
|
pContext->ProtocolHandler = Ssl2ClientProtocolHandler;
|
||
|
pContext->DecryptHandler = Ssl2DecryptHandler;
|
||
|
return(Ssl2ClientProtocolHandler(pContext, pCommInput, pCommOutput));
|
||
|
}
|
||
|
}
|
||
|
if(pb[2] == PCT1_MSG_SERVER_HELLO)
|
||
|
{
|
||
|
DWORD i;
|
||
|
dwVersion = COMBINEBYTES(pb[4], pb[5]);
|
||
|
if(dwVersion ==PCT_VERSION_1)
|
||
|
{
|
||
|
if(!(SP_PROT_PCT1_CLIENT & pCred->grbitEnabledProtocols))
|
||
|
{
|
||
|
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
|
||
|
}
|
||
|
|
||
|
// Convert challenge from 16 byte to 32 byte
|
||
|
for(i=0; i < pContext->cbChallenge; i++)
|
||
|
{
|
||
|
pContext->pChallenge[i + pContext->cbChallenge] = ~pContext->pChallenge[i];
|
||
|
}
|
||
|
pContext->cbChallenge = 2*pContext->cbChallenge;
|
||
|
|
||
|
// This appears to be a PCT server_hello.
|
||
|
pContext->dwProtocol = SP_PROT_PCT1_CLIENT;
|
||
|
pContext->ProtocolHandler = Pct1ClientProtocolHandler;
|
||
|
pContext->DecryptHandler = Pct1DecryptHandler;
|
||
|
return(Pct1ClientProtocolHandler(pContext, pCommInput, pCommOutput));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
|
||
|
}
|