public bool IsLaterVersionOf(ProtocolVersion version)
 {
     if (MajorVersion != version.MajorVersion)
     {
         return false;
     }
     int diffMinorVersion = version.MinorVersion - MinorVersion;
     return IsDtls ? diffMinorVersion > 0 : diffMinorVersion < 0;
 }
 public bool IsEqualOrEarlierVersionOf(ProtocolVersion version)
 {
     if (MajorVersion != version.MajorVersion)
     {
         return false;
     }
     int diffMinorVersion = version.MinorVersion - MinorVersion;
     return IsDtls ? diffMinorVersion <= 0 : diffMinorVersion >= 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);
     }
 }
 public virtual void NotifyClientVersion(ProtocolVersion clientVersion)
 {
     this.mClientVersion = clientVersion;
 }
Beispiel #5
0
        internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer)
        {
            SecurityParameters    securityParameters = state.serverContext.SecurityParameters;
            DtlsReliableHandshake handshake          = new DtlsReliableHandshake(state.serverContext, recordLayer);

            DtlsReliableHandshake.Message clientMessage = handshake.ReceiveMessage();

            {
                // NOTE: After receiving a record from the client, we discover the record layer version
                ProtocolVersion client_version = recordLayer.DiscoveredPeerVersion;
                // TODO Read RFCs for guidance on the expected record layer version number
                state.serverContext.SetClientVersion(client_version);
            }

            if (clientMessage.Type == HandshakeType.client_hello)
            {
                ProcessClientHello(state, clientMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            {
                byte[] serverHelloBody = GenerateServerHello(state);

                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.serverContext,
                                                                                      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.SendMessage(HandshakeType.server_hello, serverHelloBody);
            }

            handshake.NotifyHelloComplete();

            IList serverSupplementalData = state.server.GetServerSupplementalData();

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

            state.keyExchange = state.server.GetKeyExchange();
            state.keyExchange.Init(state.serverContext);

            state.serverCredentials = state.server.GetCredentials();

            Certificate serverCertificate = null;

            if (state.serverCredentials == null)
            {
                state.keyExchange.SkipServerCredentials();
            }
            else
            {
                state.keyExchange.ProcessServerCredentials(state.serverCredentials);

                serverCertificate = state.serverCredentials.Certificate;
                byte[] certificateBody = GenerateCertificate(serverCertificate);
                handshake.SendMessage(HandshakeType.certificate, certificateBody);
            }

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

            if (state.allowCertificateStatus)
            {
                CertificateStatus certificateStatus = state.server.GetCertificateStatus();
                if (certificateStatus != null)
                {
                    byte[] certificateStatusBody = GenerateCertificateStatus(state, certificateStatus);
                    handshake.SendMessage(HandshakeType.certificate_status, certificateStatusBody);
                }
            }

            byte[] serverKeyExchange = state.keyExchange.GenerateServerKeyExchange();
            if (serverKeyExchange != null)
            {
                handshake.SendMessage(HandshakeType.server_key_exchange, serverKeyExchange);
            }

            if (state.serverCredentials != null)
            {
                state.certificateRequest = state.server.GetCertificateRequest();
                if (state.certificateRequest != null)
                {
                    state.keyExchange.ValidateCertificateRequest(state.certificateRequest);

                    byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest);
                    handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody);

                    TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
                                                     state.certificateRequest.SupportedSignatureAlgorithms);
                }
            }

            handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes);

            handshake.HandshakeHash.SealHashAlgorithms();

            clientMessage = handshake.ReceiveMessage();

            if (clientMessage.Type == HandshakeType.supplemental_data)
            {
                ProcessClientSupplementalData(state, clientMessage.Body);
                clientMessage = handshake.ReceiveMessage();
            }
            else
            {
                state.server.ProcessClientSupplementalData(null);
            }

            if (state.certificateRequest == null)
            {
                state.keyExchange.SkipClientCredentials();
            }
            else
            {
                if (clientMessage.Type == HandshakeType.certificate)
                {
                    ProcessClientCertificate(state, clientMessage.Body);
                    clientMessage = handshake.ReceiveMessage();
                }
                else
                {
                    if (TlsUtilities.IsTlsV12(state.serverContext))
                    {
                        /*
                         * 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.
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    NotifyClientCertificate(state, Certificate.EmptyChain);
                }
            }

            if (clientMessage.Type == HandshakeType.client_key_exchange)
            {
                ProcessClientKeyExchange(state, clientMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();

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

            TlsProtocol.EstablishMasterSecret(state.serverContext, state.keyExchange);
            recordLayer.InitPendingEpoch(state.server.GetCipher());

            /*
             * RFC 5246 7.4.8 This message is only sent following a client certificate that has signing
             * capability (i.e., all certificates except those containing fixed Diffie-Hellman
             * parameters).
             */
            if (ExpectCertificateVerifyMessage(state))
            {
                byte[] certificateVerifyBody = handshake.ReceiveMessageBody(HandshakeType.certificate_verify);
                ProcessCertificateVerify(state, certificateVerifyBody, prepareFinishHash);
            }

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

            if (state.expectSessionTicket)
            {
                NewSessionTicket newSessionTicket     = state.server.GetNewSessionTicket();
                byte[]           newSessionTicketBody = GenerateNewSessionTicket(state, newSessionTicket);
                handshake.SendMessage(HandshakeType.session_ticket, newSessionTicketBody);
            }

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

            handshake.Finish();

            state.server.NotifyHandshakeComplete();

            return(new DtlsTransport(recordLayer));
        }
Beispiel #6
0
 public virtual void NotifyClientVersion(ProtocolVersion clientVersion)
 {
     this.mClientVersion = clientVersion;
 }
Beispiel #7
0
 public static bool IsSignatureAlgorithmsExtensionAllowed(ProtocolVersion clientVersion)
 {
     return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(clientVersion.GetEquivalentTLSVersion());
 }
        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
        {
            int blockSize = encryptCipher.GetBlockSize();
            int macSize   = mWriteMac.Size;

            ProtocolVersion version = context.ServerVersion;

            int enc_input_length = len;

            if (!encryptThenMac)
            {
                enc_input_length += macSize;
            }

            int padding_length = blockSize - 1 - (enc_input_length % blockSize);

            /*
             * Don't use variable-length padding with truncated MACs.
             *
             * See "Tag Size Does Matter: Attacks and Proofs for the TLS Record Protocol", Paterson,
             * Ristenpart, Shrimpton.
             */
            if (encryptThenMac || !context.SecurityParameters.truncatedHMac)
            {
                // TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though)
                if (!version.IsDtls && !version.IsSsl)
                {
                    // Add a random number of extra blocks worth of padding
                    int maxExtraPadBlocks    = (255 - padding_length) / blockSize;
                    int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks);
                    padding_length += actualExtraPadBlocks * blockSize;
                }
            }

            int totalSize = len + macSize + padding_length + 1;

            if (useExplicitIV)
            {
                totalSize += blockSize;
            }

            byte[] outBuf = new byte[totalSize];
            int    outOff = 0;

            if (useExplicitIV)
            {
                byte[] explicitIV = new byte[blockSize];
                context.NonceRandomGenerator.NextBytes(explicitIV);

                encryptCipher.Init(true, new ParametersWithIV(null, explicitIV));

                Array.Copy(explicitIV, 0, outBuf, outOff, blockSize);
                outOff += blockSize;
            }

            int blocks_start = outOff;

            Array.Copy(plaintext, offset, outBuf, outOff, len);
            outOff += len;

            if (!encryptThenMac)
            {
                byte[] mac = mWriteMac.CalculateMac(seqNo, type, plaintext, offset, len);
                Array.Copy(mac, 0, outBuf, outOff, mac.Length);
                outOff += mac.Length;
            }

            for (int i = 0; i <= padding_length; i++)
            {
                outBuf[outOff++] = (byte)padding_length;
            }

            for (int i = blocks_start; i < outOff; i += blockSize)
            {
                encryptCipher.ProcessBlock(outBuf, i, outBuf, i);
            }

            if (encryptThenMac)
            {
                byte[] mac = mWriteMac.CalculateMac(seqNo, type, outBuf, 0, outOff);
                Array.Copy(mac, 0, outBuf, outOff, mac.Length);
                outOff += mac.Length;
            }

            //        assert outBuf.length == outOff;

            return(outBuf);
        }
        public static byte[] SafeDecryptPreMasterSecret(TlsContext context, RsaKeyParameters rsaServerPrivateKey,
                                                        byte[] encryptedPreMasterSecret)
        {
            /*
             * RFC 5246 7.4.7.1.
             */
            ProtocolVersion clientVersion = context.ClientVersion;

            // TODO Provide as configuration option?
            bool versionNumberCheckDisabled = false;

            /*
             * Generate 48 random bytes we can use as a Pre-Master-Secret, if the
             * PKCS1 padding check should fail.
             */
            byte[] fallback = new byte[48];
            context.SecureRandom.NextBytes(fallback);

            byte[] M = Arrays.Clone(fallback);
            try
            {
                Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine(), fallback);
                encoding.Init(false,
                              new ParametersWithRandom(rsaServerPrivateKey, context.SecureRandom));

                M = encoding.ProcessBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length);
            }
            catch (Exception)
            {
                /*
                 * This should never happen since the decryption should never throw an exception
                 * and return a random value instead.
                 *
                 * In any case, a TLS server MUST NOT generate an alert if processing an
                 * RSA-encrypted premaster secret message fails, or the version number is not as
                 * expected. Instead, it MUST continue the handshake with a randomly generated
                 * premaster secret.
                 */
            }

            /*
             * If ClientHello.client_version is TLS 1.1 or higher, server implementations MUST
             * check the version number [..].
             */
            if (versionNumberCheckDisabled && clientVersion.IsEqualOrEarlierVersionOf(ProtocolVersion.TLSv10))
            {
                /*
                 * If the version number is TLS 1.0 or earlier, server
                 * implementations SHOULD check the version number, but MAY have a
                 * configuration option to disable the check.
                 *
                 * So there is nothing to do here.
                 */
            }
            else
            {
                /*
                 * OK, we need to compare the version number in the decrypted Pre-Master-Secret with the
                 * clientVersion received during the handshake. If they don't match, we replace the
                 * decrypted Pre-Master-Secret with a random one.
                 */
                int correct = (clientVersion.MajorVersion ^ (M[0] & 0xff))
                              | (clientVersion.MinorVersion ^ (M[1] & 0xff));
                correct |= correct >> 1;
                correct |= correct >> 2;
                correct |= correct >> 4;
                int mask = ~((correct & 1) - 1);

                /*
                 * mask will be all bits set to 0xff if the version number differed.
                 */
                for (int i = 0; i < 48; i++)
                {
                    M[i] = (byte)((M[i] & (~mask)) | (fallback[i] & mask));
                }
            }
            return(M);
        }
