ハローワールド。
本記事ではChromeで使えるサーバー証明書を作成します。
もし、Firefoxでは動くのにChromeで動かない証明書を作って困ってこの記事を見つけた方はChromeでも動く証明書を作成するへ行きましょう。
環境
Windows20H2上のWSL2(Ubuntu 20.04 LTS)上のopensslを利用します。
$ openssl version
OpenSSL 1.1.1f 31 Mar 2020
事前準備
証明書を作成する前にいくつか事前準備します。
まず証明書を配置するフォルダを作成しましょう。
$ mkdir certification_test
今後はこのフォルダを基点として説明していきます。
httpsサーバー
また、chromeでちゃんと動くか確認するため、httpsサーバーも用意します。httpsのサーバーはnode.jsで簡易的に実装しました。
const fs = require("fs");
const https = require("https");
const privateKey = fs.readFileSync("server.key");
const certificate = fs.readFileSync("server.crt");
https
.createServer(
{
cert: certificate,
key: privateKey,
},
(req, res) => {
res.writeHead(200);
res.write("<h1>Hello, World!</h1>");
res.end();
}
)
.listen(1443);
同じフォルダにserver.key
, server.crt
を配置して実行すればそれらの証明書を利用したHTTPSサーバーが建ちます。これを利用しましょう。
hostsの変更
IPに対する証明書の発行は難しいので、URL(サーバーのFQDN)に対する証明書を発行したいですが、そうすると今度はURLとIPアドレスを誰も紐付けてくれません。
そのため、今回はhostsを利用します。今回受け側はWindowsなので、C:\Windows\System32\drivers\etc\hosts
を編集します。管理者権限が必要であり、更には重要なファイルなので自己責任で編集してください。
管理者権限で編集する必要があります。スタートボタンの検索窓で「メモ帳」を検索して、右クリックから管理者で実行し、上のフォルダへいきhostsを選択れば(デフォルトでは.txtでフィルターが掛かっているので、全てのファイルに変更すること)、編集が可能です。
後は下記のように編集しましょう(FQDNをtest.sa2taka.com
とする場合)
...(中略)
127.0.0.1 test.sa2taka.com
証明書の作成
事前準備も完了したので、証明書を作成していきます。
ルート証明書
ルート証明書、別名自己署名証明書を作成します。
- 秘密鍵の作成
$ openssl genrsa 4096 > root.key
- 署名要求ファイルの作成。途中で入力する値は任意です
$ openssl req -new -sha256 -key root.key -out root.csr
(中略)
Country Name (2 letter code) [AU]:jp
State or Province Name (full name) [Some-State]:sa2taka
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:sa2taka
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:sa2taka_root
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
- 自己署名
$ openssl x509 -req -in root.csr -signkey root.key -days 3650 -out root.crt
CAフォルダ
opensslはCA*認証局)に簡単になれる機能が存在します。そのためにはいくつかフォルダを作成する必要があります。
$ cat /etc/ssl/openssl.cnf | grep dir -n3
...(中略)
43-[ CA_default ]
44-
45:dir = ./demoCA # Where everything is kept
46:certs = $dir/certs # Where the issued certs are kept
47:crl_dir = $dir/crl # Where the issued crl are kept
48:database = $dir/index.txt # database index file.
49-#unique_subject = no # Set to 'no' to allow creation of
50- # several certs with same subject.
51:new_certs_dir = $dir/newcerts # default place for new certs.
52-
53:certificate = $dir/cacert.pem # The CA certificate
54:serial = $dir/serial # The current serial number
55:crlnumber = $dir/crlnumber # the current crl number
56- # must be commented out to leave a V1 CRL
57:crl = $dir/crl.pem # The current CRL
58:private_key = $dir/private/cakey.pem# The private key
デフォルトだとこんな感じだと思います。
上記に合わせてフォルダやファイルを作成していきます。ちなみに./
はopenssl実行フォルダを表し/etc/ssl/
を表すわけではありません。なので任意のフォルダで問題ありません。
# 45行目 dir
$ mkdir demoCA
# 46行目 cersts
$ mkdir demoCA/certs
# 47行目 crl_dir
$ mkdir demoCA/crl
# 48行目 database
$ touch ./demoCA/index.txt
# 51行目 new_certs_dir
$ mkdir demoCA/newcerts
# 53行目 certificate
$ cp root.crt demoCA/cacert.pem
# 54行目 serial
$ echo 01 > ./demoCA/serial
# 58行目 private_key
$ mkdir demoCA/private
$ cp root.key demoCA/private/cakey.pem
サーバー証明書
続いてサーバー証明書を作っていきます。これが実際にhttpsサーバーで利用する証明書と秘密鍵です。
- 秘密鍵の作成
$ openssl genrsa 4096 > server.key
- 署名要求ファイルの作成。Common NameはFQDNにしておくのがいいでしょう。
$ openssl req -new -sha256 -key server.key -out server.csr
(中略)
Country Name (2 letter code) [AU]:jp
State or Province Name (full name) [Some-State]:sa2taka
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:sa2taka
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:test.sa2taka.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
- CAで署名(openssl x509ではなくcaを利用する)
$ openssl ca -in server.csr -out server.crt
(中略)
Sign the certificate? [y/n]:
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
試してみる
できたてほやほやの証明書を使ってhttpsサーバーを立ててアクセスしてみます。
ルート証明書を登録していないので当然エラーになります。なのでルート証明書をインストールしましょう。Windowsではcrtファイルをダブルクリックして、信頼されたルート証明機関を選択してインストールするだけです[1]。
では、アクセスしてみると…あれ、動きませんね。
でも、Firefoxでは動きます[2]。IEでも動きます。
ブラウザによって挙動が変化するんですね。
Chromeでも動く証明書を作成する
Webブラウザが証明書とURLをどうやって紐付けていると、元来「Common Name」という項目を見ていました。本証明書でもtest.sa2taka.com
が載っています。下記のCN
がそれですね。
$ openssl x509 -in server.crt -noout -subject
subject=C = jp, ST = sa2taka, O = sa2taka, CN = test.sa2taka.com
しかしChromeではCommon Nameを見なくなりました。Chrome 58での非推奨・削除項目(2017年!)を見ると、下記のようないくつかの理由でCommonNameを見なくなりました。
- commonNameへのフォールバックはRFC2818[3](2000年(!)発行)で非推奨とされている[4]
- commonNameは曖昧であるため、脆弱性の原因となっている
- commonNameを削除することによる互換性のリスクは低い
では何を見るのか? 上記のブログにも記載はありますが、subjectAlternativeName
(通称SAN)を見ます。
証明書の新規作成
というわけで証明書にSANを追加してあげれば良さそうです。
SANはいわゆるv3 extensionsであり、手っ取り早く追加するには下記の方法でいけます。
- 下記のファイルを用意します。
san.txt
と名付けておきます。
subjectAltName = DNS:test.sa2taka.com
- openssl caをやるときに邪魔になるファイルを消します。
$ rm demoCA/index.txt
$ touch demoCA/index.txt
- 証明書作成する
$ openssl ca -in server.csr -out server.crt -extfile san.txt
証明書を確認すると、ちゃんとSANが設定されていますね。
$ openssl x509 -in server.crt -noout -text | grep Alt -1
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:test.sa2taka.com
これで晴れてChromeでも動作するようになりました。
WSLのフォルダはエクスプローラーのアドレスバーに
wsl$
と入力するとアクセスできます。 ↩︎FirefoxはOSと証明書が分離されているので、別途証明書を設定からインポートしてください ↩︎
Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead.
Common Name の使用は既存の慣行であるが、これは非推奨であり、認証局は代わりに dNSName の利用を推奨する
encourage: 励ます、勧める、推奨する