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

【PHP8.x】OPENSSL_CMS_NOVERIFY定数の使い方

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

作成日: 更新日:

基本的な使い方

OPENSSL_CMS_NOVERIFY定数は、PHPのOpenSSL拡張機能において、CMS(Cryptographic Message Syntax)関連の処理で利用されるオプションを表す定数です。CMSは、デジタル署名やデータの暗号化、認証などを安全に行うための標準的な構文を定義しています。

この定数は、主にopenssl_cms_verify関数など、CMS署名の検証を行う際にオプションとして指定されます。通常、デジタル署名の検証プロセスでは、署名が改ざんされていないかの確認に加えて、署名に使用された証明書が有効で信頼できるものかどうかも厳密にチェックされます。これは、署名者の身元が正当であることを保証し、セキュリティを維持するために非常に重要です。

OPENSSL_CMS_NOVERIFY定数を指定すると、この証明書の検証プロセスがスキップされます。具体的には、署名の整合性自体は確認されますが、署名者の証明書が信頼された機関によって発行されたものであるか、有効期限内であるかといった証明書チェーンの検証が行われなくなります。

このオプションは、自己署名証明書を使用している場合や、テスト環境などで証明書の検証を一時的に無効にしたい場合に利用されることがあります。しかし、証明書の検証をスキップすることは、不正な署名や偽装された証明書を見逃す可能性があり、セキュリティ上の重大なリスクを伴います。そのため、本番環境やセキュリティが重要なシステムでの利用は極力避け、使用する際にはそのリスクを十分に理解し、慎重な検討が求められます。

構文(syntax)

1<?php
2echo OPENSSL_CMS_NOVERIFY;
3?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

int

この定数は、CMS(Cryptographic Message Syntax)署名の検証を行わないことを示す整数値です。

サンプルコード

PHP: openssl_cms_verify で署名検証をスキップする

