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

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

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

作成日: 更新日:

基本的な使い方

openssl_pkcs7_verify関数は、PKCS#7形式で署名されたデータの署名を検証する関数です。この関数は、特定のデジタルコンテンツが、信頼できる発行元によって署名され、かつ内容が改ざんされていないことを確認するために使用されます。

具体的には、入力されたPKCS#7形式のデータに対し、署名者の証明書と信頼できる認証局(CA)の証明書チェーンを用いて、署名が有効であるかを調べます。例えば、ダウンロードしたソフトウェアパッケージや電子メールの添付ファイルなどが本物であるか、途中で悪意のある変更が加えられていないかを判断する際に非常に役立ちます。

この関数は、検証したい署名付きのファイルパス、署名者の公開鍵証明書、信頼するCA証明書のファイルパス、および検証結果を出力するためのファイルパスなどを引数として受け取ります。検証が成功すれば、データが正当であることを示し、失敗すれば署名が無効であるか、データが破損している可能性を示します。セキュアなシステムを構築する上で、データの整合性と認証を保証するための重要な機能を提供します。

構文(syntax)

1<?php
2
3openssl_pkcs7_verify(
4    string $filename,
5    int $flags,
6    ?string $signercertfile = null,
7    array $cainfo = [],
8    ?string $extracertsfile = null
9): bool;
10
11?>

引数(parameters)

string $input_filename, int $flags, string|array|null $signers_certificates_filename = null, array|string|null $ca_info = [], array|string|null $untrusted_certificates_filename = null, string|null $content = null, string|null $output_filename = null

  • string $input_filename: 検証するPKCS#7署名ファイルへのパス
  • int $flags: 検証の挙動を制御するフラグ
  • string|array|null $signers_certificates_filename: 検証対象の署名者の証明書ファイルへのパス(複数指定可能)
  • array|string|null $ca_info: CA証明書(信頼できる証明書発行機関)のパスまたは情報
  • array|string|null $untrusted_certificates_filename: untrusted証明書ファイルへのパス(複数指定可能)
  • string|null $content: 検証対象の元のコンテンツ(指定しない場合はファイルから読み込まれる)
  • string|null $output_filename: 検証結果の詳細を出力するファイルへのパス

戻り値(return)

int|bool

openssl_pkcs7_verify 関数は、PKCS#7 署名付きデータの検証結果を示す整数値、または検証に失敗した場合は FALSE を返します。検証が成功した場合は 1、有効な証明書チェーンが見つからなかった場合は 0 が返されます。

サンプルコード

PHP openssl_pkcs7_verifyによる署名検証

