ArxOne / FTP

Simple FTP client
MIT License
37 stars 15 forks source link

A call to SSPI failed #32

Open zharris6 opened 7 years ago

zharris6 commented 7 years ago

Hello -

I am experiencing an issue when trying to connect to a client via the FtpProtocol.FtpES protocol.

I believe it has something to do with the SSL certificate signing.

Can you point me in the right direction to try and fix this?

I will be happy to commit my fix, once its completed.

Exception Message:

A call to SSPI failed, see inner exception.

Here is the stack trace:

at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception) at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult) at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation) at ArxOne.Ftp.FtpSession.UpgradeToSsl(Stream stream) at ArxOne.Ftp.FtpSession.EnterSslProtocol() at ArxOne.Ftp.FtpSession.InitializeProtocol() at ArxOne.Ftp.FtpSession.ProcessConnect(TimeSpan connectTimeout, TimeSpan readWriteTimeout) at ArxOne.Ftp.FtpSession.<>cDisplayClass15_0.b__0() at ArxOne.Ftp.FtpSession.Process[TResult](Func`1 func, String commandDescription, String requestCommand, String[] requestParameters) at ArxOne.Ftp.FtpSession.Connect(TimeSpan connectTimeout, TimeSpan readWriteTimeout) at ArxOne.Ftp.FtpSession.get_ProtocolStream() at ArxOne.Ftp.FtpClient.<>cDisplayClass123_0.b__0(FtpSession session) at ArxOne.Ftp.FtpClient.Process[TResult](Func`2 action, FtpSession session) at ArxOne.Ftp.FtpClient.SendSingleCommand(String command, String[] parameters).

picrap commented 7 years ago

Hi,

I had a lot of problems like this one, and for some unknown reason. I think it has something to do with the SSL protocol chosen, so the only way to fix this was to provide a property named SslProtocols in the FtpClientParameters class. Maybe (I'm thinking of it just right now) it could help to try some other protocols when the tested one fails, so catching the exception in UpgradeToSsl() method and then retry with different options. I'm not sure this helps, but this is my best.

zharris6 commented 7 years ago

Implicit SSL will not even authenticate and the server is setup to require SSL: so no SSL is not an option.

Explicit SSL is the only option that will work, for this particular server.

I will try to play around with it and let you know how it goes :)

Thanks for the quick response.

picrap commented 7 years ago

No it's not about explicit or implicit, it's about SslProtocols that you can force to have the values you need:

namespace System.Security.Authentication
{
  [Flags]
  public enum SslProtocols
  {
    None,
    Ssl2,
    Ssl3,
    Tls,
    Tls11,
    Tls12,
    Default = Tls | Ssl3,
  }
}

And you can set specific values in the FtpClientParameters class in order to use only the specified SSL protocols.

zharris6 commented 7 years ago

Sorry I should of been more specific. I have tried all of them with no luck. I either receive a connection error (due to target server limitations) or the SSPI error.

picrap commented 7 years ago

I'm sorry to read that, I think there is something I misunderstood in FTPES protocol, because I had the same error on some servers (and had to disable tests for them).

zharris6 commented 7 years ago

I am almost positive it has to do with the way you are handling certificates. Right now the CheckCertificateHandler isn't doing anything. and your passing in a null certificate to the AuthenticateAsClient method.

That is what is causing the SSPI errors we are seeing.

I am going to try and generate a cert and apply it with this method and see if it fixes it.

If it does, ill clean it up and get it committed.

picrap commented 7 years ago

Any progress on this?

zharris6 commented 7 years ago

Nope - I Tried tons of things, including add a cert to the request and no luck.

zharris6 commented 7 years ago

I fixed the SSPI call error, but now i am getting this exception "The handshake failed due to an unexpected packet format"

A wireshark says the server responded with:

421 Failed TLS negotiation on control channel, disconnected (SSL_accept():(1) error: 14076 OFC: SSL Routines: SSL23_Get_Client_Hello: unknown protocol)"

picrap commented 7 years ago

I guess that's a progress... How can I help?

picrap commented 7 years ago

Hi Zach, What FTP server do you use?

picrap commented 7 years ago

This may be a great product, however I couldn't even getting it started (because the setup is a great piece of garbage, and yes, I'm pissed). So I won't be able to help.

zharris6 commented 7 years ago

I understand, any Unix based ftpd should be fine.

I will let you know when I get back home and can look at it

On Fri, Nov 11, 2016, 12:32 PM Pascal Craponne notifications@github.com wrote:

This may be a great product, however I couldn't even getting it started (because the setup is a great piece of garbage, and yes, I'm pissed). So I won't be able to help.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ArxOne/FTP/issues/32#issuecomment-260006515, or mute the thread https://github.com/notifications/unsubscribe-auth/AGS2cVo5TIFHkBKWX0QcNXAMsURqVGN_ks5q9KKBgaJpZM4KhRpI .

picrap commented 7 years ago

Version 1.11 (just released) uses lazy initialization on FtpStream, this means they can be used only if their Validated() method was invoked. Does this fix the problem (because it may be related)?

ebarnard commented 7 years ago

I think this is caused by another issue I just encountered.

If you set ChannelProtection to contain FtpProtection.DataChannel the library never explicitly informs the server of this.

Some servers do not by default use SSL on the data channel even if it is being used on the command channel.

This can result in the server sending unencrypted data which is picked up by System.Net.Security.SslStream.AuthenticateAsClient and causes the exception seen above as the data is not a valid SSL handshake.

FtpSession.CheckProtection should, if State["PROT"] does not equal the desired protection level, issue a PROT command and fail on a non 2xx response code. State["PROT"] should not initially be set on a new connection.

I'm currently using the below as a temporary fix:

if (client.SendSingleCommand("PROT", "P").Code.Code != 200)
    throw new Exception("Could not enable data channel encryption.");
ebarnard commented 7 years ago

It appears the library also doesn't issue a PBSZ command which is apparently required by https://tools.ietf.org/html/rfc2228.

Other libraries seem to use PBSZ 0 successfully.

zharris6 commented 7 years ago

ebarnard - You are correct. Also, I ended up bypassing SSPI all together and using a OpenSSL C# implementation.

Even with your suggestions, I could not successfully handshake with a UNIX based ftpd.

Here is the package i used to successfully

https://github.com/openssl-net/openssl-net

zharris6 commented 7 years ago

Something also to add - I updated libssl32.dll and ssleay32.dll from that package with the new versions provided by OpenSSL. I believe the versions included in that package are open to the HeartBleed vulnerability.

ebarnard commented 7 years ago

Looks like mine is an unrelated issue then.

zharris6 commented 7 years ago

Ebernard - What exactly is your issue? your getting the SSPI exception?

Is your initial handshake successful? Do you see the USER command being sent?

Any logs you can provide would be helpful.

ebarnard commented 7 years ago

The issue is that a PROT command is not being sent when using ftps or ftpes. As a result the server sends unencrypted data on the data channel despite the control channel running over ssl.

As it's unrelated to this issue I opened #35.

picrap commented 7 years ago

Ahem... Let's get back to original problem here 😣 @zharris6 : is it fixed? Can we close this issue?

zharris6 commented 7 years ago

Nope, I only got it working by bypassing SSPI/SSLStream all together and using the OpenSSL fork i mentioned previously. It is a complete hack and a total butcher of your code, therefor it is not a acceptable solution.

I will try to fix this using SSPI, however, I think it is a problem with SSPI itself.

picrap commented 7 years ago

OK, let's keep this issue open, then.