private void HandleServerKeyExchange(ReadableBuffer messageBuffer) { HandshakeHash.HashData(messageBuffer); var parser = new ServerKeyExchangeParser(messageBuffer); _signatureScheme = parser.SignatureScheme; _certificate.CheckSignature(_cryptoProvider.HashProvider, _signatureScheme, parser.Signature, parser.Data); KeyExchange.SetPeerKey(parser.Key, _certificate, _signatureScheme); }
private Span<byte> HandleClientKeyExchange(ReadableBuffer messageBuffer) { var span = messageBuffer.ToSpan(); HandshakeHash.HashData(span); span = span.Slice(HandshakeFraming.HeaderSize); KeyExchange.SetPeerKey(new BigEndianAdvancingSpan(span), _certificate, _signatureScheme); _secretSchedule.GenerateMasterSecret(dispose: true); _state = HandshakeState.WaitingForChangeCipherSpec; return span; }
private void HandleServerCertificate(ReadableBuffer messageBuffer) { HandshakeHash.HashData(messageBuffer); _certificate = Connection.Listener.CertificateList.CheckCertificate(messageBuffer); KeyExchange.SetCertificate(_certificate); if (KeyExchange.RequiresServerKeyExchange) { _state = HandshakeState.WaitingForServerKeyExchange; } else { _state = HandshakeState.WaitingForServerHelloDone; } }
private void HandleServerHello(ReadableBuffer messageBuffer) { var helloParser = new ServerHelloParser(messageBuffer, Connection); var version = GetVersion(ref helloParser); if (version != TlsVersion.Tls12) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.protocol_version, "Invalid protocol version"); } _secretSchedule.SetServerRandom(helloParser.ServerRandom); CipherSuite = _cryptoProvider.CipherSuites.GetCipherSuite(TlsVersion.Tls12, helloParser.CipherSuite); KeyExchange = _cryptoProvider.KeyExchangeProvider.GetKeyExchange(CipherSuite.KeyExchange, new BigEndianAdvancingSpan(helloParser.SupportedGroups)); var oldHash = HandshakeHash; HandshakeHash = _cryptoProvider.HashProvider.GetHash(CipherSuite.HashType); HandshakeHash.HashData(((HashBuffer)oldHash).GetBufferedData()); HandshakeHash.HashData(helloParser.OriginalMessage); _state = HandshakeState.WaitingForServerCertificate; }
private void SecondFlight(ReadableBuffer messageBuffer) { HandshakeHash.HashData(messageBuffer); if (messageBuffer.Length < 4) { throw new NotImplementedException(); } // send second flight var sendSize = KeyExchange.ClientSendSize; _secretSchedule.GenerateMasterSecret(false); this.WriteHandshakeFrame(sendSize, KeyExchange.ClientSendKey, HandshakeType.client_key_exchange); RecordHandler.WriteRecords(Connection.HandshakeOutput.Reader, RecordType.Handshake); WriteChangeCipherSpec(); (_writeKey, _storedKey) = _secretSchedule.GenerateKeys(); _state = HandshakeState.WaitingForClientFinished; this.WriteHandshakeFrame(_secretSchedule.ClientVerifySize, WriteClientVerify, HandshakeType.finished); RecordHandler.WriteRecords(Connection.HandshakeOutput.Reader, RecordType.Handshake); _state = HandshakeState.WaitingForChangeCipherSpec; }
public bool HandleClientHello(ref ClientHelloParser clientHello) { CipherSuite = _cryptoProvider.CipherSuites.GetCipherSuite(TlsVersion.Tls12, clientHello.CipherSuites); HandshakeHash = _cryptoProvider.HashProvider.GetHash(CipherSuite.HashType); HandshakeHash.HashData(clientHello.OriginalMessage); _certificate = Connection.Listener.CertificateList.GetCertificate(null, CipherSuite.CertificateType.Value); _secretSchedule.SetClientRandom(clientHello.ClientRandom); _negotiatedAlpn = clientHello.NegotiatedAlpn; _hostName = clientHello.HostName; KeyExchange = _cryptoProvider.KeyExchangeProvider.GetKeyExchange(CipherSuite.KeyExchange, clientHello.SupportedGroups); if (_certificate == null) { (_certificate, _signatureScheme) = Connection.Listener.CertificateList.GetCertificate(clientHello.SignatureAlgos); } else { _signatureScheme = _certificate.SelectAlgorithm(clientHello.SignatureAlgos); } if (clientHello.SessionTicket.Length > 0) { ProcessSessionTicket(clientHello.SessionTicket); } if (_abbreviatedHandshake) { SendFirstFlightAbbreviated(clientHello); } else { SendFirstFlightFull(); } return true; }
public void HandshakeContext(ReadableBuffer readable) { HandshakeHash?.HashData(readable); }
public override void HandleHandshakeMessage(HandshakeType handshakeMessageType, ReadableBuffer buffer, ref WritableBuffer outBuffer) { switch (State) { case StateType.None: if (handshakeMessageType != HandshakeType.client_hello) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, "Tls 12 didnt get a client hello"); } Hello.ReadClientHelloTls12(buffer, this); if (CipherSuite == null) { //Couldn't agree a set of ciphers Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.handshake_failure, "Could not agree on a cipher suite during reading client hello"); } this.StartHandshakeHash(buffer); //Write server hello ChangeState(StateType.SendServerHello); _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.server_hello, Hello.SendServerHello12); _frameWriter.FinishFrame(ref outBuffer); _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.certificate, ServerHandshakeTls12.SendCertificates); _frameWriter.FinishFrame(ref outBuffer); if (CipherSuite.ExchangeType == KeyExchangeType.Ecdhe || CipherSuite.ExchangeType == KeyExchangeType.Dhe) { if (KeyShare == null) { KeyShare = CryptoProvider.GetDefaultKeyShare(CipherSuite.ExchangeType); } _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.server_key_exchange, ServerHandshakeTls12.SendKeyExchange); _frameWriter.FinishFrame(ref outBuffer); } _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.server_hello_done, (w, state) => w); _frameWriter.FinishFrame(ref outBuffer); ChangeState(StateType.WaitClientKeyExchange); break; case StateType.WaitClientKeyExchange: if (handshakeMessageType != HandshakeType.client_key_exchange) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"Received a {handshakeMessageType} when we expected a {HandshakeType.client_key_exchange}"); } HandshakeHash.HashData(buffer); KeyShare.SetPeerKey(buffer.Slice(5)); _schedule.GenerateMasterSecret(); _schedule.CalculateClientFinished(); //We can send the server finished because we have the expected client finished _schedule.GenerateKeyMaterial(); ChangeState(StateType.ChangeCipherSpec); break; case StateType.WaitClientFinished: if (handshakeMessageType != HandshakeType.finished) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"unexpected message"); } _schedule.CompareClientFinishedGenerateServerFinished(buffer); _frameWriter.StartFrame(RecordType.ChangeCipherSpec, ref outBuffer); outBuffer.WriteBigEndian <byte>(1); _frameWriter.FinishFrame(ref outBuffer); _writeKey = _schedule.GetServerKey(); _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.finished, _schedule.WriteServerFinished); _frameWriter.FinishFrame(ref outBuffer); KeyShare?.Dispose(); KeyShare = null; ChangeState(StateType.HandshakeComplete); break; default: Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"Not in any known state {State} that we expected a handshake messge from {handshakeMessageType}"); break; } }
public override async Task HandleHandshakeMessage(HandshakeType handshakeMessageType, ReadableBuffer buffer, IPipelineWriter pipe) { WritableBuffer writer; switch (State) { case StateType.None: case StateType.WaitHelloRetry: if (handshakeMessageType != HandshakeType.client_hello) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"State is wait hello retry but got {handshakeMessageType}"); } Hello.ReadClientHelloTls13(buffer, this); if (CipherSuite == null) { //Couldn't agree a set of ciphers Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.handshake_failure, "Could not agree on a cipher suite during reading client hello"); } this.StartHandshakeHash(buffer); //If we can't agree on a schedule we will have to send a hello retry and try again if (!NegotiationComplete()) { writer = pipe.Alloc(); this.WriteHandshake(ref writer, HandshakeType.hello_retry_request, Hello.SendHelloRetry); _state = StateType.WaitHelloRetry; await writer.FlushAsync(); return; } if (PskIdentity != -1 && EarlyDataSupported) { KeySchedule.GenerateEarlyTrafficKey(ref _readKey); Console.WriteLine("Generated Early Traffic Key"); } //Write the server hello, the last of the unencrypted messages _state = StateType.SendServerHello; writer = pipe.Alloc(); this.WriteHandshake(ref writer, HandshakeType.server_hello, Hello.SendServerHello13); //block our next actions because we need to have sent the message before changing keys DataForCurrentScheduleSent.Reset(); await writer.FlushAsync(); await DataForCurrentScheduleSent; _state = StateType.ServerAuthentication; //Generate the encryption keys and send the next set of messages GenerateHandshakeKeys(); writer = pipe.Alloc(); ServerHandshakeTls13.SendFlightOne(ref writer, this); ServerHandshakeTls13.SendFlightOne2(ref writer, this); DataForCurrentScheduleSent.Reset(); await writer.FlushAsync(); await DataForCurrentScheduleSent; writer = pipe.Alloc(); ServerHandshakeTls13.SendFlightOne3(ref writer, this); ServerHandshakeTls13.ServerFinished(ref writer, this, KeySchedule.GenerateServerFinishKey()); DataForCurrentScheduleSent.Reset(); await writer.FlushAsync(); await DataForCurrentScheduleSent; GenerateServerApplicationKey(); if (EarlyDataSupported && PskIdentity != -1) { _state = StateType.WaitEarlyDataFinished; } else { _state = StateType.WaitClientFinished; } return; case StateType.WaitClientFinished: if (handshakeMessageType != HandshakeType.finished) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"Waiting for client finished but received {handshakeMessageType}"); } Finished.ReadClientFinished(buffer, this); _readKey?.Dispose(); _readKey = KeySchedule.GenerateClientApplicationKey(); //Hash the finish message now we have made the traffic keys //Then we can make the resumption secret HandshakeHash.HashData(buffer); KeySchedule.GenerateResumptionSecret(); HandshakeHash.Dispose(); HandshakeHash = null; //Send a new session ticket writer = pipe.Alloc(); this.WriteHandshake(ref writer, HandshakeType.new_session_ticket, SessionKeys.CreateNewSessionKey); await writer.FlushAsync(); _state = StateType.HandshakeComplete; break; default: Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"Not in any known state {State} that we expected a handshake messge from {handshakeMessageType}"); break; } }