Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】openssl_cms_read()関数の使い方

openssl_cms_read関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

openssl_cms_read関数は、CMS (Cryptographic Message Syntax) 形式のデータを読み込むために使用される関数です。この関数は、与えられたCMSデータから、署名されたデータや暗号化されたデータといった実際のコンテンツを安全に抽出する目的で使用されます。

具体的には、第一引数として読み込みたいCMS形式のデータ文字列を受け取ります。オプションの第二引数として出力先のファイルパスを指定することができ、抽出されたコンテンツをそのファイルに書き込むことができます。もし出力先のファイルパスを指定しなかった場合は、コンテンツは内部で一時ファイルに書き込まれ、その一時ファイルの内容が関数の戻り値として文字列で返されます。

処理が正常に完了し、コンテンツの抽出に成功した場合は、抽出されたコンテンツの文字列が返されます。一方、何らかの理由で処理が失敗した場合やエラーが発生した場合には、ブール値のfalseが返されます。

この関数は、セキュアなメッセージング、デジタル署名の検証、または暗号化されたデータの復号化など、CMS形式で保護された情報をPHPアプリケーションで扱う際に重要な役割を果たします。OpenSSL拡張機能の一部として、高度な暗号学的処理を安全かつ効率的に行うための基盤を提供します。

構文(syntax)

1<?php
2$cmsFilePath = 'path/to/your/cms_file.cms';
3$extractedCertificates = [];
4
5$cmsContent = openssl_cms_read($cmsFilePath, $extractedCertificates);

引数(parameters)

string $input_filename, array &$certificates

  • string $input_filename: 読み込むCMS(Cryptographic Message Syntax)ファイルの名前を指定する文字列
  • array &$certificates: 署名者の証明書を格納する配列への参照。この引数に証明書が格納されます。

戻り値(return)

object|false

openssl_cms_read 関数は、CMS(Cryptographic Message Syntax)メッセージを解析した結果を表すオブジェクト、または解析に失敗した場合は false を返します。

サンプルコード

PHP openssl_cms_readでCMSから元データを抽出する

