Bonjour,

Je n'ai pas trouvé de discussion en français sur ce sujet et les forums en anglais ne me donnent pas assez de détail donc je vous remercie de votre aide.

Je souhaite me connecter à un serveur FTPS en mode explicite avec une authentification client/server sur la couche SSL.

J'ai systématiquement l'erreur suivante lorsque j'utilise la couche TcpClient+SslStream ou FtpWebRequest :

System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: The token supplied to the function is invalid
--- End of inner exception 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.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 CCDS.FRAMEWORK.DataAccess.Ftp.Generic.FtpControlConnection.ConnectionServer() in D:\Drivers\CCDS Packages\certificat\NET-COMMON\CCDS.FRAMEWORK\DataAccess\Ftp\Generic\FtpControlConnection.cs:line 81
at CCDS.FRAMEWORK.DataAccess.Ftp.Generic.FtpControlConnection.Connexion() in D:\Drivers\CCDS Packages\certificat\NET-COMMON\CCDS.FRAMEWORK\DataAccess\Ftp\Generic\FtpControlConnection.cs:line 34
at CCDS.FRAMEWORK.DataAccess.Ftp.Generic.FtpFactory.ListDirectory(String directory, String masque) in D:\Drivers\CCDS Packages\certificat\NET-COMMON\CCDS.FRAMEWORK\DataAccess\Ftp\Generic\FtpFactory.cs:line 40
En complément, voici mes codes :

Test 1 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
                X509Certificate cer1 = new X509Certificate("D:\\Drivers\\CCDS Packages\\certificat\\certificat-prive.pfx", "azerty");
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(OnCertificateValidation);
 
                FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create("ftp://xxx.xxx.xxx.xx:21/");
                request.Credentials = new NetworkCredential("xxxxxx", "xxxxxxxx");
                request.EnableSsl = true;
                request.ClientCertificates.Add(cer1);
                request.Proxy = null;
                request.UseBinary = true;
                request.UsePassive = true;
                request.KeepAlive = false;
 
                request.Method = WebRequestMethods.Ftp.ListDirectory;
 
                StringCollection list = new StringCollection();
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                try
                {
                    using (StreamReader read = new StreamReader(response.GetResponseStream()))
                    {
                        while (!read.EndOfStream) list.Add(read.ReadLine());
                        read.Close();
                    }
                    response.Close();
                }
                catch
                {
                    response.Close();
                    throw;
                }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
        public static bool OnCertificateValidation(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
        { 
            return true; 
        }
Test 2 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
            X509Certificate2 cer = new X509Certificate2("D:\\Drivers\\CCDS Packages\\certificat\\RSFRLB-CCDALL1D-prive.pfx", "azerty");
            X509CertificateCollection collection = new X509CertificateCollection();
            collection.Add(cer);
 
            _tcp = new TcpClient();
            _tcp.NoDelay = true;
            System.Net.IPAddress ip = new System.Net.IPAddress(new byte[]{xxx, xxx, xxx, xxx});
            _tcp.Connect(ip, 21);
            _stream = _tcp.GetStream();
 
 
            if (_type == FtpConnectionType.SECURE_IMPLICIT)
            {
                SslStream ssl = new SslStream(_tcp.GetStream(), false, new RemoteCertificateValidationCallback(OnCertificateValidation), null);
                ssl.AuthenticateAsClient(
                     System.Environment.MachineName,
                     collection,
                     System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls,
                     true);
 
                _stream = ssl;            
            }
            if (_type == FtpConnectionType.SECURE_EXPLICIT)
            {
                WebResponse();
 
                WebRequest(FtpCommands.AUTH, "TLS");
                WebResponse();
 
                SslStream ssl = new SslStream(
                    _tcp.GetStream(), 
                    false, 
                    new RemoteCertificateValidationCallback(OnCertificateValidation),
                    new LocalCertificateSelectionCallback(OnCertificateSelection));
                ssl.AuthenticateAsClient(
                     System.Environment.MachineName,
                     collection,
                     System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls,
                     false);
 
                _stream = ssl;            
 
            }
 
            WebResponse();
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
        private static bool OnCertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            Trace.TraceVerbose("CCDS.FRAMEWORK.DataAccess.Ftp.Generic", "FtpControlConnection", "OnCertificateValidation");
            return true;
        }
        public static X509Certificate OnCertificateSelection(
                                Object sender,
                                string targetHost,
                                X509CertificateCollection localCertificates,
                                X509Certificate remoteCertificate,
                                string[] acceptableIssuers
                            )
        {
            return (localCertificates.Count != 0 )?localCertificates[0]:null;
        }
La connexion tcp s'établie, les commandes FTP sont envoyées. L'erreur a lieu au moment de la connexion SSL.
De plus, j'utilise un certificat auto-signé pour cette opération.

Mon hypothèse : soit je ne passe pas les bons arguments aux classes, soit mes certificats sont invalides.

Je vous remercie de votre aide.