【PHP8.x】openssl_x509_parse関数の使い方

作成日: 更新日:

openssl_x509_parse関数は、X.509形式のデジタル証明書を解析し、その詳細な情報を取得するために使用される関数です。ウェブサイトのセキュリティやデータ通信の安全性を確保する上で重要な役割を果たす証明書の内容を、プログラムから簡単に読み取ることができます。

この関数は、解析したいX.509証明書をOpenSSLCertificateリソース、またはPEM形式の文字列として受け取ります。解析に成功すると、証明書に含まれる様々な情報(例えば、発行者、件名、有効期限の開始日と終了日、シリアル番号など)を連想配列として返します。解析に失敗した場合は、falseを返します。

この配列には、証明書の持ち主を示す「subject(件名)」、証明書を発行した機関を示す「issuer(発行者)」、証明書が有効な期間を示す「validFrom(有効開始日)」や「validTo(有効終了日)」といったキーが含まれており、これらの情報を通じて証明書の信頼性や有効性を確認できます。例えば、受け取った証明書がまだ有効期限内であるかをチェックしたり、特定の信頼できる機関によって発行されたものであるかを確認したりする際に大変役立ちます。システムがセキュアな通信を行う上で、証明書の情報をプログラム的に扱うための基本的なツールとして利用されます。

基本的な使い方

構文(syntax)

<?php

// X.509 証明書へのパスを指定します。
// 例: $certificate = '/path/to/your/certificate.pem';
// または、openssl_x509_read() で取得した OpenSSLCertificate オブジェクトも指定可能です。
$x509CertificateData = 'certificate_data_or_path';

// openssl_x509_parse 関数を使用して証明書を解析します。
// 第二引数 $shortnames (bool) はオプションで、true (デフォルト) の場合、属性名は短縮形 (例: CN) で返されます。
$parsedCertificateInfo = openssl_x509_parse($x509CertificateData);

?>

引数(parameters)

OpenSSLCertificate|string $certificate, bool $short_names = true

  • OpenSSLCertificate|string $certificate: 解析するX.509証明書。OpenSSL X.509証明書リソースまたはPEM形式の証明書文字列を指定します。
  • bool $short_names = true: 証明書内のオブジェクト識別名(OID)の短縮名を使用するかどうかを指定するブール値。trueの場合、短縮名(例: "CN")が使用され、falseの場合、完全名(例: "commonName")が使用されます。

戻り値(return)

array|false

openssl_x509_parse 関数は、X.509証明書の内容を解析し、その情報を連想配列で返します。解析に失敗した場合は false を返します。

サンプルコード

openssl_x509_parseで証明書を解析する

<?php

declare(strict_types=1);

/**
 * openssl_x509_parse() を使用してX.509証明書を解析するサンプル関数
 *
 * この関数は、自己署名証明書を動的に生成し、その内容を
 * openssl_x509_parse() で解析して表示します。
 * 第2引数 $short_names の true/false による出力の違いも示します。
 */