Beispiel #10
0
 public static bool IsTlsV12(ProtocolVersion version)
 {
     return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion());
 }
Beispiel #11
0
        protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
        {
            SecurityParameters securityParameters = state.serverContext.SecurityParameters;

            MemoryStream buf = new MemoryStream();

            {
                ProtocolVersion server_version = state.server.GetServerVersion();
                if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                // TODO Read RFCs for guidance on the expected record layer version number
                // recordStream.setReadVersion(server_version);
                // recordStream.setWriteVersion(server_version);
                // recordStream.setRestrictReadVersion(true);
                state.serverContext.SetServerVersion(server_version);

                TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
            }

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

            /*
             * The server may return an empty session_id to indicate that the session will not be cached
             * and therefore cannot be resumed.
             */
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            int selectedCipherSuite = state.server.GetSelectedCipherSuite();

            if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error);
            securityParameters.cipherSuite = selectedCipherSuite;

            byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod();

            if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            securityParameters.compressionAlgorithm = selectedCompressionMethod;

            TlsUtilities.WriteUint16(selectedCipherSuite, buf);
            TlsUtilities.WriteUint8(selectedCompressionMethod, buf);

            state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.server.GetServerExtensions());

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            if (state.secure_renegotiation)
            {
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                if (noRenegExt)
                {
                    /*
                     * 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 the secure_renegotiation flag is set to TRUE, the server MUST include an empty
                     * "renegotiation_info" extension in the ServerHello message.
                     */
                    state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                }
            }

            if (securityParameters.IsExtendedMasterSecret)
            {
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
            }

            /*
             * 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.
             */

            if (state.serverExtensions.Count > 0)
            {
                securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);

                securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
                                                                                          state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);

                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);

                /*
                 * 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(state.serverExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.internal_error);

                state.expectSessionTicket = !state.resumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.internal_error);

                ProcessCertificateFormats(state, state.clientExtensions, state.serverExtensions);

                TlsProtocol.WriteExtensions(buf, state.serverExtensions);
            }

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

            /*
             * RFC 5246 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;

            return(buf.ToArray());
        }
Beispiel #12
0
        internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer)
        {
            SecurityParameters    securityParameters = state.serverContext.SecurityParameters;
            DtlsReliableHandshake handshake          = new DtlsReliableHandshake(state.serverContext, recordLayer,
                                                                                 state.server.GetHandshakeTimeoutMillis());

            DtlsReliableHandshake.Message clientMessage = handshake.ReceiveMessage();

            // NOTE: DTLSRecordLayer requires any DTLS version, we don't otherwise constrain this
            //ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;

            if (clientMessage.Type == HandshakeType.client_hello)
            {
                ProcessClientHello(state, clientMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            {
                byte[] serverHelloBody = GenerateServerHello(state);

                ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);

                ProtocolVersion recordLayerVersion = state.serverContext.ServerVersion;
                recordLayer.ReadVersion = recordLayerVersion;
                recordLayer.SetWriteVersion(recordLayerVersion);

                handshake.SendMessage(HandshakeType.server_hello, serverHelloBody);
            }

            handshake.NotifyHelloComplete();

            IList serverSupplementalData = state.server.GetServerSupplementalData();

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

            state.keyExchange = state.server.GetKeyExchange();
            state.keyExchange.Init(state.serverContext);

            state.serverCredentials = state.server.GetCredentials();

            AbstractCertificate serverCertificate = null;

            if (state.serverCredentials == null)
            {
                state.keyExchange.SkipServerCredentials();
            }
            else
            {
                state.keyExchange.ProcessServerCredentials(state.serverCredentials);

                serverCertificate = state.serverCredentials.Certificate;
                byte[] certificateBody = GenerateCertificate(serverCertificate);
                handshake.SendMessage(HandshakeType.certificate, certificateBody);
            }

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

            if (state.allowCertificateStatus)
            {
                CertificateStatus certificateStatus = state.server.GetCertificateStatus();
                if (certificateStatus != null)
                {
                    byte[] certificateStatusBody = GenerateCertificateStatus(state, certificateStatus);
                    handshake.SendMessage(HandshakeType.certificate_status, certificateStatusBody);
                }
            }

            byte[] serverKeyExchange = state.keyExchange.GenerateServerKeyExchange();
            if (serverKeyExchange != null)
            {
                handshake.SendMessage(HandshakeType.server_key_exchange, serverKeyExchange);
            }

            if (state.serverCredentials != null)
            {
                state.certificateRequest = state.server.GetCertificateRequest();
                if (state.certificateRequest != null)
                {
                    if (TlsUtilities.IsTlsV12(state.serverContext) != (state.certificateRequest.SupportedSignatureAlgorithms != null))
                    {
                        throw new TlsFatalAlert(AlertDescription.internal_error);
                    }

                    state.keyExchange.ValidateCertificateRequest(state.certificateRequest);

                    byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest);
                    handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody);

                    TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
                                                     state.certificateRequest.SupportedSignatureAlgorithms);
                }
            }

            handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes);

            handshake.HandshakeHash.SealHashAlgorithms();

            clientMessage = handshake.ReceiveMessage();

            if (clientMessage.Type == HandshakeType.supplemental_data)
            {
                ProcessClientSupplementalData(state, clientMessage.Body);
                clientMessage = handshake.ReceiveMessage();
            }
            else
            {
                state.server.ProcessClientSupplementalData(null);
            }

            if (state.certificateRequest == null)
            {
                state.keyExchange.SkipClientCredentials();
            }
            else
            {
                if (clientMessage.Type == HandshakeType.certificate)
                {
                    ProcessClientCertificate(state, clientMessage.Body);
                    clientMessage = handshake.ReceiveMessage();
                }
                else
                {
                    if (TlsUtilities.IsTlsV12(state.serverContext))
                    {
                        /*
                         * 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.
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    NotifyClientCertificate(state, Certificate.EmptyChain);
                }
            }

            if (clientMessage.Type == HandshakeType.client_key_exchange)
            {
                ProcessClientKeyExchange(state, clientMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();

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

            TlsProtocol.EstablishMasterSecret(state.serverContext, state.keyExchange);
            recordLayer.InitPendingEpoch(state.server.GetCipher());

            /*
             * RFC 5246 7.4.8 This message is only sent following a client certificate that has signing
             * capability (i.e., all certificates except those containing fixed Diffie-Hellman
             * parameters).
             */
            if (ExpectCertificateVerifyMessage(state))
            {
                byte[] certificateVerifyBody = handshake.ReceiveMessageBody(HandshakeType.certificate_verify);
                ProcessCertificateVerify(state, certificateVerifyBody, prepareFinishHash);
            }

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

            if (state.expectSessionTicket)
            {
                NewSessionTicket newSessionTicket     = state.server.GetNewSessionTicket();
                byte[]           newSessionTicketBody = GenerateNewSessionTicket(state, newSessionTicket);
                handshake.SendMessage(HandshakeType.session_ticket, newSessionTicketBody);
            }

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

            handshake.Finish();

            //{
            //    state.sessionParameters = new SessionParameters.Builder()
            //        .SetCipherSuite(securityParameters.CipherSuite)
            //        .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
            //        .SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret)
            //        .SetMasterSecret(securityParameters.MasterSecret)
            //        .SetPeerCertificate(state.clientCertificate)
            //        .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.serverContext.SetResumableSession(state.tlsSession);
            //}

            state.server.NotifyHandshakeComplete();

            return(new DtlsTransport(recordLayer));
        }
        private int ProcessRecord(int received, byte[] record, byte[] buf, int off)
        {
            // NOTE: received < 0 (timeout) is covered by this first case
            if (received < RECORD_HEADER_LENGTH)
            {
                return(-1);
            }
            int length = TlsUtilities.ReadUint16(record, 11);

            if (received != (length + RECORD_HEADER_LENGTH))
            {
                return(-1);
            }

            byte type = TlsUtilities.ReadUint8(record, 0);

            switch (type)
            {
            case ContentType.alert:
            case ContentType.application_data:
            case ContentType.change_cipher_spec:
            case ContentType.handshake:
            case ContentType.heartbeat:
                break;

            default:
                return(-1);
            }

            int epoch = TlsUtilities.ReadUint16(record, 3);

            DtlsEpoch recordEpoch = null;

            if (epoch == mReadEpoch.Epoch)
            {
                recordEpoch = mReadEpoch;
            }
            else if (type == ContentType.handshake && mRetransmitEpoch != null &&
                     epoch == mRetransmitEpoch.Epoch)
            {
                recordEpoch = mRetransmitEpoch;
            }

            if (recordEpoch == null)
            {
                return(-1);
            }

            long seq = TlsUtilities.ReadUint48(record, 5);

            if (recordEpoch.ReplayWindow.ShouldDiscard(seq))
            {
                return(-1);
            }

            ProtocolVersion version = TlsUtilities.ReadVersion(record, 1);

            if (!version.IsDtls)
            {
                return(-1);
            }

            if (mReadVersion != null && !mReadVersion.Equals(version))
            {
                return(-1);
            }

            byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext(
                GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH,
                received - RECORD_HEADER_LENGTH);

            recordEpoch.ReplayWindow.ReportAuthenticated(seq);

            if (plaintext.Length > this.mPlaintextLimit)
            {
                return(-1);
            }

            if (mReadVersion == null)
            {
                mReadVersion = version;
            }

            switch (type)
            {
            case ContentType.alert:
            {
                if (plaintext.Length == 2)
                {
                    byte alertLevel       = plaintext[0];
                    byte alertDescription = plaintext[1];

                    mPeer.NotifyAlertReceived(alertLevel, alertDescription);

                    if (alertLevel == AlertLevel.fatal)
                    {
                        Failed();
                        throw new TlsFatalAlert(alertDescription);
                    }

                    // TODO Can close_notify be a fatal alert?
                    if (alertDescription == AlertDescription.close_notify)
                    {
                        CloseTransport();
                    }
                }

                return(-1);
            }

            case ContentType.application_data:
            {
                if (mInHandshake)
                {
                    // TODO Consider buffering application data for new epoch that arrives
                    // out-of-order with the Finished message
                    return(-1);
                }
                break;
            }

            case ContentType.change_cipher_spec:
            {
                // Implicitly receive change_cipher_spec and change to pending cipher state

                for (int i = 0; i < plaintext.Length; ++i)
                {
                    byte message = TlsUtilities.ReadUint8(plaintext, i);
                    if (message != ChangeCipherSpec.change_cipher_spec)
                    {
                        continue;
                    }

                    if (mPendingEpoch != null)
                    {
                        mReadEpoch = mPendingEpoch;
                    }
                }

                return(-1);
            }

            case ContentType.handshake:
            {
                if (!mInHandshake)
                {
                    if (mRetransmit != null)
                    {
                        mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length);
                    }

                    // TODO Consider support for HelloRequest
                    return(-1);
                }
                break;
            }

            case ContentType.heartbeat:
            {
                // TODO[RFC 6520]
                return(-1);
            }
            }

            /*
             * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
             * received our final flight.
             */
            if (!mInHandshake && mRetransmit != null)
            {
                this.mRetransmit        = null;
                this.mRetransmitEpoch   = null;
                this.mRetransmitTimeout = null;
            }

            Array.Copy(plaintext, 0, buf, off, plaintext.Length);
            return(plaintext.Length);
        }
        protected virtual void SendServerHelloMessage()
        {
            HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);

            {
                ProtocolVersion server_version = mTlsServer.GetServerVersion();
                if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                mRecordStream.ReadVersion = server_version;
                mRecordStream.SetWriteVersion(server_version);
                mRecordStream.SetRestrictReadVersion(true);
                ContextAdmin.SetServerVersion(server_version);

                TlsUtilities.WriteVersion(server_version, message);
            }

            message.Write(this.mSecurityParameters.serverRandom);

            /*
             * The server may return an empty session_id to indicate that the session will not be cached
             * and therefore cannot be resumed.
             */
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message);

            int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();

            if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            mSecurityParameters.cipherSuite = selectedCipherSuite;

            byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();

            if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;

            TlsUtilities.WriteUint16(selectedCipherSuite, message);
            TlsUtilities.WriteUint8(selectedCompressionMethod, message);

            this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mTlsServer.GetServerExtensions());

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            if (this.mSecureRenegotiation)
            {
                byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                if (noRenegExt)
                {
                    /*
                     * 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 the secure_renegotiation flag is set to TRUE, the server MUST include an empty
                     * "renegotiation_info" extension in the ServerHello message.
                     */
                    this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                }
            }

            if (TlsUtilities.IsSsl(mTlsServerContext))
            {
                mSecurityParameters.extendedMasterSecret = false;
            }
            else if (mSecurityParameters.IsExtendedMasterSecret)
            {
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
            }

            /*
             * 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.
             */

            if (this.mServerExtensions.Count > 0)
            {
                this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);

                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions,
                                                                                               mServerExtensions, AlertDescription.internal_error);

                this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
                 * a session resumption handshake.
                 */
                this.mAllowCertificateStatus = !mResumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.internal_error);

                this.mExpectSessionTicket = !mResumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.internal_error);

                WriteExtensions(message, this.mServerExtensions);
            }

            mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);

            /*
             * RFC 5246 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.
             */
            mSecurityParameters.verifyDataLength = 12;

            ApplyMaxFragmentLengthExtension();

            message.WriteToRecordStream(this);
        }
        protected virtual void ReceiveClientHelloMessage(MemoryStream buf)
        {
            ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);

            mRecordStream.SetWriteVersion(client_version);

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

            byte[] client_random = TlsUtilities.ReadFully(32, buf);

            /*
             * TODO RFC 5077 3.4. If a ticket is presented by the client, the server MUST NOT attempt to
             * use the Session ID in the ClientHello for stateful session resumption.
             */
            byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
            if (sessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            /*
             * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
             * resumption request), this vector MUST include at least the cipher_suite from that
             * session.
             */
            int cipher_suites_length = TlsUtilities.ReadUint16(buf);

            if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
            {
                throw new TlsFatalAlert(AlertDescription.decode_error);
            }

            this.mOfferedCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);

            /*
             * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
             * resumption request), it MUST include the compression_method from that session.
             */
            int compression_methods_length = TlsUtilities.ReadUint8(buf);

            if (compression_methods_length < 1)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            this.mOfferedCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);

            /*
             * 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.
             */
            this.mClientExtensions = ReadExtensions(buf);

            /*
             * TODO[resumption] Check RFC 7627 5.4. for required behaviour
             */

            /*
             * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
             * master secret [..]. (and see 5.2, 5.3)
             */
            this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mClientExtensions);
            if (!mSecurityParameters.IsExtendedMasterSecret && mTlsServer.RequiresExtendedMasterSecret())
            {
                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            ContextAdmin.SetClientVersion(client_version);

            mTlsServer.NotifyClientVersion(client_version);
            mTlsServer.NotifyFallback(Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));

            mSecurityParameters.clientRandom = client_random;

            mTlsServer.NotifyOfferedCipherSuites(mOfferedCipherSuites);
            mTlsServer.NotifyOfferedCompressionMethods(mOfferedCompressionMethods);

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            {
                /*
                 * 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.
                 */

                /*
                 * When a ClientHello is received, the server MUST check if it includes the
                 * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
                 * to TRUE.
                 */
                if (Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
                {
                    this.mSecureRenegotiation = true;
                }

                /*
                 * The server MUST check if the "renegotiation_info" extension is included in the
                 * ClientHello.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                     * If the extension is present, set secure_renegotiation flag to TRUE. The
                     * server MUST then verify that the length of the "renegotiated_connection"
                     * field is zero, and if it is not, MUST abort the handshake.
                     */
                    this.mSecureRenegotiation = true;

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

            mTlsServer.NotifySecureRenegotiation(this.mSecureRenegotiation);

            if (mClientExtensions != null)
            {
                // NOTE: Validates the padding extension data, if present
                TlsExtensionsUtilities.GetPaddingExtension(mClientExtensions);

                mTlsServer.ProcessClientExtensions(mClientExtensions);
            }
        }
Beispiel #16
0
        public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
        {
            byte[] record = null;

            for (;;)
            {
                int receiveLimit = System.Math.Min(len, GetReceiveLimit()) + RECORD_HEADER_LENGTH;
                if (record == null || record.Length < receiveLimit)
                {
                    record = new byte[receiveLimit];
                }

                try
                {
                    if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry)
                    {
                        mRetransmit = null;
                        mRetransmitEpoch = null;
                    }

                    int received = ReceiveRecord(record, 0, receiveLimit, waitMillis);
                    if (received < 0)
                    {
                        return received;
                    }
                    if (received < RECORD_HEADER_LENGTH)
                    {
                        continue;
                    }
                    int length = TlsUtilities.ReadUint16(record, 11);
                    if (received != (length + RECORD_HEADER_LENGTH))
                    {
                        continue;
                    }

                    byte type = TlsUtilities.ReadUint8(record, 0);

                    // TODO Support user-specified custom protocols?
                    switch (type)
                    {
                    case ContentType.alert:
                    case ContentType.application_data:
                    case ContentType.change_cipher_spec:
                    case ContentType.handshake:
                    case ContentType.heartbeat:
                        break;
                    default:
                        // TODO Exception?
                        continue;
                    }

                    int epoch = TlsUtilities.ReadUint16(record, 3);

                    DtlsEpoch recordEpoch = null;
                    if (epoch == mReadEpoch.Epoch)
                    {
                        recordEpoch = mReadEpoch;
                    }
                    else if (type == ContentType.handshake && mRetransmitEpoch != null
                        && epoch == mRetransmitEpoch.Epoch)
                    {
                        recordEpoch = mRetransmitEpoch;
                    }

                    if (recordEpoch == null)
                    {
                        continue;
                    }

                    long seq = TlsUtilities.ReadUint48(record, 5);
                    if (recordEpoch.ReplayWindow.ShouldDiscard(seq))
                    {
                        continue;
                    }

                    ProtocolVersion version = TlsUtilities.ReadVersion(record, 1);
                    if (!version.IsDtls)
                    {
                        continue;
                    }

                    if (mReadVersion != null && !mReadVersion.Equals(version))
                    {
                        continue;
                    }

                    byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext(
                        GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH,
                        received - RECORD_HEADER_LENGTH);

                    recordEpoch.ReplayWindow.ReportAuthenticated(seq);

                    if (plaintext.Length > this.mPlaintextLimit)
                    {
                        continue;
                    }

                    if (mReadVersion == null)
                    {
                        mReadVersion = version;
                    }

                    switch (type)
                    {
                    case ContentType.alert:
                    {
                        if (plaintext.Length == 2)
                        {
                            byte alertLevel = plaintext[0];
                            byte alertDescription = plaintext[1];

                            mPeer.NotifyAlertReceived(alertLevel, alertDescription);

                            if (alertLevel == AlertLevel.fatal)
                            {
                                Failed();
                                throw new TlsFatalAlert(alertDescription);
                            }

                            // TODO Can close_notify be a fatal alert?
                            if (alertDescription == AlertDescription.close_notify)
                            {
                                CloseTransport();
                            }
                        }

                        continue;
                    }
                    case ContentType.application_data:
                    {
                        if (mInHandshake)
                        {
                            // TODO Consider buffering application data for new epoch that arrives
                            // out-of-order with the Finished message
                            continue;
                        }
                        break;
                    }
                    case ContentType.change_cipher_spec:
                    {
                        // Implicitly receive change_cipher_spec and change to pending cipher state

                        for (int i = 0; i < plaintext.Length; ++i)
                        {
                            byte message = TlsUtilities.ReadUint8(plaintext, i);
                            if (message != ChangeCipherSpec.change_cipher_spec)
                            {
                                continue;
                            }

                            if (mPendingEpoch != null)
                            {
                                mReadEpoch = mPendingEpoch;
                            }
                        }

                        continue;
                    }
                    case ContentType.handshake:
                    {
                        if (!mInHandshake)
                        {
                            if (mRetransmit != null)
                            {
                                mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length);
                            }

                            // TODO Consider support for HelloRequest
                            continue;
                        }
                        break;
                    }
                    case ContentType.heartbeat:
                    {
                        // TODO[RFC 6520]
                        continue;
                    }
                    }

                    /*
                     * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
                     * received our final flight.
                     */
                    if (!mInHandshake && mRetransmit != null)
                    {
                        this.mRetransmit = null;
                        this.mRetransmitEpoch = null;
                    }

                    Array.Copy(plaintext, 0, buf, off, plaintext.Length);
                    return plaintext.Length;
                }
                catch (IOException e)
                {
                    // NOTE: Assume this is a timeout for the moment
                    throw e;
                }
            }
        }
        public virtual void Init(TlsContext context)
        {
            this.mContext = context;

            ProtocolVersion clientVersion = context.ClientVersion;

            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
            {
                /*
                 * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension,
                 * the server MUST do the following:
                 *
                 * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK,
                 * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}.
                 *
                 * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if
                 * the client had sent the value {sha1,dsa}.
                 *
                 * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA),
                 * behave as if the client had sent value {sha1,ecdsa}.
                 */
                if (this.mSupportedSignatureAlgorithms == null)
                {
                    switch (mKeyExchange)
                    {
                    case KeyExchangeAlgorithm.DH_DSS:
                    case KeyExchangeAlgorithm.DHE_DSS:
                    case KeyExchangeAlgorithm.SRP_DSS:
                    {
                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultDssSignatureAlgorithms();
                        break;
                    }

                    case KeyExchangeAlgorithm.ECDH_ECDSA:
                    case KeyExchangeAlgorithm.ECDHE_ECDSA:
                    {
                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
                        break;
                    }

                    case KeyExchangeAlgorithm.DH_RSA:
                    case KeyExchangeAlgorithm.DHE_RSA:
                    case KeyExchangeAlgorithm.ECDH_RSA:
                    case KeyExchangeAlgorithm.ECDHE_RSA:
                    case KeyExchangeAlgorithm.RSA:
                    case KeyExchangeAlgorithm.RSA_PSK:
                    case KeyExchangeAlgorithm.SRP_RSA:
                    {
                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
                        break;
                    }

                    case KeyExchangeAlgorithm.DHE_PSK:
                    case KeyExchangeAlgorithm.ECDHE_PSK:
                    case KeyExchangeAlgorithm.PSK:
                    case KeyExchangeAlgorithm.SRP:
                        break;

                    default:
                        throw new InvalidOperationException("unsupported key exchange algorithm");
                    }
                }
            }
            else if (this.mSupportedSignatureAlgorithms != null)
            {
                throw new InvalidOperationException("supported_signature_algorithms not allowed for " + clientVersion);
            }
        }
