예제 #1
0
        /// <summary>
        /// Send (resend) a ClientHello message to the server
        /// </summary>
        private void SendClientHello()
        {
            // Reset our verification stream
            this.nextEpoch.VerificationStream.SetLength(0);
            this.nextEpoch.ClientRandom.FillWithRandom(this.random);

            // Describe our ClientHello flight
            ClientHello clientHello = new ClientHello();

            clientHello.Random       = this.nextEpoch.ClientRandom;
            clientHello.Cookie       = this.nextEpoch.Cookie;
            clientHello.CipherSuites = new byte[2];
            clientHello.CipherSuites.WriteBigEndian16((ushort)CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256);
            clientHello.SupportedCurves = new byte[2];
            clientHello.SupportedCurves.WriteBigEndian16((ushort)NamedCurve.x25519);

            Handshake handshake = new Handshake();

            handshake.MessageType     = HandshakeType.ClientHello;
            handshake.Length          = (uint)clientHello.CalculateSize();
            handshake.MessageSequence = 0;
            handshake.FragmentOffset  = 0;
            handshake.FragmentLength  = handshake.Length;

            // Describe the record
            int    plaintextLength = (int)(Handshake.Size + handshake.Length);
            Record outgoingRecord  = new Record();

            outgoingRecord.ContentType    = ContentType.Handshake;
            outgoingRecord.Epoch          = this.epoch;
            outgoingRecord.SequenceNumber = this.currentEpoch.NextOutgoingSequence;
            outgoingRecord.Length         = (ushort)this.currentEpoch.RecordProtection.GetEncryptedSize(plaintextLength);
            ++this.currentEpoch.NextOutgoingSequence;

            // Convert the record to wire format
            ByteSpan packet = new byte[Record.Size + outgoingRecord.Length];
            ByteSpan writer = packet;

            outgoingRecord.Encode(packet);
            writer = writer.Slice(Record.Size);
            handshake.Encode(writer);
            writer = writer.Slice(Handshake.Size);
            clientHello.Encode(writer);

            // Write ClientHello to the verification stream
            this.nextEpoch.VerificationStream.Write(
                packet.GetUnderlyingArray()
                , Record.Size
                , Handshake.Size + (int)handshake.Length
                );

            // Protect the record
            this.currentEpoch.RecordProtection.EncryptClientPlaintext(
                packet.Slice(Record.Size, outgoingRecord.Length)
                , packet.Slice(Record.Size, plaintextLength)
                , ref outgoingRecord
                );

            this.nextEpoch.State = HandshakeState.ExpectingServerHello;
            this.nextEpoch.NextPacketResendTime = DateTime.UtcNow + this.handshakeResendTimeout;
            base.WriteBytesToConnection(packet.GetUnderlyingArray(), packet.Length);
        }
예제 #2
0
        /// <summary>
        /// Parse a Handshake ClientHello payload from wire format
        /// </summary>
        /// <returns>True if we successfully decode the ClientHello message. Otherwise false</returns>
        public static bool Parse(out ClientHello result, ByteSpan span)
        {
            result = new ClientHello();
            if (span.Length < MinSize)
            {
                return(false);
            }

            ProtocolVersion clientVersion = (ProtocolVersion)span.ReadBigEndian16();

            if (clientVersion != ProtocolVersion.DTLS1_2)
            {
                return(false);
            }
            span = span.Slice(2);

            result.Random = span.Slice(0, Dtls.Random.Size);
            span          = span.Slice(Dtls.Random.Size);

            ///NOTE(mendsley): We ignore session id
            byte sessionIdSize = span[0];

            if (span.Length < 1 + sessionIdSize)
            {
                return(false);
            }
            span = span.Slice(1 + sessionIdSize);

            byte cookieSize = span[0];

            if (span.Length < 1 + cookieSize)
            {
                return(false);
            }
            result.Cookie = span.Slice(1, cookieSize);
            span          = span.Slice(1 + cookieSize);

            ushort cipherSuiteSize = span.ReadBigEndian16();

            if (span.Length < 2 + cipherSuiteSize)
            {
                return(false);
            }
            else if (cipherSuiteSize % 2 != 0)
            {
                return(false);
            }
            result.CipherSuites = span.Slice(2, cipherSuiteSize);
            span = span.Slice(2 + cipherSuiteSize);

            int  compressionMethodsSize     = span[0];
            bool foundNullCompressionMethod = false;

            for (int ii = 0; ii != compressionMethodsSize; ++ii)
            {
                if (span[1 + ii] == (byte)CompressionMethod.Null)
                {
                    foundNullCompressionMethod = true;
                    break;
                }
            }
            span = span.Slice(1 + compressionMethodsSize);

            if (!foundNullCompressionMethod)
            {
                return(false);
            }

            // Parse extensions
            if (span.Length > 0)
            {
                ushort extensionsSize = span.ReadBigEndian16();
                span = span.Slice(2);
                if (span.Length != extensionsSize)
                {
                    return(false);
                }

                while (span.Length > 0)
                {
                    // Parse extension header
                    if (span.Length < 4)
                    {
                        return(false);
                    }

                    ExtensionType extensionType   = (ExtensionType)span.ReadBigEndian16(0);
                    ushort        extensionLength = span.ReadBigEndian16(2);
                    ByteSpan      extensionData   = span.Slice(4, extensionLength);
                    if (extensionData.Length < extensionLength)
                    {
                        return(false);
                    }

                    span = span.Slice(4 + extensionLength);
                    result.ParseExtension(extensionType, extensionData);
                }
            }

            return(true);
        }