画像やリンクが無効になっている可能性もあるのでご了承下さい。
ローカル内部のみで SSL を用いた通信を行うとき、自己認証局でサーバー証明書を発行できると面白い。しかし、認証局を作ったり署名要求証明書を発行して認証局に署名させて、サーバー証明書を発行する等と言う手順がややこしくていつも頭を抱えていた。
故に殆ど触れることも無くセキュアとは何か? なんて無縁な事をしてきたけど、いざ触れ出すとこれがまた面白かったのでメモしておく。自サバ運営する上での自己満足度は結構高い。
自己認証局は通称「オレオレ認証局」とも言われる。自分で作って自分で署名するという動作から来る物だ。
自己認証局の作成
自己認証局が行う仕事は「署名要求証明書」と呼ばれる CSR ファイルに「署名を行うこと」になる。自己認証局は信用されなければ意味がないので、認証局の証明書を Windows などのシステムに「信用出来る認証局」として登録する作業も必要になってくる。
自分で作った物だから「自分では信用出来る」としても何ら問題は無い。しかし、見ず知らずの人に「俺は信用出来るよ」と言っても危ない人にしかならないのと同じで、自己認証局を面識の無い第三者に押しつけても可哀想だから、あくまでも利用はローカルに限った方が良いだろう。
自己認証局用設定ファイル作成
/etc/pki/tls/openssl.cnf にあるファイルは弄らないまま
cp /etc/pki/tls/openssl.cnf /etc/pki/tls/openssl-ca.cnf
などとして認証局用に設定ファイルを作成する。
編集箇所及び内容は次の差分の通りで行頭に “+” が付いた項目を編集していく。
--- /etc/pki/tls/openssl.cnf 2015-11-28 17:57:28.166161040 +0900
+++ /etc/pki/tls/openssl-ca.cnf 2015-11-26 20:41:21.842232517 +0900
@@ -70,7 +70,7 @@
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions = crl_ext
-default_days = 365 # how long to certify for
+default_days = 3650 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha256 # use SHA-256 by default
preserve = no # keep passed DN ordering
@@ -83,8 +83,8 @@
# For the CA policy
[ policy_match ]
countryName = match
-stateOrProvinceName = match
-organizationName = match
+stateOrProvinceName = optional
+organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
@@ -127,18 +127,18 @@
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
-countryName_default = XX
+countryName_default = JP
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
-#stateOrProvinceName_default = Default Province
+stateOrProvinceName_default = Kanagawa
localityName = Locality Name (eg, city)
-localityName_default = Default City
+localityName_default = Yokohama
0.organizationName = Organization Name (eg, company)
-0.organizationName_default = Default Company Ltd
+0.organizationName_default = BP7
# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
@@ -152,6 +152,7 @@
emailAddress = Email Address
emailAddress_max = 64
+emailAddress_default = hostmaster@example.com
# SET-ex3 = SET extension number 3
@@ -169,13 +170,13 @@
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
-basicConstraints=CA:FALSE
+basicConstraints=CA:TRUE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
-# nsCertType = server
+nsCertType = sslCA, emailCA
# For an object signing certificate this would be used.
# nsCertType = objsign
@@ -187,7 +188,7 @@
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
-# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+keyUsage = cRLSign, keyCertSign
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
countryName_default や stateOrProvinceName_default など、住所に関わる物は何度も入力する事が面倒だからデフォルト値を固定するようにした。認証局作成自体、慣れない作業で何度か作り直したのだがこの辺りの入力は面倒だと思った為。入力は国名の JP とローマ字で県と市程度とした。
自己認証局の秘密鍵作成
作業は root のままで行った。適当に作業用ディレクトリを作成して cd して作業を行う。
openssl genrsa -des3 -out ./ca.key 2048 -config /etc/pki/tls/openssl-ca.cnf
これで作業ディレクトリ (カレント) に ca.key の名前で自己認証局の秘密鍵が作成される。入力したパスワードは忘れずに。
それと chmod 400 ca.key もしておく。秘密鍵は漏れちゃいけない。
自己認証局の証明書を作成
ここで作成する証明書は後に CentOS で「信用すべき認証局」として登録する為にも用いる。
openssl req -new -x509 -days 3650 -sha256 -key ./ca.key -out ./ca.crt -config /etc/pki/tls/openssl-ca.cnf
これで自己認証局の証明書 ca.crt が作成される。
更に Web ブラウザで証明書のインポートに用いられる der 形式に変換した物も作成しておく。
openssl x509 -inform pem -in ./ca.crt -outform der -out ./ca.der
完成した ca.der は IE や Firefox 等にインポートさせると自己認証局が署名したサーバー証明書を「信用する」ようになる。Postfix や Dovecot にも同様に自己認証局の署名したサーバー証明書を用いるのであれば Thunderbird 等の MUA からも ca.der をインポートさせるとセキュリティ周りの例外設定が要らなくなるので便利。
作成した ca.{key,crt,der} の設置
cp ca.key /etc/pki/CA/private/
cp ca.crt /etc/pki/CA/
この様に設置しておく事にした。
更に CentOS 7 からも自己認証局を信用した認証局だという扱いをしたかったので次の作業も行う。
cp ca.crt /usr/share/pki/ca-trust-source/anchors/
update-ca-trust extract
特定のディレクトリに認証局の証明書をつっこんでコマンドを打つと OS に管理を任せることが出来る。実はこの作業を忘れて Webmail システム周りにて SMTP や POP,IMAP において認証が通らずに悩んだ。「SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca: SSL alert number 48」などとでるのがそれだ。
ca.der に関しては他システムからアクセスのし易い場所で良い。例えば httpd の DocumentRoot 直下だとか Samba で共有してるディレクトリだとかそういう所。
サーバー証明書の作成
サーバー証明書は Apache 等の httpd や Postfix といった MTA、Dovecot の POP, IMAP で SSL による暗号化通信で必須となる物になる。現在の自分はそれが主な用途である。
サーバー証明書用設定ファイル作成
/etc/pki/tls/openssl.cnf をサーバー証明書用にコピーを行ってから設定を行うようにする。
cp /etc/pki/tls/openssl.cnf /etc/pki/tls/openssl-server.cnf
設定前後の差分は次の通り。行頭 “-” が編集前、“+” が編集後である。
--- /etc/pki/tls/openssl.cnf 2015-11-28 17:57:28.166161040 +0900
+++ /etc/pki/tls/openssl-server.cnf 2015-11-26 20:43:14.345727364 +0900
@@ -70,7 +70,7 @@
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions = crl_ext
-default_days = 365 # how long to certify for
+default_days = 3650 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha256 # use SHA-256 by default
preserve = no # keep passed DN ordering
@@ -83,8 +83,8 @@
# For the CA policy
[ policy_match ]
countryName = match
-stateOrProvinceName = match
-organizationName = match
+stateOrProvinceName = optional
+organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
@@ -127,18 +127,18 @@
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
-countryName_default = XX
+countryName_default = JP
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
-#stateOrProvinceName_default = Default Province
+stateOrProvinceName_default = Kanagawa
localityName = Locality Name (eg, city)
-localityName_default = Default City
+localityName_default = Yokohama
0.organizationName = Organization Name (eg, company)
-0.organizationName_default = Default Company Ltd
+0.organizationName_default = BP7
# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
@@ -152,6 +152,7 @@
emailAddress = Email Address
emailAddress_max = 64
+emailAddress_default = hostmaster@example.com
# SET-ex3 = SET extension number 3
@@ -175,7 +176,7 @@
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
-# nsCertType = server
+nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
countryName_default や stateOrProvinceName_default など同じ項目を何度も手入力をするのが面倒なので Common Name 以外は自分の情報に合わせて決め打ちした方が楽出来る。
サーバー証明書の秘密鍵を作成
秘密鍵はどのみちパスワードを後から解除するので、最初から無しで作成する。パスワード有りの物でも httpd 起動時に自動でパスワードを流し込むような手段もある様だが、自分は手を付けていないので割愛。
これも自己認証局を作成した時と同じように作業ディレクトリを任意に作成してそこで作業を行うと良い。
openssl genrsa 2048 > server.key
chmod 400 server.key
秘密鍵は自己署名する物であっても外部に晒す事の無いよう、大事にしよう。
署名要求証明書の作成
秘密鍵を元にしてサーバー証明書として世に出る一段階前の状態、未署名の物になる。
openssl req -new -key server.key -sha256 -config /etc/pki/tls/openssl-server.cnf > server.csr
出来た server.csr が署名要求証明書になる。これに自己認証局が署名を行うとサーバー証明書になる。自己認証局ではなく、Verisign や GeoTrust といった公的な認証局にお金を払って署名して貰えばインターネットに出しても誰もが信用してもらえるサーバー証明書になる。もちろん無料の WoSign や来月から動きそうな Let’s Encrypt、定番の StartSSL 等の認証局を用いても良い。
自己認証局による署名
認証局が署名要求証明書に署名を行った物がサーバー証明書になる。今回署名する認証局は先程作成した自己認証局である。
Google Chrome 58 以降では CommonName の評価は行われず SANs を見るようになっているのでその設定も行うようにした。(2018/07/20)
openssl ca -in server.csr -keyfile /etc/pki/CA/private/ca.key -cert /etc/pki/CA/ca.crt -out server.crt -config /etc/pki/tls/openssl-server.cnf -extfile sans_temp.cnf
”-extfile sans_temp.cnf” でそのファイルの内容を追加設定としてあげる。sans_temp.cnf は次の内容で新規作成する。hoge.example.com の部分は CommonName と同じにする。
subjectAltName=@subject_alt_names
[ subject_alt_names ]
DNS.1 = hoge.example.com
これでサーバー証明書である server.crt が完成。
サーバー証明書の設置
今後必要になるのは server.{key,crt} の 2 つになる。これらを自分なりに管理しやすい場所へパーミッションに気を付けておいておく。秘密鍵は 400 とするが、サーバー証明書は任意で 644 で構わないと思う。
SSL に関する詳細な設定は Mozilla SSL Configuration Generator を利用すると楽。
Apache の場合
Apache の場合、/etc/httpd/conf.d 以下に証明書用のディレクトリを掘りつつ、更にホスト名 (FQDN) で掘ってその中に入れておくとかすると管理しやすい。
SSLEngine on
SSLCertificateFile /etc/httpd/conf.d/certs/hoge.example.com/server.crt
SSLCertificateKeyFile /etc/httpd/conf.d/certs/hoge.example.com/server.key
Nginx の場合
Nginx の設定がある /etc/nginx 以下に適当にディレクトリを certs 等と掘り、更にドメイン名でディレクトリを掘る。そこに秘密鍵とサーバー証明書を設置する等すれば管理もしやすいかなと思う。
ssl_certificate "/etc/nginx/certs/hoge.example.com/server.crt";
ssl_certificate_key "/etc/nginx/certs/hoge.example.com/server.key";
参考サイト
余り知識の無い状態から次のサイトをグルグルと見て回って参考にさせて頂いたら上手い事出来るようになったので、非常に助かった。
2015/11/28 22:53 追記というかメモというか。
本記事ではファイルの拡張子で .key, .csr, .crt と分けているが、OpenSSL のソースに納められている証明書類は全て .pem で統一されている。
例えば秘密鍵は server-key.pem でサーバー証明書が server-cert.pem というような感じだった。こうなると署名要求証明書は server-csr.pem などと言うのだろうか。
こういったことは統一した方が良いと思うので .pem にして命名規則を OpenSSL の物にあわせようかな……
サーバー証明書発行をスクリプトで処理
2015/11/30 追記 サーバーの秘密鍵作成から自己認証局による署名までをスクリプトにした
2018/07/20 スクリプトで処理される証明書に SANs の項目を追加
#!/bin/bash
#
if [ $# -ne 1 ]; then
echo "Usage: $0 FQDN"
exit 1;
fi
C=JP # C=Country (国名)
ST=Kanagawa # ST=STate or Province (県名)
L=Yokohama # L=Locality (市名)
O=BP7 # O=Organization (組織名/社名/団体名)
OU=Web # OU=Organization Unit (部門名/部署名)
CN=$1 # CN=Common Name (FQDN)
SUBJ="/C=$C/ST=$ST/L=$L/O=$O/OU=$OU/CN=$CN"
# 秘密鍵の作成
openssl genrsa 2048 > server.key
# 署名要求証明書の作成
openssl req -new -key server.key -sha256 -subj "$SUBJ" -config /etc/pki/tls/openssl-server.cnf > server.csr
# パーミッションを落とす
chmod 400 server.{key,csr}
# 署名要求証明書の内容確認
openssl req -noout -text -in server.csr
echo "Enter キーを押すと CSR に署名をします。中断するには CTRL+C を押して下さい。"
read
# Subject Alt Names の処理
cat << EOF > sans_temp.cnf
subjectAltName=@subject_alt_names
[ subject_alt_names ]
DNS.1 = $CN
EOF
# 自己認証局による署名を行う
openssl ca -in server.csr -keyfile /etc/pki/CA/private/ca.key -cert /etc/pki/CA/ca.crt -out server.crt -config /etc/pki/tls/openssl-server.cnf -extfile sans_temp.cnf -passin pass:PASSWORD
最後のコマンドの pass:PASSWORD は PASSWORD の部分を自己認証局の秘密鍵のパスワードを記しておくと良い。セキュリティ的に不安なら「-passin pass:PASSWORD」の部分を削除すると、毎回手入力になる。
署名要求証明書の作成までに留めるのであれば、「自己認証局による署名を行う」の次の行をコメントアウトする。若しくは署名要求証明書の内容確認後のキー入力待ちで CTRL+C を押して終了させる。
上記スクリプトの実行例はこちら。スクリプト名やスクリプト内の変数設定は筆者環境の物。
create-crt.sh hoge.example.com
Generating RSA private key, 2048 bit long modulus
.............................................................................................................+++
.........................................................................................................+++
e is 65537 (0x10001)
Certificate Request:
Data:
Version: 0 (0x0)
Subject: C=JP, ST=Kanagawa, L=Yokohama, O=BP7, OU=Web Contents, CN=hoge.example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bd:63:dc:f2:4c:2f:d0:64:aa:ab:5f:90:6b:dd:
f0:5a:20:95:15:33:10:60:d9:eb:5d:62:86:8f:4e:
77:f1:c9:ca:5b:71:f5:7a:01:00:51:53:1f:ac:62:
40:7e:8e:91:e1:36:05:50:e1:29:be:09:56:96:e9:
17:2c:a8:86:a6:b6:9f:d3:7e:5b:b9:de:80:9f:8a:
00:39:86:d6:12:07:04:97:0d:d0:ab:a9:b1:e4:88:
4a:16:26:24:4d:cc:71:e2:4a:90:ff:5e:e7:0c:4d:
5c:26:c0:dd:54:69:80:a6:7a:44:39:9d:e8:f6:40:
e0:60:a5:15:66:46:4d:6b:55:22:cb:8f:49:e8:8f:
62:f3:4a:c5:77:61:8e:39:85:3f:bf:d1:bd:26:05:
f5:d1:ae:e4:e5:4b:68:dc:ce:cd:e1:30:6b:80:71:
4d:b4:36:90:9f:82:21:b7:51:86:ee:36:ec:de:b9:
3a:75:eb:d8:ca:64:e4:88:cc:2d:ee:c5:38:d6:9b:
2e:2c:f6:8e:98:48:42:1a:be:e5:2a:5a:58:f5:67:
5b:ea:8c:4a:6d:b6:8b:79:64:15:91:4a:39:35:a8:
7b:61:7e:a5:24:10:73:99:31:e0:4a:46:7e:69:85:
68:db
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption
2b:e5:ce:94:c6:91:f2:dc:2d:df:30:f6:39:c6:7b:ec:45:71:
5c:57:1a:41:9a:5c:c2:2b:52:c0:f4:3a:57:d8:20:46:25:6c:
63:35:f7:0a:a2:7b:5d:ef:dd:d5:5d:ce:66:93:9d:53:f5:c1:
af:66:ae:0b:e1:d5:16:8c:15:f6:ee:83:93:e8:9a:65:de:13:
70:f7:c2:f2:3e:40:26:63:90:a1:64:77:82:30:71:11:7d:85:
9a:8b:d1:af:8f:14:86:78:85:2b:68:f9:af:51:2a:88:37:52:
46:3a:77:92:a6:d4:89:d2:29:bc:f7:54:ee:96:df:e0:dc:42:
44:80:a7:ae:8f:37:c6:e4:3a:0a:51:da:d6:12:5e:d8:8a:f2:
f6:56:d6:48:4f:85:36:b2:d8:93:5f:49:86:0d:3a:e4:d5:7a:
0e:a5:24:d7:bd:ab:3e:fb:eb:f2:35:6f:d5:03:42:02:14:e0:
3f:95:3c:01:09:61:b7:6c:20:4b:04:d4:b0:bc:23:cb:14:bf:
d0:36:20:f7:4a:19:1a:7b:7d:e9:e8:1d:cb:f1:61:c2:68:62:
7b:12:c3:1a:b1:5a:1a:a7:23:11:ac:0e:70:d6:b7:e0:2f:6c:
b2:ae:6c:e3
Enter キーを押すと CSR に署名をします。中断するには CTRL+C を押して下さい。
Using configuration from /etc/pki/tls/openssl-server.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 14 (0xe)
Validity
Not Before: Jul 20 11:21:10 2018 GMT
Not After : Jul 17 11:21:10 2028 GMT
Subject:
countryName = JP
stateOrProvinceName = Kanagawa
localityName = Yokohama
organizationName = BP7
organizationalUnitName = Web Contents
commonName = hoge.example.com
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:hoge.example.com
Certificate is to be certified until Jul 17 11:21:10 2028 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
記事更新履歴
2015/11/28 22:53
- メモ追記
2015/11/30
- サーバーの秘密鍵作成から自己認証局による署名までをスクリプトにして掲載
2018/07/20
- 記事体裁修正
- サーバー証明書に SANs を追加して Chrome 58 以降でもエラーが出ないように各所修正
- スクリプトの実行例を追記 (23:39)
2018/09/13
- 「サーバー証明書の設置」の内容に Nginx の設定例を追記して Apache と項目を分けた。
コメント
scriptを実行すると、下記のようなエラが出ます。
Using configuration from /etc/pki/tls/openssl-server.cnf
error loading the config file ‘/etc/pki/tls/openssl-server.cnf’
140221315696544:error:02001002:system library:fopen:No such file or directory:bss_file.c:169:fopen(‘/etc/pki/tls/openssl-server.cnf’,’rb’)
140221315696544:error:2006D080:BIO routines:BIO_new_file:no such file:bss_file.c:172:
140221315696544:error:0E078072:configuration file routines:DEF_LOAD:no such file:conf_def.c:197:
「サーバー証明書用設定ファイル作成」のパートにあります「openssl-server.cnf」を作成していないとエラーにあります通り「No such file or directory」ですのでファイルが存在していないようです。