Beispiel #18
0
 internal virtual void SetWriteVersion(ProtocolVersion writeVersion)
 {
     this.mWriteVersion = writeVersion;
 }
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            ProtocolVersion writeVersion = TlsUtilities.ReadVersion(buf);

            if (writeVersion.IsDtls)
            {
                throw new TlsFatalAlert(0x2f);
            }
            if (!writeVersion.Equals(base.mRecordStream.ReadVersion))
            {
                throw new TlsFatalAlert(0x2f);
            }
            ProtocolVersion clientVersion = this.Context.ClientVersion;

            if (!writeVersion.IsEqualOrEarlierVersionOf(clientVersion))
            {
                throw new TlsFatalAlert(0x2f);
            }
            base.mRecordStream.SetWriteVersion(writeVersion);
            this.ContextAdmin.SetServerVersion(writeVersion);
            this.mTlsClient.NotifyServerVersion(writeVersion);
            base.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(0x20, buf);
            this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (this.mSelectedSessionID.Length > 0x20)
            {
                throw new TlsFatalAlert(0x2f);
            }
            this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
            base.mResumedSession = ((this.mSelectedSessionID.Length > 0) && (base.mTlsSession != null)) && Arrays.AreEqual(this.mSelectedSessionID, base.mTlsSession.SessionID);
            int n = TlsUtilities.ReadUint16(buf);

            if ((!Arrays.Contains(base.mOfferedCipherSuites, n) || (n == 0)) || (CipherSuite.IsScsv(n) || !TlsUtilities.IsValidCipherSuiteForVersion(n, this.Context.ServerVersion)))
            {
                throw new TlsFatalAlert(0x2f);
            }
            this.mTlsClient.NotifySelectedCipherSuite(n);
            byte num2 = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(base.mOfferedCompressionMethods, num2))
            {
                throw new TlsFatalAlert(0x2f);
            }
            this.mTlsClient.NotifySelectedCompressionMethod(num2);
            base.mServerExtensions = TlsProtocol.ReadExtensions(buf);
            if (base.mServerExtensions != null)
            {
                IEnumerator enumerator = base.mServerExtensions.Keys.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        int current = (int)enumerator.Current;
                        if (current != 0xff01)
                        {
                            if (TlsUtilities.GetExtensionData(base.mClientExtensions, current) == null)
                            {
                                throw new TlsFatalAlert(110);
                            }
                            if (base.mResumedSession)
                            {
                            }
                        }
                    }
                }
                finally
                {
                    if (enumerator is IDisposable disposable)
                    {
                        IDisposable disposable;
                        disposable.Dispose();
                    }
                }
            }
            byte[] extensionData = TlsUtilities.GetExtensionData(base.mServerExtensions, 0xff01);
            if (extensionData != null)
            {
                base.mSecureRenegotiation = true;
                if (!Arrays.ConstantTimeAreEqual(extensionData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                {
                    throw new TlsFatalAlert(40);
                }
            }
            this.mTlsClient.NotifySecureRenegotiation(base.mSecureRenegotiation);
            IDictionary mClientExtensions = base.mClientExtensions;
            IDictionary mServerExtensions = base.mServerExtensions;

            if (base.mResumedSession)
            {
                if ((n != base.mSessionParameters.CipherSuite) || (num2 != base.mSessionParameters.CompressionAlgorithm))
                {
                    throw new TlsFatalAlert(0x2f);
                }
                mClientExtensions = null;
                mServerExtensions = base.mSessionParameters.ReadServerExtensions();
            }
            base.mSecurityParameters.cipherSuite          = n;
            base.mSecurityParameters.compressionAlgorithm = num2;
            if (mServerExtensions != null)
            {
                bool flag = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
                if (flag && !TlsUtilities.IsBlockCipherSuite(n))
                {
                    throw new TlsFatalAlert(0x2f);
                }
                base.mSecurityParameters.encryptThenMac       = flag;
                base.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mServerExtensions);
                base.mSecurityParameters.maxFragmentLength    = this.ProcessMaxFragmentLengthExtension(mClientExtensions, mServerExtensions, 0x2f);
                base.mSecurityParameters.truncatedHMac        = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);
                base.mAllowCertificateStatus = !base.mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 5, 0x2f);
                base.mExpectSessionTicket    = !base.mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 0x23, 0x2f);
            }
            if (mClientExtensions != null)
            {
                this.mTlsClient.ProcessServerExtensions(mServerExtensions);
            }
            base.mSecurityParameters.prfAlgorithm     = TlsProtocol.GetPrfAlgorithm(this.Context, base.mSecurityParameters.CipherSuite);
            base.mSecurityParameters.verifyDataLength = 12;
        }