function parseCertificateExample(): void
{
    // --- 1. 解析対象のテスト用証明書を生成 ---

    // 秘密鍵と公開鍵のペアを生成
    $privateKey = openssl_pkey_new([
        'private_key_bits' => 2048,
        'private_key_type' => OPENSSL_KEYTYPE_RSA,
    ]);

    if ($privateKey === false) {
        echo "エラー: 秘密鍵の生成に失敗しました。\n";
        return;
    }

    // 証明書の所有者情報 (Distinguished Name)
    $dn = [
        "countryName" => "JP",
        "stateOrProvinceName" => "Tokyo",
        "localityName" => "Shinjuku-ku",
        "organizationName" => "Example Company",
        "organizationalUnitName" => "Development",
        "commonName" => "www.example.com",
        "emailAddress" => "admin@example.com"
    ];

    // 証明書署名要求 (CSR) を生成
    $csr = openssl_csr_new($dn, $privateKey, ['digest_alg' => 'sha256']);
    if ($csr === false) {
        echo "エラー: CSRの生成に失敗しました。\n";
        return;
    }

    // 自己署名証明書を生成 (有効期間: 30日)
    $certificate = openssl_csr_sign($csr, null, $privateKey, 30, ['digest_alg' => 'sha256']);
    if ($certificate === false) {
        echo "エラー: 証明書の生成に失敗しました。\n";
        return;
    }

    // --- 2. openssl_x509_parse() で証明書を解析 ---

    // $short_names = true (デフォルト) の場合。キーは 'CN' のような短い形式になります。
    echo "--- 解析結果 (short_names = true) ---\n";
    $parsedDataShort = openssl_x509_parse($certificate, true);

    if ($parsedDataShort === false) {
        echo "証明書の解析に失敗しました。\n";
    } else {
        // 重要な情報のみを抜粋して表示
        printf("コモンネーム(CN): %s\n", $parsedDataShort['subject']['CN']);
        printf("発行者(Issuer CN): %s\n", $parsedDataShort['issuer']['CN']);
        printf("有効期間(開始): %s\n", date('Y-m-d H:i:s', $parsedDataShort['validFrom_time_t']));
        printf("有効期間(終了): %s\n", date('Y-m-d H:i:s', $parsedDataShort['validTo_time_t']));
    }
    echo "\n";


    // $short_names = false の場合。キーは 'commonName' のようなOID名になります。
    echo "--- 解析結果 (short_names = false) ---\n";
    $parsedDataLong = openssl_x509_parse($certificate, false);

    if ($parsedDataLong === false) {
        echo "証明書の解析に失敗しました。\n";
    } else {
        // 重要な情報のみを抜粋して表示
        printf("コモンネーム(commonName): %s\n", $parsedDataLong['subject']['commonName']);
        printf("発行者(Issuer commonName): %s\n", $parsedDataLong['issuer']['commonName']);
        printf("有効期間(開始): %s\n", date('Y-m-d H:i:s', $parsedDataLong['validFrom_time_t']));
        printf("有効期間(終了): %s\n", date('Y-m-d H:i:s', $parsedDataLong['validTo_time_t']));
    }
}

// サンプル関数を実行
parseCertificateExample();

このPHPサンプルコードは、openssl_x509_parse()関数を使い、X.509証明書の内容を解析する方法を示します。

コードの前半では、まず解析の対象となるテスト用の自己署名証明書を動的に生成しています。これは、openssl_x509_parse()関数を試すための準備段階です。

次に、生成した証明書をopenssl_x509_parse()関数に渡して解析処理を行います。この関数は、第1引数に指定された証明書を解析し、その詳細情報を連想配列として返します。解析に失敗した場合はfalseが返ります。

第2引数の$short_namesは、戻り値の連想配列のキーの形式を指定する重要なオプションです。true(デフォルト)に設定すると、キーは「CN」(コモンネーム)のような短い形式になります。一方、falseにすると「commonName」のような、より公式な名称のキーが使われます。このサンプルでは、truefalseの両方のケースを実行し、出力結果の違いを比較しています。

最後に、関数から返された連想配列を利用して、証明書に含まれるコモンネームや発行者、有効期間といった特定の情報を取り出し、画面に表示しています。

openssl_x509_parse関数は、証明書の解析に失敗するとfalseを返します。そのため、戻り値が配列であることを必ず確認してから内容にアクセスしてください。第2引数$short_namesの値によって、返される連想配列のキー名が'CN'のような短縮形か'commonName'のような正式名称かに変わる点に注意が必要です。プログラム内でどちらの形式を使うかを決め、アクセスするキーを間違えないようにしましょう。また、証明書の有効期限を示すvalidFrom_time_tなどの値はUNIXタイムスタンプです。date()関数などで人間が読める形式へ変換してから利用してください。

PHP openssl_x509_parse で証明書を解析する

<?php

declare(strict_types=1);

/**
 * openssl_x509_parse() を使用してX.509証明書を解析するサンプル関数です。
 *
 * この関数は、自己署名証明書を動的に生成し、その内容を解析して表示します。
 * これにより、外部ファイルや設定なしに単体で動作します。
 */
