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 = 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 = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions); this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes); } } if (mSecurityParameters.extendedMasterSecret) { this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions); 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 != null) { 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 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. */ mSecurityParameters.verifyDataLength = 12; ApplyMaxFragmentLengthExtension(); message.WriteToRecordStream(this); }
protected virtual void SendServerHelloMessage() { HandshakeMessage handshakeMessage = new HandshakeMessage(2); ProtocolVersion serverVersion = mTlsServer.GetServerVersion(); if (!serverVersion.IsEqualOrEarlierVersionOf(Context.ClientVersion)) { throw new TlsFatalAlert(80); } mRecordStream.ReadVersion = serverVersion; mRecordStream.SetWriteVersion(serverVersion); mRecordStream.SetRestrictReadVersion(enabled: true); ContextAdmin.SetServerVersion(serverVersion); TlsUtilities.WriteVersion(serverVersion, handshakeMessage); handshakeMessage.Write(mSecurityParameters.serverRandom); TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, handshakeMessage); int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite(); if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite) || selectedCipherSuite == 0 || CipherSuite.IsScsv(selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion)) { throw new TlsFatalAlert(80); } mSecurityParameters.cipherSuite = selectedCipherSuite; byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod(); if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod)) { throw new TlsFatalAlert(80); } mSecurityParameters.compressionAlgorithm = selectedCompressionMethod; TlsUtilities.WriteUint16(selectedCipherSuite, handshakeMessage); TlsUtilities.WriteUint8(selectedCompressionMethod, handshakeMessage); mServerExtensions = mTlsServer.GetServerExtensions(); if (mSecureRenegotiation) { byte[] extensionData = TlsUtilities.GetExtensionData(mServerExtensions, 65281); if (null == extensionData) { mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions); mServerExtensions[65281] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes); } } if (mSecurityParameters.extendedMasterSecret) { mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions); TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions); } if (mServerExtensions != null) { mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions); mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions, mServerExtensions, 80); mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions); mAllowCertificateStatus = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 5, 80)); mExpectSessionTicket = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 35, 80)); TlsProtocol.WriteExtensions(handshakeMessage, mServerExtensions); } mSecurityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite); mSecurityParameters.verifyDataLength = 12; ApplyMaxFragmentLengthExtension(); handshakeMessage.WriteToRecordStream(this); }