1<?php
2
3/**
4 * openssl_pkcs7_verify の利用例
5 *
6 * このスクリプトは、PKCS7 形式で署名されたファイルを検証する openssl_pkcs7_verify 関数を
7 * 実演します。デモンストレーションのため、一時的な自己署名証明書と秘密鍵を生成し、
8 * メッセージを署名し、その署名を検証します。
9 *
10 * システムエンジニアを目指す初心者の方へ:
11 * このコードは、PKCS7 形式のデジタル署名がどのように生成され、その後どのように
12 * 検証されるかを示すものです。openssl_pkcs7_verify 関数は、署名されたファイルが
13 * 改ざんされていないか、また信頼できる署名者によって署名されたものかを検証するために
14 * 使用されます。
15 *
16 * 実際のアプリケーションでは、証明書や秘密鍵は安全な方法で管理され、
17 * 信頼された認証局(CA)によって発行されたものが使用されます。
18 */
19
20// 一時ファイルを格納するディレクトリを定義
21$tempDir = __DIR__ . '/pkcs7_temp';
22if (!is_dir($tempDir)) {
23    mkdir($tempDir, 0700, true); // 0700でパーミッションを設定し、セキュリティを考慮
24}
25
26// 一時ファイルのパスを定義
27$privateKeyFile = $tempDir . '/private.key';
28$certificateFile = $tempDir . '/certificate.crt';
29$originalDataFile = $tempDir . '/original_message.txt';
30$signedFile = $tempDir . '/signed_message.p7s';
31$verifiedContentFile = $tempDir . '/verified_content.txt';
32
33echo "--- openssl_pkcs7_verify のサンプル開始 ---\n\n";
34
35// --- 1. 自己署名証明書と秘密鍵の生成 ---
36// 実際のシナリオでは、これらの鍵と証明書は既存のものを使用するか、
37// 信頼された認証局から取得します。
38echo "1. 自己署名証明書と秘密鍵を生成中...\n";
39
40$config = [
41    "digest_alg"       => "sha512",
42    "private_key_bits" => 2048,
43    "private_key_type" => OPENSSL_KEYTYPE_RSA,
44];
45
46// 新しい秘密鍵を生成
47$privateKey = openssl_pkey_new($config);
48if (!$privateKey) {
49    die("エラー: 秘密鍵の生成に失敗しました。" . openssl_error_string() . "\n");
50}
51
52// CSR (Certificate Signing Request) を生成
53$csr = openssl_csr_new([
54    "countryName"          => "JP",
55    "stateOrProvinceName"  => "Tokyo",
56    "organizationName"     => "Example Corp",
57    "commonName"           => "example.com",
58    "emailAddress"         => "admin@example.com"
59], $privateKey);
60if (!$csr) {
61    die("エラー: CSR の生成に失敗しました。" . openssl_error_string() . "\n");
62}
63
64// CSR を自己署名して証明書を作成 (ここではCAなしの自己署名)
65$certificate = openssl_csr_sign($csr, null, $privateKey, $days = 365, $config);
66if (!$certificate) {
67    die("エラー: 証明書の自己署名に失敗しました。" . openssl_error_string() . "\n");
68}
69
70// 秘密鍵と証明書をファイルに保存
71openssl_pkey_export($privateKey, $privateKeyOutput);
72file_put_contents($privateKeyFile, $privateKeyOutput);
73openssl_x509_export($certificate, $certificateOutput);
74file_put_contents($certificateFile, $certificateOutput);
75
76echo "   - 秘密鍵: {$privateKeyFile}\n";
77echo "   - 証明書: {$certificateFile}\n";
78echo "生成完了。\n\n";
79
80// --- 2. 署名するオリジナルのデータを作成 ---
81echo "2. 署名するオリジナルのデータを作成中...\n";
82$originalData = "このメッセージはPKCS7形式で署名されます。";
83file_put_contents($originalDataFile, $originalData);
84echo "   - オリジナルデータ: {$originalDataFile}\n";
85echo "作成完了。\n\n";
86
87// --- 3. PKCS7形式でデータを署名 ---
88echo "3. オリジナルデータをPKCS7形式で署名中...\n";
89// PKCS7_SMIMECAPABILITIES: S/MIME機能を有効化
90// PKCS7_STREAM: ストリームAPIを使用 (大きなファイルに適している)
91// PKCS7_NOCHAIN: 署名に証明書チェーンを含めない (提供された証明書のみを使用)
92$signFlags = PKCS7_SMIMECAPABILITIES | PKCS7_STREAM | PKCS7_NOCHAIN;
93
94$signedSuccessfully = openssl_pkcs7_sign(
95    $originalDataFile,      // 署名する入力ファイル
96    $signedFile,            // 署名結果を保存するファイル
97    $certificate,           // 署名者の証明書 (resource)
98    $privateKey,            // 署名者の秘密鍵 (resource)
99    [],                      // 追加のヘッダー情報 (不要な場合は空配列)
100    $signFlags              // 署名フラグ
101);
102
103if (!$signedSuccessfully) {
104    die("エラー: データのPKCS7署名に失敗しました。" . openssl_error_string() . "\n");
105}
106echo "   - 署名済みファイル: {$signedFile}\n";
107echo "署名完了。\n\n";
108
109// --- 4. PKCS7署名ファイルを検証 ---
110echo "4. PKCS7署名ファイルの検証中...\n";
111
112// 検証フラグ:
113// OPENSSL_PKCS7_TEXT: 抽出されたコンテンツをテキスト形式で出力
114// OPENSSL_PKCS7_NOINTERN: 署名ファイル内の埋め込み証明書を使用しない
115$verifyFlags = OPENSSL_PKCS7_TEXT | OPENSSL_PKCS7_NOINTERN;
116
117$verifyResult = openssl_pkcs7_verify(
118    $signedFile,            // 検証するPKCS7署名ファイル
119    $verifyFlags,           // 検証フラグ
120    $certificateFile,       // 署名者の証明書ファイル (検証時に使用)
121    null,                   // CA証明書情報 (自己署名なので不要、または信頼チェーン検証時に使用)
122    null,                   // 信頼できない証明書 (不要)
123    null,                   // 署名されたコンテンツ (署名ファイルに埋め込まれているため null)
124    $verifiedContentFile    // 検証済みコンテンツを抽出する出力ファイル
125);
126
127echo "検証結果: ";
128if ($verifyResult === true) {
129    echo "成功!署名が有効で、内容も改ざんされていません。\n";
130    $extractedContent = file_get_contents($verifiedContentFile);
131    echo "抽出されたコンテンツ:\n---\n" . $extractedContent . "\n---\n";
132
133    // 抽出されたコンテンツが元のデータと一致するか確認
134    if (trim($originalData) === trim($extractedContent)) {
135        echo "抽出されたコンテンツはオリジナルデータと一致します。\n";
136    } else {
137        echo "警告: 抽出されたコンテンツがオリジナルデータと一致しませんでした。\n";
138        echo "オリジナル: '" . $originalData . "'\n";
139        echo "抽出:      '" . $extractedContent . "'\n";
140    }
141} elseif ($verifyResult === 0) {
142    echo "失敗 (0)!署名の検証に失敗しました。OpenSSLエラー: " . openssl_error_string() . "\n";
143} else { // $verifyResult === false
144    echo "失敗 (false)!検証中にエラーが発生しました。OpenSSLエラー: " . openssl_error_string() . "\n";
145}
146
147echo "\n--- openssl_pkcs7_verify のサンプル終了 ---\n";
148
149// --- 5. 一時ファイルのクリーンアップ ---
150echo "\n5. 一時ファイルをクリーンアップ中...\n";
151if (file_exists($privateKeyFile)) { unlink($privateKeyFile); }
152if (file_exists($certificateFile)) { unlink($certificateFile); }
153if (file_exists($originalDataFile)) { unlink($originalDataFile); }
154if (file_exists($signedFile)) { unlink($signedFile); }
155if (file_exists($verifiedContentFile)) { unlink($verifiedContentFile); }
156if (is_dir($tempDir)) { rmdir($tempDir); }
157echo "クリーンアップ完了。\n";
158
159?>

