Exemple #1
0
 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);
 }
Exemple #2
0
        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);
        }
Exemple #3
0
        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();
        }
Exemple #4
0
        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");
        }
Exemple #5
0
        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();
            }
        }
Exemple #6
0
        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;
            }
        }