logo

2024327

やむを得ず最近のOpenSSLでレガシーなプロトコルを使いたい時の設定

レガシーなプロトコルやアルゴリズムにしか対応していないサーバーに接続する際、最近の OpenSSL がインストールされた環境からはデフォルト設定のままでは接続できないことがあります。サーバー側がすぐに改修できないなどのやむを得ない状況で回避する方法を紹介します。

やること

OpenSSL は OPENSSL_CONF 環境変数に設定ファイルへのパスを入れることで作成した設定ファイルを読み込んでくれます。

今回は任意のディレクトリに次のような設定ファイルを作ります。

openssl_conf = openssl_init

[openssl_init]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol  = TLSv1
CipherString = DEFAULT:@SECLEVEL=0

MinProtocol は読んで字の如くです。

CipherStringSECLEVEL については OpenSSL ドキュメントに記載があります。今回の検証環境では 0(全て許可)まで下げる必要がありました。

検証する

検証環境

  • OpenSSL 3.0.11
  • nginx 1.25.4
  • curl 7.88.1
  • docker 25.0.3
├── cert
│   ├── cert.pem
│   └── key.pem
├── nginxconf
│   └── default.conf
└── opensslconf
    └── tlsv1.cnf

検証の準備

検証用に docker ネットワークと証明書を作ります。

docker network create mynet
openssl req \
  -x509 \
  -newkey rsa:4096 \
  -keyout cert/key.pem \
  -out cert/cert.pem \
  -sha256 \
  -days 3650 \
  -nodes \
  -subj "/CN=testserver"

nginx サーバーを立ち上げます。./nginxconf/default.conf に各ケースに記載の設定を入れます。

docker run -it --rm \
  -v ${PWD}/nginxconf:/etc/nginx/conf.d \
  -v ${PWD}/cert:/etc/ssl/certs/my \
  --net mynet \
  --name testserver \
  nginx

サーバーが TLS 1.3 に対応している場合

まずは nginx をデフォルトの状態にして試します。

server {
    listen       443 ssl;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    ssl_certificate     /etc/ssl/certs/my/cert.pem;
    ssl_certificate_key /etc/ssl/certs/my/key.pem;
}

そしてクライアント側(curl)も何も設定せずにアクセスします。当然うまくいきます。

docker run -it --rm --net mynet nginx curl -kvs -o /dev/null https://testserver
出力
*   Trying 172.20.0.2:443...
* Connected to testserver (172.20.0.2) port 443 (#0)
* ALPN: offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [25 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [1207 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [520 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=testserver
*  start date: Mar  8 12:01:47 2024 GMT
*  expire date: Mar  6 12:01:47 2034 GMT
*  issuer: CN=testserver
*  SSL certificate verify result: self-signed certificate (18), continuing anyway.
* using HTTP/1.1
} [5 bytes data]
> GET / HTTP/1.1
> Host: testserver
> User-Agent: curl/7.88.1
> Accept: */*
> 
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [265 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [281 bytes data]
* old SSL session ID is stale, removing
{ [5 bytes data]
< HTTP/1.1 200 OK
< Server: nginx/1.25.4
< Date: Fri, 08 Mar 2024 12:42:55 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Wed, 14 Feb 2024 16:03:00 GMT
< Connection: keep-alive
< ETag: "65cce434-267"
< Accept-Ranges: bytes
< 
{ [615 bytes data]
* Connection #0 to host testserver left intact

TLS v1/v1.1 のみ対応している場合

次にサーバー側がレガシーな場合を想定して古いプロトコルのみに限定します。

server {
    listen       443 ssl;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    ssl_certificate     /etc/ssl/certs/my/cert.pem;
    ssl_certificate_key /etc/ssl/certs/my/key.pem;
    ssl_protocols       TLSv1 TLSv1.1;
    ssl_ciphers         @SECLEVEL=0:ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
}

デフォルト状態のクライアントではエラーになりました。

docker run -it --rm --net mynet nginx curl -kvs -o /dev/null https://testserver --tlsv1
出力
*   Trying 172.20.0.2:443...
* Connected to testserver (172.20.0.2) port 443 (#0)
* ALPN: offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [116 bytes data]
* TLSv1.1 (IN), TLS handshake, Certificate (11):
{ [1204 bytes data]
* TLSv1.1 (IN), TLS handshake, Server key exchange (12):
{ [554 bytes data]
* TLSv1.1 (OUT), TLS alert, internal error (592):
} [2 bytes data]
* OpenSSL/3.0.11: error:0A00014D:SSL routines::legacy sigalg disallowed or unsupported
* Closing connection 0

最初に記載した OpenSSL の設定ファイルを投入してみるとうまくいきました。

docker run -it --rm -v ${PWD}/opensslconf/tlsv1.cnf:/openssl.cnf -e OPENSSL_CONF=/openssl.cnf --net mynet nginx curl -kvs -o /dev/null https://testserver --tlsv1
出力
*   Trying 172.20.0.2:443...
* Connected to testserver (172.20.0.2) port 443 (#0)
* ALPN: offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [116 bytes data]
* TLSv1.1 (IN), TLS handshake, Certificate (11):
{ [1204 bytes data]
* TLSv1.1 (IN), TLS handshake, Server key exchange (12):
{ [554 bytes data]
* TLSv1.1 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.1 (OUT), TLS handshake, Client key exchange (16):
} [37 bytes data]
* TLSv1.1 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.1 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.1 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.1 / ECDHE-RSA-AES256-SHA
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=testserver
*  start date: Mar  8 12:01:47 2024 GMT
*  expire date: Mar  6 12:01:47 2034 GMT
*  issuer: CN=testserver
*  SSL certificate verify result: self-signed certificate (18), continuing anyway.
* using HTTP/1.1
} [5 bytes data]
> GET / HTTP/1.1
> Host: testserver
> User-Agent: curl/7.88.1
> Accept: */*
> 
{ [5 bytes data]
< HTTP/1.1 200 OK
< Server: nginx/1.25.4
< Date: Fri, 08 Mar 2024 13:58:03 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Wed, 14 Feb 2024 16:03:00 GMT
< Connection: keep-alive
< ETag: "65cce434-267"
< Accept-Ranges: bytes
< 
{ [615 bytes data]
* Connection #0 to host testserver left intact

参考文献