Namespace: System.Net.Security
Represents a stream that uses the Kerberos or NTLM security protocols to authenticate a remote client or server.
Namespace: System.Net.Security
Assembly: System.Net.Security.dll
The NegotiateStream
class provides a secure communication channel between a client and a server. It negotiates the appropriate security protocol (Kerberos or NTLM) and then encrypts and/or compresses the data stream to ensure confidentiality and integrity.
Note: This class is typically used for inter-process communication or client-server applications that require authentication and data protection. It abstracts away the complexities of the underlying security protocols.
Name | Description |
---|---|
NegotiateStream(System.IO.Stream, bool) | Initializes a new instance of the NegotiateStream class with the specified stream and ownership option. |
NegotiateStream(System.Net.Security.NetworkCredential) | Initializes a new instance of the NegotiateStream class with the specified network credentials. |
NegotiateStream(System.Net.Security.NetworkCredential, bool) | Initializes a new instance of the NegotiateStream class with the specified network credentials and ownership option. |
NegotiateStream(System.Net.Security.CredentialCache) | Initializes a new instance of the NegotiateStream class with the specified credential cache. |
NegotiateStream(System.Net.Security.CredentialCache, bool) | Initializes a new instance of the NegotiateStream class with the specified credential cache and ownership option. |
This class inherits methods from Stream
and provides its own specific methods.
Name | Description |
---|---|
AuthenticateAsClient(string, System.Security.Cryptography.X509Certificates.X509Certificate, System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy, bool) | Authenticates the client to a remote server. |
AuthenticateAsClient(string, System.Security.Cryptography.X509Certificates.X509Certificate, System.Security.Authentication.SslProtocols, bool) | Authenticates the client to a remote server using specified SSL protocols. |
AuthenticateAsServer(System.Security.Cryptography.X509Certificates.X509Certificate, System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy, bool) | Authenticates the server to a remote client. |
AuthenticateAsServer(System.Security.Cryptography.X509Certificates.X509Certificate, System.Security.Authentication.SslProtocols, bool) | Authenticates the server to a remote client using specified SSL protocols. |
BeginAuthenticateAsClient(...) | Begins an asynchronous operation to authenticate the client. |
EndAuthenticateAsClient(...) | Ends an asynchronous operation to authenticate the client. |
BeginAuthenticateAsServer(...) | Begins an asynchronous operation to authenticate the server. |
EndAuthenticateAsServer(...) | Ends an asynchronous operation to authenticate the server. |
Flush() | Clears all buffers for the current stream and causes any buffered data to be written to the underlying device. (Inherited from Stream ) |
Read(...) | Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. (Inherited from Stream ) |
Write(...) | Writes a sequence of bytes to the current stream and advances the position within the stream by the number of bytes written. (Inherited from Stream ) |
Name | Description |
---|---|
CanRead | Gets a value indicating whether the stream supports reading. (Inherited from Stream ) |
CanSeek | Gets a value indicating whether the stream supports seeking. (Inherited from Stream ) |
CanWrite | Gets a value indicating whether the stream supports writing. (Inherited from Stream ) |
IsAuthenticated | Gets a value indicating whether the stream has been successfully authenticated. |
IsMutuallyAuthenticated | Gets a value indicating whether both the client and server have been mutually authenticated. |
Length | Gets the length in bytes of the stream. (Inherited from Stream ) |
Position | Gets or sets the current position within the stream. (Inherited from Stream ) |
The NegotiateStream
class handles the details of the Security Support Provider Interface (SSPI) on Windows, allowing applications to use Kerberos or NTLM for authentication without directly interacting with the SSPI functions. On non-Windows platforms, it relies on GSSAPI.
The authentication process involves a series of token exchanges between the client and server. The AuthenticateAsClient
and AuthenticateAsServer
methods manage these exchanges. After successful authentication, the stream can be used to send and receive encrypted and integrity-protected data.
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
public class ClientExample
{
public static void Main(string[] args)
{
try
{
// Assuming a server is listening on localhost:8080
TcpClient client = new TcpClient("localhost", 8080);
NetworkStream stream = client.GetStream();
// Create a NegotiateStream using the underlying network stream
// The 'true' indicates that NegotiateStream owns the underlying stream
NegotiateStream negotiateStream = new NegotiateStream(stream, true);
// Authenticate as a client.
// null for the target name means it will try to infer from the server name.
// null for the certificate means default certificate validation.
// SslProtocols.Tls implies using TLS if available, falling back to Negotiate
negotiateStream.AuthenticateAsClient("localhost", null, SslProtocols.Tls, false);
Console.WriteLine("Client authenticated successfully.");
Console.WriteLine($"IsAuthenticated: {negotiateStream.IsAuthenticated}");
Console.WriteLine($"IsMutuallyAuthenticated: {negotiateStream.IsMutuallyAuthenticated}");
// Send data
string message = "Hello from the authenticated client!";
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
negotiateStream.Write(messageBytes, 0, messageBytes.Length);
negotiateStream.Flush();
Console.WriteLine("Sent: " + message);
// Receive data
byte[] buffer = new byte[1024];
int bytesRead = negotiateStream.Read(buffer, 0, buffer.Length);
string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + response);
negotiateStream.Close(); // This will also close the underlying stream
client.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
public class ServerExample
{
public static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 8080);
listener.Start();
Console.WriteLine("Server started. Listening on port 8080...");
try
{
while (true)
{
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client connected.");
HandleClient(client);
}
}
catch (Exception ex)
{
Console.WriteLine("Server Error: " + ex.Message);
}
finally
{
listener.Stop();
}
}
private static void HandleClient(TcpClient tcpClient)
{
NetworkStream stream = tcpClient.GetStream();
// Load your server certificate here. For testing, you might use a self-signed certificate.
// In production, ensure you use a trusted certificate.
X509Certificate serverCertificate = LoadCertificate();
// Create a NegotiateStream
NegotiateStream negotiateStream = new NegotiateStream(stream, true);
try
{
// Authenticate as a server.
negotiateStream.AuthenticateAsServer(serverCertificate, SslProtocols.Tls, false);
Console.WriteLine("Server authenticated successfully.");
Console.WriteLine($"IsAuthenticated: {negotiateStream.IsAuthenticated}");
Console.WriteLine($"IsMutuallyAuthenticated: {negotiateStream.IsMutuallyAuthenticated}");
// Receive data
byte[] buffer = new byte[1024];
int bytesRead = negotiateStream.Read(buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + message);
// Send a response
string responseMessage = "Message received by the server!";
byte[] responseBytes = Encoding.UTF8.GetBytes(responseMessage);
negotiateStream.Write(responseBytes, 0, responseBytes.Length);
negotiateStream.Flush();
Console.WriteLine("Sent: " + responseMessage);
}
catch (Exception ex)
{
Console.WriteLine("Error handling client: " + ex.Message);
}
finally
{
negotiateStream.Close(); // This will also close the underlying stream
tcpClient.Close();
Console.WriteLine("Client disconnected.");
}
}
private static X509Certificate LoadCertificate()
{
// In a real application, load the certificate from a file or the certificate store.
// For example purposes, this might return null or a placeholder.
// Ensure you have a valid certificate for production use.
// Example: X509Certificate2 cert = new X509Certificate2("server.pfx", "password");
// return cert;
Console.WriteLine("Warning: No server certificate loaded. Authentication may fail.");
return null; // Or load a test certificate
}
}
Client: .NET Framework 4.5, .NET Standard 1.3, .NET Core 1.0, .NET Core 2.0, .NET Core 2.1, .NET Core 2.2, .NET Core 3.0, .NET 5, .NET 6, .NET 7, .NET 8
Server: .NET Framework 4.5, .NET Standard 1.3, .NET Core 1.0, .NET Core 2.0, .NET Core 2.1, .NET Core 2.2, .NET Core 3.0, .NET 5, .NET 6, .NET 7, .NET 8