1<?php
2
3/**
4 * PHPのOPENSSL_CMS_NOVERIFY定数の使用例を示します。
5 * この定数は、openssl_cms_verify関数で使用され、
6 * CMS (Cryptographic Message Syntax) データの署名検証をスキップします。
7 * 主にテスト目的や、署名検証が不要なCMSデータの処理に使用されます。
8 *
9 * このスクリプトは以下の手順で動作します。
10 * 1. CMS署名に必要なデータ、自己署名証明書、秘密鍵を一時的に生成します。
11 * 2. 生成したデータと証明書・鍵を使ってCMS署名ファイルを作成します。
12 * 3. OPENSSL_CMS_NOVERIFY定数なしでCMS署名を検証し、失敗する様子を示します(CA証明書がないため)。
13 * 4. OPENSSL_CMS_NOVERIFY定数ありでCMS署名を検証し、署名検証がスキップされてデータが抽出される様子を示します。
14 * 5. 使用した一時ファイルをすべて削除してクリーンアップします。
15 */
16
17// 一時ファイルのパスを定義
18$tempDir = sys_get_temp_dir();
19$dataFile = tempnam($tempDir, 'data'); // 署名する元のデータファイル
20$certFile = tempnam($tempDir, 'cert'); // 自己署名証明書ファイル
21$keyFile = tempnam($tempDir, 'key');   // 秘密鍵ファイル
22$cmsFile = tempnam($tempDir, 'cms');   // 生成されるCMS署名ファイル
23$extractedFile = tempnam($tempDir, 'extracted'); // CMSから抽出されるデータファイル
24
25// 一時ファイルの作成に失敗した場合はエラー終了
26if (!$dataFile || !$certFile || !$keyFile || !$cmsFile || !$extractedFile) {
27    error_log("一時ファイルの作成に失敗しました。\n");
28    exit(1);
29}
30
31// -----------------------------------------------------
32// 1. CMS署名のための準備: データ、自己署名証明書、秘密鍵を生成
33// -----------------------------------------------------
34
35echo "--- 準備フェーズ ---\n";
36
37// 元のデータを作成し、ファイルに保存
38$originalData = "This is a secret message that needs to be signed.";
39file_put_contents($dataFile, $originalData);
40echo "1. 元のデータファイル ('" . $dataFile . "') を作成しました。\n";
41echo "   内容: \"" . file_get_contents($dataFile) . "\"\n\n";
42
43// 自己署名証明書と秘密鍵を生成
44$privateKey = openssl_pkey_new([
45    "private_key_bits" => 2048,
46    "private_key_type" => OPENSSL_KEY_RSA,
47]);
48if (!$privateKey) {
49    error_log("秘密鍵の生成に失敗しました: " . openssl_error_string() . "\n");
50    exit(1);
51}
52
53$csr = openssl_csr_new([
54    "countryName" => "JP",
55    "stateOrProvinceName" => "Tokyo",
56    "localityName" => "Shibuya",
57    "organizationName" => "Example Corp",
58    "commonName" => "localhost",
59    "emailAddress" => "admin@example.com",
60], $privateKey);
61if (!$csr) {
62    error_log("CSR (証明書署名要求) の生成に失敗しました: " . openssl_error_string() . "\n");
63    exit(1);
64}
65
66$cert = openssl_csr_sign($csr, null, $privateKey, 365, ["digest_alg" => "sha256"]);
67if (!$cert) {
68    error_log("自己署名証明書の生成に失敗しました: " . openssl_error_string() . "\n");
69    exit(1);
70}
71
72// 証明書と秘密鍵を一時ファイルに保存
73openssl_x509_export_to_file($cert, $certFile);
74openssl_pkey_export_to_file($privateKey, $keyFile);
75echo "2. 自己署名証明書 ('" . $certFile . "') と秘密鍵 ('" . $keyFile . "') を生成しました。\n\n";
76
77// -----------------------------------------------------
78// 2. CMS署名データの生成
79// -----------------------------------------------------
80
81echo "--- CMS署名データの生成 ---\n";
82echo "3. 元のデータにCMS署名を施し、CMSファイル ('" . $cmsFile . "') を生成中...\n";
83
84// openssl_cms_sign を使用して署名付きCMSデータを作成
85// OPENSSL_CMS_BINARY: バイナリエンコーディングを使用
86// OPENSSL_CMS_DETACHED: 署名を元のデータから分離 (検証時に元のデータを抽出可能にするため)
87if (!openssl_cms_sign(
88    $dataFile,
89    $cmsFile,
90    $certFile,
91    $keyFile,
92    [],
93    OPENSSL_CMS_BINARY | OPENSSL_CMS_DETACHED
94)) {
95    error_log("CMS署名データの生成に失敗しました: " . openssl_error_string() . "\n");
96    exit(1);
97}
98echo "   CMS署名ファイルを正常に生成しました。\n\n";
99
100// -----------------------------------------------------
101// 3. CMSデータの検証 (OPENSSL_CMS_NOVERIFYなし)
102// -----------------------------------------------------
103
104echo "--- 署名検証 (OPENSSL_CMS_NOVERIFYなし) ---\n";
105echo "4. CMSファイル ('" . $cmsFile . "') の署名検証を試みます (厳密な検証)。\n";
106
107// CA証明書を指定しないため、通常は検証に失敗する
108// openssl_cms_verify の第3引数 $ca_info は、署名者の証明書を検証するためのCA証明書パス
109if (openssl_cms_verify($cmsFile, OPENSSL_CMS_BINARY | OPENSSL_CMS_DETACHED, null, [], $extractedFile)) {
110    echo "   成功: 署名が検証され、データが抽出されました。\n";
111    echo "   抽出されたデータ: \"" . file_get_contents($extractedFile) . "\"\n\n";
112} else {
113    echo "   失敗: 署名検証に失敗しました。これは想定される動作です。\n";
114    echo "   理由: 署名者の自己署名証明書は信頼されたCAによって発行されていないため、検証に失敗します。\n";
115    echo "   OpenSSLエラー: " . openssl_error_string() . "\n\n";
116}
117
118// -----------------------------------------------------
119// 4. CMSデータの検証 (OPENSSL_CMS_NOVERIFYあり)
120// -----------------------------------------------------
121
122echo "--- 署名検証 (OPENSSL_CMS_NOVERIFYあり) ---\n";
123echo "5. CMSファイル ('" . $cmsFile . "') の署名検証を試みます (OPENSSL_CMS_NOVERIFY使用)。\n";
124
125// OPENSSL_CMS_NOVERIFYを使用すると、署名検証がスキップされる
126// 署名が正しくない場合でも、データが抽出される可能性がある。
127// セキュリティリスクを伴うため、信頼できるCMSデータにのみ使用すべき。
128if (openssl_cms_verify($cmsFile, OPENSSL_CMS_BINARY | OPENSSL_CMS_DETACHED | OPENSSL_CMS_NOVERIFY, null, [], $extractedFile)) {
129    echo "   成功: OPENSSL_CMS_NOVERIFYにより署名検証がスキップされ、データが抽出されました。\n";
130    echo "   抽出されたデータ: \"" . file_get_contents($extractedFile) . "\"\n\n";
131    if (file_get_contents($extractedFile) === $originalData) {
132        echo "   抽出されたデータは元のデータと一致します。\n\n";
133    } else {
134        echo "   警告: 抽出されたデータは元のデータと一致しませんでした。\n\n";
135    }
136} else {
137    error_log("CMSデータの処理に失敗しました (OPENSSL_CMS_NOVERIFY使用時): " . openssl_error_string() . "\n");
138    exit(1);
139}
140
141// -----------------------------------------------------
142// 5. クリーンアップ
143// -----------------------------------------------------
144
145echo "--- クリーンアップフェーズ ---\n";
146echo "6. 生成した一時ファイルを削除しています...\n";
147unlink($dataFile);
148unlink($certFile);
149unlink($keyFile);
150unlink($cmsFile);
151unlink($extractedFile);
152echo "   クリーンアップ完了。\n";
153
154?>

