Пример #1
0
        protected virtual byte[] GenerateClientKeyExchange(ClientHandshakeState state)
        {
            MemoryStream buf = new MemoryStream();

            state.keyExchange.GenerateClientKeyExchange(buf);
            return(buf.ToArray());
        }
Пример #2
0
        protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
        {
            MemoryStream buf = new MemoryStream();

            certificateVerify.Encode(buf);
            return(buf.ToArray());
        }
Пример #3
0
        protected virtual void ProcessServerSupplementalData(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);
            IList        serverSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);

            state.client.ProcessServerSupplementalData(serverSupplementalData);
        }
Пример #4
0
        protected virtual byte[] ProcessHelloVerifyRequest(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);

            byte[] cookie = TlsUtilities.ReadOpaque8(buf);

            TlsProtocol.AssertEmpty(buf);

            // TODO Seems this behaviour is not yet in line with OpenSSL for DTLS 1.2
            //        reportServerVersion(state, server_version);
            if (!server_version.IsEqualOrEarlierVersionOf(state.clientContext.ClientVersion))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            /*
             * RFC 6347 This specification increases the cookie size limit to 255 bytes for greater
             * future flexibility. The limit remains 32 for previous versions of DTLS.
             */
            if (!ProtocolVersion.DTLSv12.IsEqualOrEarlierVersionOf(server_version) && cookie.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            return(cookie);
        }
Пример #5
0
        public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport)
        {
            if (client == null)
            {
                throw new ArgumentNullException("client");
            }
            if (transport == null)
            {
                throw new ArgumentNullException("transport");
            }

            SecurityParameters securityParameters = new SecurityParameters();

            securityParameters.entity = ConnectionEnd.client;

            ClientHandshakeState state = new ClientHandshakeState();

            state.client        = client;
            state.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters);

            securityParameters.clientRandom = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(),
                                                                            state.clientContext.NonceRandomGenerator);

            client.Init(state.clientContext);

            DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake);

            TlsSession sessionToResume = state.client.GetSessionToResume();

            if (sessionToResume != null)
            {
                SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
                if (sessionParameters != null)
                {
                    state.tlsSession        = sessionToResume;
                    state.sessionParameters = sessionParameters;
                }
            }

            try
            {
                return(ClientHandshake(state, recordLayer));
            }
            catch (TlsFatalAlert fatalAlert)
            {
                recordLayer.Fail(fatalAlert.AlertDescription);
                throw fatalAlert;
            }
            catch (IOException e)
            {
                recordLayer.Fail(AlertDescription.internal_error);
                throw e;
            }
            catch (Exception e)
            {
                recordLayer.Fail(AlertDescription.internal_error);
                throw new TlsFatalAlert(AlertDescription.internal_error, e);
            }
        }
Пример #6
0
        protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            state.keyExchange.ProcessServerKeyExchange(buf);

            TlsProtocol.AssertEmpty(buf);
        }
Пример #7
0
        protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
        {
            //IL_0002: Unknown result type (might be due to invalid IL or missing references)
            //IL_0008: Expected O, but got Unknown
            MemoryStream val = new MemoryStream(body, false);

            state.keyExchange.ProcessServerKeyExchange((Stream)(object)val);
            TlsProtocol.AssertEmpty(val);
        }
        protected override byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
        {
            if (certificateVerify.Algorithm != null && config.clientAuthSigAlgClaimed != null)
            {
                certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.Signature);
            }

            return base.GenerateCertificateVerify(state, certificateVerify);
        }
Пример #9
0
        protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
        {
            //IL_0000: Unknown result type (might be due to invalid IL or missing references)
            //IL_0006: Expected O, but got Unknown
            MemoryStream val = new MemoryStream();

            certificateVerify.Encode((Stream)(object)val);
            return(val.ToArray());
        }
Пример #10
0
        protected virtual byte[] GenerateClientKeyExchange(ClientHandshakeState state)
        {
            //IL_0000: Unknown result type (might be due to invalid IL or missing references)
            //IL_0006: Expected O, but got Unknown
            MemoryStream val = new MemoryStream();

            state.keyExchange.GenerateClientKeyExchange((Stream)(object)val);
            return(val.ToArray());
        }
Пример #11
0
        protected virtual void ProcessServerSupplementalData(ClientHandshakeState state, byte[] body)
        {
            //IL_0002: Unknown result type (might be due to invalid IL or missing references)
            //IL_0008: Expected O, but got Unknown
            MemoryStream input = new MemoryStream(body, false);

            global::System.Collections.IList serverSupplementalData = TlsProtocol.ReadSupplementalDataMessage(input);
            state.client.ProcessServerSupplementalData(serverSupplementalData);
        }
        protected override byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
        {
            if (certificateVerify.Algorithm != null && config.clientAuthSigAlgClaimed != null)
            {
                certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.Signature);
            }

            return(base.GenerateCertificateVerify(state, certificateVerify));
        }
Пример #13
0
        public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport)
        {
            if (client == null)
                throw new ArgumentNullException("client");
            if (transport == null)
                throw new ArgumentNullException("transport");

            SecurityParameters securityParameters = new SecurityParameters();
            securityParameters.entity = ConnectionEnd.client;

            ClientHandshakeState state = new ClientHandshakeState();
            state.client = client;
            state.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters);

            securityParameters.clientRandom = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(),
                state.clientContext.NonceRandomGenerator);

            client.Init(state.clientContext);

            DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake);

            TlsSession sessionToResume = state.client.GetSessionToResume();
            if (sessionToResume != null && sessionToResume.IsResumable)
            {
                SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
                if (sessionParameters != null)
                {
                    state.tlsSession = sessionToResume;
                    state.sessionParameters = sessionParameters;
                }
            }

            try
            {
                return ClientHandshake(state, recordLayer);
            }
            catch (TlsFatalAlert fatalAlert)
            {
                AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription);
                throw fatalAlert;
            }
            catch (IOException e)
            {
                AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
                throw e;
            }
            catch (Exception e)
            {
                AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
                throw new TlsFatalAlert(AlertDescription.internal_error, e);
            }
            finally
            {
                securityParameters.Clear();
            }
        }
