0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

パッシブFTPをTLS/SSLで暗号化する設定のトラブルシューティング(vsftpd, OpenSSL, GnuTLS)

Last updated at Posted at 2025-05-11

このトラブルシューティングについて

OpenSSLで作成した自己署名証明書を使用し、vsftpdでFTPSをテストしていてハマったので。結果からいうと暗号化スイートをopenssl、vsftpdの設定ファイルで設定する必要がありました。ついでにhttpdの設定もなぜか触ることに。

事の発端

まず初めに疑ったのは、Implicit モードがデフォルトで使用している990 番ポートをlftpのプログラムかftpコマンドが使用しようとしているのではないか?ということ。Expicitモードで21番ポートをファイアウォールで開けてても、そこではなく990番が空いていないためコントロールコネクションが確立していないのかもしれないと思いました。

We’ll need to open port 21 for FTPS login and commands. Port 990 is default for TLS, but WordPress appears to use port 21 exclusively ......
「TLSで990がデフォルトになっていてもFTPでのログインとコマンドは21番ポートを使用する必要がありますが、(例えば)WordPressは21番をブロックしてしまうようで......」

参考サイト

つまり、疑問点はImplicit(990ポートが使用される)とExplicit モードのどちらのモードをftp-userユーザーの接続に於いてどのように選択しているか、ということです。

環境

Amazon Linux 2023
vsftpd: version 3.0.5
httpd 2.4.58
openssl 3.0.8

確認すること

【確認その1】sudo firewall-cmd --permanent --list-allでサーバーの以下のポートへのインバウンドアクセスが許可されていることを確認する。

下記の実行結果は、ufw(Not firewalld in RHEL)での設定結果。

To                         Action      From
--                         ------      ----
21/tcp                     ALLOW       Anywhere
65000:65535/tcp            ALLOW       Anywhere

とくに65000〜65535はパッシブモードで接続するときのポート番号の値の範囲。

以下の出力は必須かどうかわからない(手元の環境では出力されなかった)。

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere

上記をチェックした上で、lftpコマンドをデバッグオプション (-dフラグ)を付けて実行すると、パスワードを入力した直後に下記のエラーメッセージが。

An unexpected TLS packet was received

このようなエラーメッセージの場合、以下の投稿のトラブルシューティングにしたがい、エラーが解消できるか試してみてください。


【確認その2】(任意)990番ポートを開放してnetstatでLISTENできているか確認する

もしこれでFTPSがいけたら、Implicitモードが使用されていることがわかる。

Explicitモードはコントロールコネクションとデータコネクションに分かれているから接続できないのでは?という疑問

追記 (2025/5/13):
本節タイトルに誤謬があります。コネクションが2つに分かれているのはFTP全般でいえることです。Explicitモードにおいてネゴシエーションが平文と暗号化の2つに分かれているということが言いたかったです。

lftpは厳密にはFTPクライアントではないらしいです。

Despite its name lftp is not an ftp "client". It is a tool that allows you to run ftp, ftps or other commands
「lftpという名前ですがこれはFTPクライアントではありません。ftpやftps、その他のコマンドを実行できるようにするツールです。」

It is important to note that lftp is a session tool. It is not staying logged in as you might think but rather issues new commands to the remote using the credentials you supplied when you started lftp. This caused me grief early on because I thought it logged in successfully when I started lftp and it was only after viewing debug/verbose output that I realized it was attempting and failing to login when I ran individual commands within it.
「重要なのはlftpはセッションツールであることに注意が必要だということです。誰もが思っているようにログインしたままにはならないのです。
lftpを起動するときに入力する認証情報で、リモートマシンにたいして新規にコマンドを発行しているだけです。
私も最初これには頭を抱えました。lftpを起動した時点でログインが成功していると思っていたのですが、デバッグ/バーボスの出力を表示したあとで、コマンドを個別に実行する時にログインしようとして失敗したことに気づいただけでした。」

FTP with the SSL modules turned on ( LinuxQuestions.org )

この人が書いているログインというのは、FTPによるリモートマシンへのログインのことだと思われます。つまりコントロールコネクションがlftpによって行われるわけではなく、あくまでローカルマシンがftpコマンドを実行している。

私がlftpを使っていたのは、FTPで転送する宛先のグローバルIPアドレスを指定するためでした。その用途ではうまくいきました。暗号化されていないFTPはファイルのアップロードもlftpでできていました。

