秘密鍵と証明書を1つのファイルにまとめたPFX(.pfx、.p12)を作りたいときは、openssl pkcs12 -exportを使う。Windowsの証明書ストアやmacOSのキーチェーン、Javaのキーストアなどに、秘密鍵付きの証明書を取り込む場合に使う。
$ openssl pkcs12 -export -inkey server.key -in server.crt -out server.p12
Enter Export Password:
Verifying - Enter Export Password:
-inkeyが秘密鍵、-inが証明書、-outが出力するPFXファイルである。Export Passwordは、PFXファイルを保護するパスワードである。
PFXファイルからPEM形式の秘密鍵や証明書を取り出すには、-exportなしで実行する。
$ openssl pkcs12 -in server.p12 -out all.pem -noenc
Enter Import Password:
PFXとPKCS#12は同じものを指す。.pfxと.p12の拡張子の違いは、中身に影響しない。
実行例はUbuntu 24.04のOpenSSL 3.0.13のもの。
パスワードを非対話で指定する
スクリプトから実行する場合は、-passout(作成時)と-passin(展開時)でパスワードを渡す。指定方法はpass:、env:、file:で、openssl encの-passと共通である。
$ export P12PW=secret
$ openssl pkcs12 -export -inkey server.key -in server.crt -out server.p12 -passout env:P12PW
$ openssl pkcs12 -in server.p12 -nokeys -passin env:P12PW
pass:はコマンドラインに残るため、共有環境ではenv:かfile:を使う。
参考: 【openssl】ファイルをパスワードで暗号化・復号する (enc)
中間CAの証明書や名前を含める
-certfileで、CAの証明書を一緒に格納できる。-nameは、キーチェーンやブラウザーの一覧に表示される名前(フレンドリーネーム)を付ける。
$ openssl pkcs12 -export -inkey server.key -in server.crt -certfile ca.crt \
-name "server" -out server.p12
中間CAを含めると、取り込み先がチェーンを構成できる。
PEM形式の証明書と秘密鍵を連結した1つのファイルを、-inだけで渡すこともできる。
$ cat server.crt server.key > combined.pem
$ openssl pkcs12 -export -in combined.pem -out combined.p12
秘密鍵と証明書のペアが違うと、作成時にエラーで失敗する。
$ openssl pkcs12 -export -inkey other.key -in server.crt -out bad.p12
No cert in -in file 'server.crt' matches private key
参考: 【openssl】秘密鍵と証明書が対応しているか確認する (pkey -pubout)
PFXの中身を確認する
-info -nooutで、中身の構成を確認できる。
$ openssl pkcs12 -in server.p12 -info -noout
Enter Import Password:
MAC: sha256, Iteration 2048
MAC length: 32, salt length: 8
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Certificate bag
Certificate bag
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Certificate bagが証明書、Shrouded Keybagが暗号化された秘密鍵である。MACとPBES2の行から、使われている暗号化方式を確認できる。
パスワードが違う場合は、Mac verify error: invalid password?というエラーになる。
PFXからPEMを取り出す
取り出す対象は、オプションで選ぶ。
| オプション | 取り出す内容 |
|---|---|
| なし | 証明書と秘密鍵のすべて |
-nokeys | 証明書だけ |
-nocerts | 秘密鍵だけ |
-clcerts | サーバー証明書だけ(CA証明書を除く) |
-cacerts | CA証明書だけ |
$ openssl pkcs12 -in server.p12 -nokeys -passin env:P12PW
Bag Attributes
friendlyName: server
subject=CN = server.test
issuer=CN = Test CA
-----BEGIN CERTIFICATE-----
...
秘密鍵をパスフレーズなしで取り出す
-nocertsや、オプションなしで秘密鍵を取り出すと、PEMのパスフレーズの入力を求められる。パスフレーズなしで取り出すには、-noencを付ける。
$ openssl pkcs12 -in server.p12 -nocerts -noenc -passin env:P12PW -out server.key
パスフレーズなしの秘密鍵は、ファイルが漏れるとそのまま悪用される。パーミッションを600にして保管する。
-noencは、OpenSSL 3.0で導入されたオプションである。古い記事で見かける-nodesは、同じ意味の非推奨の名前である。
取り出した証明書にヘッダーが付く
PFXから取り出したPEMには、Bag AttributesやfriendlyNameの行が付く。openssl x509などは、PEM以外の行を読み飛ばすため、そのまま使える。気になる場合は、openssl x509 -in all.pemで整形し直す。
macOSのキーチェーンに読み込めない
OpenSSL 3.0以降のpkcs12 -exportは、デフォルトで新しい暗号化方式(AES-256-CBCとPBKDF2、MACにSHA-256)を使う。この形式のPFXは、macOSのsecurity importで読み込めない。
$ security import server.p12 -k test.keychain-db -P secret
security: SecKeychainItemImport: MAC verification failed during PKCS12 import (wrong password?)
パスワードが正しくても、wrong password?というエラーになる。実際の原因はパスワードではなく、暗号化方式である。この例はmacOS 26.6.2で確認した。
-legacyを付けて作り直す
-legacyを付けて作り直すと、古い暗号化方式(秘密鍵は3DES、証明書は40ビットRC2、MACはSHA-1)で作られ、読み込める。
$ openssl pkcs12 -export -legacy -inkey server.key -in server.crt -out legacy.p12
$ openssl pkcs12 -in legacy.p12 -info -noout -legacy
MAC: sha1, Iteration 2048
MAC length: 20, salt length: 16
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
$ security import legacy.p12 -k test.keychain-db -P secret
1 identity imported.
-legacyは、OpenSSL 3.0で導入された、レガシープロバイダーを有効にするオプションである。OpenSSL 1.1.1以前やLibreSSLでは使えない。
古い暗号化方式は、強度が低い。取り込み先が新しい方式に対応している場合は、デフォルトの形式を使う。
macOS標準のopensslで作る
macOS標準の/usr/bin/openssl(LibreSSL 3.3.6)は、デフォルトで古い暗号化方式のPFXを作る。そのため、-legacyなしでsecurity importできる。
$ /usr/bin/openssl pkcs12 -export -inkey server.key -in server.crt -out libre.p12
$ security import libre.p12 -k test.keychain-db -P secret
1 identity imported.
LibreSSL 3.3.6は、OpenSSL 3.xが作ったPFXの読み込みもできる。
$ /usr/bin/openssl pkcs12 -in modern.p12 -info -noout
MAC Iteration 2048
MAC verified OK
古い暗号化方式を展開する
OpenSSL 3.xで、古い暗号化方式のPFXを展開する場合も、-legacyが必要になる。-legacyを付けないと、RC2が使えず、展開に失敗する。
$ openssl pkcs12 -in legacy.p12 -nokeys
Error outputting keys and certificates
...Algorithm (RC2-40-CBC : 0)...
$ openssl pkcs12 -in legacy.p12 -nokeys -legacy
この例はmacOSのHomebrew版OpenSSL 3.6で確認した。
取り込み先の暗号化方式を指定する
-legacyの一括指定ではなく、暗号化方式を個別に指定する方法もある。
$ openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1 \
-inkey server.key -in server.crt -out old.p12
| オプション | 指定する内容 |
|---|---|
-keypbe | 秘密鍵の暗号化方式 |
-certpbe | 証明書の暗号化方式 |
-macalg | MACのハッシュアルゴリズム |
要求される方式が分かっている場合に使う。分からない場合は、まず-legacyを試す。
バージョンによる違い
macOS標準の/usr/bin/openssl(LibreSSL 3.3.6)では、以下が異なる。
-noencに対応していない。代わりに-nodesを使う-legacyに対応していない。デフォルトで古い暗号化方式のPFXを作る