Beispiel #20
0
 public static void WriteVersion(ProtocolVersion version, Stream output)
 {
     output.WriteByte((byte)version.MajorVersion);
     output.WriteByte((byte)version.MinorVersion);
 }
Beispiel #21
0
        protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
        {
            SecurityParameters securityParameters = state.serverContext.SecurityParameters;

            MemoryStream buf = new MemoryStream();

            ProtocolVersion server_version = state.server.GetServerVersion();

            if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            // TODO Read RFCs for guidance on the expected record layer version number
            // recordStream.setReadVersion(server_version);
            // recordStream.setWriteVersion(server_version);
            // recordStream.setRestrictReadVersion(true);
            state.serverContext.SetServerVersion(server_version);

            TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);

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

            /*
             * The server may return an empty session_id to indicate that the session will not be cached
             * and therefore cannot be resumed.
             */
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            state.selectedCipherSuite = state.server.GetSelectedCipherSuite();
            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.internal_error);
            }

            ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.internal_error);

            state.selectedCompressionMethod = state.server.GetSelectedCompressionMethod();
            if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            TlsUtilities.WriteUint16(state.selectedCipherSuite, buf);
            TlsUtilities.WriteUint8((byte)state.selectedCompressionMethod, buf);

            state.serverExtensions = state.server.GetServerExtensions();

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            if (state.secure_renegotiation)
            {
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                if (noRenegExt)
                {
                    /*
                     * 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 the secure_renegotiation flag is set to TRUE, the server MUST include an empty
                     * "renegotiation_info" extension in the ServerHello message.
                     */
                    state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
                    state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                }
            }

            if (securityParameters.extendedMasterSecret)
            {
                state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
            }

            if (state.serverExtensions != null)
            {
                securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);

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

                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);

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

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

                TlsProtocol.WriteExtensions(buf, state.serverExtensions);
            }

            return(buf.ToArray());
        }
 internal virtual void SetClientVersion(ProtocolVersion clientVersion)
 {
     this.mClientVersion = clientVersion;
 }
