それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

CAを作る(openssl.cnf )中間認証局を作る、サーバー証明書を作る。ローカルドメインをHTTPS化する。

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

Chromeブラウザ(Windows)でみてみる。

Windowsの証明書マネージャに作ったMyCAを「ルート証明書」として突っ込む

(これはとても危険行為です。通常はルート証明書を書き換えることは禁忌です。)

certmgr.msc

すべてのタスク→インポート

ウイザードの開始

ファイルを選ぶ

最終確認が出る

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

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

chromeブラウザで確認する。

ローカルドメイン ( .lan ) に対して証明書エラーが回避され、通常通りHTTPS通信になっている。

中間認証局の役割。

中間認証局を作って見るために、煩雑なことをやっている。

HTTPS化するだけなら

オレオレ・ルート証明書だけで十分である。

参考資料