が、FTPSのExplicitモードでlftpを使用しようとすると、セッションがデータコネクションには自動では切り替わらないのかもしれません。おそらくコントロールコネクションとデータコネクションが別のセッションであり、lftp側でサーバーの設定にしたがってセッションを発行している。つまり、FTPのAUTHコマンドでコネクションを初期化したあと、別のセッションでlsとかcdでリモートのディレクトリやファイルを参照する時に、個別のコマンドレベルで失敗しているのでは。

トラブルシューティング

ケース 1:
lftp等でvsftpdサーバーにFTP接続しようとした場合に“An unexpected tls packet is recieved” というメッセージが表示される。

  • Explicitモードのvsftpdあるいはサーバーの設定を見直す
  • opensslを見直す
  • ftpコマンドの設定を見直す

ftpコマンドについては、このサイト の質問の回答を参考にすると、ImplicitモードしかサポートしていないFTPクライアントはほとんどなく、ftpコマンドの設定如何(いかん)で状況が変わるとはあまり思えないため、今回は見直さないことにします。

Step1. opensslで稼働確認

Explicit modeで確認する場合、以下のopensslコマンドを-starttlsフラグを付けて実行。(Implicit modeの場合は openssl s_client -connect localhost:990を実行)この方法は後述の参考記事に記載されています。

openssl s_client -connect localhost:21 -starttls ftp

実行結果 (概略)

「Verify return code: 18 (self-signed certificate)」や「220 (vsFTPd 3.0.5)」、
Post-Handshake New Session Ticket arrived: SSL-Session: Protocol : TLSv1.3 Cipher : TLS_AES_256_GCM_SHA384 Session-ID: 00F53A0C46727.....
のように表示される。SSL-Sessionのブロックが2か所出力され、それぞれ別のSession-IDが表示されている。

上記の詳細の行につづき、以下のようにサーバー証明書の詳細などが出力される。気になったのは、その下のSSL handshake... 以降の部分。(一部を抜粋)

.bash
CONNECTED(00000003) # 接続されている

...
......
......
---
Server certificate #サーバー証明書
-----BEGIN CERTIFICATE-----
MIIDMjCCA......
............
cAJYhI
-----END CERTIFICATE-----
...
......
---
SSL handshake has read 1622 bytes and written 743 bytes
Verification error: self-signed certificate # lftpの設定ファイルで、 ssl:verify-certificateの値をfalse(証明書を検証しない)にすればOK (自己署名証明書の場合)
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 # TLSのバージョン、Cipher (暗号化スイート)
Server public key is 2048 bit # 公開鍵のサイズ
Secure Renegotiation IS NOT supported # 失敗 (Cipher (暗号化スイート) がサポートされていない

上の抜粋の一番下の方にSecure Renegotiation IS NOT supportedと表示されており、これは暗号化スイートのTLS_AES_256_GCM_SHA384がサポートされていない可能性がある (下記の投稿を参照)ため、そのあたりを確認する。

Step2. 暗号化スイートがサポートされているか確認する

以下の記事を参考にすると、openssl s_clientで確認した結果、Secure Renegotiation IS NOT supportedとなっている場合、指定した暗号化スイートはサポートされていない可能性がある。

openssl s_clientを実行した後、Cipherの行にはTLS_AES_128_GCM_SHA256と出力されているが、その2行下くらいでSecure Renegotiation IS NOT supportedと表示されている。

実行結果 (概略)

再度確認のため、以下のopenssl s_clientコマンドを実行。

.bash
# 別の暗号化スイートを指定して確認。
openssl s_client -connect example.com:443 -cipher ECDHE-RSA-AES256-GCM-SHA384
CONNECTED(00000003)
...
......
---
SSL handshake has read 5489 bytes and written 318 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256 # TLSのバージョン (v1.3)、暗号化スイート
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
.bash
# サーバーが特定のTLSバージョンで、指定した暗号化スイートをサポートしているか確認する
sudo openssl s_client -connect example.com:443 -cipher TLS_AES_256_GCM_SHA384 -quiet -no_tls1_3
Call to SSL_CONF_cmd(-cipher, TLS_AES_256_GCM_SHA384) failed # サポートしていない

また、Copilot (MicrosoftのChatgpt) にきいてみると、vsftpdは TLS v1.2を標準でサポートしているらしい。
しかしTLS_AES_128_GCM_SHA256はTLS v1.3に固有のものらしいので、vsftpdがこの暗号化スイートをサポートしていないのかもしれない。(おそらく AES_256_GCM_SHA384も同じくTLS v1.3に固有のものと考えられるため。)