Beispiel #23
0
        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
        {
            int             blockSize     = this.encryptCipher.GetBlockSize();
            int             size          = this.mWriteMac.Size;
            ProtocolVersion serverVersion = this.context.ServerVersion;
            int             num3          = len;

            if (!this.encryptThenMac)
            {
                num3 += size;
            }
            int num4 = (blockSize - 1) - (num3 % blockSize);

            if (!serverVersion.IsDtls && !serverVersion.IsSsl)
            {
                int max  = (0xff - num4) / blockSize;
                int num6 = this.ChooseExtraPadBlocks(this.context.SecureRandom, max);
                num4 += num6 * blockSize;
            }
            int num7 = ((len + size) + num4) + 1;

            if (this.useExplicitIV)
            {
                num7 += blockSize;
            }
            byte[] destinationArray = new byte[num7];
            int    destinationIndex = 0;

            if (this.useExplicitIV)
            {
                byte[] bytes = new byte[blockSize];
                this.context.NonceRandomGenerator.NextBytes(bytes);
                this.encryptCipher.Init(true, new ParametersWithIV(null, bytes));
                Array.Copy(bytes, 0, destinationArray, destinationIndex, blockSize);
                destinationIndex += blockSize;
            }
            int num9 = destinationIndex;

            Array.Copy(plaintext, offset, destinationArray, destinationIndex, len);
            destinationIndex += len;
            if (!this.encryptThenMac)
            {
                byte[] sourceArray = this.mWriteMac.CalculateMac(seqNo, type, plaintext, offset, len);
                Array.Copy(sourceArray, 0, destinationArray, destinationIndex, sourceArray.Length);
                destinationIndex += sourceArray.Length;
            }
            for (int i = 0; i <= num4; i++)
            {
                destinationArray[destinationIndex++] = (byte)num4;
            }
            for (int j = num9; j < destinationIndex; j += blockSize)
            {
                this.encryptCipher.ProcessBlock(destinationArray, j, destinationArray, j);
            }
            if (this.encryptThenMac)
            {
                byte[] sourceArray = this.mWriteMac.CalculateMac(seqNo, type, destinationArray, 0, destinationIndex);
                Array.Copy(sourceArray, 0, destinationArray, destinationIndex, sourceArray.Length);
                destinationIndex += sourceArray.Length;
            }
            return(destinationArray);
        }
Beispiel #24
0
        protected virtual void SendClientHelloMessage()
        {
            this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);

            ProtocolVersion client_version = this.mTlsClient.ClientVersion;

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

            ContextAdmin.SetClientVersion(client_version);

            /*
             * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
             * Session ID in the TLS ClientHello.
             */
            byte[] session_id = TlsUtilities.EmptyBytes;
            if (this.mTlsSession != null)
            {
                session_id = this.mTlsSession.SessionID;
                if (session_id == null || session_id.Length > 32)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            bool fallback = this.mTlsClient.IsFallback;

            this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();

            this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();

            if (session_id.Length > 0 && this.mSessionParameters != null)
            {
                if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite) ||
                    !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            this.mClientExtensions = this.mTlsClient.GetClientExtensions();

            HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);

            TlsUtilities.WriteVersion(client_version, message);

            message.Write(this.mSecurityParameters.ClientRandom);

            TlsUtilities.WriteOpaque8(session_id, message);

            // 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(mClientExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);

                if (noRenegExt && noRenegScsv)
                {
                    // TODO Consider whether to default to a client extension instead
                    //                this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
                    //                this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, 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(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
                {
                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
                }

                TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
            }

            TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);

            if (mClientExtensions != null)
            {
                WriteExtensions(message, mClientExtensions);
            }

            message.WriteToRecordStream(this);
        }
 internal virtual void SetServerVersion(ProtocolVersion serverVersion)
 {
     this.mServerVersion = serverVersion;
 }