PHPのOPENSSL_CMS_NOVERIFYは、OpenSSL拡張機能で定義されるint型の定数です。この定数は引数を持ちません。主にopenssl_cms_verify関数と組み合わせて使用され、CMS(Cryptographic Message Syntax)データの署名検証処理をスキップさせる役割を持ちます。

通常、openssl_cms_verify関数は、CMSデータに含まれる署名が信頼できる証明書によって行われているか厳密に検証しようとします。しかし、このOPENSSL_CMS_NOVERIFY定数を関数に渡すと、署名の正当性チェックが省略され、CMSデータから元のコンテンツを抽出することが可能になります。

サンプルコードでは、まず自己署名証明書で署名されたCMSデータを作成します。次に、OPENSSL_CMS_NOVERIFY定数なしで検証を試みると、信頼されたCA証明書がないため署名検証に失敗する様子を示します。その後、この定数を指定して再度検証を行うと、署名検証がスキップされ、CMSデータから元のメッセージが正常に抽出されることが確認できます。

この定数は、署名の正当性検証が不要なケースや、テスト環境での動作確認などに便利ですが、署名の信頼性が保証されないため、本番環境で利用する際はセキュリティ上のリスクを十分に考慮する必要があります。

PHPのOPENSSL_CMS_NOVERIFY定数は、openssl_cms_verify関数でCMS署名検証をスキップする際に利用します。署名の正当性確認が行われないままデータが処理されるため、主に開発中のテスト目的や、署名検証が不要と判断される特殊な状況でのみ限定して使用すべきです。

この定数を安易に用いることは、署名改ざんを見逃し、セキュリティ上の重大なリスクを引き起こします。本番環境でデータの完全性と信頼性を確保するには、必ず信頼できるCA証明書を用いた厳密な署名検証が必要です。セキュリティへの影響を十分に理解し、細心の注意を払って利用してください。

openssl_cms_verifyで検証をスキップする

