//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995. // // File: srvprot.c // // Contents: // // Classes: // // Functions: // // History: 09-26-97 jbanes LSA integration stuff. // //---------------------------------------------------------------------------- #include #include #include #include #include #include /* The main purpose of this handler is to determine what kind of protocol * the client hello is */ SP_STATUS WINAPI ServerProtocolHandler( PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pCommOutput) { SP_STATUS pctRet = PCT_INT_ILLEGAL_MSG; PBYTE pb; PBYTE pbClientHello; DWORD dwVersion; DWORD dwEnabledProtocols; /* PCTv1.0 Hello starts with * RECORD_LENGTH_MSB (ignore) * RECORD_LENGTH_LSB (ignore) * PCT1_CLIENT_HELLO (must be equal) * PCT1_CLIENT_VERSION_MSB (if version greater than PCTv1) * PCT1_CLIENT_VERSION_LSB (if version greater than PCTv1) * * ... PCT hello ... */ /* Microsft Unihello starts with * RECORD_LENGTH_MSB (ignore) * RECORD_LENGTH_LSB (ignore) * SSL2_CLIENT_HELLO (must be equal) * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3) * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3) * * ... SSLv2 Compatable Hello ... */ /* SSLv2 Hello starts with * RECORD_LENGTH_MSB (ignore) * RECORD_LENGTH_LSB (ignore) * SSL2_CLIENT_HELLO (must be equal) * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3) * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3) * * ... SSLv2 Hello ... */ /* SSLv3 Type 2 Hello starts with * RECORD_LENGTH_MSB (ignore) * RECORD_LENGTH_LSB (ignore) * SSL2_CLIENT_HELLO (must be equal) * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv3) * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv3) * * ... SSLv2 Compatable Hello ... */ /* SSLv3 Type 3 Hello starts with * 0x15 Hex (HANDSHAKE MESSAGE) * VERSION MSB * VERSION LSB * RECORD_LENGTH_MSB (ignore) * RECORD_LENGTH_LSB (ignore) * HS TYPE (CLIENT_HELLO) * 3 bytes HS record length * HS Version * HS Version */ dwEnabledProtocols = pContext->pCredGroup->grbitEnabledProtocols; // We need at least 5 bytes to determine what we have. if (pCommInput->cbData < 5) { return(PCT_INT_INCOMPLETE_MSG); } pb = pCommInput->pvBuffer; // If the first byte is 0x15, then check if we have a // SSLv3 Type3 client hello if(pb[0] == SSL3_CT_HANDSHAKE) { // // This is an SSL3 ClientHello. // // We need at least foo bytes to determine what we have. if (pCommInput->cbData < sizeof(SWRAP) + sizeof(SHSH) + 2) { return(PCT_INT_INCOMPLETE_MSG); } pbClientHello = pb + sizeof(SWRAP) + sizeof(SHSH); dwVersion = COMBINEBYTES(pbClientHello[0], pbClientHello[1]); if(dwVersion > 0x300 && (0 != (SP_PROT_TLS1_SERVER & dwEnabledProtocols))) { DebugLog((DEB_TRACE, "SSL3 ClientHello received, selected TLS\n")); pContext->dwProtocol = SP_PROT_TLS1_SERVER; } else if(0 != (SP_PROT_SSL3_SERVER & dwEnabledProtocols)) { DebugLog((DEB_TRACE, "SSL3 ClientHello received, selected SSL3\n")); pContext->dwProtocol = SP_PROT_SSL3_SERVER; } else { return SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH); } pContext->ProtocolHandler = Ssl3ProtocolHandler; pContext->DecryptHandler = Ssl3DecryptHandler; pctRet = Ssl3ProtocolHandler(pContext, pCommInput, pCommOutput); return(pctRet); } else { // // Assuming SSL2 (or compatible) ClientHello // dwVersion = COMBINEBYTES(pb[3], pb[4]); } if(dwVersion >= PCT_VERSION_1) { // // This is a PCT ClientHello. // if(!(SP_PROT_PCT1_SERVER & dwEnabledProtocols)) { return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); } // We're running PCT, so set up the PCT handlers DebugLog((DEB_TRACE, "PCT ClientHello received, selected PCT\n")); pContext->dwProtocol = SP_PROT_PCT1_SERVER; pContext->ProtocolHandler = Pct1ServerProtocolHandler; pContext->DecryptHandler = Pct1DecryptHandler; return(Pct1ServerProtocolHandler(pContext, pCommInput, pCommOutput)); } if(dwVersion >= SSL2_CLIENT_VERSION) { // we're either receiving ssl2, ssl3, or pct1 compat PSSL2_CLIENT_HELLO pRawHello = pCommInput->pvBuffer; // Do we have one client hello message with at least one // cipher spec. if (pCommInput->cbData < (sizeof(SSL2_CLIENT_HELLO)+2)) { return(PCT_INT_INCOMPLETE_MSG); } // We must have at least one cipher spec if(COMBINEBYTES(pRawHello->CipherSpecsLenMsb, pRawHello->CipherSpecsLenLsb) < 1) { return(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG)); } // Does client support TLS? if((dwVersion >= TLS1_CLIENT_VERSION) && (0 != (SP_PROT_TLS1_SERVER & dwEnabledProtocols))) { DebugLog((DEB_TRACE, "SSL2 ClientHello received, selected TLS\n")); pContext->State = UNI_STATE_RECVD_UNIHELLO; pContext->dwProtocol = SP_PROT_TLS1_SERVER; pContext->ProtocolHandler = Ssl3ProtocolHandler; pContext->DecryptHandler = Ssl3DecryptHandler; return(Ssl3ProtocolHandler(pContext, pCommInput, pCommOutput)); } // Does client support SSL3? if((dwVersion >= SSL3_CLIENT_VERSION) && (0 != (SP_PROT_SSL3TLS1_SERVERS & dwEnabledProtocols))) { DebugLog((DEB_TRACE, "SSL2 ClientHello received, selected SSL3\n")); pContext->State = UNI_STATE_RECVD_UNIHELLO; pContext->dwProtocol = SP_PROT_SSL3_SERVER; pContext->ProtocolHandler = Ssl3ProtocolHandler; pContext->DecryptHandler = Ssl3DecryptHandler; return(Ssl3ProtocolHandler(pContext, pCommInput, pCommOutput)); } // Is the PCT compatability flag set? if(pRawHello->VariantData[0] == PCT_SSL_COMPAT) { // Get the pct version. dwVersion = COMBINEBYTES(pRawHello->VariantData[1], pRawHello->VariantData[2]); } // Does client support PCT? if((dwVersion >= PCT_VERSION_1) && (0 != (SP_PROT_PCT1_SERVER & dwEnabledProtocols))) { DebugLog((DEB_TRACE, "SSL2 ClientHello received, selected PCT\n")); pContext->State = UNI_STATE_RECVD_UNIHELLO; pContext->dwProtocol = SP_PROT_PCT1_SERVER; pContext->ProtocolHandler = Pct1ServerProtocolHandler; pContext->DecryptHandler = Pct1DecryptHandler; return(Pct1ServerProtocolHandler(pContext, pCommInput, pCommOutput)); } // Does client support SSL2? if((dwVersion >= SSL2_CLIENT_VERSION) && (0 != (SP_PROT_SSL2_SERVER & dwEnabledProtocols))) { DebugLog((DEB_TRACE, "SSL2 ClientHello received, selected SSL2\n")); pContext->dwProtocol = SP_PROT_SSL2_SERVER; pContext->ProtocolHandler = Ssl2ServerProtocolHandler; pContext->DecryptHandler = Ssl2DecryptHandler; return(Ssl2ServerProtocolHandler(pContext, pCommInput, pCommOutput)); } return(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG)); } return (pctRet); }