openssl_pkcs7_verify関数は、PKCS7形式でデジタル署名されたファイルが改ざんされていないか、また、信頼できる署名者によって署名されたものであるかを検証するために使用されるPHPの関数です。システムエンジニアを目指す初心者の方にとって、データの信頼性を保証するデジタル署名の検証は、セキュリティの重要な基礎となります。

このサンプルコードでは、まず一時的に自己署名証明書と秘密鍵を生成し、その鍵を使ってメッセージをPKCS7形式で署名します。次に、openssl_pkcs7_verify関数を用いて、署名されたファイルが有効であるかを確認し、元のコンテンツを安全に抽出できるかを実演しています。

関数の第一引数$input_filenameには検証対象のPKCS7署名ファイルを、第二引数$flagsには検証時の振る舞いを制御するオプション(例えば、コンテンツをテキストとして抽出するかどうか)を指定します。$signers_certificates_filenameで署名者の証明書を提供し、$output_filenameには検証が成功した場合に抽出される元のコンテンツの保存先を指定します。

戻り値は、検証が成功し署名が有効であった場合はtrue、署名に問題があったが処理自体は完了した場合は0、検証処理中にエラーが発生した場合はfalseを返します。これにより、ファイルの内容が改ざんされていないこと、そして署名者の正当性を確認することが可能となり、セキュアなシステム構築に貢献します。

このサンプルコードで生成される鍵や証明書はデモンストレーション用であり、実際のシステムでは信頼できる認証局発行のものを使用し、秘密鍵は厳重に管理してください。openssl_pkcs7_verify関数の戻り値は、成功がtrue、署名検証失敗が0、それ以外のエラーがfalseと複数のパターンがあるため、正確な条件分岐を行うことが大切です。一時ファイルのパーミッション設定や削除処理はセキュリティ上重要ですが、本番環境ではアクセス権限や確実な削除失敗時の対応も考慮してください。また、検証フラグや証明書関連の引数は、システムの信頼性確保に直結するため、その意味をしっかり理解して設定してください。エラーメッセージはopenssl_error_string()で確認できます。

PHPでPKCS#7署名を検証する