1<?php
2
3/**
4 * OpenSSL CMS_NOVERIFY フラグの利用例を示す関数
5 *
6 * この関数は、テスト用のCMS署名付きファイルを作成し、
7 * OPENSSL_CMS_NOVERIFY フラグを使用して署名検証をスキップするケースを示します。
8 * システムエンジニアを目指す初心者向けに、具体的な定数の利用シーンを解説します。
9 */
10function demonstrateOpensslCmsNoverify(): void
11{
12    // 一時ファイル名を設定
13    $inputFilename = 'temp_original_data.txt';
14    $signedCmsFilename = 'temp_signed_cms.smime';
15    $outputFilenamePrefix = 'temp_extracted_data_'; // 抽出データ用プレフィックス
16
17    // --- 1. テストデータの準備 ---
18    $originalData = "This is a test message for CMS signing.";
19    file_put_contents($inputFilename, $originalData);
20    echo "1. 元データファイル '{$inputFilename}' を作成しました。\n";
21
22    // --- 2. 署名用の鍵と証明書を生成(自己署名証明書として) ---
23    // 本番環境では、適切に管理された証明機関(CA)からの証明書と秘密鍵を使用します。
24    // PHPのOpenSSL関数を使って、コード内で秘密鍵と自己署名証明書を生成します。
25    $privateKey = openssl_pkey_new([
26        'private_key_bits' => 2048,
27        'private_key_type' => OPENSSL_KEYTYPE_RSA,
28    ]);
29    if (!$privateKey) {
30        echo "エラー: 秘密鍵の生成に失敗しました。\n";
31        return;
32    }
33
34    $csr = openssl_csr_new([
35        'countryName' => 'JP',
36        'stateOrProvinceName' => 'Tokyo',
37        'localityName' => 'Shinjuku',
38        'organizationName' => 'Example Corp',
39        'commonName' => 'localhost',
40        'emailAddress' => 'webmaster@localhost.com',
41    ], $privateKey);
42    if (!$csr) {
43        echo "エラー: CSRの生成に失敗しました。\n";
44        return;
45    }
46
47    $certificate = openssl_csr_sign($csr, null, $privateKey, 365, ['digest_alg' => 'sha256']);
48    if (!$certificate) {
49        echo "エラー: 証明書の生成に失敗しました。\n";
50        return;
51    }
52
53    // PEM形式の鍵と証明書を文字列として取得
54    $privateKeyPem = '';
55    openssl_pkey_export($privateKey, $privateKeyPem);
56    $certificatePem = '';
57    openssl_x509_export($certificate, $certificatePem);
58
59    echo "2. テスト用の秘密鍵と自己署名証明書をメモリ上に生成しました。\n";
60
61    // --- 3. CMS (Cryptographic Message Syntax) 署名付きファイルを作成 ---
62    // openssl_cms_sign() は、指定されたファイルにCMS署名を追加します。
63    // ここでは、データの内容がそのまま署名対象となります。
64    // S/MIME エンコーディングで、SHA256アルゴリズムを使用します。
65    $signResult = openssl_cms_sign(
66        $inputFilename,
67        $signedCmsFilename,
68        $certificatePem,
69        $privateKeyPem,
70        [], // 署名ヘッダーは空
71        0, // 他のフラグはなし
72        OPENSSL_ENCODING_SMIME, // S/MIMEエンコーディング
73        OPENSSL_ALGO_SHA256 // 署名アルゴリズム
74    );
75
76    if (!$signResult) {
77        echo "エラー: CMS署名付きファイルの作成に失敗しました。\n";
78        @unlink($inputFilename); // 失敗時は作成したファイルがあれば削除
79        return;
80    }
81    echo "3. CMS署名付きファイル '{$signedCmsFilename}' を作成しました。\n";
82
83    // --- 4. 通常のCMS署名検証(信頼できる証明書リストなしで試行し、失敗するはず) ---
84    echo "\n4. 通常のCMS署名検証を試みます (信頼できる証明書リストなし、失敗するはず)...\n";
85    $outputFilenameNormal = $outputFilenamePrefix . 'normal.txt';
86    // openssl_cms_verify() の第4引数 (certificates) に空の配列を渡すことで、
87    // 署名者の証明書が信頼できるかどうかの検証に失敗させます。
88    $verifyResultNormal = openssl_cms_verify(
89        $signedCmsFilename,
90        0, // フラグなし (通常検証)
91        $outputFilenameNormal,
92        [] // 検証に使用する証明書リストを空にする
93    );
94
95    if ($verifyResultNormal) {
96        echo "結果: 予期せず検証に成功しました (これは通常起こりません)。\n";
97    } else {
98        echo "結果: 検証に失敗しました (期待通り)。信頼できる証明書が提供されていないためです。\n";
99        // openssl_error_string() で詳細なエラー情報を取得できますが、
100        // 初心者向けに簡潔さを優先し、ここでは省略します。
101    }
102    @unlink($outputFilenameNormal); // 成功しても失敗しても、この抽出ファイルは削除
103
104    // --- 5. OPENSSL_CMS_NOVERIFY フラグを使用してCMS署名を検証(証明書リストなしでも成功するはず) ---
105    // このフラグは、署名者の証明書が信頼できるかどうか、
106    // あるいは有効期限内であるかどうかのチェックをスキップします。
107    // 署名自体の整合性(改ざんされていないか)はチェックされますが、
108    // 署名者の身元確認(証明書の信頼性検証)は行われません。
109    echo "\n5. OPENSSL_CMS_NOVERIFY フラグを使用してCMS署名を検証します (信頼できる証明書リストなしでも成功するはず)...\n";
110    $outputFilenameNoverify = $outputFilenamePrefix . 'noverify.txt';
111    $verifyResultNoverify = openssl_cms_verify(
112        $signedCmsFilename,
113        OPENSSL_CMS_NOVERIFY, // ここで定数を使用
114        $outputFilenameNoverify,
115        [] // 検証に使用する証明書リストは空のまま
116    );
117
118    if ($verifyResultNoverify) {
119        echo "結果: 検証成功しました! (OPENSSL_CMS_NOVERIFY フラグのおかげで、証明書の信頼性チェックがスキップされました)\n";
120        echo "データが '{$outputFilenameNoverify}' に抽出されました。\n";
121        $extractedData = file_get_contents($outputFilenameNoverify);
122        echo "抽出されたデータ: \"{$extractedData}\"\n";
123    } else {
124        echo "結果: 検証に失敗しました (OPENSSL_CMS_NOVERIFY フラグを使用しても)。\n";
125        echo "OpenSSLエラー: " . openssl_error_string() . "\n";
126    }
127
128    // --- 6. 後処理: 作成した一時ファイルを削除 ---
129    @unlink($inputFilename);
130    @unlink($signedCmsFilename);
131    @unlink($outputFilenameNoverify); // 成功した場合のみ存在する可能性
132    echo "\n6. 作成した一時ファイルを削除しました。\n";
133}
134
135// 関数を実行してデモンストレーションを開始します。
136demonstrateOpensslCmsNoverify();
137
138?>

