🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
SSL

SSL(Secure Sockets Layer)とは、暗号化されたプロトコルで、インターネット上での通信セキュリティを提供しています。

暗号化

ネットワークを通じてデジタルデータをやり取りする際に、第三者に解読されることのないよう、アルゴリズムを用いてデータを変換すること。

Tomcat

TomcatはApache Software Foundation (ASF)で開発されたオープンソースのWebコンテナです。

Q&A

解決済

1回答

3326閲覧

Apache Tomcat 8.5のSSL通信において、RSA方式の暗号スイートによる通信ができない。

hase_0691

総合スコア3

SSL

SSL(Secure Sockets Layer)とは、暗号化されたプロトコルで、インターネット上での通信セキュリティを提供しています。

暗号化

ネットワークを通じてデジタルデータをやり取りする際に、第三者に解読されることのないよう、アルゴリズムを用いてデータを変換すること。

Tomcat

TomcatはApache Software Foundation (ASF)で開発されたオープンソースのWebコンテナです。

0グッド

1クリップ

投稿2021/01/27 02:47

前提・実現したいこと

Tomcatのserver.xmlにてキーストアファイルを指定し、以下暗号スイートによる通信を行いたいです。
0. TLS_RSA_WITH_AES_128_CBC_SHA256
0. TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256

2.による通信はできますが、1.による通信ができていません。
Tomcatのserver.xmlにおいて設定不備などがあればご教授いただけますと幸いです。
なお、Tomcatサービスはローカルホストにて起動しており、サーバとクライアント共にローカルホストでやり取りをしています。

発生している問題・エラーメッセージ

Client Helloに対し、TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256の暗号スイートだと成功しますが、TLS_RSA_WITH_AES_128_CBC_SHA256の暗号スイートだとサーバからHand Shake Errorとなり、通信ができません。

該当のソースコード

Tomcatのserver.xmlの抜粋を添付します。
値は一部マスクしています。

<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" maxPostSize="0" > <SSLHostConfig certificateVerification="required" sslProtocol="TLS" protocols="TLSv1.2" ciphers="TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" honorCipherOrder="true" truststoreFile="....\Cert\Server\truststore.jks" truststorePassword="XXX"> <Certificate certificateKeystoreFile="....\Cert\Server\keystore.jks" certificateKeystorePassword="XXX" type="RSA" /> </SSLHostConfig> </Connector>

試したこと

server.xmlのSSLHostConfigタグにおいて、暗号スイート(ciphers)を固定にし、優先度(honorCipherOrder)をtrueにすることで、"TLS_RSA_WITH_AES_128_CBC_SHA256"の優先度を上げてみましたが、結果は変わりませんでした。

補足情報(FW/ツールのバージョンなど)

以下に各ツールのバージョンを記載します。

  • Apatch Tomcat 8.5
  • java version "1.8.0_271" 32bit (Tomcatサービス起動時のJava)

また、端末OSはWindows 10 Proです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

68user

2021/01/27 03:00

わたしの知識がなくて読み取れないだけなんですが、これは ブラウザ->Coyote->Tomcat というつながりで、この暗号スイート設定は Tomcat が Server 側として利用可能な暗号スイートを設定している、ということでしょうか?
68user

2021/01/27 03:00

↑が全然的外れなことを言っているようであればスルーいただいて結構です。
hase_0691

2021/01/27 03:14

説明が不足しており、申し訳ありません。 はい。その通りです。
guest

回答1

0

ベストアンサー

よくわかってませんが回答したいので回答します。

ブラウザ->Coyote->Tomcat

となると SSL クライアントは、ブラウザ (Coyote が単なる proxy である場合) か Coyote (Coyote->Tomcat がつなぎっぱなしである場合) なんですよね。

その場合、ブラウザなり Coyote なりの ClientHello で使用される暗号スイートに TLS_RSA_WITH_AES_128_CBC_SHA256 は含まれているのでしょうか。