1<?php
2
3/**
4 * openssl_pkcs7_verify 関数を使用してPKCS#7署名を検証するデモンストレーション関数。
5 * 署名に必要な鍵ペアと自己署名証明書の生成から、データの署名、そして検証までの一連の流れを示します。
6 * キーワードである openssl_pkey_new も署名プロセスの一部として使用しています。
7 */
8function demonstratePkcs7Verification(): void
9{
10    // 一時ファイルのパスを定義
11    $tempDir = sys_get_temp_dir();
12    $privateKeyPath = $tempDir . '/pkcs7_private.key';
13    $certificatePath = $tempDir . '/pkcs7_certificate.crt';
14    $originalDataPath = $tempDir . '/pkcs7_original_data.txt';
15    $signedDataPath = $tempDir . '/pkcs7_signed_data.p7m';
16    $outputContentPath = $tempDir . '/pkcs7_verified_content.txt';
17
18    // スクリプト終了時に一時ファイルをクリーンアップするためのクロージャを登録
19    // これにより、スクリプトが正常終了してもエラーで終了しても、一時ファイルが削除されます。
20    register_shutdown_function(function() use (
21        $privateKeyPath, $certificatePath, $originalDataPath,
22        $signedDataPath, $outputContentPath
23    ) {
24        // 各ファイルが存在すれば削除
25        if (file_exists($privateKeyPath)) {
26            unlink($privateKeyPath);
27        }
28        if (file_exists($certificatePath)) {
29            unlink($certificatePath);
30        }
31        if (file_exists($originalDataPath)) {
32            unlink($originalDataPath);
33        }
34        if (file_exists($signedDataPath)) {
35            unlink($signedDataPath);
36        }
37        if (file_exists($outputContentPath)) {
38            unlink($outputContentPath);
39        }
40        echo "\n一時ファイルをクリーンアップしました。\n";
41    });
42
43    echo "--- PKCS#7 署名と検証のデモンストレーションを開始します ---\n\n";
44
45    // 1. 秘密鍵を生成します (openssl_pkey_new を使用)
46    echo "1. 秘密鍵を生成しています... ";
47    $configArgs = [
48        "digest_alg" => "sha256",
49        "private_key_bits" => 2048,
50        "private_key_type" => OPENSSL_KEYTYPE_RSA,
51    ];
52    $privateKeyResource = openssl_pkey_new($configArgs); // 新しい秘密鍵リソースを生成
53    if (!$privateKeyResource) {
54        echo "失敗: " . openssl_error_string() . "\n";
55        return;
56    }
57    openssl_pkey_export($privateKeyResource, $privateKeyOutput); // 秘密鍵をPEM形式でエクスポート
58    file_put_contents($privateKeyPath, $privateKeyOutput); // ファイルに保存
59    echo "成功。\n";
60
61    // 2. 自己署名証明書を生成します
62    // 生成した秘密鍵を使用して、自身が署名者となる証明書を作成します。
63    echo "2. 自己署名証明書を生成しています... ";
64    $csrConfig = [
65        "countryName" => "JP",
66        "stateOrProvinceName" => "Tokyo",
67        "localityName" => "Shinjuku",
68        "organizationName" => "Example Corp",
69        "commonName" => "demo.example.com",
70        "emailAddress" => "admin@example.com"
71    ];
72    $csrResource = openssl_csr_new($csrConfig, $privateKeyResource, $configArgs); // CSR (証明書署名要求) を生成
73    if (!$csrResource) {
74        echo "失敗: " . openssl_error_string() . "\n";
75        return;
76    }
77    // CSRと秘密鍵を使用して自己署名証明書を作成 (CA証明書はnullで自己署名を指定)
78    $certificateResource = openssl_csr_sign($csrResource, null, $privateKeyResource, 365, $configArgs);
79    if (!$certificateResource) {
80        echo "失敗: " . openssl_error_string() . "\n";
81        return;
82    }
83    openssl_x509_export($certificateResource, $certificateOutput); // 証明書をPEM形式でエクスポート
84    file_put_contents($certificatePath, $certificateOutput); // ファイルに保存
85    echo "成功。\n";
86
87    // 3. 署名対象の元のデータファイルを作成します
88    echo "3. 署名対象のデータファイルを作成しています... ";
89    $originalContent = "これはPKCS#7署名によって保護される元のデータです。\n" .
90                       "Hello, PKCS#7 signature verification demonstration!";
91    file_put_contents($originalDataPath, $originalContent);
92    echo "成功。\n";
93
94    // 4. openssl_pkcs7_sign を使用してPKCS#7署名ファイルを作成します
95    // ここでは、データと署名が分離される "detached" 形式を使用します。
96    echo "4. PKCS#7 署名ファイルを作成しています (`openssl_pkcs7_sign`)... ";
97    $signResult = openssl_pkcs7_sign(
98        $originalDataPath,      // 署名する元のデータファイル
99        $signedDataPath,        // 署名結果を保存するファイル
100        $certificatePath,       // 署名者の証明書
101        $privateKeyPath,        // 署名者の秘密鍵
102        [],                     // 追加のヘッダー (今回はなし)
103        PKCS7_DETACHED          // 署名形式: データと署名が分離
104    );
105
106    if (!$signResult) {
107        echo "失敗: " . openssl_error_string() . "\n";
108        return;
109    }
110    echo "成功。\n";
111    echo "   署名ファイル: " . $signedDataPath . "\n";
112
113    // 5. openssl_pkcs7_verify を使用して署名ファイルを検証します
114    // 署名ファイルと署名者の証明書、そして元のデータファイルを指定して検証を行います。
115    echo "\n5. PKCS#7 署名ファイルを検証しています (`openssl_pkcs7_verify`)... \n";
116    echo "   検証対象ファイル: " . $signedDataPath . "\n";
117
118    $verifyResult = openssl_pkcs7_verify(
119        $signedDataPath,        // 検証する署名済みファイル
120        PKCS7_DETACHED,         // 署名の形式 (detached のため元のデータが必要)
121        $certificatePath,       // 署名者の証明書 (この証明書で署名がされたかを確認)
122        [],                     // CA証明書情報 (自己署名のため今回は空)
123        [],                     // 信頼できない証明書リスト (今回は空)
124        $originalDataPath,      // PKCS7_DETACHED の場合、元のデータファイル
125        $outputContentPath      // 検証が成功した場合、署名から抽出されたコンテンツを保存するファイル
126    );
127
128    // 6. 検証結果を表示します
129    if ($verifyResult === true) {
130        echo "\n検証結果: 成功!署名は有効です。\n";
131        $extractedContent = file_get_contents($outputContentPath);
132        echo "   署名から抽出されたコンテンツ:\n---\n" . $extractedContent . "\n---\n";
133        if ($extractedContent === $originalContent) {
134            echo "   抽出されたコンテンツは元のデータと一致します。\n";
135        } else {
136            echo "   警告: 抽出されたコンテンツが元のデータと一致しません。\n";
137        }
138    } elseif ($verifyResult === 0) {
139        echo "\n検証結果: 失敗。署名は無効です。\n";
140        echo "   OpenSSLエラー: " . openssl_error_string() . "\n";
141    } else { // falseの場合
142        echo "\n検証結果: エラーが発生しました。\n";
143        echo "   OpenSSLエラー: " . openssl_error_string() . "\n";
144    }
145
146    echo "\n--- デモンストレーションを終了します ---\n";
147}
148
149// 関数を実行します
150demonstratePkcs7Verification();
151
152?>

