예제 #1
0
        /// <summary>
        /// Parse a Handshake ServerHello payload from wire format
        /// </summary>
        /// <returns>
        /// True if we successfully decode the ServerHello
        /// message. Otherwise false.
        /// </returns>
        public static bool Parse(out ServerHello result, ByteSpan span)
        {
            result = new ServerHello();
            if (span.Length < Size)
            {
                return(false);
            }

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

            span = span.Slice(2);

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

            byte sessionKeySize = span[0];

            span = span.Slice(1 + sessionKeySize);

            result.CipherSuite = (CipherSuite)span.ReadBigEndian16();
            span = span.Slice(2);

            CompressionMethod compressionMethod = (CompressionMethod)span[0];

            if (compressionMethod != CompressionMethod.Null)
            {
                return(false);
            }

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Parse a Handshake HelloVerifyRequest payload from wire
        /// format
        /// </summary>
        /// <returns>
        /// True if we successfully decode the HelloVerifyRequest
        /// message. Otherwise false.
        /// </returns>
        public static bool Parse(out HelloVerifyRequest result, ByteSpan span)
        {
            result = new HelloVerifyRequest();
            if (span.Length < 3)
            {
                return(false);
            }

            ProtocolVersion serverVersion = (ProtocolVersion)span.ReadBigEndian16(0);

            if (serverVersion != ProtocolVersion.DTLS1_2)
            {
                return(false);
            }

            byte cookieSize = span[2];

            span = span.Slice(3);

            if (span.Length < cookieSize)
            {
                return(false);
            }

            result.Cookie = span;
            return(true);
        }
예제 #3
0
        /// <summary>
        /// Parse a DTLS record from wire format
        /// </summary>
        /// <returns>True if we successfully parse the record header. Otherwise false</returns>
        public static bool Parse(out Record record, ByteSpan span)
        {
            record = new Record();

            if (span.Length < Size)
            {
                return(false);
            }

            record.ContentType = (ContentType)span[0];
            ProtocolVersion version = (ProtocolVersion)span.ReadBigEndian16(1);

            record.Epoch          = span.ReadBigEndian16(3);
            record.SequenceNumber = span.ReadBigEndian48(5);
            record.Length         = span.ReadBigEndian16(11);

            if (version != ProtocolVersion.DTLS1_2)
            {
                return(false);
            }

            return(true);
        }
예제 #4
0
        /// <summary>
        /// Determines if the ClientHello message advertises support
        /// for the specified curve
        /// </summary>
        public bool ContainsCurve(NamedCurve curve)
        {
            ByteSpan iterator = this.SupportedCurves;

            while (iterator.Length >= 2)
            {
                if (iterator.ReadBigEndian16() == (ushort)curve)
                {
                    return(true);
                }

                iterator = iterator.Slice(2);
            }

            return(false);
        }
예제 #5
0
        /// <summary>
        /// Determines if the ClientHello message advertises support
        /// for the specified cipher suite
        /// </summary>
        public bool ContainsCipherSuite(CipherSuite cipherSuite)
        {
            ByteSpan iterator = this.CipherSuites;

            while (iterator.Length >= 2)
            {
                if (iterator.ReadBigEndian16() == (ushort)cipherSuite)
                {
                    return(true);
                }

                iterator = iterator.Slice(2);
            }

            return(false);
        }
예제 #6
0
        /// <summary>
        /// Parse a Handshake protocol header from wire format
        /// </summary>
        /// <returns>True if we successfully decode a handshake header. Otherwise false</returns>
        public static bool Parse(out Handshake header, ByteSpan span)
        {
            header = new Handshake();

            if (span.Length < Size)
            {
                return(false);
            }

            header.MessageType     = (HandshakeType)span[0];
            header.Length          = span.ReadBigEndian24(1);
            header.MessageSequence = span.ReadBigEndian16(4);
            header.FragmentOffset  = span.ReadBigEndian24(6);
            header.FragmentLength  = span.ReadBigEndian24(9);
            return(true);
        }
예제 #7
0
        /// <summary>
        /// Decode a ClientHello extension
        /// </summary>
        /// <param name="extensionType">Extension type</param>
        /// <param name="extensionData">Extension data</param>
        private void ParseExtension(ExtensionType extensionType, ByteSpan extensionData)
        {
            switch (extensionType)
            {
            case ExtensionType.EllipticCurves:
                if (extensionData.Length % 2 != 0)
                {
                    break;
                }
                else if (extensionData.Length < 2)
                {
                    break;
                }

                ushort namedCurveSize = extensionData.ReadBigEndian16(0);
                if (namedCurveSize % 2 != 0)
                {
                    break;
                }

                this.SupportedCurves = extensionData.Slice(2, namedCurveSize);
                break;
            }
        }
예제 #8
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);
        }
        /// <inheritdoc />
        public bool VerifyServerMessageAndGenerateSharedKey(ByteSpan output, ByteSpan serverKeyExchangeMessage, object publicKey)
        {
            RSA rsaPublicKey = publicKey as RSA;

            if (rsaPublicKey == null)
            {
                return(false);
            }
            else if (output.Length != X25519.KeySize)
            {
                return(false);
            }

            // Verify message is compatible with this cipher suite
            if (serverKeyExchangeMessage.Length != CalculateServerMessageSize(rsaPublicKey.KeySize))
            {
                return(false);
            }
            else if (serverKeyExchangeMessage[0] != (byte)ECCurveType.NamedCurve)
            {
                return(false);
            }
            else if (serverKeyExchangeMessage.ReadBigEndian16(1) != (ushort)NamedCurve.x25519)
            {
                return(false);
            }
            else if (serverKeyExchangeMessage[3] != X25519.KeySize)
            {
                return(false);
            }
            else if (serverKeyExchangeMessage[4 + X25519.KeySize] != (byte)HashAlgorithm.Sha256)
            {
                return(false);
            }
            else if (serverKeyExchangeMessage[5 + X25519.KeySize] != (byte)SignatureAlgorithm.RSA)
            {
                return(false);
            }

            ByteSpan keyParameters   = serverKeyExchangeMessage.Slice(0, 4 + X25519.KeySize);
            ByteSpan othersPublicKey = keyParameters.Slice(4);
            ushort   signatureSize   = serverKeyExchangeMessage.ReadBigEndian16(6 + X25519.KeySize);
            ByteSpan signature       = serverKeyExchangeMessage.Slice(4 + keyParameters.Length);

            if (signatureSize != signature.Length)
            {
                return(false);
            }

            // Hash the key parameters
            byte[] parameterDigest = this.sha256.ComputeHash(keyParameters.GetUnderlyingArray(), keyParameters.Offset, keyParameters.Length);

            // Verify the signature
            RSAPKCS1SignatureDeformatter verifier = new RSAPKCS1SignatureDeformatter(rsaPublicKey);

            verifier.SetHashAlgorithm("SHA256");
            if (!verifier.VerifySignature(parameterDigest, signature.ToArray()))
            {
                return(false);
            }

            // Signature has been validated, generate the shared key
            return(X25519.Func(output, this.privateAgreementKey, othersPublicKey));
        }