またいずれにせよ、https://www.dondari.com/%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8BSSL%E6%9A%97%E5%8F%B7%E5%8C%96%E3%82%B9%E3%82%A4%E3%83%BC%E3%83%88%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B のように暗号スイート指定で Tomcat に直接つなぐとどうなるでしょうか。

投稿2021/01/27 03:32

68user

総合スコア2022

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hase_0691

2021/01/27 07:04

ご返答、ありがとうございます。 >その場合、ブラウザなり Coyote なりの ClientHello で使用される暗号スイートにTLS_RSA_WITH_AES_128_CBC_SHA256 は含まれているのでしょうか。 ⇒はい。含まれています。 >暗号スイート指定で Tomcat に直接つなぐとどうなるでしょうか。 ⇒ご提示いただいたURLに従ってcurlコマンドで通信確認を試みましたが、「対象のプリンシパル名が間違っています。」というエラーが出まして、このエラーが解決できなかったので代替案としてopensslコマンドによる通信確認を行いました。 その結果、やはりサーバからの応答はECDHE-ECDSA-AES128-SHA256の暗号スイートのみであるように見えました。 コマンド結果を貼り付けさせていただきます。 なお、コマンドの結果は一部マスクしています。 ■curlコマンドの実行結果 >curl https://localhost:443/XXX --tlsv1.2 --head --ciphers "AES128-SHA256,ECDHE-ECDSA-AES128-SHA256" --verbose * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 443 (#0) * schannel: SSL/TLS connection with localhost port 443 (step 1/3) * schannel: checking server certificate revocation * schannel: sending initial handshake data: sending 174 bytes... * schannel: sent initial handshake data: sent 174 bytes * schannel: SSL/TLS connection with localhost port 443 (step 2/3) * schannel: failed to receive handshake, need more data * schannel: SSL/TLS connection with localhost port 443 (step 2/3) * schannel: encrypted data got 1531 * schannel: encrypted data buffer: offset 1531 length 4096 * schannel: SNI or certificate check failed: SEC_E_WRONG_PRINCIPAL (0x80090322) - 対象のプリンシパル名が間違っています。 * Closing connection 0 * schannel: shutting down SSL/TLS connection with localhost port 443 * schannel: clear security context handle curl: (35) schannel: SNI or certificate check failed: SEC_E_WRONG_PRINCIPAL (0x80090322) - 対象のプリンシパル名が間違っ ています。 ■opensslコマンドの実行結果 >openssl s_client -connect 127.0.0.1:443 -showcerts -CAfile "RSAのルート証明書、中間証明書を連結したファイル" CONNECTED(00000174) Can't use SSL_get_servername depth=0 C = US, O = "Hoge, Inc", OU = TEST Hoge Fuga ECC TTT Certificate, CN = ttt verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 C = US, O = "Hoge, Inc", OU = TEST Hoge Fuga ECC TTT Certificate, CN = ttt verify error:num=21:unable to verify the first certificate verify return:1 5232:error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:ssl\record\rec_layer_s3.c:1544:SSL alert number 42 --- Certificate chain 0 s:C = US, O = "Hoge, Inc", OU = TEST Hoge Fuga ECC TTT Certificate, CN = ttt i:C = US, O = Hoge Fuga, OU = ECC TTT CA0003, CN = TEST Hoge Fuga ECC TTT CA -----BEGIN CERTIFICATE----- ~~略~~ -----END CERTIFICATE----- --- Server certificate subject=C = US, O = "Hoge, Inc", OU = TEST Hoge Fuga ECC TTT Certificate, CN = ttt issuer=C = US, O = Hoge Fuga, OU = ECC TTT CA0003, CN = TEST Hoge Fuga ECC TTT CA --- Acceptable client certificate CA names C = US, O = Hoge Fuga, OU = ECC EEE CA0004, CN = TEST Hoge Fuga ECC EEE CA C = US, O = Hoge Fuga, OU = RSA Root CA0001, CN = TEST Hoge Fuga RSA Root CA C = US, O = Hoge Fuga, OU = RSA TTT CA0001, CN = TEST Hoge Fuga RSA TTT CA C = US, O = Hoge Fuga, OU = ECC TTT CA0003, CN = TEST Hoge Fuga ECC TTT CA C = US, O = Hoge Fuga, OU = ECC Root CA0003, CN = TEST Hoge Fuga ECC Root CA C = US, O = Hoge Fuga, OU = RSA EEE CA0001, CN = TEST Hoge Fuga RSA EEE CA Client Certificate Types: ECDSA sign, RSA sign, DSA sign Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:DSA+SHA256:ECDSA+SHA1:RSA+SHA1:DSA+SHA1 Shared Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:DSA+SHA256:ECDSA+SHA1:RSA+SHA1:DSA+SHA1 Peer signing digest: SHA256 Peer signature type: ECDSA Server Temp Key: ECDH, P-256, 256 bits --- SSL handshake has read 1536 bytes and written 471 bytes Verification error: unable to verify the first certificate --- New, TLSv1.2, Cipher is ECDHE-ECDSA-AES128-SHA256 Server public key is 256 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-ECDSA-AES128-SHA256 Session-ID: 31383EE269B65B5DC7D94F1332D2372CB45B1D93AAF617A2DDDBC637E4FF4756 Session-ID-ctx: Master-Key: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ PSK identity: None PSK identity hint: None SRP username: None Start Time: 1610696446 Timeout : 7200 (sec) Verify return code: 21 (unable to verify the first certificate) Extended master secret: yes ---
68user