PHPの定数OPENSSL_CMS_NOVERIFYは、OpenSSL拡張機能の一部として提供され、int型の値を持ちます。この定数自体に引数はありません。主にopenssl_cms_verify関数と組み合わせて使用し、CMS(Cryptographic Message Syntax)署名の検証動作を制御します。

OPENSSL_CMS_NOVERIFYを指定すると、openssl_cms_verify関数は、署名者の証明書が信頼できる認証局によって発行されているか、または証明書が有効期限内であるかといった「証明書の信頼性や有効性の検証」をスキップします。これにより、証明書チェーンが不完全な場合や自己署名証明書を使用している場合でも、署名されたデータが改ざんされていないかという「データ自体の整合性検証」は行われます。

サンプルコードでは、まず自己署名証明書を使ってCMS署名付きファイルを作成します。その後、このファイルに対して通常の検証を行うと、信頼できる証明書がないため検証が失敗することを示します。しかし、OPENSSL_CMS_NOVERIFYフラグをopenssl_cms_verify関数に渡して検証を行うと、証明書の信頼性チェックがスキップされるため、データの整合性検証に成功し、元のデータが抽出される様子が確認できます。この定数は、開発やテスト環境、あるいは証明書の信頼性検証が不要な特定のケースで有効活用されます。

このサンプルコードで利用しているOPENSSL_CMS_NOVERIFYは、CMS署名検証時に署名者の証明書の信頼性や有効期限のチェックをスキップするための定数です。これにより、データの改ざん有無は確認されますが、署名者が本当に信頼できる人物や組織であるかの身元確認は行われません。そのため、悪意のある第三者によって署名されたデータでも、改ざんされていなければ検証が成功してしまう可能性があります。本番環境で安易に使用するとセキュリティ上の脆弱性につながるため、データの信頼性を厳格に保証する必要がある場合は、必ず信頼できる証明書(CA証明書など)を用いて完全な検証を行うようにしてください。このフラグは、特別な理由やデバッグ目的以外での利用は極力避けるべきです。

関連コンテンツ

関連IT用語

関連プログラミング言語