中堅プログラマーの備忘録

忘れっぽくなってきたので備忘録として・・・

【vsftpd】Windows8.1だけSSPI への呼び出しに失敗しました・・・エラーが発生する

1.概要

運用中のシステムでリプレース等の理由で、過去のOSを使わなければいけない。。。
なんてことはよくある話かと思います。

今回はFTPS通信を行った時に、Windows8.1のみで何故かエラーになってしまう
という謎の現象を解決した話になります。


2.動作環境

サーバー

OS:CentOS8
vsftpd:バージョン3.0.3
証明書:あり(正規に認証されたもの)

クライアント

OS:Windows8.1
アプリケーション:自作(.net Framework4.5ターゲット)
FTPモジュール:FluentFTP

暗号化プロトコルはTLS1.2です。


3.エラーの内容

アプリケーションが出力したログは下記のとおり

System.Security.Authentication.AuthenticationException: SSPI への呼び出しに失敗しました。内部例外を参照してください。 ---> System.ComponentModel.Win32Exception: 予期されない、または形式が間違ったメッセージを受信しました。
   --- 内部例外スタック トレースの終わり ---
   場所 System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
   場所 System.Net.Security.SslState.StartSendBlob(Byte incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.ProcessReceivedBlob(Byte buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.StartReceiveBlob(Byte buffer, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.StartSendBlob(Byte incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.ProcessReceivedBlob(Byte buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.StartReceiveBlob(Byte buffer, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.StartSendBlob(Byte incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.ProcessReceivedBlob(Byte buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.StartReceiveBlob(Byte buffer, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.StartSendBlob(Byte incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   場所 FluentFTP.FtpSocketStream.ActivateEncryption(String targethost, X509CertificateCollection clientCerts, SslProtocols sslProtocols)
   場所 FluentFTP.FtpClient.Connect()


FluentFTPが出力したログは下記のとおり

# Connect()
Status:   Connecting to ***.***.***.***:***
Response: 220 (vsFTPd 3.0.3)
Status:   Detected FTP server: VsFTPd
Command:  AUTH TLS
Response: 234 Proceed with negotiation.
Status:   Disposing FtpSocketStream...
Error:    FTPS Authentication Failed


ログをみる限り、クライアントがサーバーに接続する段階で
暗号化によるエラーが発生しているようです。


過去にも別の原因で同様のエラーが発生していました。
解決記事は下記を参照
www.chuken-engineer.com


4.解決方法

原因はわかれば単純ですが、結構な時間を費やしてしまいました。。。

【vsftpd.conf】に下記を追加しました。

ssl_ciphers=HIGH

5.原因

ssl_ciphers=HIGH
は何の設定なのかと言うと

vsftpdがSSL接続を許可する暗号スイートを指定

みたいなニュアンスかと思います。

これを設定しないとデフォルトで

DES-CBC3-SHA
が設定されるとマニュアルには記載があります。


単純に考えると今回不具合が起きたWindows8.1環境では
これにより接続が出来なくなったと思われますが
Windows8.1のせいではなく、環境依存の可能性が高いのかな?と思ったりもします。


6.おまけ

自作アプリケーションのコードが悪いのかと思い
一般的なFTPクライアントソフトでも試してみました。

使ったソフトは
・FFFTP
・FileZilla
の二つです。

結果は
・FFFTPは接続失敗・・・
・FileZillaは接続成功!

という結果になりました。


一体何が違うのかというと
【SChannel】か【openSSL】
かの違いのようです。

FluentFTPも【SChannel】のようですので
またひとつ勉強になりました。