2021/01/27 07:36 編集

openssl s_client -connect 127.0.0.1:443 -cipher TLS_RSA_WITH_AES_128_CBC_SHA256 -tlsextdebug -msg -tls1_2 はどうなりますか? (★編集で -tls1_2 を追加) ClientHello ではクライアント側が対応可能な暗号スイートを指定します。 ServerHello は、クライアントが提示した暗号スイートの中から、サーバ側が対応していてもっともセキュア (設定次第) なものを選んで返します。 なお、こちらの環境では TLS_RSA_WITH_AES_128_CBC_SHA256 がなく、openssl では送れませんでした (ので検証できません)。 で、tomat 側を TLS_RSA_(略) だけにして、上記クライアント側からも TLS_RSA_(略) を指定した場合、結果が「TLS_RSA_(略) でつながった」となれば OK。「暗号スイートが一致せず失敗」となったら、Tomcat 側の設定がおかしいのでは、と思います。 その上で、  ・SSL クライアントは、ブラウザ (Coyote が単なる proxy である場合)  ・SSL クライアントは、Coyote (Coyote->Tomcat がつなぎっぱなしである場合) のどっちなのかを確認し、例えば Coyote であるなら「Coyote はそもそも ClientHello にて TLS_RSA_(略) を送信しているのか?」を疑うべきかなと。 ちなみに openssl で ClientHello の詳細を見られるかと思ったのですがどうやら無理っぽいですね。Wireshark とかでパケットキャプチャできそうならやってみてください。
68user

2021/01/27 07:38

https://www.openssl.org/docs/man1.0.2/man1/ciphers.html を見て思いましたが、TLS_RSA_WITH_AES_128_CBC_SHA256 って、openssl 的には AES128-SHA256 なのかもしれませんね。 なので、 openssl s_client -connect 127.0.0.1:443 -cipher AES128-SHA256 -tlsextdebug -msg -tls1_2 でやってみてください。www.google.com は不可、www.microsoft.comwww.yahoo.com はつながりました。
68user

2021/01/27 07:49

あと、https://qiita.com/ngyuki/items/380c96ef6b66928f16ce によると「CentOS 6 や 7 の curl の SSL は OpenSSL ではなく NSS」だそうです。Windows 版がどうなっているかはわかりませんが、NSS の CipherSuite 名は下記のようです (古いので最新ではなさそうですが)。 https://github.com/servo/nss/blob/master/tests/iopr/server_scr/cipher.list curl・openssl での CipherSuite 名指定が正しいかは注意する必要があるかもしれません。
68user

2021/01/27 07:55

