Cloudflare で SNI なしでも SSL 接続できるようにする



# SNI とは

> [SSL関連用語集 – Cloudflareヘルプセンター](https://support.cloudflare.com/hc/ja/articles/360026016272)
>
> Server Name Indication (サーバー名の表示)(SNI)
> SNIでは、一つのサーバーが一つのIPアドレスを使っている複数のWebサイトに対して、複数のTLS証明書をホストできます。TLSハンドシェイクのWebサイトホスト名を追加し、共有のIPを使用する際にどのWebサイトが提示したかをサーバーに通知するのもSNIです。Cloudflareでは、[専用SSL証明書](https://support.cloudflare.com/hc/articles/228009108)と多くの[Universal SSL証明書](https://support.cloudflare.com/hc/articles/204151138)のためにSNIを使っています。最新のSNIブラウザサポートの詳細をについては、当社のガイドをご参照ください。

# SNI なし (Non-SNI)

モダンなブラウザでは、ほとんどの場合で SNI をサポートしています。
まれに古いブラウザでは、SNI をサポートしていない場合があり、Cloudflare を経由する際に対応が求められます。

# Cloudflare Edge 証明書タイプ別の対応

以下のサイトを参考に必要事項を抜き出してみました。

>  [Browser compatibility · Cloudflare SSL docs](https://developers.cloudflare.com/ssl/ssl-tls/browser-compatibility#other-products)

| Feature/Product     | Universal SSL | Dedicated Certificates (= Advanced Certificate Manager) | Custom Certificates (Modern) | Custom Certificates (Legacy) |
| ------------------- | ------------- | ---------------------- | ---------------------------- | ---------------------------- |
| Clients without SNI | x             | x                      | x                            | o                            |

> 参考 : [Introducing: Advanced Certificate Manager](https://blog.cloudflare.com/advanced-certificate-manager/)

# SNI ありの通信確認方法

```shell
% openssl version
OpenSSL 1.1.1k  25 Mar 2021
```

`openssl` コマンドでは `-servername` オプションなしでもデフォルトで SNI が送信されますが、以下のコマンドで確認できます。

> https://www.openssl.org/news/changelog.html
> **Changes between 1.1.0i and 1.1.1 [11 Sep 2018]**
> s_client will now send the Server Name Indication (SNI) extension by  default unless the new "-noservername" option is used. The server name  is based on the host provided to the "-connect" option unless overridden by using "-servername".

```shell
export HOST_TO_CHECK="xxx.company"
echo | openssl s_client -connect $HOST_TO_CHECK:443 -servername $HOST_TO_CHECK </dev/null 2>/dev/null | openssl x509 -noout -text
```

↓ Universal SSL の場合に SNI ありで通信すると、以下のような応答が得られます。

```shell
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0e:8a:7b:66:27:1e:87:81:8a:e1:d1:8f:a8:13:29:b4
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3
        Validity
            Not Before: Jun 28 00:00:00 2021 GMT
            Not After : Jun 27 23:59:59 2022 GMT
        Subject: C = US, ST = California, L = San Francisco, O = "Cloudflare, Inc.", CN = sni.cloudflaressl.com
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:6c:7d:89:13:ed:d5:c6:67:d2:c2:64:11:de:06:
                    5f:7f:f3:30:b6:65:81:7f:77:b1:47:26:a9:dd:c5:
                    cd:6c:4e:9b:af:a6:1b:af:fc:c1:df:10:91:74:9c:
                    12:11:bf:47:d9:9d:36:ed:6c:e2:92:df:a1:ad:2e:
                    41:bd:fd:85:24
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Authority Key Identifier: 
                keyid:A5:CE:37:EA:EB:B0:75:0E:94:67:88:B4:45:FA:D9:24:10:87:96:1F

            X509v3 Subject Key Identifier: 
                37:AD:33:C9:C0:30:8E:4A:75:0D:8D:FB:03:2F:A2:9C:EE:58:79:5C
            X509v3 Subject Alternative Name: 
                DNS:xxx.company, DNS:*.xxx.company, DNS:sni.cloudflaressl.com
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:http://crl3.digicert.com/CloudflareIncECCCA-3.crl

                Full Name:
                  URI:http://crl4.digicert.com/CloudflareIncECCCA-3.crl

            X509v3 Certificate Policies: 
                Policy: 2.23.140.1.2.2
                  CPS: http://www.digicert.com/CPS

            Authority Information Access: 
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/CloudflareIncECCCA-3.crt

            X509v3 Basic Constraints: critical
                CA:FALSE
            CT Precertificate SCTs: 
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 29:79:BE:F0:9E:39:39:21:F0:56:73:9F:63:A5:77:E5:
                                BE:57:7D:9C:60:0A:F8:F9:4D:5D:26:5C:25:5D:C7:84
                    Timestamp : Jun 28 17:04:24.417 2021 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:21:00:A8:5C:CC:F6:02:35:AB:6B:02:42:CA:
                                81:C5:A5:AE:83:A9:3E:B7:F5:D8:8C:F8:D9:BF:47:10:
                                AA:6F:9D:20:F6:02:20:1B:79:B8:FC:47:A7:4C:7B:E8:
                                D1:ED:8D:21:79:AA:7D:D0:FB:AC:28:91:DA:AC:6F:C1:
                                54:AF:38:D6:FF:68:80
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 22:45:45:07:59:55:24:56:96:3F:A1:2F:F1:F7:6D:86:
                                E0:23:26:63:AD:C0:4B:7F:5D:C6:83:5C:6E:E2:0F:02
                    Timestamp : Jun 28 17:04:24.479 2021 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:20:50:04:94:C4:D2:A6:CE:28:1A:62:73:C2:
                                A6:39:3C:81:49:2E:A8:55:7E:BF:1D:86:E8:CD:CD:73:
                                09:D5:7B:A2:02:21:00:9A:AD:C2:15:52:2B:7C:68:D2:
                                0F:A5:3B:97:B8:15:B0:B1:5D:54:B9:0F:1A:7B:5A:EC:
                                0A:82:AB:EA:55:9C:5E
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 51:A3:B0:F5:FD:01:79:9C:56:6D:B8:37:78:8F:0C:A4:
                                7A:CC:1B:27:CB:F7:9E:88:42:9A:0D:FE:D4:8B:05:E5
                    Timestamp : Jun 28 17:04:24.505 2021 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:21:00:DA:6F:E8:08:6D:2B:46:C6:A5:4C:E0:
                                0B:DF:DE:E1:5D:7C:7B:69:DC:57:D4:4F:48:AE:CD:27:
                                D6:06:79:34:FA:02:20:21:38:38:B5:DD:1F:EC:54:66:
                                E5:D0:0A:D3:79:C3:84:D0:DF:A4:D4:B8:A2:C2:40:5D:
                                20:20:CC:7D:1C:A8:90
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:21:00:cf:dc:f6:cf:53:89:48:39:38:ed:42:8c:e1:
         4a:9a:3d:e7:63:06:19:77:79:bb:ca:d1:68:12:0c:fe:ad:96:
         75:02:20:5c:68:e6:9b:83:bc:cc:91:90:b8:bb:2c:5e:d1:0e:
         35:08:dc:e7:26:52:ea:b0:9c:16:1f:1a:d4:dd:d6:49:38
```



# SNI なし（Non-SNI）の通信確認方法

`-noservername` オプションを使います。

```shell
export HOST_TO_CHECK="xxx.company"
echo | openssl s_client -connect $HOST_TO_CHECK:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -text
```

↓ Universal SSL の場合に SNI なし（Non-SNI）で通信すると、以下のような応答が得られます。

```shell
unable to load certificate
4451958272:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
```

# カスタム SSL 証明書 （Legacy）での通信確認

## 証明書の取得

### `acme.sh` のインストール

```shell
curl https://get.acme.sh | sh
```

### 証明書発行

アカウント登録をします。

```shell
acme.sh --register-account -m my@example.com
```

マニュアルモードで証明書発行依頼をかけます。

```shell
acme.sh --issue --dns -d xxx.company -d '*.xxx.company' \
--yes-I-know-dns-manual-mode-enough-go-ahead-please \
--force --keylength ec-384
```

以下のような応答が得られるので、DNS に TXT レコードを登録します。

```shell
Add the following TXT record:
Domain: '_acme-challenge.xxx.company'
TXT value: 'XXX'
Please be aware that you prepend _acme-challenge. before your domain
so the resulting subdomain will be: _acme-challenge.xxx.company
Add the following TXT record:
Domain: '_acme-challenge.xxx.company'
TXT value: 'XXX'
Please be aware that you prepend _acme-challenge. before your domain
so the resulting subdomain will be: _acme-challenge.xxx.company
Please add the TXT records to the domains, and re-run with --renew.
Please add '--debug' or '--log' to check more details.
See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead.
```

![image-20210630102121855](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210630102121855.png)

その後に、以下のコマンドを実行します。

```shell
acme.sh --renew -d xxx.company -d '*.xxx.company' \
--yes-I-know-dns-manual-mode-enough-go-ahead-please \
--force --ecc
```

うまくいけば数分後に証明書ファイルがダウンロードされます。

```shell
Cert success.
-----BEGIN CERTIFICATE-----
xxx
-----END CERTIFICATE-----
Your cert is in  /home/kyouhei/.acme.sh/xxx.company_ecc/xxx.company.cer 
Your cert key is in  /home/kyouhei/.acme.sh/xxx.company_ecc/xxx.company.key 
The intermediate CA cert is in  /home/kyouhei/.acme.sh/xxx.company_ecc/ca.cer 
And the full chain certs is there:  /home/kyouhei/.acme.sh/xxx.company_ecc/fullchain.cer 
```

## 証明書の登録

カスタム SSL 証明書をアップロードします。

![image-20210630103716016](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210630103716016.png)

先ほど取得した証明書ファイルの中身を入力し、「Legacy Client Support --> Legacy」を選択しアップロードします。

![image-20210630103958091](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210630103958091.png)

以下のような状態が確認できます。

![image-20210630105936636](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210630105936636.png)

## SNI なし（Non-SNI）の通信確認

以下のように SNI なし（Non-SNI）の通信もサポートされることが確認できます。

```shell
% export HOST_TO_CHECK="xxx.company"
% echo | openssl s_client -connect $HOST_TO_CHECK:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            16:7f:a2:a8:79:dc:94:b3:ab:e8:81:11:07:5b:2e:52
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: C = AT, O = ZeroSSL, CN = ZeroSSL ECC Domain Secure Site CA
        Validity
            Not Before: Jun 30 00:00:00 2021 GMT
            Not After : Sep 28 23:59:59 2021 GMT
        Subject: CN = xxx.company
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub:
                    04:ee:a2:6f:b7:11:aa:58:49:d6:cb:aa:3f:7f:b9:
                    b7:42:bd:5c:9a:e0:76:44:41:93:e5:3f:65:92:41:
                    fb:59:79:89:aa:71:6a:65:c5:ac:9e:47:84:17:9d:
                    2a:b5:f3:3b:87:e8:a0:5b:56:b0:87:58:9c:e5:45:
                    73:e6:a2:52:cd:ef:b5:03:48:da:4b:51:62:3f:05:
                    5c:2b:09:8a:83:09:46:7c:ab:61:29:13:72:51:e7:
                    56:89:b1:a3:c8:29:ea
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        X509v3 extensions:
            X509v3 Authority Key Identifier: 
                keyid:0F:6B:E6:4B:CE:39:47:AE:F6:7E:90:1E:79:F0:30:91:92:C8:5F:A3

            X509v3 Subject Key Identifier: 
                29:C7:BE:CB:06:6C:28:39:32:E2:4D:0A:EF:56:21:EC:53:09:55:67
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Certificate Policies: 
                Policy: 1.3.6.1.4.1.6449.1.2.2.78
                  CPS: https://sectigo.com/CPS
                Policy: 2.23.140.1.2.1

            Authority Information Access: 
                CA Issuers - URI:http://zerossl.crt.sectigo.com/ZeroSSLECCDomainSecureSiteCA.crt
                OCSP - URI:http://zerossl.ocsp.sectigo.com

            CT Precertificate SCTs: 
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 7D:3E:F2:F8:8F:FF:88:55:68:24:C2:C0:CA:9E:52:89:
                                79:2B:C5:0E:78:09:7F:2E:6A:97:68:99:7E:22:F0:D7
                    Timestamp : Jun 30 01:11:15.418 2021 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:21:00:92:F8:BB:1A:48:58:95:B0:D5:76:03:
                                05:46:90:14:8B:28:34:3A:AD:97:89:D5:B4:E2:F4:4A:
                                CF:3E:43:DB:E1:02:20:2A:30:9F:8C:21:CA:1F:5D:65:
                                B9:6E:CD:97:6B:DF:51:7F:A2:58:F9:90:9D:B7:A3:93:
                                A7:16:01:B3:6B:89:F4
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 44:94:65:2E:B0:EE:CE:AF:C4:40:07:D8:A8:FE:28:C0:
                                DA:E6:82:BE:D8:CB:31:B5:3F:D3:33:96:B5:B6:81:A8
                    Timestamp : Jun 30 01:11:15.377 2021 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:20:3A:BB:DE:E2:D6:FF:D4:9A:C7:2E:F8:DD:
                                DD:DC:50:32:83:5E:DC:4F:65:D7:A2:0C:75:4E:59:CB:
                                1B:13:D9:43:02:21:00:C3:86:F0:B6:66:70:DF:61:DB:
                                DF:16:09:64:9D:95:21:4A:5F:C5:A9:9C:FD:9C:45:75:
                                5E:A3:6D:D8:8A:07:7C
            X509v3 Subject Alternative Name: 
                DNS:xxx.company, DNS:*.xxx.company
    Signature Algorithm: ecdsa-with-SHA384
         30:66:02:31:00:c8:0e:52:c6:00:97:00:d9:30:60:d4:fc:a5:
         0e:b6:d9:02:5a:de:49:3b:b7:ef:d5:5c:76:c4:c6:4e:3d:e8:
         8f:27:50:cc:8a:3a:eb:55:09:b3:d3:eb:9c:21:ce:db:72:02:
         31:00:82:d7:21:cf:ae:1b:16:da:ba:9a:83:ef:15:90:16:11:
         fe:73:f8:05:71:6f:ac:91:39:5c:72:2f:03:bc:ac:c6:73:a2:
         43:e8:ba:2d:8b:74:a2:84:b7:f1:8d:e3:9c:ff
```