Пример #1
0
        protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body)
        {
            SecurityParameters securityParameters = state.clientContext.SecurityParameters;

            MemoryStream buf = new MemoryStream(body, false);

            {
                ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
                ReportServerVersion(state, server_version);
            }

            securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);

            state.selectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (state.selectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            state.client.NotifySessionID(state.selectedSessionID);
            state.resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null &&
                                   Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);

            int selectedCipherSuite = TlsUtilities.ReadUint16(buf);

            if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.clientContext.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.illegal_parameter);
            state.client.NotifySelectedCipherSuite(selectedCipherSuite);

            byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);

            /*
             * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
             * hello message when the client has requested extended functionality via the extended
             * client hello message specified in Section 2.1. ... Note that the extended server hello
             * message is only sent in response to an extended client hello message. This prevents the
             * possibility that the extended server hello message could "break" existing TLS 1.0
             * clients.
             */

            /*
             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
             * extensions appearing in the client hello, and send a server hello containing no
             * extensions.
             */

            // Integer -> byte[]
            state.serverExtensions = TlsProtocol.ReadExtensions(buf);

            /*
             * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
             * extended client hello message. However, see RFC 5746 exception below. We always include
             * the SCSV, so an Extended Server Hello is always allowed.
             */
            if (state.serverExtensions != null)
            {
                foreach (int extType in state.serverExtensions.Keys)
                {
                    /*
                     * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
                     * ClientHello containing only the SCSV is an explicit exception to the prohibition
                     * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is
                     * only allowed because the client is signaling its willingness to receive the
                     * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
                     */
                    if (extType == ExtensionType.renegotiation_info)
                    {
                        continue;
                    }

                    /*
                     * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
                     * same extension type appeared in the corresponding ClientHello. If a client
                     * receives an extension type in ServerHello that it did not request in the
                     * associated ClientHello, it MUST abort the handshake with an unsupported_extension
                     * fatal alert.
                     */
                    if (null == TlsUtilities.GetExtensionData(state.clientExtensions, extType))
                    {
                        throw new TlsFatalAlert(AlertDescription.unsupported_extension);
                    }

                    /*
                     * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
                     * extensions appearing in the client hello, and send a server hello containing no
                     * extensions[.]
                     */
                    if (state.resumedSession)
                    {
                        // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
                        // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
                        // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
                        //throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }
                }
            }

            /*
             * RFC 5746 3.4. Client Behavior: Initial Handshake
             */
            {
                /*
                 * When a ServerHello is received, the client MUST check if it includes the
                 * "renegotiation_info" extension:
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                     * If the extension is present, set the secure_renegotiation flag to TRUE. The
                     * client MUST then verify that the length of the "renegotiated_connection"
                     * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
                     * handshake_failure alert).
                     */
                    state.secure_renegotiation = true;

                    if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                    {
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                    }
                }
            }

            // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
            state.client.NotifySecureRenegotiation(state.secure_renegotiation);

            IDictionary sessionClientExtensions = state.clientExtensions, sessionServerExtensions = state.serverExtensions;

            if (state.resumedSession)
            {
                if (selectedCipherSuite != state.sessionParameters.CipherSuite ||
                    selectedCompressionMethod != state.sessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                sessionClientExtensions = null;
                sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
            }

            securityParameters.cipherSuite          = selectedCipherSuite;
            securityParameters.compressionAlgorithm = selectedCompressionMethod;

            if (sessionServerExtensions != null)
            {
                {
                    /*
                     * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
                     * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
                     * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
                     * client.
                     */
                    bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
                    if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(securityParameters.CipherSuite))
                    {
                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }
                    securityParameters.encryptThenMac = serverSentEncryptThenMAC;
                }

                securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);

                securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
                                                                                          sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);

                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be
                 * sent in a session resumption handshake.
                 */
                state.allowCertificateStatus = !state.resumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.illegal_parameter);

                state.expectSessionTicket = !state.resumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.illegal_parameter);
            }

            /*
             * TODO[session-hash]
             *
             * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
             * that do not use the extended master secret [..]. (and see 5.2, 5.3)
             */

            if (sessionClientExtensions != null)
            {
                state.client.ProcessServerExtensions(sessionServerExtensions);
            }

            securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext,
                                                                          securityParameters.CipherSuite);

            /*
             * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
             * a verify_data_length equal to 12. This includes all existing cipher suites.
             */
            securityParameters.verifyDataLength = 12;
        }