Beispiel #26
0
        protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            // TODO Read RFCs for guidance on the expected record layer version number
            ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);

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

            /*
             * Read the client random
             */
            byte[] client_random = TlsUtilities.ReadFully(32, buf);

            byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
            if (sessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            // TODO RFC 4347 has the cookie length restricted to 32, but not in RFC 6347
            byte[] cookie = TlsUtilities.ReadOpaque8(buf);

            int cipher_suites_length = TlsUtilities.ReadUint16(buf);

            if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
            {
                throw new TlsFatalAlert(AlertDescription.decode_error);
            }

            /*
             * NOTE: "If the session_id field is not empty (implying a session resumption request) this
             * vector must include at least the cipher_suite from that session."
             */
            state.offeredCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);

            int compression_methods_length = TlsUtilities.ReadUint8(buf);

            if (compression_methods_length < 1)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            state.offeredCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);

            /*
             * 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.
             */
            state.clientExtensions = TlsProtocol.ReadExtensions(buf);

            TlsServerContextImpl context            = state.serverContext;
            SecurityParameters   securityParameters = context.SecurityParameters;

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

            context.SetClientVersion(client_version);

            state.server.NotifyClientVersion(client_version);
            state.server.NotifyFallback(Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));

            securityParameters.clientRandom = client_random;

            state.server.NotifyOfferedCipherSuites(state.offeredCipherSuites);
            state.server.NotifyOfferedCompressionMethods(state.offeredCompressionMethods);

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            {
                /*
                 * 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.
                 */

                /*
                 * When a ClientHello is received, the server MUST check if it includes the
                 * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
                 * to TRUE.
                 */
                if (Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
                {
                    state.secure_renegotiation = true;
                }

                /*
                 * The server MUST check if the "renegotiation_info" extension is included in the
                 * ClientHello.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                     * If the extension is present, set secure_renegotiation flag to TRUE. The
                     * server MUST then verify that the length of the "renegotiated_connection"
                     * field is zero, and if it is not, MUST abort the handshake.
                     */
                    state.secure_renegotiation = true;

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

            state.server.NotifySecureRenegotiation(state.secure_renegotiation);

            if (state.clientExtensions != null)
            {
                state.server.ProcessClientExtensions(state.clientExtensions);
            }
        }
Beispiel #27
0
 internal virtual void SetClientVersion(ProtocolVersion clientVersion)
 {
     mClientVersion = clientVersion;
 }
Beispiel #28
0
        public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
        {
            byte[] record = null;

            for (;;)
            {
                int receiveLimit = System.Math.Min(len, GetReceiveLimit()) + RECORD_HEADER_LENGTH;
                if (record == null || record.Length < receiveLimit)
                {
                    record = new byte[receiveLimit];
                }

                try
                {
                    if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry)
                    {
                        mRetransmit      = null;
                        mRetransmitEpoch = null;
                    }

                    int received = ReceiveRecord(record, 0, receiveLimit, waitMillis);
                    if (received < 0)
                    {
                        return(received);
                    }
                    if (received < RECORD_HEADER_LENGTH)
                    {
                        continue;
                    }
                    int length = TlsUtilities.ReadUint16(record, 11);
                    if (received != (length + RECORD_HEADER_LENGTH))
                    {
                        continue;
                    }

                    byte type = TlsUtilities.ReadUint8(record, 0);

                    // TODO Support user-specified custom protocols?
                    switch (type)
                    {
                    case ContentType.alert:
                    case ContentType.application_data:
                    case ContentType.change_cipher_spec:
                    case ContentType.handshake:
                    case ContentType.heartbeat:
                        break;

                    default:
                        // TODO Exception?
                        continue;
                    }

                    int epoch = TlsUtilities.ReadUint16(record, 3);

                    DtlsEpoch recordEpoch = null;
                    if (epoch == mReadEpoch.Epoch)
                    {
                        recordEpoch = mReadEpoch;
                    }
                    else if (type == ContentType.handshake && mRetransmitEpoch != null &&
                             epoch == mRetransmitEpoch.Epoch)
                    {
                        recordEpoch = mRetransmitEpoch;
                    }

                    if (recordEpoch == null)
                    {
                        continue;
                    }

                    long seq = TlsUtilities.ReadUint48(record, 5);
                    if (recordEpoch.ReplayWindow.ShouldDiscard(seq))
                    {
                        continue;
                    }

                    ProtocolVersion version = TlsUtilities.ReadVersion(record, 1);
                    if (!version.IsDtls)
                    {
                        continue;
                    }

                    if (mReadVersion != null && !mReadVersion.Equals(version))
                    {
                        continue;
                    }

                    byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext(
                        GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH,
                        received - RECORD_HEADER_LENGTH);

                    recordEpoch.ReplayWindow.ReportAuthenticated(seq);

                    if (plaintext.Length > this.mPlaintextLimit)
                    {
                        continue;
                    }

                    if (mReadVersion == null)
                    {
                        mReadVersion = version;
                    }

                    switch (type)
                    {
                    case ContentType.alert:
                    {
                        if (plaintext.Length == 2)
                        {
                            byte alertLevel       = plaintext[0];
                            byte alertDescription = plaintext[1];

                            mPeer.NotifyAlertReceived(alertLevel, alertDescription);

                            if (alertLevel == AlertLevel.fatal)
                            {
                                Failed();
                                throw new TlsFatalAlert(alertDescription);
                            }

                            // TODO Can close_notify be a fatal alert?
                            if (alertDescription == AlertDescription.close_notify)
                            {
                                CloseTransport();
                            }
                        }

                        continue;
                    }

                    case ContentType.application_data:
                    {
                        if (mInHandshake)
                        {
                            // TODO Consider buffering application data for new epoch that arrives
                            // out-of-order with the Finished message
                            continue;
                        }
                        break;
                    }

                    case ContentType.change_cipher_spec:
                    {
                        // Implicitly receive change_cipher_spec and change to pending cipher state

                        for (int i = 0; i < plaintext.Length; ++i)
                        {
                            byte message = TlsUtilities.ReadUint8(plaintext, i);
                            if (message != ChangeCipherSpec.change_cipher_spec)
                            {
                                continue;
                            }

                            if (mPendingEpoch != null)
                            {
                                mReadEpoch = mPendingEpoch;
                            }
                        }

                        continue;
                    }

                    case ContentType.handshake:
                    {
                        if (!mInHandshake)
                        {
                            if (mRetransmit != null)
                            {
                                mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length);
                            }

                            // TODO Consider support for HelloRequest
                            continue;
                        }
                        break;
                    }

                    case ContentType.heartbeat:
                    {
                        // TODO[RFC 6520]
                        continue;
                    }
                    }

                    /*
                     * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
                     * received our final flight.
                     */
                    if (!mInHandshake && mRetransmit != null)
                    {
                        this.mRetransmit      = null;
                        this.mRetransmitEpoch = null;
                    }

                    Array.Copy(plaintext, 0, buf, off, plaintext.Length);
                    return(plaintext.Length);
                }
                catch (IOException e)
                {
                    // NOTE: Assume this is a timeout for the moment
                    throw e;
                }
            }
        }
Beispiel #29
0
 internal virtual void SetServerVersion(ProtocolVersion serverVersion)
 {
     mServerVersion = serverVersion;
 }
