Reputation:
I'm essentially attempting to setup a HTTPS client I can use for automated testing APIs and other web services I'm developing. I'm familiar with using sockets, but not so much with using SSL/TLS in code. I've started by attempting to setup a client that sends an HTTP request to google.com with the following header: GET / HTTP/1.1
The idea is to receive a basic HTTP response from Google, via an encrypted connection of course. This is really easy when using unencrypted HTTP - I can even telnet into google over port 80 and enter GET / HTTP/1.1
and I receive a nice HTTP response header and HTML payload. Implementing the C/C# code for making unencrypted HTTP requests is also not very difficult. It's SSL that is giving me a difficult time.
Using the code below (full sample found at https://msdn.microsoft.com/en-us/library/system.net.security.sslstream.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-3), which is an almost identical implementation to what is provided by MSDN for reference, I can successfully connect to google.com
and validate the server certificate:
// Create a TCP/IP client socket.
// machineName is the host running the server application.
TcpClient client = new TcpClient(machineName, 443);
Console.WriteLine("Client connected.");
// Create an SSL stream that will close the client's stream.
SslStream sslStream = new SslStream(
client.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
// The server name must match the name on the server certificate.
try
{
sslStream.AuthenticateAsClient(serverName);
}
catch (AuthenticationException e)
{
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null)
{
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
}
Console.WriteLine("Authentication failed - closing the connection.");
client.Close();
return;
}
The issue is when the following code executes, the ReadMessage(sslStream) instruction hangs, as in I don't receive a response for a very long time, and when the response finally comes in it is an empty string:
// Encode a test message into a byte array.
// Signal the end of the message using the "<EOF>".
byte[] messsage = Encoding.UTF8.GetBytes("GET / HTTP/1.1<EOF>");
// Send hello message to the server.
sslStream.Write(messsage);
sslStream.Flush();
// Read message from the server.
string serverMessage = ReadMessage(sslStream);
Console.WriteLine("Server says: {0}", serverMessage);
Therefore, I'm unable to receive the HTTP response I was looking for (or anything at all) when I make this request over a secure socket connection. The idea in the long run is to start using this client to send customized HTTP requests to my own APIs and web services, but I certainly cannot do that if I cannot even get a generic response from google.com. Does anyone have an idea why the ReadMessage() function is timing out or otherwise providing no response? The sample code seems very straightforward so I'm having a hard time understanding what I'm doing wrong.
Upvotes: 1
Views: 6213
Reputation: 3229
One thing that immediately caught my attention is that the Microsoft example does not provide the "count" argument for sslStream.Write()
, which I believe may be related to your issue. Also note, ReadMessage()
appears to be a function you have not provided a definition for. Without knowing what ReadMessage()
is doing specifically, the exact cause of your problem cannot be determined. I modified the provided code for sending a HTTPS request and reading the response. It seems to work fine with sites I've tried thus far.
// Send request
byte[] buffer = new byte[2048];
int bytes;
byte[] request = Encoding.UTF8.GetBytes(String.Format("GET https://{0}/ HTTP/1.1\r\nHost: {0}\r\n\r\n", serverName));
sslStream.Write(request, 0, request.Length);
sslStream.Flush();
// Read response
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
} while (bytes == 2048);
As a side note, I also noticed sslStream.AuthenticateAsClient(serverName);
which certainly works for many web services; however, I've had issues with that particular overload when accessing sites that strictly use TLS1.2. Try sslStream.AuthenticateAsClient(serverName,null,SslProtocols.Tls12,false);
if you want to enable support for strictly TLS1.2 agents.
Upvotes: 4