エラーメッセージ
curl: (35) TLS connect error: error:0A00010B:SSL routines::wrong version number
別の表記
- curl: (35) error:0A00010B:SSL routines::wrong version number
- curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number
最近の curl のリリース(ここでは 8.14.1)では、OpenSSL の理由文字列の前に「TLS connect error:」が付きます。curl 7.x では理由だけが出力されていました。OpenSSL 1.1.1 のビルドでは「error:1408F10B:SSL routines:ssl3_get_record:wrong version number」という長い形式で、OpenSSL 3.x では「error:0A00010B:SSL routines::wrong version number」と出力されます。
curl (OpenSSL backend) — CURLE_SSL_CONNECT_ERROR, SSL_R_WRONG_VERSION_NUMBER
このエラーの意味
curl は TLS の ClientHello を送信しましたが、返ってきた最初のバイト列は TLS レコードではありませんでした。OpenSSL はその応答からレコードヘッダーのバージョンフィールドを読み取り、意味のない値を検出します。典型的には、平文の HTTP サーバーが返した「HTTP/1.1 400」の文字です。メッセージの文言とは裏腹に、TLS のバージョンが原因であることはほとんどありません。相手側がそのポートで TLS を使っていないのです。
発生する理由
平文の HTTP で応答するポートへの https:// 接続
よくある8080 番や 3000 番ポートの開発サーバー、ロードバランサーの背後にあるバックエンド、設定を誤った listen ディレクティブは、HTTP で応答します。URL の http と https を取り違えることや、TLS のポート番号に http:// を使うことが、このメッセージの最もよくある原因です。
プロキシの URL は https:// なのに、プロキシは HTTP で通信している
よくあるHTTPS_PROXY=https://proxy:3128 と指定すると、curl はプロキシ自体と TLS を開始します。ほとんどのフォワードプロキシはクライアントからの平文の HTTP を想定しており、宛先への暗号化された CONNECT トンネルを開きます。そのため、HTTPS の通信であっても、プロキシの URL は http:// で始めるべきです。
STARTTLS ポートに対する暗黙的 TLS
ときどき25/587 番ポートの SMTP、143 番の IMAP、110 番の POP3、389 番の LDAP、そして PostgreSQL/MySQL は、平文で通信を開始し、後から TLS にアップグレードします。そこで TLS ハンドシェイクから始めると、すぐに失敗します。
サーバーの代わりにキャプティブポータルやフィルターが応答している
ときどきホテルや空港の Wi-Fi、ペアレンタルコントロールのフィルター、一部のファイアウォールは、443 番ポートへの通信を横取りし、TLS が始まる前に HTTP のリダイレクトページを返します。
修正方法
- 1.
ポートが実際にどのプロトコルで応答するかを確認する
同じポートに http:// でリクエストしてください。HTTP のレスポンスが返ってきたら、http:// を使うか、本来の TLS ポートを使ってください。どのポートで TLS ハンドシェイクが完了するかは、openssl s_client で確認できます。
bash # What does the port speak? An HTTP status line means plain HTTP. curl -sS -i http://api.example.com:8080/ | head -1 # HTTP/1.1 200 OK -> not TLS openssl s_client -connect api.example.com:8443 -brief </dev/null # handshake summary -> TLS - 2.
プロキシの URL には http:// を使う
プロキシへの TLS 接続をプロキシが明示的にサポートしていない限り、プロキシは http://host:port の形式で指定してください。宛先への接続は、CONNECT トンネルを通じて引き続きエンドツーエンドの TLS になります。
bash # Most corporate proxies accept plain HTTP from the client and tunnel HTTPS with CONNECT export HTTPS_PROXY=http://proxy.example.net:3128 # http:// even for HTTPS traffic curl -x http://proxy.example.net:3128 https://api.example.com/ - 3.
STARTTLS ポートでは STARTTLS を使う
メールのプロトコルの場合、curl はサブミッションポートと IMAP ポートでは --ssl-reqd で TLS にアップグレードし、465 番と 993 番では smtps:// と imaps:// のスキームで暗黙的 TLS を使います。
bash # Port 587/25 (SMTP) and 143 (IMAP) start in plain text and upgrade with STARTTLS curl --ssl-reqd smtp://mail.example.com:587 -v # Implicit TLS lives on 465 (SMTPS) and 993 (IMAPS) curl smtps://mail.example.com:465 -v - 4.
サーバー管理者:リスナーで TLS を有効にする
クライアントがこのポートで https:// を使うべきなら、リスナーで TLS を有効にし、証明書を設定する必要があります。そうでなければ、正しいポートを案内してください。
text # nginx: the port that clients reach with https:// needs the ssl flag server { listen 443 ssl; ssl_certificate /etc/nginx/tls/fullchain.pem; ssl_certificate_key /etc/nginx/tls/privkey.pem; }
関連するエラー
SSL routines:tls_validate_record_header:wrong version numberOpenSSL 3 (openssl s_client and any OpenSSL-based client)code: 'ERR_SSL_WRONG_VERSION_NUMBER'Node.js tls.connect / fetch (undici)[SSL: WRONG_VERSION_NUMBER] wrong version numberPython ssl module (OpenSSL)http: server gave HTTP response to HTTPS clientGo net/httpjavax.net.ssl.SSLException: Unsupported or unrecognized SSL messageJava (JSSE)