TOC
オレオレ証明書だとどうしてもうまく行かないTLS証明書
昨今は全ての通信を暗号化する潮流になっており、この流れ自体は今後も変わらないことが想定されます。
インターネット上の通信は暗号化したほうが良いというのは説得力がありますが、LAN内の通信まで暗号化する必要があるのかという点には多少疑問があります。
インターネット上に公開しているサイトであればLet’s EncryptやZeroSSLという無料のTLS証明書を発行してくれるサービスを使用できますが、インターネットに公開しない前提で運用するものが暗号化を要求した場合、基本的に自分で暗号化する以外の選択肢がありません。
オレオレ証明書と呼ばれる自己署名証明書1では何を間違っているのかどうしてもうまく行かないことがあり、プライベートCAを構築して、暗号化が必要な場合は活用していくことにしました。
easy-rsaというOpenVPNが開発しているプロジェクトがあり、これを使うとOpenSSLを直接叩くよりも楽ができそうということと、Ubuntuにeasyrsaパッケージがあるのでセットアップも簡単で使うことに決めました。環境はUbuntu 20.10です。
今回のプライベートCAは基本的にDigital Oceanのサイトにあったものの手順をなぞっています。
作るもの・用途
名称 | 用途 | サービス側 に配備 | 端末側 に配備 | 備考 |
---|---|---|---|---|
CA(認証局) | 色んな人から受け取ったCSR(証明書署名要求)に対して、 内容に問題がなければ署名する 端末にはCRTをルート証明書として インポートしてもらう | CAを信頼する端末がある限り運用すべき | ||
CAの秘密鍵(.key) | CSRに署名(、署名取り消し)する際に必要 | どこにも公開しない | ||
CAのCRT (公開鍵・ ルート証明書) | CAを信頼する端末にインポートする | ○ | 端末に配布する | |
秘密鍵(.key) | 端末が生成 CAに署名してもらったCRTとともにサービス提供時に必要 | ○ | 個人的には拡張子を.privkeyにしている サービス公開側に配備する | |
CSR(証明書署名要求) | 端末が秘密鍵から生成 CAに提出して署名してもらう | |||
CRT(公開鍵) | CAがCSRに署名してもらった結果。 秘密鍵とともに公開するサービスで使用する | ○ | サービス公開側に配備する |
CA(認証局)の構築
easy-rsaのインストール
# apt-get install easy-rsa
CA管理用のユーザーを作成
プライベートCAの操作を実行するための(root
ではない)ユーザーを作成します。また、sudo
を実行できるようにします。
# adduser ca
ユーザー `ca' を追加しています...
新しいグループ `ca' (1002) を追加しています...
新しいユーザー `ca' (1002) をグループ `ca' に追加しています...
ホームディレクトリ `/home/ca' を作成しています...
`/etc/skel' からファイルをコピーしています...
新しいパスワード:
新しいパスワードを再入力してください:
passwd: パスワードは正しく更新されました
ca のユーザ情報を変更中
新しい値を入力してください。標準設定値を使うならリターンを押してください
フルネーム []:
部屋番号 []:
職場電話番号 []:
自宅電話番号 []:
その他 []:
以上で正しいですか? [Y/n]
# gpasswd -a ca sudo
ユーザ ca をグループ sudo に追加
以降のCA関連のコマンドは作成したca
ユーザーで行います。
# su - ca
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
$ id
uid=1002(ca) gid=1002(ca) groups=1002(ca),27(sudo)
PKI(公開鍵インフラストラクチャ)ディレクトリの準備
easy-rsaを操作する準備をします。
$ mkdir ~/easy-rsa
$ ln -s /usr/share/easy-rsa/* ~/easy-rsa/
$ chmod 700 ~/easy-rsa
$ cd ~/easy-rsa
$ ./easyrsa init-pki
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/ca/easy-rsa/pki
CAの作成
デフォルト値を記述した~/easy-rsa/vars
というファイルを作成します。
set_var EASYRSA_REQ_COUNTRY "JP"
set_var EASYRSA_REQ_PROVINCE "Tokyo"
set_var EASYRSA_REQ_CITY "Tokyo"
set_var EASYRSA_REQ_ORG "PrivateCA"
set_var EASYRSA_REQ_EMAIL "rpi4@internal"
set_var EASYRSA_REQ_OU "Community"
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"
CAの構築コマンドを実行します。
$ cd ~/easy-rsa
$ ./easyrsa build-ca
コマンド実行時、パスフレーズとCN(Common Name)を入力します。パスフレーズはCAを使っている間は絶対に漏洩してはならないものなのでオフラインのどこかにメモして置くのがオススメ。2Common Nameはインターネット上で使う予定があれば自分の所有しているドメインにするのが良いでしょう。今回はLAN内のDNSサーバで管理しているinternalにします。
Note: using Easy-RSA configuration from: ./vars
Using SSL: openssl OpenSSL 1.1.1f 31 Mar 2020
Enter New CA Key Passphrase:
Re-Enter New CA Key Passphrase:
(snip)
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:internal
CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/ca/easy-rsa/pki/ca.crt
これで2つのファイルが生成されます。
- ~/easy-rsa/pki/ca.crt CAの公開鍵
- ~/easy-rsa/pki/private/ca.key CAの秘密鍵
公開鍵は必要に応じて配布することで、暗号化されたコンテンツにアクセスできるようにします。
秘密鍵は絶対に誰にも見られてはいけないもので、CSRに署名する際に必要なものです。
以上でCAの作成は完了です。
使用する各端末にCAの公開鍵(ca.crt)をルート証明書としてインポート
システムにインポート
ここでは手元のUbuntu20.04に公開鍵をインポートします。
update-ca-certificates
ca.crtをscpでコピーするか中身のbase64の文字列をコピーして~/ca.crt
というファイルに保存したら、/usr/local/share/ca-certificates/
ディレクトリにコピーします。
$ sudo mv ca.crt /usr/local/share/ca-certificates/
端末上にCAの公開鍵を反映します。
# update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
Adding debian:ca.pem
done.
Updating Mono key store
Mono Certificate Store Sync - version 6.12.0.107
Populate Mono certificate store from a concatenated list of certificates.
Copyright 2002, 2003 Motus Technologies. Copyright 2004-2008 Novell. BSD licensed.
Importing into legacy system store:
I already trust 138, your new list has 139
Import process completed.
Importing into BTLS system store:
I already trust 138, your new list has 139
Import process completed.
Done
done.
これで、この端末はCAが署名した証明書を信頼します。
$ ls -l /etc/ssl/certs/ | grep ca.pem
lrwxrwxrwx 1 root root 6 1月 20 22:57 2352eff5.0 -> ca.pem
lrwxrwxrwx 1 root root 39 1月 20 22:57 ca.pem -> /usr/local/share/ca-certificates/ca.crt
但し、ブラウザのキャッシュが関係しているのかわかりませんがこの状態で接続できるようになったのは手元ではEpiphanyのみでした。(後で確認したRocket.Chatの画面)
certutilコマンドで$HOME/.pki/nssdbにインポート
update-ca-certificates
コマンドで反映した後もChromium Edge(Dev)では状態が変わらなかった(かつ、後述するChromiumと違って証明書のインポート設定を開けなかった)ので、他にシステム的に反映させられそうなものを検索した結果、$HOME/.pki/nssdb
がユーザー単位で操作できそうだったので、ここにインポートします。
libnss3-tools
をインストールします。
# apt-get install libnss3-tools
現在格納されている証明書を見てみます。
$ certutil -d sql:$HOME/.pki/nssdb -L
Certificate Nickname Trust Attributes
SSL,S/MIME,JAR/XPI
1つもありませんでした。/home/hogehoge/privateca.crt
というファイル名の証明書をインポートします。-t
で指定する属性はよくわかりませんでしたがとりあえずこれで動くことを確認しています。
$ certutil -d sql:$HOME/.pki/nssdb -A -t "CT,c," -n privateca -i /home/hogehoge/privateca.crt
$ certutil -d sql:$HOME/.pki/nssdb -L
Certificate Nickname Trust Attributes
SSL,S/MIME,JAR/XPI
privateca CT,c,
この後、Chromium Edge(Dev)を起動し直すかリロードすることで信頼されるようになることを確認できました。
Chromiumにインポート
Chromiumの場合どこからルート証明書を読み取っているのかわからなかったので設定画面から直接インストールします。Chromiumの場合の手順です。
システムではインポートしたはずですが、相変わらず信頼されていない状態が続いています。
Chromiumの設定から「セキュリティ」を選択します。
「詳細設定」にある「証明書の管理」を選びます。
「認証局」タブの「インポート」ボタンを押します。
CAの公開鍵ファイルを開きます。
信頼する種別を選択する画面になるので、今回はとりあえずウェブサイトの識別で信頼します。
インポートが終わると、internalというCAがインポートされたことがわかります。
信頼されていなかったタブに戻ってリロードすると、証明書が有効扱いに変更されたことがわかります。
Androidにインポート
CA公開鍵(privateca.crt
)をAndroidにコピーして、「設定」→「セキュリティ」→「暗号化と認証情報」→「ストレージからのインストール」を選択します。
CAの公開鍵ファイルを選択して認証をすると、証明書の名前を指定する画面になります。
名前を指定してOKをタップすると、信頼できる認証情報に追加されます。
CSR(証明書署名要求)の作成とCAによる署名と取り消し
サービス提供側は秘密鍵とCRTを使ってサービスを提供します。CRTは秘密鍵の生成後、秘密鍵から作成されたCSRにCAが署名することで作成されます。
一般に使用するLinuxでは既にインストールされていることが多いですが、インストールされていない場合はopenssl
パッケージをインストールします。
# apt-get install openssl
秘密鍵の作成
適当に秘密鍵を作成します。今回はファイルのコピーが面倒なので、CAの端末内に一時的に作成するディレクトリで秘密鍵(example-server.key
)を作成します。
$ mkdir ~/practice-csr
$ cd ~/practice-csr
$ openssl genrsa -out example-server.key
Generating RSA private key, 2048 bit long modulus (2 primes)
(snip)
e is 65537 (0x010001)
秘密鍵の内容を確認します。modulus
が公開鍵そのもので、prime1
とprime2
が秘密鍵です。
$ openssl rsa -text < example-server.key
RSA Private-Key: (2048 bit, 2 primes)
modulus:
00:c1:2c:6d:ab:c7:03:e5:96:f4:db:e9:57:bd:68:
(snip)
publicExponent: 65537 (0x10001)
privateExponent:
22:84:cc:e8:38:3c:f3:06:e1:a4:76:73:0e:4e:a8:
(snip)
prime1:
00:eb:5f:1b:79:a7:be:8c:e7:36:b0:82:b5:28:40:
(snip)
prime2:
00:d2:1a:8c:d2:1c:4b:21:fe:05:b6:73:2f:0f:72:
(snip)
exponent1:
00:af:a2:a0:d5:ff:1e:69:f6:7f:10:e7:f8:56:b9:
(snip)
exponent2:
08:2c:cc:49:e8:9b:eb:c8:ac:84:3a:db:1b:e8:bf:
(snip)
coefficient:
00:be:68:c5:bd:37:43:4e:8f:04:c1:7d:76:4b:88:
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
(snip)
-----END RSA PRIVATE KEY-----
CSRの作成
作成した秘密鍵を元に、CSR(example-server.req)を作成します。この内容をCAが見てCSRに署名するため、基本的にはちゃんと作ります(今回はサンプルなので適当に入力しますが)
$ openssl req -new -key example-server.key -out example-server.req
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Tokyo
Organization Name (eg, company) [Internet Widgits Pty Ltd]:arekore
Organizational Unit Name (eg, section) []:Community
Common Name (e.g. server FQDN or YOUR name) []:internal
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
上記のように対話式で実行せずとも以下の様にopensslコマンドに引数で渡すことができます。
$ openssl req -new -key sammy-server.key -out server.req -subj /C=JP/ST=Tokyo/L=Tokyo/O=arekore/OU=Community/CN=internal
CSRの内容を確認します。
$ openssl req -in example-server.req -noout -subjectsubject=C = JP, ST = Tokyo, L = Tokyo, O = arekore, OU = Community, CN = internal
CSRを署名してもらうためにCAにコピーします。
$ sudo cp ~hogehoge/practice-csr/example-server.req /tmp/example-server.req
CAによる署名
CSRをインポートします。インポートが終了するとeasy-rsaコマンドのsign-reqオプションで署名できるようになります。
$ cd ~/easy-rsa/
$ ./easyrsa import-req /tmp/example-server.req example-server
Note: using Easy-RSA configuration from: ./vars
Using SSL: openssl OpenSSL 1.1.1f 31 Mar 2020
The request has been successfully imported with a short name of: example-server
You may now use this name to perform signing operations on this request.
今回はリクエストタイプをサーバー(server)にして署名します。申請内容を確認して問題がなければyesと入力し、CAのパスフレーズを入力します。
$ ./easyrsa sign-req server example-server
Note: using Easy-RSA configuration from: ./vars
Using SSL: openssl OpenSSL 1.1.1f 31 Mar 2020
You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.
Request subject, to be signed as a server certificate for 1080 days:
subject=
countryName = JP
stateOrProvinceName = Tokyo
localityName = Tokyo
organizationName = arekore
organizationalUnitName = Community
commonName = internal
Type the word 'yes' to continue, or any other input to abort.
Confirm request details: yes
Using configuration from /home/ca/easy-rsa/pki/safessl-easyrsa.cnf
Enter pass phrase for /home/ca/easy-rsa/pki/private/ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'JP'
stateOrProvinceName :ASN.1 12:'Tokyo'
localityName :ASN.1 12:'Tokyo'
organizationName :ASN.1 12:'arekore'
organizationalUnitName:ASN.1 12:'Community'
commonName :ASN.1 12:'internal'
Certificate is to be certified until Jan 5 21:32:08 2024 GMT (1080 days)
Write out database with 1 new entries
Data Base Updated
Certificate created at: /home/ca/easy-rsa/pki/issued/example-server.crt
出来上がった/home/ca/easy-rsa/pki/issued/example-server.crt
に公開暗号化キーとCAからの署名が含まれます。
$ openssl x509 -text -noout -in pki/issued/example-server.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
(snip)
Signature Algorithm: ecdsa-with-SHA512
Issuer: CN = internal
Validity
(snip)
Subject: C = JP, ST = Tokyo, L = Tokyo, O = arekore, OU = Community, CN = internal
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus: 00:c1:2c:6d:ab:c7:03:e5:96:f4:db:e9:57:bd:68:
(snip)
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Key Identifier:
(snip)
X509v3 Authority Key Identifier:
(snip)
DirName:/CN=internal serial:35:58:33:C9:EA:39:B2:01:49:5D
(snip)
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Subject Alternative Name:
DNS:internal
Signature Algorithm: ecdsa-with-SHA512 30:64:02:30:33:77:3e:e6:28:f4:14:4a:36:00:07:c4:00:c8:
(snip)
サービス提供側は秘密鍵とこの署名されたCRTファイルを組み合わせることで、CAを信頼している各端末で通信させることができます。
署名の取り消し
CAが署名をしたものの、後からCRL(証明書失効リスト)を発行することで署名を取り消すことができます。
ここでは上の手順でインポートしたexample-server
を無効化します。
署名した時と同様、内容を確認してyesと打ち込んだ後、CAのパスフレーズを入力します。
$ cd ~/easy-rsa/
$ ./easyrsa revoke example-server
Note: using Easy-RSA configuration from: ./vars
Using SSL: openssl OpenSSL 1.1.1f 31 Mar 2020
Please confirm you wish to revoke the certificate with the following subject:
subject=
countryName = JP
stateOrProvinceName = Tokyo
localityName = Tokyo
organizationName = arekore
organizationalUnitName = Community
commonName = internal
Type the word 'yes' to continue, or any other input to abort.
Continue with revocation: yes
Using configuration from /home/ca/easy-rsa/pki/safessl-easyrsa.cnf
Enter pass phrase for /home/ca/easy-rsa/pki/private/ca.key:
Revoking Certificate 3CB552D4968EED59.
Data Base Updated
IMPORTANT!!!
Revocation was successful. You must run gen-crl and upload a CRL to your
infrastructure in order to prevent the revoked cert from being accepted.
CRLを生成します。CAのパスフレーズが必要です。
$ ./easyrsa gen-crl
Note: using Easy-RSA configuration from: ./vars
Using SSL: openssl OpenSSL 1.1.1f 31 Mar 2020
Using configuration from /home/ca/easy-rsa/pki/safessl-easyrsa.cnf
Enter pass phrase for /home/ca/easy-rsa/pki/private/ca.key:
An updated CRL has been created.
CRL file: /home/ca/easy-rsa/pki/crl.pem
$ openssl crl -in pki/crl.pem -text
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: ecdsa-with-SHA512
Issuer: CN = internal
(snip)
CRL extensions:
X509v3 Authority Key Identifier: (snip)
DirName:/CN=internal
(snip)
Revoked Certificates:
Serial Number: 3CB552D4
Revocation Date: Jan 20 18:59:54 2021 GMT
Signature Algorithm: ecdsa-with-SHA512 30:66:02:31:00:83:48:df:9d:63:6e:4c:77:b9:9c:95:6a:31:
(snip)
-----BEGIN X509 CRL-----
(snip)
-----END X509 CRL-----
生成されたcrl.pem
ファイルをCAをインポートした端末にコピーし、CRLのインポートを行うことで該当端末での失効を行うことができます。
ということになっていますが、CRLファイルがOSでハンドリングできる場合はともかく、コマンドからインポートする方法がよくわかりませんでした。
スポンサーリンク
comments powered by Disqus