function displayParsedCertificateInfo(): void
{
    // --- 1. 解析対象の自己署名証明書を生成 ---

    // 秘密鍵を生成します。
    $privateKey = openssl_pkey_new([
        'private_key_bits' => 2048,
        'private_key_type' => OPENSSL_KEYTYPE_RSA,
    ]);

    if ($privateKey === false) {
        echo 'エラー: 秘密鍵の生成に失敗しました。' . PHP_EOL;
        return;
    }

    // 証明書の所有者情報 (Distinguished Name) を設定します。
    $dn = [
        "countryName" => "JP",
        "stateOrProvinceName" => "Tokyo",
        "localityName" => "Shinjuku-ku",
        "organizationName" => "My Example Organization",
        "commonName" => "www.example.com",
    ];

    // 証明書署名要求 (CSR) を生成します。
    $csr = openssl_csr_new($dn, $privateKey, ['digest_alg' => 'sha256']);
    if ($csr === false) {
        echo 'エラー: CSRの生成に失敗しました。' . PHP_EOL;
        openssl_pkey_free($privateKey); // 生成した秘密鍵リソースを解放
        return;
    }

    // 365日間有効な自己署名証明書 (X.509) を生成します。
    $x509 = openssl_csr_sign($csr, null, $privateKey, 365, ['digest_alg' => 'sha256']);
    if ($x509 === false) {
        echo 'エラー: 自己署名証明書の生成に失敗しました。' . PHP_EOL;
        openssl_pkey_free($privateKey);
        return;
    }


    // --- 2. openssl_x509_parse() を使用して証明書を解析 ---

    // 第2引数 short_names を true (デフォルト) に設定して解析します。
    // キーが 'CN' や 'O' のような短い名前になります。
    echo "--- 証明書情報の解析結果 (short_names = true) ---" . PHP_EOL;
    $certDataShort = openssl_x509_parse($x509, true);

    if ($certDataShort === false) {
        echo 'エラー: 証明書の解析に失敗しました。' . PHP_EOL;
    } else {
        // 必要な情報のみを抜粋して表示
        printf("コモンネーム (CN): %s\n", $certDataShort['subject']['CN']);
        printf("組織名 (O): %s\n", $certDataShort['subject']['O']);
        printf("有効期間(開始): %s\n", date('Y-m-d H:i:s', $certDataShort['validFrom_time_t']));
        printf("有効期間(終了): %s\n", date('Y-m-d H:i:s', $certDataShort['validTo_time_t']));
        printf("シリアル番号: %s\n", $certDataShort['serialNumber']);
    }

    echo PHP_EOL;

    // --- 3. リソースの解放 ---
    openssl_pkey_free($privateKey);
}

// サンプル関数を実行します。
displayParsedCertificateInfo();

openssl_x509_parse()は、X.509証明書を解析し、その詳細な情報を連想配列として取得するためのPHP関数です。

このサンプルコードは、まずopenssl_pkey_new()openssl_csr_sign()といった関数を使い、解析対象となる自己署名証明書をプログラム内で動的に生成しています。これにより、外部に証明書ファイルを用意することなく、関数の動作を単体で確認できます。

次に、生成した証明書をopenssl_x509_parse()の第一引数に渡して解析を実行します。第二引数の$short_namesは、戻り値となる連想配列のキーを短い形式にするかどうかの設定です。サンプルではtrueを指定しているため、コモンネームは'commonName'ではなく'CN'というキーで取得できます。

関数が成功すると、証明書の所有者情報、有効期間、シリアル番号などが格納された連想配列が返されます。コードでは、この配列からコモンネームや組織名、タイムスタンプ形式の有効期間などを取り出し、人間が読みやすい形式に整形して表示しています。もし解析に失敗した場合はfalseが返されるため、その場合はエラーメッセージを表示します。最後に、生成した秘密鍵リソースをopenssl_pkey_free()で解放して処理を終了します。

このコードで使われる openssl_ 系の関数は、処理に失敗すると false を返すことがあります。そのため、戻り値を必ずチェックし、エラー処理を記述することが重要です。また、openssl_pkey_new で生成した秘密鍵のようなリソースは、使い終わったら openssl_pkey_free で必ず解放してください。これを怠るとメモリリークの原因となります。openssl_x509_parse が返す配列のキー名は、第2引数が true だと CN のような短い形式に、false だと commonName のような公式な形式に変わる点にも注意が必要です。有効期限のタイムスタンプはUNIX形式で返されるため、date関数などで読みやすい形式へ変換して利用します。

【PHP8.x】openssl_x509_parse関数の使い方 | いっしー@Webエンジニア