strongSwan で使用可能なサーバ証明書やクライアント証明書の作成方法について書きます。基本的には、strongSwan を使って作成するのが簡便ですが、それでもいちいち覚えてられないので、認証局に関する一連の運用を Makefile にまとめました。気に入っていただけたら、ご利用ください。

認証局の設定

/etc/pki/myCA を作成し、その中に Makefile を配置します。

# mkdir -p /etc/pki/myCA
# cd /etc/pki/myCA
# curl -O "https://raw.githubusercontent.com/seinolab/simple-ca-with-strongswan/main/Makefile"
...
#

Makefile の設定部分を編集します。各自の環境や好みに合わせて設定してください。RSA の証明書も使えますので、その場合は TYPErsa を、SIZE20484096 を指定してください。

CA_ROOT=/etc/pki/myCA

# information of your Certificate Authority
COUNTRY=JP
STATE=Niigata
ORGANIZATION=My Great Company
CA_NAME=ca.example.com

# lifetime of certificates
EXPIRE_CERT=366    # サーバ/クライアント証明書の有効期限(単位: 日)
EXPIRE_CA=3660     # 認証局証明書の有効期限(単位: 日)
EXPIRE_CRL=10      # CRLの有効期限(単位: 日)

# Type of certificates
TYPE=ecdsa         # 証明書の cipher(rsa|ecdsa|ed25519|ed448)
SIZE=256           # 鍵のサイズ(単位: bit)

# default destination
MAILTO=root

認証局の作成

make すると認証局が作成されます。認証局は明示的に作成しなくとも、最初のサーバ証明書またはクライアント証明書を発行する時に、Makefile の依存関係の解決の仕組みにより、必要な場合は自動的に作成されます。

# cd /etc/pki/myCA
# make
...
#

ルート証明書は /etc/pki/myCA/cacerts/ 以下に作成されます。配布用の .der ファイルも作成されます。

# ls cacerts/
root.cert.der  root.cert.pem  root.key.pem
# ls crls/
crl.pem
#

root.cert.der (公開鍵)はメール送付されますので、クライアント側へインストールし、「常に信頼する」に設定してください。

期限切れなどで認証局を破棄する場合は、make clean します。認証局を破棄すると、/etc/pki/myCA 以下の発行済みの各種証明書も削除されます。

# make clean
...
#

何をやっているか知りたい方は、以下をクリックしてください。

認証局の秘密鍵 ${CA_KEY} を生成します。パーミッションは 600 にしておきます。

mkdir -p ${CA_CERT_DIR}
strongswan pki --gen --type ${TYPE} --size ${SIZE} --outform pem > ${CA_KEY}
chmod 600 ${CA_KEY}

認証局の公開鍵 ${CA_PUB} を生成します。自身の秘密鍵で署名します。

strongswan pki --self --ca --lifetime ${EXPIRE_CA} \
               --in ${CA_KEY} --type ${TYPE} \
               --san "${CA_CERT_DN}" \
               --dn "${CA_CERT_DN}" --outform pem \
               --flag crlSign \
           > ${CA_PUB}

strongSwan 5.9.11 以降、crlSign フラグが設定されていない認証局の証明書は使用不可になりました。現状、明示的に指定しなくてもデフォルトで設定されるのですが、念のため付けておきます。

配布用の .der 形式のファイルを作成します。

openssl x509 -in ${CA_PUB} -outform DER -out ${CA_CERT_DIR}/root.cert.der

CRL ${CRL} を作成します。

mkdir -p ${CRL_DIR}
strongswan pki --signcrl --cacert ${CA_PUB} --cakey ${CA_KEY} \
               --lifetime=${EXPIRE_CRL} --outform pem \
           > ${CRL}

サーバ証明書の発行

サーバ example.com 用のサーバ証明書を発行します。ワイルドカード証明書(*.example.com)が発行されます。

# cd /etc/pki/myCA
# make SERVER=example.com server
...
#

サーバ証明書は /etc/pki/myCA/servers/ 以下に作成されます。

# ls servers/
example.com.cert.pem  example.com.key.pem
#

.cert.pem の方が公開鍵、.key.pem の方が秘密鍵です。

何をやっているか知りたい方は、以下をクリックしてください。

サーバ証明書の秘密鍵 ${SKEY} を生成します。パーミッションは 600 にしておきます。

mkdir -p ${SERVER_CERT_DIR}
strongswan pki --gen --type ${TYPE} --size ${SIZE} --outform pem > ${SKEY}
chmod 600 ${SKEY}

サーバ証明書の秘密鍵 ${SKEY} の鍵ペアとなる公開鍵 ${SPUB} を作成し、認証局の秘密鍵 ${CA_KEY} で署名します。

strongswan pki --pub --in ${SKEY} --type ${TYPE} \
| strongswan pki --issue --lifetime ${EXPIRE_CERT} \
                 --cacert ${CA_PUB} --cakey ${CA_KEY} \
                 --dn "C=${COUNTRY}, O=${ORGANIZATION}, CN=${SERVER}" \
                 --san ${SERVER} --san *.${SERVER} \
                 --flag serverAuth --flag ikeIntermediate --outform pem \
             > ${SPUB}

SAN を設定することで、ワイルドカード証明書にしています。サーバ証明書の場合、serverAuth フラグを設定します。

