Openssl csr get subject: примеры (PHP)

Работа с CSR в PHP: извлечение данных субъекта
Раздел: Шифрование (OpenSSL)
openssl_csr_get_subject(OpenSSLCertificateSigningRequest|string $csr, bool $short_names = true): array|false
Описание функции openssl_csr_get_subject

Функция openssl_csr_get_subject извлекает информацию о субъекте из запроса на подпись сертификата (Certificate Signing Request, CSR). Функция используется при обработке CSR, например, для проверки данных перед созданием или подписью сертификата, в системах автоматизации PKI (Public Key Infrastructure) или веб-интерфейсах для генерации сертификатов.

Аргументы функции
  • csr: Может быть строкой в формате PEM или ресурсом, возвращаемым функциями openssl_csr_new() или openssl_csr_sign(). Это обязательный аргумент.
  • short_names: Необязательный логический параметр (по умолчанию true). При значении true ключи в возвращаемом массиве будут короткими именами (например, 'CN', 'C'). При false будут использоваться длинные описательные имена (например, 'commonName', 'countryName').

Функция возвращает ассоциативный массив с данными субъекта или false в случае ошибки.

Короткие примеры использования
Пример 1: Базовое использование

Получение данных из CSR в виде строки PEM.

<?php
$csrPem = '-----BEGIN CERTIFICATE REQUEST-----
MIIC0TCCAbkCAQAwgYcxCzAJBgNVBAYTAlJVMQ8wDQYDVQQIDAZNb3Njb3cxDzAN
... (остальная часть CSR) ...
-----END CERTIFICATE REQUEST-----';

$subject = openssl_csr_get_subject($csrPem);
print_r($subject);
?>
Array
(
    [C] => RU
    [ST] => Moscow
    [L] => Moscow
    [O] => Example Company
    [CN] => www.example.com
)
Пример 2: Использование с параметром short_names = false
<?php
$csrPem = '-----BEGIN CERTIFICATE REQUEST-----...';
$subject = openssl_csr_get_subject($csrPem, false);
print_r($subject);
?>
Array
(
    [countryName] => RU
    [stateOrProvinceName] => Moscow
    [localityName] => Moscow
    [organizationName] => Example Company
    [commonName] => www.example.com
)
Пример 3: Использование с ресурсом CSR
<?php
// Создание нового CSR
$dn = [
    "countryName" => "RU",
    "commonName" => "test.local",
];
$privkey = openssl_pkey_new();
$csrResource = openssl_csr_new($dn, $privkey);

// Извлечение данных субъекта
$subject = openssl_csr_get_subject($csrResource);
print_r($subject);
?>
Array
(
    [C] => RU
    [CN] => test.local
)
Похожие функции в PHP

Извлекает открытый ключ из CSR в виде ресурса. Применяется, когда нужен не сам субъект, а связанный с запросом открытый ключ.

Создает новый CSR. Функция openssl_csr_get_subject часто используется для проверки данных CSR, сгенерированного этой функцией.

Анализирует уже подписанный сертификат X.509 и возвращает детальную информацию, включая данные субъекта и издателя. Предпочтительнее для работы с готовыми сертификатами, а не с запросами.

openssl_csr_get_subject используют специфически для работы с запросами на подпись до их превращения в сертификат.

Типичные ошибки
Ошибка 1: Некорректный или поврежденный PEM
<?php
$badPem = "-----BEGIN CERTIFICATE REQUEST-----
INVALID_DATA
-----END CERTIFICATE REQUEST-----";
$result = openssl_csr_get_subject($badPem);
var_dump($result);
?>
bool(false)

Функция возвращает false. Для диагностики можно использовать openssl_error_string().

Ошибка 2: Передача неверного типа данных
<?php
$result = openssl_csr_get_subject(12345);
var_dump($result);
?>
Warning: openssl_csr_get_subject(): supplied parameter cannot be coerced into a CSR in ...
bool(false)

