//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995. // // File: cliprot.c // // Contents: // // Classes: // // Functions: // // History: 09-23-97 jbanes LSA integration stuff. // //---------------------------------------------------------------------------- #include #include #include #include #include #include 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, 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(!CryptGetProvParam(hProv, PP_ENUMALGS_EX, (PBYTE)&AlgInfo, &cbData, dwFlags)) { 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(!CryptGetProvParam(hProv, PP_ENUMALGS_EX, (PBYTE)(*ppAlgInfo + i), &cbData, dwFlags)) { 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; 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"); pctRet = GenerateRandomBits(pContext->pChallenge, SSL2_CHALLENGE_SIZE); if(pctRet != STATUS_SUCCESS) { SP_RETURN(pctRet); } 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) { 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); }