Пример #14
0
        protected virtual void ProcessNewSessionTicket(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            state.client.NotifyNewSessionTicket(newSessionTicket);
        }
Пример #15
0
        protected virtual void ProcessNewSessionTicket(ClientHandshakeState state, byte[] body)
        {
            //IL_0002: Unknown result type (might be due to invalid IL or missing references)
            //IL_0008: Expected O, but got Unknown
            MemoryStream     val = new MemoryStream(body, false);
            NewSessionTicket newSessionTicket = NewSessionTicket.Parse((Stream)(object)val);

            TlsProtocol.AssertEmpty(val);
            state.client.NotifyNewSessionTicket(newSessionTicket);
        }
Пример #16
0
        public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport)
        {
            //IL_0008: Unknown result type (might be due to invalid IL or missing references)
            //IL_0016: Unknown result type (might be due to invalid IL or missing references)
            //IL_00d2: Expected O, but got Unknown
            if (client == null)
            {
                throw new ArgumentNullException("client");
            }
            if (transport == null)
            {
                throw new ArgumentNullException("transport");
            }
            SecurityParameters securityParameters = new SecurityParameters();

            securityParameters.entity = 1;
            ClientHandshakeState clientHandshakeState = new ClientHandshakeState();

            clientHandshakeState.client        = client;
            clientHandshakeState.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters);
            securityParameters.clientRandom    = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(), clientHandshakeState.clientContext.NonceRandomGenerator);
            client.Init(clientHandshakeState.clientContext);
            DtlsRecordLayer dtlsRecordLayer = new DtlsRecordLayer(transport, clientHandshakeState.clientContext, client, 22);
            TlsSession      sessionToResume = clientHandshakeState.client.GetSessionToResume();

            if (sessionToResume != null && sessionToResume.IsResumable)
            {
                SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
                if (sessionParameters != null)
                {
                    clientHandshakeState.tlsSession        = sessionToResume;
                    clientHandshakeState.sessionParameters = sessionParameters;
                }
            }
            try
            {
                return(ClientHandshake(clientHandshakeState, dtlsRecordLayer));
            }
            catch (TlsFatalAlert tlsFatalAlert)
            {
                dtlsRecordLayer.Fail(tlsFatalAlert.AlertDescription);
                throw tlsFatalAlert;
            }
            catch (IOException val)
            {
                IOException val2 = val;
                dtlsRecordLayer.Fail(80);
                throw val2;
            }
            catch (global::System.Exception alertCause)
            {
                dtlsRecordLayer.Fail(80);
                throw new TlsFatalAlert(80, alertCause);
            }
        }
Пример #17
0
        protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
        {
            //IL_0000: Unknown result type (might be due to invalid IL or missing references)
            //IL_0006: Expected O, but got Unknown
            MemoryStream    val           = new MemoryStream();
            ProtocolVersion clientVersion = client.ClientVersion;

            if (!clientVersion.IsDtls)
            {
                throw new TlsFatalAlert(80);
            }
            TlsClientContextImpl clientContext = state.clientContext;

            clientContext.SetClientVersion(clientVersion);
            TlsUtilities.WriteVersion(clientVersion, (Stream)(object)val);
            SecurityParameters securityParameters = clientContext.SecurityParameters;

            ((Stream)val).Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);
            byte[] array = TlsUtilities.EmptyBytes;
            if (state.tlsSession != null)
            {
                array = state.tlsSession.SessionID;
                if (array == null || array.Length > 32)
                {
                    array = TlsUtilities.EmptyBytes;
                }
            }
            TlsUtilities.WriteOpaque8(array, (Stream)(object)val);
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, (Stream)(object)val);
            bool isFallback = client.IsFallback;

            state.offeredCipherSuites = client.GetCipherSuites();
            state.clientExtensions    = client.GetClientExtensions();
            byte[] extensionData = TlsUtilities.GetExtensionData(state.clientExtensions, 65281);
            bool   flag          = null == extensionData;
            bool   flag2         = !Arrays.Contains(state.offeredCipherSuites, 255);

            if (flag && flag2)
            {
                state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, 255);
            }
            if (isFallback && !Arrays.Contains(state.offeredCipherSuites, 22016))
            {
                state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, 22016);
            }
            TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, (Stream)(object)val);
            byte[] array2 = (state.offeredCompressionMethods = new byte[1]);
            TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, (Stream)(object)val);
            if (state.clientExtensions != null)
            {
                TlsProtocol.WriteExtensions((Stream)(object)val, state.clientExtensions);
            }
            return(val.ToArray());
        }
Пример #18
0
 protected virtual void InvalidateSession(ClientHandshakeState state)
 {
     if (state.sessionParameters != null)
     {
         state.sessionParameters.Clear();
         state.sessionParameters = null;
     }
     if (state.tlsSession != null)
     {
         state.tlsSession.Invalidate();
         state.tlsSession = null;
     }
 }
Пример #19
0
        protected virtual Certificate ProcessServerCertificate(ClientHandshakeState state, byte[] body)
        {
            //IL_0002: Unknown result type (might be due to invalid IL or missing references)
            //IL_0008: Expected O, but got Unknown
            MemoryStream val         = new MemoryStream(body, false);
            Certificate  certificate = Certificate.Parse((Stream)(object)val);

            TlsProtocol.AssertEmpty(val);
            state.keyExchange.ProcessServerCertificate(certificate);
            state.authentication = state.client.GetAuthentication();
            state.authentication.NotifyServerCertificate(certificate);
            return(certificate);
        }
Пример #20
0
        protected virtual void ProcessCertificateStatus(ClientHandshakeState state, byte[] body)
        {
            //IL_0012: Unknown result type (might be due to invalid IL or missing references)
            //IL_0018: Expected O, but got Unknown
            if (!state.allowCertificateStatus)
            {
                throw new TlsFatalAlert(10);
            }
            MemoryStream val = new MemoryStream(body, false);

            state.certificateStatus = CertificateStatus.Parse((Stream)(object)val);
            TlsProtocol.AssertEmpty(val);
        }
