認証局にサーバー証明書を発行してもらうには、CSR(Certificate Signing Request)を作成して提出する。CSRはopenssl req -newで作る。

すでに秘密鍵がある場合は、-keyで指定する。

$ openssl req -new -key server.key -out server.csr -subj "/C=JP/ST=Tokyo/O=Example Inc./CN=example.com"

秘密鍵もまとめて新しく作る場合は、-newkeyと-keyoutを使う。

$ openssl req -new -newkey rsa:2048 -noenc -keyout server.key -out server.csr -subj "/C=JP/ST=Tokyo/O=Example Inc./CN=example.com"

CSRには公開鍵とサブジェクト(組織名やドメイン名)が含まれる。秘密鍵は含まれないため、CSRを認証局に送っても秘密鍵は漏れない。

実行例はUbuntu 24.04のOpenSSL 3.0.13のもの。

既存の秘密鍵からCSRを作る

秘密鍵の作り方は別の記事で説明している。

参考: 【openssl】秘密鍵を作成する (genpkey)

ECDSAの鍵を作ってCSRを作る例は以下のとおり。

$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out ec.key
$ openssl req -new -key ec.key -out ec.csr -subj "/CN=example.com"
$ head -1 ec.csr
-----BEGIN CERTIFICATE REQUEST-----

-outを省略すると、標準出力にPEM形式で出力する。

サブジェクトを指定する

-subjは/キー=値を並べた形式で指定する。よく使うキーは以下のとおり。

キー意味例
C国(2文字)JP
ST都道府県Tokyo
L市区町村Shibuya
O組織名Example Inc.
OU部署名Engineering
CNコモンネームexample.com

-subjを省略すると、対話形式で各項目を入力する。

Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

値を空にする項目は.を入力する。スクリプトから実行する場合は、-subjを指定して対話を避ける。

値に/が含まれる場合は、\でエスケープする。,は-subjの区切りではないため、そのまま書ける。

$ openssl req -new -key ec.key -subj "/O=Example, Inc./CN=a" | openssl req -noout -subject
subject=O = "Example, Inc.", CN = a

/で始めないとエラーになる。

$ openssl req -new -key ec.key -subj "CN=a"
req: subject name is expected to be in the format /type0=value0/type1=value1/type2=... where characters may be escaped by \. This name is not in that format: 'CN=a'

SANを追加する

現在のブラウザーは、証明書のコモンネーム(CN)ではなく、SAN(Subject Alternative Name)でホスト名を検証する。CSRにSANを含めるには、-addextを使う。

$ openssl req -new -key ec.key -out san.csr -subj "/CN=example.com" \
    -addext "subjectAltName=DNS:example.com,DNS:www.example.com,IP:192.0.2.1"

-addextは複数回指定できる。キー用途なども追加できる。

$ openssl req -new -key ec.key -out ext.csr -subj "/CN=a" \
    -addext "subjectAltName=DNS:a.example.com" \
    -addext "keyUsage=digitalSignature" \
    -addext "extendedKeyUsage=serverAuth"

認証局によっては、CSRに含めた拡張が無視され、認証局側の設定で上書きされる。申請先の仕様を確認する。

CSRの内容を確認する

-noout -textで、CSRの内容を表示する。

$ openssl req -in san.csr -noout -text
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: CN = example.com
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                ...
        Attributes:
            Requested Extensions:
                X509v3 Subject Alternative Name:
                    DNS:example.com, DNS:www.example.com, IP Address:192.0.2.1
    Signature Algorithm: ecdsa-with-SHA256

SANはRequested Extensionsに表示される。提出前に、ホスト名や鍵の種類、署名アルゴリズムを確認する。

サブジェクトだけを見る場合は-subjectを使う。

$ openssl req -in san.csr -noout -subject
subject=CN = example.com

CSRの署名が正しいかは-verifyで検証できる。

$ openssl req -in san.csr -noout -verify
Certificate request self-signature verify OK

設定ファイルで指定する

SANや複数の項目を毎回コマンドラインに書くのは面倒である。設定ファイルにまとめて、-configで読み込む。

[req]
distinguished_name = dn
req_extensions = v3
prompt = no

[dn]
C = JP
O = Example Inc.
CN = example.com

[v3]
subjectAltName = DNS:example.com,DNS:www.example.com
$ openssl req -new -key ec.key -config csr.cnf -out csr.csr
$ openssl req -in csr.csr -noout -text | grep -E 'Subject:|DNS:'
        Subject: C = JP, O = Example Inc., CN = example.com
                    DNS:example.com, DNS:www.example.com

prompt = noを指定すると、対話入力なしで[dn]の値を使う。

秘密鍵を暗号化せずに保存する

-newkeyで鍵も作る場合、秘密鍵はパスフレーズで暗号化される。パスフレーズなしで保存するには、-noencを付ける。Webサーバーを自動で起動する場合など、起動時にパスフレーズを入力できない用途で使う。

$ openssl req -new -newkey rsa:2048 -noenc -keyout server.key -out server.csr -subj "/CN=example.com"
$ head -1 server.key
-----BEGIN PRIVATE KEY-----

-noencを付けないと、パスフレーズの入力を求められる。-passoutで非対話に指定できる。

$ openssl req -new -newkey rsa:2048 -passout pass:pw -keyout server.key -out server.csr -subj "/CN=example.com"
$ head -1 server.key
-----BEGIN ENCRYPTED PRIVATE KEY-----

古い記事では、同じ意味の-nodesが使われている。OpenSSL 3.0でも-nodesは動作するが、非推奨である。

鍵の種類を指定する

-newkeyには、鍵の種類を指定する。

指定鍵の種類
rsa:2048RSA 2048ビット
ec -pkeyopt ec_paramgen_curve:P-256ECDSA P-256
ed25519Ed25519
$ openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc -keyout ec.key -out ec.csr -subj "/CN=a"
$ openssl req -new -newkey ed25519 -noenc -keyout ed.key -out ed.csr -subj "/CN=a"

Ed25519のCSRは、署名アルゴリズムがEd25519になる。一般的な認証局では、Ed25519の証明書を発行できない場合がある。RSAかECDSAを使うのが無難である。

バージョンによる違い

OpenSSL 3.5や3.6でも、ここまでの例は同じように動く。

macOS標準の/usr/bin/openssl(LibreSSL 3.3.6)では、以下が異なる。

  • -noencに対応していない。代わりに-nodesを使う
  • -verifyの出力がverify OKになる

-addextと設定ファイルでのSAN指定は、LibreSSL 3.3.6でも使える。

参考

openssl-req - OpenSSL Documentation