JavaScriptでp12ファイルから証明書と秘密鍵を取得する

JavaScriptを使って、ブラウザ上で、p12ファイルからpemの書式で証明書と秘密鍵を取得してみます。

forgeの使用

以下、forgeというライブラリを使って実装してゆきます。ブラウザで読み込むには、以下のようにminファイルを読み込む必要があります。

1
const forge = require('node-forge/dist/forge.min.js');

p12ファイルを読み込み

p12ファイルはブラウザで添付される想定ですので、まずは、以下のようにして、ファイルを解読可能にします。

1
2
3
4
5
6
7
8
9
10
11
// p12Bufferは、添付されたファイルをBufferに変換したもの
const p12String = p12Buffer.toString('base64');

// base64からデコード
const p12Der = forge.util.decode64(p12String);

// ASN.1オブジェクトを取得
const p12Asn1 = forge.asn1.fromDer(p12Der);

// p12ファイルを読み込み
const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1);

注意点としては、p12ファイルにパスワードを設定する場合は、forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password')のようにする必要があることです。Google API Consoleで取得した場合はデフォルトでnotasecretになっていたりするので、要件にあわせて実装を行ってください。

証明書の取得

証明書は以下のように取得できます。Bagは、p12ファイルにおける、情報を入れておく箱のようなものです。

1
2
3
4
5
6
// Bagタイプから証明書を取得
// https://tools.ietf.org/html/rfc7292#section-4.2.3
const cert = p12.getBags({ bagType: forge.pki.oids.certBag })[forge.pki.oids.certBag][0].cert;

// pemの書式で取得
const pemCert = forge.pki.certificateToPem(cert);

秘密鍵の取得

秘密鍵も基本的には同様ですが、間に変換の処理が入ります。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Bagタイプから秘密鍵を取得。秘密鍵なのでPKCS#8で取り出せる
// https://tools.ietf.org/html/rfc7292#section-4.2.2
const privateKey = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag })[forge.pki.oids.pkcs8ShroudedKeyBag][0].key;

// ASN.1のRSA秘密鍵に変換
const rsaPrivateKey = forge.pki.privateKeyToAsn1(privateKey);

// PKCS#8のPrivateKeyInfoでラップする
// https://tools.ietf.org/html/rfc5208#section-5
const privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey);

// pemの書式で取得
const pemPrivate = forge.pki.privateKeyInfoToPem(privateKeyInfo);

秘密鍵はp12.getBags({friendlyName: "privatekey"})のようにfriendlyNameをつかって取得することもできますが、基本的に任意で設定できてしまうので、Bagタイプで取るのがよさそうです。

まとめ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
出力:
-----BEGIN CERTIFICATE-----
base64エンコード
-----END CERTIFICATE-----
*/
console.log(pemCert.replace(/\r\n/g, '\n'))

/*
出力:
-----BEGIN PRIVATE KEY-----
base64エンコード
-----END PRIVATE KEY-----
*/
console.log(pemPrivate.replace(/\r\n/g, '\n'))

無事pem書式で情報を取得できました。

このエントリーをはてなブックマークに追加