https://gakumon.tech/tomcat/server_xml/ssl.html ---- NIOおよびNIO2コネクタは、JSSE Java SSL実装またはOpenSSL実装を使用しますが、 APR/ネイティブコネクタはOpenSSLのみを使用します。 Tomcat 8.5より前は、JSSEとOpenSSLで異なる設定属性が使用されていました。 Tomcat 8.5以降では、JSSEとOpenSSLの両方に共通の設定属性が使用されています。 また、JSSE OpenSSL実装を使用する場合は、JSSE属性またはAPR属性を使用して設定を行うことができます(ただし、同じ設定内の両方の型ではありません)。 これは、SSLコネクターのコネクター実装を簡単に切り替えるのを助けるためです。 ciphers 暗号はOpenSSL構文を使用して有効にします。 (サポートされている暗号のリストと構文については、OpenSSLのマニュアルを参照してください)。 代わりに、標準のOpenSSL暗号名または標準のJSSE暗号名を使用する暗号のコンマ区切りリストを使用することもできます。 ---- tomcat 側の設定において、TLS_RSA_WITH_AES_128_CBC_SHA256 が「標準のOpenSSL暗号名または標準のJSSE暗号名」に合致するのかも気になります。
hase_0691

2021/01/28 05:50

ご返答、ありがとうございます。 以下、いただいたアドバイスに沿って実施してみましたが、結果は芳しくありませんでした。 >openssl s_client -connect 127.0.0.1:443 -cipher AES128-SHA256 -tlsextdebug -msg -tls1_2 >でやってみてください。 実施した結果、同じくHand Shake Errorになってしまいました。 以下にコマンド結果を貼り付けます。 コマンド結果は一部マスクしています。 ========================================== >openssl s_client -connect 127.0.0.1:443 -cipher AES128-SHA256 -tlsextdebug -msg -tls1_2 -CAfile "RSAのルート証明書、中間証明書を連結したファイル" CONNECTED(00000150) >>> ??? [length 0005] 16 03 01 00 71 >>> TLS 1.2, Handshake [length 0071], ClientHello ~~略~~ <<< ??? [length 0005] 15 03 03 00 02 <<< TLS 1.2, Alert [length 0002], fatal handshake_failure 02 28 16460:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl\record\rec_layer_s3.c:1544:SSL alert number 40 --- no peer certificate available --- No client certificate CA names sent --- SSL handshake has read 7 bytes and written 118 bytes Verification: OK --- New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : 0000 Session-ID: Session-ID-ctx: Master-Key: PSK identity: None PSK identity hint: None SRP username: None Start Time: 1611810820 Timeout : 7200 (sec) Verify return code: 0 (ok) Extended master secret: no --- ========================================== >Wireshark とかでパケットキャプチャできそうならやってみてください。 パケットキャプチャでも確認しました。 ClientHalloではTLS_RSA_WITH_AES_128_CBC_SHA256の暗号スイートを指定しているのに対し、ServerHelloではTLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256を返しているためHandShakeErrorとなっているようでした。 >curl・openssl での CipherSuite 名指定が正しいかは注意する必要があるかもしれません。 各コマンドでの CipherSuite 名は、以下のコマンドで表示されたものを指定していますので、指定方法としては正しいのではないかなと思っております。 >openssl ciphers -v 【参考URL】 https://www.dondari.com/%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8BSSL%E6%9A%97%E5%8F%B7%E5%8C%96%E3%82%B9%E3%82%A4%E3%83%BC%E3%83%88%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B >tomcat 側の設定において、TLS_RSA_WITH_AES_128_CBC_SHA256 が「標準のOpenSSL暗号名または標準のJSSE暗号名」に合致するのかも気になります。 ご指摘のとおり、Tomcatのserver.xmlにおいて暗号スイート(ciphers)の値を以下に変えてみましたが、結果は同様でした。 >ciphers="AES128-SHA256,ECDHE-ECDSA-AES128-SHA256"
68user

2021/01/28 06:01 編集