Beispiel #30
0
 internal virtual void SetWriteVersion(ProtocolVersion writeVersion)
 {
     this.mWriteVersion = writeVersion;
 }
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(buf);

            if (protocolVersion.IsDtls)
            {
                throw new TlsFatalAlert(47);
            }
            if (!protocolVersion.Equals(mRecordStream.ReadVersion))
            {
                throw new TlsFatalAlert(47);
            }
            ProtocolVersion clientVersion = Context.ClientVersion;

            if (!protocolVersion.IsEqualOrEarlierVersionOf(clientVersion))
            {
                throw new TlsFatalAlert(47);
            }
            mRecordStream.SetWriteVersion(protocolVersion);
            ContextAdmin.SetServerVersion(protocolVersion);
            mTlsClient.NotifyServerVersion(protocolVersion);
            mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
            mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (mSelectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySessionID(mSelectedSessionID);
            mResumedSession = (mSelectedSessionID.Length > 0 && mTlsSession != null && Arrays.AreEqual(mSelectedSessionID, mTlsSession.SessionID));
            int num = TlsUtilities.ReadUint16(buf);

            if (!Arrays.Contains(mOfferedCipherSuites, num) || num == 0 || CipherSuite.IsScsv(num) || !TlsUtilities.IsValidCipherSuiteForVersion(num, Context.ServerVersion))
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySelectedCipherSuite(num);
            byte b = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(mOfferedCompressionMethods, b))
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySelectedCompressionMethod(b);
            mServerExtensions = TlsProtocol.ReadExtensions(buf);
            if (mServerExtensions != null)
            {
                foreach (int key in mServerExtensions.Keys)
                {
                    if (key != 65281)
                    {
                        if (TlsUtilities.GetExtensionData(mClientExtensions, key) == null)
                        {
                            throw new TlsFatalAlert(110);
                        }
                        if (!mResumedSession)
                        {
                        }
                    }
                }
            }
            byte[] extensionData = TlsUtilities.GetExtensionData(mServerExtensions, 65281);
            if (extensionData != null)
            {
                mSecureRenegotiation = true;
                if (!Arrays.ConstantTimeAreEqual(extensionData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                {
                    throw new TlsFatalAlert(40);
                }
            }
            mTlsClient.NotifySecureRenegotiation(mSecureRenegotiation);
            IDictionary dictionary  = mClientExtensions;
            IDictionary dictionary2 = mServerExtensions;

            if (mResumedSession)
            {
                if (num != mSessionParameters.CipherSuite || b != mSessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(47);
                }
                dictionary  = null;
                dictionary2 = mSessionParameters.ReadServerExtensions();
            }
            mSecurityParameters.cipherSuite          = num;
            mSecurityParameters.compressionAlgorithm = b;
            if (dictionary2 != null)
            {
                bool flag = TlsExtensionsUtilities.HasEncryptThenMacExtension(dictionary2);
                if (flag && !TlsUtilities.IsBlockCipherSuite(num))
                {
                    throw new TlsFatalAlert(47);
                }
                mSecurityParameters.encryptThenMac       = flag;
                mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(dictionary2);
                mSecurityParameters.maxFragmentLength    = ProcessMaxFragmentLengthExtension(dictionary, dictionary2, 47);
                mSecurityParameters.truncatedHMac        = TlsExtensionsUtilities.HasTruncatedHMacExtension(dictionary2);
                mAllowCertificateStatus = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 5, 47));
                mExpectSessionTicket    = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 35, 47));
            }
            if (dictionary != null)
            {
                mTlsClient.ProcessServerExtensions(dictionary2);
            }
            mSecurityParameters.prfAlgorithm     = TlsProtocol.GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
            mSecurityParameters.verifyDataLength = 12;
        }
 internal virtual ProtocolVersion ResetDiscoveredPeerVersion()
 {
     ProtocolVersion result = mDiscoveredPeerVersion;
     mDiscoveredPeerVersion = null;
     return result;
 }
Beispiel #33
0
        public virtual IDictionary GetClientExtensions()
        {
            IDictionary clientExtensions = null;

            ProtocolVersion clientVersion = mContext.ClientVersion;

            /*
             * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior to 1.2.
             * Clients MUST NOT offer it if they are offering prior versions.
             */
            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
            {
                // TODO Provide a way for the user to specify the acceptable hash/signature algorithms.

                byte[] hashAlgorithms = new byte[] { HashAlgorithm.sha512, HashAlgorithm.sha384, HashAlgorithm.sha256,
                                                     HashAlgorithm.sha224, HashAlgorithm.sha1 };

                // TODO Sort out ECDSA signatures and add them as the preferred option here
                byte[] signatureAlgorithms = new byte[] { SignatureAlgorithm.rsa };

                this.mSupportedSignatureAlgorithms = Platform.CreateArrayList();
                for (int i = 0; i < hashAlgorithms.Length; ++i)
                {
                    for (int j = 0; j < signatureAlgorithms.Length; ++j)
                    {
                        this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(hashAlgorithms[i],
                                                                                             signatureAlgorithms[j]));
                    }
                }

                /*
                 * RFC 5264 7.4.3. Currently, DSA [DSS] may only be used with SHA-1.
                 */
                this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(HashAlgorithm.sha1,
                                                                                     SignatureAlgorithm.dsa));

                clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);

                TlsUtilities.AddSignatureAlgorithmsExtension(clientExtensions, mSupportedSignatureAlgorithms);
            }

            if (TlsEccUtilities.ContainsEccCipherSuites(GetCipherSuites()))
            {
                /*
                 * RFC 4492 5.1. A client that proposes ECC cipher suites in its ClientHello message
                 * appends these extensions (along with any others), enumerating the curves it supports
                 * and the point formats it can parse. Clients SHOULD send both the Supported Elliptic
                 * Curves Extension and the Supported Point Formats Extension.
                 */
                /*
                 * TODO Could just add all the curves since we support them all, but users may not want
                 * to use unnecessarily large fields. Need configuration options.
                 */
                this.mNamedCurves          = new int[] { NamedCurve.secp256r1, NamedCurve.secp384r1 };
                this.mClientECPointFormats = new byte[] { ECPointFormat.uncompressed,
                                                          ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };

                clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);

                TlsEccUtilities.AddSupportedEllipticCurvesExtension(clientExtensions, mNamedCurves);
                TlsEccUtilities.AddSupportedPointFormatsExtension(clientExtensions, mClientECPointFormats);
            }

            return(clientExtensions);
        }
 public virtual ProtocolVersion GetServerVersion()
 {
     if (MinimumVersion.IsEqualOrEarlierVersionOf(mClientVersion))
     {
         ProtocolVersion maximumVersion = MaximumVersion;
         if (mClientVersion.IsEqualOrEarlierVersionOf(maximumVersion))
         {
             return mServerVersion = mClientVersion;
         }
         if (mClientVersion.IsLaterVersionOf(maximumVersion))
         {
             return mServerVersion = maximumVersion;
         }
     }
     throw new TlsFatalAlert(AlertDescription.protocol_version);
 }
Beispiel #35
0
 public bool Equals(ProtocolVersion other)
 {
     return(other != null && version == other.version);
 }
Beispiel #36
0
        internal virtual bool ReadRecord()
        {
            byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput);
            if (recordHeader == null)
                return false;

            byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);

            /*
             * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
             * unexpected_message alert.
             */
            CheckType(type, AlertDescription.unexpected_message);

            if (!mRestrictReadVersion)
            {
                int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
                if ((version & 0xffffff00) != 0x0300)
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            else
            {
                ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
                if (mReadVersion == null)
                {
                    mReadVersion = version;
                }
                else if (!version.Equals(mReadVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }
            }

            int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);
            byte[] plaintext = DecodeAndVerify(type, mInput, length);
            mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length);
            return true;
        }
