예제 #1
0
        HandshakeType SendClientHello(ref int offset)
        {
            _pendingConnState = new ConnectionState();
            _handshakeData = new HandshakeData
            {
                HandshakeHash1 = Hasher.Create(TLSHashAlgorithm.SHA256),
                HandshakeHash2 = Hasher.Create(TLSHashAlgorithm.SHA256),
                HandshakeHash1_384 = Hasher.Create(TLSHashAlgorithm.SHA384),
                HandshakeHash2_384 = Hasher.Create(TLSHashAlgorithm.SHA384),
                HandshakeHash1_MD5SHA1 = Hasher.Create(TLSHashAlgorithm.MD5SHA1),
                HandshakeHash2_MD5SHA1 = Hasher.Create(TLSHashAlgorithm.MD5SHA1),
                CertificateVerifyHash_MD5 = Hasher.Create(TLSHashAlgorithm.MD5),
                CertificateVerifyHash_SHA1 = Hasher.Create(TLSHashAlgorithm.SHA1)
            };

            // Highest version supported
            offset += Utils.WriteUInt16(_buf, offset, (ushort)HighestTlsVersionSupported);

            // Client random
            var timestamp = (uint)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
            _pendingConnState.ClientRandom = new byte[32];
            _rng.GetBytes(_pendingConnState.ClientRandom);
            Utils.WriteUInt32(_pendingConnState.ClientRandom, 0, timestamp);

            Buffer.BlockCopy(_pendingConnState.ClientRandom, 0, _buf, offset, 32);
            offset += 32;

            // No session id
            _buf[offset++] = 0;

            // Cipher suites
            var supportedCipherSuites = CipherSuiteInfo.Supported;
            /*
            if (HighestTlsVersionSupported != TlsVersion.TLSv1_2)
                supportedCipherSuites = supportedCipherSuites.Where(cs => cs.IsAllowedBefore1_2).ToArray();
            */
            offset += Utils.WriteUInt16(_buf, offset, (ushort)(supportedCipherSuites.Length * sizeof(ushort)));
            foreach (var suite in supportedCipherSuites)
            {
                offset += Utils.WriteUInt16(_buf, offset, (ushort)suite.Id);
            }

            // Compression methods
            _buf[offset++] = 1; // Length
            _buf[offset++] = 0; // "null" compression method

            // Extensions length, fill in later
            var extensionLengthOffset = offset;
            offset += 2;

            // Renegotiation extension
            offset += Utils.WriteUInt16(_buf, offset, (ushort)ExtensionType.RenegotiationInfo);
            if (_connState.SecureRenegotiation)
            {
                // Extension length
                offset += Utils.WriteUInt16(_buf, offset, 13);

                // Renegotiated connection length
                _buf[offset++] = 12;
                // Renegotiated connection data
                Buffer.BlockCopy(_connState.ClientVerifyData, 0, _buf, offset, 12);
                offset += 12;
            }
            else
            {
                // Extension length
                offset += Utils.WriteUInt16(_buf, offset, 1);
                // Renegotiated connection length
                _buf[offset++] = 0;
            }

            // SNI extension
            if (_hostName != null)
            {
                // TODO: IDN Unicode -> Punycode

                // NOTE: IP addresses should not use SNI extension, per specification.
                System.Net.IPAddress ip;
                if (!System.Net.IPAddress.TryParse(_hostName, out ip))
                {
                    offset += Utils.WriteUInt16(_buf, offset, (ushort)ExtensionType.ServerName);
                    var byteLen = Encoding.ASCII.GetBytes(_hostName, 0, _hostName.Length, _buf, offset + 7);
                    offset += Utils.WriteUInt16(_buf, offset, (ushort)(5 + byteLen));
                    offset += Utils.WriteUInt16(_buf, offset, (ushort)(3 + byteLen));
                    _buf[offset++] = 0; // host_name
                    offset += Utils.WriteUInt16(_buf, offset, (ushort)byteLen);
                    offset += byteLen;
                }
            }

            if (HighestTlsVersionSupported == TlsVersion.TLSv1_2)
            {
                // Signature algorithms extension. At least IIS 7.5 needs this or it immediately resets the connection.
                // Used to specify what kind of server certificate hash/signature algorithms we can use to verify it.
                offset += Utils.WriteUInt16(_buf, offset, (ushort)ExtensionType.SignatureAlgorithms);
                offset += Utils.WriteUInt16(_buf, offset, 20);
                offset += Utils.WriteUInt16(_buf, offset, 18);
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA1;
                _buf[offset++] = (byte)SignatureAlgorithm.ECDSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA256;
                _buf[offset++] = (byte)SignatureAlgorithm.ECDSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA384;
                _buf[offset++] = (byte)SignatureAlgorithm.ECDSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA512;
                _buf[offset++] = (byte)SignatureAlgorithm.ECDSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA1;
                _buf[offset++] = (byte)SignatureAlgorithm.RSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA256;
                _buf[offset++] = (byte)SignatureAlgorithm.RSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA384;
                _buf[offset++] = (byte)SignatureAlgorithm.RSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA512;
                _buf[offset++] = (byte)SignatureAlgorithm.RSA;
                _buf[offset++] = (byte)TLSHashAlgorithm.SHA1;
                _buf[offset++] = (byte)SignatureAlgorithm.DSA;
            }

            if (supportedCipherSuites.Any(s => s.KeyExchange == KeyExchange.ECDHE_RSA || s.KeyExchange == KeyExchange.ECDHE_ECDSA))
            {
                // Supported Elliptic Curves Extension

                offset += Utils.WriteUInt16(_buf, offset, (ushort)ExtensionType.SupportedEllipticCurves);
                offset += Utils.WriteUInt16(_buf, offset, 8);
                offset += Utils.WriteUInt16(_buf, offset, 6);
                offset += Utils.WriteUInt16(_buf, offset, (ushort)NamedCurve.secp256r1);
                offset += Utils.WriteUInt16(_buf, offset, (ushort)NamedCurve.secp384r1);
                offset += Utils.WriteUInt16(_buf, offset, (ushort)NamedCurve.secp521r1);

                // Supported Point Formats Extension

                offset += Utils.WriteUInt16(_buf, offset, (ushort)ExtensionType.SupportedPointFormats);
                offset += Utils.WriteUInt16(_buf, offset, 2);
                _buf[offset++] = 1; // Length
                _buf[offset++] = 0; // Uncompressed
            }


            Utils.WriteUInt16(_buf, extensionLengthOffset, (ushort)(offset - (extensionLengthOffset + 2)));

            return HandshakeType.ClientHello;
        }
예제 #2
0
        void ParseFinishedMessage(byte[] buf)
        {
            byte[] hash = Utils.PRF(_connState.PRFAlgorithm, _connState.MasterSecret, "server finished", _handshakeData.HandshakeHash2.Final(), 12);
            if (buf.Length != 4 + 12 || !hash.SequenceEqual(buf.Skip(4)))
                SendAlertFatal(AlertDescription.DecryptError);
            if (_connState.SecureRenegotiation)
                _connState.ServerVerifyData = hash;

            _handshakeData = null;
        }