.NET Security
How To Implement Secure TCP Communications in Microsoft .NET 2.0
Microsoft .NET Framework 2.0 promises to be the first major upgrade to Windows and Web development tools
Jul. 29, 2005 12:15 AM
Digg This!
Page 1 of 2
next page »
The release of the .NET Framework 2.0 promises to be the first major upgrade to Windows and Web development tools since the initial release of .NET in 2001. In the realm of general networking, some of the major improvements to the Framework include FTP, Ping, packet tracing, and revised SMTP/MIME classes that are not dependent on the Windows SMTP service. While the network classes are getting a boost in features, network security in particular has received a major enhancement. Security is getting upgraded with support for SslStream for SSL (Secure Sockets Layer)-based network security, NegotiateStream for Kerberos and NTLM, plus enriched x509 certificate classes that are necessary for public key cryptography.
The current version of .NET includes excellent support for network communications, but lacks security functionality. For example, the Socket class is the base tool for developing custom clients and servers. On a higher level are the TcpClient, UdpClient, and TcpListener classes for TCP/IP and UDP communications, and at the highest level are the HttpWebRequest and HttpWebResponse classes for HTTP-specific communications. While all of these classes provide a wide variety of network functionality, the lower level socket, TCP, and TCP listener classes lack the ability to communicate securely. The new version of the Framework builds upon the current classes with additional extensions to address the security holes.
One of the most exciting additions to the Framework is support for SSL during TCP/IP client/server communications. The SSL protocol is a technology used on networks to secure communications by means of public key cryptography. A secure communications channel is established between the server and the client with all data encrypted. Digital signatures are used to verify data integrity, and trust in a client or server is confirmed by using digital certificates signed by a Certificate Authority called a “trusted third party.” There are a number of Certificate Authorities that provide certificates such as Verisign and Thawt, but organizations can also be their own authorities by setting up certificate servers using Microsoft Windows 2000 or 2003 Server.
New to socket development in the 2.0 Framework is the SslStream class and supporting x509 certificate functionality. While previous versions of the Framework did support certificates using the x509Certificate object, the object only allowed a certificate to be loaded from a file and interrogated. Furthermore, as there was no corresponding SslStream class to take advantage of the certificate, the x509Certificate class could not be used with a native secure TCP implementation. This was problematic, as one of the key capabilities of any SSL solution is to be able to access certificates from the Certificate Store on the computer. To accomplish this, .NET 2.0 introduces the x509Store class with the ability to specify which Store is to be used (such as “My” for the Personal Store) and the location of the Store (such as “Current User” or “Local Machine”). Now, a developer has the choice of loading a certificate from a file or accessing the list of certificates in a Store and choosing one. In most cases, the server only requires a certificate as the client is authenticating the server; however, if a client also requires authentication, then both sides will require certificates. In the example demonstrated below, only the server will acquire a certificate.
Creating a client and server application that will take advantage of the SslStream capability is a straightforward process. To start, let’s look at two non-secure examples. Listing 1 demonstrates a non-secure TCP client application and Listing 2 demonstrates a non-secure TCP server that acts as an echo server (sending all data back to the client). Both of these examples are slightly modified Microsoft .NET Framework SDK code samples and will work in all .NET versions. The client consists of the following major operations:
- Instantiate an instance of the TcpClient with the server name and port number.
- Convert the data to send into a byte array.
- Get the NetworkStream for the TcpClient for reading and writing.
- Write (send) the data using the NetworkStream.
- Read (receive) any data returned from the server.
- Convert the received bytes into a string.
- Close the NetworkStream.
The server consists of the following major operations:
- Instantiate a TcpListener class with a local IP address (in this case it is localhost, but otherwise it is the IP address of the network card in use) and port number to act as the server.
- Start the server.
- Loop while listening for incoming connections.
- Accept a connection and instantiate a TcpClient for that connection. (Every connection needs a TCP object for sending and receiving, and the TcpClient is used for such an operation. For more control over the operation, AcceptSocket should be used to return a raw Socket object.)
- Get the NetworkStream for the TcpClient for reading the incoming data.
- Loop to read all incoming data.
- Echo the data back to the connecting client.
- Close the NetworkStream.
Listings 3 and 4 demonstrate taking the code mentioned above and adding the SSL-specific functionality to enable encrypted and authenticated communications using a secure client and secure server, respectively.
First, to turn Listing 1 into a secure TCP client a reference to System.Security needs to be added. Then, the following namespaces need to be included:
System.Net.Security;
System.Security.Authentication;
System.Security.Cryptography.X509Certificates;
The first major change to the code is the use of the SslStream for reading and writing instead of the NetworkStream. The SslStream transmits data using the stream provided during instantiation, which in this case is the NetworkStream. For remote certificate validation, a RemoteCertificateValidationCallback must be specified. The callback is passed as a parameter when instantiating the SslStream. This function will allow the remote certificate received from the server to be interrogated to ensure that it meets policy specifications and reports any errors detected in the certificate. The function will return true or false based on whether you choose to validate the certificate.
The next major addition is calling the AuthenticateAsClient method of SslStream and passing the target host name as the parameter. The host name must match the name on the server certificate. In this case, the name is “localhost.” This process authenticates the server. By making the AuthenticateAsClient call, the SslStream class can be interrogated for information about the security services in use for the connection.
The final difference is the incorporation of a check for AuthenticationException to the try-catch block. If an error occurs during the AuthenticateAsClient call, this exception will be raised. To iterate the major steps for creating an SSL client application as exemplified in Listing 3:
- Instantiate an instance of the TcpClient with the server name and port number.
- Convert the data to be sent into a byte array.
- Specify the callback function that will act as the validation delegate (OnCertificateValidation).
- Instantiate an SslStream with the NetworkStream returned from the TcpClient and pass the validation delegate specified in Step 3.
- Authenticate the server and check any security services required from the SslStream.
- Write (send) the data using the SslStream.
- Read (receive) any data returned from the server with the SslStream.
- Convert the received bytes into a string.
- Close the SslStream.
Listing 4 demonstrates the additions necessary to create a secure server. Just as in the secure TCP client application, a reference to System.Security must be added and the following namespaces included:
System.Net.Security
System.Security.Authentication
System.Security.Cryptography
System.Security.Cryptography.X509Certificates
Again, as with the secure TCP client application, the first difference is that instead of a NetworkStream, an SslStream is instantiated with the NetworkStream returned from the TcpClient. The next step is a call to the AuthenticateAsServer method of the SslStream. Unlike the client, which calls the AuthenticateAsClient and takes a string, AuthenticateAsServer takes an x509Certificate object that represents the server certificate. While the certificate can be loaded from a file, your certificate most likely resides in a Certificate Store.
The GetCertificate method in Listing 4 returns an x509Certificate object. This object is created by first instantiating an x509Store object with the location of the store that contains the certificate needed. The store is then opened and a find operation is conducted using the X509FindType enumeration. In this example, the search criteria is FindBySubjectName, which returns all certificates whose name contains the characters specified in the search value. The Find method, which takes the X509FindType enumeration and the search value, returns a collection. Using a fine-tuned search will return a collection of one. Another option is to conduct a more general search and iterate through the returned collection of certificates, checking each certificate’s properties for a match.
After the certificate is passed to the AuthenticateAsServer method, the SslStream can be queried for the security services provided. Just like the secure TCP client, the AuthenticationException check is added to the try-catch block. The remaining operations are the same as the non-secure example, with the exception of the SslStream taking the place of the NetworkStream in read/write operations. The major steps in Listing 4 are:
- Instantiate a TcpListener class with a local IP address (in this case it is localhost, but otherwise it would be the IP address of the network card in use) and port number to act as the server.
- Start the server.
- Loop while listening for incoming connections.
- Accept a connection and instantiate a TcpClient for that connection. (Every connection needs a TCP object for sending and receiving, and the TcpClient is used for such an operation.) For more control over the operation, AcceptSocket should be used to return a raw Socket object.
- Instantiate an SslStream with the NetworkStream returned from the TcpClient.
- Authenticate the server using the server certificate and validate the results using the SslStream object.
- Loop to read all incoming data.
- Echo the data back to the connecting client.
- Close the SslStream.
To test the examples, first start the secure server in Listing 4. The server will wait for a connection. Then start the secure client in Listing 3, which should establish a connection to the server, display the secure connection information in the console, and show the sent and received information. The server should likewise show the connection information and the received and echoed data.
Most problems that occur when attempting to establish SSL connections between a client and a server are related to the certificate. Often times the installed certificate may not be valid, may have a missing or invalid CA (Certificate Authority), or is installed in an unexpected store. Also, verify that the search criteria are correct when looking for the certificate in the store.
Regardless of any certificate-related perils, the addition of the SslStream class and accompanying certificate classes are a major addition and significantly enhance the .NET network communications toolbox. The approach Microsoft has taken fits naturally as an extension to the current network communications classes, but their approach is not new. An SslStream class has been available for .NET 1.0 and 1.1 from Dart Communications, a third-party component company, and other alternative SSL approaches exist. Still, the addition of native classes adds more options and no doubt interesting products and applications will become available that leverage this functionality.
• • •
Special thanks go to Sajee Mathew of Microsoft for his assistance in providing code snippets.
Page 1 of 2
next page »
About Alexander GladshteinAlex Gladshtein is a product manager at The CBORD Group, Inc. in Ithaca, NY. CBORD is the world's largest supplier of food and nutrition software solutions, campus-wide ID card programs, cashless dining, and housing management systems. Alex holds undergraduate and graduate degrees from the University of Michigan, and when not obsessing about .NET he enjoys spending time with his wonderful wife and cheering on the Michigan Wolverines.