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); }
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"); }
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); }