Пример #21
0
        protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
        {
            //IL_0012: Unknown result type (might be due to invalid IL or missing references)
            //IL_0018: Expected O, but got Unknown
            if (state.authentication == null)
            {
                throw new TlsFatalAlert(40);
            }
            MemoryStream val = new MemoryStream(body, false);

            state.certificateRequest = CertificateRequest.Parse(state.clientContext, (Stream)(object)val);
            TlsProtocol.AssertEmpty(val);
            state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
        }
Пример #22
0
        protected virtual Certificate ProcessServerCertificate(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            Certificate serverCertificate = Certificate.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            state.keyExchange.ProcessServerCertificate(serverCertificate);
            state.authentication = state.client.GetAuthentication();
            state.authentication.NotifyServerCertificate(serverCertificate);

            return(serverCertificate);
        }
Пример #23
0
        protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
        {
            TlsClientContextImpl clientContext        = state.clientContext;
            ProtocolVersion      currentServerVersion = clientContext.ServerVersion;

            if (null == currentServerVersion)
            {
                clientContext.SetServerVersion(server_version);
                state.client.NotifyServerVersion(server_version);
            }
            else if (!currentServerVersion.Equals(server_version))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
        }
Пример #24
0
        protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
        {
            TlsClientContextImpl clientContext = state.clientContext;
            ProtocolVersion      serverVersion = clientContext.ServerVersion;

            if (serverVersion == null)
            {
                clientContext.SetServerVersion(server_version);
                state.client.NotifyServerVersion(server_version);
            }
            else if (!serverVersion.Equals(server_version))
            {
                throw new TlsFatalAlert(47);
            }
        }
