User Certificate

Nov 13, 2012 at 7:36 AM

Does this framework support user certificates?

The specific host requires the client to provide a certificate for authentication. And the working directory is retrieved from the UID of the certicificate.

How does one add a certificate upon opening the connection.

Thanks,
Mikkel 

Coordinator
Nov 13, 2012 at 12:31 PM

It doesn't but I think it should be trivial to implement. I'll look into it and post back here.

Thanks,
J.P.

Nov 13, 2012 at 1:20 PM

Sounds good, Thanks.

Mikkel

Coordinator
Nov 13, 2012 at 1:21 PM
I'll have a new revision up in a few minutes with the new code. I don't have a quick and easy way to test it so you'll have to be the guinea pig.
Coordinator
Nov 13, 2012 at 1:32 PM

Alright, the latest revision has a new ClientCertificates X509CertificateCollection property in FtpClient. Add your client certificates to it before you connect and they will be used when authenticating the SSL connection.

Here's the relevant documention for X509Certificate which is what you'll be adding to the collection:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate.aspx

Nov 13, 2012 at 8:04 PM

Thank you for responding so quickly.

Unfortunately it did not solve the problem.

First, I did not see any changes in the download?

Then, I did find changes in the Source Code tab. I copied the content of FtpClient.cs and FtpSocketStream.cs and compiled.

Have you made changes to other files?

The new property i FtpClient showed up.

This code:

string efiHostName = "secureftpgatewaytest.skat.dk";
System.Net.FtpClient.FtpClient client = new System.Net.FtpClient.FtpClient();
client.Host = efiHostName;
client.Port = 6371;
client.Credentials = new NetworkCredential("Anonymous","");

// Select certificate and add to client
X509Store store = new X509Store("MY", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);       X509Certificate2Collection scollection
         = X509Certificate2UI.SelectFromCollection(fcollection, "Vælg certifikat", "Vælg et certifikat og tryk OK", X509SelectionFlag.MultiSelection); 

if (scollection.Count != 1)
{
                    throw new Exception("Error: You have not chosen exactly one certificate");
 }
foreach (X509Certificate2 x509 in scollection)
{
                  client.ClientCertificates.Add(x509);
}
store.Close();

client.ReadTimeout = 10000;
client.Connect();

this.textBoxOutput.Text += client.IsConnected + Environment.NewLine;
this.textBoxOutput.Text += client.GetWorkingDirectory() + Environment.NewLine;
this.textBoxOutput.Text += client.IsConnected + Environment.NewLine;
this.textBoxOutput.Text += client.DirectoryExists("out") + Environment.NewLine;

System.Net.FtpClient.FtpListItem[] list = client.GetListing();
foreach (System.Net.FtpClient.FtpListItem item in list)
{
                    this.textBoxOutput.Text += item.Name + Environment.NewLine;
}

client.Disconnect();

Gives this result:

True
/
True
False
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host   at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)   at System.Net.FtpClient.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)   at System.Net.FtpClient.FtpSocketStream.ReadLine(Encoding encoding)   at System.Net.FtpClient.FtpClient.GetReply()   at System.Net.FtpClient.FtpClient.Execute(String command)   at System.Net.FtpClient.FtpClient.OpenPassiveDataStream(FtpDataConnectionType type, String command, Object[] args)   at System.Net.FtpClient.FtpClient.OpenPassiveDataStream(FtpDataConnectionType type, String command, Object[] args)   at System.Net.FtpClient.FtpClient.OpenDataStream(String command, Object[] args)   at System.Net.FtpClient.FtpClient.GetListing(String path, FtpListOption options)   at FTPS1.Form1.buttonUpload2_Click(Object sender, EventArgs e) in C:\KMD\VS2010\FTPS1\FTPS1\Form1.cs:line 124

The host is closing the connection when calling the GetListing() method.

I am able to open a connection and up-/download files using the SmartFtp-application, so issues with ports and firewall should be ok.

Thanks,
Mikkel 

Coordinator
Nov 13, 2012 at 8:09 PM

I think I know what's going on. Give me a few minutes and I'll update the code.

Coordinator
Nov 13, 2012 at 8:16 PM

I just pushed up a new revision. I forgot to authenticate the data connection with the client certificates which is probably why GetListing() is failing. I fixed some other SSL bugs as well.

Nov 13, 2012 at 8:38 PM

Unfortunately, No.

The host is still closing on GetListing()

True
/
True
False
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host   at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)   at System.Net.FtpClient.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)   at System.Net.FtpClient.FtpSocketStream.ReadLine(Encoding encoding)   at System.Net.FtpClient.FtpClient.GetReply()   at System.Net.FtpClient.FtpClient.Execute(String command)   at System.Net.FtpClient.FtpClient.OpenPassiveDataStream(FtpDataConnectionType type, String command, Object[] args)   at System.Net.FtpClient.FtpClient.OpenPassiveDataStream(FtpDataConnectionType type, String command, Object[] args)   at System.Net.FtpClient.FtpClient.OpenDataStream(String command, Object[] args)   at System.Net.FtpClient.FtpClient.GetListing(String path, FtpListOption options)   at System.Net.FtpClient.FtpClient.GetListing(String path)   at System.Net.FtpClient.FtpClient.GetListing()   at FTPS1.Form1.buttonUpload2_Click(Object sender, EventArgs e) in C:\KMD\VS2010\FTPS1\FTPS1\Form1.cs:line 124

I have updated FtpClient.cs only.

Thanks,
Mikkel 

Coordinator
Nov 13, 2012 at 8:42 PM

Please try setting the ThreadSafeDataConnections property to false. When this property is True, the ClientCertificates (among other things) are supposed to be cloned into a new object. Setting it to false will let me see if it's an issue with cloning the X509CertificateCollection property.

Coordinator
Nov 13, 2012 at 8:43 PM

If that doesn't fix it let me know the server software you are using so that I can try to setup a similar environment to debug with.

Nov 13, 2012 at 9:01 PM
Edited Nov 13, 2012 at 9:10 PM

Still no, unfortunately.

The welcome message from the host is: Welcome to Synchrony Gateway FTP server

I can mail the certificate to you, if you want?

It is just a test certificate and we can revoke it later if necessary.

The remaining info you have from the code above.

Coordinator
Nov 13, 2012 at 9:09 PM
That would be great. Send me a private message through codeplex and I'll reply with my email address unless you already have it from somewhere else.
Jan 2, 2013 at 9:41 AM

Confirmed: The client certificate feature is working.

Thanks a lot!