CAを作る(openssl.cnf )
MyCAという名前でRoot CA を作る。
mkdir MyCA
cd MyCA
必要なディレクトリを作る。
mkdir ./newcerts
mkdir ./requests
touch index.txt
echo 00 > serial
echo 00 > crlnumber
openssl.cnf を作る。
/etc/ssl/openssl.cnf
から必要な部分、[ ca ]
セクション から [ tsa ]
セクション手前 までを取り出す
cat /etc/ssl/openssl.cnf \
| sed -n '/\[ ca \]/,$p' \
| sed '/\[ tsa/,$d' \
> openssl.cnf
keyUsage(鍵用途)で証明書発行を許可した証明書(CAになれる)となるよう設定を変更
sed -i openssl.cnf -e '/^keyUsage = nonRepudiation/s|^|# |'
sed -i openssl.cnf -e '/keyUsage = cRLSign/s|^# ||'
有効期限を10年くらいにする(1年は365日と覚えてるだろうが、360日で計算してたほうが楽なので、1年は360日+誤差だと考えてたほうが計算が楽。)
sed -i openssl.cnf -e 's|365|3600|'
CAディレクトリをカレントにする
sed -i openssl.cnf -e 's|\./demoCA|\.|'
設定ファイルを確定させる。
cp openssl.cnf myCA.openssl.cnf
秘密鍵作成から、自己署名証明書の作成まで
openssl genrsa > myCA.priv.key
openssl req -new -subj "/C=JP/ST=Kyoto/O=my/CN=MyCA" -key myCA.priv.key > myCA.csr
openssl req -text < myCA.csr
openssl x509 -req -in myCA.csr -signkey myCA.priv.key > myCA.crt
自己署名証明書を作る。
openssl ca -config myCA.openssl.cnf -extensions v3_ca -in myCA.csr -keyfile myCA.priv.key -selfsign
PEM をコピーする
openssl x509 < newcerts/00.pem > myCA.crt
ここまでで、次のようになった
~/MyCA$ tree .
.
├── crlnumber
├── index.txt
├── index.txt.attr
├── index.txt.old
├── myCA.crt
├── myCA.csr
├── myCA.openssl.cnf
├── myCA.priv.key
├── newcerts
│ └── 00.pem
├── openssl.cnf
├── requests
├── serial
└── serial.old
2 directories, 12 files
中間認証局(intermediate)を作成してみる。
ディレクトリを確保する
mkdir MedCA
cd MedCA
初期化しておいて
mkdir ./newcerts
mkdir ./requests
touch index.txt
echo 00 > serial
echo 00 > crlnumber
設定ファイルをサクッと作る。
cat /etc/ssl/openssl.cnf \
| sed -n '/\[ ca \]/,$p' \
| sed '/\[ tsa/,$d' \
| sed -e 's|365|3600|' \
| sed -e '/^keyUsage = nonRepudiation/s|^|# |' \
| sed -e '/keyUsage = cRLSign/s|^# ||' \
| sed -e '/copy_extensions/s|^# ||' \
| sed -e 's|\./demoCA|\.|' \
> medCA.openssl.cnf
中間認証局用の秘密鍵とリクエスト作成
openssl genrsa > medCA.priv.key
openssl req -new -subj "/C=JP/ST=Kyoto/O=my medium/CN=MedCA" -key medCA.priv.key > medCA.csr
openssl req -text < medCA.csr
Root CA(MyCA)にリクエストを送信(コピー)する
cp MedCA/medCA.csr MyCA/requests/
Root CAに入り、中間認証局向けに証明書を発行してあげる
cd ../myCA
openssl ca \
-config myCA.openssl.cnf \
-extensions v3_ca \
-policy policy_anything \
-cert myCA.crt \
-in ./requests/medCA.csr \
-keyfile myCA.priv.key
結果を確認
openssl x509 -text < ./newcerts/01.pem
証明書PEMを払い出し(コピー)
openssl x509 < ./newcerts/01.pem > medCA.crt
mv medCA.crt ../MedCA/
一般利用者向けに証明書を中間認証局から発行する
nginx などで使えるように、DNS証明書(DV証明書を作る。)対象とするホスト名はraspi3.lan
とする。IPアドレスでも使えるようにIP:xxx.xxx.xxx.xxx
にも署名した証明書を作る。
今回は、SAN値(subject alternative name )を使って証明書を発行する。
SAN値を使うにはコンフィグ(openssl.cnf)の構成が必要
サーバー証明書を入れるディレクトリ
mkdir srv
cd srv
san.conf を作る。
cat << 'EOF' > san.cnf
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
commonName = Common Name (e.g. server FQDN or YOUR name)
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
# Write SANs(Subject Alternative Names)
DNS.1 = raspi3.lan
DNS.2 = raspi3.local
IP.1 = 10.3.0.2
IP.2 = 127.0.0.1
EOF
SANつきでCSRを作る
openssl genrsa > server.priv.key
openssl req -new \
-config san.cnf \
-subj "/C=JP/ST=Kyoto/L=Kyoto City/O=acid/CN=raspi3.lan" \
-key server.priv.key \
> server.csr
リクエストを認証局(中間)へコピーする
cp server.csr ../MedCA/requests/
中間認証局で署名する。
cd ../MedCA
openssl ca \
-config medCA.openssl.cnf \
-policy policy_anything \
-in requests/server.csr \
-cert medCA.crt \
-keyfile medCA.priv.key
サーバーの証明書を払い出し(コピー)
openssl x509 < newcerts/00.pem > server.crt
mv server.crt ../srv/
ここまでで、MyCA(root CA) → MedCA(中間CA) -> サーバー(証明書利用者)の3層構造が出来上がったわけである。
証明書の検証を行う。
証明書チェーンのファイルを作る
cat ../MedCA/medCA.crt ../MyCA/myCA.crt > chain.pem
verify すると。
openssl verify -verbose -CAfile chain.pem server.crt
# => server.crt: OK
これで使えることがわかる。
nginx で使ってみる
nginx で作った証明書と鍵を導入する。
/etc/nginx/sites-enabled/raspi3.lan.conf
server {
server_name raspi3.lan;
add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive";
listen 10.3.0.2:443 ssl http2;
ssl_certificate_key /home/takuya/certs/srv/server.priv.key;
ssl_certificate /home/takuya/certs/srv/chain.crt;
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
location / {
add_header Content-Type "text/html";
return 200 "<h1>It works.(nginx)</h1>\n";
}
}
設定を反映
sudo nginx -t
sudo nginx -s reload
クライアントから接続してみる
HTTPSで証明書が使えるか検証してみる
curl --cacert ./MyCA/myCA.crt https://raspi3.lan
# => <h1>It works.(nginx)</h1>
-k
の insecure オプションを使わなくても、curl が complainせずに暗号化通信が行えている
openssl でALPN/TLSプロトコルを見てみる。問題なさそう。
openssl s_client -connect 10.3.0.2:443 -crlf -servername raspi3.lan
Windowsの証明書マネージャに作ったMyCAを「ルート証明書」として突っ込む
(これはとても危険行為です。通常はルート証明書を書き換えることは禁忌です。)
certmgr.msc
すべてのタスク→インポート

ウイザードの開始

ファイルを選ぶ

最終確認が出る

ルート証明書を触るのは非常時なので「通常やらないことやってるけどダイジョブか」と更に注意が出る。

インポートされた(後で削除を忘れないよう)

chromeブラウザで確認する。

ローカルドメイン ( .lan ) に対して証明書エラーが回避され、通常通りHTTPS通信になっている。
中間認証局を作って見るために、煩雑なことをやっている。
オレオレ・ルート証明書だけで十分である。
参考資料