Пример #25
0
        protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
        {
            if (state.authentication == null)
            {
                /*
                 * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to
                 * request client identification.
                 */
                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            MemoryStream buf = new MemoryStream(body, false);

            state.certificateRequest = CertificateRequest.Parse(state.clientContext, buf);

            TlsProtocol.AssertEmpty(buf);

            state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
        }
Пример #26
0
        protected virtual byte[] ProcessHelloVerifyRequest(ClientHandshakeState state, byte[] body)
        {
            //IL_0002: Unknown result type (might be due to invalid IL or missing references)
            //IL_0008: Expected O, but got Unknown
            MemoryStream    val             = new MemoryStream(body, false);
            ProtocolVersion protocolVersion = TlsUtilities.ReadVersion((Stream)(object)val);

            byte[] array = TlsUtilities.ReadOpaque8((Stream)(object)val);
            TlsProtocol.AssertEmpty(val);
            if (!protocolVersion.IsEqualOrEarlierVersionOf(state.clientContext.ClientVersion))
            {
                throw new TlsFatalAlert(47);
            }
            if (!ProtocolVersion.DTLSv12.IsEqualOrEarlierVersionOf(protocolVersion) && array.Length > 32)
            {
                throw new TlsFatalAlert(47);
            }
            return(array);
        }
Пример #27
0
        protected virtual void ProcessCertificateStatus(ClientHandshakeState state, byte[] body)
        {
            if (!state.allowCertificateStatus)
            {
                /*
                 * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
                 * server MUST have included an extension of type "status_request" with empty
                 * "extension_data" in the extended server hello..
                 */
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            MemoryStream buf = new MemoryStream(body, false);

            state.certificateStatus = CertificateStatus.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
        }
Пример #28
0
        protected virtual AbstractCertificate ParseServerCertificate(ClientHandshakeState state, Stream stm)
        {
            AbstractCertificate cert = state.client.ParseServerCertificate(state.serverCertificateType, stm);

            if (cert != null)
            {
                return(cert);
            }

            switch (state.serverCertificateType)
            {
            case CertificateType.X509:
                return(Certificate.Parse(stm));

            case CertificateType.RawPublicKey:
                return(RawPublicKey.Parse(stm));

            case CertificateType.CwtPublicKey:
                return(CwtPublicKey.Parse(stm));

            default:
                throw new TlsFatalAlert(AlertDescription.bad_certificate);
            }
        }
        protected virtual void ProcessCertificateStatus(ClientHandshakeState state, byte[] body)
        {
            if (!state.allowCertificateStatus)
            {
                /*
                 * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
                 * server MUST have included an extension of type "status_request" with empty
                 * "extension_data" in the extended server hello..
                 */
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            MemoryStream buf = new MemoryStream(body, false);

            state.certificateStatus = CertificateStatus.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
        }
 protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
 {
     MemoryStream buf = new MemoryStream();
     certificateVerify.Encode(buf);
     return buf.ToArray();
 }
Пример #31
0
        internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer)
        {
            SecurityParameters    securityParameters = state.clientContext.SecurityParameters;
            DtlsReliableHandshake handshake          = new DtlsReliableHandshake(state.clientContext, recordLayer);

            byte[] clientHelloBody = GenerateClientHello(state, state.client);
            handshake.SendMessage(HandshakeType.client_hello, clientHelloBody);

            DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage();

            while (serverMessage.Type == HandshakeType.hello_verify_request)
            {
                ProtocolVersion recordLayerVersion = recordLayer.ResetDiscoveredPeerVersion();
                ProtocolVersion client_version     = state.clientContext.ClientVersion;

                /*
                 * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of
                 * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use
                 * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and
                 * 1.0) and not as part of version negotiation.
                 */
                if (!recordLayerVersion.IsEqualOrEarlierVersionOf(client_version))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                byte[] cookie  = ProcessHelloVerifyRequest(state, serverMessage.Body);
                byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie);

                handshake.ResetHandshakeMessagesDigest();
                handshake.SendMessage(HandshakeType.client_hello, patched);

                serverMessage = handshake.ReceiveMessage();
            }

            if (serverMessage.Type == HandshakeType.server_hello)
            {
                ReportServerVersion(state, recordLayer.DiscoveredPeerVersion);

                ProcessServerHello(state, serverMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            if (state.maxFragmentLength >= 0)
            {
                int plainTextLimit = 1 << (8 + state.maxFragmentLength);
                recordLayer.SetPlaintextLimit(plainTextLimit);
            }

            securityParameters.cipherSuite          = state.selectedCipherSuite;
            securityParameters.compressionAlgorithm = (byte)state.selectedCompressionMethod;
            securityParameters.prfAlgorithm         = TlsProtocol.GetPrfAlgorithm(state.clientContext, state.selectedCipherSuite);

            /*
             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
             * a verify_data_length equal to 12. This includes all existing cipher suites.
             */
            securityParameters.verifyDataLength = 12;

            handshake.NotifyHelloComplete();

            bool resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null &&
                                  Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);

            if (resumedSession)
            {
                if (securityParameters.CipherSuite != state.sessionParameters.CipherSuite ||
                    securityParameters.CompressionAlgorithm != state.sessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                IDictionary sessionServerExtensions = state.sessionParameters.ReadServerExtensions();

                securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);

                securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret);
                recordLayer.InitPendingEpoch(state.client.GetCipher());

                // NOTE: Calculated exclusive of the actual Finished message from the server
                byte[] resExpectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
                                                                                      TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
                ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), resExpectedServerVerifyData);

                // NOTE: Calculated exclusive of the Finished message itself
                byte[] resClientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
                                                                              TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
                handshake.SendMessage(HandshakeType.finished, resClientVerifyData);

                handshake.Finish();

                state.clientContext.SetResumableSession(state.tlsSession);

                state.client.NotifyHandshakeComplete();

                return(new DtlsTransport(recordLayer));
            }

            InvalidateSession(state);

            if (state.selectedSessionID.Length > 0)
            {
                state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null);
            }

            serverMessage = handshake.ReceiveMessage();

            if (serverMessage.Type == HandshakeType.supplemental_data)
            {
                ProcessServerSupplementalData(state, serverMessage.Body);
                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                state.client.ProcessServerSupplementalData(null);
            }

            state.keyExchange = state.client.GetKeyExchange();
            state.keyExchange.Init(state.clientContext);

            Certificate serverCertificate = null;

            if (serverMessage.Type == HandshakeType.certificate)
            {
                serverCertificate = ProcessServerCertificate(state, serverMessage.Body);
                serverMessage     = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, Certificate is optional
                state.keyExchange.SkipServerCredentials();
            }

            // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
            if (serverCertificate == null || serverCertificate.IsEmpty)
            {
                state.allowCertificateStatus = false;
            }

            if (serverMessage.Type == HandshakeType.certificate_status)
            {
                ProcessCertificateStatus(state, serverMessage.Body);
                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, CertificateStatus is optional
            }

            if (serverMessage.Type == HandshakeType.server_key_exchange)
            {
                ProcessServerKeyExchange(state, serverMessage.Body);
                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, ServerKeyExchange is optional
                state.keyExchange.SkipServerKeyExchange();
            }

            if (serverMessage.Type == HandshakeType.certificate_request)
            {
                ProcessCertificateRequest(state, serverMessage.Body);

                /*
                 * TODO Give the client a chance to immediately select the CertificateVerify hash
                 * algorithm here to avoid tracking the other hash algorithms unnecessarily?
                 */
                TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
                                                 state.certificateRequest.SupportedSignatureAlgorithms);

                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, CertificateRequest is optional
            }

            if (serverMessage.Type == HandshakeType.server_hello_done)
            {
                if (serverMessage.Body.Length != 0)
                {
                    throw new TlsFatalAlert(AlertDescription.decode_error);
                }
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            handshake.HandshakeHash.SealHashAlgorithms();

            IList clientSupplementalData = state.client.GetClientSupplementalData();

            if (clientSupplementalData != null)
            {
                byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
                handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
            }

            if (state.certificateRequest != null)
            {
                state.clientCredentials = state.authentication.GetClientCredentials(state.certificateRequest);

                /*
                 * RFC 5246 If no suitable certificate is available, the client MUST send a certificate
                 * message containing no certificates.
                 *
                 * NOTE: In previous RFCs, this was SHOULD instead of MUST.
                 */
                Certificate clientCertificate = null;
                if (state.clientCredentials != null)
                {
                    clientCertificate = state.clientCredentials.Certificate;
                }
                if (clientCertificate == null)
                {
                    clientCertificate = Certificate.EmptyChain;
                }

                byte[] certificateBody = GenerateCertificate(clientCertificate);
                handshake.SendMessage(HandshakeType.certificate, certificateBody);
            }

            if (state.clientCredentials != null)
            {
                state.keyExchange.ProcessClientCredentials(state.clientCredentials);
            }
            else
            {
                state.keyExchange.SkipClientCredentials();
            }

            byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state);
            handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody);

            TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();

            securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, prepareFinishHash, null);

            TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange);
            recordLayer.InitPendingEpoch(state.client.GetCipher());

            if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials)
            {
                TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials;

                /*
                 * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
                 */
                SignatureAndHashAlgorithm signatureAndHashAlgorithm;
                byte[] hash;

                if (TlsUtilities.IsTlsV12(state.clientContext))
                {
                    signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm;
                    if (signatureAndHashAlgorithm == null)
                    {
                        throw new TlsFatalAlert(AlertDescription.internal_error);
                    }

                    hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
                }
                else
                {
                    signatureAndHashAlgorithm = null;
                    hash = securityParameters.SessionHash;
                }

                byte[]          signature             = signerCredentials.GenerateCertificateSignature(hash);
                DigitallySigned certificateVerify     = new DigitallySigned(signatureAndHashAlgorithm, signature);
                byte[]          certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
                handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
            }

            // NOTE: Calculated exclusive of the Finished message itself
            byte[] clientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
                                                                       TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
            handshake.SendMessage(HandshakeType.finished, clientVerifyData);

            if (state.expectSessionTicket)
            {
                serverMessage = handshake.ReceiveMessage();
                if (serverMessage.Type == HandshakeType.session_ticket)
                {
                    ProcessNewSessionTicket(state, serverMessage.Body);
                }
                else
                {
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
            }

            // NOTE: Calculated exclusive of the actual Finished message from the server
            byte[] expectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
                                                                               TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
            ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedServerVerifyData);

            handshake.Finish();

            if (state.tlsSession != null)
            {
                state.sessionParameters = new SessionParameters.Builder()
                                          .SetCipherSuite(securityParameters.cipherSuite)
                                          .SetCompressionAlgorithm(securityParameters.compressionAlgorithm)
                                          .SetMasterSecret(securityParameters.masterSecret)
                                          .SetPeerCertificate(serverCertificate)
                                          .SetPskIdentity(securityParameters.pskIdentity)
                                          .Build();

                state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);

                state.clientContext.SetResumableSession(state.tlsSession);
            }

            state.client.NotifyHandshakeComplete();

            return(new DtlsTransport(recordLayer));
        }
 protected virtual byte[] GenerateClientKeyExchange(ClientHandshakeState state)
 {
     MemoryStream buf = new MemoryStream();
     state.keyExchange.GenerateClientKeyExchange(buf);
     return buf.ToArray();
 }
        protected virtual Certificate ProcessServerCertificate(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            Certificate serverCertificate = Certificate.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            state.keyExchange.ProcessServerCertificate(serverCertificate);
            state.authentication = state.client.GetAuthentication();
            state.authentication.NotifyServerCertificate(serverCertificate);

            return serverCertificate;
        }
        protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body)
        {
            SecurityParameters securityParameters = state.clientContext.SecurityParameters;

            MemoryStream buf = new MemoryStream(body, false);

            {
                ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
                ReportServerVersion(state, server_version);
            }

            securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);

            state.selectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (state.selectedSessionID.Length > 32)
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            state.client.NotifySessionID(state.selectedSessionID);
            state.resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null
                && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);

            int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
            if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
                || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
                || CipherSuite.IsScsv(selectedCipherSuite)
                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.clientContext.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.illegal_parameter);
            state.client.NotifySelectedCipherSuite(selectedCipherSuite);

            byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
            if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);

            /*
             * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
             * hello message when the client has requested extended functionality via the extended
             * client hello message specified in Section 2.1. ... Note that the extended server hello
             * message is only sent in response to an extended client hello message. This prevents the
             * possibility that the extended server hello message could "break" existing TLS 1.0
             * clients.
             */

            /*
             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
             * extensions appearing in the client hello, and send a server hello containing no
             * extensions.
             */

            // Integer -> byte[]
            state.serverExtensions = TlsProtocol.ReadExtensions(buf);

            /*
             * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
             * extended client hello message. However, see RFC 5746 exception below. We always include
             * the SCSV, so an Extended Server Hello is always allowed.
             */
            if (state.serverExtensions != null)
            {
                foreach (int extType in state.serverExtensions.Keys)
                {
                    /*
                     * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
                     * ClientHello containing only the SCSV is an explicit exception to the prohibition
                     * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is
                     * only allowed because the client is signaling its willingness to receive the
                     * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
                     */
                    if (extType == ExtensionType.renegotiation_info)
                        continue;

                    /*
                     * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
                     * same extension type appeared in the corresponding ClientHello. If a client
                     * receives an extension type in ServerHello that it did not request in the
                     * associated ClientHello, it MUST abort the handshake with an unsupported_extension
                     * fatal alert.
                     */
                    if (null == TlsUtilities.GetExtensionData(state.clientExtensions, extType))
                        throw new TlsFatalAlert(AlertDescription.unsupported_extension);

                    /*
                     * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
                     * extensions appearing in the client hello, and send a server hello containing no
                     * extensions[.]
                     */
                    if (state.resumedSession)
                    {
                        // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
                        // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
                        // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
                        //throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }
                }
            }

            /*
             * RFC 5746 3.4. Client Behavior: Initial Handshake
             */
            {
                /*
                 * When a ServerHello is received, the client MUST check if it includes the
                 * "renegotiation_info" extension:
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                        * If the extension is present, set the secure_renegotiation flag to TRUE. The
                        * client MUST then verify that the length of the "renegotiated_connection"
                        * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
                        * handshake_failure alert).
                        */
                    state.secure_renegotiation = true;

                    if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                }
            }

            // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
            state.client.NotifySecureRenegotiation(state.secure_renegotiation);

            IDictionary sessionClientExtensions = state.clientExtensions, sessionServerExtensions = state.serverExtensions;
            if (state.resumedSession)
            {
                if (selectedCipherSuite != state.sessionParameters.CipherSuite
                    || selectedCompressionMethod != state.sessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                sessionClientExtensions = null;
                sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
            }

            securityParameters.cipherSuite = selectedCipherSuite;
            securityParameters.compressionAlgorithm = selectedCompressionMethod;

            if (sessionServerExtensions != null)
            {
                {
                    /*
                     * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
                     * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
                     * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
                     * client.
                     */
                    bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
                    if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(securityParameters.CipherSuite))
                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    securityParameters.encryptThenMac = serverSentEncryptThenMAC;
                }

                securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);

                securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
                    sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);

                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be
                 * sent in a session resumption handshake.
                 */
                state.allowCertificateStatus = !state.resumedSession
                    && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
                        AlertDescription.illegal_parameter);

                state.expectSessionTicket = !state.resumedSession
                    && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
                        AlertDescription.illegal_parameter);
            }

            /*
             * TODO[session-hash]
             * 
             * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
             * that do not use the extended master secret [..]. (and see 5.2, 5.3)
             */

            if (sessionClientExtensions != null)
            {
                state.client.ProcessServerExtensions(sessionServerExtensions);
            }

            securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext,
                securityParameters.CipherSuite);

            /*
             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
             * a verify_data_length equal to 12. This includes all existing cipher suites.
             */
            securityParameters.verifyDataLength = 12;
        }
        internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer)
        {
            SecurityParameters securityParameters = state.clientContext.SecurityParameters;
            DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.clientContext, recordLayer);

            byte[] clientHelloBody = GenerateClientHello(state, state.client);
            handshake.SendMessage(HandshakeType.client_hello, clientHelloBody);

            DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage();

            while (serverMessage.Type == HandshakeType.hello_verify_request)
            {
                ProtocolVersion recordLayerVersion = recordLayer.ResetDiscoveredPeerVersion();
                ProtocolVersion client_version = state.clientContext.ClientVersion;

                /*
                 * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of
                 * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use
                 * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and
                 * 1.0) and not as part of version negotiation.
                 */
                if (!recordLayerVersion.IsEqualOrEarlierVersionOf(client_version))
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);

                byte[] cookie = ProcessHelloVerifyRequest(state, serverMessage.Body);
                byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie);

                handshake.ResetHandshakeMessagesDigest();
                handshake.SendMessage(HandshakeType.client_hello, patched);

                serverMessage = handshake.ReceiveMessage();
            }

            if (serverMessage.Type == HandshakeType.server_hello)
            {
                ReportServerVersion(state, recordLayer.DiscoveredPeerVersion);

                ProcessServerHello(state, serverMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            handshake.NotifyHelloComplete();

            ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);

            if (state.resumedSession)
            {
                securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret);
                recordLayer.InitPendingEpoch(state.client.GetCipher());

                // NOTE: Calculated exclusive of the actual Finished message from the server
                byte[] resExpectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
                    TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
                ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), resExpectedServerVerifyData);

                // NOTE: Calculated exclusive of the Finished message itself
                byte[] resClientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
                    TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
                handshake.SendMessage(HandshakeType.finished, resClientVerifyData);

                handshake.Finish();

                state.clientContext.SetResumableSession(state.tlsSession);

                state.client.NotifyHandshakeComplete();

                return new DtlsTransport(recordLayer);
            }

            InvalidateSession(state);

            if (state.selectedSessionID.Length > 0)
            {
                state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null);
            }

            serverMessage = handshake.ReceiveMessage();

            if (serverMessage.Type == HandshakeType.supplemental_data)
            {
                ProcessServerSupplementalData(state, serverMessage.Body);
                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                state.client.ProcessServerSupplementalData(null);
            }

            state.keyExchange = state.client.GetKeyExchange();
            state.keyExchange.Init(state.clientContext);

            Certificate serverCertificate = null;

            if (serverMessage.Type == HandshakeType.certificate)
            {
                serverCertificate = ProcessServerCertificate(state, serverMessage.Body);
                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, Certificate is optional
                state.keyExchange.SkipServerCredentials();
            }

            // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
            if (serverCertificate == null || serverCertificate.IsEmpty)
            {
                state.allowCertificateStatus = false;
            }

            if (serverMessage.Type == HandshakeType.certificate_status)
            {
                ProcessCertificateStatus(state, serverMessage.Body);
                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, CertificateStatus is optional
            }

            if (serverMessage.Type == HandshakeType.server_key_exchange)
            {
                ProcessServerKeyExchange(state, serverMessage.Body);
                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, ServerKeyExchange is optional
                state.keyExchange.SkipServerKeyExchange();
            }

            if (serverMessage.Type == HandshakeType.certificate_request)
            {
                ProcessCertificateRequest(state, serverMessage.Body);

                /*
                 * TODO Give the client a chance to immediately select the CertificateVerify hash
                 * algorithm here to avoid tracking the other hash algorithms unnecessarily?
                 */
                TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
                    state.certificateRequest.SupportedSignatureAlgorithms);

                serverMessage = handshake.ReceiveMessage();
            }
            else
            {
                // Okay, CertificateRequest is optional
            }

            if (serverMessage.Type == HandshakeType.server_hello_done)
            {
                if (serverMessage.Body.Length != 0)
                {
                    throw new TlsFatalAlert(AlertDescription.decode_error);
                }
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            handshake.HandshakeHash.SealHashAlgorithms();

            IList clientSupplementalData = state.client.GetClientSupplementalData();
            if (clientSupplementalData != null)
            {
                byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
                handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
            }

            if (state.certificateRequest != null)
            {
                state.clientCredentials = state.authentication.GetClientCredentials(state.certificateRequest);

                /*
                 * RFC 5246 If no suitable certificate is available, the client MUST send a certificate
                 * message containing no certificates.
                 * 
                 * NOTE: In previous RFCs, this was SHOULD instead of MUST.
                 */
                Certificate clientCertificate = null;
                if (state.clientCredentials != null)
                {
                    clientCertificate = state.clientCredentials.Certificate;
                }
                if (clientCertificate == null)
                {
                    clientCertificate = Certificate.EmptyChain;
                }

                byte[] certificateBody = GenerateCertificate(clientCertificate);
                handshake.SendMessage(HandshakeType.certificate, certificateBody);
            }

            if (state.clientCredentials != null)
            {
                state.keyExchange.ProcessClientCredentials(state.clientCredentials);
            }
            else
            {
                state.keyExchange.SkipClientCredentials();
            }

            byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state);
            handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody);

            TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();
            securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, prepareFinishHash, null);

            TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange);
            recordLayer.InitPendingEpoch(state.client.GetCipher());

            if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials)
            {
                TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials;

                /*
                 * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
                 */
                SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
                    state.clientContext, signerCredentials);

                byte[] hash;
                if (signatureAndHashAlgorithm == null)
                {
                    hash = securityParameters.SessionHash;
                }
                else
                {
                    hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
                }

                byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
                DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
                byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
                handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
            }

            // NOTE: Calculated exclusive of the Finished message itself
            byte[] clientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
                TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
            handshake.SendMessage(HandshakeType.finished, clientVerifyData);

            if (state.expectSessionTicket)
            {
                serverMessage = handshake.ReceiveMessage();
                if (serverMessage.Type == HandshakeType.session_ticket)
                {
                    ProcessNewSessionTicket(state, serverMessage.Body);
                }
                else
                {
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
            }

            // NOTE: Calculated exclusive of the actual Finished message from the server
            byte[] expectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
                TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
            ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedServerVerifyData);

            handshake.Finish();

            if (state.tlsSession != null)
            {
                state.sessionParameters = new SessionParameters.Builder()
                    .SetCipherSuite(securityParameters.CipherSuite)
                    .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
                    .SetMasterSecret(securityParameters.MasterSecret)
                    .SetPeerCertificate(serverCertificate)
                    .SetPskIdentity(securityParameters.PskIdentity)
                    .SetSrpIdentity(securityParameters.SrpIdentity)
                    // TODO Consider filtering extensions that aren't relevant to resumed sessions
                    .SetServerExtensions(state.serverExtensions)
                    .Build();

                state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);

                state.clientContext.SetResumableSession(state.tlsSession);
            }

            state.client.NotifyHandshakeComplete();

            return new DtlsTransport(recordLayer);
        }
        protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            state.keyExchange.ProcessServerKeyExchange(buf);

            TlsProtocol.AssertEmpty(buf);
        }
 protected virtual void ProcessServerSupplementalData(ClientHandshakeState state, byte[] body)
 {
     MemoryStream buf = new MemoryStream(body, false);
     IList serverSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);
     state.client.ProcessServerSupplementalData(serverSupplementalData);
 }
 protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
 {
     TlsClientContextImpl clientContext = state.clientContext;
     ProtocolVersion currentServerVersion = clientContext.ServerVersion;
     if (null == currentServerVersion)
     {
         clientContext.SetServerVersion(server_version);
         state.client.NotifyServerVersion(server_version);
     }
     else if (!currentServerVersion.Equals(server_version))
     {
         throw new TlsFatalAlert(AlertDescription.illegal_parameter);
     }
 }
        protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
        {
            if (state.authentication == null)
            {
                /*
                 * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to
                 * request client identification.
                 */
                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            MemoryStream buf = new MemoryStream(body, false);

            state.certificateRequest = CertificateRequest.Parse(state.clientContext, buf);

            TlsProtocol.AssertEmpty(buf);

            state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
        }
        protected virtual void InvalidateSession(ClientHandshakeState state)
        {
            if (state.sessionParameters != null)
            {
                state.sessionParameters.Clear();
                state.sessionParameters = null;
            }

            if (state.tlsSession != null)
            {
                state.tlsSession.Invalidate();
                state.tlsSession = null;
            }
        }
 internal virtual void AbortClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription)
 {
     recordLayer.Fail(alertDescription);
     InvalidateSession(state);
 }
