Windows OpenSSL 無しで pem 形式のサーバー証明書と秘密鍵を IP アドレスベースで作成する (PowerShell版)
PowerShell だけでサーバー証明書と秘密鍵を .pem
形式で作成する方法を紹介します。また既存の .pfx
ファイルや Windows 証明書ストアの証明書を .pem
形式でエクスポートする方法も紹介します。
やりたいこと
以前 こちらの記事 で Windows で OpenSSL なしで .pem
形式の証明書や秘密鍵の作成方法を紹介したのですが、PowerShell と Python の両方を使う形になっていて中途半端だなと思っていたのと、その後の調査で PowerShell だけで全部やれることがわかったので、改めて本記事で PowerShell だけで一気通貫に .pem
形式の証明書や秘密鍵を作成する方法を紹介したいと思います。また元記事は逆に全部 Python で作成できるように今後記事の内容を変更しようと思います。
環境
- OS
- Microsoft Windows 10 21H2
- PowerShell
- 7.3.6
PowerShell で証明書作成から pem 変換までの手順
証明書作成
PowerShell を開いて以下のコマンドで秘密鍵と証明書を作成します。
各パラメータの内容は以下の通りです。詳細は New-SelfSignedCertificate (pki) | Microsoft Learn をご覧ください。
Subject
: 証明書のサブジェクトです。C は Country で国コード、ST は State で日本の場合は都道府県、CN は Common Name でサーバーの IP アドレスを指定します。(ちなみにドメインで証明書発行する場合はここをドメインにします)TextExtension
: 証明書の拡張項目を OID で指定して設定します。OID=2.5.29.17
は Subject Alternative Name です。(ちなみにドメインで証明書発行する場合は代わりに-DnsName
オプションでドメイン名を指定します)KeyAlgorithm
: 鍵の作成アルゴリズムです。KeyLength
: 鍵の長さです。KeyExportPolicy
: 秘密鍵のエクスポートポリシーです。エクスポート可能にしています。NotAfter
: 証明書の有効期限です。1年後を期限としています。CertStoreLocation
: 証明書を作成する証明書ストア内の場所です。ここでは「現在のユーザー」の「個人」に作成しています。(なお「現在のユーザー」でも「ローカルコンピューター」でも「個人」にしか作成できません)
なお、ここでサーバーの IP アドレスをサブジェクトの Common Name と Subject Alternative Name の双方にセットしていますが、RFC 2818: HTTP Over TLS では以下の通り記載されており、Common Name は廃止しており、Subject Alternative Name の DNS の値を使用すべきとされていますが、一部古いブラウザでは Common Name を見てる可能性もあるので念のため設定しています。Chrome は結構前から Common Name は見ておらず、Subject Alternative Name の DNS
(または IPAdress
) が設定されていないと証明書エラーになります。
If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead. - RFC 2818: HTTP Over TLS
証明書を pem 形式でエクスポート
作成した証明書を .pem
形式に変換していきます。なお、ここで前項で作成した証明書ではなく、既存の .pfx
ファイルを使用したい場合は .pfx
を一度証明書ストアに取り込んでください。.pfx
ファイルを開くと「証明書のインポートウィザード」が開きますので画面に沿ってインポートしてください。
また、既存の証明書ストアにある証明書を使用したい場合も同様ですが、以下コマンドでエクスポートしたい証明書の Thumbprint
を確認してください。
ここでは「現在のユーザー」の「個人」内の証明書をリストしていますが、「ローカルコンピューター」の場合は CurrentUser
を LocalMachine
にしてください。
確認した Thumbprint の値を使用して以下のように証明書をオブジェクトとして $cert
に格納してください。念のためですが、前項で作成した証明書を使用する場合は既に $cert
に証明書オブジェクトが格納されていますのでこの作業は不要です。
さて、前置きが長くなりましたがここからは前項で作成した証明書を使用するケースも、既存の証明書を使用するケースも同様に進めていきます。
-
以下のコマンドで証明書を Base64 エンコードされた文字列に変換できます。
この
[System.Convert]::ToBase64String()
メソッドは第 2 引数で改行の挿入を指定できるのですが、その単位が何故か 76 文字ごとという…。ToBase64String(Byte[], Base64FormattingOptions)
8 ビット符号なし整数の配列を、Base64 の数字でエンコードされた等価の文字列形式に変換します。 戻り値に改行を挿入するかどうかを指定できます。パラメーター inArray
Byte[]
8 ビット符号なし整数の配列。options
Base64FormattingOptions
76 文字ごとに改行を挿入する場合はInsertLineBreaks
。改行を挿入しない場合はNone
。一方、pem ファイルの形式は 1 行 64 文字とすることが規定されています。
Generators MUST wrap the base64-encoded lines so that each line consists of exactly 64 characters except for the final line, which will encode the remainder of the data (within the 64-character line boundary), and they MUST NOT emit extraneous whitespace.
-
仕方ないので 64 文字で改行しつつ、ついでに開始・終了行とラベル付けをする関数を用意します。
開始・終了行やラベルについても RFC 7468 で定義されています。Textual encoding begins with a line comprising “—–BEGIN “, a label, and “—–”, and ends with a line comprising “—–END “, a label, and “—–”.
The type of data encoded is labeled depending on the type label in the “—–BEGIN " line (pre-encapsulation boundary). For example, the line may be “—–BEGIN CERTIFICATE—–” to indicate that the content is a PKIX certificate (see further below). Generators MUST put the same label on the “—–END " line (post-encapsulation boundary) as the corresponding “—–BEGIN " line.ちょっと長いですが、対話形式で PowerShell を使っていても、全部貼り付ければそのセッション内で定義した関数を使用できます。
-
作成した
Format-Pem
関数を使って 64 文字ごとに改行しつつ、開始・終了行も追加します。 -
最後にカレントディレクトリの
cert.pem
ファイルに書き出します。
秘密鍵を pem 形式でエクスポート
-
RSACertificateExtensions.GetRSAPrivateKey()
メソッドに証明書オブジェクト$cert
を渡してRSACng
オブジェクト を取得します -
CngKey.Export()
メソッドで秘密鍵を PKCS #8 形式のバイト列として取得します。 -
取得したバイト列を Base64 エンコードされた文字列に変換します。
-
証明書エクスポートの際に作成した
Format-Pem
関数を使用して 64 文字ごとに改行しつつ、開始・終了行も追加します。 -
最後にカレントディレクトリの
key.pem
ファイルに書き出します。
これで PowerShell だけで証明書と秘密鍵を .pem
形式で作成することができました。
あとがき
これまで自己署名証明書作る際に Mac や Linux で OpenSSL で作成して持ってきたり、WSL で Linux 動かして作成したりしてたのですが、Windows で PowerShell だけで.pem
形式で作成できたのでものすごく楽になりました。他にも Python だけで作成したり、node.js だけで作成したりもできそうなので今後紹介したいと思います。