質問: "./cacert.pem" ``` cacert.pemは以下で取得し、上記の実装ファイルと同じ階層に置いています。 以下を指定して証明書を無視した場合は通信できており、 ``` OpenSSL::SSL::VERIFY_NONE ``` cert.pemが本当に存在しているのか以下のコマンドを実行すると、 証明書情報が出力されていたので保存されているのだと思います。 $ cat (ファイルパス)/cacert.pem ちなみに、以下は接続したと出力されたのですが、HTTPSを指定すると 接続を拒否されています。なにかサーバへの設定が必要なのでしょうか? ``` $ wget -S --spider http://xx.xx.xx.xx スパイダーモードが有効です。リモートファイルが存在してるか確認します。 --2018-05-10 09:27:27-- http://xx.xx.xx.xx/ xx.xx.xx.xx:80 に接続しています... 接続しました。 HTTP による接続要求を送信しました、応答を待っています... HTTP/1.1 200 OK ~~ $ wget -S --spider https://xx.xx.xx.xx スパイダーモードが有効です。リモートファイルが存在してるか確認します。 --2018-05-10 09:28:06-- https://xx.xx.xx.xx/ xx.xx.xx.xx:443 に接続しています... 失敗しました: 接続を拒否されました. ```
回答: 原因が解るわけではないのですが、気になる点もありますので、回答としてまとめておきます。 * `SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed` CA 証明書(つまり `cacert.pem`)が見つからない場合に発生することが多いようです。 以下の `https.ca_file = "./cacert.pem"` の項目を確認してください。 * `https = Net::HTTP.new('ホスト', 443)` `'ホスト'` と書かれているので判りにくいのですが、ここに IP アドレスは指定できません。必ずホスト名を指定してください。そしてそのホスト名はサーバ証明書に記載されている必要があります。 * `https.ca_file = "./cacert.pem"` `./` の部分は、実装ファイルと同じ階層という意味でなく、実行時のカレントディレクトリを意味します。階層は合っていますか? * 「cert.pemが本当に存在しているのか」 `cert.pem` ではなく `cacert.pem` のはずです。 * `wget -S --spider https://xx.xx.xx.xx` `https = Net::HTTP.new('ホスト', 443)` の場合と同様、https では IP アドレスの指定はできません。ホスト名を指定してください。 ただし、IP アドレスで指定したからといって「接続を拒否されました」にはならないはずで、 nginx (または apache 等) やファイアウォールの設定を確認する必要があるのかもしれません。 以上です。解決につながることを祈ります。 HTTPS (というか SSL/TLS) では、証明書の検証をします。 例えば `https://example.com` にアクセスすると、example.com がサーバ証明書を送ってくるので、その証明書が偽造されたものでないことと、その証明書の中の Common Name (CN) または Subject Alt Name に `example.com` と記載されていることを確認します。 これが証明書の検証です。 `Net::HTTP.new('ホスト名', 443)` の場合、指定した`ホスト名`が証明書の中に記載されていることを確認します。 同様に、`Net::HTTP.new('IPアドレス', 443)` の場合、指定した`IPアドレス`が証明書の中に記載されていることを確認します。しかし、証明書の中に IP アドレスは記載されていないため、検証は失敗し、そこでエラーとなります。 この検証は、verify_mode を VERIFY_PEER にすると行われますが、VERIFY_NONE の時は行われません。VERIFY_NONE にすると実行できるのは証明書を検証していないためです。