OpenSSLでチェーン証明書を作成する方法

最近は常時SSL化や、http/2対応など、テスト環境でも検証用のTLS証明書を作成する機会が増えてきました。

OpenSSLを利用した証明書作成には`openssl ca`コマンドを使った方法など、色々な方法がありますが、証明書のみを簡単に作成ができる方法をまとめます。

### 今回作る構成
2018年現在でよく使用されているRSA 2048bit鍵でSHA-2な証明書で、
今回は、ルートCAが配下にサーバ証明書を作成する構成(中間CA証明書無し)とします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/206223/bc47b1fd-e2ec-6451-3d82-c65dd2a5a88d.png)



# 1.CA証明書の作成
まずは、チェーン証明書のルートCAのとなるCA証明書の作成を行います。

## 1-1. CA秘密鍵生成
`opnessl genrsa`コマンドを利用して証明書の秘密鍵を生成します。
下記のコマンドで、標準的なRSA 2048 bitの鍵が作成されます。

```sh
openssl genrsa -out ca.key 2048
```

## 1-2. CSR(+公開鍵)作成
1-1.で作成した秘密鍵をもとに、CSRを作成します。

```sh
openssl req -new -key ca.key -out ca.csr
```
※ 上記コマンド実行後に、CommonNameなどの必要事項を対話式に入力していく形になりますが、`-subj`というオプションを利用すると、対話式入力なしで引数に指定した情報で作成することもできます。

## 1-3. CA証明書作成
1-2.で作成したCSRから、証明書を作成します。

### 1-3-a. 証明属性定義ファイルの作成
CSRを署名する前に、次の`ca.ext`ような内容の証明書属性定義ファイルを作成しておきます。

#### CA証明書用

```ini:ca.ext
# CA証明書用
[ v3_ca ]
basicConstraints = critical, CA:true
keyUsage = keyCertSign, cRLSign
extendedKeyUsage = serverAuth, clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
```

### 1-3-b. CSRに署名し、証明書を作成

ルートCAだけは自己署名である必要があり、自己署名の場合は、1-1.で作成した秘密鍵で1-2.のCSRを署名する形になります。
`-signkey`オプションで署名に使用する秘密鍵を指定します。

```sh
openssl x509 -req \
    -signkey ca.key \
    -extfile ca.ext \
    -extensions "v3_ca" \
    -in ca.csr \
    -out ca.crt \
    -days 3650 \
    -sha256
```

# 2.サーバ証明書の作成
これまでに作成したCAの秘密鍵と証明書を利用して、サーバ証明書を作成(発行)します。

## 2-1. 秘密鍵生成
CA秘密鍵を作成した際と同様です。

```sh
openssl genrsa -out server.key 2048
```

## 2-2. CSR(+公開鍵)作成
こちらもCA同様に秘密鍵をもとに、CSRを作成します。

```sh
openssl req -new -key server.key -out server.csr
```

## 2-3. 証明書作成
2-2.で作成したCSRから、サーバ証明書を作成します。

### 2-3-a. 証明書属性定義ファイルの作成
こちらもCA同様に、CSRを署名する前に、証明書属性定義ファイルを作成しておきます。
これはCA証明書用と、サーバ証明書用で一部属性が異なるので、CA証明書の際に作成したものとは別に作成します。
(今回は、`server.ext`というファイルとして作成することにします)

#### サーバ証明書用
※ subjectAltNameの値は、作成するサーバ証明書に設定するCommonName(CN)のドメインへ書き換えてください。
ドメインの場合は、「DNS: *ドメイン名*」、IPアドレスの場合は、「IP: *IPアドレス*」の形式で指定します。

```ini:server.ext
# TLSサーバ証明書用
[ v3_server ]
basicConstraints = critical, CA:false
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName = DNS:www.example.com
```

### 2-3-b. CSRに署名し、証明書を作成

CAからのチェーン証明書として発行する場合は、`-CAkey`オプションでCAの秘密鍵、`-CA`オプションでCA証明書を指定します。
これにより、CAの鍵でCSRが署名され、チェーン証明書となります。

```sh
openssl x509 -req \
    -CAkey ca.key \
    -CA ca.crt \
    -CAcreateserial \
    -extfile server.ext \
    -extensions "v3_server" \
    -in server.csr \
    -out server.crt \
    -days 365 \
    -sha256
```

## 3. 証明書の確認

作成した証明書の詳細情報は下記コマンドにて内容を確認することができます。

```sh
openssl x509 -in server.crt -noout -text
```

以上で、CA証明書 & サーバ証明書の作成は完了です。

# 手順だけまとめ

#### ルートCA証明書作成

```sh
# 秘密鍵作成
openssl genrsa -out ca.key 2048

# CSR作成
openssl req -new -key ca.key -out ca.csr -subj "/C=JP/CN=Hogehoge CA"

# 証明書属性定義ファイル作成
cat << _EOF_ > ca.ext
[ v3_ca ]
basicConstraints = critical, CA:true
keyUsage = keyCertSign, cRLSign
extendedKeyUsage = serverAuth, clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
_EOF_

# 自己署名でルート証明書を作成
openssl x509 -req -signkey ca.key -extfile ca.ext -extensions "v3_ca" -in ca.csr -out ca.crt -days 3650 -sha256
```

#### サーバ証明書作成(ルートCAで署名)

```sh
# 秘密鍵作成
openssl genrsa -out server.key 2048

# CSR作成
openssl req -new -key server.key -out server.csr -subj "/CN=www.hogehoge.com"

# 証明書属性定義ファイル作成
cat << _EOF_ > server.ext
[ v3_server ]
basicConstraints = critical, CA:false
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName = DNS:www.hogehoge.com
_EOF_

# ルート証明書で署名した証明書を作成
openssl x509 -req -CAkey ca.key -CA ca.crt -CAcreateserial -extfile server.ext -extensions "v3_server" -in server.csr -out server.crt -days 365 -sha256
```