開発環境やテスト用に、認証局を通さず自分で署名したサーバー証明書を作りたいときは、openssl req -x509を使う。秘密鍵と証明書を1コマンドで作れる。
$ openssl req -x509 -newkey rsa:2048 -noenc -keyout server.key -out server.crt -days 365 \
-subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
server.keyが秘密鍵、server.crtが証明書である。-daysは証明書の有効日数である。
実行例はUbuntu 24.04のOpenSSL 3.0.13のもの。
有効期間を指定する
-daysを省略すると、有効期間は30日になる。開発用に長く使う場合は、-daysを明示する。
$ openssl req -x509 -key server.key -out server.crt -subj "/CN=a"
$ openssl x509 -in server.crt -noout -dates
notBefore=Sep 30 14:53:44 2026 GMT
notAfter=Oct 30 14:53:44 2026 GMT
$ openssl req -x509 -key server.key -out server.crt -subj "/CN=a" -days 3650
$ openssl x509 -in server.crt -noout -enddate
notAfter=Sep 27 14:53:44 2036 GMT
開発用であれば1年程度にして、期限切れ時に作り直すのが扱いやすい。長い有効期間は、秘密鍵が漏れた場合の影響も長引く。
有効期限の確認方法は別の記事で説明している。
参考: 【openssl】証明書ファイルの有効期限を確認する
SANを指定する
現在のブラウザーやHTTPクライアントは、コモンネーム(CN)ではなく、SAN(Subject Alternative Name)でホスト名を検証する。SANがない証明書は、CNが一致していてもホスト名の検証に失敗する場合がある。-addextでSANを指定する。
$ openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
-keyout ec.key -out ec.crt -days 365 -subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:*.localhost,IP:127.0.0.1,IP:::1"
$ openssl x509 -in ec.crt -noout -ext subjectAltName
X509v3 Subject Alternative Name:
DNS:localhost, DNS:*.localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
DNS名とIPアドレスは、DNS:とIP:で区別して、カンマで区切って並べる。
既存の秘密鍵から作る
すでに秘密鍵がある場合は、-newkeyと-keyoutの代わりに-keyを指定する。
$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out k.key
$ openssl req -x509 -key k.key -out k.crt -days 30 -subj "/CN=a"
秘密鍵の作り方は別の記事で説明している。
参考: 【openssl】秘密鍵を作成する (genpkey)
CSRから作る
CSRが手元にある場合は、openssl x509 -req -signkeyで、CSRと同じ秘密鍵を使って署名できる。
$ openssl req -new -key k.key -out k.csr -subj "/CN=b"
$ openssl x509 -req -in k.csr -signkey k.key -out k2.crt -days 30
Certificate request self-signature ok
$ openssl x509 -in k2.crt -noout -subject -issuer -ext basicConstraints
subject=CN = b
issuer=CN = b
No extensions in certificate
この方法では、CSRに含まれる拡張(SANなど)は証明書に引き継がれない。SANが必要な場合は、req -x509 -addextを使う。
参考: 【openssl】CSRを作成する (req -new)
鍵のパスフレーズを省略する
-newkeyで鍵を作るとき、-noencを付けないと、秘密鍵をパスフレーズで暗号化する。Webサーバーを自動で起動する場合など、パスフレーズを入力できない用途では-noencを付ける。
-noencは、OpenSSL 3.0で導入されたオプションである。古い記事で見かける-nodesは、同じ意味の非推奨の名前である。
証明書に設定される拡張
req -x509で作った証明書は、デフォルトでbasicConstraintsがCA:TRUEになる。つまり、認証局の証明書として扱われる。
$ openssl x509 -in server.crt -noout -ext basicConstraints
X509v3 Basic Constraints: critical
CA:TRUE
サーバー証明書として使うだけなら、CA:FALSEを明示したほうが意図に合う。キー用途も合わせて指定する。
$ openssl req -x509 -key k.key -out ext.crt -subj "/CN=a" -days 30 \
-addext "subjectAltName=DNS:a" \
-addext "keyUsage=digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage=serverAuth" \
-addext "basicConstraints=critical,CA:FALSE"
$ openssl x509 -in ext.crt -noout -ext keyUsage,extendedKeyUsage,basicConstraints
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Basic Constraints: critical
CA:FALSE
作成した証明書を確認する
openssl x509で、サブジェクト、発行者、有効期間を確認する。自己署名の証明書は、サブジェクトと発行者が同じになる。
$ openssl x509 -in server.crt -noout -subject -issuer -dates
subject=CN = localhost
issuer=CN = localhost
notBefore=Sep 30 14:53:44 2026 GMT
notAfter=Sep 30 14:53:44 2027 GMT
証明書自身を信頼する認証局として渡すと、openssl verifyで検証できる。何も指定しない場合は、信頼済みの認証局のリストに含まれないため失敗する。
$ openssl verify -CAfile server.crt server.crt
server.crt: OK
$ openssl verify server.crt
CN = localhost
error 18 at 0 depth lookup: self-signed certificate
error server.crt: verification failed
クライアントから接続して確認する
openssl s_serverでHTTPSサーバーを起動し、openssl s_clientで接続すると、証明書を使った接続を試せる。
$ openssl s_server -accept 4433 -cert server.crt -key server.key -www
別のターミナルから接続する。証明書を信頼していない場合は、検証に失敗する。
$ echo | openssl s_client -connect localhost:4433 2>&1 | grep -E 'Verif'
Verification error: self-signed certificate
Verify return code: 18 (self-signed certificate)
-CAfileで証明書自身を信頼する認証局として渡すと、検証に成功する。
$ echo | openssl s_client -connect localhost:4433 -CAfile server.crt -verify_hostname localhost 2>&1 | grep -E 'Verif'
Verification: OK
Verify return code: 0 (ok)
参考: 【openssl】指定したURLの証明書をコマンドで確認する
秘密鍵と証明書を1つのファイルにまとめる
サーバーによっては、証明書と秘密鍵を1つのPEMファイルにまとめる必要がある。catで連結する。
$ cat server.crt server.key > combined.pem
バージョンによる違い
OpenSSL 3.5や3.6でも、有効期間のデフォルトとCA:TRUEの挙動は同じである。
macOS標準の/usr/bin/openssl(LibreSSL 3.3.6)では、以下が異なる。
-noencに対応していない。代わりに-nodesを使う- デフォルトで
basicConstraintsが付かない openssl x509の-extに対応していない。拡張の確認は-textを使う
-addextでのSAN指定と、-daysのデフォルト30日は、LibreSSL 3.3.6でも同じである。