Beispiel #37
0
        protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
        {
            ProtocolVersion client_version = client.ClientVersion;

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

            TlsClientContextImpl context = state.clientContext;

            context.SetClientVersion(client_version);

            SecurityParameters securityParameters = context.SecurityParameters;

            // 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;
                }
            }

            bool fallback = client.IsFallback;

            state.offeredCipherSuites = client.GetCipherSuites();

            if (session_id.Length > 0 && state.sessionParameters != null)
            {
                if (!state.sessionParameters.IsExtendedMasterSecret ||
                    !Arrays.Contains(state.offeredCipherSuites, state.sessionParameters.CipherSuite) ||
                    CompressionMethod.cls_null != state.sessionParameters.CompressionAlgorithm)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(client.GetClientExtensions());

            TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions);

            MemoryStream buf = new MemoryStream();

            TlsUtilities.WriteVersion(client_version, buf);

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

            TlsUtilities.WriteOpaque8(session_id, buf);

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

            // 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);
                }

                /*
                 * RFC 7507 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 [..]. (The
                 * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
                 * to negotiate.)
                 */
                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);
            }

            TlsUtilities.WriteUint8ArrayWithUint8Length(new byte[] { CompressionMethod.cls_null }, buf);

            TlsProtocol.WriteExtensions(buf, state.clientExtensions);

            return(buf.ToArray());
        }
 public virtual void NotifyServerVersion(ProtocolVersion serverVersion)
 {
     if (!MinimumVersion.IsEqualOrEarlierVersionOf(serverVersion))
         throw new TlsFatalAlert(AlertDescription.protocol_version);
 }
        public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
        {
            byte[] array = null;
            int    result;

            while (true)
            {
                int num = Math.Min(len, this.GetReceiveLimit()) + 13;
                if (array == null || array.Length < num)
                {
                    array = new byte[num];
                }
                try
                {
                    if (this.mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > this.mRetransmitExpiry)
                    {
                        this.mRetransmit      = null;
                        this.mRetransmitEpoch = null;
                    }
                    int num2 = this.ReceiveRecord(array, 0, num, waitMillis);
                    if (num2 < 0)
                    {
                        result = num2;
                    }
                    else
                    {
                        if (num2 < 13)
                        {
                            continue;
                        }
                        int num3 = TlsUtilities.ReadUint16(array, 11);
                        if (num2 != num3 + 13)
                        {
                            continue;
                        }
                        byte b = TlsUtilities.ReadUint8(array, 0);
                        switch (b)
                        {
                        case 20:
                        case 21:
                        case 22:
                        case 23:
                        case 24:
                        {
                            int       num4      = TlsUtilities.ReadUint16(array, 3);
                            DtlsEpoch dtlsEpoch = null;
                            if (num4 == this.mReadEpoch.Epoch)
                            {
                                dtlsEpoch = this.mReadEpoch;
                            }
                            else if (b == 22 && this.mRetransmitEpoch != null && num4 == this.mRetransmitEpoch.Epoch)
                            {
                                dtlsEpoch = this.mRetransmitEpoch;
                            }
                            if (dtlsEpoch == null)
                            {
                                continue;
                            }
                            long num5 = TlsUtilities.ReadUint48(array, 5);
                            if (dtlsEpoch.ReplayWindow.ShouldDiscard(num5))
                            {
                                continue;
                            }
                            ProtocolVersion other = TlsUtilities.ReadVersion(array, 1);
                            if (this.mDiscoveredPeerVersion != null && !this.mDiscoveredPeerVersion.Equals(other))
                            {
                                continue;
                            }
                            byte[] array2 = dtlsEpoch.Cipher.DecodeCiphertext(DtlsRecordLayer.GetMacSequenceNumber(dtlsEpoch.Epoch, num5), b, array, 13, num2 - 13);
                            dtlsEpoch.ReplayWindow.ReportAuthenticated(num5);
                            if (array2.Length > this.mPlaintextLimit)
                            {
                                continue;
                            }
                            if (this.mDiscoveredPeerVersion == null)
                            {
                                this.mDiscoveredPeerVersion = other;
                            }
                            switch (b)
                            {
                            case 20:
                                for (int i = 0; i < array2.Length; i++)
                                {
                                    byte b2 = TlsUtilities.ReadUint8(array2, i);
                                    if (b2 == 1 && this.mPendingEpoch != null)
                                    {
                                        this.mReadEpoch = this.mPendingEpoch;
                                    }
                                }
                                continue;

                            case 21:
                                if (array2.Length == 2)
                                {
                                    byte b3 = array2[0];
                                    byte b4 = array2[1];
                                    this.mPeer.NotifyAlertReceived(b3, b4);
                                    if (b3 == 2)
                                    {
                                        this.Fail(b4);
                                        throw new TlsFatalAlert(b4);
                                    }
                                    if (b4 == 0)
                                    {
                                        this.CloseTransport();
                                    }
                                }
                                continue;

                            case 22:
                                if (!this.mInHandshake)
                                {
                                    if (this.mRetransmit != null)
                                    {
                                        this.mRetransmit.ReceivedHandshakeRecord(num4, array2, 0, array2.Length);
                                    }
                                    continue;
                                }
                                break;

                            case 23:
                                if (this.mInHandshake)
                                {
                                    continue;
                                }
                                break;

                            case 24:
                                continue;
                            }
                            if (!this.mInHandshake && this.mRetransmit != null)
                            {
                                this.mRetransmit      = null;
                                this.mRetransmitEpoch = null;
                            }
                            Array.Copy(array2, 0, buf, off, array2.Length);
                            result = array2.Length;
                            break;
                        }

                        default:
                            continue;
                        }
                    }
                }
                catch (IOException ex)
                {
                    throw ex;
                }
                break;
            }
            return(result);
        }
Beispiel #40
0
 public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion)
 {
     return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion());
 }
Beispiel #41
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());
        }
Beispiel #42
0
 public static void WriteVersion(ProtocolVersion version, byte[] buf, int offset)
 {
     buf[offset] = (byte)version.MajorVersion;
     buf[offset + 1] = (byte)version.MinorVersion;
 }
Beispiel #43
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);
            }
        }
Beispiel #44
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)
                                          .Build();

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

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

            state.client.NotifyHandshakeComplete();

            return(new DtlsTransport(recordLayer));
        }
Beispiel #45
0
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            {
                ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
                if (server_version.IsDtls)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                // Check that this matches what the server is Sending in the record layer
                if (!server_version.Equals(this.mRecordStream.ReadVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                ProtocolVersion client_version = Context.ClientVersion;
                if (!server_version.IsEqualOrEarlierVersionOf(client_version))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                this.mRecordStream.SetWriteVersion(server_version);
                ContextAdmin.SetServerVersion(server_version);
                this.mTlsClient.NotifyServerVersion(server_version);
            }

            /*
             * Read the server random
             */
            this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);

            this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (this.mSelectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
            this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null &&
                                   Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);

            /*
             * Find out which CipherSuite the server has chosen and check that it was one of the offered
             * ones, and is a valid selection for the negotiated version.
             */
            int selectedCipherSuite = TlsUtilities.ReadUint16(buf);

            if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);

            /*
             * Find out which CompressionMethod the server has chosen and check that it was one of the
             * offered ones.
             */
            byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.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.
             */
            this.mServerExtensions = 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 (this.mServerExtensions != null)
            {
                foreach (int extType in this.mServerExtensions.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(this.mClientExtensions, 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 (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 = TlsUtilities.GetExtensionData(this.mServerExtensions, 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).
                     */
                    this.mSecureRenegotiation = true;

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

            // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
            this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);

            IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;

            if (this.mResumedSession)
            {
                if (selectedCipherSuite != this.mSessionParameters.CipherSuite ||
                    selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                sessionClientExtensions = null;
                sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
            }

            this.mSecurityParameters.cipherSuite          = selectedCipherSuite;
            this.mSecurityParameters.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(selectedCipherSuite))
                    {
                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }

                    this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
                }

                this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);

                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
                                                                                               sessionServerExtensions, AlertDescription.illegal_parameter);

                this.mSecurityParameters.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.
                 */
                this.mAllowCertificateStatus = !this.mResumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.illegal_parameter);

                this.mExpectSessionTicket = !this.mResumedSession &&
                                            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)
            {
                this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
            }

            this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.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.
             */
            this.mSecurityParameters.verifyDataLength = 12;
        }
 public bool Equals(ProtocolVersion other)
 {
     return other != null && this.version == other.version;
 }
        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
        {
            int             blockSize     = encryptCipher.GetBlockSize();
            int             size          = mWriteMac.Size;
            ProtocolVersion serverVersion = context.ServerVersion;
            int             num           = len;

            if (!encryptThenMac)
            {
                num += size;
            }
            int num2 = blockSize - 1 - num % blockSize;

            if (!serverVersion.IsDtls && !serverVersion.IsSsl)
            {
                int max  = (255 - num2) / blockSize;
                int num3 = ChooseExtraPadBlocks(context.SecureRandom, max);
                num2 += num3 * blockSize;
            }
            int num4 = len + size + num2 + 1;

            if (useExplicitIV)
            {
                num4 += blockSize;
            }
            byte[] array = new byte[num4];
            int    num5  = 0;

            if (useExplicitIV)
            {
                byte[] array2 = new byte[blockSize];
                context.NonceRandomGenerator.NextBytes(array2);
                encryptCipher.Init(forEncryption: true, new ParametersWithIV(null, array2));
                global::System.Array.Copy((global::System.Array)array2, 0, (global::System.Array)array, num5, blockSize);
                num5 += blockSize;
            }
            int num6 = num5;

            global::System.Array.Copy((global::System.Array)plaintext, offset, (global::System.Array)array, num5, len);
            num5 += len;
            if (!encryptThenMac)
            {
                byte[] array3 = mWriteMac.CalculateMac(seqNo, type, plaintext, offset, len);
                global::System.Array.Copy((global::System.Array)array3, 0, (global::System.Array)array, num5, array3.Length);
                num5 += array3.Length;
            }
            for (int i = 0; i <= num2; i++)
            {
                array[num5++] = (byte)num2;
            }
            for (int j = num6; j < num5; j += blockSize)
            {
                encryptCipher.ProcessBlock(array, j, array, j);
            }
            if (encryptThenMac)
            {
                byte[] array4 = mWriteMac.CalculateMac(seqNo, type, array, 0, num5);
                global::System.Array.Copy((global::System.Array)array4, 0, (global::System.Array)array, num5, array4.Length);
                num5 += array4.Length;
            }
            return(array);
        }