Пример #42
0
        protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body)
        {
            SecurityParameters securityParameters = state.clientContext.SecurityParameters;

            MemoryStream buf = new MemoryStream(body, false);

            ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);

            ReportServerVersion(state, server_version);

            securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);

            state.selectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (state.selectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            state.client.NotifySessionID(state.selectedSessionID);

            state.selectedCipherSuite = TlsUtilities.ReadUint16(buf);
            if (!Arrays.Contains(state.offeredCipherSuites, state.selectedCipherSuite) ||
                state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(state.selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(state.selectedCipherSuite, server_version))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.illegal_parameter);

            state.client.NotifySelectedCipherSuite(state.selectedCipherSuite);

            state.selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
            if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            state.client.NotifySelectedCompressionMethod((byte)state.selectedCompressionMethod);

            /*
             * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
             * hello message when the client has requested extended functionality via the extended
             * client hello message specified in Section 2.1. ... Note that the extended server hello
             * message is only sent in response to an extended client hello message. This prevents the
             * possibility that the extended server hello message could "break" existing TLS 1.0
             * clients.
             */

            /*
             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
             * extensions appearing in the client hello, and send a server hello containing no
             * extensions.
             */

            // Integer -> byte[]
            IDictionary serverExtensions = TlsProtocol.ReadExtensions(buf);

            /*
             * draft-ietf-tls-session-hash-01 5.2. If a server receives the "extended_master_secret"
             * extension, it MUST include the "extended_master_secret" extension in its ServerHello
             * message.
             */
            bool serverSentExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(serverExtensions);

            if (serverSentExtendedMasterSecret != securityParameters.extendedMasterSecret)
            {
                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            /*
             * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
             * extended client hello message. However, see RFC 5746 exception below. We always include
             * the SCSV, so an Extended Server Hello is always allowed.
             */
            if (serverExtensions != null)
            {
                foreach (int extType in serverExtensions.Keys)
                {
                    /*
                     * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
                     * ClientHello containing only the SCSV is an explicit exception to the prohibition
                     * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is
                     * only allowed because the client is signaling its willingness to receive the
                     * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
                     */
                    if (extType == ExtensionType.renegotiation_info)
                    {
                        continue;
                    }

                    /*
                     * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
                     * same extension type appeared in the corresponding ClientHello. If a client
                     * receives an extension type in ServerHello that it did not request in the
                     * associated ClientHello, it MUST abort the handshake with an unsupported_extension
                     * fatal alert.
                     */
                    if (null == TlsUtilities.GetExtensionData(state.clientExtensions, extType))
                    {
                        throw new TlsFatalAlert(AlertDescription.unsupported_extension);
                    }

                    /*
                     * draft-ietf-tls-session-hash-01 5.2. Implementation note: if the server decides to
                     * proceed with resumption, the extension does not have any effect. Requiring the
                     * extension to be included anyway makes the extension negotiation logic easier,
                     * because it does not depend on whether resumption is accepted or not.
                     */
                    if (extType == ExtensionType.extended_master_secret)
                    {
                        continue;
                    }

                    /*
                     * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
                     * extensions appearing in the client hello, and send a server hello containing no
                     * extensions[.]
                     */
                    // TODO[sessions]
                    //                if (this.mResumedSession)
                    //                {
                    //                    // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
                    //                    // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
                    //                    // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
                    ////                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    //                }
                }

                /*
                 * RFC 5746 3.4. Client Behavior: Initial Handshake
                 */
                {
                    /*
                     * When a ServerHello is received, the client MUST check if it includes the
                     * "renegotiation_info" extension:
                     */
                    byte[] renegExtData = (byte[])serverExtensions[ExtensionType.renegotiation_info];
                    if (renegExtData != null)
                    {
                        /*
                         * If the extension is present, set the secure_renegotiation flag to TRUE. The
                         * client MUST then verify that the length of the "renegotiated_connection"
                         * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
                         * handshake_failure alert).
                         */
                        state.secure_renegotiation = true;

                        if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                        {
                            throw new TlsFatalAlert(AlertDescription.handshake_failure);
                        }
                    }
                }

                /*
                 * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
                 * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
                 * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
                 * client.
                 */
                bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(serverExtensions);
                if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(state.selectedCipherSuite))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                securityParameters.encryptThenMac = serverSentEncryptThenMAC;

                state.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.clientExtensions, serverExtensions,
                                                                             AlertDescription.illegal_parameter);

                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(serverExtensions);

                state.allowCertificateStatus = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions,
                                                                                          ExtensionType.status_request, AlertDescription.illegal_parameter);

                state.expectSessionTicket = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions,
                                                                                       ExtensionType.session_ticket, AlertDescription.illegal_parameter);
            }

            state.client.NotifySecureRenegotiation(state.secure_renegotiation);

            if (state.clientExtensions != null)
            {
                state.client.ProcessServerExtensions(serverExtensions);
            }
        }
        protected virtual void ProcessNewSessionTicket(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            state.client.NotifyNewSessionTicket(newSessionTicket);
        }
        protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
        {
            MemoryStream buf = new MemoryStream();

            ProtocolVersion client_version = client.ClientVersion;
            if (!client_version.IsDtls)
                throw new TlsFatalAlert(AlertDescription.internal_error);

            TlsClientContextImpl context = state.clientContext;

            context.SetClientVersion(client_version);
            TlsUtilities.WriteVersion(client_version, buf);

            SecurityParameters securityParameters = context.SecurityParameters;
            buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);

            // Session ID
            byte[] session_id = TlsUtilities.EmptyBytes;
            if (state.tlsSession != null)
            {
                session_id = state.tlsSession.SessionID;
                if (session_id == null || session_id.Length > 32)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }
            TlsUtilities.WriteOpaque8(session_id, buf);

            // Cookie
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            bool fallback = client.IsFallback;

            /*
             * Cipher suites
             */
            state.offeredCipherSuites = client.GetCipherSuites();

            // Integer -> byte[]
            state.clientExtensions = client.GetClientExtensions();

            // Cipher Suites (and SCSV)
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
                bool noRenegExt = (null == renegExtData);

                bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);

                if (noRenegExt && noRenegSCSV)
                {
                    // TODO Consider whether to default to a client extension instead
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
                }

                /*
                 * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
                 * containing a lower value than the latest (highest-valued) version supported by the
                 * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
                 * ClientHello.cipher_suites.
                 */
                if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
                {
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
                }

                TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
            }

            // TODO Add support for compression
            // Compression methods
            // state.offeredCompressionMethods = client.getCompressionMethods();
            state.offeredCompressionMethods = new byte[]{ CompressionMethod.cls_null };

            TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf);

            // Extensions
            if (state.clientExtensions != null)
            {
                TlsProtocol.WriteExtensions(buf, state.clientExtensions);
            }

            return buf.ToArray();
        }
        protected virtual byte[] ProcessHelloVerifyRequest(ClientHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
            byte[] cookie = TlsUtilities.ReadOpaque8(buf);

            TlsProtocol.AssertEmpty(buf);

            // TODO Seems this behaviour is not yet in line with OpenSSL for DTLS 1.2
    //        reportServerVersion(state, server_version);
            if (!server_version.IsEqualOrEarlierVersionOf(state.clientContext.ClientVersion))
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);

            /*
             * RFC 6347 This specification increases the cookie size limit to 255 bytes for greater
             * future flexibility. The limit remains 32 for previous versions of DTLS.
             */
            if (!ProtocolVersion.DTLSv12.IsEqualOrEarlierVersionOf(server_version) && cookie.Length > 32)
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);

            return cookie;
        }