Step3. TLS v1.2でサポートされている暗号化スイートに変えてみる

TLSのバージョンごとに、サポートされている暗号化スイートの一覧をopenssl ciphersコマンドで調べることができるようです。
4行目までは、TLSv1.3のみでサポートされているものが出てきている。上記の説明で出てきたTLS_AES_256_GCM_SHA384も、一番上の行に出ています。これらはvsftpdでサポートされていない可能性があるので、今回はそれ以外の暗号化スイートを使うように修正します。

.bash
# サポートされている暗号化スイートの一覧を取得(一部を抜粋)
openssl ciphers -v
TLS_AES_256_GCM_SHA384         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(256)            Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256   TLSv1.3 Kx=any      Au=any   Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(128)            Mac=AEAD
TLS_AES_128_CCM_SHA256         TLSv1.3 Kx=any      Au=any   Enc=AESCCM(128)            Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256)            Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH     Au=RSA   Enc=AESGCM(256)            Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128)            Mac=AEAD
AES256-GCM-SHA384              TLSv1.2 Kx=RSA      Au=RSA   Enc=AESGCM(256)            Mac=AEAD
AES256-CCM                     TLSv1.2 Kx=RSA      Au=RSA   Enc=AESCCM(256)            Mac=AEAD
AES128-GCM-SHA256              TLSv1.2 Kx=RSA      Au=RSA   Enc=AESGCM(128)            Mac=AEAD
AES128-CCM                     TLSv1.2 Kx=RSA      Au=RSA   Enc=AESCCM(128)            Mac=AEAD
AES256-SHA256                  TLSv1.2 Kx=RSA      Au=RSA   Enc=AES(256)               Mac=SHA256
DHE-RSA-AES256-GCM-SHA384      TLSv1.2 Kx=DH       Au=RSA   Enc=AESGCM(256)            Mac=AEAD
DHE-RSA-CHACHA20-POLY1305      TLSv1.2 Kx=DH       Au=RSA   Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-RSA-AES256-CCM             TLSv1.2 Kx=DH       Au=RSA   Enc=AESCCM(256)            Mac=AEAD
DHE-RSA-AES128-GCM-SHA256      TLSv1.2 Kx=DH       Au=RSA   Enc=AESGCM(128)            Mac=AEAD
DHE-RSA-AES128-CCM             TLSv1.2 Kx=DH       Au=RSA   Enc=AESCCM(128)            Mac=AEAD
......
..........

vsftpd.confの設定箇所

vsftpdの設定ファイルに、暗号化スイート (Cipher) の設定を行います。
openssl genpkey -algorithm ec で秘密鍵を作ったので、ECDSA ( Elliptic Curve Digital Signature Algorithm)を指定していますが、-algorithm rsa でカギを作成した場合は、RSAに対応した暗号化スイートを指定する必要があることに注意。
また、: (コロン)でつなぐことで複数の暗号化スイートを指定することも可能ですが、下記の例では簡単化のために一つor2つだけ指定しています。

vsftpd.conf
# ssl_ciphersを指定。

例1) ECDSAでカギを生成した場合
# AES256 & SHA384
ssl_ciphers=ECDHE-ECDSA-AES256-GCM-SHA384

例2) ECDSAでカギを生成した場合(AES128 & SHA256)
# AES128 & SHA256
ssl_ciphers=ECDHE-ECDSA-AES128-GCM-SHA256


例3) RSAの鍵交換でカギを生成した場合
# AES256 & SHA384
ssl_ciphers=DHE-RSA-AES256-GCM-SHA384

今回実際に設定したvsftpd.confは以下です。

vsftpd.conf
# ECDHの鍵交換でカギを生成した場合 (OpenSSL方式でして)
ssl_ciphers=kEECDH+AESGCM+AES128:kEECDH+AESGCM:kEECDH+AES128:kEECDH+AES:!aNULL:!eNULL:!LOW:!EXP


# 秘密鍵と証明書のパスを指定。
rsa_cert_file=/path/to/your/certificate.pem
rsa_private_key_file=/path/to/your/ecdsa_private.key

# 使用プロトコル
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1=NO
ssl_tlsv11=NO
ssl_tlsv12=YES

下の方で秘密鍵と証明書のパスを指定していますが、Copilotによるとrsa_というディレクティブ名でもECDSAをRSAのかわりに指定してもOKなようです。openssl genpkey -algorithm ecのようにアルゴリズム(左記のコマンドの場合はECDSA)を指定して秘密鍵を作成していてもRSA以外の場合でも、rsa_private_key_fileにそのパスを設定すれば大丈夫です。

