インポートダイアログはパスワードを受け取り、しばらく回ってからバンドルを読めないと告げます。そのメッセージには、パスフレーズの打ち間違いなのか、クライアントがもう同梱しない暗号で封印されたのか、どちらなのかが書かれていません。これは別々の障害で対処も異なり、選び間違えるとクライアントのダウングレードに進み、判断を先送りするだけになります。クライアントがどの段階で止まるかを見れば、およそ一分で両者を切り分けられます。

ダイアログと証明書一覧の間で何が起きるか

.p12 ファイルは証明書ではなくコンテナです。中には一つ以上の証明書バッグと、パスワードから導いた鍵で暗号化された秘密鍵バッグがあり、さらにファイル全体に対する MAC という完全性検査があります。開くということは、その MAC を検証し、鍵バッグを復号し、出てきた鍵と証明書を照合するということです。

パスワードの問題は MAC の段階で現れます。暗号の問題はもっと後、鍵バッグを開く必要があり、それを実行するビルドにファイルで指定されたアルゴリズムの実装がないときに現れます。

二つ目のケースが現在のシステムでよく起きるのは、OpenSSL 3 が 古いアルゴリズムの一群を任意の legacy プロバイダへ移したためです。OpenSSL 1.x が書き出したバンドルは通常、証明書を 40 ビット RC2 で、秘密鍵を三鍵 Triple DES で封印していました。既定の OpenSSL 3 ビルドは正しいパスワードで MAC を検証したうえでバッグで失敗するので、パスワードは決して間違っておらず、打ち直しても何も変わりません。

鍵を書き出さずにコンテナを読む

自分のマシンの OpenSSL ビルドにファイルを解析させ、どこで諦めるかを読み取ります。出力ファイルを伴わない検査なら鍵はディスク上で暗号化されたままなので、共有ホストでもこの手順が安全なのはそのためです。

openssl pkcs12 -in vpn-identity.p12 -info -noout

正しいパスワードの legacy バンドルでは、バッグ属性を表示したあと digital envelope routines::unsupported で止まります。パスワードが違えば、どのバッグも読まれる前に Mac verify error: invalid password? が出ます。二つのメッセージは正反対を指しており、まさにそれがクライアントが伏せていた情報です。

非対応アルゴリズムの失敗であれば、-legacy を加え、他は何も変えずに同じコマンドをもう一度実行します。このフラグはその一プロセスに限って legacy プロバイダを読み込むだけです。VPN クライアントが古いバンドルを解析するようになるわけでも、システム全体の暗号ポリシーに触れるわけでもなく、ファイルは結局差し替える必要があるので、これは修理ではなく計測です。

どのエラーがどの段階を意味するか

短い表で三つの結果を切り分けられ、ダイアログがどこに出たかより文言のほうが重要です。

Text you seeStageWhat it tells you
Mac verify error: invalid password?Integrity checkPassphrase or cached credential, not the cipher
digital envelope routines::unsupportedBag decryptAlgorithm missing from the default provider
not enough data / header too longContainer formatWrong encoding, edited file, or truncated download

not enough data や header too long のような文言は、最初の二群のどちらにも属しません。これは形式の問題で、.pem に改名した DER ファイル、行末を書き換えたエディタで壊れたコピー、ダウンロードの途中終了のいずれかです。暗号を眺める前に、発行者が送ったチェックサムと比べてください。

Mac verify error はパスワードについての証拠としてだけ扱います。入力から計算した MAC が保存値と一致しないという意味で、打ち間違い、以前のインポートでキャッシュされたパスワード、別のパスフレーズで再書き出しされたファイルのいずれかで起こります。中のアルゴリズムが古いかどうかは何も語りません。

クライアントが実際に開けるバンドルを作る

legacy パーサがファイルの健全性を確認したら、恒久的な修正は、対象クライアントが対応するアルゴリズムを持つ差し替え、つまり鍵と証明書のバッグには AES-256-CBC、導出には SHA-256 を用いた PBKDF2、MAC には SHA-256 を使うものです。PKI 管理者は同じ鍵素材から書き出せますし、中の証明書はサーバがすでに信頼しているもののままです。

ローカルで変換する必要があるときは、まず中身を吐き出すのではなく、pkcs12 ツールにバッグを再封印させます。両方のパスフレーズはファイルから読むことでシェル履歴に残さないようにします。

openssl pkcs12 -in vpn-identity.p12 -out vpn-identity-aes.p12 \
  -keypbe AES-256-CBC -certpbe AES-256-CBC -macalg sha256 \
  -passin file:old.pass -passout file:new.pass

変換に成功しても、有効期限、鍵用途、秘密鍵の一致、サーバが発行連鎖を信頼するかどうかについては何も分かりません。再パッケージは輸送の変更であり更新ではないので、それぞれに独自の確認が要ります。

クライアントがファイルを受け入れたというだけで、保護されていない中間鍵を書き出す手順や空の出力パスワードを使う手順は避けてください。保護を剥がした読めるバンドルは、最初のインポート失敗より悪い結果です。

クライアントが作成したファイルをインポートしたことを確認する

端末でのきれいな解析はコンテナが妥当であることを示しますが、クライアントがそれを選んだことまでは示しません。残ったプロファイルが古いファイルを指し続けることがあり、インポートした識別情報を選んでいない名前でキャッシュするクライアントもあるからです。

これからインポートする識別情報を出力し、クライアントの証明書ビューに表示される内容と比べます。

openssl pkcs12 -in vpn-identity-aes.p12 -clcerts -nokeys -passin file:new.pass \
  | openssl x509 -noout -subject -dates -fingerprint -sha256

まず古いプロファイル項目を削除してからインポートします。クライアントが読み込んだサブジェクトやフィンガープリントを記録するなら上の行と突き合わせ、友好的な名前しか表示しないなら、同じ発行者の別の証明書と取り違えにくい有効期限のほうを確認してください。

PKCS12 のリファレンスには、ここで使うプロバイダ、パスフレーズ、出力の各オプションが載っています。要点は legacy プロバイダをクライアント環境の外に置くことで、それで測り、それなしで配布し、秘密鍵はディスク上で保護したままにします。

関連記事