public override void HandleChangeCipherSpec(ReadableBuffer readable) { if (State != StateType.ChangeCipherSpec) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, ""); } _readKey = _schedule.GetClientKey(); ChangeState(StateType.WaitClientFinished); }
public void GenerateEarlyTrafficKey(ref IBulkCipherInstance earlyDataKey) { var hash = stackalloc byte[_hashSize]; _state.HandshakeHash.InterimHash(hash, _hashSize); var hashSpan = new Span <byte>(hash, _hashSize); HkdfFunctions.ClientEarlyTrafficSecret(CryptoProvider.HashProvider, CipherSuite.HashType, _secret, hashSpan, new Span <byte>(_clientHandshakeTrafficSecret, _hashSize)); earlyDataKey = GetKey(_clientHandshakeTrafficSecret, _hashSize); }
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 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; } }