/**
  * Encode this {@link ServerSRPParams} to an {@link OutputStream}.
  *
  * @param output
  *            the {@link OutputStream} to encode to.
  * @throws IOException
  */
 public virtual void Encode(Stream output)
 {
     TlsSrpUtilities.WriteSrpParameter(m_N, output);
     TlsSrpUtilities.WriteSrpParameter(m_g, output);
     TlsUtilities.WriteOpaque8(m_s, output);
     TlsSrpUtilities.WriteSrpParameter(m_B, output);
 }
Beispiel #2
0
        public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters,
                                                     Stream output)
        {
            ECCurve curve = ecParameters.Curve;

            if (ECAlgorithms.IsFpCurve(curve))
            {
                TlsUtilities.WriteUint8(ECCurveType.explicit_prime, output);

                WriteECParameter(curve.Field.Characteristic, output);
            }
            else if (ECAlgorithms.IsF2mCurve(curve))
            {
                IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
                int[] exponents = field.MinimalPolynomial.GetExponentsPresent();

                TlsUtilities.WriteUint8(ECCurveType.explicit_char2, output);

                int m = exponents[exponents.Length - 1];
                TlsUtilities.CheckUint16(m);
                TlsUtilities.WriteUint16(m, output);

                if (exponents.Length == 3)
                {
                    TlsUtilities.WriteUint8(ECBasisType.ec_basis_trinomial, output);
                    WriteECExponent(exponents[1], output);
                }
                else if (exponents.Length == 5)
                {
                    TlsUtilities.WriteUint8(ECBasisType.ec_basis_pentanomial, output);
                    WriteECExponent(exponents[1], output);
                    WriteECExponent(exponents[2], output);
                    WriteECExponent(exponents[3], output);
                }
                else
                {
                    throw new ArgumentException("Only trinomial and pentomial curves are supported");
                }
            }
            else
            {
                throw new ArgumentException("'ecParameters' not a known curve type");
            }

            WriteECFieldElement(curve.A, output);
            WriteECFieldElement(curve.B, output);
            TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
            WriteECParameter(ecParameters.N, output);
            WriteECParameter(ecParameters.H, output);
        }
Beispiel #3
0
        public static byte[] CreateUseSrtpExtension(UseSrtpData useSrtpData)
        {
            if (useSrtpData == null)
            {
                throw new ArgumentNullException("useSrtpData");
            }

            MemoryStream buf = new MemoryStream();

            // SRTPProtectionProfiles
            TlsUtilities.WriteUint16ArrayWithUint16Length(useSrtpData.ProtectionProfiles, buf);

            // srtp_mki
            TlsUtilities.WriteOpaque8(useSrtpData.Mki, buf);

            return(buf.ToArray());
        }
    public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters, Stream output)
    {
        ECCurve curve = ecParameters.Curve;

        if (ECAlgorithms.IsFpCurve(curve))
        {
            TlsUtilities.WriteUint8(1, output);
            WriteECParameter(curve.Field.Characteristic, output);
        }
        else
        {
            if (!ECAlgorithms.IsF2mCurve(curve))
            {
                throw new ArgumentException("'ecParameters' not a known curve type");
            }
            IPolynomialExtensionField polynomialExtensionField = (IPolynomialExtensionField)curve.Field;
            int[] exponentsPresent = polynomialExtensionField.MinimalPolynomial.GetExponentsPresent();
            TlsUtilities.WriteUint8(2, output);
            int i = exponentsPresent[exponentsPresent.Length - 1];
            TlsUtilities.CheckUint16(i);
            TlsUtilities.WriteUint16(i, output);
            if (exponentsPresent.Length == 3)
            {
                TlsUtilities.WriteUint8(1, output);
                WriteECExponent(exponentsPresent[1], output);
            }
            else
            {
                if (exponentsPresent.Length != 5)
                {
                    throw new ArgumentException("Only trinomial and pentomial curves are supported");
                }
                TlsUtilities.WriteUint8(2, output);
                WriteECExponent(exponentsPresent[1], output);
                WriteECExponent(exponentsPresent[2], output);
                WriteECExponent(exponentsPresent[3], output);
            }
        }
        WriteECFieldElement(curve.A, output);
        WriteECFieldElement(curve.B, output);
        TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
        WriteECParameter(ecParameters.N, output);
        WriteECParameter(ecParameters.H, output);
    }