PHPのopenssl_pkcs7_verify関数は、PKCS#7形式で電子署名されたデータが、改ざんされていないか、そして指定された証明書によって正しく署名されているかを検証するために使用されます。これにより、データの信頼性と完全性を確認できます。

このサンプルコードは、署名検証の一連の流れをデモンストレーションしています。まず、openssl_pkey_new関数を使って新しい秘密鍵を生成し、その秘密鍵を用いて自己署名証明書を作成します。次に、署名対象のデータファイルを作成し、openssl_pkcs7_sign関数でそのデータに署名を施したファイルを生成します。

その後、いよいよopenssl_pkcs7_verify関数が登場します。この関数には、検証したい署名済みファイル、署名の形式(例: PKCS7_DETACHEDの場合、元のデータファイルも指定)、署名者の証明書ファイルなどを引数として渡します。また、検証が成功した場合に署名から抽出されるコンテンツを保存するファイルパスも指定できます。

関数の戻り値は、署名が有効であればtrue、署名が無効であれば0、処理中にエラーが発生した場合はfalseとなります。サンプルコードでは、これらの戻り値に応じて検証結果を表示し、最後に生成した一時ファイルを適切にクリーンアップすることで、安全で完全な検証プロセスを示しています。

このサンプルコードはPKCS#7署名の検証プロセスを理解するのに役立ちますが、本番環境での利用にはいくつかの注意が必要です。openssl_pkey_newで生成される秘密鍵や証明書は、実運用では厳重に管理し、信頼できる認証局から発行されたものを使用してください。自己署名証明書はテスト用途に適しています。また、PKCS7_DETACHEDフラグを使用する際は、検証時に元のデータファイルが必須となることを理解してください。一時ファイルのセキュリティと適切なクリーンアップも重要です。openssl_pkcs7_verify関数の戻り値はtrue(検証成功)、0(検証失敗)、false(エラー発生)の三通りがあるため、これを正確に区別してハンドリングしてください。特に、署名者の証明書や信頼するCAの情報を正しく指定しないと、無効な署名を有効と誤認するセキュリティリスクが生じます。

関連コンテンツ

関連IT用語

関連プログラミング言語