OpenSSLでプライベート認証局の構築（ルートCA、中間CA）

## はじめに
このエントリはOpenSSLを利用したPKIを構築する手順について記載します。
PKIそのものや技術背景などの記載はありません。

## 概要

以下のようにルートCAと中間CAを作成します。
![Screenshot from Gyazo](https://gyazo.com/b2634118202c10904c5e05b3afb3a1c7/raw)


## 更新履歴
2020.1.28 図の追加と引数を一部変更（example.netにしたりとか）
　　　 　 と、おまけの、一発構築コピペテキストも修正しました。


## 対象機器および環境

* CentOS7(7.6.1810)

## このエントリを読むとできること

* LinuxのOpenSSLを利用して
* ルートCAと中間CAを作成して
* 証明書発行できる環境が準備できる

はず。

## 事前準備

### ディレクトリ配置

```
mkdir -p /opt/pki
mkdir /opt/pki/configs
mkdir /opt/pki/crl
mkdir /opt/pki/RootCA
mkdir /opt/pki/InterCA
mkdir /opt/pki/Server
mkdir /opt/pki/Client
```

### openssl用コンフィグファイル作成

署名用

```bash:/opt/pki/configs/openssl_sign.cnf
[ ca ]
default_ca      = CA_default

[ CA_default ]
dir             = ./
certs           = $dir/certs
crl_dir         = $dir/crl
database        = $dir/index.txt
new_certs_dir   = $dir/newcerts
serial          = $dir/serial
crlnumber       = $dir/crlnumber
crl             = $dir/crl.pem
RANDFILE        = $dir/.rand

name_opt        = ca_default
cert_opt        = ca_default

default_days    = 365
default_crl_days= 30
default_bits    = 2048
default_md      = sha256
preserve        = no
policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints=CA:true
keyUsage = cRLSign,keyCertSign

[ v3_server ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
crlDistributionPoints = URI:http://192.168.0.254/crl/example.net.crl

[ v3_client ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
crlDistributionPoints = URI:http://192.168.0.254/crl/example.net.crl
```

## 認証局の構築

### RootCA（ルート認証局）
以下の順で生成していきます
１．秘密鍵を生成（＝ただの秘密鍵）
２．秘密鍵から証明書署名要求を生成（＝ただの秘密鍵から生成した、ただの証明書署名要求）
３．秘密鍵で証明書署名要求に署名（＝２．で生成した証明書署名要求に、「CAだよ（とかいろいろ）」のオプション付きで、１．で生成した秘密鍵で署名した、オレオレ証明書）

つまり、この手順は **「自己署名された、CAの機能を有する証明書」を生成する** だけである。
オレオレな世界で、「これがルートCAだ！」と認識すれば、これがルートCA証明書になる。

[![Screenshot from Gyazo](https://gyazo.com/ec6b3899ceb28c7547a23a5ad8cd7113/raw)](https://gyazo.com/ec6b3899ceb28c7547a23a5ad8cd7113)


#### 環境の初期化

```
cd /opt/pki/RootCA
mkdir newcerts
echo "01" > serial
echo "00" > crlnumber
touch index.txt
```

#### RootCAの秘密鍵の作成

RootCAの秘密鍵の暗号化パスワードは `-passout` で与えています。
パスワードは  `rootcaprivkeypass` としています。

```
openssl genrsa \
 -out RootCA_key.pem \
 -aes256 \
 -passout pass:rootcaprivkeypass \
 2048
```

#### RootCAの秘密鍵で、RootCAの証明書署名要求を作成
RootCAの秘密鍵を利用するので `-passin` でパスワードを与えてます。

```
openssl req -new \
 -subj "/C=JP/ST=Tokyo/O=EXAMPLE/CN=EXAMPLE Root CA" \
 -out RootCA_csr.pem \
 -key RootCA_key.pem \
 -passin pass:rootcaprivkeypass
```

#### RootCAの秘密鍵で、RootCAの証明書署名要求に署名する
RootCAの秘密鍵を利用するので `-passin` でパスワードを与えてます。

```
openssl ca -config ../configs/openssl_sign.cnf  -batch -extensions v3_ca \
 -out RootCA_crt.pem \
 -in RootCA_csr.pem \
 -selfsign \
 -keyfile RootCA_key.pem \
 -passin pass:rootcaprivkeypass
```

最後に余計な文字列を取り除くため、 `openssl x509 -in 証明書 -out 証明書` しています。
これがRootCAの証明書となります。

```
openssl x509 -in RootCA_crt.pem -out RootCA_crt.pem
```



### InterCA（中間認証局）
以下の順で生成していきます
１．秘密鍵を生成（＝ただの秘密鍵）
２．秘密鍵から証明書署名要求を生成（＝ただの秘密鍵から生成した、ただの証明書署名要求）
３．秘密鍵で証明書署名要求に署名（＝２．で生成した証明書署名要求に、「CAだよ（とかいろいろ）」のオプション付きで、ルートCAの秘密鍵で署名した、証明書）

つまり、この手順は **「ルートCA（と認識されている証明書）から発行された、CAの機能を有する証明書」を生成する** ということである。


[![Screenshot from Gyazo](https://gyazo.com/ff6f090a91c4e06bd41ca9adea0b9687/raw)](https://gyazo.com/ff6f090a91c4e06bd41ca9adea0b9687)


#### 環境の初期化

```
cd /opt/pki/InterCA
mkdir newcerts
echo "01" > serial
echo "00" > crlnumber
touch index.txt
```

#### InterCAの秘密鍵の作成

InterCAの秘密鍵の暗号化パスワードは `-passout` で与えています。
パスワードは  `intercaprivkeypass` としています。

```
openssl genrsa \
 -out InterCA_key.pem \
 -aes256 \
 -passout pass:intercaprivkeypass \
 2048
```

#### InterCAの秘密鍵で、InterCAの証明書署名要求を作成
InterCAの秘密鍵を利用するので `-passin` でパスワードを与えてます。

```
openssl req -new \
 -subj "/C=JP/ST=Tokyo/O=EXAMPLE/CN=EXAMPLE Intermediate CA" \
 -out InterCA_csr.pem \
 -key InterCA_key.pem \
 -passin pass:intercaprivkeypass 
```

#### RootCAの秘密鍵で、InterCAの証明書署名要求に署名をする。
RootCAの秘密鍵を利用するので `-passin` でパスワードを与えてます。

```
cd /opt/pki/RootCA
openssl ca -config ../configs/openssl_sign.cnf  -batch -extensions v3_ca \
 -out ../InterCA/InterCA_crt.pem \
 -in  ../InterCA/InterCA_csr.pem \
 -cert RootCA_crt.pem \
 -keyfile RootCA_key.pem \
 -passin pass:rootcaprivkeypass
```

最後に余計な文字列を取り除くため、 `openssl x509 -in 証明書 -out 証明書` しています。
これがInterCAの証明書となります。

```
cd /opt/pki/InterCA
openssl x509 -in InterCA_crt.pem -out InterCA_crt.pem
```

## さいごに

今後、このPKIを利用したEAP-TLS認証のやり方も整理したいです。

### おまけ

一連の作成は以下のコマンドをべろべろー、とコピペすると `/opt/pki` 配下に環境がつくれます。
コンフィグファイルもヒアドキュメントにしているので、まるまるコピペでOKです。

既存で同ディレクトリが存在している場合には、テキストを修正して別名で作成してください。

もしくは **/opt/pkiのデータを別のところに退避してから！**
`rm /opt/pki -rf` で既存をすべて削除してもつくれます。


```
mkdir -p /opt/pki
mkdir /opt/pki/configs
mkdir /opt/pki/crl
mkdir /opt/pki/RootCA
mkdir /opt/pki/InterCA
mkdir /opt/pki/Server
mkdir /opt/pki/Client

cat <<'EOF' > /opt/pki/configs/openssl_sign.cnf
[ ca ]
default_ca      = CA_default

[ CA_default ]
dir             = ./
certs           = $dir/certs
crl_dir         = $dir/crl
database        = $dir/index.txt
new_certs_dir   = $dir/newcerts
serial          = $dir/serial
crlnumber       = $dir/crlnumber
crl             = $dir/crl.pem
RANDFILE        = $dir/.rand

name_opt        = ca_default
cert_opt        = ca_default

default_days    = 365
default_crl_days= 30
default_bits    = 2048
default_md      = sha256
preserve        = no
policy          = policy_match

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints=CA:true
keyUsage = cRLSign,keyCertSign

[ v3_server ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
crlDistributionPoints = URI:http://192.168.0.254/crl/example.net.crl

[ v3_client ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
crlDistributionPoints = URI:http://192.168.0.254/crl/example.net.crl
EOF

cd /opt/pki/RootCA
mkdir newcerts
echo "01" > serial
echo "00" > crlnumber
touch index.txt

openssl genrsa -out RootCA_key.pem -aes256 -passout pass:rootcaprivkeypass 2048
openssl req  -new -out RootCA_csr.pem -key RootCA_key.pem -passin pass:rootcaprivkeypass -subj "/C=JP/ST=Tokyo/O=EXAMPLE/CN=EXAMPLE Root CA"
openssl ca -config ../configs/openssl_sign.cnf -out RootCA_crt.pem -in RootCA_csr.pem -selfsign -keyfile RootCA_key.pem -passin pass:rootcaprivkeypass -batch -extensions v3_ca
openssl x509 -in RootCA_crt.pem -out RootCA_crt.pem


cd /opt/pki/InterCA
mkdir newcerts
echo "01" > serial
echo "00" > crlnumber
touch index.txt

openssl genrsa -out InterCA_key.pem -aes256 -passout pass:intercaprivkeypass 2048
openssl req  -new -out InterCA_csr.pem -key InterCA_key.pem -passin pass:intercaprivkeypass -subj "/C=JP/ST=Tokyo/O=EXAMPLE/CN=EXAMPLE Intermediate CA"
cd /opt/pki/RootCA
openssl ca -config ../configs/openssl_sign.cnf -out ../InterCA/InterCA_crt.pem -in ../InterCA/InterCA_csr.pem -cert RootCA_crt.pem -keyfile RootCA_key.pem -passin pass:rootcaprivkeypass -batch -extensions v3_ca
cd /opt/pki/InterCA
openssl x509 -in InterCA_crt.pem -out InterCA_crt.pem

```