Важно передавать именно строку PEM или ресурс CSR.

Ошибка 3: Использование подписанного сертификата вместо CSR
<?php
$x509Pem = '-----BEGIN CERTIFICATE-----...';
$result = openssl_csr_get_subject($x509Pem);
var_dump($result);
?>
bool(false)

Функция предназначена только для CSR. Для сертификатов существует openssl_x509_parse().

История изменений
  • PHP 8.0.0: Параметр short_names теперь имеет тип bool. Ранее он был целочисленным (int).
  • PHP 7.3.0: В качестве параметра csr стала приниматься строка PEM в дополнение к ресурсу.
Расширенные примеры
Пример 1: Валидация поля Common Name
Пример php
<?php
function validateCSRCN($csrPem, $expectedDomain) {
    $subject = openssl_csr_get_subject($csrPem);
    if ($subject === false) {
        return "Ошибка чтения CSR";
    }
    $actualCN = $subject['CN'] ?? null;
    return ($actualCN === $expectedDomain) ? "CN совпадает" : "CN не совпадает. Ожидалось: $expectedDomain, получено: $actualCN";
}

$csr = '...CSR для example.com...';
echo validateCSRCN($csr, "example.com");
?>
CN совпадает
Пример 2: Извлечение всех атрибутов субъекта с обработкой ошибок
Пример php
<?php
$csrPem = file_get_contents('/path/to/invalid.csr');

if ($csrPem === false) {
    die("Не удалось прочитать файл.");
}

$subject = openssl_csr_get_subject($csrPem, false);

if ($subject === false) {
    $errorMsg = "";
    while (($error = openssl_error_string()) !== false) {
        $errorMsg .= $error . "\n";
    }
    die("Ошибка при разборе CSR:\n" . $errorMsg);
}

echo "Данные субъекта (полные имена):\n";
foreach ($subject as $key => $value) {
    echo "$key: $value\n";
}
?>
Ошибка при разборе CSR:
error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag
error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error
...
Пример 3: Сравнение данных из двух CSR
Пример php
<?php
function compareCSRSubjects($csr1, $csr2) {
    $subj1 = openssl_csr_get_subject($csr1);
    $subj2 = openssl_csr_get_subject($csr2);
    if ($subj1 === false || $subj2 === false) {
        return false;
    }
    // Сравниваем только основные поля, игнорируя возможные дополнительные атрибуты в одном из CSR
    $fields = ['C', 'ST', 'L', 'O', 'OU', 'CN', 'emailAddress'];
    $differences = [];
    foreach ($fields as $field) {
        $val1 = $subj1[$field] ?? '(не задано)';
        $val2 = $subj2[$field] ?? '(не задано)';
        if ($val1 !== $val2) {
            $differences[$field] = ["CSR1" => $val1, "CSR2" => $val2];
        }
    }
    return $differences;
}
?>
Альтернативы в других языках
Python (cryptography)
from cryptography import x509
from cryptography.hazmat.primitives import serialization

pem_csr = b"-----BEGIN CERTIFICATE REQUEST-----..."
csr = x509.load_pem_x509_csr(pem_csr)
subject = csr.subject
print(subject.rfc4514_string())
CN=www.example.com, O=Example Company, L=Moscow, ST=Moscow, C=RU

Библиотека предлагает более объектно-ориентированный и детализированный API.

OpenSSL CLI
openssl req -in request.csr -noout -subject
subject=C = RU, ST = Moscow, L = Moscow, O = Example Company, CN = www.example.com

Консольная утилита предоставляет аналогичные данные в текстовом формате.

JavaScript (Node.js с модулем 'openssl-wrapper' или 'pkijs')

Прямого аналога в стандартной библиотеке нет. Требуются сторонние модули для парсинга ASN.1 структуры CSR, что делает процесс менее тривиальным, чем в PHP.

PHP openssl_csr_get_subject function comments

En
Openssl csr get subject Returns the subject of a CSR