Beispiel #5
0
        public static byte[] CreateALPNExtension(System.Collections.Generic.List <string> protocols)
        {
            if (protocols == null)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            // https://tools.ietf.org/html/rfc7301
            using (var buf = new BestHTTP.Extensions.BufferPoolMemoryStream())
            {
                using (var protoBuf = new BestHTTP.Extensions.BufferPoolMemoryStream())
                {
                    foreach (string protocol in protocols)
                    {
                        // Empty strings MUST NOT be included and byte strings MUST NOT be truncated.
                        if (string.IsNullOrEmpty(protocol))
                        {
                            continue;
                        }

                        byte[] asciiEncoding = Strings.ToAsciiByteArray(protocol);
                        if (asciiEncoding.Length < 1)
                        {
                            throw new TlsFatalAlert(AlertDescription.internal_error);
                        }
                        TlsUtilities.WriteOpaque8(asciiEncoding, protoBuf);
                        BestHTTP.PlatformSupport.Memory.BufferPool.Release(asciiEncoding);
                    }

                    TlsUtilities.CheckUint16(protoBuf.Length);
                    TlsUtilities.WriteUint16((int)protoBuf.Length, buf);
                    protoBuf.WriteTo(buf);
                }

                return(buf.ToArray());
            }
        }
        protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
        {
            ProtocolVersion client_version = client.ClientVersion;

            if (!client_version.IsDtls)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            TlsClientContextImpl context = state.clientContext;

            context.SetClientVersion(client_version);

            SecurityParameters securityParameters = context.SecurityParameters;

            // Session ID
            byte[] session_id = TlsUtilities.EmptyBytes;
            if (state.tlsSession != null)
            {
                session_id = state.tlsSession.SessionID;
                if (session_id == null || session_id.Length > 32)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            bool fallback = client.IsFallback;

            state.offeredCipherSuites = client.GetCipherSuites();

            if (session_id.Length > 0 && state.sessionParameters != null)
            {
                if (!state.sessionParameters.IsExtendedMasterSecret ||
                    !Arrays.Contains(state.offeredCipherSuites, state.sessionParameters.CipherSuite) ||
                    CompressionMethod.cls_null != state.sessionParameters.CompressionAlgorithm)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(client.GetClientExtensions());

            TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions);

            MemoryStream buf = new MemoryStream();

            TlsUtilities.WriteVersion(client_version, buf);

            buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);

            TlsUtilities.WriteOpaque8(session_id, buf);

            // Cookie
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            // Cipher Suites (and SCSV)
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);

                if (noRenegExt && noRenegSCSV)
                {
                    // TODO Consider whether to default to a client extension instead
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
                }

                /*
                 * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
                 * than the latest (highest-valued) version supported by the client, it SHOULD include
                 * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
                 * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
                 * to negotiate.)
                 */
                if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
                {
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
                }

                TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
            }

            TlsUtilities.WriteUint8ArrayWithUint8Length(new byte[] { CompressionMethod.cls_null }, buf);

            TlsProtocol.WriteExtensions(buf, state.clientExtensions);

            return(buf.ToArray());
        }
Beispiel #7
0
 public static void WriteECPoint(byte[] ecPointFormats, ECPoint point, Stream output)
 {
     TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, point), output);
 }
Beispiel #8
0
 public static void WriteECParameter(BigInteger x, Stream output)
 {
     TlsUtilities.WriteOpaque8(BigIntegers.AsUnsignedByteArray(x), output);
 }
Beispiel #9
0
 public static void WriteECFieldElement(int fieldSize, BigInteger x, Stream output)
 {
     TlsUtilities.WriteOpaque8(SerializeECFieldElement(fieldSize, x), output);
 }