そもそも暗号スイートの問題であれば ClientHello と ServerHello で終了するのではないか、証明書云々まで行っていればそれは暗号スイート合意できているのではと思うのですがどうでしょうか。 要は tomcat 側を ciphers="AES128-SHA256" なり ciphers="TLS_RSA_WITH_AES_128_CBC_SHA256" にして、クライアント側が AES128-SHA256 なり TLS_RSA_WITH_AES_128_CBC_SHA256 を ClientHello で送って証明書のエラーになったら、暗号スイートの合意はできていると言えないでしょうか。
68user

2021/01/28 06:04

あと、tomcat 側に TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 を入れてしまうと、TLS_RSA_WITH_AES_128_CBC_SHA256 が使えないから TLS_ECDHE_(略) が使われたのか、暗号強度が高いから TLS_ECDHE_(略) が使われたのか判断できないと思います。外してみてはどうでしょうか。
hase_0691

2021/01/29 14:26 編集

ご返答、ありがとうございます。 > tomcat 側を ciphers="AES128-SHA256" なりciphers="TLS_RSA_WITH_AES_128_CBC_SHA256" にして、クライアント側が AES128-SHA256 なり TLS_RSA_WITH_AES_128_CBC_SHA256 を ClientHello で送って証明書のエラーになったら、暗号スイートの合意はできていると言えないでしょうか。 tomcat側を ciphers="TLS_RSA_WITH_AES_128_CBC_SHA256" 固定とし、クライアント側も TLS_RSA_WITH_AES_128_CBC_SHA256 によるClientHelloを送りましたら、通信が行えました。 その際、キーストアファイルもRSAのみとしたもので作成し直しました。 >tomcat 側に TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 を入れてしまうと、TLS_RSA_WITH_AES_128_CBC_SHA256 が使えないから TLS_ECDHE_(略) が使われたのか、暗号強度が高いから TLS_ECDHE_(略) が使われたのか判断できないと思います。外してみてはどうでしょうか。 ご指摘の通り、 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 を外してみたところ、うまくいきました。 ただ、Tomcatの設定としては TLS_ECDHE_(略) も TLS_RSA_(略) もどちらも許容するという設定になっているはずで、クライアントからは TLS_RSA_(略) で通信を行いたいと指定しているにも関わらず、Tomcatは TLS_ECDHE_(略) で通信を行おうとしている動作が謎のままです。 ※TLS_ECDHE_(略)の方が暗号強度が高いから、でしょうか。。。 表題の「RSA方式の暗号スイートによる通信ができない」という問題は解決できましたので、質問をクローズさせていただきます。 様々なアドバイスをいただいた 68user 様のご回答をベストアンサーとさせていただきます。 ありがとうございました。
68user

2021/01/29 14:41

それは大変よかったです。仕事をせずに調べまくったかいがありました。 https://gakumon.tech/tomcat/server_xml/ssl.html > デフォルトでは、暗号が定義されている順序は優先順位として扱われます。 honorCipherOrderを参照してください。 書き方は openssl ciphers 方式ですので、左が優先度高、右が優先度低だと思います (ちなみに最後に :@STRENGTH を付けると openssl にて定義されている暗号強度順で並びます)。 なので、左が優先されていないということであれば honorCipherOrder が true になっていないのではと思いますがどうでしょうか (よくわかってませんが、これが true 以外だとクライアントが提示した ciphers の並び順を尊重するのでしょうか)。
hase_0691

2021/02/02 03:53

コメントありがとうございます。 >左が優先されていないということであれば honorCipherOrder が true になっていないのではと思いますがどうでしょうか これについては、すでに試してみていました。 server.xmlにて、honorCipherOrder を true にしていたにも関わらず、TLS_RSA_(略) の通信ができませんでした。 逆に、Tomcatの設定上は TLS_ECDHE_(略) も TLS_RSA_(略) もどちらも許容するという設定にしておいて、クライアントからは TLS_ECDHE_(略) の通信を行おうとすると、正常に通信できたという結果になりました。 このあたりのTomcatの動きがやはり謎なので、別スレッドで質問をさせていただこうと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問