Пример #46
0
        protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
        {
            MemoryStream buf = new MemoryStream();

            ProtocolVersion client_version = client.ClientVersion;

            if (!client_version.IsDtls)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            TlsClientContextImpl context = state.clientContext;

            context.SetClientVersion(client_version);
            TlsUtilities.WriteVersion(client_version, buf);

            SecurityParameters securityParameters = context.SecurityParameters;

            buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);

            // Session ID
            byte[] session_id = TlsUtilities.EmptyBytes;
            if (state.tlsSession != null)
            {
                session_id = state.tlsSession.SessionID;
                if (session_id == null || session_id.Length > 32)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }
            TlsUtilities.WriteOpaque8(session_id, buf);

            // Cookie
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            bool fallback = client.IsFallback;

            /*
             * Cipher suites
             */
            state.offeredCipherSuites = client.GetCipherSuites();

            // Integer -> byte[]
            state.clientExtensions = client.GetClientExtensions();

            securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions);

            // Cipher Suites (and SCSV)
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);

                if (noRenegExt && noRenegSCSV)
                {
                    // TODO Consider whether to default to a client extension instead
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
                }

                /*
                 * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
                 * containing a lower value than the latest (highest-valued) version supported by the
                 * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
                 * ClientHello.cipher_suites.
                 */
                if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
                {
                    state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
                }

                TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
            }

            // TODO Add support for compression
            // Compression methods
            // state.offeredCompressionMethods = client.getCompressionMethods();
            state.offeredCompressionMethods = new byte[] { CompressionMethod.cls_null };

            TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf);

            // Extensions
            if (state.clientExtensions != null)
            {
                TlsProtocol.WriteExtensions(buf, state.clientExtensions);
            }

            return(buf.ToArray());
        }
Пример #47
0
 internal virtual void AbortClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription)
 {
     recordLayer.Fail(alertDescription);
     InvalidateSession(state);
 }