1<?php
2
3/**
4 * プログラミング初心者向けのopenssl_cms_read関数のサンプルコードです。
5 *
6 * この関数は、CMS (Cryptographic Message Syntax) 署名ファイルを作成し、
7 * それをopenssl_cms_read関数で読み込み、CMS内部にカプセル化された
8 * 元のデータ(「生のデータ」)を抽出する方法を示します。
9 *
10 * CMS(暗号メッセージ構文)とは、デジタル署名されたり、暗号化されたりした
11 * メッセージ(例えば、セキュアなメールなど)を扱うための標準的な形式です。
12 * openssl_cms_read関数は、PHPでこれらの特殊なファイルを解析し、内容を読み取るのに使います。
13 * この例では、署名されたCMSファイルから元のデータをどのように取り出すかを示します。
14 */
15function processCmsSignedContent(): void
16{
17    echo "--- CMSコンテンツ処理の例 ---" . PHP_EOL;
18
19    // 1. 署名のために一時的な秘密鍵と自己署名証明書を生成します。
20    //    実際のシステムでは、既存の安全に管理された鍵と証明書を使用します。
21    $privateKeyPath = tempnam(sys_get_temp_dir(), 'pk_'); // 一時ファイル名
22    $certificatePath = tempnam(sys_get_temp_dir(), 'cert_'); // 一時ファイル名
23
24    echo "秘密鍵と自己署名証明書を生成中..." . PHP_EOL;
25    $config = [
26        "digest_alg" => "sha256",       // 署名に使用するハッシュアルゴリズム
27        "private_key_bits" => 2048,    // 秘密鍵のビット数
28        "private_key_type" => OPENSSL_KEYTYPE_RSA, // 鍵の種類 (RSA)
29    ];
30    // 新しい秘密鍵を生成
31    $privateKey = openssl_pkey_new($config);
32    if (!$privateKey) {
33        echo "エラー: 秘密鍵の生成に失敗しました: " . openssl_error_string() . PHP_EOL;
34        return;
35    }
36
37    // 証明書署名要求 (CSR) を生成
38    $csr = openssl_csr_new(["CN" => "Example User for CMS"], $privateKey, $config);
39    if (!$csr) {
40        echo "エラー: CSRの生成に失敗しました: " . openssl_error_string() . PHP_EOL;
41        // 鍵ファイルの削除も忘れずに
42        unlink($privateKeyPath);
43        return;
44    }
45
46    // 自己署名証明書を生成 (証明書自身が自分を信頼すると主張)
47    $certificate = openssl_csr_sign($csr, null, $privateKey, 365, $config); // 365日間有効
48    if (!$certificate) {
49        echo "エラー: 証明書の署名に失敗しました: " . openssl_error_string() . PHP_EOL;
50        unlink($privateKeyPath);
51        return;
52    }
53
54    // 生成した鍵と証明書をファイルに保存します(openssl_pkcs7_signがファイルパスを必要とするため)。
55    openssl_pkey_export_to_file($privateKey, $privateKeyPath);
56    openssl_x509_export_to_file($certificate, $certificatePath);
57
58    echo "鍵と証明書を生成し、一時ファイルに保存しました。" . PHP_EOL;
59    echo "  秘密鍵パス: " . $privateKeyPath . PHP_EOL;
60    echo "  証明書パス: " . $certificatePath . PHP_EOL;
61
62    // 2. 署名する元のデータを用意します。
63    $originalData = "PHPのopenssl_cms_read関数を学ぶための秘密のメッセージです。";
64    $inputFilePath = tempnam(sys_get_temp_dir(), 'cms_input_'); // 署名するデータ用の一時ファイル
65    file_put_contents($inputFilePath, $originalData);
66
67    echo "署名対象の元のデータを用意しました。" . PHP_EOL;
68    echo "  元のデータ: " . $originalData . PHP_EOL;
69
70    // 3. openssl_pkcs7_signを使ってCMS署名ファイルを作成します。
71    //    PKCS#7はCMSの以前のバージョンですが、互換性があります。
72    //    PKCS7_BINARYフラグは、バイナリ形式 (DERエンコード) で署名ファイルを作成します。
73    //    このフラグがないとBase64エンコードされたテキスト形式になります。
74    $outputCmsFilePath = tempnam(sys_get_temp_dir(), 'cms_output_'); // 生成されるCMSファイル用の一時ファイル
75    echo "元のデータをCMSファイルとして署名中..." . PHP_EOL;
76    $signed = openssl_pkcs7_sign(
77        $inputFilePath,       // 署名するデータが保存されたファイル
78        $outputCmsFilePath,   // 生成するCMS署名ファイルのパス
79        $certificate,         // 署名に使用する証明書 (OpenSSLCertificateオブジェクト)
80        $privateKey,          // 署名に使用する秘密鍵 (OpenSSLAsymmetricKeyオブジェクト)
81        [],                   // ヘッダーは今回は空
82        PKCS7_BINARY          // バイナリ形式で出力 (コンテンツがCMS内に埋め込まれる)
83    );
84
85    if (!$signed) {
86        echo "エラー: CMS署名ファイルの作成に失敗しました: " . openssl_error_string() . PHP_EOL;
87        // エラーが発生した場合、一時ファイルを削除して終了
88        unlink($privateKeyPath);
89        unlink($certificatePath);
90        unlink($inputFilePath);
91        // $outputCmsFilePathは作成されていない可能性があるので、存在チェックしてから削除
92        if (file_exists($outputCmsFilePath)) {
93             unlink($outputCmsFilePath);
94        }
95        return;
96    }
97    echo "CMS署名ファイルが作成されました: " . $outputCmsFilePath . PHP_EOL;
98
99    // 4. openssl_cms_read関数を使ってCMS署名ファイルを読み込みます。
100    echo "openssl_cms_readでCMSファイルを読み込み中..." . PHP_EOL;
101    $certificates = []; // この配列には、CMSメッセージ内に含まれる証明書が格納されます。
102
103    /**
104     * openssl_cms_readは、成功するとOpenSSLCMSMessageオブジェクト(PHP 8.0ではobjectとドキュメントされている)を返します。
105     * 失敗するとfalseを返します。
106     * このオブジェクトには、CMSメッセージの内容に関する情報が含まれています。
107     * PHP 8.0ではOpenSSLCMSMessage::getEncapsulatedContent()メソッドが利用可能です。
108     * @var OpenSSLCMSMessage|false $cmsMessage
109     */
110    $cmsMessage = openssl_cms_read($outputCmsFilePath, $certificates);
111
112    if ($cmsMessage === false) {
113        echo "エラー: CMSファイルの読み込みに失敗しました: " . openssl_error_string() . PHP_EOL;
114    } else {
115        echo "CMSファイルの読み込みに成功しました。" . PHP_EOL;
116
117        // 5. OpenSSLCMSMessageオブジェクトから、カプセル化されたコンテンツ(元のデータ)を抽出します。
118        //    これが、署名または暗号化された「生のデータ」です。
119        $extractedContent = $cmsMessage->getEncapsulatedContent();
120
121        if ($extractedContent === false) {
122            echo "エラー: カプセル化されたコンテンツの抽出に失敗しました: " . openssl_error_string() . PHP_EOL;
123        } else {
124            echo "抽出されたコンテンツ(元のデータ):" . PHP_EOL;
125            echo "------------------------------------" . PHP_EOL;
126            echo $extractedContent . PHP_EOL;
127            echo "------------------------------------" . PHP_EOL;
128
129            // 抽出されたコンテンツが元のデータと一致するか検証します。
130            if ($extractedContent === $originalData) {
131                echo "検証結果: 抽出されたコンテンツは元のデータと一致しました。" . PHP_EOL;
132            } else {
133                echo "検証結果: 抽出されたコンテンツは元のデータと一致しませんでした!" . PHP_EOL;
134            }
135        }
136
137        // CMSメッセージ内に含まれる証明書があれば表示します。
138        // openssl_pkcs7_signで作成された署名には、通常、署名者の証明書が埋め込まれます。
139        if (!empty($certificates)) {
140            echo "CMSメッセージ内で見つかった証明書数: " . count($certificates) . PHP_EOL;
141            foreach ($certificates as $index => $cert) {
142                // $certはOpenSSLCertificateオブジェクトです。
143                // openssl_x509_parseで証明書の詳細を解析できます。
144                $certDetails = openssl_x509_parse($cert);
145                echo "  証明書 " . ($index + 1) . ": 発行先 (Subject CN) = " . ($certDetails['subject']['CN'] ?? 'N/A') . PHP_EOL;
146            }
147        } else {
148            echo "CMSメッセージ内に証明書は見つかりませんでした。" . PHP_EOL;
149        }
150    }
151
152    // 6. 作成した一時ファイルをすべて削除します。
153    //    実際のシステムでは、一時ファイルの管理は慎重に行い、使用後は必ず削除する必要があります。
154    echo "一時ファイルをクリーンアップ中..." . PHP_EOL;
155    unlink($privateKeyPath);
156    unlink($certificatePath);
157    unlink($inputFilePath);
158    if (file_exists($outputCmsFilePath)) { // 念のため、ファイルが存在するか確認してから削除
159        unlink($outputCmsFilePath);
160    }
161    echo "一時ファイルがすべて削除されました。" . PHP_EOL;
162    echo "--- 例の実行が完了しました ---" . PHP_EOL;
163}
164
165// 上記の関数を実行して、openssl_cms_readの動作を確認します。
166processCmsSignedContent();
167

