public override void Dispose() { HandshakeHash?.Dispose(); KeySchedule?.Dispose(); KeyShare?.Dispose(); ReadKey?.Dispose(); WriteKey?.Dispose(); GC.SuppressFinalize(this); }
private unsafe void GenerateServerApplicationKey() { var hash = stackalloc byte[HandshakeHash.HashSize]; var span = new Span <byte>(hash, HandshakeHash.HashSize); HandshakeHash.InterimHash(hash, HandshakeHash.HashSize); KeySchedule.GenerateMasterSecret(span); Console.WriteLine("Application Write Key"); _writeKey?.Dispose(); _writeKey = KeySchedule.GenerateServerApplicationKey(); }
public override void HandleAlertMessage(ReadableBuffer messageBuffer) { var level = messageBuffer.ReadBigEndian <Alerts.AlertLevel>(); messageBuffer = messageBuffer.Slice(sizeof(Alerts.AlertLevel)); var description = messageBuffer.ReadBigEndian <Alerts.AlertDescription>(); if (level == Alerts.AlertLevel.Warning && description == Alerts.AlertDescription.end_of_early_data && State == StateType.WaitEarlyDataFinished) { //0RTT data finished so we switch the reader key to the handshake key and wait for //the client to send it's finish message _readKey?.Dispose(); _readKey = KeySchedule.GenerateClientHandshakeKey(); ChangeState(StateType.WaitClientFinished); return; } Alerts.AlertException.ThrowAlert(level, description, "Alert from the client"); }
private unsafe void GenerateHandshakeKeys() { if (KeySchedule == null) { KeySchedule = Listener.KeyScheduleProvider.GetKeySchedule(this); } KeySchedule.SetDheDerivedValue(KeyShare); var hash = stackalloc byte[HandshakeHash.HashSize]; var span = new Span <byte>(hash, HandshakeHash.HashSize); HandshakeHash.InterimHash(hash, HandshakeHash.HashSize); KeySchedule.GenerateHandshakeTrafficSecrets(span); _writeKey = KeySchedule.GenerateServerHandshakeKey(); if (PskIdentity == -1 || !EarlyDataSupported) { _readKey?.Dispose(); _readKey = KeySchedule.GenerateClientHandshakeKey(); } }
public async Task HandleHandshakeMessage(HandshakeType handshakeMessageType, ReadableBuffer buffer, IPipelineWriter pipe) { switch (State) { case StateType.WaitServerHello: if (handshakeMessageType == HandshakeType.server_hello) { Hello.ReadServerHello(buffer, this); GenerateHandshakeKeys(); State = StateType.WaitEncryptedExtensions; return; } break; case StateType.WaitEncryptedExtensions: if (handshakeMessageType == HandshakeType.encrypted_extensions) { HandshakeContext(buffer); State = StateType.WaitServerVerification; return; } break; case StateType.WaitServerVerification: if (handshakeMessageType == HandshakeType.certificate) { Handshake.Certificates.ReadCertificates(buffer, Listener); HandshakeContext(buffer); return; } if (handshakeMessageType == HandshakeType.certificate_verify) { HandshakeContext(buffer); State = StateType.WaitServerFinished; return; } break; case StateType.WaitServerFinished: if (handshakeMessageType == HandshakeType.finished) { HandshakeContext(buffer); var hash = new byte[HandshakeHash.HashSize]; HandshakeHash.InterimHash(hash); var writer = pipe.Alloc(); ServerHandshakeTls13.ServerFinished(ref writer, this, KeySchedule.GenerateClientFinishedKey()); _dataForCurrentScheduleSent.Reset(); await writer.FlushAsync(); await _dataForCurrentScheduleSent; GenerateApplicationKeys(hash); KeySchedule.GenerateResumptionSecret(); HandshakeHash.Dispose(); HandshakeHash = null; State = StateType.HandshakeComplete; return; } break; case StateType.HandshakeComplete: if (handshakeMessageType == HandshakeType.new_session_ticket) { Listener.ResumptionProvider.RegisterSessionTicket(buffer); return; } break; } Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, ""); }
private unsafe void GenerateApplicationKeys(byte[] hash) { KeySchedule.GenerateMasterSecret(hash); }
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; } }