クライアント証明書の発行

vpnuser@example.com 用のクライアント証明書を発行します。途中でクライアント証明書をインポートする際のパスワードを聞かれますので、入力します。発行したクライアント証明書は、delivery-to@example.com へメール送付されます。

# cd /etc/pki/myCA
# make USER=vpnuser@example.com MAILTO=delivery-to@example.com issue
...
Enter Export Password:
Verifying - Enter Export Password:
...
#

証明書のコモンネームは vpnuser@example.com の形式はダメで、vpnuser としなければならない、という情報もありますが、そのような制限は確認できませんでした。

クライアント証明書は /etc/pki/myCA/clients/ 以下に作成されます。

# ls clients/
vpnuser@example.com.cert.pem  vpnuser@example.com.key.pem  vpnuser@example.com.p12
#

クライアント側にインストール後、これらのファイルは削除してしまっても認証できますが、クライアント証明書を失効させる際に必要になるので、残しておきましょう。

PKCS12(.p12 ファイル)には、クライアント証明書の鍵ペアに加えて、認証局のルート証明書(公開鍵)を含めることもできます。

何をやっているか知りたい方は、以下をクリックしてください。

クライアント証明書の秘密鍵 ${CKEY} を生成します。パーミッションは 600 にしておきます。

mkdir -p ${CLIENT_CERT_DIR}
strongswan pki --gen --type ${TYPE} --size ${SIZE} --outform pem > ${CKEY}
chmod 600 ${CKEY}

クライアント証明書の秘密鍵 ${CKEY} に対する鍵ペアとまる公開鍵 ${CPUB} を生成します。認証局の秘密鍵 ${CA_KEY} で署名します。

strongswan pki --pub --in ${CKEY} --type ${TYPE} \
| strongswan pki --issue --lifetime ${EXPIRE_CERT} \
                 --cacert ${CA_PUB} --cakey ${CA_KEY} \
                 --dn "C=${COUNTRY}, O=${ORGANIZATION}, CN=${USER}" \
                 --flag clientAuth \
                 --san ${USER} --outform pem \
             > ${CPUB}

クライアント証明書の秘密鍵 ${CKEY} と公開鍵 ${CKEY} をまとめて、配布用に .p12 形式で出力します。

openssl pkcs12 -export -legacy \
               -inkey ${CKEY} -in ${CPUB} \
               -name "${ORGANIZATION} client certificate" \
               -out ${CLIENT_CERT_DIR}/${USER}.p12

macOS や iOS が対応していないので、-legacy オプションを付けています。

クライアント証明書を失効させる

vpnuser@example.com 用のクライアント証明書を失効させます。無効化する際は、理由を指定します。理由には key-compromiseca-compromiseaffiliation-changedsupersededcessation-of-operationcertificate-hold のいずれか一つが設定できます)。

# cd /etc/pki/myCA
# make USER=vpnuser@example.com REASON=key-compromise revoke
...
#

クライアント証明書 ${CPUB} を理由 ${REASON} により失効させます。その後、古い CRL を新しい CRL で、atomic な操作で置き換えます。

strongswan pki --signcrl --lifetime=${EXPIRE_CRL} --basecrl=${CRL} \
               --cacert ${CA_PUB} --cakey ${CA_KEY} \
               --reason ${REASON} --cert ${CPUB} --outform pem \
           > ${CRL}.new \
&& mv -f ${CRL}.new ${CRL}

サーバ証明書も失効させられるのですが、面倒なのでそこまでは対応していません。--cert にサーバ証明書の公開鍵のパスを渡せば、失効させられます。

CRL を更新する

CRL の有効期限を更新します。CRL のチェックを有効にしている場合、CRL の有効期限が切れると、すべての証明書が無効扱いになりますので、ご注意ください。CRL をチェックしない設定の場合は、CRL を更新しなくても問題ないですが、証明書を失効させることができません(認証局から証明書のファイルを削除しても失効になりませんのでご注意ください)。

# cd /etc/pki/myCA
# make update
...
#

何をやっているか知りたい方は、以下をクリックしてください。

CRL ${CRL} を認証局の秘密鍵 ${CA_KEY} で署名し、CRL の有効期限を ${EXPIRE_CRL} 日後に再設定します。その後、古い CRL を新しい CRL で、atomic な操作で置き換えます。

strongswan pki --signcrl --lifetime=${EXPIRE_CRL} --basecrl=${CRL} \
               --cacert ${CA_PUB} --cakey ${CA_KEY} --outform pem \
           > ${CRL}.new \
&& mv -f ${CRL}.new ${CRL}

通常は、systemdcron で定期的に実行します。以下は systemd で自動更新する場合の設定例です。週次で更新されます。

# mkdir -p /usr/local/systemd/system
# cd /usr/local/systemd/system
# curl -O "https://raw.githubusercontent.com/seinolab/simple-ca-with-strongswan/main/pki-update-crl.service"
# curl -O "https://raw.githubusercontent.com/seinolab/simple-ca-with-strongswan/main/pki-update-crl.timer"
# systemctl start pki-update-crl.timer
# systemctl enable pki-update-crl.timer

おわりに

シンプルな Makefile ですので、各自の環境に合わせてカスタマイズしていただけると幸いです。