PHP 8のopenssl_cms_read関数は、CMS(Cryptographic Message Syntax)形式のファイルを解析し、その内容を読み込むための関数です。CMSは、デジタル署名や暗号化されたメッセージなど、セキュアな情報交換に用いられる標準的なデータ形式です。

この関数は、読み込みたいCMSファイルのパスを$input_filename引数で指定します。また、CMSメッセージ内に含まれる証明書は、参照渡しされる$certificates配列に格納されます。

読み込みが成功すると、関数はOpenSSLCMSMessageオブジェクト(PHP 8.0ではobject型としてドキュメントされています)を返します。このオブジェクトのgetEncapsulatedContent()メソッドを使用することで、CMS内部にカプセル化された元のデータ、いわゆる「生のデータ」を抽出できます。失敗した場合はfalseを返します。

サンプルコードでは、openssl_pkcs7_sign関数を使って署名付きのCMSファイルを作成し、次にopenssl_cms_readでそのファイルを読み込み、元のテキストデータと埋め込まれた証明書を抽出する一連の流れが示されています。これにより、セキュアなメッセージの検証や内容の取り出しがどのように行われるかを理解できます。

openssl_cms_read関数は、署名されたCMSファイルから元の「生のデータ」を安全に抽出する際に使用します。本サンプルでは一時的な鍵と証明書を生成していますが、実際のシステムではこれらを厳重に管理し、使用後は必ず一時ファイルを削除するよう注意してください。

