【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の情報を正しく指定しないと、無効な署名を有効と誤認するセキュリティリスクが生じます。