openssl.cnfの設定箇所

opensslの設定ファイルにTLS v1.2を使用するように指定する。

/etc/pki/tls/openssl.cnf
MaxProtocol = TLSv1.2

その他

  • vsftpd が GnuTLSでコンパイルされている場合、OpenSSL方式の暗号化スイート規約を優先しない可能性がある。そのためもしGnuTLSを使用している場合、OpenSSLベースのvsftpdパッケージへの切り替えを検討する。
.bash
# GnuTLSの情報が表示されるか確認
vsftpd -version
vsftpd: version 3.0.5 # とくになし

# libsslが表示されれば、GnuTLSを使用していない
ldd $(which vsftpd) | grep ssl
        libssl.so.3 => /lib64/libssl.so.3 (0x00007f61c44f4000)

# vsftpdのパッケージを確認
rpm -qa | grep vsftpd
vsftpd-3.0.5-1.amzn2023.0.2.x86_64 # GnuTLSではない

Step4. httpdのSSL設定をおこなう

ssl.confの内容を自動で生成してくれるサイトを使用して、SSLCipherSuiteなどを設定する。以下のサイトは自分が使用するhttpdとopensslのバージョンを指定すると、設定値を自動生成してくれる。

.bash
# httpdのバージョン確認
yum list installed | grep httpd
httpd.x86_64                              2.4.58-1.amzn2023                  @amazonlinux

# opensslのバージョン確認
yum list installed | grep openssl
openssl.x86_64                            1:3.0.8-1.amzn2023.0.10            @System
/etc/httpd/conf.d/ssl.conf
/* 許可する暗号化プロトコルを設定 */
#SSLProtocol all -SSLv3
SSLProtocol             -all +TLSv1.2

/* 暗号化スイートを指定する */
#SSLCipherSuite PROFILE=SYSTEM
SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305

/* ランクの高い暗号化スイートを優先するようサーバーに強制 */
SSLHonorCipherOrder on

確認

openssl s_client コマンドでTLS接続の状態を確認します。

.bash
# TLSv1.2で接続の詳細を確認
sudo openssl s_client -connect localhost:443 -tls1_2 < /dev/null
CONNECTED(00000003)
...
......
..........
#
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384 # TLSv1.2がサポートしている暗号化スイートが使用されている
Server public key is 2048 bit
Secure Renegotiation IS supported # 安全な再ネゴシエーションがサポートされている

ケース 2:
lftpで lscd コマンドを打っても “Not connected” というメッセージが表示されるだけで、 pwdコマンドを打つと何も結果が返ってこない。

lftpにログインすると、正常ならリモート側のカレントディレクトリに対してUNIX系のシェルと同じように lscd が実行できますが、ディレクトリのリストが返ってこないし、カレントディレクトリも移動しない状況の場合、以下を確認してください。

Step1. クライアント側のシステムログ

.bash
sudo journalctl -a --lines=all # すべての行を出力 (あるいは journalctl -af で最新のログだけを出力)

Step2. lftpをデバッグモードで起動
デバッグモードで ls を実行し、表示されるメッセージを確認します。

.bash
lftp -u hoge -e "debug 12" ftp://example.com
~> ls

Step3. Step2 で以下のメッセージが出る場合
GNUTLS: Received record packet of unknown type 53gnutls_record_recv: An unexpected TLS packet was received. というメッセージが出ることがあります。

.bash
lftp -u hoge -e "debug 12" ftp://example.com
Password:
~> ls
......
..........
---- Connecting to xx.xx.xxx.xxx (xx.xx.xxx.xxx) port 21
<--- 220 (vsFTPd 3.0.5)
......
..........
<--- 200 Always in UTF8 mode.
---> USER ftp-user
<--- 331 Please specify the password.
---> PASS XXXX
GNUTLS: Received record packet of unknown type 53
**** gnutls_record_recv: An unexpected TLS packet was received. # エラーが発生
---- Closing control socket
ls: Fatal error: gnutls_record_recv: An unexpected TLS packet was received. # エラーが発生

上記のようなエラーメッセージの場合、以下の投稿のトラブルシューティングにしたがい、エラーが解消できるか試してみてください。


Step 1. のシステムログに異常がない場合で、Step 3. で書いているエラーではなく "Not connected”が直らない場合、下記の投稿で対処法を書いています。手順に従い、宛先のグローバルIPアドレスを見直し、TLSプロトコルバージョンの優先順位の設定を行ってください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?