この関数は成功時にOpenSSLCMSMessageオブジェクトを返し、失敗時はfalseを返します。必ず戻り値を確認し、エラー時はopenssl_error_string()で詳細を調べてください。抽出されたコンテンツは、返されたオブジェクトのgetEncapsulatedContent()メソッドで取得できます。また、第二引数の$certificatesには、CMS内に含まれる証明書が格納されます。

openssl_cms_readでCMSファイルを読む

1<?php
2
3/**
4 * openssl_cms_read 関数の使用例を示すサンプルコードです。
5 *
6 * このスクリプトは、システムエンジニアを目指す初心者向けに、
7 * CMS (Cryptographic Message Syntax) 形式のファイルからデータと証明書を読み込む方法を実演します。
8 *
9 * 動作の流れ:
10 * 1. テスト用の自己署名証明書と秘密鍵を生成します。
11 * 2. 生成した証明書と鍵を使用して、サンプルテキストデータをCMS形式で署名し、一時ファイルとして保存します。
12 *    この署名されたファイルが openssl_cms_read 関数の入力となります。
13 * 3. openssl_cms_read 関数を呼び出し、署名されたCMSファイルから元のデータと含まれる証明書を抽出します。
14 * 4. 抽出したデータと証明書の詳細情報を画面に出力します。
15 * 5. 使用したすべての一時ファイルを削除して、環境をクリーンアップします。
16 */
17
18/**
19 * テスト用の自己署名証明書と秘密鍵を生成するヘルパー関数。
20 * @return array{cert: string, key: string}|false 成功した場合は証明書と秘密鍵のPEM形式文字列、失敗した場合は false。
21 */
22function generateSelfSignedCertAndKey(): array|false
23{
24    // 秘密鍵を生成 (2048ビットのRSA鍵)
25    $privKey = openssl_pkey_new([
26        "private_key_bits" => 2048,
27        "private_key_type" => OPENSSL_KEYTYPE_RSA,
28    ]);
29    if (!$privKey) {
30        error_log("Error generating private key: " . openssl_error_string());
31        return false;
32    }
33
34    // 証明書署名要求 (CSR) を生成
35    $csr = openssl_csr_new([
36        "countryName" => "JP",
37        "stateOrProvinceName" => "Tokyo",
38        "localityName" => "Shinjuku-ku",
39        "organizationName" => "Example Corp",
40        "commonName" => "localhost",
41        "emailAddress" => "webmaster@example.com"
42    ], $privKey);
43    if (!$csr) {
44        error_log("Error generating CSR: " . openssl_error_string());
45        openssl_pkey_free($privKey);
46        return false;
47    }
48
49    // 自己署名証明書を生成 (CSRを自己署名し、365日間有効)
50    $x509 = openssl_csr_sign($csr, null, $privKey, 365, ["digest_alg" => "sha256"]);
51    if (!$x509) {
52        error_log("Error signing certificate: " . openssl_error_string());
53        openssl_pkey_free($privKey);
54        return false;
55    }
56
57    // 生成した証明書と秘密鍵をPEM形式でエクスポート
58    openssl_x509_export($x509, $certOut);
59    openssl_pkey_export($privKey, $keyOut);
60
61    // OpenSSLリソースを解放
62    openssl_x509_free($x509);
63    openssl_pkey_free($privKey);
64
65    return ['cert' => $certOut, 'key' => $keyOut];
66}
67
68/**
69 * 指定されたデータ、証明書、秘密鍵を使用してCMS(PKCS7)署名ファイルを作成するヘルパー関数。
70 * @param string $dataToSign 署名する元のデータ。
71 * @param string $outputFilePath 署名済みCMSファイルが保存されるパス。
72 * @param string $certPem 証明書 (PEM形式)。
73 * @param string $keyPem 秘密鍵 (PEM形式)。
74 * @return bool 成功した場合は true、失敗した場合は false。
75 */
76function createSignedCmsFile(string $dataToSign, string $outputFilePath, string $certPem, string $keyPem): bool
77{
78    // 署名するデータを一時ファイルに書き込む
79    $inputFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'temp_data_to_sign.txt';
80    if (file_put_contents($inputFilePath, $dataToSign) === false) {
81        error_log("Error writing data to temporary file: {$inputFilePath}");
82        return false;
83    }
84
85    // openssl_pkcs7_sign を使用してデータを署名し、CMS(PKCS7)ファイルを作成
86    // PKCS7_BINARY: データをバイナリとして処理します。
87    // PKCS7_DETACHED: 署名が元のデータから分離される形式です。
88    //                  これにより openssl_cms_read は元のデータを返します。
89    $success = openssl_pkcs7_sign(
90        $inputFilePath,
91        $outputFilePath,
92        $certPem,
93        $keyPem,
94        [], // 追加ヘッダー(ここでは空の配列)
95        PKCS7_BINARY | PKCS7_DETACHED
96    );
97
98    // 一時入力ファイルを削除
99    unlink($inputFilePath);
100
101    if (!$success) {
102        error_log("Error signing data to CMS file: " . openssl_error_string());
103        return false;
104    }
105
106    return true;
107}
108
109/**
110 * openssl_cms_read を使用してCMSファイルを読み込み、その内容と含まれる証明書を表示する関数。
111 * @param string $cmsFilePath 読み込むCMSファイルのパス。
112 * @return void
113 */
114function readCmsFileExample(string $cmsFilePath): void
115{
116    echo "== openssl_cms_read の実行例 ==\n";
117    echo "CMSファイル '{$cmsFilePath}' を読み込みます。\n\n";
118
119    $certificates = []; // 抽出された証明書を格納する配列(参照渡し)
120
121    // openssl_cms_read を呼び出し、CMSファイルからコンテンツと証明書を読み込む
122    // 戻り値はデコードされたコンテンツ(PKCS7_DETACHEDの場合、元のデータ)または false (失敗時)
123    $cmsContent = openssl_cms_read($cmsFilePath, $certificates);
124
125    if ($cmsContent === false) {
126        echo "エラー: CMSデータの読み込みに失敗しました。\n";
127        echo "OpenSSLエラー: " . openssl_error_string() . "\n";
128        return;
129    }
130
131    echo "CMSデータの読み込みに成功しました。\n";
132    echo "--- 抽出された元のコンテンツ ---\n";
133    echo $cmsContent . "\n";
134    echo "------------------------------\n\n";
135
136    echo "CMSファイル内で " . count($certificates) . " 個の証明書が見つかりました。\n";
137    foreach ($certificates as $index => $certPem) {
138        echo "  --- 証明書 " . ($index + 1) . " ---\n";
139        // 証明書情報を解析して、主要な情報を表示
140        $parsedCert = openssl_x509_parse($certPem);
141        if ($parsedCert) {
142            echo "    Subject (CN): " . ($parsedCert['subject']['CN'] ?? 'N/A') . "\n";
143            echo "    Issuer (CN): " . ($parsedCert['issuer']['CN'] ?? 'N/A') . "\n";
144            echo "    有効期間開始: " . date('Y-m-d H:i:s', $parsedCert['validFrom_time_t']) . "\n";
145            echo "    有効期間終了: " . date('Y-m-d H:i:s', $parsedCert['validTo_time_t']) . "\n";
146        } else {
147            echo "    エラー: 証明書の解析に失敗しました。\n";
148        }
149        echo "  --------------------------\n";
150    }
151}
152
153// --- メイン処理 ---
154echo "サンプルコードを開始します...\n\n";
155
156// 一時ファイルパスを定義
157$tempDir = sys_get_temp_dir();
158$cmsFilePath = $tempDir . DIRECTORY_SEPARATOR . 'example_signed_cms.p7m';
159$dataToSign = "こんにちは、システムエンジニアの皆さん! openssl_cms_read のテストメッセージです。";
160
161// 1. 自己署名証明書と秘密鍵を生成
162echo "1. テスト用の証明書と秘密鍵を生成中...\n";
163$certAndKey = generateSelfSignedCertAndKey();
164if ($certAndKey === false) {
165    echo "エラー: テスト用証明書と鍵の生成に失敗しました。スクリプトを終了します。\n";
166    exit(1);
167}
168$certPem = $certAndKey['cert'];
169$keyPem = $certAndKey['key'];
170echo "   生成完了。\n\n";
171
172// 2. 署名するデータと証明書、秘密鍵を使ってCMSファイルを生成
173echo "2. サンプルデータをCMS形式で署名し、ファイルを作成中...\n";
174if (!createSignedCmsFile($dataToSign, $cmsFilePath, $certPem, $keyPem)) {
175    echo "エラー: CMSファイルの作成に失敗しました。スクリプトを終了します。\n";
176    exit(1);
177}
178echo "   CMSファイルが '{$cmsFilePath}' に作成されました。\n\n";
179
180// 3. openssl_cms_read を使ってCMSファイルを読み込む
181readCmsFileExample($cmsFilePath);
182
183// 4. 生成した一時ファイルをクリーンアップ
184echo "\n3. 一時ファイルをクリーンアップ中...\n";
185if (file_exists($cmsFilePath)) {
186    unlink($cmsFilePath);
187    echo "   '{$cmsFilePath}' を削除しました。\n";
188}
189echo "サンプルコードの実行が完了しました。\n";
190
191?>