Beispiel #10
0
 public static void WriteECFieldElement(ECFieldElement x, Stream output)
 {
     TlsUtilities.WriteOpaque8(x.GetEncoded(), output);
 }
        protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
        {
            SecurityParameters securityParameters = state.serverContext.SecurityParameters;

            MemoryStream buf = new MemoryStream();

            {
                ProtocolVersion server_version = state.server.GetServerVersion();
                if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                // TODO Read RFCs for guidance on the expected record layer version number
                // recordStream.setReadVersion(server_version);
                // recordStream.setWriteVersion(server_version);
                // recordStream.setRestrictReadVersion(true);
                state.serverContext.SetServerVersion(server_version);

                TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
            }

            buf.Write(securityParameters.ServerRandom, 0, securityParameters.ServerRandom.Length);

            /*
             * The server may return an empty session_id to indicate that the session will not be cached
             * and therefore cannot be resumed.
             */
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            int selectedCipherSuite = state.server.GetSelectedCipherSuite();

            if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error);
            securityParameters.cipherSuite = selectedCipherSuite;

            byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod();

            if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            securityParameters.compressionAlgorithm = selectedCompressionMethod;

            TlsUtilities.WriteUint16(selectedCipherSuite, buf);
            TlsUtilities.WriteUint8(selectedCompressionMethod, buf);

            state.serverExtensions = state.server.GetServerExtensions();

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            if (state.secure_renegotiation)
            {
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                if (noRenegExt)
                {
                    /*
                     * 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 the secure_renegotiation flag is set to TRUE, the server MUST include an empty
                     * "renegotiation_info" extension in the ServerHello message.
                     */
                    state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
                    state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                }
            }

            if (securityParameters.extendedMasterSecret)
            {
                state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
            }

            /*
             * 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.
             */

            if (state.serverExtensions != null)
            {
                securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);

                securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
                                                                                          state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);

                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);

                /*
                 * 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(state.serverExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.internal_error);

                state.expectSessionTicket = !state.resumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.internal_error);

                TlsProtocol.WriteExtensions(buf, state.serverExtensions);
            }

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

            /*
             * RFC 5264 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;

            return(buf.ToArray());
        }
    protected virtual void SendServerHelloMessage()
    {
        HandshakeMessage handshakeMessage = new HandshakeMessage(2);
        ProtocolVersion  serverVersion    = mTlsServer.GetServerVersion();

        if (!serverVersion.IsEqualOrEarlierVersionOf(Context.ClientVersion))
        {
            throw new TlsFatalAlert(80);
        }
        mRecordStream.ReadVersion = serverVersion;
        mRecordStream.SetWriteVersion(serverVersion);
        mRecordStream.SetRestrictReadVersion(enabled: true);
        ContextAdmin.SetServerVersion(serverVersion);
        TlsUtilities.WriteVersion(serverVersion, handshakeMessage);
        handshakeMessage.Write(mSecurityParameters.serverRandom);
        TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, handshakeMessage);
        int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();

        if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite) || selectedCipherSuite == 0 || CipherSuite.IsScsv(selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
        {
            throw new TlsFatalAlert(80);
        }
        mSecurityParameters.cipherSuite = selectedCipherSuite;
        byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();

        if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
        {
            throw new TlsFatalAlert(80);
        }
        mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
        TlsUtilities.WriteUint16(selectedCipherSuite, handshakeMessage);
        TlsUtilities.WriteUint8(selectedCompressionMethod, handshakeMessage);
        mServerExtensions = mTlsServer.GetServerExtensions();
        if (mSecureRenegotiation)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(mServerExtensions, 65281);
            if (null == extensionData)
            {
                mServerExtensions        = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
                mServerExtensions[65281] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
            }
        }
        if (mSecurityParameters.extendedMasterSecret)
        {
            mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
            TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
        }
        if (mServerExtensions != null)
        {
            mSecurityParameters.encryptThenMac    = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
            mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions, mServerExtensions, 80);
            mSecurityParameters.truncatedHMac     = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);
            mAllowCertificateStatus = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 5, 80));
            mExpectSessionTicket    = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 35, 80));
            TlsProtocol.WriteExtensions(handshakeMessage, mServerExtensions);
        }
        mSecurityParameters.prfAlgorithm     = TlsProtocol.GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
        mSecurityParameters.verifyDataLength = 12;
        ApplyMaxFragmentLengthExtension();
        handshakeMessage.WriteToRecordStream(this);
    }
        protected virtual void SendServerHelloMessage()
        {
            HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);

            {
                ProtocolVersion server_version = mTlsServer.GetServerVersion();
                if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                mRecordStream.ReadVersion = server_version;
                mRecordStream.SetWriteVersion(server_version);
                mRecordStream.SetRestrictReadVersion(true);
                ContextAdmin.SetServerVersion(server_version);

                TlsUtilities.WriteVersion(server_version, message);
            }

            message.Write(this.mSecurityParameters.serverRandom);

            /*
             * The server may return an empty session_id to indicate that the session will not be cached
             * and therefore cannot be resumed.
             */
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message);

            int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();

            if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            mSecurityParameters.cipherSuite = selectedCipherSuite;

            byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();

            if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;

            TlsUtilities.WriteUint16(selectedCipherSuite, message);
            TlsUtilities.WriteUint8(selectedCompressionMethod, message);

            this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mTlsServer.GetServerExtensions());

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            if (this.mSecureRenegotiation)
            {
                byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                if (noRenegExt)
                {
                    /*
                     * 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 the secure_renegotiation flag is set to TRUE, the server MUST include an empty
                     * "renegotiation_info" extension in the ServerHello message.
                     */
                    this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                }
            }

            if (TlsUtilities.IsSsl(mTlsServerContext))
            {
                mSecurityParameters.extendedMasterSecret = false;
            }
            else if (mSecurityParameters.IsExtendedMasterSecret)
            {
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
            }

            /*
             * 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.
             */

            if (this.mServerExtensions.Count > 0)
            {
                this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);

                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions,
                                                                                               mServerExtensions, AlertDescription.internal_error);

                this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
                 * a session resumption handshake.
                 */
                this.mAllowCertificateStatus = !mResumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.internal_error);

                this.mExpectSessionTicket = !mResumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.internal_error);

                WriteExtensions(message, this.mServerExtensions);
            }

            mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.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.
             */
            mSecurityParameters.verifyDataLength = 12;

            ApplyMaxFragmentLengthExtension();

            message.WriteToRecordStream(this);
        }
        protected virtual void SendClientHelloMessage()
        {
            if (HTTPManager.Logger.Level <= Loglevels.All)
            {
                HTTPManager.Logger.Verbose("TlsClientProtocol", "SendClientHelloMessage", this.LoggingContext);
            }

            this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);

            ProtocolVersion client_version = this.mTlsClient.ClientVersion;

            if (client_version.IsDtls)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            ContextAdmin.SetClientVersion(client_version);

            /*
             * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
             * Session ID in the TLS ClientHello.
             */
            byte[] session_id = TlsUtilities.EmptyBytes;
            if (this.mTlsSession != null)
            {
                session_id = this.mTlsSession.SessionID;
                if (session_id == null || session_id.Length > 32)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            bool fallback = this.mTlsClient.IsFallback;

            this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();

            this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();

            if (session_id.Length > 0 && this.mSessionParameters != null)
            {
                if (!mSessionParameters.IsExtendedMasterSecret ||
                    !Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite) ||
                    !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mTlsClient.GetClientExtensions());

            if (!client_version.IsSsl)
            {
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(this.mClientExtensions);
            }

            HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);

            TlsUtilities.WriteVersion(client_version, message);

            message.Write(this.mSecurityParameters.ClientRandom);

            TlsUtilities.WriteOpaque8(session_id, message);

            // Cipher Suites (and SCSV)
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);

                if (noRenegExt && noRenegScsv)
                {
                    // TODO Consider whether to default to a client extension instead
                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
                }

                /*
                 * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
                 * than the latest (highest-valued) version supported by the client, it SHOULD include
                 * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
                 * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
                 * to negotiate.)
                 */
                if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
                {
                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
                }

                TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
            }

            TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);

            WriteExtensions(message, mClientExtensions);

            message.WriteToRecordStream(this);
        }
        protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
        {
            MemoryStream buf = new MemoryStream();

            ProtocolVersion client_version = client.ClientVersion;

            if (!client_version.IsDtls)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            TlsClientContextImpl context = state.clientContext;

            context.SetClientVersion(client_version);
            TlsUtilities.WriteVersion(client_version, buf);

            SecurityParameters securityParameters = context.SecurityParameters;

            buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);

            // Session ID
            byte[] session_id = TlsUtilities.EmptyBytes;
            if (state.tlsSession != null)
            {
                session_id = state.tlsSession.SessionID;
                if (session_id == null || session_id.Length > 32)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }
            TlsUtilities.WriteOpaque8(session_id, buf);

            // Cookie
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            bool fallback = client.IsFallback;

            /*
             * Cipher suites
             */
            state.offeredCipherSuites = client.GetCipherSuites();

            // Integer -> byte[]
            state.clientExtensions = client.GetClientExtensions();

            // Cipher Suites (and SCSV)
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);

                if (noRenegExt && noRenegSCSV)
                {
                    // TODO Consider whether to default to a client extension instead
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
                }

                /*
                 * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
                 * containing a lower value than the latest (highest-valued) version supported by the
                 * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
                 * ClientHello.cipher_suites.
                 */
                if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
                {
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
                }

                TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
            }

            // TODO Add support for compression
            // Compression methods
            // state.offeredCompressionMethods = client.getCompressionMethods();
            state.offeredCompressionMethods = new byte[] { CompressionMethod.cls_null };

            TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf);

            // Extensions
            if (state.clientExtensions != null)
            {
                TlsProtocol.WriteExtensions(buf, state.clientExtensions);
            }

            return(buf.ToArray());
        }