예제 #1
0
        private void ProcessChangeCipherSpecRecord(Record record, AsyncHandshakeResult asyncHandshakeResult)
        {
            if (record.Fragment.Length != 1 || record.Fragment[0] != 0x01)
            {
                throw new AlertException(AlertDescription.IllegalParameter,
                                         "Received an invalid ChangeCipherSpec record");
            }

            // NOTE: keep this before recordHandler.ChangeLocalState since it may generate masterSecret
            _handshakeSession.RemoteChangeCipherSpec();

            // Change cipher suite in record handler and handle it in handshake session
            _recordHandler.SetCipherSuite(_handshakeSession.CipherSuite, _handshakeSession.ConnectionState);
            _recordHandler.ChangeRemoteState();

            // Read the finished message after changing cipher spec
            _recordStream.BeginReceive(new AsyncCallback(ReceiveHandshakeCallback), asyncHandshakeResult);
        }
예제 #2
0
        private async Task ReceiveChangeCipherSpecAndFinished(CancellationToken token)
        {
            var recordList = new List <Record>();
            var changeCipherSpecReceived = false;
            var finishedReceived         = false;

            while (!token.IsCancellationRequested)
            {
                var records = await _recordStream.ReceiveAsync(token);

                if (records == null || records.Count == 0)
                {
                    continue;
                }

                // Check for alerts
                foreach (var record in records)
                {
                    if (record.Type == RecordType.Alert)
                    {
                        logger?.Error($"Alert received: { (AlertDescription)record.Fragment[1]}");
                        if (record.Fragment.Length == 2)
                        {
                            var alert = (AlertDescription)record.Fragment[1];
                            throw new AlertException((AlertDescription)record.Fragment[1], $"Received TLS alert record: {alert}");
                        }
                    }
                }

                recordList.AddRange(records);
                if (recordList.Count < 2)
                {
                    continue;
                }

                foreach (var record in recordList)
                {
                    _recordHandler.ProcessInputRecord(record);

                    if (record.Type == RecordType.ChangeCipherSpec)
                    {
                        changeCipherSpecReceived = true;

                        if (record.Fragment.Length != 1 || record.Fragment[0] != 0x01)
                        {
                            throw new AlertException(AlertDescription.IllegalParameter, "Received an invalid ChangeCipherSpec record");
                        }

                        // NOTE: keep this before recordHandler.ChangeLocalState since it may generate masterSecret
                        _handshakeSession.RemoteChangeCipherSpec();

                        // Change cipher suite in record handler and handle it in handshake session
                        _recordHandler.SetCipherSuite(_handshakeSession.CipherSuite, _handshakeSession.ConnectionState);
                        _recordHandler.ChangeRemoteState();

                        continue;
                    }

                    if (record.Type == RecordType.Handshake)
                    {
                        finishedReceived = true;
                        HandshakeMessage[] handshakeMessages = _handshakePacketizer.ProcessHandshakeRecord(_handshakeSession.NegotiatedVersion, record);
                        foreach (HandshakeMessage hsm in handshakeMessages)
                        {
                            if (hsm.Type != HandshakeMessageType.Finished)
                            {
                                throw new AlertException(AlertDescription.UnexpectedMessage, "Finished handshake message was expected");
                            }

                            logger?.Debug("Received Handshake message {0}", hsm.Type);
                            _handshakeSession.ProcessMessage(hsm);
                        }
                    }

                    if (changeCipherSpecReceived && finishedReceived)
                    {
                        return;
                    }
                }
            }

            throw new TimeoutException("ReceiveAsync change cipher spec timed out");
        }
예제 #3
0
        public bool ReadPacket(Stream stream)
        {
            byte[] header    = new byte[5];
            int    readBytes = 0;

            while (readBytes < header.Length)
            {
                readBytes += stream.Read(header, readBytes, header.Length - readBytes);
            }

            Record record = new Record(header);

            readBytes = 0;
            while (readBytes < record.Fragment.Length)
            {
                readBytes += stream.Read(record.Fragment, readBytes, record.Fragment.Length - readBytes);
            }

            _recordHandler.ProcessInputRecord(record);

            if (record.Type == 22)
            {
                HandshakeMessage hs = HandshakeMessage.GetInstance(VERSION, record.Fragment);
                if (hs == null)
                {
                    Console.WriteLine("Skipped handling packet");
                    return(true);
                }

                Console.WriteLine("adding bytes to hash " + record.Fragment.Length);
                _handshakeStream.Write(record.Fragment, 0, record.Fragment.Length);

                if (hs.Type == HandshakeMessageType.ServerHello)
                {
                    HandshakeServerHello sh = (HandshakeServerHello)hs;
                    _serverRandom = sh.Random.GetBytes();
                    if (sh.ServerVersion != VERSION)
                    {
                        throw new Exception("Version doesn't match");
                    }
                }
                else if (hs.Type == HandshakeMessageType.Certificate)
                {
                    Console.WriteLine("Found certificate");
                    HandshakeCertificate cert = (HandshakeCertificate)hs;

                    _rsaPublicKey = null;
                    foreach (X509Certificate c in cert.CertificateList)
                    {
                        Console.WriteLine(c.ToString(true));

                        if (_rsaPublicKey == null)
                        {
                            X509Certificate c2 = new X509Certificate(c);
                            _rsaPublicKey = new CertificatePublicKey(c2);
                        }
                    }
                }
                else if (hs.Type == HandshakeMessageType.ServerHelloDone)
                {
                    SendClientKey(stream);

                    byte[] seed = new byte[64];
                    Array.Copy(_clientRandom, 0, seed, 0, 32);
                    Array.Copy(_serverRandom, 0, seed, 32, 32);
                    PrintBytes("hash seed", seed);

                    _masterSecret = _cipherSuite.KeyExchangeAlgorithm.GetMasterSecret(_cipherSuite.PseudoRandomFunction, seed);
                    PrintBytes("master secret", _masterSecret);

                    seed = new byte[64];
                    Array.Copy(_serverRandom, 0, seed, 0, 32);
                    Array.Copy(_clientRandom, 0, seed, 32, 32);

                    ConnectionState connectionState = new ConnectionState(_clientRandom, _serverRandom, _masterSecret);
                    _recordHandler.SetCipherSuite(_cipherSuite, connectionState);

                    SendFinished(stream);
                }
                else if (hs.Type == HandshakeMessageType.Finished)
                {
                    Console.WriteLine("Got Finished message!!!");
                    SendHttpGet(stream);
                }
            }
            else if (record.Type == 20)
            {
                Console.WriteLine("Got change cipher spec from server");
                _recordHandler.ChangeRemoteState();
            }
            else if (record.Type == 21)
            {
                // This is an alert
                if (record.Fragment.Length >= 2 && record.Fragment[1] == 0)
                {
                    // Close notify
                    Console.WriteLine("Close notify received");
                    return(false);
                }
            }
            else if (record.Type == 23)
            {
                Console.WriteLine("Got data: " + Encoding.UTF8.GetString(record.Fragment));
            }

            return(true);
        }