PHPのopenssl_cms_read関数は、CMS(Cryptographic Message Syntax)形式のファイルから、その内部に含まれるデータやデジタル証明書を安全に読み取るための機能を提供します。この関数は、OpenSSL拡張機能の一部として、データの完全性や認証を確認する際に利用されます。

第一引数$input_filenameには、読み込みたいCMSファイルのパスを文字列で指定します。このファイルは、通常、デジタル署名されたデータや暗号化されたデータを含んでいます。

第二引数&$certificatesは、CMSファイル内から抽出されたデジタル証明書を格納するための配列です。この引数は参照渡しであるため、関数が成功すると、渡された配列変数にPEM形式の証明書文字列が自動的に追加されます。

関数が成功した場合、戻り値としてCMSファイルからデコードされた元のデータが文字列として返されます。特に、PKCS7_DETACHED形式で署名されたファイルの場合、署名前の元のコンテンツが返されます。読み込みに失敗した場合はfalseが返されます。

このサンプルコードでは、まずテスト用の自己署名証明書と秘密鍵を生成し、それらを使って任意のテキストデータをCMS形式で署名した一時ファイルを作成しています。次に、openssl_cms_read関数を用いてその一時ファイルから元のテキストデータと含まれる証明書を抽出し、その内容を表示しています。これにより、CMSファイルからのデータと証明書の安全な読み込み処理を実践的に学ぶことができます。

PHPのOpenSSL拡張がサーバーで有効になっていることを確認してください。openssl_cms_read関数は、CMSファイルパスと参照渡しで渡す証明書格納用配列を引数に取ります。関数が成功した場合はデコードされたコンテンツ、失敗した場合はfalseを返すため、必ず戻り値を確認しエラーハンドリングを行ってください。実際のシステムでは、サンプルコードのような自己署名証明書ではなく、信頼できる認証局が発行した証明書を使用し、秘密鍵は厳重に管理することがセキュリティ上不可欠です。openssl_pkcs7_signPKCS7_DETACHEDフラグを使って作成されたCMSファイルであれば、元のデータが読み込まれます。

関連コンテンツ

関連IT用語

関連プログラミング言語